Skip to content

Commit 8d48f50

Browse files
byteoceanaboch
authored andcommitted
Added ip6tnlEncap to insert ip6tnl encap route
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.
1 parent 36b61ad commit 8d48f50

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

nl/ip6tnl_linux.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package nl
2+
3+
// id's of route attribute from https://elixir.bootlin.com/linux/v5.17.3/source/include/uapi/linux/lwtunnel.h#L38
4+
// the value's size are specified in https://elixir.bootlin.com/linux/v5.17.3/source/net/ipv4/ip_tunnel_core.c#L928
5+
6+
const (
7+
LWTUNNEL_IP6_UNSPEC = iota
8+
LWTUNNEL_IP6_ID
9+
LWTUNNEL_IP6_DST
10+
LWTUNNEL_IP6_SRC
11+
LWTUNNEL_IP6_HOPLIMIT
12+
LWTUNNEL_IP6_TC
13+
LWTUNNEL_IP6_FLAGS
14+
LWTUNNEL_IP6_PAD // not implemented
15+
LWTUNNEL_IP6_OPTS // not implemented
16+
__LWTUNNEL_IP6_MAX
17+
)
18+
19+
20+
21+

route_linux.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,109 @@ func (e *BpfEncap) Equal(x Encap) bool {
589589
return true
590590
}
591591

