github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/route_test.go (about) 1 //go:build linux 2 // +build linux 3 4 package netlink 5 6 import ( 7 "net" 8 "os" 9 "strconv" 10 "testing" 11 "time" 12 13 "github.com/sagernet/netlink/nl" 14 "github.com/vishvananda/netns" 15 "golang.org/x/sys/unix" 16 ) 17 18 func TestRouteAddDel(t *testing.T) { 19 tearDown := setUpNetlinkTest(t) 20 defer tearDown() 21 22 // get loopback interface 23 link, err := LinkByName("lo") 24 if err != nil { 25 t.Fatal(err) 26 } 27 28 // bring the interface up 29 if err := LinkSetUp(link); err != nil { 30 t.Fatal(err) 31 } 32 33 // add a gateway route 34 dst := &net.IPNet{ 35 IP: net.IPv4(192, 168, 0, 0), 36 Mask: net.CIDRMask(24, 32), 37 } 38 39 ip := net.IPv4(127, 1, 1, 1) 40 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 41 if err := RouteAdd(&route); err != nil { 42 t.Fatal(err) 43 } 44 routes, err := RouteList(link, FAMILY_V4) 45 if err != nil { 46 t.Fatal(err) 47 } 48 if len(routes) != 1 { 49 t.Fatal("Route not added properly") 50 } 51 52 dstIP := net.IPv4(192, 168, 0, 42) 53 routeToDstIP, err := RouteGet(dstIP) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 if len(routeToDstIP) == 0 { 59 t.Fatal("Default route not present") 60 } 61 if err := RouteDel(&route); err != nil { 62 t.Fatal(err) 63 } 64 routes, err = RouteList(link, FAMILY_V4) 65 if err != nil { 66 t.Fatal(err) 67 } 68 if len(routes) != 0 { 69 t.Fatal("Route not removed properly") 70 } 71 72 } 73 74 func TestRoute6AddDel(t *testing.T) { 75 tearDown := setUpNetlinkTest(t) 76 defer tearDown() 77 78 // create dummy interface 79 // IPv6 route added to loopback interface will be unreachable 80 la := NewLinkAttrs() 81 la.Name = "dummy_route6" 82 la.TxQLen = 1500 83 dummy := &Dummy{LinkAttrs: la} 84 if err := LinkAdd(dummy); err != nil { 85 t.Fatal(err) 86 } 87 88 // get dummy interface 89 link, err := LinkByName("dummy_route6") 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 // bring the interface up 95 if err := LinkSetUp(link); err != nil { 96 t.Fatal(err) 97 } 98 99 // remember number of routes before adding 100 // typically one route (fe80::/64) will be created when dummy_route6 is created 101 routes, err := RouteList(link, FAMILY_V6) 102 if err != nil { 103 t.Fatal(err) 104 } 105 nroutes := len(routes) 106 107 // add a gateway route 108 dst := &net.IPNet{ 109 IP: net.ParseIP("2001:db8::0"), 110 Mask: net.CIDRMask(64, 128), 111 } 112 route := Route{LinkIndex: link.Attrs().Index, Dst: dst} 113 if err := RouteAdd(&route); err != nil { 114 t.Fatal(err) 115 } 116 routes, err = RouteList(link, FAMILY_V6) 117 if err != nil { 118 t.Fatal(err) 119 } 120 if len(routes) != nroutes+1 { 121 t.Fatal("Route not added properly") 122 } 123 124 dstIP := net.ParseIP("2001:db8::1") 125 routeToDstIP, err := RouteGet(dstIP) 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 // cleanup route and dummy interface created for the test 131 if len(routeToDstIP) == 0 { 132 t.Fatal("Route not present") 133 } 134 if err := RouteDel(&route); err != nil { 135 t.Fatal(err) 136 } 137 routes, err = RouteList(link, FAMILY_V6) 138 if err != nil { 139 t.Fatal(err) 140 } 141 if len(routes) != nroutes { 142 t.Fatal("Route not removed properly") 143 } 144 if err := LinkDel(link); err != nil { 145 t.Fatal(err) 146 } 147 } 148 149 func TestRouteReplace(t *testing.T) { 150 tearDown := setUpNetlinkTest(t) 151 defer tearDown() 152 153 // get loopback interface 154 link, err := LinkByName("lo") 155 if err != nil { 156 t.Fatal(err) 157 } 158 159 // bring the interface up 160 if err := LinkSetUp(link); err != nil { 161 t.Fatal(err) 162 } 163 164 // add a gateway route 165 dst := &net.IPNet{ 166 IP: net.IPv4(192, 168, 0, 0), 167 Mask: net.CIDRMask(24, 32), 168 } 169 170 ip := net.IPv4(127, 1, 1, 1) 171 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 172 if err := RouteAdd(&route); err != nil { 173 t.Fatal(err) 174 } 175 routes, err := RouteList(link, FAMILY_V4) 176 if err != nil { 177 t.Fatal(err) 178 } 179 if len(routes) != 1 { 180 t.Fatal("Route not added properly") 181 } 182 183 ip = net.IPv4(127, 1, 1, 2) 184 route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 185 if err := RouteReplace(&route); err != nil { 186 t.Fatal(err) 187 } 188 189 routes, err = RouteList(link, FAMILY_V4) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 if len(routes) != 1 || !routes[0].Src.Equal(ip) { 195 t.Fatal("Route not replaced properly") 196 } 197 198 if err := RouteDel(&route); err != nil { 199 t.Fatal(err) 200 } 201 routes, err = RouteList(link, FAMILY_V4) 202 if err != nil { 203 t.Fatal(err) 204 } 205 if len(routes) != 0 { 206 t.Fatal("Route not removed properly") 207 } 208 209 } 210 211 func TestRouteAppend(t *testing.T) { 212 tearDown := setUpNetlinkTest(t) 213 defer tearDown() 214 215 // get loopback interface 216 link, err := LinkByName("lo") 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 // bring the interface up 222 if err := LinkSetUp(link); err != nil { 223 t.Fatal(err) 224 } 225 226 // add a gateway route 227 dst := &net.IPNet{ 228 IP: net.IPv4(192, 168, 0, 0), 229 Mask: net.CIDRMask(24, 32), 230 } 231 232 ip := net.IPv4(127, 1, 1, 1) 233 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 234 if err := RouteAdd(&route); err != nil { 235 t.Fatal(err) 236 } 237 routes, err := RouteList(link, FAMILY_V4) 238 if err != nil { 239 t.Fatal(err) 240 } 241 if len(routes) != 1 { 242 t.Fatal("Route not added properly") 243 } 244 245 ip = net.IPv4(127, 1, 1, 2) 246 route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 247 if err := RouteAppend(&route); err != nil { 248 t.Fatal(err) 249 } 250 251 routes, err = RouteList(link, FAMILY_V4) 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 if len(routes) != 2 || !routes[1].Src.Equal(ip) { 257 t.Fatal("Route not append properly") 258 } 259 260 if err := RouteDel(&routes[0]); err != nil { 261 t.Fatal(err) 262 } 263 if err := RouteDel(&routes[1]); err != nil { 264 t.Fatal(err) 265 } 266 routes, err = RouteList(link, FAMILY_V4) 267 if err != nil { 268 t.Fatal(err) 269 } 270 if len(routes) != 0 { 271 t.Fatal("Route not removed properly") 272 } 273 } 274 275 func TestRouteAddIncomplete(t *testing.T) { 276 tearDown := setUpNetlinkTest(t) 277 defer tearDown() 278 279 // get loopback interface 280 link, err := LinkByName("lo") 281 if err != nil { 282 t.Fatal(err) 283 } 284 285 // bring the interface up 286 if err = LinkSetUp(link); err != nil { 287 t.Fatal(err) 288 } 289 290 route := Route{LinkIndex: link.Attrs().Index} 291 if err := RouteAdd(&route); err == nil { 292 t.Fatal("Adding incomplete route should fail") 293 } 294 } 295 296 // expectNeighUpdate returns whether the expected updated is received within one minute. 297 func expectRouteUpdate(ch <-chan RouteUpdate, t uint16, dst net.IP) bool { 298 for { 299 timeout := time.After(time.Minute) 300 select { 301 case update := <-ch: 302 if update.Type == t && 303 update.Route.Dst != nil && 304 update.Route.Dst.IP.Equal(dst) { 305 return true 306 } 307 case <-timeout: 308 return false 309 } 310 } 311 } 312 313 func TestRouteSubscribe(t *testing.T) { 314 tearDown := setUpNetlinkTest(t) 315 defer tearDown() 316 317 ch := make(chan RouteUpdate) 318 done := make(chan struct{}) 319 defer close(done) 320 if err := RouteSubscribe(ch, done); err != nil { 321 t.Fatal(err) 322 } 323 324 // get loopback interface 325 link, err := LinkByName("lo") 326 if err != nil { 327 t.Fatal(err) 328 } 329 330 // bring the interface up 331 if err = LinkSetUp(link); err != nil { 332 t.Fatal(err) 333 } 334 335 // add a gateway route 336 dst := &net.IPNet{ 337 IP: net.IPv4(192, 168, 0, 0), 338 Mask: net.CIDRMask(24, 32), 339 } 340 341 ip := net.IPv4(127, 1, 1, 1) 342 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 343 if err := RouteAdd(&route); err != nil { 344 t.Fatal(err) 345 } 346 347 if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, dst.IP) { 348 t.Fatal("Add update not received as expected") 349 } 350 if err := RouteDel(&route); err != nil { 351 t.Fatal(err) 352 } 353 if !expectRouteUpdate(ch, unix.RTM_DELROUTE, dst.IP) { 354 t.Fatal("Del update not received as expected") 355 } 356 } 357 358 func TestRouteSubscribeWithOptions(t *testing.T) { 359 tearDown := setUpNetlinkTest(t) 360 defer tearDown() 361 362 ch := make(chan RouteUpdate) 363 done := make(chan struct{}) 364 defer close(done) 365 var lastError error 366 defer func() { 367 if lastError != nil { 368 t.Fatalf("Fatal error received during subscription: %v", lastError) 369 } 370 }() 371 if err := RouteSubscribeWithOptions(ch, done, RouteSubscribeOptions{ 372 ErrorCallback: func(err error) { 373 lastError = err 374 }, 375 }); err != nil { 376 t.Fatal(err) 377 } 378 379 // get loopback interface 380 link, err := LinkByName("lo") 381 if err != nil { 382 t.Fatal(err) 383 } 384 385 // bring the interface up 386 if err = LinkSetUp(link); err != nil { 387 t.Fatal(err) 388 } 389 390 // add a gateway route 391 dst := &net.IPNet{ 392 IP: net.IPv4(192, 168, 0, 0), 393 Mask: net.CIDRMask(24, 32), 394 } 395 396 ip := net.IPv4(127, 1, 1, 1) 397 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 398 if err := RouteAdd(&route); err != nil { 399 t.Fatal(err) 400 } 401 402 if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, dst.IP) { 403 t.Fatal("Add update not received as expected") 404 } 405 } 406 407 func TestRouteSubscribeAt(t *testing.T) { 408 skipUnlessRoot(t) 409 410 // Create an handle on a custom netns 411 newNs, err := netns.New() 412 if err != nil { 413 t.Fatal(err) 414 } 415 defer newNs.Close() 416 417 nh, err := NewHandleAt(newNs) 418 if err != nil { 419 t.Fatal(err) 420 } 421 defer nh.Close() 422 423 // Subscribe for Route events on the custom netns 424 ch := make(chan RouteUpdate) 425 done := make(chan struct{}) 426 defer close(done) 427 if err := RouteSubscribeAt(newNs, ch, done); err != nil { 428 t.Fatal(err) 429 } 430 431 // get loopback interface 432 link, err := nh.LinkByName("lo") 433 if err != nil { 434 t.Fatal(err) 435 } 436 437 // bring the interface up 438 if err = nh.LinkSetUp(link); err != nil { 439 t.Fatal(err) 440 } 441 442 // add a gateway route 443 dst := &net.IPNet{ 444 IP: net.IPv4(192, 169, 0, 0), 445 Mask: net.CIDRMask(24, 32), 446 } 447 448 ip := net.IPv4(127, 100, 1, 1) 449 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 450 if err := nh.RouteAdd(&route); err != nil { 451 t.Fatal(err) 452 } 453 454 if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, dst.IP) { 455 t.Fatal("Add update not received as expected") 456 } 457 if err := nh.RouteDel(&route); err != nil { 458 t.Fatal(err) 459 } 460 if !expectRouteUpdate(ch, unix.RTM_DELROUTE, dst.IP) { 461 t.Fatal("Del update not received as expected") 462 } 463 } 464 465 func TestRouteSubscribeListExisting(t *testing.T) { 466 skipUnlessRoot(t) 467 468 // Create an handle on a custom netns 469 newNs, err := netns.New() 470 if err != nil { 471 t.Fatal(err) 472 } 473 defer newNs.Close() 474 475 nh, err := NewHandleAt(newNs) 476 if err != nil { 477 t.Fatal(err) 478 } 479 defer nh.Close() 480 481 // get loopback interface 482 link, err := nh.LinkByName("lo") 483 if err != nil { 484 t.Fatal(err) 485 } 486 487 // bring the interface up 488 if err = nh.LinkSetUp(link); err != nil { 489 t.Fatal(err) 490 } 491 492 // add a gateway route before subscribing 493 dst10 := &net.IPNet{ 494 IP: net.IPv4(10, 10, 10, 0), 495 Mask: net.CIDRMask(24, 32), 496 } 497 498 ip := net.IPv4(127, 100, 1, 1) 499 route10 := Route{LinkIndex: link.Attrs().Index, Dst: dst10, Src: ip} 500 if err := nh.RouteAdd(&route10); err != nil { 501 t.Fatal(err) 502 } 503 504 // Subscribe for Route events including existing routes 505 ch := make(chan RouteUpdate) 506 done := make(chan struct{}) 507 defer close(done) 508 if err := RouteSubscribeWithOptions(ch, done, RouteSubscribeOptions{ 509 Namespace: &newNs, 510 ListExisting: true}, 511 ); err != nil { 512 t.Fatal(err) 513 } 514 515 if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, dst10.IP) { 516 t.Fatal("Existing add update not received as expected") 517 } 518 519 // add a gateway route 520 dst := &net.IPNet{ 521 IP: net.IPv4(192, 169, 0, 0), 522 Mask: net.CIDRMask(24, 32), 523 } 524 525 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} 526 if err := nh.RouteAdd(&route); err != nil { 527 t.Fatal(err) 528 } 529 530 if !expectRouteUpdate(ch, unix.RTM_NEWROUTE, dst.IP) { 531 t.Fatal("Add update not received as expected") 532 } 533 if err := nh.RouteDel(&route); err != nil { 534 t.Fatal(err) 535 } 536 if !expectRouteUpdate(ch, unix.RTM_DELROUTE, dst.IP) { 537 t.Fatal("Del update not received as expected") 538 } 539 if err := nh.RouteDel(&route10); err != nil { 540 t.Fatal(err) 541 } 542 if !expectRouteUpdate(ch, unix.RTM_DELROUTE, dst10.IP) { 543 t.Fatal("Del update not received as expected") 544 } 545 } 546 547 func TestRouteFilterAllTables(t *testing.T) { 548 tearDown := setUpNetlinkTest(t) 549 defer tearDown() 550 551 // get loopback interface 552 link, err := LinkByName("lo") 553 if err != nil { 554 t.Fatal(err) 555 } 556 // bring the interface up 557 if err = LinkSetUp(link); err != nil { 558 t.Fatal(err) 559 } 560 561 // add a gateway route 562 dst := &net.IPNet{ 563 IP: net.IPv4(1, 1, 1, 1), 564 Mask: net.CIDRMask(32, 32), 565 } 566 567 tables := []int{1000, 1001, 1002} 568 src := net.IPv4(127, 3, 3, 3) 569 for _, table := range tables { 570 route := Route{ 571 LinkIndex: link.Attrs().Index, 572 Dst: dst, 573 Src: src, 574 Scope: unix.RT_SCOPE_LINK, 575 Priority: 13, 576 Table: table, 577 Type: unix.RTN_UNICAST, 578 Tos: 14, 579 Hoplimit: 100, 580 Realm: 328, 581 } 582 if err := RouteAdd(&route); err != nil { 583 t.Fatal(err) 584 } 585 } 586 routes, err := RouteListFiltered(FAMILY_V4, &Route{ 587 Dst: dst, 588 Src: src, 589 Scope: unix.RT_SCOPE_LINK, 590 Table: unix.RT_TABLE_UNSPEC, 591 Type: unix.RTN_UNICAST, 592 Tos: 14, 593 Hoplimit: 100, 594 Realm: 328, 595 }, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS|RT_FILTER_HOPLIMIT|RT_FILTER_REALM) 596 if err != nil { 597 t.Fatal(err) 598 } 599 if len(routes) != 3 { 600 t.Fatal("Routes not added properly") 601 } 602 603 for _, route := range routes { 604 if route.Scope != unix.RT_SCOPE_LINK { 605 t.Fatal("Invalid Scope. Route not added properly") 606 } 607 if route.Priority != 13 { 608 t.Fatal("Invalid Priority. Route not added properly") 609 } 610 if !tableIDIn(tables, route.Table) { 611 t.Fatalf("Invalid Table %d. Route not added properly", route.Table) 612 } 613 if route.Type != unix.RTN_UNICAST { 614 t.Fatal("Invalid Type. Route not added properly") 615 } 616 if route.Tos != 14 { 617 t.Fatal("Invalid Tos. Route not added properly") 618 } 619 if route.Hoplimit != 100 { 620 t.Fatal("Invalid Hoplimit. Route not added properly") 621 } 622 if route.Realm != 328 { 623 t.Fatal("Invalid Realm. Route not added properly") 624 } 625 } 626 } 627 628 func tableIDIn(ids []int, id int) bool { 629 for _, v := range ids { 630 if v == id { 631 return true 632 } 633 } 634 return false 635 } 636 637 func TestRouteExtraFields(t *testing.T) { 638 tearDown := setUpNetlinkTest(t) 639 defer tearDown() 640 641 // get loopback interface 642 link, err := LinkByName("lo") 643 if err != nil { 644 t.Fatal(err) 645 } 646 // bring the interface up 647 if err = LinkSetUp(link); err != nil { 648 t.Fatal(err) 649 } 650 651 // add a gateway route 652 dst := &net.IPNet{ 653 IP: net.IPv4(1, 1, 1, 1), 654 Mask: net.CIDRMask(32, 32), 655 } 656 657 src := net.IPv4(127, 3, 3, 3) 658 route := Route{ 659 LinkIndex: link.Attrs().Index, 660 Dst: dst, 661 Src: src, 662 Scope: unix.RT_SCOPE_LINK, 663 Priority: 13, 664 Table: unix.RT_TABLE_MAIN, 665 Type: unix.RTN_UNICAST, 666 Tos: 14, 667 Hoplimit: 100, 668 Realm: 239, 669 } 670 if err := RouteAdd(&route); err != nil { 671 t.Fatal(err) 672 } 673 routes, err := RouteListFiltered(FAMILY_V4, &Route{ 674 Dst: dst, 675 Src: src, 676 Scope: unix.RT_SCOPE_LINK, 677 Table: unix.RT_TABLE_MAIN, 678 Type: unix.RTN_UNICAST, 679 Tos: 14, 680 Hoplimit: 100, 681 Realm: 239, 682 }, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS|RT_FILTER_HOPLIMIT|RT_FILTER_REALM) 683 if err != nil { 684 t.Fatal(err) 685 } 686 if len(routes) != 1 { 687 t.Fatal("Route not added properly") 688 } 689 690 if routes[0].Scope != unix.RT_SCOPE_LINK { 691 t.Fatal("Invalid Scope. Route not added properly") 692 } 693 if routes[0].Priority != 13 { 694 t.Fatal("Invalid Priority. Route not added properly") 695 } 696 if routes[0].Table != unix.RT_TABLE_MAIN { 697 t.Fatal("Invalid Scope. Route not added properly") 698 } 699 if routes[0].Type != unix.RTN_UNICAST { 700 t.Fatal("Invalid Type. Route not added properly") 701 } 702 if routes[0].Tos != 14 { 703 t.Fatal("Invalid Tos. Route not added properly") 704 } 705 if routes[0].Hoplimit != 100 { 706 t.Fatal("Invalid Hoplimit. Route not added properly") 707 } 708 if routes[0].Realm != 239 { 709 t.Fatal("Invalid Realm. Route not added properly") 710 } 711 } 712 713 func TestRouteMultiPath(t *testing.T) { 714 tearDown := setUpNetlinkTest(t) 715 defer tearDown() 716 717 // get loopback interface 718 link, err := LinkByName("lo") 719 if err != nil { 720 t.Fatal(err) 721 } 722 // bring the interface up 723 if err = LinkSetUp(link); err != nil { 724 t.Fatal(err) 725 } 726 727 // add a gateway route 728 dst := &net.IPNet{ 729 IP: net.IPv4(192, 168, 0, 0), 730 Mask: net.CIDRMask(24, 32), 731 } 732 733 idx := link.Attrs().Index 734 route := Route{Dst: dst, MultiPath: []*NexthopInfo{{LinkIndex: idx}, {LinkIndex: idx}}} 735 if err := RouteAdd(&route); err != nil { 736 t.Fatal(err) 737 } 738 routes, err := RouteList(nil, FAMILY_V4) 739 if err != nil { 740 t.Fatal(err) 741 } 742 if len(routes) != 1 { 743 t.Fatal("MultiPath Route not added properly") 744 } 745 if len(routes[0].MultiPath) != 2 { 746 t.Fatal("MultiPath Route not added properly") 747 } 748 } 749 750 func TestRouteOifOption(t *testing.T) { 751 tearDown := setUpNetlinkTest(t) 752 defer tearDown() 753 754 // setup two interfaces: eth0, eth1 755 err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}}) 756 if err != nil { 757 t.Fatal(err) 758 } 759 760 link1, err := LinkByName("eth0") 761 if err != nil { 762 t.Fatal(err) 763 } 764 765 if err = LinkSetUp(link1); err != nil { 766 t.Fatal(err) 767 } 768 769 if err = LinkAdd(&Dummy{LinkAttrs{Name: "eth1"}}); err != nil { 770 t.Fatal(err) 771 } 772 773 link2, err := LinkByName("eth1") 774 if err != nil { 775 t.Fatal(err) 776 } 777 778 if err = LinkSetUp(link2); err != nil { 779 t.Fatal(err) 780 } 781 782 // config ip addresses on interfaces 783 addr1 := &Addr{ 784 IPNet: &net.IPNet{ 785 IP: net.IPv4(192, 168, 1, 1), 786 Mask: net.CIDRMask(24, 32), 787 }, 788 } 789 790 if err = AddrAdd(link1, addr1); err != nil { 791 t.Fatal(err) 792 } 793 794 addr2 := &Addr{ 795 IPNet: &net.IPNet{ 796 IP: net.IPv4(192, 168, 2, 1), 797 Mask: net.CIDRMask(24, 32), 798 }, 799 } 800 801 if err = AddrAdd(link2, addr2); err != nil { 802 t.Fatal(err) 803 } 804 805 // add default multipath route 806 dst := &net.IPNet{ 807 IP: net.IPv4(0, 0, 0, 0), 808 Mask: net.CIDRMask(0, 32), 809 } 810 gw1 := net.IPv4(192, 168, 1, 254) 811 gw2 := net.IPv4(192, 168, 2, 254) 812 route := Route{Dst: dst, MultiPath: []*NexthopInfo{{LinkIndex: link1.Attrs().Index, 813 Gw: gw1}, {LinkIndex: link2.Attrs().Index, Gw: gw2}}} 814 if err := RouteAdd(&route); err != nil { 815 t.Fatal(err) 816 } 817 818 // check getting route from specified Oif 819 dstIP := net.IPv4(10, 1, 1, 1) 820 routes, err := RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth0"}) 821 if err != nil { 822 t.Fatal(err) 823 } 824 825 if len(routes) != 1 || routes[0].LinkIndex != link1.Attrs().Index || 826 !routes[0].Gw.Equal(gw1) { 827 t.Fatal("Get route from unmatched interface") 828 } 829 830 routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{Oif: "eth1"}) 831 if err != nil { 832 t.Fatal(err) 833 } 834 835 if len(routes) != 1 || routes[0].LinkIndex != link2.Attrs().Index || 836 !routes[0].Gw.Equal(gw2) { 837 t.Fatal("Get route from unmatched interface") 838 } 839 840 } 841 842 func TestFilterDefaultRoute(t *testing.T) { 843 tearDown := setUpNetlinkTest(t) 844 defer tearDown() 845 846 // get loopback interface 847 link, err := LinkByName("lo") 848 if err != nil { 849 t.Fatal(err) 850 } 851 // bring the interface up 852 if err = LinkSetUp(link); err != nil { 853 t.Fatal(err) 854 } 855 856 address := &Addr{ 857 IPNet: &net.IPNet{ 858 IP: net.IPv4(127, 0, 0, 2), 859 Mask: net.CIDRMask(24, 32), 860 }, 861 } 862 if err = AddrAdd(link, address); err != nil { 863 t.Fatal(err) 864 } 865 866 // Add default route 867 gw := net.IPv4(127, 0, 0, 2) 868 869 defaultRoute := Route{ 870 Dst: nil, 871 Gw: gw, 872 } 873 874 if err := RouteAdd(&defaultRoute); err != nil { 875 t.Fatal(err) 876 } 877 878 // add an extra route 879 dst := &net.IPNet{ 880 IP: net.IPv4(192, 168, 0, 0), 881 Mask: net.CIDRMask(24, 32), 882 } 883 884 extraRoute := Route{ 885 Dst: dst, 886 Gw: gw, 887 } 888 889 if err := RouteAdd(&extraRoute); err != nil { 890 t.Fatal(err) 891 } 892 var filterTests = []struct { 893 filter *Route 894 mask uint64 895 expected net.IP 896 }{ 897 { 898 &Route{Dst: nil}, 899 RT_FILTER_DST, 900 gw, 901 }, 902 { 903 &Route{Dst: dst}, 904 RT_FILTER_DST, 905 gw, 906 }, 907 } 908 909 for _, f := range filterTests { 910 routes, err := RouteListFiltered(FAMILY_V4, f.filter, f.mask) 911 if err != nil { 912 t.Fatal(err) 913 } 914 if len(routes) != 1 { 915 t.Fatal("Route not filtered properly") 916 } 917 if !routes[0].Gw.Equal(gw) { 918 t.Fatal("Unexpected Gateway") 919 } 920 } 921 922 } 923 924 func TestMPLSRouteAddDel(t *testing.T) { 925 tearDown := setUpMPLSNetlinkTest(t) 926 defer tearDown() 927 928 // get loopback interface 929 link, err := LinkByName("lo") 930 if err != nil { 931 t.Fatal(err) 932 } 933 934 // bring the interface up 935 if err := LinkSetUp(link); err != nil { 936 t.Fatal(err) 937 } 938 939 mplsDst := 100 940 route := Route{ 941 LinkIndex: link.Attrs().Index, 942 MPLSDst: &mplsDst, 943 NewDst: &MPLSDestination{ 944 Labels: []int{200, 300}, 945 }, 946 } 947 if err := RouteAdd(&route); err != nil { 948 t.Fatal(err) 949 } 950 routes, err := RouteList(link, FAMILY_MPLS) 951 if err != nil { 952 t.Fatal(err) 953 } 954 if len(routes) != 1 { 955 t.Fatal("Route not added properly") 956 } 957 958 if err := RouteDel(&route); err != nil { 959 t.Fatal(err) 960 } 961 routes, err = RouteList(link, FAMILY_MPLS) 962 if err != nil { 963 t.Fatal(err) 964 } 965 if len(routes) != 0 { 966 t.Fatal("Route not removed properly") 967 } 968 969 } 970 971 func TestRouteEqual(t *testing.T) { 972 mplsDst := 100 973 seg6encap := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP} 974 seg6encap.Segments = []net.IP{net.ParseIP("fc00:a000::11")} 975 cases := []Route{ 976 { 977 Dst: nil, 978 Gw: net.IPv4(1, 1, 1, 1), 979 }, 980 { 981 LinkIndex: 20, 982 Dst: nil, 983 Gw: net.IPv4(1, 1, 1, 1), 984 }, 985 { 986 ILinkIndex: 21, 987 LinkIndex: 20, 988 Dst: nil, 989 Gw: net.IPv4(1, 1, 1, 1), 990 }, 991 { 992 LinkIndex: 20, 993 Dst: nil, 994 Protocol: 20, 995 Gw: net.IPv4(1, 1, 1, 1), 996 }, 997 { 998 LinkIndex: 20, 999 Dst: nil, 1000 Priority: 20, 1001 Gw: net.IPv4(1, 1, 1, 1), 1002 }, 1003 { 1004 LinkIndex: 20, 1005 Dst: nil, 1006 Type: 20, 1007 Gw: net.IPv4(1, 1, 1, 1), 1008 }, 1009 { 1010 LinkIndex: 20, 1011 Dst: nil, 1012 Table: 200, 1013 Gw: net.IPv4(1, 1, 1, 1), 1014 }, 1015 { 1016 LinkIndex: 20, 1017 Dst: nil, 1018 Tos: 1, 1019 Gw: net.IPv4(1, 1, 1, 1), 1020 }, 1021 { 1022 LinkIndex: 20, 1023 Dst: nil, 1024 Hoplimit: 1, 1025 Gw: net.IPv4(1, 1, 1, 1), 1026 }, 1027 { 1028 LinkIndex: 20, 1029 Dst: nil, 1030 Realm: 29, 1031 Gw: net.IPv4(1, 1, 1, 1), 1032 }, 1033 { 1034 LinkIndex: 20, 1035 Dst: nil, 1036 Flags: int(FLAG_ONLINK), 1037 Gw: net.IPv4(1, 1, 1, 1), 1038 }, 1039 { 1040 LinkIndex: 10, 1041 Dst: &net.IPNet{ 1042 IP: net.IPv4(192, 168, 0, 0), 1043 Mask: net.CIDRMask(24, 32), 1044 }, 1045 Src: net.IPv4(127, 1, 1, 1), 1046 }, 1047 { 1048 LinkIndex: 10, 1049 Scope: unix.RT_SCOPE_LINK, 1050 Dst: &net.IPNet{ 1051 IP: net.IPv4(192, 168, 0, 0), 1052 Mask: net.CIDRMask(24, 32), 1053 }, 1054 Src: net.IPv4(127, 1, 1, 1), 1055 }, 1056 { 1057 LinkIndex: 3, 1058 Dst: &net.IPNet{ 1059 IP: net.IPv4(1, 1, 1, 1), 1060 Mask: net.CIDRMask(32, 32), 1061 }, 1062 Src: net.IPv4(127, 3, 3, 3), 1063 Scope: unix.RT_SCOPE_LINK, 1064 Priority: 13, 1065 Table: unix.RT_TABLE_MAIN, 1066 Type: unix.RTN_UNICAST, 1067 Tos: 14, 1068 }, 1069 { 1070 LinkIndex: 3, 1071 Dst: &net.IPNet{ 1072 IP: net.IPv4(1, 1, 1, 1), 1073 Mask: net.CIDRMask(32, 32), 1074 }, 1075 Src: net.IPv4(127, 3, 3, 3), 1076 Scope: unix.RT_SCOPE_LINK, 1077 Priority: 13, 1078 Table: unix.RT_TABLE_MAIN, 1079 Type: unix.RTN_UNICAST, 1080 Hoplimit: 100, 1081 }, 1082 { 1083 LinkIndex: 3, 1084 Dst: &net.IPNet{ 1085 IP: net.IPv4(1, 1, 1, 1), 1086 Mask: net.CIDRMask(32, 32), 1087 }, 1088 Src: net.IPv4(127, 3, 3, 3), 1089 Scope: unix.RT_SCOPE_LINK, 1090 Priority: 13, 1091 Table: unix.RT_TABLE_MAIN, 1092 Type: unix.RTN_UNICAST, 1093 Realm: 129, 1094 }, 1095 { 1096 LinkIndex: 10, 1097 MPLSDst: &mplsDst, 1098 NewDst: &MPLSDestination{ 1099 Labels: []int{200, 300}, 1100 }, 1101 }, 1102 { 1103 Dst: nil, 1104 Gw: net.IPv4(1, 1, 1, 1), 1105 Encap: &MPLSEncap{ 1106 Labels: []int{100}, 1107 }, 1108 }, 1109 { 1110 LinkIndex: 10, 1111 Dst: &net.IPNet{ 1112 IP: net.IPv4(10, 0, 0, 102), 1113 Mask: net.CIDRMask(32, 32), 1114 }, 1115 Encap: seg6encap, 1116 }, 1117 { 1118 Dst: nil, 1119 MultiPath: []*NexthopInfo{{LinkIndex: 10}, {LinkIndex: 20}}, 1120 }, 1121 { 1122 Dst: nil, 1123 MultiPath: []*NexthopInfo{{ 1124 LinkIndex: 10, 1125 Gw: net.IPv4(1, 1, 1, 1), 1126 }, {LinkIndex: 20}}, 1127 }, 1128 { 1129 Dst: nil, 1130 MultiPath: []*NexthopInfo{{ 1131 LinkIndex: 10, 1132 Gw: net.IPv4(1, 1, 1, 1), 1133 Encap: &MPLSEncap{ 1134 Labels: []int{100}, 1135 }, 1136 }, {LinkIndex: 20}}, 1137 }, 1138 { 1139 Dst: nil, 1140 MultiPath: []*NexthopInfo{{ 1141 LinkIndex: 10, 1142 NewDst: &MPLSDestination{ 1143 Labels: []int{200, 300}, 1144 }, 1145 }, {LinkIndex: 20}}, 1146 }, 1147 { 1148 Dst: nil, 1149 MultiPath: []*NexthopInfo{{ 1150 LinkIndex: 10, 1151 Encap: seg6encap, 1152 }, {LinkIndex: 20}}, 1153 }, 1154 } 1155 for i1 := range cases { 1156 for i2 := range cases { 1157 got := cases[i1].Equal(cases[i2]) 1158 expected := i1 == i2 1159 if got != expected { 1160 t.Errorf("Equal(%q,%q) == %s but expected %s", 1161 cases[i1], cases[i2], 1162 strconv.FormatBool(got), 1163 strconv.FormatBool(expected)) 1164 } 1165 } 1166 } 1167 } 1168 1169 func TestIPNetEqual(t *testing.T) { 1170 cases := []string{ 1171 "1.1.1.1/24", "1.1.1.0/24", "1.1.1.1/32", 1172 "0.0.0.0/0", "0.0.0.0/14", 1173 "2001:db8::/32", "2001:db8::/128", 1174 "2001:db8::caff/32", "2001:db8::caff/128", 1175 "", 1176 } 1177 for _, c1 := range cases { 1178 var n1 *net.IPNet 1179 if c1 != "" { 1180 var i1 net.IP 1181 var err1 error 1182 i1, n1, err1 = net.ParseCIDR(c1) 1183 if err1 != nil { 1184 panic(err1) 1185 } 1186 n1.IP = i1 1187 } 1188 for _, c2 := range cases { 1189 var n2 *net.IPNet 1190 if c2 != "" { 1191 var i2 net.IP 1192 var err2 error 1193 i2, n2, err2 = net.ParseCIDR(c2) 1194 if err2 != nil { 1195 panic(err2) 1196 } 1197 n2.IP = i2 1198 } 1199 1200 got := ipNetEqual(n1, n2) 1201 expected := c1 == c2 1202 if got != expected { 1203 t.Errorf("IPNetEqual(%q,%q) == %s but expected %s", 1204 c1, c2, 1205 strconv.FormatBool(got), 1206 strconv.FormatBool(expected)) 1207 } 1208 } 1209 } 1210 } 1211 1212 func TestSEG6LocalEqual(t *testing.T) { 1213 // Different attributes exists in different Actions. For example, Action 1214 // SEG6_LOCAL_ACTION_END_X has In6Addr, SEG6_LOCAL_ACTION_END_T has Table etc. 1215 segs := []net.IP{net.ParseIP("fc00:a000::11")} 1216 // set flags for each actions. 1217 var flags_end [nl.SEG6_LOCAL_MAX]bool 1218 flags_end[nl.SEG6_LOCAL_ACTION] = true 1219 var flags_end_x [nl.SEG6_LOCAL_MAX]bool 1220 flags_end_x[nl.SEG6_LOCAL_ACTION] = true 1221 flags_end_x[nl.SEG6_LOCAL_NH6] = true 1222 var flags_end_t [nl.SEG6_LOCAL_MAX]bool 1223 flags_end_t[nl.SEG6_LOCAL_ACTION] = true 1224 flags_end_t[nl.SEG6_LOCAL_TABLE] = true 1225 var flags_end_dx2 [nl.SEG6_LOCAL_MAX]bool 1226 flags_end_dx2[nl.SEG6_LOCAL_ACTION] = true 1227 flags_end_dx2[nl.SEG6_LOCAL_OIF] = true 1228 var flags_end_dx6 [nl.SEG6_LOCAL_MAX]bool 1229 flags_end_dx6[nl.SEG6_LOCAL_ACTION] = true 1230 flags_end_dx6[nl.SEG6_LOCAL_NH6] = true 1231 var flags_end_dx4 [nl.SEG6_LOCAL_MAX]bool 1232 flags_end_dx4[nl.SEG6_LOCAL_ACTION] = true 1233 flags_end_dx4[nl.SEG6_LOCAL_NH4] = true 1234 var flags_end_dt6 [nl.SEG6_LOCAL_MAX]bool 1235 flags_end_dt6[nl.SEG6_LOCAL_ACTION] = true 1236 flags_end_dt6[nl.SEG6_LOCAL_TABLE] = true 1237 var flags_end_dt4 [nl.SEG6_LOCAL_MAX]bool 1238 flags_end_dt4[nl.SEG6_LOCAL_ACTION] = true 1239 flags_end_dt4[nl.SEG6_LOCAL_TABLE] = true 1240 var flags_end_b6 [nl.SEG6_LOCAL_MAX]bool 1241 flags_end_b6[nl.SEG6_LOCAL_ACTION] = true 1242 flags_end_b6[nl.SEG6_LOCAL_SRH] = true 1243 var flags_end_b6_encaps [nl.SEG6_LOCAL_MAX]bool 1244 flags_end_b6_encaps[nl.SEG6_LOCAL_ACTION] = true 1245 flags_end_b6_encaps[nl.SEG6_LOCAL_SRH] = true 1246 1247 cases := []SEG6LocalEncap{ 1248 { 1249 Flags: flags_end, 1250 Action: nl.SEG6_LOCAL_ACTION_END, 1251 }, 1252 { 1253 Flags: flags_end_x, 1254 Action: nl.SEG6_LOCAL_ACTION_END_X, 1255 In6Addr: net.ParseIP("2001:db8::1"), 1256 }, 1257 { 1258 Flags: flags_end_t, 1259 Action: nl.SEG6_LOCAL_ACTION_END_T, 1260 Table: 10, 1261 }, 1262 { 1263 Flags: flags_end_dx2, 1264 Action: nl.SEG6_LOCAL_ACTION_END_DX2, 1265 Oif: 20, 1266 }, 1267 { 1268 Flags: flags_end_dx6, 1269 Action: nl.SEG6_LOCAL_ACTION_END_DX6, 1270 In6Addr: net.ParseIP("2001:db8::1"), 1271 }, 1272 { 1273 Flags: flags_end_dx4, 1274 Action: nl.SEG6_LOCAL_ACTION_END_DX4, 1275 InAddr: net.IPv4(192, 168, 10, 10), 1276 }, 1277 { 1278 Flags: flags_end_dt6, 1279 Action: nl.SEG6_LOCAL_ACTION_END_DT6, 1280 Table: 30, 1281 }, 1282 { 1283 Flags: flags_end_dt4, 1284 Action: nl.SEG6_LOCAL_ACTION_END_DT4, 1285 Table: 40, 1286 }, 1287 { 1288 Flags: flags_end_b6, 1289 Action: nl.SEG6_LOCAL_ACTION_END_B6, 1290 Segments: segs, 1291 }, 1292 { 1293 Flags: flags_end_b6_encaps, 1294 Action: nl.SEG6_LOCAL_ACTION_END_B6_ENCAPS, 1295 Segments: segs, 1296 }, 1297 } 1298 for i1 := range cases { 1299 for i2 := range cases { 1300 got := cases[i1].Equal(&cases[i2]) 1301 expected := i1 == i2 1302 if got != expected { 1303 t.Errorf("Equal(%v,%v) == %s but expected %s", 1304 cases[i1], cases[i2], 1305 strconv.FormatBool(got), 1306 strconv.FormatBool(expected)) 1307 } 1308 } 1309 } 1310 } 1311 func TestSEG6RouteAddDel(t *testing.T) { 1312 if os.Getenv("CI") == "true" { 1313 t.Skipf("Fails in CI with: route_test.go:*: Invalid Type. SEG6_IPTUN_MODE_INLINE routes not added properly") 1314 } 1315 // add/del routes with LWTUNNEL_SEG6 to/from loopback interface. 1316 // Test both seg6 modes: encap (IPv4) & inline (IPv6). 1317 tearDown := setUpSEG6NetlinkTest(t) 1318 defer tearDown() 1319 1320 // get loopback interface and bring it up 1321 link, err := LinkByName("lo") 1322 if err != nil { 1323 t.Fatal(err) 1324 } 1325 if err := LinkSetUp(link); err != nil { 1326 t.Fatal(err) 1327 } 1328 1329 dst1 := &net.IPNet{ // INLINE mode must be IPv6 route 1330 IP: net.ParseIP("2001:db8::1"), 1331 Mask: net.CIDRMask(128, 128), 1332 } 1333 dst2 := &net.IPNet{ 1334 IP: net.IPv4(10, 0, 0, 102), 1335 Mask: net.CIDRMask(32, 32), 1336 } 1337 var s1, s2 []net.IP 1338 s1 = append(s1, net.ParseIP("::")) // inline requires "::" 1339 s1 = append(s1, net.ParseIP("fc00:a000::12")) 1340 s1 = append(s1, net.ParseIP("fc00:a000::11")) 1341 s2 = append(s2, net.ParseIP("fc00:a000::22")) 1342 s2 = append(s2, net.ParseIP("fc00:a000::21")) 1343 e1 := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_INLINE} 1344 e2 := &SEG6Encap{Mode: nl.SEG6_IPTUN_MODE_ENCAP} 1345 e1.Segments = s1 1346 e2.Segments = s2 1347 route1 := Route{LinkIndex: link.Attrs().Index, Dst: dst1, Encap: e1} 1348 route2 := Route{LinkIndex: link.Attrs().Index, Dst: dst2, Encap: e2} 1349 1350 // Add SEG6 routes 1351 if err := RouteAdd(&route1); err != nil { 1352 t.Fatal(err) 1353 } 1354 if err := RouteAdd(&route2); err != nil { 1355 t.Fatal(err) 1356 } 1357 // SEG6_IPTUN_MODE_INLINE 1358 routes, err := RouteList(link, FAMILY_V6) 1359 if err != nil { 1360 t.Fatal(err) 1361 } 1362 if len(routes) != 1 { 1363 t.Fatal("SEG6 routes not added properly") 1364 } 1365 for _, route := range routes { 1366 if route.Encap == nil || route.Encap.Type() != nl.LWTUNNEL_ENCAP_SEG6 { 1367 t.Fatal("Invalid Type. SEG6_IPTUN_MODE_INLINE routes not added properly") 1368 } 1369 } 1370 // SEG6_IPTUN_MODE_ENCAP 1371 routes, err = RouteList(link, FAMILY_V4) 1372 if err != nil { 1373 t.Fatal(err) 1374 } 1375 if len(routes) != 1 { 1376 t.Fatal("SEG6 routes not added properly") 1377 } 1378 for _, route := range routes { 1379 if route.Encap.Type() != nl.LWTUNNEL_ENCAP_SEG6 { 1380 t.Fatal("Invalid Type. SEG6_IPTUN_MODE_ENCAP routes not added properly") 1381 } 1382 } 1383 1384 // Del (remove) SEG6 routes 1385 if err := RouteDel(&route1); err != nil { 1386 t.Fatal(err) 1387 } 1388 if err := RouteDel(&route2); err != nil { 1389 t.Fatal(err) 1390 } 1391 routes, err = RouteList(link, FAMILY_V4) 1392 if err != nil { 1393 t.Fatal(err) 1394 } 1395 if len(routes) != 0 { 1396 t.Fatal("SEG6 routes not removed properly") 1397 } 1398 } 1399 1400 // add/del routes with LWTUNNEL_ENCAP_SEG6_LOCAL to/from dummy interface. 1401 func TestSEG6LocalRoute6AddDel(t *testing.T) { 1402 minKernelRequired(t, 4, 14) 1403 tearDown := setUpSEG6NetlinkTest(t) 1404 defer tearDown() 1405 1406 // create dummy interface 1407 // IPv6 route added to loopback interface will be unreachable 1408 la := NewLinkAttrs() 1409 la.Name = "dummy_route6" 1410 la.TxQLen = 1500 1411 dummy := &Dummy{LinkAttrs: la} 1412 if err := LinkAdd(dummy); err != nil { 1413 t.Fatal(err) 1414 } 1415 // get dummy interface and bring it up 1416 link, err := LinkByName("dummy_route6") 1417 if err != nil { 1418 t.Fatal(err) 1419 } 1420 if err := LinkSetUp(link); err != nil { 1421 t.Fatal(err) 1422 } 1423 1424 dst1 := &net.IPNet{ 1425 IP: net.ParseIP("2001:db8::1"), 1426 Mask: net.CIDRMask(128, 128), 1427 } 1428 1429 // Create Route including Action SEG6_LOCAL_ACTION_END_B6. 1430 // Could be any Action but thought better to have seg list. 1431 var s1 []net.IP 1432 s1 = append(s1, net.ParseIP("fc00:a000::12")) 1433 s1 = append(s1, net.ParseIP("fc00:a000::11")) 1434 var flags_end_b6_encaps [nl.SEG6_LOCAL_MAX]bool 1435 flags_end_b6_encaps[nl.SEG6_LOCAL_ACTION] = true 1436 flags_end_b6_encaps[nl.SEG6_LOCAL_SRH] = true 1437 e1 := &SEG6LocalEncap{ 1438 Flags: flags_end_b6_encaps, 1439 Action: nl.SEG6_LOCAL_ACTION_END_B6, 1440 Segments: s1, 1441 } 1442 route1 := Route{LinkIndex: link.Attrs().Index, Dst: dst1, Encap: e1} 1443 1444 // Add SEG6Local routes 1445 if err := RouteAdd(&route1); err != nil { 1446 t.Fatal(err) 1447 } 1448 1449 // typically one route (fe80::/64) will be created when dummy_route6 is created. 1450 // Thus you cannot use RouteList() to find the route entry just added. 1451 // Lookup route and confirm it's SEG6Local route just added. 1452 routesFound, err := RouteGet(dst1.IP) 1453 if err != nil { 1454 t.Fatal(err) 1455 } 1456 if len(routesFound) != 1 { // should only find 1 route entry 1457 t.Fatal("SEG6Local route not added correctly") 1458 } 1459 if !e1.Equal(routesFound[0].Encap) { 1460 t.Fatal("Encap does not match the original SEG6LocalEncap") 1461 } 1462 1463 // Del SEG6Local routes 1464 if err := RouteDel(&route1); err != nil { 1465 t.Fatal(err) 1466 } 1467 // Confirm route is deleted. 1468 if _, err = RouteGet(dst1.IP); err == nil { 1469 t.Fatal("SEG6Local route still exists.") 1470 } 1471 1472 // cleanup dummy interface created for the test 1473 if err := LinkDel(link); err != nil { 1474 t.Fatal(err) 1475 } 1476 } 1477 1478 func TestBpfEncap(t *testing.T) { 1479 tCase := &BpfEncap{} 1480 if err := tCase.SetProg(nl.LWT_BPF_IN, 0, "test_in"); err == nil { 1481 t.Fatal("BpfEncap: inserting invalid FD did not return error") 1482 } 1483 if err := tCase.SetProg(nl.LWT_BPF_XMIT_HEADROOM, 23, "test_nout"); err == nil { 1484 t.Fatal("BpfEncap: inserting invalid mode did not return error") 1485 } 1486 if err := tCase.SetProg(nl.LWT_BPF_XMIT, 12, "test_xmit"); err != nil { 1487 t.Fatal("BpfEncap: inserting valid program option returned error") 1488 } 1489 if err := tCase.SetXmitHeadroom(12); err != nil { 1490 t.Fatal("BpfEncap: inserting valid headroom returned error") 1491 } 1492 if err := tCase.SetXmitHeadroom(nl.LWT_BPF_MAX_HEADROOM + 1); err == nil { 1493 t.Fatal("BpfEncap: inserting invalid headroom did not return error") 1494 } 1495 tCase = &BpfEncap{} 1496 1497 expected := &BpfEncap{ 1498 progs: [nl.LWT_BPF_MAX]bpfObj{ 1499 1: { 1500 progName: "test_in[fd:10]", 1501 progFd: 10, 1502 }, 1503 2: { 1504 progName: "test_out[fd:11]", 1505 progFd: 11, 1506 }, 1507 3: { 1508 progName: "test_xmit[fd:21]", 1509 progFd: 21, 1510 }, 1511 }, 1512 headroom: 128, 1513 } 1514 1515 _ = tCase.SetProg(1, 10, "test_in") 1516 _ = tCase.SetProg(2, 11, "test_out") 1517 _ = tCase.SetProg(3, 21, "test_xmit") 1518 _ = tCase.SetXmitHeadroom(128) 1519 if !tCase.Equal(expected) { 1520 t.Fatal("BpfEncap: equal comparison failed") 1521 } 1522 _ = tCase.SetProg(3, 21, "test2_xmit") 1523 if tCase.Equal(expected) { 1524 t.Fatal("BpfEncap: equal comparison succeeded when attributes differ") 1525 } 1526 } 1527 1528 func TestMTURouteAddDel(t *testing.T) { 1529 _, err := RouteList(nil, FAMILY_V4) 1530 if err != nil { 1531 t.Fatal(err) 1532 } 1533 1534 tearDown := setUpNetlinkTest(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 // add a gateway route 1549 dst := &net.IPNet{ 1550 IP: net.IPv4(192, 168, 0, 0), 1551 Mask: net.CIDRMask(24, 32), 1552 } 1553 1554 route := Route{LinkIndex: link.Attrs().Index, Dst: dst, MTU: 500} 1555 if err := RouteAdd(&route); err != nil { 1556 t.Fatal(err) 1557 } 1558 routes, err := RouteList(link, FAMILY_V4) 1559 if err != nil { 1560 t.Fatal(err) 1561 } 1562 if len(routes) != 1 { 1563 t.Fatal("Route not added properly") 1564 } 1565 1566 if route.MTU != routes[0].MTU { 1567 t.Fatal("Route mtu not set properly") 1568 } 1569 1570 if err := RouteDel(&route); err != nil { 1571 t.Fatal(err) 1572 } 1573 routes, err = RouteList(link, FAMILY_V4) 1574 if err != nil { 1575 t.Fatal(err) 1576 } 1577 if len(routes) != 0 { 1578 t.Fatal("Route not removed properly") 1579 } 1580 } 1581 1582 func TestRouteViaAddDel(t *testing.T) { 1583 minKernelRequired(t, 5, 4) 1584 tearDown := setUpNetlinkTest(t) 1585 defer tearDown() 1586 1587 _, err := RouteList(nil, FAMILY_V4) 1588 if err != nil { 1589 t.Fatal(err) 1590 } 1591 1592 link, err := LinkByName("lo") 1593 if err != nil { 1594 t.Fatal(err) 1595 } 1596 1597 if err := LinkSetUp(link); err != nil { 1598 t.Fatal(err) 1599 } 1600 1601 route := &Route{ 1602 LinkIndex: link.Attrs().Index, 1603 Dst: &net.IPNet{ 1604 IP: net.IPv4(192, 168, 0, 0), 1605 Mask: net.CIDRMask(24, 32), 1606 }, 1607 MultiPath: []*NexthopInfo{ 1608 { 1609 LinkIndex: link.Attrs().Index, 1610 Via: &Via{ 1611 AddrFamily: FAMILY_V6, 1612 Addr: net.ParseIP("2001::1"), 1613 }, 1614 }, 1615 }, 1616 } 1617 1618 if err := RouteAdd(route); err != nil { 1619 t.Fatalf("route: %v, err: %v", route, err) 1620 } 1621 1622 routes, err := RouteList(link, FAMILY_V4) 1623 if err != nil { 1624 t.Fatal(err) 1625 } 1626 if len(routes) != 1 { 1627 t.Fatal("Route not added properly") 1628 } 1629 1630 got := routes[0].Via 1631 want := route.MultiPath[0].Via 1632 if !want.Equal(got) { 1633 t.Fatalf("Route Via attribute does not match; got: %s, want: %s", got, want) 1634 } 1635 1636 if err := RouteDel(route); err != nil { 1637 t.Fatal(err) 1638 } 1639 routes, err = RouteList(link, FAMILY_V4) 1640 if err != nil { 1641 t.Fatal(err) 1642 } 1643 if len(routes) != 0 { 1644 t.Fatal("Route not removed properly") 1645 } 1646 } 1647 1648 func TestRouteUIDOption(t *testing.T) { 1649 tearDown := setUpNetlinkTest(t) 1650 defer tearDown() 1651 1652 // setup eth0 so that network is reachable 1653 err := LinkAdd(&Dummy{LinkAttrs{Name: "eth0"}}) 1654 if err != nil { 1655 t.Fatal(err) 1656 } 1657 link, err := LinkByName("eth0") 1658 if err != nil { 1659 t.Fatal(err) 1660 } 1661 if err = LinkSetUp(link); err != nil { 1662 t.Fatal(err) 1663 } 1664 addr := &Addr{ 1665 IPNet: &net.IPNet{ 1666 IP: net.IPv4(192, 168, 1, 1), 1667 Mask: net.CIDRMask(16, 32), 1668 }, 1669 } 1670 if err = AddrAdd(link, addr); err != nil { 1671 t.Fatal(err) 1672 } 1673 1674 // a table different than unix.RT_TABLE_MAIN 1675 testtable := 1000 1676 1677 gw1 := net.IPv4(192, 168, 1, 254) 1678 gw2 := net.IPv4(192, 168, 2, 254) 1679 1680 // add default route via gw1 (in main route table by default) 1681 defaultRouteMain := Route{ 1682 Dst: nil, 1683 Gw: gw1, 1684 } 1685 if err := RouteAdd(&defaultRouteMain); err != nil { 1686 t.Fatal(err) 1687 } 1688 1689 // add default route via gw2 in test route table 1690 defaultRouteTest := Route{ 1691 Dst: nil, 1692 Gw: gw2, 1693 Table: testtable, 1694 } 1695 if err := RouteAdd(&defaultRouteTest); err != nil { 1696 t.Fatal(err) 1697 } 1698 1699 // check the routes are in different tables 1700 routes, err := RouteListFiltered(FAMILY_V4, &Route{ 1701 Dst: nil, 1702 Table: unix.RT_TABLE_UNSPEC, 1703 }, RT_FILTER_DST|RT_FILTER_TABLE) 1704 if err != nil { 1705 t.Fatal(err) 1706 } 1707 if len(routes) != 2 || routes[0].Table == routes[1].Table { 1708 t.Fatal("Routes not added properly") 1709 } 1710 1711 // add a rule that uidrange match should result in route lookup of test table for uid other than current 1712 // current uid is 0 due to skipUnlessRoot() 1713 var uid uint32 = 1000 1714 rule := NewRule() 1715 rule.UIDRange = NewRuleUIDRange(uid, uid) 1716 rule.Table = testtable 1717 if err := RuleAdd(rule); err != nil { 1718 t.Fatal(err) 1719 } 1720 1721 dstIP := net.IPv4(10, 1, 1, 1) 1722 1723 // check getting route without UID option 1724 routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{UID: nil}) 1725 if err != nil { 1726 t.Fatal(err) 1727 } 1728 // current uid is outside uidrange; rule does not apply; lookup main table 1729 if len(routes) != 1 || !routes[0].Gw.Equal(gw1) { 1730 t.Fatal(routes) 1731 } 1732 1733 // check getting route with UID option 1734 routes, err = RouteGetWithOptions(dstIP, &RouteGetOptions{UID: &uid}) 1735 if err != nil { 1736 t.Fatal(err) 1737 } 1738 // option uid is within uidrange; rule applies; lookup test table 1739 if len(routes) != 1 || !routes[0].Gw.Equal(gw2) { 1740 t.Fatal(routes) 1741 } 1742 }