From 4e9cdead09a638dea5a6a5cda2541a1f875d704e Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Fri, 2 Oct 2020 10:52:24 -0400 Subject: [PATCH] rtnetlink: add RouteMetrics nested attributes within RouteAttributes (#81) Signed-off-by: Matt Layher --- go.mod | 1 + go.sum | 2 ++ internal/unix/types_linux.go | 5 ++++ internal/unix/types_other.go | 5 ++++ route.go | 55 +++++++++++++++++++++++++++++++++++- route_test.go | 23 +++++++++------ 6 files changed, 82 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 3bf5aec..7f6f1a1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/jsimonetti/rtnetlink go 1.12 require ( + github.com/google/go-cmp v0.5.2 github.com/mdlayher/netlink v1.1.0 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 ) diff --git a/go.sum b/go.sum index a466ad7..6fd77eb 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= diff --git a/internal/unix/types_linux.go b/internal/unix/types_linux.go index 7c82f40..2ccf386 100644 --- a/internal/unix/types_linux.go +++ b/internal/unix/types_linux.go @@ -72,6 +72,11 @@ const ( RTA_TABLE = linux.RTA_TABLE RTA_MARK = linux.RTA_MARK RTA_EXPIRES = linux.RTA_EXPIRES + RTA_METRICS = linux.RTA_METRICS + RTAX_ADVMSS = linux.RTAX_ADVMSS + RTAX_FEATURES = linux.RTAX_FEATURES + RTAX_INITCWND = linux.RTAX_INITCWND + RTAX_MTU = linux.RTAX_MTU NTF_PROXY = linux.NTF_PROXY RTN_UNICAST = linux.RTN_UNICAST RT_TABLE_MAIN = linux.RT_TABLE_MAIN diff --git a/internal/unix/types_other.go b/internal/unix/types_other.go index 398f9dc..bd5b5a7 100644 --- a/internal/unix/types_other.go +++ b/internal/unix/types_other.go @@ -68,6 +68,11 @@ const ( RTA_TABLE = 0xf RTA_MARK = 0x10 RTA_EXPIRES = 0x17 + RTA_METRICS = 0x8 + RTAX_ADVMSS = 0x8 + RTAX_FEATURES = 0xc + RTAX_INITCWND = 0xb + RTAX_MTU = 0x2 NTF_PROXY = 0x8 RTN_UNICAST = 0x1 RT_TABLE_MAIN = 0xfe diff --git a/route.go b/route.go index a4db32c..fb7fe5e 100644 --- a/route.go +++ b/route.go @@ -178,6 +178,7 @@ type RouteAttributes struct { Table uint32 Mark uint32 Expires *uint32 + Metrics *RouteMetrics } func (a *RouteAttributes) decode(ad *netlink.AttributeDecoder) error { @@ -215,10 +216,13 @@ func (a *RouteAttributes) decode(ad *netlink.AttributeDecoder) error { case unix.RTA_EXPIRES: timeout := ad.Uint32() a.Expires = &timeout + case unix.RTA_METRICS: + a.Metrics = &RouteMetrics{} + ad.Nested(a.Metrics.decode) } } - return nil + return ad.Err() } func (a *RouteAttributes) encode(ae *netlink.AttributeEncoder) error { @@ -273,5 +277,54 @@ func (a *RouteAttributes) encode(ae *netlink.AttributeEncoder) error { ae.Uint32(unix.RTA_EXPIRES, *a.Expires) } + if a.Metrics != nil { + ae.Nested(unix.RTA_METRICS, a.Metrics.encode) + } + + return nil +} + +type RouteMetrics struct { + AdvMSS uint32 + Features uint32 + InitCwnd uint32 + MTU uint32 +} + +func (rm *RouteMetrics) decode(ad *netlink.AttributeDecoder) error { + for ad.Next() { + switch ad.Type() { + case unix.RTAX_ADVMSS: + rm.AdvMSS = ad.Uint32() + case unix.RTAX_FEATURES: + rm.Features = ad.Uint32() + case unix.RTAX_INITCWND: + rm.InitCwnd = ad.Uint32() + case unix.RTAX_MTU: + rm.MTU = ad.Uint32() + } + } + + // ad.Err call handled by Nested method in calling attribute decoder. + return nil +} + +func (rm *RouteMetrics) encode(ae *netlink.AttributeEncoder) error { + if rm.AdvMSS != 0 { + ae.Uint32(unix.RTAX_ADVMSS, rm.AdvMSS) + } + + if rm.Features != 0 { + ae.Uint32(unix.RTAX_FEATURES, rm.Features) + } + + if rm.InitCwnd != 0 { + ae.Uint32(unix.RTAX_INITCWND, rm.InitCwnd) + } + + if rm.MTU != 0 { + ae.Uint32(unix.RTAX_MTU, rm.MTU) + } + return nil } diff --git a/route_test.go b/route_test.go index c407537..06f2e7c 100644 --- a/route_test.go +++ b/route_test.go @@ -1,11 +1,10 @@ package rtnetlink import ( - "bytes" "net" - "reflect" "testing" + "github.com/google/go-cmp/cmp" "github.com/jsimonetti/rtnetlink/internal/unix" ) @@ -49,6 +48,9 @@ func TestRouteMessageMarshalBinary(t *testing.T) { Gateway: net.ParseIP("10.10.10.10"), OutIface: 4, Expires: &timeout, + Metrics: &RouteMetrics{ + MTU: 1500, + }, }, }, b: []byte{ @@ -57,7 +59,8 @@ func TestRouteMessageMarshalBinary(t *testing.T) { 0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x08, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, - 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x80, + 0x08, 0x00, 0x02, 0x00, 0xdc, 0x05, 0x00, 0x00, }, }, } @@ -73,8 +76,8 @@ func TestRouteMessageMarshalBinary(t *testing.T) { return } - if want, got := tt.b, b; !bytes.Equal(want, got) { - t.Fatalf("unexpected Message bytes:\n- want: [%# x]\n- got: [%# x]", want, got) + if diff := cmp.Diff(tt.b, b); diff != "" { + t.Fatalf("unexpected RouteMessage bytes (-want +got):\n%s", diff) } }) } @@ -121,7 +124,8 @@ func TestRouteMessageUnmarshalBinary(t *testing.T) { 0x0a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0a, 0x64, 0x0a, 0x01, 0x08, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, - 0xe8, 0x03, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x80, + 0x08, 0x00, 0x02, 0x00, 0xdc, 0x05, 0x00, 0x00, }, m: &RouteMessage{ Family: 2, @@ -135,6 +139,9 @@ func TestRouteMessageUnmarshalBinary(t *testing.T) { Src: net.IP{0x0a, 0x64, 0x0a, 0x01}, OutIface: 5, Expires: &timeout, + Metrics: &RouteMetrics{ + MTU: 1500, + }, }, }, }, @@ -152,8 +159,8 @@ func TestRouteMessageUnmarshalBinary(t *testing.T) { return } - if want, got := tt.m, m; !reflect.DeepEqual(want, got) { - t.Fatalf("unexpected Message:\n- want: %#v\n- got: %#v", want, got) + if diff := cmp.Diff(tt.m, m); diff != "" { + t.Fatalf("unexpected RouteMessage (-want +got):\n%s", diff) } }) }