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