]> git.puffer.fish Git - matthieu/frr.git/commitdiff
tests: Modify inter-area ECMP topotest to also test redundant ABRs
authorMartin Buck <mb-tmp-tvguho.pbz@gromit.dyndns.org>
Mon, 22 Apr 2024 11:01:22 +0000 (13:01 +0200)
committerMartin Buck <mb-tmp-tvguho.pbz@gromit.dyndns.org>
Fri, 3 May 2024 07:49:24 +0000 (09:49 +0200)
So far, this test only convered redundant paths to one ABR, now it checks
redundant paths to redundant ABRs, covering both cases. Useful as a
regression test for #15777.

Signed-off-by: Martin Buck <mb-tmp-tvguho.pbz@gromit.dyndns.org>
tests/topotests/ospf6_ecmp_inter_area/r5/ospf6d.conf
tests/topotests/ospf6_ecmp_inter_area/r6/ospf6d.conf
tests/topotests/ospf6_ecmp_inter_area/r7/ospf6d.conf
tests/topotests/ospf6_ecmp_inter_area/r7/zebra.conf
tests/topotests/ospf6_ecmp_inter_area/r8/ospf6d.conf
tests/topotests/ospf6_ecmp_inter_area/r8/zebra.conf
tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf [deleted file]
tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf [deleted file]
tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py

index 2a6c9abd2e111a88a2a3ca7ad2af73ab6ae3781d..24cd3541184c8c1171efd4212023d1b0826061e9 100644 (file)
@@ -4,31 +4,11 @@ interface r5-eth0
  ipv6 ospf6 dead-interval 10
 !
 interface r5-eth1
- ipv6 ospf6 area 0
- ipv6 ospf6 hello-interval 2
- ipv6 ospf6 dead-interval 10
-!
-interface r5-eth2
- ipv6 ospf6 area 0
- ipv6 ospf6 hello-interval 2
- ipv6 ospf6 dead-interval 10
-!
-interface r5-eth3
  ipv6 ospf6 area 1
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
-interface r5-eth4
- ipv6 ospf6 area 1
- ipv6 ospf6 hello-interval 2
- ipv6 ospf6 dead-interval 10
-!
-interface r5-eth5
- ipv6 ospf6 area 0
- ipv6 ospf6 hello-interval 2
- ipv6 ospf6 dead-interval 10
-!
-interface r5-eth6
+interface r5-eth2
  ipv6 ospf6 area 0
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
index a1f48b51a5d95f218a7caeca357b07d09566a5f6..4efaa318a914a036023e5ad4cf079978511d7b2e 100644 (file)
@@ -1,8 +1,23 @@
 interface r6-eth0
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r6-eth1
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r6-eth2
  ipv6 ospf6 area 1
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
+interface r6-eth3
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
 router ospf6
  ospf6 router-id 10.254.254.6
  redistribute connected
index 0e49b0df6c72bdf838fcc83d5d356f300e806fd2..9b7756e838c1300e0fb43b35f2b074b2f025d219 100644 (file)
@@ -1,11 +1,22 @@
-interface lo
+interface r7-eth0
  ipv6 ospf6 area 1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
 !
-interface r7-eth0
+interface r7-eth1
  ipv6 ospf6 area 1
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
+interface r7-eth2
+ ipv6 ospf6 area 1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r7-eth3
+ shutdown
+!
 router ospf6
  ospf6 router-id 10.254.254.7
+ redistribute connected
 !
index a410be8f7330a20ae54544908071cba321e9659f..1608cad0b07493fc98b50e3b0d0d8ec79bc909af 100644 (file)
@@ -3,3 +3,6 @@ ipv6 forwarding
 interface lo
  ipv6 address 2001:db8:7::1/64
 !
+interface r7-eth2
+ ipv6 address 2001:db8:8007::1/64
+!
index fb5483ce9968ed93b8e688c2edc2f8a5a9f460db..33c64979ca6f463898e9dc99ac896b04f43a8f79 100644 (file)
@@ -3,6 +3,19 @@ interface r8-eth0
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
+interface r8-eth1
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r8-eth2
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r8-eth3
+ shutdown
+!
 router ospf6
  ospf6 router-id 10.254.254.8
  redistribute connected
index 8e343d8f452f47a9a7469dc3475f09517c5b733d..e756cd4b95452fa55a661b4a9bd24cab99e3900c 100644 (file)
@@ -3,3 +3,6 @@ ipv6 forwarding
 interface lo
  ipv6 address 2001:db8:8::1/64
 !
