]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf6_topo2/test_ospf6_topo2.py
2 # SPDX-License-Identifier: ISC
6 # Part of NetDEF Topology Tests
8 # Copyright (c) 2021 by
9 # Network Device Education Foundation, Inc. ("NetDEF")
13 test_ospf6_topo2.py: Test the FRR OSPFv3 daemon.
18 from functools
import partial
21 # Save the Current Working Directory to find configuration files.
22 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
23 sys
.path
.append(os
.path
.join(CWD
, "../"))
25 # pylint: disable=C0413
26 # Import topogen and topotest helpers
27 from lib
import topotest
28 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
29 from lib
.topolog
import logger
31 # Required to instantiate the topology builder class.
33 pytestmark
= [pytest
.mark
.ospf6d
]
36 def expect_lsas(router
, area
, lsas
, wait
=5, extra_params
=""):
38 Run the OSPFv3 show LSA database command and expect the supplied LSAs.
41 * `wait`: amount of seconds to wait.
42 * `extra_params`: extra LSA database parameters.
43 * `inverse`: assert the inverse of the expected.
47 command
= "show ipv6 ospf6 database {} json".format(extra_params
)
49 logger
.info("waiting OSPFv3 router '{}' LSA".format(router
))
51 topotest
.router_json_cmp
,
54 {"areaScopedLinkStateDb": [{"areaId": area
, "lsa": lsas
}]},
56 _
, result
= topotest
.run_and_expect(test_func
, None, count
=wait
, wait
=1)
57 assertmsg
= '"{}" convergence failure'.format(router
)
59 assert result
is None, assertmsg
62 def expect_ospfv3_routes(router
, routes
, wait
=5, type=None, detail
=False):
63 "Run command `ipv6 ospf6 route` and expect route with type."
68 cmd
= "show ipv6 ospf6 route json"
70 cmd
= "show ipv6 ospf6 route {} json".format(type)
73 cmd
= "show ipv6 ospf6 route detail json"
75 cmd
= "show ipv6 ospf6 route {} detail json".format(type)
77 logger
.info("waiting OSPFv3 router '{}' route".format(router
))
79 topotest
.router_json_cmp
, tgen
.gears
[router
], cmd
, {"routes": routes
}
81 _
, result
= topotest
.run_and_expect(test_func
, None, count
=wait
, wait
=1)
82 assertmsg
= '"{}" convergence failure'.format(router
)
84 assert result
is None, assertmsg
87 def dont_expect_route(router
, unexpected_route
, type=None):
88 "Specialized test function to expect route go missing"
92 cmd
= "show ipv6 ospf6 route json"
94 cmd
= "show ipv6 ospf6 route {} json".format(type)
96 output
= tgen
.gears
[router
].vtysh_cmd(cmd
, isjson
=True)
97 if unexpected_route
in output
["routes"]:
98 return output
["routes"][unexpected_route
]
102 def build_topo(tgen
):
106 for routern
in range(1, 5):
107 tgen
.add_router("r{}".format(routern
))
109 switch
= tgen
.add_switch("s1")
110 switch
.add_link(tgen
.gears
["r1"])
111 switch
.add_link(tgen
.gears
["r2"])
113 switch
= tgen
.add_switch("s2")
114 switch
.add_link(tgen
.gears
["r2"])
115 switch
.add_link(tgen
.gears
["r3"])
117 switch
= tgen
.add_switch("s3")
118 switch
.add_link(tgen
.gears
["r2"])
119 switch
.add_link(tgen
.gears
["r4"])
121 switch
= tgen
.add_switch("s4")
122 switch
.add_link(tgen
.gears
["r4"], nodeif
="r4-stubnet")
125 def setup_module(mod
):
126 "Sets up the pytest environment"
127 tgen
= Topogen(build_topo
, mod
.__name
__)
128 tgen
.start_topology()
130 router_list
= tgen
.routers()
131 for rname
, router
in router_list
.items():
132 daemon_file
= "{}/{}/zebra.conf".format(CWD
, rname
)
133 if os
.path
.isfile(daemon_file
):
134 router
.load_config(TopoRouter
.RD_ZEBRA
, daemon_file
)
136 daemon_file
= "{}/{}/ospf6d.conf".format(CWD
, rname
)
137 if os
.path
.isfile(daemon_file
):
138 router
.load_config(TopoRouter
.RD_OSPF6
, daemon_file
)
140 # Initialize all routers.
144 def test_wait_protocol_convergence():
145 "Wait for OSPFv3 to converge"
147 if tgen
.routers_have_failure():
148 pytest
.skip(tgen
.errors
)
150 logger
.info("waiting for protocols to converge")
152 def expect_neighbor_full(router
, neighbor
):
153 "Wait until OSPFv3 convergence."
154 logger
.info("waiting OSPFv3 router '{}'".format(router
))
156 topotest
.router_json_cmp
,
158 "show ipv6 ospf6 neighbor json",
159 {"neighbors": [{"neighborId": neighbor
, "state": "Full"}]},
161 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
162 assertmsg
= '"{}" convergence failure'.format(router
)
163 assert result
is None, assertmsg
165 expect_neighbor_full("r1", "10.254.254.2")
166 expect_neighbor_full("r2", "10.254.254.1")
167 expect_neighbor_full("r2", "10.254.254.3")
168 expect_neighbor_full("r2", "10.254.254.4")
169 expect_neighbor_full("r3", "10.254.254.2")
170 expect_neighbor_full("r4", "10.254.254.2")
173 def test_ospfv3_expected_route_types():
174 "Test routers route type to determine if NSSA/Stub is working as expected."
176 if tgen
.routers_have_failure():
177 pytest
.skip(tgen
.errors
)
179 logger
.info("waiting for protocols to converge")
181 def expect_ospf6_route_types(router
, expected_summary
):
182 "Expect the correct route types."
183 logger
.info("waiting OSPFv3 router '{}'".format(router
))
185 topotest
.router_json_cmp
,
187 "show ipv6 ospf6 route summary json",
190 _
, result
= topotest
.run_and_expect(test_func
, None, count
=10, wait
=1)
191 assertmsg
= '"{}" convergence failure'.format(router
)
192 assert result
is None, assertmsg
194 # Stub router: no external routes.
195 expect_ospf6_route_types(
198 "numberOfIntraAreaRoutes": 1,
199 "numberOfInterAreaRoutes": 3,
200 "numberOfExternal1Routes": 0,
201 "numberOfExternal2Routes": 0,
204 # NSSA router: no external routes.
205 expect_ospf6_route_types(
208 "numberOfIntraAreaRoutes": 1,
209 "numberOfInterAreaRoutes": 2,
210 "numberOfExternal1Routes": 0,
211 "numberOfExternal2Routes": 3,
216 def test_ospf6_default_route():
217 "Wait for OSPFv3 default route in stub area."
219 if tgen
.routers_have_failure():
220 pytest
.skip(tgen
.errors
)
222 logger
.info("waiting for default route")
224 def expect_route(router
, route
, metric
):
225 "Test OSPF6 route existence."
226 logger
.info("waiting OSPFv3 router '{}' routes".format(router
))
228 topotest
.router_json_cmp
,
230 "show ipv6 route json",
231 {route
: [{"metric": metric
}]},
233 _
, result
= topotest
.run_and_expect(test_func
, None, count
=5, wait
=1)
234 assertmsg
= '"{}" convergence failure'.format(router
)
235 assert result
is None, assertmsg
241 [{"prefix": "::/0", "metric": metric
}],
242 extra_params
="inter-prefix detail",
244 expect_route("r1", "::/0", metric
+ 10)
247 def test_redistribute_metrics():
249 Test that the configured metrics are honored when a static route is
253 if tgen
.routers_have_failure():
254 pytest
.skip(tgen
.errors
)
256 # Add new static route on r3.
259 ipv6 route 2001:db8:500::/64 Null0
261 tgen
.gears
["r3"].vtysh_cmd(config
)
264 "2001:db8:500::/64": {
270 "Expecting AS-external route 2001:db8:500::/64 to show up with default metrics"
272 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
274 # Change the metric of redistributed routes of the static type on r3.
278 redistribute static metric 50 metric-type 1
280 tgen
.gears
["r3"].vtysh_cmd(config
)
282 # Check if r3 reinstalled 2001:db8:500::/64 using the new metric type and value.
284 "2001:db8:500::/64": {
290 "Expecting AS-external route 2001:db8:500::/64 to show up with updated metric type and value"
292 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
295 def test_nssa_lsa_type7():
297 Test that static route gets announced as external route when redistributed
298 and gets removed when redistribution stops.
301 if tgen
.routers_have_failure():
302 pytest
.skip(tgen
.errors
)
305 # Add new static route and check if it gets announced as LSA Type-7.
309 ipv6 route 2001:db8:100::/64 Null0
311 tgen
.gears
["r2"].vtysh_cmd(config
)
316 "advertisingRouter": "10.254.254.2",
317 "prefix": "2001:db8:100::/64",
318 "forwardingAddress": "2001:db8:3::1",
322 "2001:db8:100::/64": {
324 "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}],
328 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to show up")
329 expect_lsas("r4", "0.0.0.2", lsas
, wait
=30, extra_params
="type-7 detail")
330 expect_ospfv3_routes("r4", route
, wait
=30)
333 # Remove static route and check for LSA Type-7 removal.
337 no ipv6 route 2001:db8:100::/64 Null0
339 tgen
.gears
["r2"].vtysh_cmd(config
)
341 def dont_expect_lsa(unexpected_lsa
):
342 "Specialized test function to expect LSA go missing"
343 output
= tgen
.gears
["r4"].vtysh_cmd(
344 "show ipv6 ospf6 database type-7 detail json", isjson
=True
346 for lsa
in output
["areaScopedLinkStateDb"][0]["lsa"]:
347 if lsa
["prefix"] == unexpected_lsa
["prefix"]:
348 if lsa
["forwardingAddress"] == unexpected_lsa
["forwardingAddress"]:
352 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away")
354 # Test that LSA doesn't exist.
355 test_func
= partial(dont_expect_lsa
, lsas
[0])
356 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
357 assertmsg
= '"{}" LSA still exists'.format("r4")
358 assert result
is None, assertmsg
360 # Test that route doesn't exist.
361 test_func
= partial(dont_expect_route
, "r4", "2001:db8:100::/64")
362 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
363 assertmsg
= '"{}" route still exists'.format("r4")
364 assert result
is None, assertmsg
367 def test_nssa_no_summary():
370 * Type-3 inter-area routes should be removed when the NSSA no-summary option
372 * A type-3 inter-area default route should be originated into the NSSA area
373 when the no-summary option is configured;
374 * Once the no-summary option is unconfigured, all previously existing
375 Type-3 inter-area routes should be re-added, and the inter-area default
379 if tgen
.routers_have_failure():
380 pytest
.skip(tgen
.errors
)
383 # Configure area 1 as a NSSA totally stub area.
388 area 2 nssa no-summary
390 tgen
.gears
["r2"].vtysh_cmd(config
)
392 logger
.info("Expecting inter-area routes to be removed")
393 for route
in ["2001:db8:1::/64", "2001:db8:2::/64"]:
394 test_func
= partial(dont_expect_route
, "r4", route
, type="inter-area")
395 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
396 assertmsg
= "{}'s {} inter-area route still exists".format("r4", route
)
397 assert result
is None, assertmsg
399 logger
.info("Expecting inter-area default-route to be added")
400 routes
= {"::/0": {}}
401 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
404 # Configure area 1 as a regular NSSA area.
411 tgen
.gears
["r2"].vtysh_cmd(config
)
413 logger
.info("Expecting inter-area routes to be re-added")
414 routes
= {"2001:db8:1::/64": {}, "2001:db8:2::/64": {}}
415 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
417 logger
.info("Expecting inter-area default route to be removed")
418 test_func
= partial(dont_expect_route
, "r4", "::/0", type="inter-area")
419 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
420 assertmsg
= "{}'s inter-area default route still exists".format("r4")
421 assert result
is None, assertmsg
424 def test_nssa_default_originate():
427 * A type-7 default route should be originated into the NSSA area
428 when the default-information-originate option is configured;
429 * Once the default-information-originate option is unconfigured, the
430 previously originated Type-7 default route should be removed.
433 if tgen
.routers_have_failure():
434 pytest
.skip(tgen
.errors
)
437 # Configure r2 to announce a Type-7 default route.
442 no default-information originate
443 area 2 nssa default-information-originate
445 tgen
.gears
["r2"].vtysh_cmd(config
)
447 logger
.info("Expecting Type-7 default-route to be added")
448 routes
= {"::/0": {}}
449 expect_ospfv3_routes("r4", routes
, wait
=30, type="external-2")
452 # Configure r2 to stop announcing a Type-7 default route.
459 tgen
.gears
["r2"].vtysh_cmd(config
)
461 logger
.info("Expecting Type-7 default route to be removed")
462 test_func
= partial(dont_expect_route
, "r4", "::/0", type="external-2")
463 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
464 assertmsg
= "r4's Type-7 default route still exists"
465 assert result
is None, assertmsg
468 def test_area_filters():
470 Test ABR import/export filters.
473 if tgen
.routers_have_failure():
474 pytest
.skip(tgen
.errors
)
477 # Configure import/export filters on r2 (ABR for area 2).
481 ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
482 ipv6 access-list ACL_IMPORT seq 10 deny any
483 ipv6 access-list ACL_EXPORT seq 10 deny any
485 area 1 import-list ACL_IMPORT
486 area 1 export-list ACL_EXPORT
488 tgen
.gears
["r2"].vtysh_cmd(config
)
490 logger
.info("Expecting inter-area routes to be removed on r1")
491 for route
in ["::/0", "2001:db8:3::/64"]:
492 test_func
= partial(dont_expect_route
, "r1", route
, type="inter-area")
493 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
494 assertmsg
= "{}'s {} inter-area route still exists".format("r1", route
)
495 assert result
is None, assertmsg
497 logger
.info("Expecting inter-area routes to be removed on r3")
498 for route
in ["2001:db8:1::/64"]:
499 test_func
= partial(dont_expect_route
, "r3", route
, type="inter-area")
500 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
501 assertmsg
= "{}'s {} inter-area route still exists".format("r3", route
)
502 assert result
is None, assertmsg
505 # Update the ACLs used by the import/export filters.
509 ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
510 ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
512 tgen
.gears
["r2"].vtysh_cmd(config
)
514 logger
.info("Expecting 2001:db8:3::/64 to be re-added on r1")
515 routes
= {"2001:db8:3::/64": {}}
516 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
517 logger
.info("Expecting 2001:db8:1::/64 to be re-added on r3")
518 routes
= {"2001:db8:1::/64": {}}
519 expect_ospfv3_routes("r3", routes
, wait
=30, type="inter-area")
522 # Unconfigure r2's ABR import/export filters.
527 no area 1 import-list ACL_IMPORT
528 no area 1 export-list ACL_EXPORT
530 tgen
.gears
["r2"].vtysh_cmd(config
)
532 logger
.info("Expecting ::/0 to be re-added on r1")
533 routes
= {"::/0": {}}
534 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
537 def test_nssa_range():
539 Test NSSA ABR ranges.
542 if tgen
.routers_have_failure():
543 pytest
.skip(tgen
.errors
)
545 # Configure new addresses on r4 and enable redistribution of connected
550 ipv6 address 2001:db8:1000::1/128
551 ipv6 address 2001:db8:1000::2/128
553 redistribute connected
555 tgen
.gears
["r4"].vtysh_cmd(config
)
556 logger
.info("Expecting NSSA-translated external routes to be added on r3")
557 routes
= {"2001:db8:1000::1/128": {}, "2001:db8:1000::2/128": {}}
558 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2")
560 # Configure an NSSA range on r2 (ABR for area 2).
564 area 2 nssa range 2001:db8:1000::/64
566 tgen
.gears
["r2"].vtysh_cmd(config
)
567 logger
.info("Expecting summarized routes to be removed from r3")
568 for route
in ["2001:db8:1000::1/128", "2001:db8:1000::2/128"]:
569 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
570 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
571 assertmsg
= "{}'s {} summarized route still exists".format("r3", route
)
572 assert result
is None, assertmsg
573 logger
.info("Expecting NSSA range to be added on r3")
575 "2001:db8:1000::/64": {
581 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
583 # Change the NSSA range cost.
587 area 2 nssa range 2001:db8:1000::/64 cost 1000
589 tgen
.gears
["r2"].vtysh_cmd(config
)
590 logger
.info("Expecting NSSA range to be updated with new cost")
592 "2001:db8:1000::/64": {
595 "metricCostE2": 1000,
598 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
600 # Configure the NSSA range to not be advertised.
604 area 2 nssa range 2001:db8:1000::/64 not-advertise
606 tgen
.gears
["r2"].vtysh_cmd(config
)
607 logger
.info("Expecting NSSA summary route to be removed")
608 route
= "2001:db8:1000::/64"
609 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
610 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
611 assertmsg
= "{}'s {} NSSA summary route still exists".format("r3", route
)
612 assert result
is None, assertmsg
614 # Remove the NSSA range.
618 no area 2 nssa range 2001:db8:1000::/64
620 tgen
.gears
["r2"].vtysh_cmd(config
)
621 logger
.info("Expecting previously summarized routes to be re-added")
623 "2001:db8:1000::1/128": {
627 "2001:db8:1000::2/128": {
632 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
635 def teardown_module(_mod
):
636 "Teardown the pytest environment"
641 def test_memory_leak():
642 "Run the memory leak test and report results."
644 if not tgen
.is_memleak_enabled():
645 pytest
.skip("Memory leak test/report is disabled")
647 tgen
.report_memory_leaks()
650 if __name__
== "__main__":
651 args
= ["-s"] + sys
.argv
[1:]
652 sys
.exit(pytest
.main(args
))