diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref index 993b4df6a216..044cffae7a45 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -10,8 +10,14 @@ C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, weight 1, XX:XX:XX -S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth0, weight 1, XX:XX:XX -S>* 1.1.1.2/32 [1/0] is directly connected, r1-eth1, weight 1, XX:XX:XX +S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth1, weight 1, XX:XX:XX +S>* 1.1.1.2/32 [1/0] is directly connected, r1-eth2, weight 1, XX:XX:XX +S>* 1.1.1.3/32 [1/0] is directly connected, r1-eth3, weight 1, XX:XX:XX +S>* 1.1.1.4/32 [1/0] is directly connected, r1-eth4, weight 1, XX:XX:XX +S>* 1.1.1.5/32 [1/0] is directly connected, r1-eth5, weight 1, XX:XX:XX +S>* 1.1.1.6/32 [1/0] is directly connected, r1-eth6, weight 1, XX:XX:XX +S>* 1.1.1.7/32 [1/0] is directly connected, r1-eth7, weight 1, XX:XX:XX +S>* 1.1.1.8/32 [1/0] is directly connected, r1-eth8, weight 1, XX:XX:XX S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, weight 1, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf index 858a8a585df2..c5ef79630e21 100644 --- a/tests/topotests/all-protocol-startup/r1/zebra.conf +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -27,8 +27,14 @@ ipv6 route 4:5::6:12/128 r1-eth0 ip route 4.5.6.15/32 192.168.0.2 255 ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255 # Routes to put into a nexthop-group -ip route 1.1.1.1/32 r1-eth0 -ip route 1.1.1.2/32 r1-eth1 +ip route 1.1.1.1/32 r1-eth1 +ip route 1.1.1.2/32 r1-eth2 +ip route 1.1.1.3/32 r1-eth3 +ip route 1.1.1.4/32 r1-eth4 +ip route 1.1.1.5/32 r1-eth5 +ip route 1.1.1.6/32 r1-eth6 +ip route 1.1.1.7/32 r1-eth7 +ip route 1.1.1.8/32 r1-eth8 # Create a route that has overlapping distance # so we have backups diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index 5f23525a1b0e..f78c2b4bc055 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -347,6 +347,35 @@ def test_converge_protocols(): # For debugging after starting FRR/Quagga daemons, uncomment the next line ## CLI(net) +def route_get_nhg_id(route_str): + output = net["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str) + match = re.search(r"Nexthop Group ID: (\d+)", output) + assert match is not None, "Nexthop Group ID not found for sharpd route %s" % route_str + + nhg_id = int(match.group(1)) + return nhg_id + +def verify_nexthop_group(nhg_id, recursive=False): + # Verify NHG is valid/installed + output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + + match = re.search(r"Valid", output) + assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id + + # If recursive, we need to look at its resolved group + if recursive: + match = re.search(r"Depends: \((\d+)\)", output) + resolved_id = int(match.group(1)) + verify_nexthop_group(resolved_id, False) + else: + match = re.search(r"Installed", output) + assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id + +def verify_route_nexthop_group(route_str, recursive=False): + # Verify route and that zebra created NHGs for and they are valid/installed + nhg_id = route_get_nhg_id(route_str) + verify_nexthop_group(nhg_id, recursive) + def test_nexthop_groups(): global fatal_error global net @@ -358,25 +387,77 @@ def test_nexthop_groups(): print("\n\n** Verifying Nexthop Groups") print("******************************************\n") + ### Nexthop Group Tests + + ## Basic test + # Create a lib nexthop-group - net["r1"].cmd('vtysh -c "c t" -c "nexthop-group red" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') # Create with sharpd using nexthop-group - net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group red 1"') + net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"') - # Verify route and that zebra created NHGs for and they are valid/installed - output = net["r1"].cmd('vtysh -c "show ip route 2.2.2.1/32 nexthop-group"') - match = re.search(r"Nexthop Group ID: (\d+)", output); - assert match is not None, "Nexthop Group ID not found for sharpd route 2.2.2.1/32" + verify_route_nexthop_group("2.2.2.1/32") - nhe_id = int(match.group(1)) + ## Connected - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhe_id) - match = re.search(r"Valid", output) - assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhe_id + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"') - match = re.search(r"Installed", output) - assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhe_id + net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"') + + verify_route_nexthop_group("2.2.2.2/32") + + ## Recursive + + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"') + + net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"') + + verify_route_nexthop_group("3.3.3.1/32", True) + + ## Duplicate + + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"') + + net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"') + + verify_route_nexthop_group("3.3.3.2/32") + + ## Two 4-Way ECMP + + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \ + -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"') + + net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"') + + verify_route_nexthop_group("4.4.4.1/32") + + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \ + -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"') + + net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"') + + verify_route_nexthop_group("4.4.4.2/32") + + ## Recursive to 8-Way ECMP + + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"') + + net["r1"].cmd('vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"') + + verify_route_nexthop_group("5.5.5.1/32") + + ##CLI(net) + + ## Remove all NHG routes + + net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"') + net["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"') def test_rip_status(): global fatal_error @@ -924,6 +1005,82 @@ def test_route_map(): assert failures == 0, "Show route-map command failed for router r%s:\n%s" % (i, diff) +def test_nexthop_groups_with_route_maps(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Verifying Nexthop Groups With Route-Maps") + print("******************************************\n") + + ### Nexthop Group With Route-Map Tests + + # Create a lib nexthop-group + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') + + ## Route-Map Proto Source + + route_str = "2.2.2.1" + src_str = "192.168.0.1" + + net["r1"].cmd('vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str) + net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"') + + net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str) + + verify_route_nexthop_group("%s/32" % route_str) + + # Only a valid test on linux using nexthop objects + if sys.platform.startswith("linux"): + output = net["r1"].cmd('ip route show %s/32' % route_str) + match = re.search(r"src %s" % src_str, output) + assert match is not None, "Route %s/32 not installed with src %s" % (route_str, src_str) + + # Remove NHG routes and route-map + net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str) + net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"') + net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC permit 111" -c "set src %s"' % src_str) + net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"') + + ## Route-Map Deny/Permit with same nexthop group + + permit_route_str = "3.3.3.1" + deny_route_str = "3.3.3.2" + + net["r1"].cmd('vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str) + net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"') + net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"') + net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"') + + # This route should be permitted + net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str) + + verify_route_nexthop_group("%s/32" % permit_route_str) + + # This route should be denied + net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str) + + nhg_id = route_get_nhg_id(deny_route_str) + output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + + match = re.search(r"Valid", output) + assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id + + match = re.search(r"Installed", output) + assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id + + # Remove NHG routes and route-map + net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str) + net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str) + net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"') + net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"') + net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"') + net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"') + net["r1"].cmd('vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str) + def test_mpls_interfaces(): global fatal_error global net