+interface r8-eth2
+ ipv6 address 2001:db8:8008::1/64
+!
diff --git a/tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf
deleted file mode 100644 (file)
index 57fa8e3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-interface lo
- ipv6 ospf6 area 0
-!
-interface r9-eth0
- ipv6 ospf6 area 0
- ipv6 ospf6 hello-interval 2
- ipv6 ospf6 dead-interval 10
-!
-router ospf6
- ospf6 router-id 10.254.254.9
-!
diff --git a/tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf b/tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf
deleted file mode 100644 (file)
index e267496..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-ipv6 forwarding
-!
-interface lo
- ipv6 address 2001:db8:9::1/64
-!
index 2eaccb8348d0f380ce489bf6f74f750e8b1e3f08..adf289e2de20565488a5e3e6a30729ef8f0a7bb1 100644 (file)
@@ -3,7 +3,7 @@
 
 # test_ospf6_ecmp_inter_area.py
 #
-# Copyright (c) 2021, 2022 by Martin Buck
+# Copyright (c) 2021, 2022, 2024 by Martin Buck
 # Copyright (c) 2016 by
 # Network Device Education Foundation, Inc. ("NetDEF")
 #
 r"""
 test_ospf6_ecmp_inter_area.py: Test OSPFv3 ECMP inter-area nexthop update
 
-Check proper removal of ECMP nexthops after a path used by one nexthop
-disappears. We remove a path by bringing down a link required by that
-path which is not adjacent to the router being checked. This is important
-because when bringing down adjacent links, the kernel might remove the
-nexthops itself without ospf6d having to do anything.
+Check proper addition and removal of ECMP nexthops in 2 cases: Parallel
+paths to one ABR and parallel ABRs. We test nexthop removal triggered by
+path removal by bringing down a link required by that path which is not
+adjacent to the router being checked. This is important because when
+bringing down adjacent links, the kernel might remove the nexthops itself
+without ospf6d having to do anything.
 
-Useful as a regression test for #9720.
+Useful as a regression test for #9720 and #15777.
 
 Topology:
-             .
-      Area 0 . Area 1
-             .
-   -- R2 --  . ---- R6
-  /        \ ./
-R1 -- R3 -- R5 ---- R7  Area 1
-  \        /  \\ ..............
-   -- R4 --    \--- R8  Area 0
-                \
-                 -- R9
-
-We check routes on R1, primarily those towards R6/7/8/9. Those to R6/7 are
-inter-area routes with R5 being ABR, those to R8/9 are intra-area routes
-and are used for reference. R6/R8 announce external routes, R7/R9 announce
-internal routes.
+                  .
+           Area 0 . Area 1
+                  .
+    -- R2 ------ R5 -----
+   /              .\     \
+  /               . |     \
+R1 --- R3 ------ R6 ------ R7
+  \            / |. |
+   \          /  |. |
+    -- R4 ----   |. |
+                / ./
+              R8 --
+                  .
+
+We check routes on R1, primarily those towards R7/8. Those to R7 are
+inter-area routes with R5/6 being ABRs, those to R8 are intra-area routes
+and are used for reference. R7/R8 announce one internal and one external
+route each.
 
 With all links up, we expect 3 ECMP paths and 3 nexthops on R1 towards each
-of R6/7/8/9. Then we bring down the R2-R5 link, causing only 2 remaining
-paths and 2 nexthops on R1. The test is successful if the number of nexthops
-for the routes on R1 is as expected.
+of R7/8. Then we bring down the R3-R6 link, causing only 2 remaining
+paths and 2 nexthops on R1. Then we bring down the R2-R5 link, causing only
+1 remaining path and 1 nexthop on R1. 
+
+The test is successful if the number of nexthops for the routes on R1 is as
+expected.
 """
 
 import os
@@ -65,20 +72,24 @@ pytestmark = [pytest.mark.ospf6d]
 def build_topo(tgen):
     "Build function"
 
-    # Create 9 routers
-    for routern in range(1, 10):
+    # Create 8 routers
+    for routern in range(1, 9):
         tgen.add_router("r{}".format(routern))
-
     tgen.gears["r1"].add_link(tgen.gears["r2"])
     tgen.gears["r1"].add_link(tgen.gears["r3"])
     tgen.gears["r1"].add_link(tgen.gears["r4"])
     tgen.gears["r2"].add_link(tgen.gears["r5"])
-    tgen.gears["r3"].add_link(tgen.gears["r5"])
-    tgen.gears["r4"].add_link(tgen.gears["r5"])
-    tgen.gears["r5"].add_link(tgen.gears["r6"])
+    tgen.gears["r3"].add_link(tgen.gears["r6"])
+    tgen.gears["r4"].add_link(tgen.gears["r6"])
     tgen.gears["r5"].add_link(tgen.gears["r7"])
     tgen.gears["r5"].add_link(tgen.gears["r8"])
