Skip to content

Commit 5da81c2

Browse files
committed
Adding support for RTA_VIA
Signed-off-by: Steve Shaw <shaw38@gmail.com>
1 parent fb953eb commit 5da81c2

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

route.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Route struct {
4545
MPLSDst *int
4646
NewDst Destination
4747
Encap Encap
48+
Via Destination
4849
MTU int
4950
Window int
5051
Rtt int
@@ -79,6 +80,9 @@ func (r Route) String() string {
7980
if r.Encap != nil {
8081
elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap))
8182
}
83+
if r.Via != nil {
84+
elems = append(elems, fmt.Sprintf("Via: %s", r.Via))
85+
}
8286
elems = append(elems, fmt.Sprintf("Src: %s", r.Src))
8387
if len(r.MultiPath) > 0 {
8488
elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
@@ -107,6 +111,7 @@ func (r Route) Equal(x Route) bool {
107111
r.Flags == x.Flags &&
108112
(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
109113
(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&
114+
(r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) &&
110115
(r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap)))
111116
}
112117

@@ -136,6 +141,7 @@ type NexthopInfo struct {
136141
Flags int
137142
NewDst Destination
138143
Encap Encap
144+
Via Destination
139145
}
140146

141147
func (n *NexthopInfo) String() string {
@@ -147,6 +153,9 @@ func (n *NexthopInfo) String() string {
147153
if n.Encap != nil {
148154
elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap))
149155
}
156+
if n.Via != nil {
157+
elems = append(elems, fmt.Sprintf("Via: %s", n.Via))
158+
}
150159
elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
151160
elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw))
152161
elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))

route_linux.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package netlink
22

33
import (
4+
"bytes"
5+
"encoding/binary"
46
"fmt"
57
"net"
68
"strings"
@@ -446,6 +448,62 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
446448
return true
447449
}
448450

451+
type Via struct {
452+
AddrFamily int
453+
Addr net.IP
454+
}
455+
456+
func (v *Via) Equal(x Destination) bool {
457+
o, ok := x.(*Via)
458+
if !ok {
459+
return false
460+
}
461+
if v.AddrFamily == x.Family() && v.Addr.Equal(o.Addr) {
462+
return true
463+
}
464+
return false
465+
}
466+
467+
func (v *Via) String() string {
468+
return fmt.Sprintf("Family: %d, Address: %s", v.AddrFamily, v.Addr.String())
469+
}
470+
471+
func (v *Via) Family() int {
472+
return v.AddrFamily
473+
}
474+
475+
func (v *Via) Encode() ([]byte, error) {
476+
buf := &bytes.Buffer{}
477+
err := binary.Write(buf, native, uint16(v.AddrFamily))
478+
if err != nil {
479+
return nil, err
480+
}
481+
err = binary.Write(buf, native, v.Addr)
482+
if err != nil {
483+
return nil, err
484+
}
485+
return buf.Bytes(), nil
486+
}
487+
488+
func (v *Via) Decode(b []byte) error {
489+
native := nl.NativeEndian()
490+
if len(b) < 6 {
491+
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
492+
}
493+
v.AddrFamily = int(native.Uint16(b[0:2]))
494+
if v.AddrFamily == nl.FAMILY_V4 {
495+
v.Addr = net.IP(b[2:6])
496+
return nil
497+
} else if v.AddrFamily == nl.FAMILY_V6 {
498+
if len(b) < 18 {
499+
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
500+
}
501+
v.Addr = net.IP(b[2:])
502+
return nil
503+
}
504+
return fmt.Errorf("decoding failed: address family %d unknown", v.AddrFamily)
505+
}
506+
449507
// RouteAdd will add a route to the system.
450508
// Equivalent to: `ip route add $route`
451509
func RouteAdd(route *Route) error {
@@ -567,6 +625,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
567625
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
568626
}
569627

