Add IifIndex option to RouteGetOptions

This commit is contained in:
Hasan Mahmood 2022-05-04 12:23:23 -05:00 committed by Alessandro Boch
parent ec7bcb248e
commit 42d9a053ea
2 changed files with 150 additions and 1 deletions

View File

@ -1424,6 +1424,7 @@ func deserializeRoute(m []byte) (Route, error) {
// RouteGetWithOptions
type RouteGetOptions struct {
Iif string
IifIndex int
Oif string
VrfName string
SrcAddr net.IP
@ -1485,14 +1486,21 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}
iifIndex := 0
if len(options.Iif) > 0 {
link, err := LinkByName(options.Iif)
if err != nil {
return nil, err
}
iifIndex = link.Attrs().Index
} else if options.IifIndex > 0 {
iifIndex = options.IifIndex
}
if iifIndex > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
native.PutUint32(b, uint32(iifIndex))
req.AddData(nl.NewRtAttr(unix.RTA_IIF, b))
}

View File

@ -6,6 +6,7 @@ package netlink
import (
"net"
"os"
"runtime"
"strconv"
"testing"
"time"
@ -931,6 +932,146 @@ func TestRouteMultiPath(t *testing.T) {
}
}
func TestRouteIifOption(t *testing.T) {
skipUnlessRoot(t)
runtime.LockOSThread()
t.Cleanup(runtime.UnlockOSThread)
rootNs, err := netns.GetFromPid(1)
if err != nil {
t.Fatalf("could not get root ns: %s", err)
}
t.Cleanup(func() { rootNs.Close() })
rootHdl, err := NewHandleAt(rootNs)
if err != nil {
t.Fatalf("could not create handle for root ns: %s", err)
}
t.Cleanup(func() { rootHdl.Close() })
// setup a veth pair across two namespaces
// veth1 (2.2.2.3/24) <-> veth2 (2.2.2.4/24)
// peer ns for veth pair
ns, err := netns.New()
if err != nil {
t.Fatalf("could not create new ns: %s", err)
}
t.Cleanup(func() { ns.Close() })
l := &Veth{
LinkAttrs: LinkAttrs{Name: "veth1"},
PeerName: "veth2",
PeerNamespace: NsFd(ns),
}
if err = rootHdl.LinkAdd(l); err != nil {
t.Fatalf("could not add veth interface: %s", err)
}
t.Cleanup(func() { rootHdl.LinkDel(l) })
ve1, err := rootHdl.LinkByName("veth1")
if err != nil {
t.Fatalf("could not get link veth1: %s", err)
}
err = rootHdl.AddrAdd(ve1, &Addr{IPNet: &net.IPNet{IP: net.ParseIP("2.2.2.3"), Mask: net.CIDRMask(24, 32)}})
if err != nil {
t.Fatalf("could not set address for veth1: %s", err)
}
nh, err := NewHandleAt(ns)
if err != nil {
t.Fatalf("could not get handle for ns %+v: %s", ns, err)
}
t.Cleanup(func() { nh.Close() })
ve2, err := nh.LinkByName("veth2")
if err != nil {
t.Fatalf("could not get link veth2: %s", err)
}
err = nh.AddrAdd(ve2, &Addr{IPNet: &net.IPNet{IP: net.ParseIP("2.2.2.4"), Mask: net.CIDRMask(24, 32)}})
if err != nil {
t.Fatalf("could set address for veth2: %s", err)
}
if err = rootHdl.LinkSetUp(ve1); err != nil {
t.Fatalf("could not set veth1 up: %s", err)
}
if err = nh.LinkSetUp(ve2); err != nil {
t.Fatalf("could not set veth2 up: %s", err)
}
err = nh.RouteAdd(&Route{
Dst: &net.IPNet{
IP: net.IPv4zero,
Mask: net.CIDRMask(0, 32),
},
Gw: net.ParseIP("2.2.2.3"),
})
if err != nil {
t.Fatalf("could not add default route to ns: %s", err)
}
// setup finished, now do the actual test
_, err = rootHdl.RouteGetWithOptions(net.ParseIP("8.8.8.8"), &RouteGetOptions{
SrcAddr: net.ParseIP("2.2.2.4"),
})
if err == nil {
t.Fatal("route get should have resulted in error but did not")
}
testWithOptions := func(opts *RouteGetOptions) {
routes, err := rootHdl.RouteGetWithOptions(net.ParseIP("8.8.8.8"), opts)
if err != nil {
t.Fatalf("could not get route: %s", err)
}
if len(routes) != 1 {
t.Fatalf("did not get exactly one route, routes: %+v", routes)
}
// should be the default route
r, err := rootHdl.RouteGet(net.ParseIP("8.8.8.8"))
if err != nil {
t.Fatalf("could not get default route for 8.8.8.8: %s", err)
}
if len(r) != 1 {
t.Fatalf("did not get exactly one route, routes: %+v", routes)
}
if !routes[0].Gw.Equal(r[0].Gw) {
t.Fatalf("wrong gateway in route: expected: %s, got: %s", r[0].Gw, routes[0].Gw)
}
if routes[0].LinkIndex != r[0].LinkIndex {
t.Fatalf("wrong link in route: expected: %d, got: %d", r[0].LinkIndex, routes[0].LinkIndex)
}
}
t.Run("with iif", func(t *testing.T) {
testWithOptions(&RouteGetOptions{
SrcAddr: net.ParseIP("2.2.2.4"),
Iif: "veth1",
})
})
t.Run("with iifIndex", func(t *testing.T) {
testWithOptions(&RouteGetOptions{
SrcAddr: net.ParseIP("2.2.2.4"),
IifIndex: ve1.Attrs().Index,
})
})
t.Run("with iif and iifIndex", func(t *testing.T) {
testWithOptions(&RouteGetOptions{
SrcAddr: net.ParseIP("2.2.2.4"),
Iif: "veth1",
IifIndex: ve2.Attrs().Index, // Iif will supersede here
})
})
}
func TestRouteOifOption(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()