-    tgen.gears["r5"].add_link(tgen.gears["r9"])
+    tgen.gears["r6"].add_link(tgen.gears["r7"])
+    tgen.gears["r6"].add_link(tgen.gears["r8"])
+    # Additional "loopback" interfaces. Not used for communication, just to
+    # hold an address we use to inject intra-/inter-area routes (the one on
+    # the real "lo" loopback is used for external routes).
+    tgen.gears["r7"].add_link(tgen.gears["r7"])
+    tgen.gears["r8"].add_link(tgen.gears["r8"])
 
 
 def setup_module(mod):
@@ -131,20 +142,19 @@ def test_wait_protocol_convergence():
     expect_neighbor_full("r2", "10.254.254.1")
     expect_neighbor_full("r2", "10.254.254.5")
     expect_neighbor_full("r3", "10.254.254.1")
-    expect_neighbor_full("r3", "10.254.254.5")
+    expect_neighbor_full("r3", "10.254.254.6")
     expect_neighbor_full("r4", "10.254.254.1")
-    expect_neighbor_full("r4", "10.254.254.5")
+    expect_neighbor_full("r4", "10.254.254.6")
     expect_neighbor_full("r5", "10.254.254.2")
-    expect_neighbor_full("r5", "10.254.254.3")
-    expect_neighbor_full("r5", "10.254.254.4")
-    expect_neighbor_full("r5", "10.254.254.6")
     expect_neighbor_full("r5", "10.254.254.7")
     expect_neighbor_full("r5", "10.254.254.8")
-    expect_neighbor_full("r5", "10.254.254.9")
-    expect_neighbor_full("r6", "10.254.254.5")
+    expect_neighbor_full("r6", "10.254.254.3")
+    expect_neighbor_full("r6", "10.254.254.7")
+    expect_neighbor_full("r6", "10.254.254.8")
     expect_neighbor_full("r7", "10.254.254.5")
+    expect_neighbor_full("r7", "10.254.254.6")
     expect_neighbor_full("r8", "10.254.254.5")
-    expect_neighbor_full("r9", "10.254.254.5")
+    expect_neighbor_full("r8", "10.254.254.6")
 
 
 def test_ecmp_inter_area():
@@ -154,9 +164,16 @@ def test_ecmp_inter_area():
         pytest.skip(tgen.errors)
 
     def num_nexthops(router):
-        routes = tgen.gears[router].vtysh_cmd("show ipv6 ospf6 route json", isjson=True)
-        route_prefixes_infos = sorted(routes.get("routes", {}).items())
-        return [len(ri.get("nextHops", [])) for rp, ri in route_prefixes_infos]
+        # Careful: "show ipv6 ospf6 route json" doesn't work here. It will
+        # only list one route type per prefix and that might not necessarily
+        # be the best/selected route. "show ipv6 route ospf6 json" only
+        # lists selected routes, so that's more useful in this case.
+        routes = tgen.gears[router].vtysh_cmd("show ipv6 route ospf6 json", isjson=True)
+        route_prefixes_infos = sorted(routes.items())
+        # Note: ri may contain one entry per routing protocol, but since
+        # we've explicitly requested only ospf6 above, we can count on ri[0]
+        # being the entry we're looking for.
+        return [ri[0]["internalNextHopActiveNum"] for rp, ri in route_prefixes_infos]
 
     def expect_num_nexthops(router, expected_num_nexthops, count):
         "Wait until number of nexthops for routes matches expectation"
@@ -174,14 +191,22 @@ def test_ecmp_inter_area():
         ), "'{}' wrong number of route nexthops".format(router)
 
     # Check nexthops pre link-down
-    expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3, 3, 3], 4)
+    # tgen.mininet_cli()
+    expect_num_nexthops("r1", [1, 1, 1, 1, 2, 3, 3, 3, 3], 4)
+
+    logger.info("triggering R3-R6 link down")
+    tgen.gears["r3"].run("ip link set r3-eth1 down")
+
+    # tgen.mininet_cli()
+    # Check nexthops post link-down
+    expect_num_nexthops("r1", [1, 1, 1, 1, 1, 2, 2, 2, 2], 8)
 
-    logger.info("triggering R2-R4 link down")
+    logger.info("triggering R2-R5 link down")
     tgen.gears["r2"].run("ip link set r2-eth1 down")
 
     # tgen.mininet_cli()
     # Check nexthops post link-down
-    expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2, 2, 2], 8)
+    expect_num_nexthops("r1", [1, 1, 1, 1, 1, 1, 1, 1, 1], 8)
 
 
 def teardown_module(_mod):