592+
// IP6tnlEncap definition
593+
type IP6tnlEncap struct {
594+
ID uint64
595+
Dst net.IP
596+
Src net.IP
597+
Hoplimit uint8
598+
TC uint8
599+
Flags uint16
600+
}
601+
602+
func (e *IP6tnlEncap) Type() int {
603+
return nl.LWTUNNEL_ENCAP_IP6
604+
}
605+
606+
func (e *IP6tnlEncap) Decode(buf []byte) error {
607+
attrs, err := nl.ParseRouteAttr(buf)
608+
if err != nil {
609+
return err
610+
}
611+
for _, attr := range attrs {
612+
switch attr.Attr.Type {
613+
case nl.LWTUNNEL_IP6_ID:
614+
e.ID = uint64(native.Uint64(attr.Value[0:4]))
615+
case nl.LWTUNNEL_IP6_DST:
616+
e.Dst = net.IP(attr.Value[:])
617+
case nl.LWTUNNEL_IP6_SRC:
618+
e.Src = net.IP(attr.Value[:])
619+
case nl.LWTUNNEL_IP6_HOPLIMIT:
620+
e.Hoplimit = attr.Value[0]
621+
case nl.LWTUNNEL_IP6_TC:
622+
// e.TC = attr.Value[0]
623+
err = fmt.Errorf("decoding TC in IP6tnlEncap is not supported")
624+
case nl.LWTUNNEL_IP6_FLAGS:
625+
// e.Flags = uint16(native.Uint16(attr.Value[0:2]))
626+
err = fmt.Errorf("decoding FLAG in IP6tnlEncap is not supported")
627+
case nl.LWTUNNEL_IP6_PAD:
628+
err = fmt.Errorf("decoding PAD in IP6tnlEncap is not supported")
629+
case nl.LWTUNNEL_IP6_OPTS:
630+
err = fmt.Errorf("decoding OPTS in IP6tnlEncap is not supported")
631+
}
632+
}
633+
return err
634+
}
635+
636+
func (e *IP6tnlEncap) Encode() ([]byte, error) {
637+
638+
final := []byte{}
639+
640+
resID := make([]byte, 12)
641+
native.PutUint16(resID, 12) // 2+2+8
642+
native.PutUint16(resID[2:], nl.LWTUNNEL_IP6_ID)
643+
native.PutUint64(resID[4:], 0)
644+
final = append(final, resID...)
645+
646+
resDst := make([]byte, 4)
647+
native.PutUint16(resDst, 20) // 2+2+16
648+
native.PutUint16(resDst[2:], nl.LWTUNNEL_IP6_DST)
649+
resDst = append(resDst, e.Dst...)
650+
final = append(final, resDst...)
651+
652+
resSrc := make([]byte, 4)
653+
native.PutUint16(resSrc, 20)
654+
native.PutUint16(resSrc[2:], nl.LWTUNNEL_IP6_SRC)
655+
resSrc = append(resSrc, e.Src...)
656+
final = append(final, resSrc...)
657+
658+
// resTc := make([]byte, 5)
659+
// native.PutUint16(resTc, 5)
660+
// native.PutUint16(resTc[2:], nl.LWTUNNEL_IP6_TC)
661+
// resTc[4] = e.TC
662+
// final = append(final,resTc...)
663+
664+
resHops := make([]byte, 5)
665+
native.PutUint16(resHops, 5)
666+
native.PutUint16(resHops[2:], nl.LWTUNNEL_IP6_HOPLIMIT)
667+
resHops[4] = e.Hoplimit
668+
final = append(final, resHops...)
669+
670+
// resFlags := make([]byte, 6)
671+
// native.PutUint16(resFlags, 6)
672+
// native.PutUint16(resFlags[2:], nl.LWTUNNEL_IP6_FLAGS)
673+
// native.PutUint16(resFlags[4:], e.Flags)
674+
// final = append(final,resFlags...)
675+
676+
return final, nil
677+
}
678+
679+
func (e *IP6tnlEncap) String() string {
680+
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)
681+
}
682+
683+
func (e *IP6tnlEncap) Equal(x Encap) bool {
684+
o, ok := x.(*IP6tnlEncap)
685+
if !ok {
686+
return false
687+
}
688+
689+
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 {
690+
return false
691+
}
692+
return true
693+
}
694+
592695
type Via struct {
593696
AddrFamily int
594697
Addr net.IP

route_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,66 @@ func TestMPLSRouteAddDel(t *testing.T) {
11521152

11531153
}
11541154

1155+
func TestIP6tnlRouteAddDel(t *testing.T) {
1156+
_, err := RouteList(nil, FAMILY_V4)
1157+
if err != nil {
1158+
t.Fatal(err)
1159+
}
1160+
1161+
tearDown := setUpNetlinkTest(t)
1162+
defer tearDown()
1163+
1164+
// get loopback interface
1165+
link, err := LinkByName("lo")
1166+
if err != nil {
1167+
t.Fatal(err)
1168+
}
1169+
1170+
// bring the interface up
1171+
if err := LinkSetUp(link); err != nil {
1172+
t.Fatal(err)
1173+
}
1174+
1175+
_, dst, err := net.ParseCIDR("192.168.99.0/24")
1176+
if err != nil {
1177+
t.Fatalf("cannot parse destination prefix: %v", err)
1178+
}
1179+
1180+
encap := IP6tnlEncap{
1181+
Dst: net.ParseIP("2001:db8::"),
1182+
Src: net.ParseIP("::"),
1183+
}
1184+
1185+
route := &Route{
1186+
LinkIndex: link.Attrs().Index,
1187+
Dst: dst,
1188+
Encap: &encap,
1189+
}
1190+
1191+
if err := RouteAdd(route); err != nil {
1192+
t.Fatalf("Cannot add route: %v", err)
1193+
}
1194+
routes, err := RouteList(link, FAMILY_V4)
1195+
if err != nil {
1196+
t.Fatal(err)
1197+
}
1198+
if len(routes) != 1 {
1199+
t.Fatal("Route not added properly")
1200+
}
1201+
1202+
if err := RouteDel(route); err != nil {
1203+
t.Fatal(err)
1204+
}
1205+
routes, err = RouteList(link, FAMILY_V4)
1206+
if err != nil {
1207+
t.Fatal(err)
1208+
}
1209+
if len(routes) != 0 {
1210+
t.Fatal("Route not removed properly")
1211+
}
1212+
1213+
}
1214+
11551215
func TestRouteEqual(t *testing.T) {
11561216
mplsDst := 100
11571217
seg6encap := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP}

0 commit comments

Comments
 (0)