]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / topotests / isis_lfa_topo1 / test_isis_lfa_topo1.py
1 #!/usr/bin/env python
2 # SPDX-License-Identifier: ISC
3
4 #
5 # test_isis_tilfa_topo1.py
6 # Part of NetDEF Topology Tests
7 #
8 # Copyright (c) 2020 by
9 # Network Device Education Foundation, Inc. ("NetDEF")
10 #
11
12 """
13 test_isis_lfa_topo1.py:
14
15 +---------+
16 | |
17 +--------------------------------+ RT1 +-------------------------------+
18 | +-------------+ +-------------+ |
19 | | | | | |
20 | | +----+----+ | |
21 | | | |20 |
22 | | | | |
23 | | | | |
24 +----+----+ +----+----+ +----+----+ +----+----+ +----+----+
25 | | | | | | | | | |
26 | RT2 | 5 | RT3 | | RT4 | | RT5 | | RT6 |
27 | +--------+ | | | | | | |
28 | | | | | | | | | |
29 +----+----+ +----+----+ +----+----+ +----+----+ +----+----+
30 | | | | |
31 | | |15 | |
32 |5 | | | |
33 | | +----+----+ | |
34 | | | | | |
35 | +-------------+ RT7 +-------------+ |
36 +--------------------------------+ +-------------------------------+
37 | |
38 +---------+
39 """
40
41 import os
42 import sys
43 import pytest
44 import json
45 import time
46 import tempfile
47 from functools import partial
48
49 # Save the Current Working Directory to find configuration files.
50 CWD = os.path.dirname(os.path.realpath(__file__))
51 sys.path.append(os.path.join(CWD, "../"))
52
53 # pylint: disable=C0413
54 # Import topogen and topotest helpers
55 from lib import topotest
56 from lib.topogen import Topogen, TopoRouter, get_topogen
57 from lib.topolog import logger
58
59 # Required to instantiate the topology builder class.
60
61 pytestmark = [pytest.mark.isisd]
62
63 # Global multi-dimensional dictionary containing all expected outputs
64 outputs = {}
65
66
67 def build_topo(tgen):
68 "Build function"
69
70 #
71 # Define FRR Routers
72 #
73 for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
74 tgen.add_router(router)
75
76 #
77 # Define connections
78 #
79 switch = tgen.add_switch("s1")
80 switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
81 switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
82 switch = tgen.add_switch("s2")
83 switch.add_link(tgen.gears["rt2"], nodeif="eth-rt3")
84 switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2")
85 switch = tgen.add_switch("s3")
86 switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
87 switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
88 switch = tgen.add_switch("s4")
89 switch.add_link(tgen.gears["rt1"], nodeif="eth-rt4")
90 switch.add_link(tgen.gears["rt4"], nodeif="eth-rt1")
91 switch = tgen.add_switch("s5")
92 switch.add_link(tgen.gears["rt1"], nodeif="eth-rt5")
93 switch.add_link(tgen.gears["rt5"], nodeif="eth-rt1")
94 switch = tgen.add_switch("s6")
95 switch.add_link(tgen.gears["rt1"], nodeif="eth-rt6")
96 switch.add_link(tgen.gears["rt6"], nodeif="eth-rt1")
97 switch = tgen.add_switch("s7")
98 switch.add_link(tgen.gears["rt2"], nodeif="eth-rt7")
99 switch.add_link(tgen.gears["rt7"], nodeif="eth-rt2")
100 switch = tgen.add_switch("s8")
101 switch.add_link(tgen.gears["rt3"], nodeif="eth-rt7")
102 switch.add_link(tgen.gears["rt7"], nodeif="eth-rt3")
103 switch = tgen.add_switch("s9")
104 switch.add_link(tgen.gears["rt4"], nodeif="eth-rt7")
105 switch.add_link(tgen.gears["rt7"], nodeif="eth-rt4")
106 switch = tgen.add_switch("s10")
107 switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
108 switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
109 switch = tgen.add_switch("s11")
110 switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7")
111 switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6")
112
113 #
114 # Populate multi-dimensional dictionary containing all expected outputs
115 #
116 files = ["show_ipv6_route.ref", "show_yang_interface_isis_adjacencies.ref"]
117 for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
118 outputs[rname] = {}
119 for step in range(1, 16 + 1):
120 outputs[rname][step] = {}
121 for file in files:
122 if step == 1:
123 # Get snapshots relative to the expected initial network convergence
124 filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
125 outputs[rname][step][file] = open(filename).read()
126 else:
127 if rname != "rt1":
128 continue
129 if file == "show_yang_interface_isis_adjacencies.ref":
130 continue
131
132 # Get diff relative to the previous step
133 filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
134
135 # Create temporary files in order to apply the diff
136 f_in = tempfile.NamedTemporaryFile(mode="w")
137 f_in.write(outputs[rname][step - 1][file])
138 f_in.flush()
139 f_out = tempfile.NamedTemporaryFile(mode="r")
140 os.system(
141 "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
142 )
143
144 # Store the updated snapshot and remove the temporary files
145 outputs[rname][step][file] = open(f_out.name).read()
146 f_in.close()
147 f_out.close()
148
149
150 def setup_module(mod):
151 "Sets up the pytest environment"
152 tgen = Topogen(build_topo, mod.__name__)
153 tgen.start_topology()
154
155 router_list = tgen.routers()
156
157 # For all registered routers, load the zebra configuration file
158 for rname, router in router_list.items():
159 router.load_config(
160 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
161 )
162 router.load_config(
163 TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
164 )
165 router.load_config(
166 TopoRouter.RD_BFD, os.path.join(CWD, "/dev/null".format(rname))
167 )
168
169 tgen.start_router()
170
171
172 def teardown_module(mod):
173 "Teardown the pytest environment"
174 tgen = get_topogen()
175
176 # This function tears down the whole topology.
177 tgen.stop_topology()
178
179
180 def router_compare_json_output(rname, command, reference, wait=0.5, count=120):
181 "Compare router JSON output"
182
183 logger.info('Comparing router "%s" "%s" output', rname, command)
184
185 tgen = get_topogen()
186 expected = json.loads(reference)
187
188 # Run test function until we get an result. Wait at most 60 seconds.
189 test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
190 _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
191 assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
192 assert diff is None, assertmsg
193
194
195 #
196 # Step 1
197 #
198 # Test initial network convergence
199 #
200 def test_isis_adjacencies_step1():
201 logger.info("Test (step 1): check IS-IS adjacencies")
202 tgen = get_topogen()
203
204 # Skip if previous fatal error condition is raised
205 if tgen.routers_have_failure():
206 pytest.skip(tgen.errors)
207
208 for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
209 router_compare_json_output(
210 rname,
211 "show yang operational-data /frr-interface:lib isisd",
212 outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
213 )
214
215
216 def test_rib_ipv6_step1():
217 logger.info("Test (step 1): verify IPv6 RIB")
218 tgen = get_topogen()
219
220 # Skip if previous fatal error condition is raised
221 if tgen.routers_have_failure():
222 pytest.skip(tgen.errors)
223
224 for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
225 router_compare_json_output(
226 rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
227 )
228
229
230 #
231 # Step 2
232 #
233 # Action(s):
234 # -Disable LFA protection on all interfaces
235 #
236 # Expected changes:
237 # -rt1 should uninstall all backup nexthops from all routes
238 #
239 def test_rib_ipv6_step2():
240 logger.info("Test (step 2): verify IPv6 RIB")
241 tgen = get_topogen()
242
243 # Skip if previous fatal error condition is raised
244 if tgen.routers_have_failure():
245 pytest.skip(tgen.errors)
246
247 logger.info("Disabling LFA protection on all rt1 interfaces")
248 tgen.net["rt1"].cmd(
249 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"'
250 )
251 tgen.net["rt1"].cmd(
252 'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"'
253 )
254 tgen.net["rt1"].cmd(
255 'vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"'
256 )
257 tgen.net["rt1"].cmd(
258 'vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"'
259 )
260 tgen.net["rt1"].cmd(
261 'vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"'
262 )
263
264 for rname in ["rt1"]:
265 router_compare_json_output(
266 rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
267 )
268
269
270 #
271 # Step 3
272 #
273 # Action(s):
274 # -Re-enable LFA protection on all interfaces
275 #
276 # Expected changes:
277 # -Revert changes from the previous step
278 #
279 def test_rib_ipv6_step3():
280 logger.info("Test (step 3): verify IPv6 RIB")
281 tgen = get_topogen()
282
283 # Skip if previous fatal error condition is raised
284 if tgen.routers_have_failure():
285 pytest.skip(tgen.errors)
286
287 logger.info("Re-enabling LFA protection on all rt1 interfaces")
288 tgen.net["rt1"].cmd(
289 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"'
290 )
291 tgen.net["rt1"].cmd(
292 'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"'
293 )
294 tgen.net["rt1"].cmd(
295 'vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"'
296 )
297 tgen.net["rt1"].cmd(
298 'vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"'
299 )
300 tgen.net["rt1"].cmd(
301 'vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"'
302 )
303
304 for rname in ["rt1"]:
305 router_compare_json_output(
306 rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
307 )
308
309
310 #
311 # Step 4
312 #
313 # Action(s):
314 # -Disable LFA load-sharing
315 #
316 # Expected changes:
317 # -rt1 should use at most one backup nexthop for each route
318 #
319 def test_rib_ipv6_step4():
320 logger.info("Test (step 4): verify IPv6 RIB")
321 tgen = get_topogen()
322
323 # Skip if previous fatal error condition is raised
324 if tgen.routers_have_failure():
325 pytest.skip(tgen.errors)
326
327 logger.info("Disabling LFA load-sharing on rt1")
328 tgen.net["rt1"].cmd(
329 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"'
330 )
331
332 for rname in ["rt1"]:
333 router_compare_json_output(
334 rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
335 )
336
337
338 #
339 # Step 5
340 #
341 # Action(s):
342 # -Re-enable LFA load-sharing
343 #
344 # Expected changes:
345 # -Revert changes from the previous step
346 #
347 def test_rib_ipv6_step5():
348 logger.info("Test (step 5): verify IPv6 RIB")
349 tgen = get_topogen()
350
351 # Skip if previous fatal error condition is raised
352 if tgen.routers_have_failure():
353 pytest.skip(tgen.errors)
354
355 logger.info("Re-enabling LFA load-sharing on rt1")
356 tgen.net["rt1"].cmd(
357 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"'
358 )
359
360 for rname in ["rt1"]:
361 router_compare_json_output(
362 rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
363 )
364
365
366 #
367 # Step 6
368 #
369 # Action(s):
370 # -Limit backup computation to critical priority prefixes only
371 #
372 # Expected changes:
373 # -rt1 should uninstall all backup nexthops from all routes
374 #
375 def test_rib_ipv6_step6():
376 logger.info("Test (step 6): verify IPv6 RIB")
377 tgen = get_topogen()
378
379 # Skip if previous fatal error condition is raised
380 if tgen.routers_have_failure():
381 pytest.skip(tgen.errors)
382
383 logger.info("Limiting backup computation to critical priority prefixes only")
384 tgen.net["rt1"].cmd(
385 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"'
386 )
387
388 for rname in ["rt1"]:
389 router_compare_json_output(
390 rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
391 )
392
393
394 #
395 # Step 7
396 #
397 # Action(s):
398 # -Configure a prefix priority list to classify rt7's loopback as a
399 # critical-priority prefix
400 #
401 # Expected changes:
402 # -rt1 should install backup nexthops for rt7's loopback route.
403 #
404 def test_rib_ipv6_step7():
405 logger.info("Test (step 7): verify IPv6 RIB")
406 tgen = get_topogen()
407
408 # Skip if previous fatal error condition is raised
409 if tgen.routers_have_failure():
410 pytest.skip(tgen.errors)
411
412 logger.info("Configuring a prefix priority list")
413 tgen.net["rt1"].cmd(
414 'vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"'
415 )
416 tgen.net["rt1"].cmd(
417 'vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
418 )
419
420 for rname in ["rt1"]:
421 router_compare_json_output(
422 rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
423 )
424
425
426 #
427 # Step 8
428 #
429 # Action(s):
430 # -Revert previous changes related to prefix priorities
431 #
432 # Expected changes:
433 # -Revert changes from the previous two steps
434 #
435 def test_rib_ipv6_step8():
436 logger.info("Test (step 8): verify IPv6 RIB")
437 tgen = get_topogen()
438
439 # Skip if previous fatal error condition is raised
440 if tgen.routers_have_failure():
441 pytest.skip(tgen.errors)
442
443 logger.info("Reverting previous changes related to prefix priorities")
444 tgen.net["rt1"].cmd(
445 'vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
446 )
447 tgen.net["rt1"].cmd(
448 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"'
449 )
450 tgen.net["rt1"].cmd(
451 'vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"'
452 )
453
454 for rname in ["rt1"]:
455 router_compare_json_output(
456 rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
457 )
458
459
460 #
461 # Step 9
462 #
463 # Action(s):
464 # -Exclude eth-rt6 from LFA computation for eth-rt2's failure
465 #
466 # Expected changes:
467 # -Uninstall the eth-rt2 protecting backup nexthops that go through eth-rt6
468 #
469 def test_rib_ipv6_step9():
470 logger.info("Test (step 9): verify IPv6 RIB")
471 tgen = get_topogen()
472
473 # Skip if previous fatal error condition is raised
474 if tgen.routers_have_failure():
475 pytest.skip(tgen.errors)
476
477 logger.info("Excluding eth-rt6 from LFA computation for eth-rt2's failure")
478 tgen.net["rt1"].cmd(
479 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"'
480 )
481
482 for rname in ["rt1"]:
483 router_compare_json_output(
484 rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
485 )
486
487
488 #
489 # Step 10
490 #
491 # Action(s):
492 # -Remove exclusion of eth-rt6 from LFA computation for eth-rt2's failure
493 #
494 # Expected changes:
495 # -Revert changes from the previous step
496 #
497 def test_rib_ipv6_step10():
498 logger.info("Test (step 10): verify IPv6 RIB")
499 tgen = get_topogen()
500
501 # Skip if previous fatal error condition is raised
502 if tgen.routers_have_failure():
503 pytest.skip(tgen.errors)
504
505 logger.info(
506 "Removing exclusion of eth-rt6 from LFA computation for eth-rt2's failure"
507 )
508 tgen.net["rt1"].cmd(
509 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"'
510 )
511
512 for rname in ["rt1"]:
513 router_compare_json_output(
514 rname,
515 "show ipv6 route isis json",
516 outputs[rname][10]["show_ipv6_route.ref"],
517 )
518
519
520 #
521 # Step 11
522 #
523 # Action(s):
524 # -Add LFA tiebreaker: prefer node protecting backup path
525 #
526 # Expected changes:
527 # -rt1 should prefer backup nexthops that provide node protection
528 #
529 def test_rib_ipv6_step11():
530 logger.info("Test (step 11): verify IPv6 RIB")
531 tgen = get_topogen()
532
533 # Skip if previous fatal error condition is raised
534 if tgen.routers_have_failure():
535 pytest.skip(tgen.errors)
536
537 logger.info("Adding LFA tiebreaker: prefer node protecting backup path")
538 tgen.net["rt1"].cmd(
539 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"'
540 )
541
542 for rname in ["rt1"]:
543 router_compare_json_output(
544 rname,
545 "show ipv6 route isis json",
546 outputs[rname][11]["show_ipv6_route.ref"],
547 )
548
549
550 #
551 # Step 12
552 #
553 # Action(s):
554 # -Add LFA tiebreaker: prefer backup path via downstream node
555 #
556 # Expected changes:
557 # -rt1 should prefer backup nexthops that satisfy the downstream condition
558 #
559 def test_rib_ipv6_step12():
560 logger.info("Test (step 12): verify IPv6 RIB")
561 tgen = get_topogen()
562
563 # Skip if previous fatal error condition is raised
564 if tgen.routers_have_failure():
565 pytest.skip(tgen.errors)
566
567 logger.info("Adding LFA tiebreaker: prefer backup path via downstream node")
568 tgen.net["rt1"].cmd(
569 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"'
570 )
571
572 for rname in ["rt1"]:
573 router_compare_json_output(
574 rname,
575 "show ipv6 route isis json",
576 outputs[rname][12]["show_ipv6_route.ref"],
577 )
578
579
580 #
581 # Step 13
582 #
583 # Action(s):
584 # -Add LFA tiebreaker: prefer backup path with lowest total metric
585 #
586 # Expected changes:
587 # -rt1 should prefer backup nexthops that have the best metric
588 #
589 def test_rib_ipv6_step13():
590 logger.info("Test (step 13): verify IPv6 RIB")
591 tgen = get_topogen()
592
593 # Skip if previous fatal error condition is raised
594 if tgen.routers_have_failure():
595 pytest.skip(tgen.errors)
596
597 logger.info("Adding LFA tiebreaker: prefer backup path with lowest total metric")
598 tgen.net["rt1"].cmd(
599 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"'
600 )
601
602 for rname in ["rt1"]:
603 router_compare_json_output(
604 rname,
605 "show ipv6 route isis json",
606 outputs[rname][13]["show_ipv6_route.ref"],
607 )
608
609
610 #
611 # Step 14
612 #
613 # Action(s):
614 # - Setting spf-delay-ietf init-delay of 15s
615 #
616 # Expected changes:
617 # - No routing table change
618 # - At the end of test, SPF reacts to a failure in 15s
619 #
620 def test_rib_ipv6_step14():
621 logger.info("Test (step 14): verify IPv6 RIB")
622 tgen = get_topogen()
623
624 # Skip if previous fatal error condition is raised
625 if tgen.routers_have_failure():
626 pytest.skip(tgen.errors)
627
628 logger.info("Setting spf-delay-ietf init-delay of 15s")
629 tgen.net["rt1"].cmd(
630 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
631 )
632
633 for rname in ["rt1"]:
634 router_compare_json_output(
635 rname,
636 "show ipv6 route isis json",
637 outputs[rname][14]["show_ipv6_route.ref"],
638 )
639
640
641 #
642 # Step 15
643 #
644 # Action(s):
645 # - shut the eth-rt2 interface on rt1
646 #
647 # Expected changes:
648 # - Route switchover of routes via eth-rt2
649 #
650 def test_rib_ipv6_step15():
651 logger.info("Test (step 15): verify IPv6 RIB")
652 tgen = get_topogen()
653
654 # Skip if previous fatal error condition is raised
655 if tgen.routers_have_failure():
656 pytest.skip(tgen.errors)
657
658 logger.info("Shut the interface to rt2 from the switch side and check fast-reroute")
659 tgen.net.cmd_raises("ip link set %s down" % tgen.net["s1"].intfs[0])
660
661 for rname in ["rt1"]:
662 router_compare_json_output(
663 rname,
664 "show ipv6 route isis json",
665 outputs[rname][15]["show_ipv6_route.ref"],
666 count=10,
667 wait=0.5,
668 )
669
670
671 #
672 # Step 16
673 #
674 # Action(s): wait for the convergence and SPF computation on rt1
675 #
676 # Expected changes:
677 # - convergence of IPv6 RIB
678 #
679 def test_rib_ipv6_step16():
680 logger.info("Test (step 16): verify IPv6 RIB")
681 tgen = get_topogen()
682
683 # Skip if previous fatal error condition is raised
684 if tgen.routers_have_failure():
685 pytest.skip(tgen.errors)
686
687 logger.info("Check SPF convergence")
688
689 for rname in ["rt1"]:
690 router_compare_json_output(
691 rname,
692 "show ipv6 route isis json",
693 outputs[rname][16]["show_ipv6_route.ref"],
694 )
695
696
697 #
698 # Step 17
699 #
700 # Action(s):
701 # - Unshut the interface to rt2 from the switch sid
702 #
703 # Expected changes:
704 # - The routing table converges
705 #
706 def test_rib_ipv6_step17():
707 logger.info("Test (step 17): verify IPv6 RIB")
708 tgen = get_topogen()
709
710 # Skip if previous fatal error condition is raised
711 if tgen.routers_have_failure():
712 pytest.skip(tgen.errors)
713
714 rname = "rt1"
715
716 logger.info("Unsetting spf-delay-ietf init-delay of 15s")
717 tgen.net[rname].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"')
718
719 logger.info(
720 "Unshut the interface to rt2 from the switch side and check fast-reroute"
721 )
722 tgen.net.cmd_raises("ip link set %s up" % tgen.net["s1"].intfs[0])
723
724 logger.info("Setting spf-delay-ietf init-delay of 15s")
725 tgen.net[rname].cmd(
726 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
727 )
728
729 router_compare_json_output(
730 rname,
731 "show ipv6 route isis json",
732 outputs[rname][14]["show_ipv6_route.ref"],
733 )
734
735
736 #
737 # Step 18
738 #
739 # Action(s):
740 # - drop traffic between rt1 and rt2 by shutting down the bridge between
741 # the routers. Interfaces on rt1 and rt2 stay up.
742 #
743 #
744 # Expected changes:
745 # - Route switchover of routes via eth-rt2
746 #
747 def test_rib_ipv6_step18():
748 def _rt2_neigh_down(router):
749 output = json.loads(router.vtysh_cmd("show isis neighbor rt2 json"))
750
751 """
752 Previous output was:
753 {
754 "areas":[
755 {
756 "area":"1",
757 "circuits":[
758 {
759 "circuit":0,
760 "adj":"rt2",
761 "interface":{
762 "name":"eth-rt2",
763 "state":"Up",
764 "adj-flaps":1,
765 "last-ago":"21s",
766 "circuit-type":"L1",
767 "speaks":"IPv6",
768 "topologies":{
769 "topo-0":"ipv6-unicast"
770 },
771 "snpa":"2020.2020.2020",
772 "area-address":{
773 "isonet":"49.0000"
774 },
775 "ipv6-link-local":{
776 "ipv6":"fe80::ac19:a8ff:fee5:f48f"
777 },
778 "adj-sid":{
779 }
780 },
781 "level":1,
782 "expires-in":"2s"
783 },
784 {
785 "circuit":0
786 },
787 {
788 "circuit":0
789 },
790 {
791 "circuit":0
792 },
793 {
794 "circuit":0
795 },
796 {
797 "circuit":0
798 }
799 ]
800 }
801 ]
802 """
803
804 expected = {
805 "areas": [
806 {
807 "area": "1",
808 "circuits": [
809 {"circuit": 0},
810 {"circuit": 0},
811 {"circuit": 0},
812 {"circuit": 0},
813 {"circuit": 0},
814 {"circuit": 0},
815 ],
816 }
817 ]
818 }
819
820 return topotest.json_cmp(output, expected, exact=True)
821
822 logger.info("Test (step 18): verify IPv6 RIB")
823 tgen = get_topogen()
824
825 # Skip if previous fatal error condition is raised
826 if tgen.routers_have_failure():
827 pytest.skip(tgen.errors)
828
829 logger.info("Drop traffic between rt1 and rt2")
830 tgen.net.cmd_raises("ip link set s1 down")
831
832 rname = "rt1"
833 router = tgen.gears[rname]
834 test_func = partial(_rt2_neigh_down, router)
835 success, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05)
836 assert result is None, 'rt2 neighbor is still present on "{}"'.format(router)
837
838 router_compare_json_output(
839 rname,
840 "show ipv6 route isis json",
841 outputs[rname][15]["show_ipv6_route.ref"],
842 count=10,
843 wait=0.5,
844 )
845
846
847 #
848 # Step 19
849 #
850 # Action(s): wait for the convergence and SPF computation on rt1
851 #
852 # Expected changes:
853 # - convergence of IPv6 RIB
854 #
855 def test_rib_ipv6_step19():
856 logger.info("Test (step 19): verify IPv6 RIB")
857 tgen = get_topogen()
858
859 # Skip if previous fatal error condition is raised
860 if tgen.routers_have_failure():
861 pytest.skip(tgen.errors)
862
863 logger.info("Check SPF convergence")
864
865 for rname in ["rt1"]:
866 router_compare_json_output(
867 rname,
868 "show ipv6 route isis json",
869 outputs[rname][16]["show_ipv6_route.ref"],
870 )
871
872
873 #
874 # Step 20
875 #
876 # Action(s):
877 # - Unshut the switch from rt1 to rt2
878 #
879 # Expected changes:
880 # - The routing table goes back to the nominal state
881 #
882 def test_rib_ipv6_step20():
883 logger.info("Test (step 20): verify IPv6 RIB")
884 tgen = get_topogen()
885
886 # Skip if previous fatal error condition is raised
887 if tgen.routers_have_failure():
888 pytest.skip(tgen.errors)
889
890 rname = "rt1"
891
892 logger.info("Unsetting spf-delay-ietf init-delay of 15s")
893 tgen.net[rname].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"')
894
895 logger.info(
896 "Unshut the interface to rt2 from the switch side and check fast-reroute"
897 )
898 tgen.net.cmd_raises("ip link set s1 up")
899
900 logger.info("Setting spf-delay-ietf init-delay of 15s")
901 tgen.net[rname].cmd(
902 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
903 )
904
905 router_compare_json_output(
906 rname,
907 "show ipv6 route isis json",
908 outputs[rname][14]["show_ipv6_route.ref"],
909 )
910
911
912 #
913 # Step 21
914 #
915 # Action(s):
916 # - clear the rt2 ISIS neighbor on rt1
917 #
918 # Expected changes:
919 # - Route switchover of routes via eth-rt2
920 #
921 def test_rib_ipv6_step21():
922 logger.info("Test (step 21): verify IPv6 RIB")
923 tgen = get_topogen()
924
925 # Skip if previous fatal error condition is raised
926 if tgen.routers_have_failure():
927 pytest.skip(tgen.errors)
928
929 rname = "rt1"
930
931 logger.info("Clear the rt2 ISIS neighbor on rt1 and check fast-reroute")
932 tgen.gears[rname].vtysh_cmd("clear isis neighbor rt2")
933
934 router_compare_json_output(
935 rname,
936 "show ipv6 route isis json",
937 outputs[rname][15]["show_ipv6_route.ref"],
938 count=10,
939 wait=0.5,
940 )
941
942
943 #
944 # Step 22
945 #
946 # Action(s): wait for the convergence and SPF computation on rt1
947 #
948 # Expected changes:
949 # - convergence of IPv6 RIB
950 #
951 def test_rib_ipv6_step22():
952 logger.info("Test (step 22): verify IPv6 RIB")
953 tgen = get_topogen()
954
955 # Skip if previous fatal error condition is raised
956 if tgen.routers_have_failure():
957 pytest.skip(tgen.errors)
958
959 logger.info("Check SPF convergence")
960
961 for rname in ["rt1"]:
962 router_compare_json_output(
963 rname,
964 "show ipv6 route isis json",
965 outputs[rname][16]["show_ipv6_route.ref"],
966 )
967
968
969 #
970 # Step 23
971 #
972 # Action(s):
973 # - Setting BFD
974 #
975 # Expected changes:
976 # - No routing table change
977 # - BFD comes up
978 #
979 def test_rib_ipv6_step23():
980 logger.info("Test (step 23): verify IPv6 RIB")
981 tgen = get_topogen()
982
983 # Skip if previous fatal error condition is raised
984 if tgen.routers_have_failure():
985 pytest.skip(tgen.errors)
986
987 logger.info("Setup BFD on rt1 and rt2")
988 for rname in ["rt1", "rt2"]:
989 conf_file = os.path.join(CWD, "{}/bfdd.conf".format(rname))
990 tgen.net[rname].cmd("vtysh -f {}".format(conf_file))
991
992 logger.info("Set ISIS BFD")
993 tgen.net["rt1"].cmd('vtysh -c "conf t" -c "int eth-rt2" -c "isis bfd"')
994 tgen.net["rt2"].cmd('vtysh -c "conf t" -c "int eth-rt1" -c "isis bfd"')
995
996 rname = "rt1"
997 expect = '[{"multihop":false,"interface":"eth-rt2","status":"up"}]'
998 router_compare_json_output(rname, "show bfd peers json", expect)
999
1000 router_compare_json_output(
1001 rname,
1002 "show ipv6 route isis json",
1003 outputs[rname][14]["show_ipv6_route.ref"],
1004 )
1005
1006
1007 #
1008 # Step 24
1009 #
1010 # Action(s):
1011 # - drop traffic between rt1 and rt2 by shutting down the bridge between
1012 # the routers. Interfaces on rt1 and rt2 stay up.
1013 #
1014 # Expected changes:
1015 # - BFD comes down before IS-IS
1016 # - Route switchover of routes via eth-rt2
1017 #
1018 def test_rib_ipv6_step24():
1019 def _bfd_down(router):
1020 output = json.loads(router.vtysh_cmd("show bfd peers json"))
1021 expected = []
1022 return topotest.json_cmp(output, expected, exact=True)
1023
1024 logger.info("Test (step 24): verify IPv6 RIB")
1025 tgen = get_topogen()
1026
1027 # Skip if previous fatal error condition is raised
1028 if tgen.routers_have_failure():
1029 pytest.skip(tgen.errors)
1030
1031 logger.info("Shut the interface to rt2 from the switch side and check fast-reroute")
1032 tgen.net.cmd_raises("ip link set s1 down")
1033
1034 rname = "rt1"
1035 router = tgen.gears[rname]
1036 test_func = partial(_bfd_down, router)
1037 success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3)
1038 assert result is None, 'BFD session is still up on "{}"'.format(router)
1039
1040 router_compare_json_output(
1041 rname,
1042 "show ipv6 route isis json",
1043 outputs[rname][15]["show_ipv6_route.ref"],
1044 count=10,
1045 )
1046
1047
1048 #
1049 # Step 25
1050 #
1051 # Action(s): wait for the convergence and SPF computation on rt1
1052 #
1053 # Expected changes:
1054 # - convergence of IPv6 RIB
1055 #
1056 def test_rib_ipv6_step25():
1057 logger.info("Test (step 25): verify IPv6 RIB")
1058 tgen = get_topogen()
1059
1060 # Skip if previous fatal error condition is raised
1061 if tgen.routers_have_failure():
1062 pytest.skip(tgen.errors)
1063
1064 logger.info("Check SPF convergence")
1065
1066 for rname in ["rt1"]:
1067 router_compare_json_output(
1068 rname,
1069 "show ipv6 route isis json",
1070 outputs[rname][16]["show_ipv6_route.ref"],
1071 )
1072
1073
1074 # Memory leak test template
1075 def test_memory_leak():
1076 "Run the memory leak test and report results."
1077 tgen = get_topogen()
1078 if not tgen.is_memleak_enabled():
1079 pytest.skip("Memory leak test/report is disabled")
1080
1081 tgen.report_memory_leaks()
1082
1083
1084 if __name__ == "__main__":
1085 args = ["-s"] + sys.argv[1:]
1086 sys.exit(pytest.main(args))