]>
Commit | Line | Data |
---|---|---|
bcddbefe | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: ISC |
bcddbefe RZ |
3 | |
4 | # | |
5 | # test_ospf6_topo2.py | |
6 | # Part of NetDEF Topology Tests | |
7 | # | |
8 | # Copyright (c) 2021 by | |
9 | # Network Device Education Foundation, Inc. ("NetDEF") | |
10 | # | |
bcddbefe RZ |
11 | |
12 | """ | |
13 | test_ospf6_topo2.py: Test the FRR OSPFv3 daemon. | |
14 | """ | |
15 | ||
16 | import os | |
17 | import sys | |
18 | from functools import partial | |
19 | import pytest | |
20 | ||
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, "../")) | |
24 | ||
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 | |
30 | ||
31 | # Required to instantiate the topology builder class. | |
bcddbefe RZ |
32 | |
33 | pytestmark = [pytest.mark.ospf6d] | |
34 | ||
35 | ||
12a97d46 RZ |
36 | def expect_lsas(router, area, lsas, wait=5, extra_params=""): |
37 | """ | |
38 | Run the OSPFv3 show LSA database command and expect the supplied LSAs. | |
39 | ||
40 | Optional parameters: | |
41 | * `wait`: amount of seconds to wait. | |
42 | * `extra_params`: extra LSA database parameters. | |
43 | * `inverse`: assert the inverse of the expected. | |
44 | """ | |
45 | tgen = get_topogen() | |
46 | ||
47 | command = "show ipv6 ospf6 database {} json".format(extra_params) | |
48 | ||
49 | logger.info("waiting OSPFv3 router '{}' LSA".format(router)) | |
50 | test_func = partial( | |
51 | topotest.router_json_cmp, | |
52 | tgen.gears[router], | |
53 | command, | |
54 | {"areaScopedLinkStateDb": [{"areaId": area, "lsa": lsas}]}, | |
55 | ) | |
56 | _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1) | |
57 | assertmsg = '"{}" convergence failure'.format(router) | |
58 | ||
59 | assert result is None, assertmsg | |
60 | ||
61 | ||
fee16c7e | 62 | def expect_ospfv3_routes(router, routes, wait=5, type=None, detail=False): |
12a97d46 RZ |
63 | "Run command `ipv6 ospf6 route` and expect route with type." |
64 | tgen = get_topogen() | |
65 | ||
476e9575 | 66 | if detail == False: |
fee16c7e RW |
67 | if type == None: |
68 | cmd = "show ipv6 ospf6 route json" | |
69 | else: | |
70 | cmd = "show ipv6 ospf6 route {} json".format(type) | |
476e9575 | 71 | else: |
fee16c7e RW |
72 | if type == None: |
73 | cmd = "show ipv6 ospf6 route detail json" | |
74 | else: | |
75 | cmd = "show ipv6 ospf6 route {} detail json".format(type) | |
476e9575 | 76 | |
12a97d46 RZ |
77 | logger.info("waiting OSPFv3 router '{}' route".format(router)) |
78 | test_func = partial( | |
a53c08bc | 79 | topotest.router_json_cmp, tgen.gears[router], cmd, {"routes": routes} |
12a97d46 RZ |
80 | ) |
81 | _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1) | |
82 | assertmsg = '"{}" convergence failure'.format(router) | |
83 | ||
84 | assert result is None, assertmsg | |
85 | ||
86 | ||
fee16c7e RW |
87 | def dont_expect_route(router, unexpected_route, type=None): |
88 | "Specialized test function to expect route go missing" | |
89 | tgen = get_topogen() | |
90 | ||
91 | if type == None: | |
92 | cmd = "show ipv6 ospf6 route json" | |
93 | else: | |
94 | cmd = "show ipv6 ospf6 route {} json".format(type) | |
95 | ||
96 | output = tgen.gears[router].vtysh_cmd(cmd, isjson=True) | |
97 | if unexpected_route in output["routes"]: | |
98 | return output["routes"][unexpected_route] | |
99 | return None | |
100 | ||
101 | ||
e82b531d CH |
102 | def build_topo(tgen): |
103 | "Build function" | |
bcddbefe | 104 | |
e82b531d CH |
105 | # Create 4 routers |
106 | for routern in range(1, 5): | |
107 | tgen.add_router("r{}".format(routern)) | |
bcddbefe | 108 | |
e82b531d CH |
109 | switch = tgen.add_switch("s1") |
110 | switch.add_link(tgen.gears["r1"]) | |
111 | switch.add_link(tgen.gears["r2"]) | |
bcddbefe | 112 | |
e82b531d CH |
113 | switch = tgen.add_switch("s2") |
114 | switch.add_link(tgen.gears["r2"]) | |
115 | switch.add_link(tgen.gears["r3"]) | |
bcddbefe | 116 | |
e82b531d CH |
117 | switch = tgen.add_switch("s3") |
118 | switch.add_link(tgen.gears["r2"]) | |
119 | switch.add_link(tgen.gears["r4"]) | |
d87586c6 | 120 | |
343e16ce RW |
121 | switch = tgen.add_switch("s4") |
122 | switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet") | |
bcddbefe | 123 | |
9a974f22 | 124 | |
bcddbefe RZ |
125 | def setup_module(mod): |
126 | "Sets up the pytest environment" | |
e82b531d | 127 | tgen = Topogen(build_topo, mod.__name__) |
bcddbefe RZ |
128 | tgen.start_topology() |
129 | ||
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) | |
135 | ||
136 | daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname) | |
137 | if os.path.isfile(daemon_file): | |
138 | router.load_config(TopoRouter.RD_OSPF6, daemon_file) | |
139 | ||
140 | # Initialize all routers. | |
141 | tgen.start_router() | |
142 | ||
143 | ||
144 | def test_wait_protocol_convergence(): | |
145 | "Wait for OSPFv3 to converge" | |
146 | tgen = get_topogen() | |
147 | if tgen.routers_have_failure(): | |
148 | pytest.skip(tgen.errors) | |
149 | ||
150 | logger.info("waiting for protocols to converge") | |
151 | ||
152 | def expect_neighbor_full(router, neighbor): | |
153 | "Wait until OSPFv3 convergence." | |
154 | logger.info("waiting OSPFv3 router '{}'".format(router)) | |
155 | test_func = partial( | |
156 | topotest.router_json_cmp, | |
157 | tgen.gears[router], | |
158 | "show ipv6 ospf6 neighbor json", | |
159 | {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, | |
160 | ) | |
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 | |
164 | ||
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") | |
d87586c6 | 168 | expect_neighbor_full("r2", "10.254.254.4") |
bcddbefe | 169 | expect_neighbor_full("r3", "10.254.254.2") |
d87586c6 K |
170 | expect_neighbor_full("r4", "10.254.254.2") |
171 | ||
172 | ||
173 | def test_ospfv3_expected_route_types(): | |
174 | "Test routers route type to determine if NSSA/Stub is working as expected." | |
175 | tgen = get_topogen() | |
176 | if tgen.routers_have_failure(): | |
177 | pytest.skip(tgen.errors) | |
178 | ||
179 | logger.info("waiting for protocols to converge") | |
180 | ||
181 | def expect_ospf6_route_types(router, expected_summary): | |
182 | "Expect the correct route types." | |
183 | logger.info("waiting OSPFv3 router '{}'".format(router)) | |
184 | test_func = partial( | |
185 | topotest.router_json_cmp, | |
186 | tgen.gears[router], | |
187 | "show ipv6 ospf6 route summary json", | |
188 | expected_summary, | |
189 | ) | |
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 | |
193 | ||
194 | # Stub router: no external routes. | |
195 | expect_ospf6_route_types( | |
196 | "r1", | |
197 | { | |
198 | "numberOfIntraAreaRoutes": 1, | |
199 | "numberOfInterAreaRoutes": 3, | |
200 | "numberOfExternal1Routes": 0, | |
201 | "numberOfExternal2Routes": 0, | |
202 | }, | |
203 | ) | |
204 | # NSSA router: no external routes. | |
205 | expect_ospf6_route_types( | |
206 | "r4", | |
207 | { | |
208 | "numberOfIntraAreaRoutes": 1, | |
209 | "numberOfInterAreaRoutes": 2, | |
242a9767 | 210 | "numberOfExternal1Routes": 0, |
210429c7 | 211 | "numberOfExternal2Routes": 3, |
d87586c6 K |
212 | }, |
213 | ) | |
bcddbefe RZ |
214 | |
215 | ||
216 | def test_ospf6_default_route(): | |
217 | "Wait for OSPFv3 default route in stub area." | |
218 | tgen = get_topogen() | |
219 | if tgen.routers_have_failure(): | |
220 | pytest.skip(tgen.errors) | |
221 | ||
222 | logger.info("waiting for default route") | |
223 | ||
224 | def expect_route(router, route, metric): | |
225 | "Test OSPF6 route existence." | |
226 | logger.info("waiting OSPFv3 router '{}' routes".format(router)) | |
227 | test_func = partial( | |
228 | topotest.router_json_cmp, | |
229 | tgen.gears[router], | |
230 | "show ipv6 route json", | |
231 | {route: [{"metric": metric}]}, | |
232 | ) | |
d3a6af08 | 233 | _, result = topotest.run_and_expect(test_func, None, count=5, wait=1) |
bcddbefe RZ |
234 | assertmsg = '"{}" convergence failure'.format(router) |
235 | assert result is None, assertmsg | |
236 | ||
bcddbefe | 237 | metric = 123 |
12a97d46 RZ |
238 | expect_lsas( |
239 | "r1", | |
240 | "0.0.0.1", | |
241 | [{"prefix": "::/0", "metric": metric}], | |
242 | extra_params="inter-prefix detail", | |
243 | ) | |
bcddbefe RZ |
244 | expect_route("r1", "::/0", metric + 10) |
245 | ||
246 | ||
476e9575 RW |
247 | def test_redistribute_metrics(): |
248 | """ | |
249 | Test that the configured metrics are honored when a static route is | |
250 | redistributed. | |
251 | """ | |
252 | tgen = get_topogen() | |
253 | if tgen.routers_have_failure(): | |
254 | pytest.skip(tgen.errors) | |
255 | ||
256 | # Add new static route on r3. | |
257 | config = """ | |
258 | configure terminal | |
259 | ipv6 route 2001:db8:500::/64 Null0 | |
260 | """ | |
261 | tgen.gears["r3"].vtysh_cmd(config) | |
262 | ||
263 | route = { | |
264 | "2001:db8:500::/64": { | |
a53c08bc CH |
265 | "metricType": 2, |
266 | "metricCost": 10, | |
476e9575 RW |
267 | } |
268 | } | |
a53c08bc CH |
269 | logger.info( |
270 | "Expecting AS-external route 2001:db8:500::/64 to show up with default metrics" | |
271 | ) | |
476e9575 RW |
272 | expect_ospfv3_routes("r2", route, wait=30, detail=True) |
273 | ||
274 | # Change the metric of redistributed routes of the static type on r3. | |
275 | config = """ | |
276 | configure terminal | |
277 | router ospf6 | |
278 | redistribute static metric 50 metric-type 1 | |
279 | """ | |
280 | tgen.gears["r3"].vtysh_cmd(config) | |
281 | ||
282 | # Check if r3 reinstalled 2001:db8:500::/64 using the new metric type and value. | |
283 | route = { | |
284 | "2001:db8:500::/64": { | |
a53c08bc CH |
285 | "metricType": 1, |
286 | "metricCost": 60, | |
476e9575 RW |
287 | } |
288 | } | |
a53c08bc CH |
289 | logger.info( |
290 | "Expecting AS-external route 2001:db8:500::/64 to show up with updated metric type and value" | |
291 | ) | |
476e9575 RW |
292 | expect_ospfv3_routes("r2", route, wait=30, detail=True) |
293 | ||
294 | ||
12a97d46 RZ |
295 | def test_nssa_lsa_type7(): |
296 | """ | |
297 | Test that static route gets announced as external route when redistributed | |
298 | and gets removed when redistribution stops. | |
299 | """ | |
300 | tgen = get_topogen() | |
301 | if tgen.routers_have_failure(): | |
302 | pytest.skip(tgen.errors) | |
303 | ||
304 | # | |
305 | # Add new static route and check if it gets announced as LSA Type-7. | |
306 | # | |
307 | config = """ | |
308 | configure terminal | |
309 | ipv6 route 2001:db8:100::/64 Null0 | |
310 | """ | |
311 | tgen.gears["r2"].vtysh_cmd(config) | |
312 | ||
313 | lsas = [ | |
314 | { | |
315 | "type": "NSSA", | |
316 | "advertisingRouter": "10.254.254.2", | |
317 | "prefix": "2001:db8:100::/64", | |
318 | "forwardingAddress": "2001:db8:3::1", | |
319 | } | |
320 | ] | |
321 | route = { | |
322 | "2001:db8:100::/64": { | |
242a9767 | 323 | "pathType": "E2", |
a53c08bc | 324 | "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}], |
12a97d46 RZ |
325 | } |
326 | } | |
327 | ||
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) | |
331 | ||
332 | # | |
333 | # Remove static route and check for LSA Type-7 removal. | |
334 | # | |
335 | config = """ | |
336 | configure terminal | |
337 | no ipv6 route 2001:db8:100::/64 Null0 | |
338 | """ | |
339 | tgen.gears["r2"].vtysh_cmd(config) | |
340 | ||
341 | def dont_expect_lsa(unexpected_lsa): | |
342 | "Specialized test function to expect LSA go missing" | |
a53c08bc CH |
343 | output = tgen.gears["r4"].vtysh_cmd( |
344 | "show ipv6 ospf6 database type-7 detail json", isjson=True | |
345 | ) | |
346 | for lsa in output["areaScopedLinkStateDb"][0]["lsa"]: | |
12a97d46 RZ |
347 | if lsa["prefix"] == unexpected_lsa["prefix"]: |
348 | if lsa["forwardingAddress"] == unexpected_lsa["forwardingAddress"]: | |
349 | return lsa | |
350 | return None | |
351 | ||
12a97d46 RZ |
352 | logger.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away") |
353 | ||
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 | |
359 | ||
360 | # Test that route doesn't exist. | |
fee16c7e | 361 | test_func = partial(dont_expect_route, "r4", "2001:db8:100::/64") |
12a97d46 RZ |
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 | |
365 | ||
366 | ||
fee16c7e RW |
367 | def test_nssa_no_summary(): |
368 | """ | |
369 | Test the following: | |
370 | * Type-3 inter-area routes should be removed when the NSSA no-summary option | |
371 | is configured; | |
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 | |
376 | route removed. | |
377 | """ | |
378 | tgen = get_topogen() | |
379 | if tgen.routers_have_failure(): | |
380 | pytest.skip(tgen.errors) | |
381 | ||
382 | # | |
383 | # Configure area 1 as a NSSA totally stub area. | |
384 | # | |
385 | config = """ | |
386 | configure terminal | |
387 | router ospf6 | |
388 | area 2 nssa no-summary | |
389 | """ | |
390 | tgen.gears["r2"].vtysh_cmd(config) | |
391 | ||
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 | |
398 | ||
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") | |
402 | ||
403 | # | |
404 | # Configure area 1 as a regular NSSA area. | |
405 | # | |
406 | config = """ | |
407 | configure terminal | |
408 | router ospf6 | |
409 | area 2 nssa | |
410 | """ | |
411 | tgen.gears["r2"].vtysh_cmd(config) | |
412 | ||
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") | |
416 | ||
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 | |
422 | ||
423 | ||
6735622c RW |
424 | def test_nssa_default_originate(): |
425 | """ | |
426 | Test the following: | |
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. | |
431 | """ | |
432 | tgen = get_topogen() | |
433 | if tgen.routers_have_failure(): | |
434 | pytest.skip(tgen.errors) | |
435 | ||
436 | # | |
437 | # Configure r2 to announce a Type-7 default route. | |
438 | # | |
439 | config = """ | |
440 | configure terminal | |
441 | router ospf6 | |
442 | no default-information originate | |
443 | area 2 nssa default-information-originate | |
444 | """ | |
445 | tgen.gears["r2"].vtysh_cmd(config) | |
446 | ||
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") | |
450 | ||
451 | # | |
452 | # Configure r2 to stop announcing a Type-7 default route. | |
453 | # | |
454 | config = """ | |
455 | configure terminal | |
456 | router ospf6 | |
457 | area 2 nssa | |
458 | """ | |
459 | tgen.gears["r2"].vtysh_cmd(config) | |
460 | ||
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 | |
466 | ||
467 | ||
f4f0098c RW |
468 | def test_area_filters(): |
469 | """ | |
470 | Test ABR import/export filters. | |
471 | """ | |
472 | tgen = get_topogen() | |
473 | if tgen.routers_have_failure(): | |
474 | pytest.skip(tgen.errors) | |
475 | ||
476 | # | |
343e16ce | 477 | # Configure import/export filters on r2 (ABR for area 2). |
f4f0098c RW |
478 | # |
479 | config = """ | |
480 | configure terminal | |
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 | |
484 | router ospf6 | |
485 | area 1 import-list ACL_IMPORT | |
486 | area 1 export-list ACL_EXPORT | |
487 | """ | |
488 | tgen.gears["r2"].vtysh_cmd(config) | |
489 | ||
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 | |
496 | ||
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 | |
503 | ||
504 | # | |
505 | # Update the ACLs used by the import/export filters. | |
506 | # | |
507 | config = """ | |
508 | configure terminal | |
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 | |
511 | """ | |
512 | tgen.gears["r2"].vtysh_cmd(config) | |
513 | ||
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") | |
520 | ||
521 | # | |
522 | # Unconfigure r2's ABR import/export filters. | |
523 | # | |
524 | config = """ | |
525 | configure terminal | |
526 | router ospf6 | |
527 | no area 1 import-list ACL_IMPORT | |
528 | no area 1 export-list ACL_EXPORT | |
529 | """ | |
530 | tgen.gears["r2"].vtysh_cmd(config) | |
531 | ||
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") | |
535 | ||
536 | ||
343e16ce RW |
537 | def test_nssa_range(): |
538 | """ | |
539 | Test NSSA ABR ranges. | |
540 | """ | |
541 | tgen = get_topogen() | |
542 | if tgen.routers_have_failure(): | |
543 | pytest.skip(tgen.errors) | |
544 | ||
545 | # Configure new addresses on r4 and enable redistribution of connected | |
546 | # routes. | |
547 | config = """ | |
548 | configure terminal | |
549 | interface r4-stubnet | |
550 | ipv6 address 2001:db8:1000::1/128 | |
551 | ipv6 address 2001:db8:1000::2/128 | |
552 | router ospf6 | |
553 | redistribute connected | |
554 | """ | |
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") | |
559 | ||
560 | # Configure an NSSA range on r2 (ABR for area 2). | |
561 | config = """ | |
562 | configure terminal | |
563 | router ospf6 | |
564 | area 2 nssa range 2001:db8:1000::/64 | |
565 | """ | |
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") | |
574 | routes = { | |
575 | "2001:db8:1000::/64": { | |
9a974f22 | 576 | "metricType": 2, |
577 | "metricCost": 20, | |
578 | "metricCostE2": 10, | |
579 | } | |
580 | } | |
343e16ce RW |
581 | expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) |
582 | ||
583 | # Change the NSSA range cost. | |
584 | config = """ | |
585 | configure terminal | |
586 | router ospf6 | |
587 | area 2 nssa range 2001:db8:1000::/64 cost 1000 | |
588 | """ | |
589 | tgen.gears["r2"].vtysh_cmd(config) | |
590 | logger.info("Expecting NSSA range to be updated with new cost") | |
591 | routes = { | |
592 | "2001:db8:1000::/64": { | |
9a974f22 | 593 | "metricType": 2, |
594 | "metricCost": 20, | |
595 | "metricCostE2": 1000, | |
596 | } | |
597 | } | |
343e16ce RW |
598 | expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) |
599 | ||
600 | # Configure the NSSA range to not be advertised. | |
601 | config = """ | |
602 | configure terminal | |
603 | router ospf6 | |
604 | area 2 nssa range 2001:db8:1000::/64 not-advertise | |
605 | """ | |
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 | |
613 | ||
614 | # Remove the NSSA range. | |
615 | config = """ | |
616 | configure terminal | |
617 | router ospf6 | |
618 | no area 2 nssa range 2001:db8:1000::/64 | |
619 | """ | |
620 | tgen.gears["r2"].vtysh_cmd(config) | |
621 | logger.info("Expecting previously summarized routes to be re-added") | |
622 | routes = { | |
623 | "2001:db8:1000::1/128": { | |
9a974f22 | 624 | "metricType": 2, |
625 | "metricCostE2": 20, | |
343e16ce RW |
626 | }, |
627 | "2001:db8:1000::2/128": { | |
9a974f22 | 628 | "metricType": 2, |
629 | "metricCostE2": 20, | |
343e16ce RW |
630 | }, |
631 | } | |
632 | expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) | |
633 | ||
634 | ||
bcddbefe RZ |
635 | def teardown_module(_mod): |
636 | "Teardown the pytest environment" | |
637 | tgen = get_topogen() | |
638 | tgen.stop_topology() | |
639 | ||
640 | ||
641 | def test_memory_leak(): | |
642 | "Run the memory leak test and report results." | |
643 | tgen = get_topogen() | |
644 | if not tgen.is_memleak_enabled(): | |
645 | pytest.skip("Memory leak test/report is disabled") | |
646 | ||
647 | tgen.report_memory_leaks() | |
648 | ||
649 | ||
650 | if __name__ == "__main__": | |
651 | args = ["-s"] + sys.argv[1:] | |
652 | sys.exit(pytest.main(args)) |