Skip to content

Commit

Permalink
Added ip6tnlEncap to insert ip6tnl encap route
Browse files Browse the repository at this point in the history
This commit added support to allow the operation of ip6tnl encapsulation.
It is equivalent to the iproute2 command, e.g., ip route add 192.168.99.0/24 encap ip6 dst 2001:db8:: dev ip6-tunnel
The limitation include that the options field defined in encap nl route attribute is not implenmented yet.
Testcase is included.
  • Loading branch information
byteocean committed Apr 22, 2022
1 parent 5e915e0 commit 54ec8c3
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 0 deletions.
21 changes: 21 additions & 0 deletions nl/ip6tnl_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package nl

// id's of route attribute from https://elixir.bootlin.com/linux/v5.17.3/source/include/uapi/linux/lwtunnel.h#L38
// the value's size are specified in https://elixir.bootlin.com/linux/v5.17.3/source/net/ipv4/ip_tunnel_core.c#L928

const (
LWTUNNEL_IP6_UNSPEC = iota
LWTUNNEL_IP6_ID
LWTUNNEL_IP6_DST
LWTUNNEL_IP6_SRC
LWTUNNEL_IP6_HOPLIMIT
LWTUNNEL_IP6_TC
LWTUNNEL_IP6_FLAGS
LWTUNNEL_IP6_PAD // not implemented
LWTUNNEL_IP6_OPTS // not implemented
__LWTUNNEL_IP6_MAX
)




103 changes: 103 additions & 0 deletions route_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,109 @@ func (e *BpfEncap) Equal(x Encap) bool {
return true
}

// IP6tnlEncap definition
type IP6tnlEncap struct {

ID uint64
Dst net.IP
Src net.IP
Hoplimit uint8
TC uint8
Flags uint16

}

func (e *IP6tnlEncap) Type() int {
return nl.LWTUNNEL_ENCAP_IP6
}

func (e *IP6tnlEncap) Decode(buf []byte) error {
attrs, err := nl.ParseRouteAttr(buf)
if err != nil {
return err
}
for _, attr := range attrs {
switch attr.Attr.Type {
case nl.LWTUNNEL_IP6_ID:
e.ID = uint64(native.Uint64(attr.Value[0:4]))
case nl.LWTUNNEL_IP6_DST:
e.Dst = net.IP(attr.Value[:])
case nl.LWTUNNEL_IP6_SRC:
e.Src = net.IP(attr.Value[:])
case nl.LWTUNNEL_IP6_HOPLIMIT:
e.Hoplimit = attr.Value[0]
case nl.LWTUNNEL_IP6_TC:
e.TC = attr.Value[0]
case nl.LWTUNNEL_IP6_FLAGS:
e.Flags = uint16(native.Uint16(attr.Value[0:2]))
case nl.LWTUNNEL_IP6_PAD:
err = fmt.Errorf("decoding PAD in IP6tnlEncap is not supported",)
case nl.LWTUNNEL_IP6_OPTS:
err = fmt.Errorf("decoding OPTS in IP6tnlEncap is not supported")
}
}
return err
}

func (e *IP6tnlEncap) Encode() ([]byte, error) {

final := []byte{}

resID := make([]byte, 12)
native.PutUint16(resID, 12) // 2+2+8
native.PutUint16(resID[2:], nl.LWTUNNEL_IP6_ID)
native.PutUint64(resID[4:], 0)
final = append(final,resID...)

resDst := make([]byte, 4)
native.PutUint16(resDst, 20) // 2+2+16
native.PutUint16(resDst[2:], nl.LWTUNNEL_IP6_DST)
resDst = append(resDst, e.Dst...)
final = append(final,resDst...)

resSrc := make([]byte, 4)
native.PutUint16(resSrc, 20)
native.PutUint16(resSrc[2:], nl.LWTUNNEL_IP6_SRC)
resSrc = append(resSrc, e.Src...)
final = append(final,resSrc...)

resTc := make([]byte, 5)
native.PutUint16(resTc, 5)
native.PutUint16(resTc[2:], nl.LWTUNNEL_IP6_TC)
resTc[4] = e.TC
final = append(final,resTc...)

resHops := make([]byte, 5)
native.PutUint16(resHops, 5)
native.PutUint16(resHops[2:], nl.LWTUNNEL_IP6_HOPLIMIT)
resHops[4] = e.Hoplimit
final = append(final,resHops...)

resFlags := make([]byte, 6)
native.PutUint16(resFlags, 6)
native.PutUint16(resFlags[2:], nl.LWTUNNEL_IP6_FLAGS)
native.PutUint16(resFlags[4:], e.Flags)
final = append(final,resFlags...)

return final, nil
}

func (e *IP6tnlEncap) String() string {
return fmt.Sprintf("id %d src %s dst %s hoplimit %d tc %d flags 0x%.4x", e.ID, e.Src, e.Dst, e.Hoplimit, e.TC, e.Flags)
}

func (e *IP6tnlEncap) Equal(x Encap) bool {
o, ok := x.(*IP6tnlEncap)
if !ok {
return false
}

if e.ID != o.ID || e.Flags != o.Flags || e.Hoplimit != o.Hoplimit || e.Src.Equal(o.Src) || e.Dst.Equal(o.Dst) || e.TC != o.TC {
return false
}
return true
}

type Via struct {
AddrFamily int
Addr net.IP
Expand Down
60 changes: 60 additions & 0 deletions route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,66 @@ func TestMPLSRouteAddDel(t *testing.T) {

}

func TestIP6tnlRouteAddDel(t *testing.T) {
_, err := RouteList(nil, FAMILY_V4)
if err != nil {
t.Fatal(err)
}

tearDown := setUpNetlinkTest(t)
defer tearDown()

// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}

// bring the interface up
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}

_, dst, err := net.ParseCIDR("192.168.99.0/24")
if err != nil {
t.Fatalf("cannot parse destination prefix: %v", err)
}

encap := IP6tnlEncap{
Dst: net.ParseIP("2001:db8::"),
Src: net.ParseIP("::"),
}

route := &Route{
LinkIndex: link.Attrs().Index,
Dst: dst,
Encap: &encap,
}

if err := RouteAdd(route); err != nil {
t.Fatalf("Cannot add route: %v", err)
}
routes, err := RouteList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("Route not added properly")
}

if err := RouteDel(route); err != nil {
t.Fatal(err)
}
routes, err = RouteList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 0 {
t.Fatal("Route not removed properly")
}

}

func TestRouteEqual(t *testing.T) {
mplsDst := 100
seg6encap := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP}
Expand Down

0 comments on commit 54ec8c3

Please sign in to comment.