Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ip6tnlEncap to insert ip6tnl encap route #758

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -589,6 +589,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]
err = fmt.Errorf("decoding TC in IP6tnlEncap is not supported")
case nl.LWTUNNEL_IP6_FLAGS:
// e.Flags = uint16(native.Uint16(attr.Value[0:2]))
err = fmt.Errorf("decoding FLAG in IP6tnlEncap is not supported")
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 @@ -1152,6 +1152,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
Loading