628+
if route.Via != nil {
629+
buf, err := route.Via.Encode()
630+
if err != nil {
631+
return fmt.Errorf("failed to encode RTA_VIA: %v", err)
632+
}
633+
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf))
634+
}
635+
570636
if len(route.MultiPath) > 0 {
571637
buf := []byte{}
572638
for _, nh := range route.MultiPath {
@@ -609,6 +675,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
609675
}
610676
children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
611677
}
678+
if nh.Via != nil {
679+
buf, err := nh.Via.Encode()
680+
if err != nil {
681+
return err
682+
}
683+
children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf))
684+
}
612685
rtnh.Children = children
613686
buf = append(buf, rtnh.Serialize()...)
614687
}
@@ -907,6 +980,12 @@ func deserializeRoute(m []byte) (Route, error) {
907980
encapType = attr
908981
case unix.RTA_ENCAP:
909982
encap = attr
983+
case unix.RTA_VIA:
984+
d := &Via{}
985+
if err := d.Decode(attr.Value); err != nil {
986+
return nil, nil, err
987+
}
988+
info.Via = d
910989
}
911990
}
912991

@@ -944,6 +1023,12 @@ func deserializeRoute(m []byte) (Route, error) {
9441023
return route, err
9451024
}
9461025
route.NewDst = d
1026+
case unix.RTA_VIA:
1027+
v := &Via{}
1028+
if err := v.Decode(attr.Value); err != nil {
1029+
return route, err
1030+
}
1031+
route.Via = v
9471032
case unix.RTA_ENCAP_TYPE:
9481033
encapType = attr
9491034
case unix.RTA_ENCAP:

route_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,3 +1339,69 @@ func TestMTURouteAddDel(t *testing.T) {
13391339
t.Fatal("Route not removed properly")
13401340
}
13411341
}
1342+
1343+
func TestRouteViaAddDel(t *testing.T) {
1344+
minKernelRequired(t, 5, 4)
1345+
tearDown := setUpNetlinkTest(t)
1346+
defer tearDown()
1347+
1348+
_, err := RouteList(nil, FAMILY_V4)
1349+
if err != nil {
1350+
t.Fatal(err)
1351+
}
1352+
1353+
link, err := LinkByName("lo")
1354+
if err != nil {
1355+
t.Fatal(err)
1356+
}
1357+
1358+
if err := LinkSetUp(link); err != nil {
1359+
t.Fatal(err)
1360+
}
1361+
1362+
route := &Route{
1363+
LinkIndex: link.Attrs().Index,
1364+
Dst: &net.IPNet{
1365+
IP: net.IPv4(192, 168, 0, 0),
1366+
Mask: net.CIDRMask(24, 32),
1367+
},
1368+
MultiPath: []*NexthopInfo{
1369+
{
1370+
LinkIndex: link.Attrs().Index,
1371+
Via: &Via{
1372+
AddrFamily: FAMILY_V6,
1373+
Addr: net.ParseIP("2001::1"),
1374+
},
1375+
},
1376+
},
1377+
}
1378+
1379+
if err := RouteAdd(route); err != nil {
1380+
t.Fatalf("route: %v, err: %v", route, err)
1381+
}
1382+
1383+
routes, err := RouteList(link, FAMILY_V4)
1384+
if err != nil {
1385+
t.Fatal(err)
1386+
}
1387+
if len(routes) != 1 {
1388+
t.Fatal("Route not added properly")
1389+
}
1390+
1391+
got := routes[0].Via
1392+
want := route.MultiPath[0].Via
1393+
if !want.Equal(got) {
1394+
t.Fatalf("Route Via attribute does not match; got: %s, want: %s", got, want)
1395+
}
1396+
1397+
if err := RouteDel(route); err != nil {
1398+
t.Fatal(err)
1399+
}
1400+
routes, err = RouteList(link, FAMILY_V4)
1401+
if err != nil {
1402+
t.Fatal(err)
1403+
}
1404+
if len(routes) != 0 {
1405+
t.Fatal("Route not removed properly")
1406+
}
1407+
}

0 commit comments

Comments
 (0)