Add linux route get oif option.

This option is equivalent to "ip route get ... dev ...", which is useful when the route is multipath.

Signed-off-by: yuwenchao <yuwenchao@qiyi.com>
This commit is contained in:
yuwenchao 2021-06-12 21:36:24 +08:00 committed by Vish (Ishaya) Abrams
parent 533d417a1a
commit f055e5464f
2 changed files with 105 additions and 0 deletions

View File

@ -1308,6 +1308,7 @@ func deserializeRoute(m []byte) (Route, error) {
// RouteGetWithOptions
type RouteGetOptions struct {
Iif string
Oif string
VrfName string
SrcAddr net.IP
}
@ -1374,6 +1375,18 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
req.AddData(nl.NewRtAttr(unix.RTA_IIF, b))
}
if len(options.Oif) > 0 {
link, err := LinkByName(options.Oif)
if err != nil {
return nil, err
}
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}
if options.SrcAddr != nil {
var srcAddr []byte
if family == FAMILY_V4 {

View File

@ -745,6 +745,98 @@ func TestRouteMultiPath(t *testing.T) {
}
}
func TestRouteOifOption(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
// setup two interfaces: eth0, eth1
err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
if err != nil {
t.Fatal(err)
}
link1, err := LinkByName("eth0")
if err != nil {
t.Fatal(err)
}
if err = LinkSetUp(link1); err != nil {
t.Fatal(err)
}
if err = LinkAdd(&Dummy{LinkAttrs{Name: "eth1"}}); err != nil {
t.Fatal(err)
}
link2, err := LinkByName("eth1")
if err != nil {
t.Fatal(err)
}
if err = LinkSetUp(link2); err != nil {
t.Fatal(err)
}
// config ip addresses on interfaces
addr1 := &Addr{
IPNet: &net.IPNet{
IP: net.IPv4(192, 168, 1, 1),
Mask: net.CIDRMask(24, 32),
},
}
if err = AddrAdd(link1, addr1); err != nil {
t.Fatal(err)
}
addr2 := &Addr{
IPNet: &net.IPNet{
IP: net.IPv4(192, 168, 2, 1),
Mask: net.CIDRMask(24, 32),
},
}
if err = AddrAdd(link2, addr2); err != nil {
t.Fatal(err)
}
// add default multipath route
dst := &net.IPNet{
IP: net.IPv4(0, 0, 0, 0),
Mask: net.CIDRMask(0, 32),
}
gw1 := net.IPv4(192, 168, 1, 254)
gw2 := net.IPv4(192, 168, 2, 254)
route := Route{Dst: dst, MultiPath: []*NexthopInfo{{LinkIndex: link1.Attrs().Index,
Gw: gw1}, {LinkIndex: link2.Attrs().Index, Gw: gw2}}}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
// check getting route from specified Oif
dstIP := net.IPv4(10, 1, 1, 1)
routes, err := RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth0"})
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 || routes[0].LinkIndex != link1.Attrs().Index ||
!routes[0].Gw.Equal(gw1) {
t.Fatal("Get route from unmatched interface")
}
routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth1"})
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 || routes[0].LinkIndex != link2.Attrs().Index ||
!routes[0].Gw.Equal(gw2) {
t.Fatal("Get route from unmatched interface")
}
}
func TestFilterDefaultRoute(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()