github.com/vishvananda/netlink@v1.3.0/route_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package netlink
     5  
     6  import (
     7  	"net"
     8  	"os"
     9  	"runtime"
    10  	"strconv"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/vishvananda/netlink/nl"
    15  	"github.com/vishvananda/netns"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  func TestRouteAddDel(t *testing.T) {
    20  	tearDown := setUpNetlinkTest(t)
    21  	defer tearDown()
    22  
    23  	// get loopback interface
    24  	link, err := LinkByName("lo")
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  
    29  	// bring the interface up
    30  	if err := LinkSetUp(link); err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	// add a gateway route
    35  	dst := &net.IPNet{
    36  		IP:   net.IPv4(192, 168, 0, 0),
    37  		Mask: net.CIDRMask(24, 32),
    38  	}
    39  
    40  	ip := net.IPv4(127, 1, 1, 1)
    41  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
    42  	if err := RouteAdd(&route); err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	routes, err := RouteList(link, FAMILY_V4)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	if len(routes) != 1 {
    50  		t.Fatal("Route not added properly")
    51  	}
    52  
    53  	routes, err = RouteList(nil, FAMILY_V4)
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	if len(routes) != 1 {
    58  		t.Fatal("Route not listed properly")
    59  	}
    60  
    61  	dstIP := net.IPv4(192, 168, 0, 42)
    62  	routeToDstIP, err := RouteGet(dstIP)
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  
    67  	if len(routeToDstIP) == 0 {
    68  		t.Fatal("Default route not present")
    69  	}
    70  	if err := RouteDel(&route); err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	routes, err = RouteList(link, FAMILY_V4)
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if len(routes) != 0 {
    78  		t.Fatal("Route not removed properly")
    79  	}
    80  
    81  	// add default route test
    82  	// equiv: default dev lo
    83  	_, defaultDst, _ := net.ParseCIDR("0.0.0.0/0")
    84  	route = Route{Dst: defaultDst, LinkIndex: link.Attrs().Index}
    85  	if err := RouteAdd(&route); err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	routes, err = RouteList(link, FAMILY_V4)
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  	if len(routes) != 1 {
    93  		t.Fatal("Dev default route not listed properly")
    94  	}
    95  	if err := RouteDel(&routes[0]); err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	routes, err = RouteList(link, FAMILY_V4)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	if len(routes) != 0 {
   103  		t.Fatal("Dev default route not removed properly")
   104  	}
   105  
   106  	// equiv: blackhole default
   107  	route = Route{Dst: defaultDst, Type: unix.RTN_BLACKHOLE, Family: FAMILY_V4}
   108  	if err := RouteAdd(&route); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	routes, err = RouteList(nil, FAMILY_V4)
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  	t.Logf("%+v", routes)
   116  
   117  	if len(routes) != 1 {
   118  		t.Fatal("Blackhole default route not listed properly")
   119  	}
   120  
   121  	if err := RouteDel(&routes[0]); err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	routes, err = RouteList(nil, FAMILY_V4)
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	if len(routes) != 0 {
   129  		t.Fatal("Blackhole default route not removed properly")
   130  	}
   131  
   132  	// equiv: prohibit default
   133  	route = Route{Dst: defaultDst, Type: unix.RTN_PROHIBIT}
   134  	if err := RouteAdd(&route); err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	routes, err = RouteList(nil, FAMILY_V4)
   138  	if err != nil {
   139  		t.Fatal(err)
   140  	}
   141  	if len(routes) != 1 {
   142  		t.Fatal("Prohibit default route not listed properly")
   143  	}
   144  
   145  	if err := RouteDel(&routes[0]); err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	routes, err = RouteList(nil, FAMILY_V4)
   149  	if err != nil {
   150  		t.Fatal(err)
   151  	}
   152  	if len(routes) != 0 {
   153  		t.Fatal("Prohibit default route not removed properly")
   154  	}
   155  }
   156  
   157  func TestRoute6AddDel(t *testing.T) {
   158  	tearDown := setUpNetlinkTest(t)
   159  	defer tearDown()
   160  
   161  	// create dummy interface
   162  	// IPv6 route added to loopback interface will be unreachable
   163  	la := NewLinkAttrs()
   164  	la.Name = "dummy_route6"
   165  	la.TxQLen = 1500
   166  	dummy := &Dummy{LinkAttrs: la}
   167  	if err := LinkAdd(dummy); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	// get dummy interface
   172  	link, err := LinkByName("dummy_route6")
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	// bring the interface up
   178  	if err := LinkSetUp(link); err != nil {
   179  		t.Fatal(err)
   180  	}
   181  
   182  	// remember number of routes before adding
   183  	// typically one route (fe80::/64) will be created when dummy_route6 is created
   184  	routes, err := RouteList(link, FAMILY_V6)
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	nroutes := len(routes)
   189  
   190  	// add a gateway route
   191  	dst := &net.IPNet{
   192  		IP:   net.ParseIP("2001:db8::0"),
   193  		Mask: net.CIDRMask(64, 128),
   194  	}
   195  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst}
   196  	if err := RouteAdd(&route); err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	routes, err = RouteList(link, FAMILY_V6)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	if len(routes) != nroutes+1 {
   204  		t.Fatal("Route not added properly")
   205  	}
   206  
   207  	dstIP := net.ParseIP("2001:db8::1")
   208  	routeToDstIP, err := RouteGet(dstIP)
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	// cleanup route
   214  	if len(routeToDstIP) == 0 {
   215  		t.Fatal("Route not present")
   216  	}
   217  	if err := RouteDel(&route); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	routes, err = RouteList(link, FAMILY_V6)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	if len(routes) != nroutes {
   225  		t.Fatal("Route not removed properly")
   226  	}
   227  
   228  	// add a default link route
   229  	_, defaultDst, _ := net.ParseCIDR("::/0")
   230  	route = Route{LinkIndex: link.Attrs().Index, Dst: defaultDst}
   231  	if err := RouteAdd(&route); err != nil {
   232  		t.Fatal(err)
   233  	}
   234  	routes, err = RouteList(link, FAMILY_V6)
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	if len(routes) != nroutes+1 {
   239  		t.Fatal("Default route not added properly")
   240  	}
   241  
   242  	// add a default link route
   243  	for _, route := range routes {
   244  		if route.Dst.String() == defaultDst.String() {
   245  			if err := RouteDel(&route); err != nil {
   246  				t.Fatal(err)
   247  			}
   248  		}
   249  	}
   250  	routes, err = RouteList(link, FAMILY_V6)
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  	if len(routes) != nroutes {
   255  		t.Fatal("Default route not removed properly")
   256  	}
   257  
   258  	// add blackhole default link route
   259  	routes, err = RouteList(nil, FAMILY_V6)
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  	nroutes = len(routes)
   264  
   265  	route = Route{Type: unix.RTN_BLACKHOLE, Dst: defaultDst}
   266  	if err := RouteAdd(&route); err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	routes, err = RouteList(nil, FAMILY_V6)
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	if len(routes) != nroutes+1 {
   274  		t.Fatal("Blackhole default route not added properly")
   275  	}
   276  
   277  	// add blackhole default link route
   278  	for _, route := range routes {
   279  		if ipNetEqual(route.Dst, defaultDst) {
   280  			if err := RouteDel(&route); err != nil {
   281  				t.Fatal(err)
   282  			}
   283  		}
   284  	}
   285  	routes, err = RouteList(nil, FAMILY_V6)
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	if len(routes) != nroutes {
   290  		t.Fatal("Blackhole default route not removed properly")
   291  	}
   292  
   293  	// add prohibit default link route
   294  	routes, err = RouteList(nil, FAMILY_V6)
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  	nroutes = len(routes)
   299  
   300  	route = Route{Type: unix.RTN_BLACKHOLE, Dst: defaultDst}
   301  	if err := RouteAdd(&route); err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	routes, err = RouteList(nil, FAMILY_V6)
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  	if len(routes) != nroutes+1 {
   309  		t.Fatal("Prohibit default route not added properly")
   310  	}
   311  
   312  	// add prohibit default link route
   313  	for _, route := range routes {
   314  		if ipNetEqual(route.Dst, defaultDst) {
   315  			if err := RouteDel(&route); err != nil {
   316  				t.Fatal(err)
   317  			}
   318  		}
   319  	}
   320  	routes, err = RouteList(nil, FAMILY_V6)
   321  	if err != nil {
   322  		t.Fatal(err)
   323  	}
   324  	if len(routes) != nroutes {
   325  		t.Fatal("Prohibit default route not removed properly")
   326  	}
   327  
   328  	// cleanup dummy interface created for the test
   329  	if err := LinkDel(link); err != nil {
   330  		t.Fatal(err)
   331  	}
   332  }
   333  
   334  func TestRouteChange(t *testing.T) {
   335  	tearDown := setUpNetlinkTest(t)
   336  	defer tearDown()
   337  
   338  	// get loopback interface
   339  	link, err := LinkByName("lo")
   340  	if err != nil {
   341  		t.Fatal(err)
   342  	}
   343  
   344  	// bring the interface up
   345  	if err := LinkSetUp(link); err != nil {
   346  		t.Fatal(err)
   347  	}
   348  
   349  	// add a gateway route
   350  	dst := &net.IPNet{
   351  		IP:   net.IPv4(192, 168, 0, 0),
   352  		Mask: net.CIDRMask(24, 32),
   353  	}
   354  
   355  	ip := net.IPv4(127, 1, 1, 1)
   356  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   357  
   358  	if err := RouteChange(&route); err == nil {
   359  		t.Fatal("Route added while it should fail")
   360  	}
   361  
   362  	if err := RouteAdd(&route); err != nil {
   363  		t.Fatal(err)
   364  	}
   365  	routes, err := RouteList(link, FAMILY_V4)
   366  	if err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	if len(routes) != 1 {
   370  		t.Fatal("Route not added properly")
   371  	}
   372  
   373  	ip = net.IPv4(127, 1, 1, 2)
   374  	route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   375  	if err := RouteChange(&route); err != nil {
   376  		t.Fatal(err)
   377  	}
   378  
   379  	routes, err = RouteList(link, FAMILY_V4)
   380  	if err != nil {
   381  		t.Fatal(err)
   382  	}
   383  
   384  	if len(routes) != 1 || !routes[0].Src.Equal(ip) {
   385  		t.Fatal("Route not changed properly")
   386  	}
   387  
   388  	if err := RouteDel(&route); err != nil {
   389  		t.Fatal(err)
   390  	}
   391  	routes, err = RouteList(link, FAMILY_V4)
   392  	if err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	if len(routes) != 0 {
   396  		t.Fatal("Route not removed properly")
   397  	}
   398  }
   399  
   400  func TestRouteReplace(t *testing.T) {
   401  	tearDown := setUpNetlinkTest(t)
   402  	defer tearDown()
   403  
   404  	// get loopback interface
   405  	link, err := LinkByName("lo")
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	// bring the interface up
   411  	if err := LinkSetUp(link); err != nil {
   412  		t.Fatal(err)
   413  	}
   414  
   415  	// add a gateway route
   416  	dst := &net.IPNet{
   417  		IP:   net.IPv4(192, 168, 0, 0),
   418  		Mask: net.CIDRMask(24, 32),
   419  	}
   420  
   421  	ip := net.IPv4(127, 1, 1, 1)
   422  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   423  	if err := RouteAdd(&route); err != nil {
   424  		t.Fatal(err)
   425  	}
   426  	routes, err := RouteList(link, FAMILY_V4)
   427  	if err != nil {
   428  		t.Fatal(err)
   429  	}
   430  	if len(routes) != 1 {
   431  		t.Fatal("Route not added properly")
   432  	}
   433  
   434  	ip = net.IPv4(127, 1, 1, 2)
   435  	route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   436  	if err := RouteReplace(&route); err != nil {
   437  		t.Fatal(err)
   438  	}
   439  
   440  	routes, err = RouteList(link, FAMILY_V4)
   441  	if err != nil {
   442  		t.Fatal(err)
   443  	}
   444  
   445  	if len(routes) != 1 || !routes[0].Src.Equal(ip) {
   446  		t.Fatal("Route not replaced properly")
   447  	}
   448  
   449  	if err := RouteDel(&route); err != nil {
   450  		t.Fatal(err)
   451  	}
   452  	routes, err = RouteList(link, FAMILY_V4)
   453  	if err != nil {
   454  		t.Fatal(err)
   455  	}
   456  	if len(routes) != 0 {
   457  		t.Fatal("Route not removed properly")
   458  	}
   459  }
   460  
   461  func TestRouteAppend(t *testing.T) {
   462  	tearDown := setUpNetlinkTest(t)
   463  	defer tearDown()
   464  
   465  	// get loopback interface
   466  	link, err := LinkByName("lo")
   467  	if err != nil {
   468  		t.Fatal(err)
   469  	}
   470  
   471  	// bring the interface up
   472  	if err := LinkSetUp(link); err != nil {
   473  		t.Fatal(err)
   474  	}
   475  
   476  	// add a gateway route
   477  	dst := &net.IPNet{
   478  		IP:   net.IPv4(192, 168, 0, 0),
   479  		Mask: net.CIDRMask(24, 32),
   480  	}
   481  
   482  	ip := net.IPv4(127, 1, 1, 1)
   483  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   484  	if err := RouteAdd(&route); err != nil {
   485  		t.Fatal(err)
   486  	}
   487  	routes, err := RouteList(link, FAMILY_V4)
   488  	if err != nil {
   489  		t.Fatal(err)
   490  	}
   491  	if len(routes) != 1 {
   492  		t.Fatal("Route not added properly")
   493  	}
   494  
   495  	ip = net.IPv4(127, 1, 1, 2)
   496  	route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   497  	if err := RouteAppend(&route); err != nil {
   498  		t.Fatal(err)
   499  	}
   500  
   501  	routes, err = RouteList(link, FAMILY_V4)
   502  	if err != nil {
   503  		t.Fatal(err)
   504  	}
   505  
   506  	if len(routes) != 2 || !routes[1].Src.Equal(ip) {
   507  		t.Fatal("Route not append properly")
   508  	}
   509  
   510  	if err := RouteDel(&routes[0]); err != nil {
   511  		t.Fatal(err)
   512  	}
   513  	if err := RouteDel(&routes[1]); err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	routes, err = RouteList(link, FAMILY_V4)
   517  	if err != nil {
   518  		t.Fatal(err)
   519  	}
   520  	if len(routes) != 0 {
   521  		t.Fatal("Route not removed properly")
   522  	}
   523  }
   524  
   525  func TestRouteAddIncomplete(t *testing.T) {
   526  	tearDown := setUpNetlinkTest(t)
   527  	defer tearDown()
   528  
   529  	// get loopback interface
   530  	link, err := LinkByName("lo")
   531  	if err != nil {
   532  		t.Fatal(err)
   533  	}
   534  
   535  	// bring the interface up
   536  	if err = LinkSetUp(link); err != nil {
   537  		t.Fatal(err)
   538  	}
   539  
   540  	route := Route{LinkIndex: link.Attrs().Index}
   541  	if err := RouteAdd(&route); err == nil {
   542  		t.Fatal("Adding incomplete route should fail")
   543  	}
   544  }
   545  
   546  // expectRouteUpdate returns whether the expected updated is received within one minute.
   547  func expectRouteUpdate(ch <-chan RouteUpdate, t, f uint16, dst net.IP) bool {
   548  	for {
   549  		timeout := time.After(time.Minute)
   550  		select {
   551  		case update := <-ch:
   552  			if update.Type == t &&
   553  				update.NlFlags == f &&
   554  				update.Route.Dst != nil &&
   555  				update.Route.Dst.IP.Equal(dst) {
   556  				return true
   557  			}
   558  		case <-timeout:
   559  			return false
   560  		}
   561  	}
   562  }
   563  
   564  func TestRouteSubscribe(t *testing.T) {
   565  	tearDown := setUpNetlinkTest(t)
   566  	defer tearDown()
   567  
   568  	ch := make(chan RouteUpdate)
   569  	done := make(chan struct{})
   570  	defer close(done)
   571  	if err := RouteSubscribe(ch, done); err != nil {
   572  		t.Fatal(err)
   573  	}
   574  
   575  	// get loopback interface
   576  	link, err := LinkByName("lo")
   577  	if err != nil {
   578  		t.Fatal(err)
   579  	}
   580  
   581  	// bring the interface up
   582  	if err = LinkSetUp(link); err != nil {
   583  		t.Fatal(err)
   584  	}
   585  
   586  	// add a gateway route
   587  	dst := &net.IPNet{
   588  		IP:   net.IPv4(192, 168, 0, 0),
   589  		Mask: net.CIDRMask(24, 32),
   590  	}
   591  
   592  	ip := net.IPv4(127, 1, 1, 1)
   593  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   594  	if err := RouteAdd(&route); err != nil {
   595  		t.Fatal(err)
   596  	}
   597  
   598  	if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, unix.NLM_F_EXCL|unix.NLM_F_CREATE, dst.IP) {
   599  		t.Fatal("Add update not received as expected")
   600  	}
   601  	if err := RouteDel(&route); err != nil {
   602  		t.Fatal(err)
   603  	}
   604  	if !expectRouteUpdate(ch, unix.RTM_DELROUTE, 0, dst.IP) {
   605  		t.Fatal("Del update not received as expected")
   606  	}
   607  }
   608  
   609  func TestRouteSubscribeWithOptions(t *testing.T) {
   610  	tearDown := setUpNetlinkTest(t)
   611  	defer tearDown()
   612  
   613  	ch := make(chan RouteUpdate)
   614  	done := make(chan struct{})
   615  	defer close(done)
   616  	var lastError error
   617  	defer func() {
   618  		if lastError != nil {
   619  			t.Fatalf("Fatal error received during subscription: %v", lastError)
   620  		}
   621  	}()
   622  	if err := RouteSubscribeWithOptions(ch, done, RouteSubscribeOptions{
   623  		ErrorCallback: func(err error) {
   624  			lastError = err
   625  		},
   626  	}); err != nil {
   627  		t.Fatal(err)
   628  	}
   629  
   630  	// get loopback interface
   631  	link, err := LinkByName("lo")
   632  	if err != nil {
   633  		t.Fatal(err)
   634  	}
   635  
   636  	// bring the interface up
   637  	if err = LinkSetUp(link); err != nil {
   638  		t.Fatal(err)
   639  	}
   640  
   641  	// add a gateway route
   642  	dst := &net.IPNet{
   643  		IP:   net.IPv4(192, 168, 0, 0),
   644  		Mask: net.CIDRMask(24, 32),
   645  	}
   646  
   647  	ip := net.IPv4(127, 1, 1, 1)
   648  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   649  	if err := RouteAdd(&route); err != nil {
   650  		t.Fatal(err)
   651  	}
   652  
   653  	if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, unix.NLM_F_EXCL|unix.NLM_F_CREATE, dst.IP) {
   654  		t.Fatal("Add update not received as expected")
   655  	}
   656  }
   657  
   658  func TestRouteSubscribeAt(t *testing.T) {
   659  	skipUnlessRoot(t)
   660  
   661  	// Create an handle on a custom netns
   662  	newNs, err := netns.New()
   663  	if err != nil {
   664  		t.Fatal(err)
   665  	}
   666  	defer newNs.Close()
   667  
   668  	nh, err := NewHandleAt(newNs)
   669  	if err != nil {
   670  		t.Fatal(err)
   671  	}
   672  	defer nh.Close()
   673  
   674  	// Subscribe for Route events on the custom netns
   675  	ch := make(chan RouteUpdate)
   676  	done := make(chan struct{})
   677  	defer close(done)
   678  	if err := RouteSubscribeAt(newNs, ch, done); err != nil {
   679  		t.Fatal(err)
   680  	}
   681  
   682  	// get loopback interface
   683  	link, err := nh.LinkByName("lo")
   684  	if err != nil {
   685  		t.Fatal(err)
   686  	}
   687  
   688  	// bring the interface up
   689  	if err = nh.LinkSetUp(link); err != nil {
   690  		t.Fatal(err)
   691  	}
   692  
   693  	// add a gateway route
   694  	dst := &net.IPNet{
   695  		IP:   net.IPv4(192, 169, 0, 0),
   696  		Mask: net.CIDRMask(24, 32),
   697  	}
   698  
   699  	ip := net.IPv4(127, 100, 1, 1)
   700  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   701  	if err := nh.RouteAdd(&route); err != nil {
   702  		t.Fatal(err)
   703  	}
   704  
   705  	if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, unix.NLM_F_EXCL|unix.NLM_F_CREATE, dst.IP) {
   706  		t.Fatal("Add update not received as expected")
   707  	}
   708  	if err := nh.RouteDel(&route); err != nil {
   709  		t.Fatal(err)
   710  	}
   711  	if !expectRouteUpdate(ch, unix.RTM_DELROUTE, 0, dst.IP) {
   712  		t.Fatal("Del update not received as expected")
   713  	}
   714  }
   715  
   716  func TestRouteSubscribeListExisting(t *testing.T) {
   717  	skipUnlessRoot(t)
   718  
   719  	// Create an handle on a custom netns
   720  	newNs, err := netns.New()
   721  	if err != nil {
   722  		t.Fatal(err)
   723  	}
   724  	defer newNs.Close()
   725  
   726  	nh, err := NewHandleAt(newNs)
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  	defer nh.Close()
   731  
   732  	// get loopback interface
   733  	link, err := nh.LinkByName("lo")
   734  	if err != nil {
   735  		t.Fatal(err)
   736  	}
   737  
   738  	// bring the interface up
   739  	if err = nh.LinkSetUp(link); err != nil {
   740  		t.Fatal(err)
   741  	}
   742  
   743  	// add a gateway route before subscribing
   744  	dst10 := &net.IPNet{
   745  		IP:   net.IPv4(10, 10, 10, 0),
   746  		Mask: net.CIDRMask(24, 32),
   747  	}
   748  
   749  	ip := net.IPv4(127, 100, 1, 1)
   750  	route10 := Route{LinkIndex: link.Attrs().Index, Dst: dst10, Src: ip}
   751  	if err := nh.RouteAdd(&route10); err != nil {
   752  		t.Fatal(err)
   753  	}
   754  
   755  	// Subscribe for Route events including existing routes
   756  	ch := make(chan RouteUpdate)
   757  	done := make(chan struct{})
   758  	defer close(done)
   759  	if err := RouteSubscribeWithOptions(ch, done, RouteSubscribeOptions{
   760  		Namespace:    &newNs,
   761  		ListExisting: true},
   762  	); err != nil {
   763  		t.Fatal(err)
   764  	}
   765  
   766  	if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, 0, dst10.IP) {
   767  		t.Fatal("Existing add update not received as expected")
   768  	}
   769  
   770  	// add a gateway route
   771  	dst := &net.IPNet{
   772  		IP:   net.IPv4(192, 169, 0, 0),
   773  		Mask: net.CIDRMask(24, 32),
   774  	}
   775  
   776  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
   777  	if err := nh.RouteAdd(&route); err != nil {
   778  		t.Fatal(err)
   779  	}
   780  
   781  	if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, unix.NLM_F_EXCL|unix.NLM_F_CREATE, dst.IP) {
   782  		t.Fatal("Add update not received as expected")
   783  	}
   784  	if err := nh.RouteDel(&route); err != nil {
   785  		t.Fatal(err)
   786  	}
   787  	if !expectRouteUpdate(ch, unix.RTM_DELROUTE, 0, dst.IP) {
   788  		t.Fatal("Del update not received as expected")
   789  	}
   790  	if err := nh.RouteDel(&route10); err != nil {
   791  		t.Fatal(err)
   792  	}
   793  	if !expectRouteUpdate(ch, unix.RTM_DELROUTE, 0, dst10.IP) {
   794  		t.Fatal("Del update not received as expected")
   795  	}
   796  }
   797  
   798  func TestRouteFilterAllTables(t *testing.T) {
   799  	tearDown := setUpNetlinkTest(t)
   800  	defer tearDown()
   801  
   802  	// get loopback interface
   803  	link, err := LinkByName("lo")
   804  	if err != nil {
   805  		t.Fatal(err)
   806  	}
   807  	// bring the interface up
   808  	if err = LinkSetUp(link); err != nil {
   809  		t.Fatal(err)
   810  	}
   811  
   812  	// add a gateway route
   813  	dst := &net.IPNet{
   814  		IP:   net.IPv4(1, 1, 1, 1),
   815  		Mask: net.CIDRMask(32, 32),
   816  	}
   817  
   818  	tables := []int{1000, 1001, 1002}
   819  	src := net.IPv4(127, 3, 3, 3)
   820  	for _, table := range tables {
   821  		route := Route{
   822  			LinkIndex: link.Attrs().Index,
   823  			Dst:       dst,
   824  			Src:       src,
   825  			Scope:     unix.RT_SCOPE_LINK,
   826  			Priority:  13,
   827  			Table:     table,
   828  			Type:      unix.RTN_UNICAST,
   829  			Tos:       12,
   830  			Hoplimit:  100,
   831  			Realm:     328,
   832  		}
   833  		if err := RouteAdd(&route); err != nil {
   834  			t.Fatal(err)
   835  		}
   836  	}
   837  	routes, err := RouteListFiltered(FAMILY_V4, &Route{
   838  		Dst:      dst,
   839  		Src:      src,
   840  		Scope:    unix.RT_SCOPE_LINK,
   841  		Table:    unix.RT_TABLE_UNSPEC,
   842  		Type:     unix.RTN_UNICAST,
   843  		Tos:      12,
   844  		Hoplimit: 100,
   845  		Realm:    328,
   846  	}, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS|RT_FILTER_HOPLIMIT|RT_FILTER_REALM)
   847  	if err != nil {
   848  		t.Fatal(err)
   849  	}
   850  	if len(routes) != 3 {
   851  		t.Fatal("Routes not added properly")
   852  	}
   853  
   854  	for _, route := range routes {
   855  		if route.Scope != unix.RT_SCOPE_LINK {
   856  			t.Fatal("Invalid Scope. Route not added properly")
   857  		}
   858  		if route.Priority != 13 {
   859  			t.Fatal("Invalid Priority. Route not added properly")
   860  		}
   861  		if !tableIDIn(tables, route.Table) {
   862  			t.Fatalf("Invalid Table %d. Route not added properly", route.Table)
   863  		}
   864  		if route.Type != unix.RTN_UNICAST {
   865  			t.Fatal("Invalid Type. Route not added properly")
   866  		}
   867  		if route.Tos != 12 {
   868  			t.Fatal("Invalid Tos. Route not added properly")
   869  		}
   870  		if route.Hoplimit != 100 {
   871  			t.Fatal("Invalid Hoplimit. Route not added properly")
   872  		}
   873  		if route.Realm != 328 {
   874  			t.Fatal("Invalid Realm. Route not added properly")
   875  		}
   876  	}
   877  }
   878  
   879  func TestRouteFilterByFamily(t *testing.T) {
   880  	tearDown := setUpNetlinkTest(t)
   881  	defer tearDown()
   882  
   883  	const table int = 999
   884  
   885  	// get loopback interface
   886  	link, err := LinkByName("lo")
   887  	if err != nil {
   888  		t.Fatal(err)
   889  	}
   890  	// bring the interface up
   891  	if err = LinkSetUp(link); err != nil {
   892  		t.Fatal(err)
   893  	}
   894  
   895  	// add a IPv4 gateway route
   896  	dst4 := &net.IPNet{
   897  		IP:   net.IPv4(2, 2, 0, 0),
   898  		Mask: net.CIDRMask(24, 32),
   899  	}
   900  	route4 := Route{LinkIndex: link.Attrs().Index, Dst: dst4, Table: table}
   901  	if err := RouteAdd(&route4); err != nil {
   902  		t.Fatal(err)
   903  	}
   904  
   905  	// add a IPv6 gateway route
   906  	dst6 := &net.IPNet{
   907  		IP:   net.ParseIP("2001:db9::0"),
   908  		Mask: net.CIDRMask(64, 128),
   909  	}
   910  	route6 := Route{LinkIndex: link.Attrs().Index, Dst: dst6, Table: table}
   911  	if err := RouteAdd(&route6); err != nil {
   912  		t.Fatal(err)
   913  	}
   914  
   915  	// Get routes for both families
   916  	routes_all, err := RouteListFiltered(FAMILY_ALL, &Route{Table: table}, RT_FILTER_TABLE)
   917  	if err != nil {
   918  		t.Fatal(err)
   919  	}
   920  	if len(routes_all) != 2 {
   921  		t.Fatal("Filtering by FAMILY_ALL doesn't find two routes")
   922  	}
   923  
   924  	// Get IPv4 route
   925  	routes_v4, err := RouteListFiltered(FAMILY_V4, &Route{Table: table}, RT_FILTER_TABLE)
   926  	if err != nil {
   927  		t.Fatal(err)
   928  	}
   929  	if len(routes_v4) != 1 {
   930  		t.Fatal("Filtering by FAMILY_V4 doesn't find one route")
   931  	}
   932  
   933  	// Get IPv6 route
   934  	routes_v6, err := RouteListFiltered(FAMILY_V6, &Route{Table: table}, RT_FILTER_TABLE)
   935  	if err != nil {
   936  		t.Fatal(err)
   937  	}
   938  	if len(routes_v6) != 1 {
   939  		t.Fatal("Filtering by FAMILY_V6 doesn't find one route")
   940  	}
   941  
   942  	// Get non-existent routes
   943  	routes_non_existent, err := RouteListFiltered(99, &Route{Table: table}, RT_FILTER_TABLE)
   944  	if err != nil {
   945  		t.Fatal(err)
   946  	}
   947  	if len(routes_non_existent) != 0 {
   948  		t.Fatal("Filtering by non-existent family find some route")
   949  	}
   950  }
   951  
   952  func TestRouteFilterIterCanStop(t *testing.T) {
   953  	tearDown := setUpNetlinkTest(t)
   954  	defer tearDown()
   955  
   956  	// get loopback interface
   957  	link, err := LinkByName("lo")
   958  	if err != nil {
   959  		t.Fatal(err)
   960  	}
   961  	// bring the interface up
   962  	if err = LinkSetUp(link); err != nil {
   963  		t.Fatal(err)
   964  	}
   965  
   966  	// add a gateway route
   967  	dst := &net.IPNet{
   968  		IP:   net.IPv4(1, 1, 1, 1),
   969  		Mask: net.CIDRMask(32, 32),
   970  	}
   971  
   972  	for i := 0; i < 3; i++ {
   973  		route := Route{
   974  			LinkIndex: link.Attrs().Index,
   975  			Dst:       dst,
   976  			Scope:     unix.RT_SCOPE_LINK,
   977  			Priority:  1 + i,
   978  			Table:     1000,
   979  			Type:      unix.RTN_UNICAST,
   980  		}
   981  		if err := RouteAdd(&route); err != nil {
   982  			t.Fatal(err)
   983  		}
   984  	}
   985  
   986  	var routes []Route
   987  	err = RouteListFilteredIter(FAMILY_V4, &Route{
   988  		Dst:   dst,
   989  		Scope: unix.RT_SCOPE_LINK,
   990  		Table: 1000,
   991  		Type:  unix.RTN_UNICAST,
   992  	}, RT_FILTER_TABLE, func(route Route) (cont bool) {
   993  		routes = append(routes, route)
   994  		return len(routes) < 2
   995  	})
   996  	if err != nil {
   997  		t.Fatal(err)
   998  	}
   999  	if len(routes) != 2 {
  1000  		t.Fatal("Unexpected number of iterations")
  1001  	}
  1002  	for _, route := range routes {
  1003  		if route.Scope != unix.RT_SCOPE_LINK {
  1004  			t.Fatal("Invalid Scope. Route not added properly")
  1005  		}
  1006  		if route.Priority < 1 || route.Priority > 3 {
  1007  			t.Fatal("Priority outside expected range. Route not added properly")
  1008  		}
  1009  		if route.Table != 1000 {
  1010  			t.Fatalf("Invalid Table %d. Route not added properly", route.Table)
  1011  		}
  1012  		if route.Type != unix.RTN_UNICAST {
  1013  			t.Fatal("Invalid Type. Route not added properly")
  1014  		}
  1015  	}
  1016  }
  1017  
  1018  func BenchmarkRouteListFilteredNew(b *testing.B) {
  1019  	tearDown := setUpNetlinkTest(b)
  1020  	defer tearDown()
  1021  
  1022  	link, err := setUpRoutesBench(b)
  1023  
  1024  	b.ResetTimer()
  1025  	b.ReportAllocs()
  1026  	var routes []Route
  1027  	for i := 0; i < b.N; i++ {
  1028  		routes, err = pkgHandle.RouteListFiltered(FAMILY_V4, &Route{
  1029  			LinkIndex: link.Attrs().Index,
  1030  		}, RT_FILTER_OIF)
  1031  		if err != nil {
  1032  			b.Fatal(err)
  1033  		}
  1034  		if len(routes) != 65535 {
  1035  			b.Fatal("Incorrect number of routes.", len(routes))
  1036  		}
  1037  	}
  1038  	runtime.KeepAlive(routes)
  1039  }
  1040  
  1041  func BenchmarkRouteListIter(b *testing.B) {
  1042  	tearDown := setUpNetlinkTest(b)
  1043  	defer tearDown()
  1044  
  1045  	link, err := setUpRoutesBench(b)
  1046  
  1047  	b.ResetTimer()
  1048  	b.ReportAllocs()
  1049  	for i := 0; i < b.N; i++ {
  1050  		var routes int
  1051  		err = RouteListFilteredIter(FAMILY_V4, &Route{
  1052  			LinkIndex: link.Attrs().Index,
  1053  		}, RT_FILTER_OIF, func(route Route) (cont bool) {
  1054  			routes++
  1055  			return true
  1056  		})
  1057  		if err != nil {
  1058  			b.Fatal(err)
  1059  		}
  1060  		if routes != 65535 {
  1061  			b.Fatal("Incorrect number of routes.", routes)
  1062  		}
  1063  	}
  1064  }
  1065  
  1066  func setUpRoutesBench(b *testing.B) (Link, error) {
  1067  	// get loopback interface
  1068  	link, err := LinkByName("lo")
  1069  	if err != nil {
  1070  		b.Fatal(err)
  1071  	}
  1072  	// bring the interface up
  1073  	if err = LinkSetUp(link); err != nil {
  1074  		b.Fatal(err)
  1075  	}
  1076  
  1077  	// add a gateway route
  1078  	for i := 0; i < 65535; i++ {
  1079  		dst := &net.IPNet{
  1080  			IP:   net.IPv4(1, 1, byte(i>>8), byte(i&0xff)),
  1081  			Mask: net.CIDRMask(32, 32),
  1082  		}
  1083  		route := Route{
  1084  			LinkIndex: link.Attrs().Index,
  1085  			Dst:       dst,
  1086  			Scope:     unix.RT_SCOPE_LINK,
  1087  			Priority:  10,
  1088  			Type:      unix.RTN_UNICAST,
  1089  		}
  1090  		if err := RouteAdd(&route); err != nil {
  1091  			b.Fatal(err)
  1092  		}
  1093  	}
  1094  	return link, err
  1095  }
  1096  
  1097  func tableIDIn(ids []int, id int) bool {
  1098  	for _, v := range ids {
  1099  		if v == id {
  1100  			return true
  1101  		}
  1102  	}
  1103  	return false
  1104  }
  1105  
  1106  func TestRouteExtraFields(t *testing.T) {
  1107  	tearDown := setUpNetlinkTest(t)
  1108  	defer tearDown()
  1109  
  1110  	// get loopback interface
  1111  	link, err := LinkByName("lo")
  1112  	if err != nil {
  1113  		t.Fatal(err)
  1114  	}
  1115  	// bring the interface up
  1116  	if err = LinkSetUp(link); err != nil {
  1117  		t.Fatal(err)
  1118  	}
  1119  
  1120  	// add a gateway route
  1121  	dst := &net.IPNet{
  1122  		IP:   net.IPv4(1, 1, 1, 1),
  1123  		Mask: net.CIDRMask(32, 32),
  1124  	}
  1125  
  1126  	src := net.IPv4(127, 3, 3, 3)
  1127  	route := Route{
  1128  		LinkIndex: link.Attrs().Index,
  1129  		Dst:       dst,
  1130  		Src:       src,
  1131  		Scope:     unix.RT_SCOPE_LINK,
  1132  		Priority:  13,
  1133  		Table:     unix.RT_TABLE_MAIN,
  1134  		Type:      unix.RTN_UNICAST,
  1135  		Tos:       12,
  1136  		Hoplimit:  100,
  1137  		Realm:     239,
  1138  	}
  1139  	if err := RouteAdd(&route); err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  	routes, err := RouteListFiltered(FAMILY_V4, &Route{
  1143  		Dst:      dst,
  1144  		Src:      src,
  1145  		Scope:    unix.RT_SCOPE_LINK,
  1146  		Table:    unix.RT_TABLE_MAIN,
  1147  		Type:     unix.RTN_UNICAST,
  1148  		Tos:      12,
  1149  		Hoplimit: 100,
  1150  		Realm:    239,
  1151  	}, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS|RT_FILTER_HOPLIMIT|RT_FILTER_REALM)
  1152  	if err != nil {
  1153  		t.Fatal(err)
  1154  	}
  1155  	if len(routes) != 1 {
  1156  		t.Fatal("Route not added properly")
  1157  	}
  1158  
  1159  	if routes[0].Scope != unix.RT_SCOPE_LINK {
  1160  		t.Fatal("Invalid Scope. Route not added properly")
  1161  	}
  1162  	if routes[0].Priority != 13 {
  1163  		t.Fatal("Invalid Priority. Route not added properly")
  1164  	}
  1165  	if routes[0].Table != unix.RT_TABLE_MAIN {
  1166  		t.Fatal("Invalid Scope. Route not added properly")
  1167  	}
  1168  	if routes[0].Type != unix.RTN_UNICAST {
  1169  		t.Fatal("Invalid Type. Route not added properly")
  1170  	}
  1171  	if routes[0].Tos != 12 {
  1172  		t.Fatal("Invalid Tos. Route not added properly")
  1173  	}
  1174  	if routes[0].Hoplimit != 100 {
  1175  		t.Fatal("Invalid Hoplimit. Route not added properly")
  1176  	}
  1177  	if routes[0].Realm != 239 {
  1178  		t.Fatal("Invalid Realm. Route not added properly")
  1179  	}
  1180  }
  1181  
  1182  func TestRouteMultiPath(t *testing.T) {
  1183  	tearDown := setUpNetlinkTest(t)
  1184  	defer tearDown()
  1185  
  1186  	// get loopback interface
  1187  	link, err := LinkByName("lo")
  1188  	if err != nil {
  1189  		t.Fatal(err)
  1190  	}
  1191  	// bring the interface up
  1192  	if err = LinkSetUp(link); err != nil {
  1193  		t.Fatal(err)
  1194  	}
  1195  
  1196  	// add a gateway route
  1197  	dst := &net.IPNet{
  1198  		IP:   net.IPv4(192, 168, 0, 0),
  1199  		Mask: net.CIDRMask(24, 32),
  1200  	}
  1201  
  1202  	idx := link.Attrs().Index
  1203  	route := Route{Dst: dst, MultiPath: []*NexthopInfo{{LinkIndex: idx}, {LinkIndex: idx}}}
  1204  	if err := RouteAdd(&route); err != nil {
  1205  		t.Fatal(err)
  1206  	}
  1207  	routes, err := RouteList(nil, FAMILY_V4)
  1208  	if err != nil {
  1209  		t.Fatal(err)
  1210  	}
  1211  	if len(routes) != 1 {
  1212  		t.Fatal("MultiPath Route not added properly")
  1213  	}
  1214  	if len(routes[0].MultiPath) != 2 {
  1215  		t.Fatal("MultiPath Route not added properly")
  1216  	}
  1217  }
  1218  
  1219  func TestRouteIifOption(t *testing.T) {
  1220  	skipUnlessRoot(t)
  1221  
  1222  	runtime.LockOSThread()
  1223  	t.Cleanup(runtime.UnlockOSThread)
  1224  
  1225  	rootNs, err := netns.GetFromPid(1)
  1226  	if err != nil {
  1227  		t.Fatalf("could not get root ns: %s", err)
  1228  	}
  1229  	t.Cleanup(func() { rootNs.Close() })
  1230  
  1231  	rootHdl, err := NewHandleAt(rootNs)
  1232  	if err != nil {
  1233  		t.Fatalf("could not create handle for root ns: %s", err)
  1234  	}
  1235  	t.Cleanup(func() { rootHdl.Close() })
  1236  
  1237  	// setup a veth pair across two namespaces
  1238  	//   veth1 (2.2.2.3/24) <-> veth2 (2.2.2.4/24)
  1239  
  1240  	// peer ns for veth pair
  1241  	ns, err := netns.New()
  1242  	if err != nil {
  1243  		t.Fatalf("could not create new ns: %s", err)
  1244  	}
  1245  	t.Cleanup(func() { ns.Close() })
  1246  
  1247  	l := &Veth{
  1248  		LinkAttrs:     LinkAttrs{Name: "veth1"},
  1249  		PeerName:      "veth2",
  1250  		PeerNamespace: NsFd(ns),
  1251  	}
  1252  	if err = rootHdl.LinkAdd(l); err != nil {
  1253  		t.Fatalf("could not add veth interface: %s", err)
  1254  	}
  1255  	t.Cleanup(func() { rootHdl.LinkDel(l) })
  1256  
  1257  	ve1, err := rootHdl.LinkByName("veth1")
  1258  	if err != nil {
  1259  		t.Fatalf("could not get link veth1: %s", err)
  1260  	}
  1261  
  1262  	err = rootHdl.AddrAdd(ve1, &Addr{IPNet: &net.IPNet{IP: net.ParseIP("2.2.2.3"), Mask: net.CIDRMask(24, 32)}})
  1263  	if err != nil {
  1264  		t.Fatalf("could not set address for veth1: %s", err)
  1265  	}
  1266  
  1267  	nh, err := NewHandleAt(ns)
  1268  	if err != nil {
  1269  		t.Fatalf("could not get handle for ns %+v: %s", ns, err)
  1270  	}
  1271  	t.Cleanup(func() { nh.Close() })
  1272  
  1273  	ve2, err := nh.LinkByName("veth2")
  1274  	if err != nil {
  1275  		t.Fatalf("could not get link veth2: %s", err)
  1276  	}
  1277  
  1278  	err = nh.AddrAdd(ve2, &Addr{IPNet: &net.IPNet{IP: net.ParseIP("2.2.2.4"), Mask: net.CIDRMask(24, 32)}})
  1279  	if err != nil {
  1280  		t.Fatalf("could set address for veth2: %s", err)
  1281  	}
  1282  
  1283  	if err = rootHdl.LinkSetUp(ve1); err != nil {
  1284  		t.Fatalf("could not set veth1 up: %s", err)
  1285  	}
  1286  
  1287  	if err = nh.LinkSetUp(ve2); err != nil {
  1288  		t.Fatalf("could not set veth2 up: %s", err)
  1289  	}
  1290  
  1291  	err = nh.RouteAdd(&Route{
  1292  		Dst: &net.IPNet{
  1293  			IP:   net.IPv4zero,
  1294  			Mask: net.CIDRMask(0, 32),
  1295  		},
  1296  		Gw: net.ParseIP("2.2.2.3"),
  1297  	})
  1298  	if err != nil {
  1299  		t.Fatalf("could not add default route to ns: %s", err)
  1300  	}
  1301  
  1302  	// setup finished, now do the actual test
  1303  
  1304  	_, err = rootHdl.RouteGetWithOptions(net.ParseIP("8.8.8.8"), &RouteGetOptions{
  1305  		SrcAddr: net.ParseIP("2.2.2.4"),
  1306  	})
  1307  	if err == nil {
  1308  		t.Fatal("route get should have resulted in error but did not")
  1309  	}
  1310  
  1311  	testWithOptions := func(opts *RouteGetOptions) {
  1312  		routes, err := rootHdl.RouteGetWithOptions(net.ParseIP("8.8.8.8"), opts)
  1313  		if err != nil {
  1314  			t.Fatalf("could not get route: %s", err)
  1315  		}
  1316  		if len(routes) != 1 {
  1317  			t.Fatalf("did not get exactly one route, routes: %+v", routes)
  1318  		}
  1319  
  1320  		// should be the default route
  1321  		r, err := rootHdl.RouteGet(net.ParseIP("8.8.8.8"))
  1322  		if err != nil {
  1323  			t.Fatalf("could not get default route for 8.8.8.8: %s", err)
  1324  		}
  1325  		if len(r) != 1 {
  1326  			t.Fatalf("did not get exactly one route, routes: %+v", routes)
  1327  		}
  1328  		if !routes[0].Gw.Equal(r[0].Gw) {
  1329  			t.Fatalf("wrong gateway in route: expected: %s, got: %s", r[0].Gw, routes[0].Gw)
  1330  		}
  1331  		if routes[0].LinkIndex != r[0].LinkIndex {
  1332  			t.Fatalf("wrong link in route: expected: %d, got: %d", r[0].LinkIndex, routes[0].LinkIndex)
  1333  		}
  1334  	}
  1335  
  1336  	t.Run("with iif", func(t *testing.T) {
  1337  		testWithOptions(&RouteGetOptions{
  1338  			SrcAddr: net.ParseIP("2.2.2.4"),
  1339  			Iif:     "veth1",
  1340  		})
  1341  	})
  1342  
  1343  	t.Run("with iifIndex", func(t *testing.T) {
  1344  		testWithOptions(&RouteGetOptions{
  1345  			SrcAddr:  net.ParseIP("2.2.2.4"),
  1346  			IifIndex: ve1.Attrs().Index,
  1347  		})
  1348  	})
  1349  
  1350  	t.Run("with iif and iifIndex", func(t *testing.T) {
  1351  		testWithOptions(&RouteGetOptions{
  1352  			SrcAddr:  net.ParseIP("2.2.2.4"),
  1353  			Iif:      "veth1",
  1354  			IifIndex: ve2.Attrs().Index, // Iif will supersede here
  1355  		})
  1356  	})
  1357  }
  1358  
  1359  func TestRouteOifOption(t *testing.T) {
  1360  	tearDown := setUpNetlinkTest(t)
  1361  	defer tearDown()
  1362  
  1363  	// setup two interfaces: eth0, eth1
  1364  	err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
  1365  	if err != nil {
  1366  		t.Fatal(err)
  1367  	}
  1368  
  1369  	link1, err := LinkByName("eth0")
  1370  	if err != nil {
  1371  		t.Fatal(err)
  1372  	}
  1373  
  1374  	if err = LinkSetUp(link1); err != nil {
  1375  		t.Fatal(err)
  1376  	}
  1377  
  1378  	if err = LinkAdd(&Dummy{LinkAttrs{Name: "eth1"}}); err != nil {
  1379  		t.Fatal(err)
  1380  	}
  1381  
  1382  	link2, err := LinkByName("eth1")
  1383  	if err != nil {
  1384  		t.Fatal(err)
  1385  	}
  1386  
  1387  	if err = LinkSetUp(link2); err != nil {
  1388  		t.Fatal(err)
  1389  	}
  1390  
  1391  	// config ip addresses on interfaces
  1392  	addr1 := &Addr{
  1393  		IPNet: &net.IPNet{
  1394  			IP:   net.IPv4(192, 168, 1, 1),
  1395  			Mask: net.CIDRMask(24, 32),
  1396  		},
  1397  	}
  1398  
  1399  	if err = AddrAdd(link1, addr1); err != nil {
  1400  		t.Fatal(err)
  1401  	}
  1402  
  1403  	addr2 := &Addr{
  1404  		IPNet: &net.IPNet{
  1405  			IP:   net.IPv4(192, 168, 2, 1),
  1406  			Mask: net.CIDRMask(24, 32),
  1407  		},
  1408  	}
  1409  
  1410  	if err = AddrAdd(link2, addr2); err != nil {
  1411  		t.Fatal(err)
  1412  	}
  1413  
  1414  	// add default multipath route
  1415  	dst := &net.IPNet{
  1416  		IP:   net.IPv4(0, 0, 0, 0),
  1417  		Mask: net.CIDRMask(0, 32),
  1418  	}
  1419  	gw1 := net.IPv4(192, 168, 1, 254)
  1420  	gw2 := net.IPv4(192, 168, 2, 254)
  1421  	route := Route{Dst: dst, MultiPath: []*NexthopInfo{{LinkIndex: link1.Attrs().Index,
  1422  		Gw: gw1}, {LinkIndex: link2.Attrs().Index, Gw: gw2}}}
  1423  	if err := RouteAdd(&route); err != nil {
  1424  		t.Fatal(err)
  1425  	}
  1426  
  1427  	// check getting route from specified Oif
  1428  	dstIP := net.IPv4(10, 1, 1, 1)
  1429  	routes, err := RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth0"})
  1430  	if err != nil {
  1431  		t.Fatal(err)
  1432  	}
  1433  
  1434  	if len(routes) != 1 || routes[0].LinkIndex != link1.Attrs().Index ||
  1435  		!routes[0].Gw.Equal(gw1) {
  1436  		t.Fatal("Get route from unmatched interface")
  1437  	}
  1438  
  1439  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth1"})
  1440  	if err != nil {
  1441  		t.Fatal(err)
  1442  	}
  1443  
  1444  	if len(routes) != 1 || routes[0].LinkIndex != link2.Attrs().Index ||
  1445  		!routes[0].Gw.Equal(gw2) {
  1446  		t.Fatal("Get route from unmatched interface")
  1447  	}
  1448  
  1449  }
  1450  
  1451  func TestFilterDefaultRoute(t *testing.T) {
  1452  	tearDown := setUpNetlinkTest(t)
  1453  	defer tearDown()
  1454  
  1455  	// get loopback interface
  1456  	link, err := LinkByName("lo")
  1457  	if err != nil {
  1458  		t.Fatal(err)
  1459  	}
  1460  	// bring the interface up
  1461  	if err = LinkSetUp(link); err != nil {
  1462  		t.Fatal(err)
  1463  	}
  1464  
  1465  	address := &Addr{
  1466  		IPNet: &net.IPNet{
  1467  			IP:   net.IPv4(127, 0, 0, 2),
  1468  			Mask: net.CIDRMask(24, 32),
  1469  		},
  1470  	}
  1471  	if err = AddrAdd(link, address); err != nil {
  1472  		t.Fatal(err)
  1473  	}
  1474  
  1475  	// Add default route
  1476  	gw := net.IPv4(127, 0, 0, 2)
  1477  
  1478  	defaultRoute := Route{
  1479  		Dst: nil,
  1480  		Gw:  gw,
  1481  	}
  1482  
  1483  	if err := RouteAdd(&defaultRoute); err != nil {
  1484  		t.Fatal(err)
  1485  	}
  1486  
  1487  	// add an extra route
  1488  	dst := &net.IPNet{
  1489  		IP:   net.IPv4(192, 168, 0, 0),
  1490  		Mask: net.CIDRMask(24, 32),
  1491  	}
  1492  
  1493  	extraRoute := Route{
  1494  		Dst: dst,
  1495  		Gw:  gw,
  1496  	}
  1497  
  1498  	if err := RouteAdd(&extraRoute); err != nil {
  1499  		t.Fatal(err)
  1500  	}
  1501  	var filterTests = []struct {
  1502  		filter   *Route
  1503  		mask     uint64
  1504  		expected net.IP
  1505  	}{
  1506  		{
  1507  			&Route{Dst: nil},
  1508  			RT_FILTER_DST,
  1509  			gw,
  1510  		},
  1511  		{
  1512  			&Route{Dst: dst},
  1513  			RT_FILTER_DST,
  1514  			gw,
  1515  		},
  1516  	}
  1517  
  1518  	for _, f := range filterTests {
  1519  		routes, err := RouteListFiltered(FAMILY_V4, f.filter, f.mask)
  1520  		if err != nil {
  1521  			t.Fatal(err)
  1522  		}
  1523  		if len(routes) != 1 {
  1524  			t.Fatal("Route not filtered properly")
  1525  		}
  1526  		if !routes[0].Gw.Equal(gw) {
  1527  			t.Fatal("Unexpected Gateway")
  1528  		}
  1529  	}
  1530  
  1531  }
  1532  
  1533  func TestMPLSRouteAddDel(t *testing.T) {
  1534  	tearDown := setUpMPLSNetlinkTest(t)
  1535  	defer tearDown()
  1536  
  1537  	// get loopback interface
  1538  	link, err := LinkByName("lo")
  1539  	if err != nil {
  1540  		t.Fatal(err)
  1541  	}
  1542  
  1543  	// bring the interface up
  1544  	if err := LinkSetUp(link); err != nil {
  1545  		t.Fatal(err)
  1546  	}
  1547  
  1548  	mplsDst := 100
  1549  	route := Route{
  1550  		LinkIndex: link.Attrs().Index,
  1551  		MPLSDst:   &mplsDst,
  1552  		NewDst: &MPLSDestination{
  1553  			Labels: []int{200, 300},
  1554  		},
  1555  	}
  1556  	if err := RouteAdd(&route); err != nil {
  1557  		t.Fatal(err)
  1558  	}
  1559  	routes, err := RouteList(link, FAMILY_MPLS)
  1560  	if err != nil {
  1561  		t.Fatal(err)
  1562  	}
  1563  	if len(routes) != 1 {
  1564  		t.Fatal("Route not added properly")
  1565  	}
  1566  
  1567  	if err := RouteDel(&route); err != nil {
  1568  		t.Fatal(err)
  1569  	}
  1570  	routes, err = RouteList(link, FAMILY_MPLS)
  1571  	if err != nil {
  1572  		t.Fatal(err)
  1573  	}
  1574  	if len(routes) != 0 {
  1575  		t.Fatal("Route not removed properly")
  1576  	}
  1577  
  1578  }
  1579  
  1580  func TestIP6tnlRouteAddDel(t *testing.T) {
  1581  	_, err := RouteList(nil, FAMILY_V4)
  1582  	if err != nil {
  1583  		t.Fatal(err)
  1584  	}
  1585  
  1586  	tearDown := setUpNetlinkTest(t)
  1587  	defer tearDown()
  1588  
  1589  	// get loopback interface
  1590  	link, err := LinkByName("lo")
  1591  	if err != nil {
  1592  		t.Fatal(err)
  1593  	}
  1594  
  1595  	// bring the interface up
  1596  	if err := LinkSetUp(link); err != nil {
  1597  		t.Fatal(err)
  1598  	}
  1599  
  1600  	_, dst, err := net.ParseCIDR("192.168.99.0/24")
  1601  	if err != nil {
  1602  		t.Fatalf("cannot parse destination prefix: %v", err)
  1603  	}
  1604  
  1605  	encap := IP6tnlEncap{
  1606  		Dst: net.ParseIP("2001:db8::"),
  1607  		Src: net.ParseIP("::"),
  1608  	}
  1609  
  1610  	route := &Route{
  1611  		LinkIndex: link.Attrs().Index,
  1612  		Dst:       dst,
  1613  		Encap:     &encap,
  1614  	}
  1615  
  1616  	if err := RouteAdd(route); err != nil {
  1617  		t.Fatalf("Cannot add route: %v", err)
  1618  	}
  1619  	routes, err := RouteList(link, FAMILY_V4)
  1620  	if err != nil {
  1621  		t.Fatal(err)
  1622  	}
  1623  	if len(routes) != 1 {
  1624  		t.Fatal("Route not added properly")
  1625  	}
  1626  
  1627  	if err := RouteDel(route); err != nil {
  1628  		t.Fatal(err)
  1629  	}
  1630  	routes, err = RouteList(link, FAMILY_V4)
  1631  	if err != nil {
  1632  		t.Fatal(err)
  1633  	}
  1634  	if len(routes) != 0 {
  1635  		t.Fatal("Route not removed properly")
  1636  	}
  1637  
  1638  }
  1639  
  1640  func TestRouteEqual(t *testing.T) {
  1641  	mplsDst := 100
  1642  	seg6encap := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP}
  1643  	seg6encap.Segments = []net.IP{net.ParseIP("fc00:a000::11")}
  1644  	cases := []Route{
  1645  		{
  1646  			Dst: nil,
  1647  			Gw:  net.IPv4(1, 1, 1, 1),
  1648  		},
  1649  		{
  1650  			LinkIndex: 20,
  1651  			Dst:       nil,
  1652  			Gw:        net.IPv4(1, 1, 1, 1),
  1653  		},
  1654  		{
  1655  			ILinkIndex: 21,
  1656  			LinkIndex:  20,
  1657  			Dst:        nil,
  1658  			Gw:         net.IPv4(1, 1, 1, 1),
  1659  		},
  1660  		{
  1661  			LinkIndex: 20,
  1662  			Dst:       nil,
  1663  			Protocol:  20,
  1664  			Gw:        net.IPv4(1, 1, 1, 1),
  1665  		},
  1666  		{
  1667  			LinkIndex: 20,
  1668  			Dst:       nil,
  1669  			Priority:  20,
  1670  			Gw:        net.IPv4(1, 1, 1, 1),
  1671  		},
  1672  		{
  1673  			LinkIndex: 20,
  1674  			Dst:       nil,
  1675  			Type:      20,
  1676  			Gw:        net.IPv4(1, 1, 1, 1),
  1677  		},
  1678  		{
  1679  			LinkIndex: 20,
  1680  			Dst:       nil,
  1681  			Table:     200,
  1682  			Gw:        net.IPv4(1, 1, 1, 1),
  1683  		},
  1684  		{
  1685  			LinkIndex: 20,
  1686  			Dst:       nil,
  1687  			Tos:       1,
  1688  			Gw:        net.IPv4(1, 1, 1, 1),
  1689  		},
  1690  		{
  1691  			LinkIndex: 20,
  1692  			Dst:       nil,
  1693  			Hoplimit:  1,
  1694  			Gw:        net.IPv4(1, 1, 1, 1),
  1695  		},
  1696  		{
  1697  			LinkIndex: 20,
  1698  			Dst:       nil,
  1699  			Realm:     29,
  1700  			Gw:        net.IPv4(1, 1, 1, 1),
  1701  		},
  1702  		{
  1703  			LinkIndex: 20,
  1704  			Dst:       nil,
  1705  			Flags:     int(FLAG_ONLINK),
  1706  			Gw:        net.IPv4(1, 1, 1, 1),
  1707  		},
  1708  		{
  1709  			LinkIndex: 10,
  1710  			Dst: &net.IPNet{
  1711  				IP:   net.IPv4(192, 168, 0, 0),
  1712  				Mask: net.CIDRMask(24, 32),
  1713  			},
  1714  			Src: net.IPv4(127, 1, 1, 1),
  1715  		},
  1716  		{
  1717  			LinkIndex: 10,
  1718  			Scope:     unix.RT_SCOPE_LINK,
  1719  			Dst: &net.IPNet{
  1720  				IP:   net.IPv4(192, 168, 0, 0),
  1721  				Mask: net.CIDRMask(24, 32),
  1722  			},
  1723  			Src: net.IPv4(127, 1, 1, 1),
  1724  		},
  1725  		{
  1726  			LinkIndex: 3,
  1727  			Dst: &net.IPNet{
  1728  				IP:   net.IPv4(1, 1, 1, 1),
  1729  				Mask: net.CIDRMask(32, 32),
  1730  			},
  1731  			Src:      net.IPv4(127, 3, 3, 3),
  1732  			Scope:    unix.RT_SCOPE_LINK,
  1733  			Priority: 13,
  1734  			Table:    unix.RT_TABLE_MAIN,
  1735  			Type:     unix.RTN_UNICAST,
  1736  			Tos:      12,
  1737  		},
  1738  		{
  1739  			LinkIndex: 3,
  1740  			Dst: &net.IPNet{
  1741  				IP:   net.IPv4(1, 1, 1, 1),
  1742  				Mask: net.CIDRMask(32, 32),
  1743  			},
  1744  			Src:      net.IPv4(127, 3, 3, 3),
  1745  			Scope:    unix.RT_SCOPE_LINK,
  1746  			Priority: 13,
  1747  			Table:    unix.RT_TABLE_MAIN,
  1748  			Type:     unix.RTN_UNICAST,
  1749  			Hoplimit: 100,
  1750  		},
  1751  		{
  1752  			LinkIndex: 3,
  1753  			Dst: &net.IPNet{
  1754  				IP:   net.IPv4(1, 1, 1, 1),
  1755  				Mask: net.CIDRMask(32, 32),
  1756  			},
  1757  			Src:      net.IPv4(127, 3, 3, 3),
  1758  			Scope:    unix.RT_SCOPE_LINK,
  1759  			Priority: 13,
  1760  			Table:    unix.RT_TABLE_MAIN,
  1761  			Type:     unix.RTN_UNICAST,
  1762  			Realm:    129,
  1763  		},
  1764  		{
  1765  			LinkIndex: 10,
  1766  			MPLSDst:   &mplsDst,
  1767  			NewDst: &MPLSDestination{
  1768  				Labels: []int{200, 300},
  1769  			},
  1770  		},
  1771  		{
  1772  			Dst: nil,
  1773  			Gw:  net.IPv4(1, 1, 1, 1),
  1774  			Encap: &MPLSEncap{
  1775  				Labels: []int{100},
  1776  			},
  1777  		},
  1778  		{
  1779  			LinkIndex: 10,
  1780  			Dst: &net.IPNet{
  1781  				IP:   net.IPv4(10, 0, 0, 102),
  1782  				Mask: net.CIDRMask(32, 32),
  1783  			},
  1784  			Encap: seg6encap,
  1785  		},
  1786  		{
  1787  			Dst:       nil,
  1788  			MultiPath: []*NexthopInfo{{LinkIndex: 10}, {LinkIndex: 20}},
  1789  		},
  1790  		{
  1791  			Dst: nil,
  1792  			MultiPath: []*NexthopInfo{{
  1793  				LinkIndex: 10,
  1794  				Gw:        net.IPv4(1, 1, 1, 1),
  1795  			}, {LinkIndex: 20}},
  1796  		},
  1797  		{
  1798  			Dst: nil,
  1799  			MultiPath: []*NexthopInfo{{
  1800  				LinkIndex: 10,
  1801  				Gw:        net.IPv4(1, 1, 1, 1),
  1802  				Encap: &MPLSEncap{
  1803  					Labels: []int{100},
  1804  				},
  1805  			}, {LinkIndex: 20}},
  1806  		},
  1807  		{
  1808  			Dst: nil,
  1809  			MultiPath: []*NexthopInfo{{
  1810  				LinkIndex: 10,
  1811  				NewDst: &MPLSDestination{
  1812  					Labels: []int{200, 300},
  1813  				},
  1814  			}, {LinkIndex: 20}},
  1815  		},
  1816  		{
  1817  			Dst: nil,
  1818  			MultiPath: []*NexthopInfo{{
  1819  				LinkIndex: 10,
  1820  				Encap:     seg6encap,
  1821  			}, {LinkIndex: 20}},
  1822  		},
  1823  	}
  1824  	for i1 := range cases {
  1825  		for i2 := range cases {
  1826  			got := cases[i1].Equal(cases[i2])
  1827  			expected := i1 == i2
  1828  			if got != expected {
  1829  				t.Errorf("Equal(%q,%q) == %s but expected %s",
  1830  					cases[i1], cases[i2],
  1831  					strconv.FormatBool(got),
  1832  					strconv.FormatBool(expected))
  1833  			}
  1834  		}
  1835  	}
  1836  }
  1837  
  1838  func TestIPNetEqual(t *testing.T) {
  1839  	cases := []string{
  1840  		"1.1.1.1/24", "1.1.1.0/24", "1.1.1.1/32",
  1841  		"0.0.0.0/0", "0.0.0.0/14",
  1842  		"2001:db8::/32", "2001:db8::/128",
  1843  		"2001:db8::caff/32", "2001:db8::caff/128",
  1844  		"",
  1845  	}
  1846  	for _, c1 := range cases {
  1847  		var n1 *net.IPNet
  1848  		if c1 != "" {
  1849  			var i1 net.IP
  1850  			var err1 error
  1851  			i1, n1, err1 = net.ParseCIDR(c1)
  1852  			if err1 != nil {
  1853  				panic(err1)
  1854  			}
  1855  			n1.IP = i1
  1856  		}
  1857  		for _, c2 := range cases {
  1858  			var n2 *net.IPNet
  1859  			if c2 != "" {
  1860  				var i2 net.IP
  1861  				var err2 error
  1862  				i2, n2, err2 = net.ParseCIDR(c2)
  1863  				if err2 != nil {
  1864  					panic(err2)
  1865  				}
  1866  				n2.IP = i2
  1867  			}
  1868  
  1869  			got := ipNetEqual(n1, n2)
  1870  			expected := c1 == c2
  1871  			if got != expected {
  1872  				t.Errorf("IPNetEqual(%q,%q) == %s but expected %s",
  1873  					c1, c2,
  1874  					strconv.FormatBool(got),
  1875  					strconv.FormatBool(expected))
  1876  			}
  1877  		}
  1878  	}
  1879  }
  1880  
  1881  func TestSEG6LocalEqual(t *testing.T) {
  1882  	// Different attributes exists in different Actions. For example, Action
  1883  	// SEG6_LOCAL_ACTION_END_X has In6Addr, SEG6_LOCAL_ACTION_END_T has Table etc.
  1884  	segs := []net.IP{net.ParseIP("fc00:a000::11")}
  1885  	// set flags for each actions.
  1886  	var flags_end [nl.SEG6_LOCAL_MAX]bool
  1887  	flags_end[nl.SEG6_LOCAL_ACTION] = true
  1888  	var flags_end_x [nl.SEG6_LOCAL_MAX]bool
  1889  	flags_end_x[nl.SEG6_LOCAL_ACTION] = true
  1890  	flags_end_x[nl.SEG6_LOCAL_NH6] = true
  1891  	var flags_end_t [nl.SEG6_LOCAL_MAX]bool
  1892  	flags_end_t[nl.SEG6_LOCAL_ACTION] = true
  1893  	flags_end_t[nl.SEG6_LOCAL_TABLE] = true
  1894  	var flags_end_dx2 [nl.SEG6_LOCAL_MAX]bool
  1895  	flags_end_dx2[nl.SEG6_LOCAL_ACTION] = true
  1896  	flags_end_dx2[nl.SEG6_LOCAL_OIF] = true
  1897  	var flags_end_dx6 [nl.SEG6_LOCAL_MAX]bool
  1898  	flags_end_dx6[nl.SEG6_LOCAL_ACTION] = true
  1899  	flags_end_dx6[nl.SEG6_LOCAL_NH6] = true
  1900  	var flags_end_dx4 [nl.SEG6_LOCAL_MAX]bool
  1901  	flags_end_dx4[nl.SEG6_LOCAL_ACTION] = true
  1902  	flags_end_dx4[nl.SEG6_LOCAL_NH4] = true
  1903  	var flags_end_dt6 [nl.SEG6_LOCAL_MAX]bool
  1904  	flags_end_dt6[nl.SEG6_LOCAL_ACTION] = true
  1905  	flags_end_dt6[nl.SEG6_LOCAL_TABLE] = true
  1906  	var flags_end_dt4 [nl.SEG6_LOCAL_MAX]bool
  1907  	flags_end_dt4[nl.SEG6_LOCAL_ACTION] = true
  1908  	flags_end_dt4[nl.SEG6_LOCAL_TABLE] = true
  1909  	var flags_end_b6 [nl.SEG6_LOCAL_MAX]bool
  1910  	flags_end_b6[nl.SEG6_LOCAL_ACTION] = true
  1911  	flags_end_b6[nl.SEG6_LOCAL_SRH] = true
  1912  	var flags_end_b6_encaps [nl.SEG6_LOCAL_MAX]bool
  1913  	flags_end_b6_encaps[nl.SEG6_LOCAL_ACTION] = true
  1914  	flags_end_b6_encaps[nl.SEG6_LOCAL_SRH] = true
  1915  	var flags_end_bpf [nl.SEG6_LOCAL_MAX]bool
  1916  	flags_end_bpf[nl.SEG6_LOCAL_ACTION] = true
  1917  	flags_end_bpf[nl.SEG6_LOCAL_BPF] = true
  1918  
  1919  	cases := []SEG6LocalEncap{
  1920  		{
  1921  			Flags:  flags_end,
  1922  			Action: nl.SEG6_LOCAL_ACTION_END,
  1923  		},
  1924  		{
  1925  			Flags:   flags_end_x,
  1926  			Action:  nl.SEG6_LOCAL_ACTION_END_X,
  1927  			In6Addr: net.ParseIP("2001:db8::1"),
  1928  		},
  1929  		{
  1930  			Flags:  flags_end_t,
  1931  			Action: nl.SEG6_LOCAL_ACTION_END_T,
  1932  			Table:  10,
  1933  		},
  1934  		{
  1935  			Flags:  flags_end_dx2,
  1936  			Action: nl.SEG6_LOCAL_ACTION_END_DX2,
  1937  			Oif:    20,
  1938  		},
  1939  		{
  1940  			Flags:   flags_end_dx6,
  1941  			Action:  nl.SEG6_LOCAL_ACTION_END_DX6,
  1942  			In6Addr: net.ParseIP("2001:db8::1"),
  1943  		},
  1944  		{
  1945  			Flags:  flags_end_dx4,
  1946  			Action: nl.SEG6_LOCAL_ACTION_END_DX4,
  1947  			InAddr: net.IPv4(192, 168, 10, 10),
  1948  		},
  1949  		{
  1950  			Flags:  flags_end_dt6,
  1951  			Action: nl.SEG6_LOCAL_ACTION_END_DT6,
  1952  			Table:  30,
  1953  		},
  1954  		{
  1955  			Flags:  flags_end_dt4,
  1956  			Action: nl.SEG6_LOCAL_ACTION_END_DT4,
  1957  			Table:  40,
  1958  		},
  1959  		{
  1960  			Flags:    flags_end_b6,
  1961  			Action:   nl.SEG6_LOCAL_ACTION_END_B6,
  1962  			Segments: segs,
  1963  		},
  1964  		{
  1965  			Flags:    flags_end_b6_encaps,
  1966  			Action:   nl.SEG6_LOCAL_ACTION_END_B6_ENCAPS,
  1967  			Segments: segs,
  1968  		},
  1969  	}
  1970  
  1971  	// SEG6_LOCAL_ACTION_END_BPF
  1972  	endBpf := SEG6LocalEncap{
  1973  		Flags:  flags_end_bpf,
  1974  		Action: nl.SEG6_LOCAL_ACTION_END_BPF,
  1975  	}
  1976  	_ = endBpf.SetProg(1, "firewall")
  1977  	cases = append(cases, endBpf)
  1978  
  1979  	for i1 := range cases {
  1980  		for i2 := range cases {
  1981  			got := cases[i1].Equal(&cases[i2])
  1982  			expected := i1 == i2
  1983  			if got != expected {
  1984  				t.Errorf("Equal(%v,%v) == %s but expected %s",
  1985  					cases[i1], cases[i2],
  1986  					strconv.FormatBool(got),
  1987  					strconv.FormatBool(expected))
  1988  			}
  1989  		}
  1990  	}
  1991  }
  1992  func TestSEG6RouteAddDel(t *testing.T) {
  1993  	if os.Getenv("CI") == "true" {
  1994  		t.Skipf("Fails in CI with: route_test.go:*: Invalid Type. SEG6_IPTUN_MODE_INLINE routes not added properly")
  1995  	}
  1996  	// add/del routes with LWTUNNEL_SEG6 to/from loopback interface.
  1997  	// Test both seg6 modes: encap (IPv4) & inline (IPv6).
  1998  	tearDown := setUpSEG6NetlinkTest(t)
  1999  	defer tearDown()
  2000  
  2001  	// get loopback interface and bring it up
  2002  	link, err := LinkByName("lo")
  2003  	if err != nil {
  2004  		t.Fatal(err)
  2005  	}
  2006  	if err := LinkSetUp(link); err != nil {
  2007  		t.Fatal(err)
  2008  	}
  2009  
  2010  	dst1 := &net.IPNet{ // INLINE mode must be IPv6 route
  2011  		IP:   net.ParseIP("2001:db8::1"),
  2012  		Mask: net.CIDRMask(128, 128),
  2013  	}
  2014  	dst2 := &net.IPNet{
  2015  		IP:   net.IPv4(10, 0, 0, 102),
  2016  		Mask: net.CIDRMask(32, 32),
  2017  	}
  2018  	var s1, s2 []net.IP
  2019  	s1 = append(s1, net.ParseIP("::")) // inline requires "::"
  2020  	s1 = append(s1, net.ParseIP("fc00:a000::12"))
  2021  	s1 = append(s1, net.ParseIP("fc00:a000::11"))
  2022  	s2 = append(s2, net.ParseIP("fc00:a000::22"))
  2023  	s2 = append(s2, net.ParseIP("fc00:a000::21"))
  2024  	e1 := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_INLINE}
  2025  	e2 := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP}
  2026  	e1.Segments = s1
  2027  	e2.Segments = s2
  2028  	route1 := Route{LinkIndex: link.Attrs().Index, Dst: dst1, Encap: e1}
  2029  	route2 := Route{LinkIndex: link.Attrs().Index, Dst: dst2, Encap: e2}
  2030  
  2031  	// Add SEG6 routes
  2032  	if err := RouteAdd(&route1); err != nil {
  2033  		t.Fatal(err)
  2034  	}
  2035  	if err := RouteAdd(&route2); err != nil {
  2036  		t.Fatal(err)
  2037  	}
  2038  	// SEG6_IPTUN_MODE_INLINE
  2039  	routes, err := RouteList(link, FAMILY_V6)
  2040  	if err != nil {
  2041  		t.Fatal(err)
  2042  	}
  2043  	if len(routes) != 1 {
  2044  		t.Fatal("SEG6 routes not added properly")
  2045  	}
  2046  	for _, route := range routes {
  2047  		if route.Encap == nil || route.Encap.Type() != nl.LWTUNNEL_ENCAP_SEG6 {
  2048  			t.Fatal("Invalid Type. SEG6_IPTUN_MODE_INLINE routes not added properly")
  2049  		}
  2050  	}
  2051  	// SEG6_IPTUN_MODE_ENCAP
  2052  	routes, err = RouteList(link, FAMILY_V4)
  2053  	if err != nil {
  2054  		t.Fatal(err)
  2055  	}
  2056  	if len(routes) != 1 {
  2057  		t.Fatal("SEG6 routes not added properly")
  2058  	}
  2059  	for _, route := range routes {
  2060  		if route.Encap.Type() != nl.LWTUNNEL_ENCAP_SEG6 {
  2061  			t.Fatal("Invalid Type. SEG6_IPTUN_MODE_ENCAP routes not added properly")
  2062  		}
  2063  	}
  2064  
  2065  	// Del (remove) SEG6 routes
  2066  	if err := RouteDel(&route1); err != nil {
  2067  		t.Fatal(err)
  2068  	}
  2069  	if err := RouteDel(&route2); err != nil {
  2070  		t.Fatal(err)
  2071  	}
  2072  	routes, err = RouteList(link, FAMILY_V4)
  2073  	if err != nil {
  2074  		t.Fatal(err)
  2075  	}
  2076  	if len(routes) != 0 {
  2077  		t.Fatal("SEG6 routes not removed properly")
  2078  	}
  2079  }
  2080  
  2081  // add/del routes with LWTUNNEL_ENCAP_SEG6_LOCAL to/from dummy interface.
  2082  func TestSEG6LocalRoute6AddDel(t *testing.T) {
  2083  	minKernelRequired(t, 4, 14)
  2084  	tearDown := setUpSEG6NetlinkTest(t)
  2085  	defer tearDown()
  2086  
  2087  	// create dummy interface
  2088  	// IPv6 route added to loopback interface will be unreachable
  2089  	la := NewLinkAttrs()
  2090  	la.Name = "dummy_route6"
  2091  	la.TxQLen = 1500
  2092  	dummy := &Dummy{LinkAttrs: la}
  2093  	if err := LinkAdd(dummy); err != nil {
  2094  		t.Fatal(err)
  2095  	}
  2096  	// get dummy interface and bring it up
  2097  	link, err := LinkByName("dummy_route6")
  2098  	if err != nil {
  2099  		t.Fatal(err)
  2100  	}
  2101  	if err := LinkSetUp(link); err != nil {
  2102  		t.Fatal(err)
  2103  	}
  2104  
  2105  	dst1 := &net.IPNet{
  2106  		IP:   net.ParseIP("2001:db8::1"),
  2107  		Mask: net.CIDRMask(128, 128),
  2108  	}
  2109  
  2110  	// Create Route including Action SEG6_LOCAL_ACTION_END_B6.
  2111  	// Could be any Action but thought better to have seg list.
  2112  	var s1 []net.IP
  2113  	s1 = append(s1, net.ParseIP("fc00:a000::12"))
  2114  	s1 = append(s1, net.ParseIP("fc00:a000::11"))
  2115  	var flags_end_b6_encaps [nl.SEG6_LOCAL_MAX]bool
  2116  	flags_end_b6_encaps[nl.SEG6_LOCAL_ACTION] = true
  2117  	flags_end_b6_encaps[nl.SEG6_LOCAL_SRH] = true
  2118  	e1 := &SEG6LocalEncap{
  2119  		Flags:    flags_end_b6_encaps,
  2120  		Action:   nl.SEG6_LOCAL_ACTION_END_B6,
  2121  		Segments: s1,
  2122  	}
  2123  	route1 := Route{LinkIndex: link.Attrs().Index, Dst: dst1, Encap: e1}
  2124  
  2125  	// Add SEG6Local routes
  2126  	if err := RouteAdd(&route1); err != nil {
  2127  		t.Fatal(err)
  2128  	}
  2129  
  2130  	// typically one route (fe80::/64) will be created when dummy_route6 is created.
  2131  	// Thus you cannot use RouteList() to find the route entry just added.
  2132  	// Lookup route and confirm it's SEG6Local route just added.
  2133  	routesFound, err := RouteGet(dst1.IP)
  2134  	if err != nil {
  2135  		t.Fatal(err)
  2136  	}
  2137  	if len(routesFound) != 1 { // should only find 1 route entry
  2138  		t.Fatal("SEG6Local route not added correctly")
  2139  	}
  2140  	if !e1.Equal(routesFound[0].Encap) {
  2141  		t.Fatal("Encap does not match the original SEG6LocalEncap")
  2142  	}
  2143  
  2144  	// Del SEG6Local routes
  2145  	if err := RouteDel(&route1); err != nil {
  2146  		t.Fatal(err)
  2147  	}
  2148  	// Confirm route is deleted.
  2149  	if _, err = RouteGet(dst1.IP); err == nil {
  2150  		t.Fatal("SEG6Local route still exists.")
  2151  	}
  2152  
  2153  	// cleanup dummy interface created for the test
  2154  	if err := LinkDel(link); err != nil {
  2155  		t.Fatal(err)
  2156  	}
  2157  }
  2158  
  2159  func TestBpfEncap(t *testing.T) {
  2160  	tCase := &BpfEncap{}
  2161  	if err := tCase.SetProg(nl.LWT_BPF_IN, 0, "test_in"); err == nil {
  2162  		t.Fatal("BpfEncap: inserting invalid FD did not return error")
  2163  	}
  2164  	if err := tCase.SetProg(nl.LWT_BPF_XMIT_HEADROOM, 23, "test_nout"); err == nil {
  2165  		t.Fatal("BpfEncap: inserting invalid mode did not return error")
  2166  	}
  2167  	if err := tCase.SetProg(nl.LWT_BPF_XMIT, 12, "test_xmit"); err != nil {
  2168  		t.Fatal("BpfEncap: inserting valid program option returned error")
  2169  	}
  2170  	if err := tCase.SetXmitHeadroom(12); err != nil {
  2171  		t.Fatal("BpfEncap: inserting valid headroom returned error")
  2172  	}
  2173  	if err := tCase.SetXmitHeadroom(nl.LWT_BPF_MAX_HEADROOM + 1); err == nil {
  2174  		t.Fatal("BpfEncap: inserting invalid headroom did not return error")
  2175  	}
  2176  	tCase = &BpfEncap{}
  2177  
  2178  	expected := &BpfEncap{
  2179  		progs: [nl.LWT_BPF_MAX]bpfObj{
  2180  			1: {
  2181  				progName: "test_in[fd:10]",
  2182  				progFd:   10,
  2183  			},
  2184  			2: {
  2185  				progName: "test_out[fd:11]",
  2186  				progFd:   11,
  2187  			},
  2188  			3: {
  2189  				progName: "test_xmit[fd:21]",
  2190  				progFd:   21,
  2191  			},
  2192  		},
  2193  		headroom: 128,
  2194  	}
  2195  
  2196  	_ = tCase.SetProg(1, 10, "test_in")
  2197  	_ = tCase.SetProg(2, 11, "test_out")
  2198  	_ = tCase.SetProg(3, 21, "test_xmit")
  2199  	_ = tCase.SetXmitHeadroom(128)
  2200  	if !tCase.Equal(expected) {
  2201  		t.Fatal("BpfEncap: equal comparison failed")
  2202  	}
  2203  	_ = tCase.SetProg(3, 21, "test2_xmit")
  2204  	if tCase.Equal(expected) {
  2205  		t.Fatal("BpfEncap: equal comparison succeeded when attributes differ")
  2206  	}
  2207  }
  2208  
  2209  func TestMTURouteAddDel(t *testing.T) {
  2210  	_, err := RouteList(nil, FAMILY_V4)
  2211  	if err != nil {
  2212  		t.Fatal(err)
  2213  	}
  2214  
  2215  	tearDown := setUpNetlinkTest(t)
  2216  	defer tearDown()
  2217  
  2218  	// get loopback interface
  2219  	link, err := LinkByName("lo")
  2220  	if err != nil {
  2221  		t.Fatal(err)
  2222  	}
  2223  
  2224  	// bring the interface up
  2225  	if err := LinkSetUp(link); err != nil {
  2226  		t.Fatal(err)
  2227  	}
  2228  
  2229  	// add a gateway route
  2230  	dst := &net.IPNet{
  2231  		IP:   net.IPv4(192, 168, 0, 0),
  2232  		Mask: net.CIDRMask(24, 32),
  2233  	}
  2234  
  2235  	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, MTU: 500}
  2236  	if err := RouteAdd(&route); err != nil {
  2237  		t.Fatal(err)
  2238  	}
  2239  	routes, err := RouteList(link, FAMILY_V4)
  2240  	if err != nil {
  2241  		t.Fatal(err)
  2242  	}
  2243  	if len(routes) != 1 {
  2244  		t.Fatal("Route not added properly")
  2245  	}
  2246  
  2247  	if route.MTU != routes[0].MTU {
  2248  		t.Fatal("Route mtu not set properly")
  2249  	}
  2250  
  2251  	if err := RouteDel(&route); err != nil {
  2252  		t.Fatal(err)
  2253  	}
  2254  	routes, err = RouteList(link, FAMILY_V4)
  2255  	if err != nil {
  2256  		t.Fatal(err)
  2257  	}
  2258  	if len(routes) != 0 {
  2259  		t.Fatal("Route not removed properly")
  2260  	}
  2261  }
  2262  
  2263  func TestRouteViaAddDel(t *testing.T) {
  2264  	minKernelRequired(t, 5, 4)
  2265  	tearDown := setUpNetlinkTest(t)
  2266  	defer tearDown()
  2267  
  2268  	_, err := RouteList(nil, FAMILY_V4)
  2269  	if err != nil {
  2270  		t.Fatal(err)
  2271  	}
  2272  
  2273  	link, err := LinkByName("lo")
  2274  	if err != nil {
  2275  		t.Fatal(err)
  2276  	}
  2277  
  2278  	if err := LinkSetUp(link); err != nil {
  2279  		t.Fatal(err)
  2280  	}
  2281  
  2282  	route := &Route{
  2283  		LinkIndex: link.Attrs().Index,
  2284  		Dst: &net.IPNet{
  2285  			IP:   net.IPv4(192, 168, 0, 0),
  2286  			Mask: net.CIDRMask(24, 32),
  2287  		},
  2288  		MultiPath: []*NexthopInfo{
  2289  			{
  2290  				LinkIndex: link.Attrs().Index,
  2291  				Via: &Via{
  2292  					AddrFamily: FAMILY_V6,
  2293  					Addr:       net.ParseIP("2001::1"),
  2294  				},
  2295  			},
  2296  		},
  2297  	}
  2298  
  2299  	if err := RouteAdd(route); err != nil {
  2300  		t.Fatalf("route: %v, err: %v", route, err)
  2301  	}
  2302  
  2303  	routes, err := RouteList(link, FAMILY_V4)
  2304  	if err != nil {
  2305  		t.Fatal(err)
  2306  	}
  2307  	if len(routes) != 1 {
  2308  		t.Fatal("Route not added properly")
  2309  	}
  2310  
  2311  	got := routes[0].Via
  2312  	want := route.MultiPath[0].Via
  2313  	if !want.Equal(got) {
  2314  		t.Fatalf("Route Via attribute does not match; got: %s, want: %s", got, want)
  2315  	}
  2316  
  2317  	if err := RouteDel(route); err != nil {
  2318  		t.Fatal(err)
  2319  	}
  2320  	routes, err = RouteList(link, FAMILY_V4)
  2321  	if err != nil {
  2322  		t.Fatal(err)
  2323  	}
  2324  	if len(routes) != 0 {
  2325  		t.Fatal("Route not removed properly")
  2326  	}
  2327  }
  2328  
  2329  func TestRouteUIDOption(t *testing.T) {
  2330  	tearDown := setUpNetlinkTest(t)
  2331  	defer tearDown()
  2332  
  2333  	// setup eth0 so that network is reachable
  2334  	err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
  2335  	if err != nil {
  2336  		t.Fatal(err)
  2337  	}
  2338  	link, err := LinkByName("eth0")
  2339  	if err != nil {
  2340  		t.Fatal(err)
  2341  	}
  2342  	if err = LinkSetUp(link); err != nil {
  2343  		t.Fatal(err)
  2344  	}
  2345  	addr := &Addr{
  2346  		IPNet: &net.IPNet{
  2347  			IP:   net.IPv4(192, 168, 1, 1),
  2348  			Mask: net.CIDRMask(16, 32),
  2349  		},
  2350  	}
  2351  	if err = AddrAdd(link, addr); err != nil {
  2352  		t.Fatal(err)
  2353  	}
  2354  
  2355  	// a table different than unix.RT_TABLE_MAIN
  2356  	testtable := 1000
  2357  
  2358  	gw1 := net.IPv4(192, 168, 1, 254)
  2359  	gw2 := net.IPv4(192, 168, 2, 254)
  2360  
  2361  	// add default route via gw1 (in main route table by default)
  2362  	defaultRouteMain := Route{
  2363  		Dst: nil,
  2364  		Gw:  gw1,
  2365  	}
  2366  	if err := RouteAdd(&defaultRouteMain); err != nil {
  2367  		t.Fatal(err)
  2368  	}
  2369  
  2370  	// add default route via gw2 in test route table
  2371  	defaultRouteTest := Route{
  2372  		Dst:   nil,
  2373  		Gw:    gw2,
  2374  		Table: testtable,
  2375  	}
  2376  	if err := RouteAdd(&defaultRouteTest); err != nil {
  2377  		t.Fatal(err)
  2378  	}
  2379  
  2380  	// check the routes are in different tables
  2381  	routes, err := RouteListFiltered(FAMILY_V4, &Route{
  2382  		Dst:   nil,
  2383  		Table: unix.RT_TABLE_UNSPEC,
  2384  	}, RT_FILTER_DST|RT_FILTER_TABLE)
  2385  	if err != nil {
  2386  		t.Fatal(err)
  2387  	}
  2388  	if len(routes) != 2 || routes[0].Table == routes[1].Table {
  2389  		t.Fatal("Routes not added properly")
  2390  	}
  2391  
  2392  	// add a rule that uidrange match should result in route lookup of test table for uid other than current
  2393  	// current uid is 0 due to skipUnlessRoot()
  2394  	var uid uint32 = 1000
  2395  	rule := NewRule()
  2396  	rule.UIDRange = NewRuleUIDRange(uid, uid)
  2397  	rule.Table = testtable
  2398  	if err := RuleAdd(rule); err != nil {
  2399  		t.Fatal(err)
  2400  	}
  2401  
  2402  	dstIP := net.IPv4(10, 1, 1, 1)
  2403  
  2404  	// check getting route without UID option
  2405  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{UID: nil})
  2406  	if err != nil {
  2407  		t.Fatal(err)
  2408  	}
  2409  	// current uid is outside uidrange; rule does not apply; lookup main table
  2410  	if len(routes) != 1 || !routes[0].Gw.Equal(gw1) {
  2411  		t.Fatal(routes)
  2412  	}
  2413  
  2414  	// check getting route with UID option
  2415  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{UID: &uid})
  2416  	if err != nil {
  2417  		t.Fatal(err)
  2418  	}
  2419  	// option uid is within uidrange; rule applies; lookup test table
  2420  	if len(routes) != 1 || !routes[0].Gw.Equal(gw2) {
  2421  		t.Fatal(routes)
  2422  	}
  2423  }
  2424  
  2425  func TestRouteFWMarkOption(t *testing.T) {
  2426  	tearDown := setUpNetlinkTest(t)
  2427  	defer tearDown()
  2428  
  2429  	// setup eth0 so that network is reachable
  2430  	err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
  2431  	if err != nil {
  2432  		t.Fatal(err)
  2433  	}
  2434  	link, err := LinkByName("eth0")
  2435  	if err != nil {
  2436  		t.Fatal(err)
  2437  	}
  2438  	if err = LinkSetUp(link); err != nil {
  2439  		t.Fatal(err)
  2440  	}
  2441  	addr := &Addr{
  2442  		IPNet: &net.IPNet{
  2443  			IP:   net.IPv4(192, 168, 1, 1),
  2444  			Mask: net.CIDRMask(16, 32),
  2445  		},
  2446  	}
  2447  	if err = AddrAdd(link, addr); err != nil {
  2448  		t.Fatal(err)
  2449  	}
  2450  
  2451  	// a table different than unix.RT_TABLE_MAIN
  2452  	testTable0 := 254
  2453  	testTable1 := 1000
  2454  	testTable2 := 1001
  2455  
  2456  	gw0 := net.IPv4(192, 168, 1, 254)
  2457  	gw1 := net.IPv4(192, 168, 2, 254)
  2458  	gw2 := net.IPv4(192, 168, 3, 254)
  2459  
  2460  	// add default route via gw0 (in main route table by default)
  2461  	defaultRouteMain := Route{
  2462  		Dst:   nil,
  2463  		Gw:    gw0,
  2464  		Table: testTable0,
  2465  	}
  2466  	if err := RouteAdd(&defaultRouteMain); err != nil {
  2467  		t.Fatal(err)
  2468  	}
  2469  
  2470  	// add default route via gw1 in test route table
  2471  	defaultRouteTest1 := Route{
  2472  		Dst:   nil,
  2473  		Gw:    gw1,
  2474  		Table: testTable1,
  2475  	}
  2476  	if err := RouteAdd(&defaultRouteTest1); err != nil {
  2477  		t.Fatal(err)
  2478  	}
  2479  
  2480  	// add default route via gw2 in test route table
  2481  	defaultRouteTest2 := Route{
  2482  		Dst:   nil,
  2483  		Gw:    gw2,
  2484  		Table: testTable2,
  2485  	}
  2486  	if err := RouteAdd(&defaultRouteTest2); err != nil {
  2487  		t.Fatal(err)
  2488  	}
  2489  
  2490  	// check the routes are in different tables
  2491  	routes, err := RouteListFiltered(FAMILY_V4, &Route{
  2492  		Dst:   nil,
  2493  		Table: unix.RT_TABLE_UNSPEC,
  2494  	}, RT_FILTER_DST|RT_FILTER_TABLE)
  2495  	if err != nil {
  2496  		t.Fatal(err)
  2497  	}
  2498  	if len(routes) != 3 || routes[0].Table == routes[1].Table || routes[1].Table == routes[2].Table ||
  2499  		routes[0].Table == routes[2].Table {
  2500  		t.Fatal("Routes not added properly")
  2501  	}
  2502  
  2503  	// add a rule that fwmark match should result in route lookup of test table
  2504  	fwmark1 := uint32(0xAFFFFFFF)
  2505  	fwmark2 := uint32(0xBFFFFFFF)
  2506  
  2507  	rule := NewRule()
  2508  	rule.Mark = fwmark1
  2509  	rule.Mask = &[]uint32{0xFFFFFFFF}[0]
  2510  
  2511  	rule.Table = testTable1
  2512  	if err := RuleAdd(rule); err != nil {
  2513  		t.Fatal(err)
  2514  	}
  2515  
  2516  	rule = NewRule()
  2517  	rule.Mark = fwmark2
  2518  	rule.Mask = &[]uint32{0xFFFFFFFF}[0]
  2519  	rule.Table = testTable2
  2520  	if err := RuleAdd(rule); err != nil {
  2521  		t.Fatal(err)
  2522  	}
  2523  
  2524  	rules, err := RuleListFiltered(FAMILY_V4, &Rule{Mark: fwmark1}, RT_FILTER_MARK)
  2525  	if err != nil {
  2526  		t.Fatal(err)
  2527  	}
  2528  	if len(rules) != 1 || rules[0].Table != testTable1 || rules[0].Mark != fwmark1 {
  2529  		t.Fatal("Rules not added properly")
  2530  	}
  2531  
  2532  	rules, err = RuleListFiltered(FAMILY_V4, &Rule{Mark: fwmark2}, RT_FILTER_MARK)
  2533  	if err != nil {
  2534  		t.Fatal(err)
  2535  	}
  2536  	if len(rules) != 1 || rules[0].Table != testTable2 || rules[0].Mark != fwmark2 {
  2537  		t.Fatal("Rules not added properly")
  2538  	}
  2539  
  2540  	dstIP := net.IPv4(10, 1, 1, 1)
  2541  
  2542  	// check getting route without FWMark option
  2543  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{})
  2544  	if err != nil {
  2545  		t.Fatal(err)
  2546  	}
  2547  	if len(routes) != 1 || !routes[0].Gw.Equal(gw0) {
  2548  		t.Fatal(routes)
  2549  	}
  2550  
  2551  	// check getting route with FWMark option
  2552  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Mark: fwmark1})
  2553  	if err != nil {
  2554  		t.Fatal(err)
  2555  	}
  2556  	if len(routes) != 1 || !routes[0].Gw.Equal(gw1) {
  2557  		t.Fatal(routes)
  2558  	}
  2559  
  2560  	// check getting route with FWMark option
  2561  	routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Mark: fwmark2})
  2562  	if err != nil {
  2563  		t.Fatal(err)
  2564  	}
  2565  	if len(routes) != 1 || !routes[0].Gw.Equal(gw2) {
  2566  		t.Fatal(routes)
  2567  	}
  2568  }
  2569  
  2570  func TestRouteGetFIBMatchOption(t *testing.T) {
  2571  	tearDown := setUpNetlinkTest(t)
  2572  	defer tearDown()
  2573  
  2574  	err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}})
  2575  	if err != nil {
  2576  		t.Fatal(err)
  2577  	}
  2578  	link, err := LinkByName("eth0")
  2579  	if err != nil {
  2580  		t.Fatal(err)
  2581  	}
  2582  	if err = LinkSetUp(link); err != nil {
  2583  		t.Fatal(err)
  2584  	}
  2585  	addr := &Addr{
  2586  		IPNet: &net.IPNet{
  2587  			IP:   net.IPv4(192, 168, 0, 2),
  2588  			Mask: net.CIDRMask(24, 32),
  2589  		},
  2590  	}
  2591  	if err = AddrAdd(link, addr); err != nil {
  2592  		t.Fatal(err)
  2593  	}
  2594  
  2595  	route := &Route{
  2596  		LinkIndex: link.Attrs().Index,
  2597  		Gw:        net.IPv4(192, 168, 1, 1),
  2598  		Dst: &net.IPNet{
  2599  			IP:   net.IPv4(192, 168, 2, 0),
  2600  			Mask: net.CIDRMask(24, 32),
  2601  		},
  2602  		Flags: int(FLAG_ONLINK),
  2603  	}
  2604  
  2605  	err = RouteAdd(route)
  2606  	if err != nil {
  2607  		t.Fatal(err)
  2608  	}
  2609  
  2610  	routes, err := RouteGetWithOptions(net.IPv4(192, 168, 2, 1), &RouteGetOptions{FIBMatch: true})
  2611  	if err != nil {
  2612  		t.Fatal(err)
  2613  	}
  2614  
  2615  	if len(routes) != 1 {
  2616  		t.Fatalf("More than one route matched %v", routes)
  2617  	}
  2618  
  2619  	if len(routes[0].ListFlags()) != 1 {
  2620  		t.Fatalf("More than one route flag returned %v", routes[0].ListFlags())
  2621  	}
  2622  
  2623  	flag := routes[0].ListFlags()[0]
  2624  	if flag != "onlink" {
  2625  		t.Fatalf("Unexpected flag %s returned", flag)
  2626  	}
  2627  }