add protocol, priority, table, type, tos to route

This commit is contained in:
marek-polewski 2015-11-26 16:09:33 +01:00
parent a57a12c1b1
commit dfdad47336
3 changed files with 124 additions and 34 deletions

View File

@ -24,16 +24,19 @@ const (
FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE
) )
// Route represents a netlink route. A route is associated with a link, // Route represents a netlink route.
// has a destination network, an optional source ip, and optional
// gateway. Advanced route parameters and non-main routing tables are
// currently not supported.
type Route struct { type Route struct {
LinkIndex int LinkIndex int
Iif int
Scope Scope Scope Scope
Dst *net.IPNet Dst *net.IPNet
Src net.IP Src net.IP
Gw net.IP Gw net.IP
Protocol int
Priority int
Table int
Type int
Tos int
Flags int Flags int
} }

View File

@ -29,8 +29,6 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil") return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
} }
msg.Scope = uint8(route.Scope)
msg.Flags = uint32(route.Flags)
family := -1 family := -1
var rtAttrs []*nl.RtAttr var rtAttrs []*nl.RtAttr
@ -79,8 +77,34 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
} }
msg.Family = uint8(family) if route.Table > 0 {
if route.Table >= 256 {
msg.Table = syscall.RT_TABLE_UNSPEC
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Table))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b))
} else {
msg.Table = uint8(route.Table)
}
}
if route.Priority > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Priority))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b))
}
if route.Tos > 0 {
msg.Tos = uint8(route.Tos)
}
if route.Protocol > 0 {
msg.Protocol = uint8(route.Protocol)
}
if route.Type > 0 {
msg.Type = uint8(route.Type)
}
msg.Scope = uint8(route.Scope)
msg.Family = uint8(family)
req.AddData(msg) req.AddData(msg)
for _, attr := range rtAttrs { for _, attr := range rtAttrs {
req.AddData(attr) req.AddData(attr)
@ -103,8 +127,8 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
// The list can be filtered by link and ip family. // The list can be filtered by link and ip family.
func RouteList(link Link, family int) ([]Route, error) { func RouteList(link Link, family int) ([]Route, error) {
req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family) infmsg := nl.NewIfInfomsg(family)
req.AddData(msg) req.AddData(infmsg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
if err != nil { if err != nil {
@ -149,14 +173,19 @@ func RouteList(link Link, family int) ([]Route, error) {
// deserializeRoute decodes a binary netlink message into a Route struct // deserializeRoute decodes a binary netlink message into a Route struct
func deserializeRoute(m []byte) (Route, error) { func deserializeRoute(m []byte) (Route, error) {
route := Route{}
msg := nl.DeserializeRtMsg(m) msg := nl.DeserializeRtMsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():]) attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil { if err != nil {
return route, err return Route{}, err
}
route := Route{
Scope: Scope(msg.Scope),
Protocol: int(msg.Protocol),
Table: int(msg.Table),
Type: int(msg.Type),
Tos: int(msg.Tos),
Flags: int(msg.Flags),
} }
route.Scope = Scope(msg.Scope)
route.Flags = int(msg.Flags)
native := nl.NativeEndian() native := nl.NativeEndian()
for _, attr := range attrs { for _, attr := range attrs {
@ -171,8 +200,13 @@ func deserializeRoute(m []byte) (Route, error) {
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
} }
case syscall.RTA_OIF: case syscall.RTA_OIF:
routeIndex := int(native.Uint32(attr.Value[0:4])) route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
route.LinkIndex = routeIndex case syscall.RTA_IIF:
route.Iif = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4]))
} }
} }
return route, nil return route, nil

View File

@ -18,17 +18,19 @@ func TestRouteAddDel(t *testing.T) {
} }
// bring the interface up // bring the interface up
if err = LinkSetUp(link); err != nil { if err := LinkSetUp(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// add a gateway route // add a gateway route
_, dst, err := net.ParseCIDR("192.168.0.0/24") dst := &net.IPNet{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(24, 32),
}
ip := net.ParseIP("127.1.1.1") ip := net.IPv4(127, 1, 1, 1)
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
err = RouteAdd(&route) if err := RouteAdd(&route); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
routes, err := RouteList(link, FAMILY_V4) routes, err := RouteList(link, FAMILY_V4)
@ -36,10 +38,10 @@ func TestRouteAddDel(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if len(routes) != 1 { if len(routes) != 1 {
t.Fatal("Link not added properly") t.Fatal("Route not added properly")
} }
dstIP := net.ParseIP("192.168.0.42") dstIP := net.IPv4(192, 168, 0, 42)
routeToDstIP, err := RouteGet(dstIP) routeToDstIP, err := RouteGet(dstIP)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -48,12 +50,9 @@ func TestRouteAddDel(t *testing.T) {
if len(routeToDstIP) == 0 { if len(routeToDstIP) == 0 {
t.Fatal("Default route not present") t.Fatal("Default route not present")
} }
if err := RouteDel(&route); err != nil {
err = RouteDel(&route)
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
routes, err = RouteList(link, FAMILY_V4) routes, err = RouteList(link, FAMILY_V4)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -122,25 +121,79 @@ func TestRouteSubscribe(t *testing.T) {
} }
// add a gateway route // add a gateway route
_, dst, err := net.ParseCIDR("192.168.0.0/24") dst := &net.IPNet{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(24, 32),
}
ip := net.ParseIP("127.1.1.1") ip := net.IPv4(127, 1, 1, 1)
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
err = RouteAdd(&route) if err := RouteAdd(&route); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) { if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
t.Fatal("Add update not received as expected") t.Fatal("Add update not received as expected")
} }
if err := RouteDel(&route); err != nil {
err = RouteDel(&route)
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) { if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) {
t.Fatal("Del update not received as expected") t.Fatal("Del update not received as expected")
} }
} }
func TestRouteExtraFields(t *testing.T) {
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)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(1, 1, 1, 1),
Mask: net.CIDRMask(32, 32),
}
src := net.IPv4(127, 3, 3, 3)
route := Route{
LinkIndex: link.Attrs().Index,
Dst: dst,
Src: src,
Scope: syscall.RT_SCOPE_LINK,
Priority: 13,
Table: syscall.RT_TABLE_MAIN,
Type: syscall.RTN_UNICAST,
}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
routes, err := RouteList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("Route not added properly")
}
if routes[0].Scope != syscall.RT_SCOPE_LINK {
t.Fatal("Invalid Scope. Route not added properly")
}
if routes[0].Priority != 13 {
t.Fatal("Invalid Priority. Route not added properly")
}
if routes[0].Table != syscall.RT_TABLE_MAIN {
t.Fatal("Invalid Scope. Route not added properly")
}
if routes[0].Type != syscall.RTN_UNICAST {
t.Fatal("Invalid Type. Route not added properly")
}
}