mirror of
https://github.com/vishvananda/netlink
synced 2024-12-24 15:42:41 +00:00
Implement basic route get
functionality
This provides the basic functionality of the iproute2 `route get` command. It allows you to query netlink for the route to a destination IP.Net While implementing I noticed that the `s.Receive()` function was hanging after the netlink response was recieved, so I added an additional clause to break from the loop and return the decoded message if the NLM_F_MULTI flag is not set. Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
This commit is contained in:
parent
7f10b9c2b8
commit
80a80badbd
@ -248,6 +248,9 @@ done:
|
||||
continue
|
||||
}
|
||||
res = append(res, m.Data)
|
||||
if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
|
||||
break done
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
|
@ -164,3 +164,62 @@ func RouteList(link Link, family int) ([]Route, error) {
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// RouteGet gets a route to a specific destination from the host system.
|
||||
// Equivalent to: 'ip route get'.
|
||||
func RouteGet(destination net.IP) ([]Route, error) {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
|
||||
family := nl.GetIPFamily(destination)
|
||||
var destinationData []byte
|
||||
var bitlen uint8
|
||||
if family == FAMILY_V4 {
|
||||
destinationData = destination.To4()
|
||||
bitlen = 32
|
||||
} else {
|
||||
destinationData = destination.To16()
|
||||
bitlen = 128
|
||||
}
|
||||
msg := &nl.RtMsg{}
|
||||
msg.Family = uint8(family)
|
||||
msg.Dst_len = bitlen
|
||||
req.AddData(msg)
|
||||
|
||||
rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
|
||||
req.AddData(rtaDst)
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
native := nl.NativeEndian()
|
||||
res := make([]Route, 0)
|
||||
for _, m := range msgs {
|
||||
msg := nl.DeserializeRtMsg(m)
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
route := Route{}
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.RTA_GATEWAY:
|
||||
route.Gw = net.IP(attr.Value)
|
||||
case syscall.RTA_PREFSRC:
|
||||
route.Src = net.IP(attr.Value)
|
||||
case syscall.RTA_DST:
|
||||
route.Dst = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.RTA_OIF:
|
||||
routeIndex := int(native.Uint32(attr.Value[0:4]))
|
||||
route.LinkIndex = routeIndex
|
||||
}
|
||||
}
|
||||
res = append(res, route)
|
||||
}
|
||||
return res, nil
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,17 @@ func TestRouteAddDel(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(routes) != 1 {
|
||||
t.Fatal("Link not removed properly")
|
||||
t.Fatal("Link not added properly")
|
||||
}
|
||||
|
||||
dstIP := net.ParseIP("192.168.0.42")
|
||||
routeToDstIP, err := RouteGet(dstIP)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(routeToDstIP) == 0 {
|
||||
t.Fatal("Default route not present")
|
||||
}
|
||||
|
||||
err = RouteDel(&route)
|
||||
|
Loading…
Reference in New Issue
Block a user