]>
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():
133 daemon_file
= "{}/{}/zebra.conf".format(CWD
, rname
)
134 if os
.path
.isfile(daemon_file
):
135 router
.load_config(TopoRouter
.RD_ZEBRA
, daemon_file
)
137 daemon_file
= "{}/{}/ospf6d.conf".format(CWD
, rname
)
138 if os
.path
.isfile(daemon_file
):
139 router
.load_config(TopoRouter
.RD_OSPF6
, daemon_file
)
141 # Initialize all routers.
145 def test_wait_protocol_convergence():
146 "Wait for OSPFv3 to converge"
148 if tgen
.routers_have_failure():
149 pytest
.skip(tgen
.errors
)
151 logger
.info("waiting for protocols to converge")
153 def expect_neighbor_full(router
, neighbor
):
154 "Wait until OSPFv3 convergence."
155 logger
.info("waiting OSPFv3 router '{}'".format(router
))
157 topotest
.router_json_cmp
,
159 "show ipv6 ospf6 neighbor json",
160 {"neighbors": [{"neighborId": neighbor
, "state": "Full"}]},
162 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
163 assertmsg
= '"{}" convergence failure'.format(router
)
164 assert result
is None, assertmsg
166 expect_neighbor_full("r1", "10.254.254.2")
167 expect_neighbor_full("r2", "10.254.254.1")
168 expect_neighbor_full("r2", "10.254.254.3")
169 expect_neighbor_full("r2", "10.254.254.4")
170 expect_neighbor_full("r3", "10.254.254.2")
171 expect_neighbor_full("r4", "10.254.254.2")
174 def test_ospfv3_expected_route_types():
175 "Test routers route type to determine if NSSA/Stub is working as expected."
177 if tgen
.routers_have_failure():
178 pytest
.skip(tgen
.errors
)
180 logger
.info("waiting for protocols to converge")
182 def expect_ospf6_route_types(router
, expected_summary
):
183 "Expect the correct route types."
184 logger
.info("waiting OSPFv3 router '{}'".format(router
))
186 topotest
.router_json_cmp
,
188 "show ipv6 ospf6 route summary json",
191 _
, result
= topotest
.run_and_expect(test_func
, None, count
=10, wait
=1)
192 assertmsg
= '"{}" convergence failure'.format(router
)
193 assert result
is None, assertmsg
195 # Stub router: no external routes.
196 expect_ospf6_route_types(
199 "numberOfIntraAreaRoutes": 1,
200 "numberOfInterAreaRoutes": 3,
201 "numberOfExternal1Routes": 0,
202 "numberOfExternal2Routes": 0,
205 # NSSA router: no external routes.
206 expect_ospf6_route_types(
209 "numberOfIntraAreaRoutes": 1,
210 "numberOfInterAreaRoutes": 2,
211 "numberOfExternal1Routes": 0,
212 "numberOfExternal2Routes": 3,
217 def test_ospf6_default_route():
218 "Wait for OSPFv3 default route in stub area."
220 if tgen
.routers_have_failure():
221 pytest
.skip(tgen
.errors
)
223 logger
.info("waiting for default route")
225 def expect_route(router
, route
, metric
):
226 "Test OSPF6 route existence."
227 logger
.info("waiting OSPFv3 router '{}' routes".format(router
))
229 topotest
.router_json_cmp
,
231 "show ipv6 route json",
232 {route
: [{"metric": metric
}]},
234 _
, result
= topotest
.run_and_expect(test_func
, None, count
=5, wait
=1)
235 assertmsg
= '"{}" convergence failure'.format(router
)
236 assert result
is None, assertmsg
242 [{"prefix": "::/0", "metric": metric
}],
243 extra_params
="inter-prefix detail",
245 expect_route("r1", "::/0", metric
+ 10)
248 def test_redistribute_metrics():
250 Test that the configured metrics are honored when a static route is
254 if tgen
.routers_have_failure():
255 pytest
.skip(tgen
.errors
)
257 # Add new static route on r3.
260 ipv6 route 2001:db8:500::/64 Null0
262 tgen
.gears
["r3"].vtysh_cmd(config
)
265 "2001:db8:500::/64": {
271 "Expecting AS-external route 2001:db8:500::/64 to show up with default metrics"
273 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
275 # Change the metric of redistributed routes of the static type on r3.
279 redistribute static metric 50 metric-type 1
281 tgen
.gears
["r3"].vtysh_cmd(config
)
283 # Check if r3 reinstalled 2001:db8:500::/64 using the new metric type and value.
285 "2001:db8:500::/64": {
291 "Expecting AS-external route 2001:db8:500::/64 to show up with updated metric type and value"
293 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
296 def test_nssa_lsa_type7():
298 Test that static route gets announced as external route when redistributed
299 and gets removed when redistribution stops.
302 if tgen
.routers_have_failure():
303 pytest
.skip(tgen
.errors
)
306 # Add new static route and check if it gets announced as LSA Type-7.
310 ipv6 route 2001:db8:100::/64 Null0
312 tgen
.gears
["r2"].vtysh_cmd(config
)
317 "advertisingRouter": "10.254.254.2",
318 "prefix": "2001:db8:100::/64",
319 "forwardingAddress": "2001:db8:3::1",
323 "2001:db8:100::/64": {
325 "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}],
329 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to show up")
330 expect_lsas("r4", "0.0.0.2", lsas
, wait
=30, extra_params
="type-7 detail")
331 expect_ospfv3_routes("r4", route
, wait
=30)
334 # Remove static route and check for LSA Type-7 removal.
338 no ipv6 route 2001:db8:100::/64 Null0
340 tgen
.gears
["r2"].vtysh_cmd(config
)
342 def dont_expect_lsa(unexpected_lsa
):
343 "Specialized test function to expect LSA go missing"
344 output
= tgen
.gears
["r4"].vtysh_cmd(
345 "show ipv6 ospf6 database type-7 detail json", isjson
=True
347 for lsa
in output
["areaScopedLinkStateDb"][0]["lsa"]:
348 if lsa
["prefix"] == unexpected_lsa
["prefix"]:
349 if lsa
["forwardingAddress"] == unexpected_lsa
["forwardingAddress"]:
353 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away")
355 # Test that LSA doesn't exist.
356 test_func
= partial(dont_expect_lsa
, lsas
[0])
357 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
358 assertmsg
= '"{}" LSA still exists'.format("r4")
359 assert result
is None, assertmsg
361 # Test that route doesn't exist.
362 test_func
= partial(dont_expect_route
, "r4", "2001:db8:100::/64")
363 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
364 assertmsg
= '"{}" route still exists'.format("r4")
365 assert result
is None, assertmsg
368 def test_nssa_no_summary():
371 * Type-3 inter-area routes should be removed when the NSSA no-summary option
373 * A type-3 inter-area default route should be originated into the NSSA area
374 when the no-summary option is configured;
375 * Once the no-summary option is unconfigured, all previously existing
376 Type-3 inter-area routes should be re-added, and the inter-area default
380 if tgen
.routers_have_failure():
381 pytest
.skip(tgen
.errors
)
384 # Configure area 1 as a NSSA totally stub area.
389 area 2 nssa no-summary
391 tgen
.gears
["r2"].vtysh_cmd(config
)
393 logger
.info("Expecting inter-area routes to be removed")
394 for route
in ["2001:db8:1::/64", "2001:db8:2::/64"]:
395 test_func
= partial(dont_expect_route
, "r4", route
, type="inter-area")
396 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
397 assertmsg
= "{}'s {} inter-area route still exists".format("r4", route
)
398 assert result
is None, assertmsg
400 logger
.info("Expecting inter-area default-route to be added")
401 routes
= {"::/0": {}}
402 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
405 # Configure area 1 as a regular NSSA area.
412 tgen
.gears
["r2"].vtysh_cmd(config
)
414 logger
.info("Expecting inter-area routes to be re-added")
415 routes
= {"2001:db8:1::/64": {}, "2001:db8:2::/64": {}}
416 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
418 logger
.info("Expecting inter-area default route to be removed")
419 test_func
= partial(dont_expect_route
, "r4", "::/0", type="inter-area")
420 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
421 assertmsg
= "{}'s inter-area default route still exists".format("r4")
422 assert result
is None, assertmsg
425 def test_nssa_default_originate():
428 * A type-7 default route should be originated into the NSSA area
429 when the default-information-originate option is configured;
430 * Once the default-information-originate option is unconfigured, the
431 previously originated Type-7 default route should be removed.
434 if tgen
.routers_have_failure():
435 pytest
.skip(tgen
.errors
)
438 # Configure r2 to announce a Type-7 default route.
443 no default-information originate
444 area 2 nssa default-information-originate
446 tgen
.gears
["r2"].vtysh_cmd(config
)
448 logger
.info("Expecting Type-7 default-route to be added")
449 routes
= {"::/0": {}}
450 expect_ospfv3_routes("r4", routes
, wait
=30, type="external-2")
453 # Configure r2 to stop announcing a Type-7 default route.
460 tgen
.gears
["r2"].vtysh_cmd(config
)
462 logger
.info("Expecting Type-7 default route to be removed")
463 test_func
= partial(dont_expect_route
, "r4", "::/0", type="external-2")
464 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
465 assertmsg
= "r4's Type-7 default route still exists"
466 assert result
is None, assertmsg
469 def test_area_filters():
471 Test ABR import/export filters.
474 if tgen
.routers_have_failure():
475 pytest
.skip(tgen
.errors
)
478 # Configure import/export filters on r2 (ABR for area 2).
482 ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
483 ipv6 access-list ACL_IMPORT seq 10 deny any
484 ipv6 access-list ACL_EXPORT seq 10 deny any
486 area 1 import-list ACL_IMPORT
487 area 1 export-list ACL_EXPORT
489 tgen
.gears
["r2"].vtysh_cmd(config
)
491 logger
.info("Expecting inter-area routes to be removed on r1")
492 for route
in ["::/0", "2001:db8:3::/64"]:
493 test_func
= partial(dont_expect_route
, "r1", route
, type="inter-area")
494 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
495 assertmsg
= "{}'s {} inter-area route still exists".format("r1", route
)
496 assert result
is None, assertmsg
498 logger
.info("Expecting inter-area routes to be removed on r3")
499 for route
in ["2001:db8:1::/64"]:
500 test_func
= partial(dont_expect_route
, "r3", route
, type="inter-area")
501 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
502 assertmsg
= "{}'s {} inter-area route still exists".format("r3", route
)
503 assert result
is None, assertmsg
506 # Update the ACLs used by the import/export filters.
510 ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
511 ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
513 tgen
.gears
["r2"].vtysh_cmd(config
)
515 logger
.info("Expecting 2001:db8:3::/64 to be re-added on r1")
516 routes
= {"2001:db8:3::/64": {}}
517 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
518 logger
.info("Expecting 2001:db8:1::/64 to be re-added on r3")
519 routes
= {"2001:db8:1::/64": {}}
520 expect_ospfv3_routes("r3", routes
, wait
=30, type="inter-area")
523 # Unconfigure r2's ABR import/export filters.
528 no area 1 import-list ACL_IMPORT
529 no area 1 export-list ACL_EXPORT
531 tgen
.gears
["r2"].vtysh_cmd(config
)
533 logger
.info("Expecting ::/0 to be re-added on r1")
534 routes
= {"::/0": {}}
535 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
538 def test_nssa_range():
540 Test NSSA ABR ranges.
543 if tgen
.routers_have_failure():
544 pytest
.skip(tgen
.errors
)
546 # Configure new addresses on r4 and enable redistribution of connected
551 ipv6 address 2001:db8:1000::1/128
552 ipv6 address 2001:db8:1000::2/128
554 redistribute connected
556 tgen
.gears
["r4"].vtysh_cmd(config
)
557 logger
.info("Expecting NSSA-translated external routes to be added on r3")
558 routes
= {"2001:db8:1000::1/128": {}, "2001:db8:1000::2/128": {}}
559 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2")
561 # Configure an NSSA range on r2 (ABR for area 2).
565 area 2 nssa range 2001:db8:1000::/64
567 tgen
.gears
["r2"].vtysh_cmd(config
)
568 logger
.info("Expecting summarized routes to be removed from r3")
569 for route
in ["2001:db8:1000::1/128", "2001:db8:1000::2/128"]:
570 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
571 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
572 assertmsg
= "{}'s {} summarized route still exists".format("r3", route
)
573 assert result
is None, assertmsg
574 logger
.info("Expecting NSSA range to be added on r3")
576 "2001:db8:1000::/64": {
582 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
584 # Change the NSSA range cost.
588 area 2 nssa range 2001:db8:1000::/64 cost 1000
590 tgen
.gears
["r2"].vtysh_cmd(config
)
591 logger
.info("Expecting NSSA range to be updated with new cost")
593 "2001:db8:1000::/64": {
596 "metricCostE2": 1000,
599 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
601 # Configure the NSSA range to not be advertised.
605 area 2 nssa range 2001:db8:1000::/64 not-advertise
607 tgen
.gears
["r2"].vtysh_cmd(config
)
608 logger
.info("Expecting NSSA summary route to be removed")
609 route
= "2001:db8:1000::/64"
610 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
611 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
612 assertmsg
= "{}'s {} NSSA summary route still exists".format("r3", route
)
613 assert result
is None, assertmsg
615 # Remove the NSSA range.
619 no area 2 nssa range 2001:db8:1000::/64
621 tgen
.gears
["r2"].vtysh_cmd(config
)
622 logger
.info("Expecting previously summarized routes to be re-added")
624 "2001:db8:1000::1/128": {
628 "2001:db8:1000::2/128": {
633 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
636 def teardown_module(_mod
):
637 "Teardown the pytest environment"
642 def test_memory_leak():
643 "Run the memory leak test and report results."
645 if not tgen
.is_memleak_enabled():
646 pytest
.skip("Memory leak test/report is disabled")
648 tgen
.report_memory_leaks()
651 if __name__
== "__main__":
652 args
= ["-s"] + sys
.argv
[1:]
653 sys
.exit(pytest
.main(args
))