2 # SPDX-License-Identifier: ISC
5 # test_all_protocol_startup.py
6 # Part of NetDEF Topology Tests
8 # Copyright (c) 2017 by
9 # Network Device Education Foundation, Inc. ("NetDEF")
13 test_all_protocol_startup.py: Test of all protocols at same time
22 from time
import sleep
34 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
35 from lib
import topotest
36 from lib
.topogen
import Topogen
, get_topogen
37 from lib
.common_config
import (
38 required_linux_kernel_version
,
44 #####################################################
46 ## Network Topology Definition
48 #####################################################
52 router
= tgen
.add_router("r1")
53 for i
in range(0, 10):
54 tgen
.add_switch("sw%d" % i
).add_link(router
)
57 #####################################################
61 #####################################################
64 def setup_module(module
):
67 print("\n\n** %s: Setup Topology" % module
.__name
__)
68 print("******************************************\n")
70 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
71 tgen
= Topogen(build_topo
, module
.__name
__)
76 if net
["r1"].get_routertype() != "frr":
77 fatal_error
= "Test is only implemented for FRR"
78 sys
.stderr
.write("\n\nTest is only implemented for FRR - Skipping\n\n")
79 pytest
.skip(fatal_error
)
85 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
86 net
["r%s" % i
].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir
, i
))
87 net
["r%s" % i
].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir
, i
))
88 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
89 if net
["r1"].checkRouterVersion("<", "4.0"):
90 net
["r%s" % i
].loadConf(
91 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir
, i
)
94 net
["r%s" % i
].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir
, i
))
95 net
["r%s" % i
].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir
, i
))
96 net
["r%s" % i
].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir
, i
))
97 if net
["r%s" % i
].daemon_available("ldpd"):
98 # Only test LDPd if it's installed and Kernel >= 4.5
99 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
100 net
["r%s" % i
].loadConf("sharpd")
101 net
["r%s" % i
].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir
, i
))
102 net
["r%s" % i
].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir
, i
))
103 net
["r%s" % i
].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir
, i
))
104 tgen
.gears
["r%s" % i
].start()
106 # For debugging after starting FRR daemons, uncomment the next line
110 def teardown_module(module
):
111 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
112 print("******************************************\n")
117 def test_router_running():
122 # Skip if previous fatal error condition is raised
123 if fatal_error
!= "":
124 pytest
.skip(fatal_error
)
126 print("\n\n** Check if FRR is running on each Router node")
127 print("******************************************\n")
131 for i
in range(1, 2):
132 fatal_error
= net
["r%s" % i
].checkRouterRunning()
133 assert fatal_error
== "", fatal_error
135 # For debugging after starting FRR daemons, uncomment the next line
139 def test_error_messages_vtysh():
141 net
= get_topogen().net
143 # Skip if previous fatal error condition is raised
144 if fatal_error
!= "":
145 pytest
.skip(fatal_error
)
147 print("\n\n** Check for error messages on VTYSH")
148 print("******************************************\n")
151 for i
in range(1, 2):
153 # First checking Standard Output
156 # VTYSH output from router
157 vtystdout
= net
["r%s" % i
].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
159 # Fix newlines (make them all the same)
160 vtystdout
= ("\n".join(vtystdout
.splitlines()) + "\n").rstrip()
161 # Drop everything starting with "FRRouting X.xx" message
162 vtystdout
= re
.sub(r
"FRRouting [0-9]+.*", "", vtystdout
, flags
=re
.DOTALL
)
165 print("r%s StdOut ok" % i
)
167 assert vtystdout
== "", "Vtysh StdOut Output check failed for router r%s" % i
170 # Second checking Standard Error
173 # VTYSH StdErr output from router
174 vtystderr
= net
["r%s" % i
].cmd('vtysh -c "show version" > /dev/null').rstrip()
176 # Fix newlines (make them all the same)
177 vtystderr
= ("\n".join(vtystderr
.splitlines()) + "\n").rstrip()
178 # # Drop everything starting with "FRRouting X.xx" message
179 # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
182 print("r%s StdErr ok" % i
)
184 assert vtystderr
== "", "Vtysh StdErr Output check failed for router r%s" % i
186 # Make sure that all daemons are running
187 for i
in range(1, 2):
188 fatal_error
= net
["r%s" % i
].checkRouterRunning()
189 assert fatal_error
== "", fatal_error
192 def test_error_messages_daemons():
194 net
= get_topogen().net
196 # Skip if previous fatal error condition is raised
197 if fatal_error
!= "":
198 pytest
.skip(fatal_error
)
200 print("\n\n** Check for error messages in daemons")
201 print("******************************************\n")
205 for i
in range(1, 2):
206 log
= net
["r%s" % i
].getStdErr("ripd")
208 error_logs
+= "r%s RIPd StdErr Output:\n" % i
210 log
= net
["r%s" % i
].getStdErr("ripngd")
212 error_logs
+= "r%s RIPngd StdErr Output:\n" % i
214 log
= net
["r%s" % i
].getStdErr("ospfd")
216 error_logs
+= "r%s OSPFd StdErr Output:\n" % i
218 log
= net
["r%s" % i
].getStdErr("ospf6d")
220 error_logs
+= "r%s OSPF6d StdErr Output:\n" % i
222 log
= net
["r%s" % i
].getStdErr("isisd")
223 # ISIS shows debugging enabled status on StdErr
224 # Remove these messages
225 log
= re
.sub(r
"^IS-IS .* debugging is on.*", "", log
).rstrip()
227 error_logs
+= "r%s ISISd StdErr Output:\n" % i
229 log
= net
["r%s" % i
].getStdErr("bgpd")
231 error_logs
+= "r%s BGPd StdErr Output:\n" % i
233 if net
["r%s" % i
].daemon_available("ldpd"):
234 log
= net
["r%s" % i
].getStdErr("ldpd")
236 error_logs
+= "r%s LDPd StdErr Output:\n" % i
239 log
= net
["r1"].getStdErr("nhrpd")
240 # NHRPD shows YANG model not embedded messages
242 log
= re
.sub(r
".*YANG model.*not embedded.*", "", log
).rstrip()
244 error_logs
+= "r%s NHRPd StdErr Output:\n" % i
247 log
= net
["r1"].getStdErr("babeld")
249 error_logs
+= "r%s BABELd StdErr Output:\n" % i
252 log
= net
["r1"].getStdErr("pbrd")
254 error_logs
+= "r%s PBRd StdErr Output:\n" % i
257 log
= net
["r%s" % i
].getStdErr("zebra")
259 error_logs
+= "r%s Zebra StdErr Output:\n" % i
264 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
267 # Ignoring the issue if told to ignore (ie not yet fixed)
269 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
271 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
274 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
277 assert error_logs
== "", "Daemons report errors to StdErr"
280 def test_converge_protocols():
282 net
= get_topogen().net
284 # Skip if previous fatal error condition is raised
285 if fatal_error
!= "":
286 pytest
.skip(fatal_error
)
288 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
290 print("\n\n** Waiting for protocols convergence")
291 print("******************************************\n")
293 # Not really implemented yet - just sleep 60 secs for now
296 # Make sure that all daemons are running
298 for i
in range(1, 2):
299 fatal_error
= net
["r%s" % i
].checkRouterRunning()
300 assert fatal_error
== "", fatal_error
302 print("Show that v4 routes are right\n")
303 v4_routesFile
= "%s/r%s/ipv4_routes.ref" % (thisDir
, i
)
305 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v4_routesFile
)).rstrip()
307 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
312 "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
316 # Drop time in last update
317 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
318 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
319 diff
= topotest
.get_textdiff(
322 title1
="Actual IP Routing Table",
323 title2
="Expected IP RoutingTable",
326 sys
.stderr
.write("r%s failed IP Routing table check:\n%s\n" % (i
, diff
))
331 assert failures
== 0, "IP Routing table failed for r%s\n%s" % (i
, diff
)
335 print("Show that v6 routes are right\n")
336 v6_routesFile
= "%s/r%s/ipv6_routes.ref" % (thisDir
, i
)
338 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v6_routesFile
)).rstrip()
340 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
345 "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
349 # Drop time in last update
350 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
351 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
352 diff
= topotest
.get_textdiff(
355 title1
="Actual IPv6 Routing Table",
356 title2
="Expected IPv6 RoutingTable",
359 sys
.stderr
.write("r%s failed IPv6 Routing table check:\n%s\n" % (i
, diff
))
364 assert failures
== 0, "IPv6 Routing table failed for r%s\n%s" % (i
, diff
)
367 def route_get_nhg_id(route_str
):
368 net
= get_topogen().net
369 output
= net
["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str
)
370 match
= re
.search(r
"Nexthop Group ID: (\d+)", output
)
371 assert match
is not None, (
372 "Nexthop Group ID not found for sharpd route %s" % route_str
375 nhg_id
= int(match
.group(1))
379 def verify_nexthop_group(nhg_id
, recursive
=False, ecmp
=0):
380 net
= get_topogen().net
389 while not found
and count
< 10:
391 # Verify NHG is valid/installed
392 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
393 valid
= re
.search(r
"Valid", output
)
399 if ecmp
or recursive
:
400 ecmpcount
= re
.search(r
"Depends:.*\n", output
)
401 if ecmpcount
is None:
406 # list of IDs in group
407 depends
= re
.findall(r
"\((\d+)\)", ecmpcount
.group(0))
410 if len(depends
) != ecmp
:
415 # If recursive, we need to look at its resolved group
416 if len(depends
) != 1:
421 resolved_id
= int(depends
[0])
422 verify_nexthop_group(resolved_id
, False)
424 installed
= re
.search(r
"Installed", output
)
425 if installed
is None:
431 assert valid
is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
432 if ecmp
or recursive
:
433 assert ecmpcount
is not None, "Nexthop Group ID=%d has no depends" % nhg_id
435 assert len(depends
) == ecmp
, (
436 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
439 assert len(depends
) == 1, (
440 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
443 assert installed
is not None, (
444 "Nexthop Group ID=%d not marked Installed" % nhg_id
448 def verify_route_nexthop_group(route_str
, recursive
=False, ecmp
=0):
449 # Verify route and that zebra created NHGs for and they are valid/installed
450 nhg_id
= route_get_nhg_id(route_str
)
451 verify_nexthop_group(nhg_id
, recursive
, ecmp
)
454 def test_nexthop_groups():
456 net
= get_topogen().net
458 # Skip if previous fatal error condition is raised
459 if fatal_error
!= "":
460 pytest
.skip(fatal_error
)
462 print("\n\n** Verifying Nexthop Groups")
463 print("******************************************\n")
465 ### Nexthop Group Tests
469 # Create a lib nexthop-group
471 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
474 # Create with sharpd using nexthop-group
475 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
476 verify_route_nexthop_group("2.2.2.1/32")
481 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
484 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
485 verify_route_nexthop_group("2.2.2.2/32")
490 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
494 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
497 verify_route_nexthop_group("3.3.3.1/32", True)
502 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
505 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
507 verify_route_nexthop_group("3.3.3.2/32")
512 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
513 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
516 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
518 verify_route_nexthop_group("4.4.4.1/32")
521 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
522 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
525 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
527 verify_route_nexthop_group("4.4.4.2/32")
529 ## Recursive to 8-Way ECMP
532 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
536 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
539 verify_route_nexthop_group("5.5.5.1/32")
541 ## 4-way ECMP Routes Pointing to Each Other
543 # This is to check for a bug with NH resolution where
544 # routes would infintely resolve to each other blowing
545 # up the resolved-> nexthop pointer.
548 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
549 -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
552 # static route nexthops can recurse to
554 net
["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
556 # Make routes that point to themselves in ecmp
559 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
564 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
569 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
574 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
577 # Get routes and test if has too many (duplicate) nexthops
580 nhg_id
= route_get_nhg_id("6.6.6.1/32")
581 while (len(dups
) != 3) and count
< 10:
582 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
584 dups
= re
.findall(r
"(via 1\.1\.1\.1)", output
)
589 # Should find 3, itself is inactive
590 assert len(dups
) == 3, (
591 "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
595 ## Remove all NHG routes
597 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
598 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
599 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
600 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
601 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
602 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
603 net
["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
604 net
["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
605 net
["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
608 def test_rip_status():
610 net
= get_topogen().net
612 # Skip if previous fatal error condition is raised
613 if fatal_error
!= "":
614 pytest
.skip(fatal_error
)
616 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
618 print("\n\n** Verifying RIP status")
619 print("******************************************\n")
621 for i
in range(1, 2):
622 refTableFile
= "%s/r%s/rip_status.ref" % (thisDir
, i
)
623 if os
.path
.isfile(refTableFile
):
624 # Read expected result from file
625 expected
= open(refTableFile
).read().rstrip()
626 # Fix newlines (make them all the same)
627 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
629 # Actual output from router
632 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
635 # Drop time in next due
636 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
637 # Drop time in last update
638 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
639 # Fix newlines (make them all the same)
640 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
643 diff
= topotest
.get_textdiff(
646 title1
="actual IP RIP status",
647 title2
="expected IP RIP status",
650 # Empty string if it matches, otherwise diff contains unified diff
652 sys
.stderr
.write("r%s failed IP RIP status check:\n%s\n" % (i
, diff
))
657 assert failures
== 0, "IP RIP status failed for router r%s:\n%s" % (i
, diff
)
659 # Make sure that all daemons are running
660 for i
in range(1, 2):
661 fatal_error
= net
["r%s" % i
].checkRouterRunning()
662 assert fatal_error
== "", fatal_error
665 def test_ripng_status():
667 net
= get_topogen().net
669 # Skip if previous fatal error condition is raised
670 if fatal_error
!= "":
671 pytest
.skip(fatal_error
)
673 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
675 print("\n\n** Verifying RIPng status")
676 print("******************************************\n")
678 for i
in range(1, 2):
679 refTableFile
= "%s/r%s/ripng_status.ref" % (thisDir
, i
)
680 if os
.path
.isfile(refTableFile
):
681 # Read expected result from file
682 expected
= open(refTableFile
).read().rstrip()
683 # Fix newlines (make them all the same)
684 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
686 # Actual output from router
689 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
692 # Mask out Link-Local mac address portion. They are random...
693 actual
= re
.sub(r
" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual
)
694 # Drop time in next due
695 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
696 # Drop time in last update
697 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
698 # Fix newlines (make them all the same)
699 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
702 diff
= topotest
.get_textdiff(
705 title1
="actual IPv6 RIPng status",
706 title2
="expected IPv6 RIPng status",
709 # Empty string if it matches, otherwise diff contains unified diff
712 "r%s failed IPv6 RIPng status check:\n%s\n" % (i
, diff
)
718 assert failures
== 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
723 # Make sure that all daemons are running
724 for i
in range(1, 2):
725 fatal_error
= net
["r%s" % i
].checkRouterRunning()
726 assert fatal_error
== "", fatal_error
729 def test_ospfv2_interfaces():
731 net
= get_topogen().net
733 # Skip if previous fatal error condition is raised
734 if fatal_error
!= "":
735 pytest
.skip(fatal_error
)
737 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
739 print("\n\n** Verifying OSPFv2 interfaces")
740 print("******************************************\n")
742 for i
in range(1, 2):
743 refTableFile
= "%s/r%s/show_ip_ospf_interface.ref" % (thisDir
, i
)
744 if os
.path
.isfile(refTableFile
):
745 # Read expected result from file
746 expected
= open(refTableFile
).read().rstrip()
747 # Fix newlines (make them all the same)
748 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
750 # Actual output from router
753 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
756 # Mask out Bandwidth portion. They may change..
757 actual
= re
.sub(r
"BW [0-9]+ Mbit", "BW XX Mbit", actual
)
758 actual
= re
.sub(r
"ifindex [0-9]+", "ifindex X", actual
)
760 # Drop time in next due
761 actual
= re
.sub(r
"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual
)
763 r
"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
765 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
767 r
"MTU mismatch detection:([a-z]+.*)",
768 r
"MTU mismatch detection: \1",
771 # Fix newlines (make them all the same)
772 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
775 diff
= topotest
.get_textdiff(
778 title1
="actual SHOW IP OSPF INTERFACE",
779 title2
="expected SHOW IP OSPF INTERFACE",
782 # Empty string if it matches, otherwise diff contains unified diff
785 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i
, diff
)
791 # Ignoring the issue if told to ignore (ie not yet fixed)
793 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
795 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
798 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
803 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i
, diff
)
805 # Make sure that all daemons are running
806 for i
in range(1, 2):
807 fatal_error
= net
["r%s" % i
].checkRouterRunning()
808 assert fatal_error
== "", fatal_error
811 def test_isis_interfaces():
813 net
= get_topogen().net
815 # Skip if previous fatal error condition is raised
816 if fatal_error
!= "":
817 pytest
.skip(fatal_error
)
819 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
821 print("\n\n** Verifying ISIS interfaces")
822 print("******************************************\n")
824 for i
in range(1, 2):
825 refTableFile
= "%s/r%s/show_isis_interface_detail.ref" % (thisDir
, i
)
826 if os
.path
.isfile(refTableFile
):
827 # Read expected result from file
828 expected
= open(refTableFile
).read().rstrip()
829 # Fix newlines (make them all the same)
830 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
832 # Actual output from router
835 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
838 # Mask out Link-Local mac address portion. They are random...
839 actual
= re
.sub(r
"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual
)
840 # Mask out SNPA mac address portion. They are random...
841 actual
= re
.sub(r
"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual
)
842 # Mask out Circuit ID number
843 actual
= re
.sub(r
"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual
)
844 # Fix newlines (make them all the same)
845 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
848 diff
= topotest
.get_textdiff(
851 title1
="actual SHOW ISIS INTERFACE DETAIL",
852 title2
="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
855 # Empty string if it matches, otherwise diff contains unified diff
858 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i
, diff
)
866 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i
, diff
)
868 # Make sure that all daemons are running
869 for i
in range(1, 2):
870 fatal_error
= net
["r%s" % i
].checkRouterRunning()
871 assert fatal_error
== "", fatal_error
874 def test_bgp_summary():
876 net
= get_topogen().net
878 # Skip if previous fatal error condition is raised
879 if fatal_error
!= "":
880 pytest
.skip(fatal_error
)
882 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
884 print("\n\n** Verifying BGP Summary")
885 print("******************************************\n")
887 for i
in range(1, 2):
888 refTableFile
= "%s/r%s/show_ip_bgp_summary.ref" % (thisDir
, i
)
889 if os
.path
.isfile(refTableFile
):
890 # Read expected result from file
891 expected_original
= open(refTableFile
).read().rstrip()
895 "remote-as internal",
896 "remote-as external",
899 "neighbor 192.168.7.10",
900 "neighbor 192.168.7.10",
901 "neighbor fc00:0:0:8::1000",
904 "remote-as internal terse",
905 "remote-as external terse",
906 "remote-as 100 terse",
907 "remote-as 123 terse",
908 "neighbor 192.168.7.10 terse",
909 "neighbor 192.168.7.10 terse",
910 "neighbor fc00:0:0:8::1000 terse",
911 "neighbor 10.0.0.1 terse",
913 # Actual output from router
917 'vtysh -c "show ip bgp summary ' + arguments
+ '" 2> /dev/null'
922 # Mask out "using XXiXX bytes" portion. They are random...
923 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
924 # Mask out "using XiXXX KiB" portion. They are random...
925 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
927 # Remove extra summaries which exist with newer versions
929 # Remove summary lines (changed recently)
930 actual
= re
.sub(r
"Total number.*", "", actual
)
931 actual
= re
.sub(r
"Displayed.*", "", actual
)
932 # Remove IPv4 Unicast Summary (Title only)
933 actual
= re
.sub(r
"IPv4 Unicast Summary \(VRF default\):", "", actual
)
934 # Remove IPv4 Multicast Summary (all of it)
935 actual
= re
.sub(r
"IPv4 Multicast Summary \(VRF default\):", "", actual
)
936 actual
= re
.sub(r
"No IPv4 Multicast neighbor is configured", "", actual
)
937 # Remove IPv4 VPN Summary (all of it)
938 actual
= re
.sub(r
"IPv4 VPN Summary \(VRF default\):", "", actual
)
939 actual
= re
.sub(r
"No IPv4 VPN neighbor is configured", "", actual
)
940 # Remove IPv4 Encap Summary (all of it)
941 actual
= re
.sub(r
"IPv4 Encap Summary \(VRF default\):", "", actual
)
942 actual
= re
.sub(r
"No IPv4 Encap neighbor is configured", "", actual
)
943 # Remove Unknown Summary (all of it)
944 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
945 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
946 # Make Connect/Active/Idle the same (change them all to Active)
947 actual
= re
.sub(r
" Connect ", " Active ", actual
)
948 actual
= re
.sub(r
" Idle ", " Active ", actual
)
951 r
"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
954 r
"No IPv4 labeled-unicast neighbor is configured", "", actual
957 expected
= expected_original
958 # apply argumentss on expected output
959 if "internal" in arguments
or "remote-as 100" in arguments
:
960 expected
= re
.sub(r
".+\s+200\s+.+", "", expected
)
961 elif "external" in arguments
:
962 expected
= re
.sub(r
".+\s+100\s+.+Active.+", "", expected
)
963 elif "remote-as 123" in arguments
:
965 r
"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
969 expected
= re
.sub(r
"\nNeighbor.+Desc", "", expected
)
970 expected
= expected
+ "% No matching neighbor\n"
971 elif "192.168.7.10" in arguments
:
973 r
"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
975 elif "fc00:0:0:8::1000" in arguments
:
977 r
"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
979 elif "10.0.0.1" in arguments
:
980 expected
= "No such neighbor in this view/vrf"
982 if "terse" in arguments
:
983 expected
= re
.sub(r
"BGP table version .+", "", expected
)
984 expected
= re
.sub(r
"RIB entries .+", "", expected
)
985 expected
= re
.sub(r
"Peers [0-9]+, using .+", "", expected
)
988 actual
= actual
.lstrip().rstrip()
989 expected
= expected
.lstrip().rstrip()
990 actual
= re
.sub(r
"\n+", "\n", actual
)
991 expected
= re
.sub(r
"\n+", "\n", expected
)
993 # reapply initial formatting
994 if "terse" in arguments
:
995 actual
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", actual
)
996 expected
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", expected
)
998 actual
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", actual
)
999 expected
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", expected
)
1001 # realign expected neighbor columns if needed
1004 re
.search(r
"(Neighbor\s+V\s+)", actual
).group(1).find("V")
1007 re
.search(r
"(Neighbor\s+V\s+)", expected
).group(1).find("V")
1009 idx_diff
= idx_expected
- idx_actual
1011 # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
1012 expected
= re
.sub(" " * idx_diff
+ "V ", "V ", expected
)
1013 # 192.168.7.10 4 100 0 0 0 0 0 never Active
1014 expected
= re
.sub(" " * idx_diff
+ "4 ", "4 ", expected
)
1015 except AttributeError:
1018 # Fix newlines (make them all the same)
1019 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1020 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1023 diff
= topotest
.get_textdiff(
1026 title1
="actual SHOW IP BGP SUMMARY " + arguments
.upper(),
1027 title2
="expected SHOW IP BGP SUMMARY " + arguments
.upper(),
1030 # Empty string if it matches, otherwise diff contains unified diff
1033 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i
, diff
)
1041 ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
1046 # Make sure that all daemons are running
1047 for i
in range(1, 2):
1048 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1049 assert fatal_error
== "", fatal_error
1052 def test_bgp_ipv6_summary():
1054 net
= get_topogen().net
1056 # Skip if previous fatal error condition is raised
1057 if fatal_error
!= "":
1058 pytest
.skip(fatal_error
)
1060 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1062 print("\n\n** Verifying BGP IPv6 Summary")
1063 print("******************************************\n")
1065 for i
in range(1, 2):
1066 refTableFile
= "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir
, i
)
1067 if os
.path
.isfile(refTableFile
):
1068 # Read expected result from file
1069 expected
= open(refTableFile
).read().rstrip()
1070 # Fix newlines (make them all the same)
1071 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1073 # Actual output from router
1076 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
1079 # Mask out "using XXiXX bytes" portion. They are random...
1080 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
1081 # Mask out "using XiXXX KiB" portion. They are random...
1082 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
1084 # Remove extra summaries which exist with newer versions
1086 # Remove summary lines (changed recently)
1087 actual
= re
.sub(r
"Total number.*", "", actual
)
1088 actual
= re
.sub(r
"Displayed.*", "", actual
)
1089 # Remove IPv4 Unicast Summary (Title only)
1090 actual
= re
.sub(r
"IPv6 Unicast Summary \(VRF default\):", "", actual
)
1091 # Remove IPv4 Multicast Summary (all of it)
1092 actual
= re
.sub(r
"IPv6 Multicast Summary \(VRF default\):", "", actual
)
1093 actual
= re
.sub(r
"No IPv6 Multicast neighbor is configured", "", actual
)
1094 # Remove IPv4 VPN Summary (all of it)
1095 actual
= re
.sub(r
"IPv6 VPN Summary \(VRF default\):", "", actual
)
1096 actual
= re
.sub(r
"No IPv6 VPN neighbor is configured", "", actual
)
1097 # Remove IPv4 Encap Summary (all of it)
1098 actual
= re
.sub(r
"IPv6 Encap Summary \(VRF default\):", "", actual
)
1099 actual
= re
.sub(r
"No IPv6 Encap neighbor is configured", "", actual
)
1100 # Remove Unknown Summary (all of it)
1101 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
1102 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
1103 # Make Connect/Active/Idle the same (change them all to Active)
1104 actual
= re
.sub(r
" Connect ", " Active ", actual
)
1105 actual
= re
.sub(r
" Idle ", " Active ", actual
)
1107 # Remove Labeled Unicast Summary (all of it)
1109 r
"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
1112 r
"No IPv6 labeled-unicast neighbor is configured", "", actual
1116 actual
= actual
.lstrip()
1117 actual
= actual
.rstrip()
1119 # Fix newlines (make them all the same)
1120 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1123 diff
= topotest
.get_textdiff(
1126 title1
="actual SHOW BGP IPv6 SUMMARY",
1127 title2
="expected SHOW BGP IPv6 SUMMARY",
1130 # Empty string if it matches, otherwise diff contains unified diff
1133 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i
, diff
)
1139 assert failures
== 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1144 # Make sure that all daemons are running
1145 for i
in range(1, 2):
1146 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1147 assert fatal_error
== "", fatal_error
1152 net
= get_topogen().net
1154 # Skip if previous fatal error condition is raised
1155 if fatal_error
!= "":
1156 pytest
.skip(fatal_error
)
1158 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1160 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1162 for i
in range(1, 2):
1163 nhtFile
= "%s/r%s/ip_nht.ref" % (thisDir
, i
)
1164 expected
= open(nhtFile
).read().rstrip()
1165 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1167 actual
= net
["r%s" % i
].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
1168 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1169 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1171 diff
= topotest
.get_textdiff(
1174 title1
="Actual `show ip nht`",
1175 title2
="Expected `show ip nht`",
1179 assert 0, "r%s failed ip nht check:\n%s\n" % (i
, diff
)
1181 print("show ip nht is ok\n")
1183 nhtFile
= "%s/r%s/ipv6_nht.ref" % (thisDir
, i
)
1184 expected
= open(nhtFile
).read().rstrip()
1185 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1187 actual
= net
["r%s" % i
].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
1188 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1189 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1191 diff
= topotest
.get_textdiff(
1194 title1
="Actual `show ip nht`",
1195 title2
="Expected `show ip nht`",
1199 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i
, diff
)
1201 print("show ipv6 nht is ok\n")
1204 def test_bgp_ipv4():
1206 net
= get_topogen().net
1208 # Skip if previous fatal error condition is raised
1209 if fatal_error
!= "":
1210 pytest
.skip(fatal_error
)
1212 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1214 print("\n\n** Verifying BGP IPv4")
1215 print("******************************************\n")
1217 for i
in range(1, 2):
1219 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir
, i
)):
1220 if os
.path
.isfile(refTableFile
):
1221 # Read expected result from file
1222 expected
= open(refTableFile
).read().rstrip()
1223 # Fix newlines (make them all the same)
1224 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1226 # Actual output from router
1228 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1230 # Remove summary line (changed recently)
1231 actual
= re
.sub(r
"Total number.*", "", actual
)
1232 actual
= re
.sub(r
"Displayed.*", "", actual
)
1233 actual
= actual
.rstrip()
1234 # Fix newlines (make them all the same)
1235 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1238 diff
= topotest
.get_textdiff(
1241 title1
="actual SHOW BGP IPv4",
1242 title2
="expected SHOW BGP IPv4",
1245 # Empty string if it matches, otherwise diff contains unified diff
1247 diffresult
[refTableFile
] = diff
1250 print("template %s matched: r%s ok" % (refTableFile
, i
))
1254 resultstr
= "No template matched.\n"
1255 for f
in diffresult
.keys():
1256 resultstr
+= "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1261 raise AssertionError(
1262 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i
, resultstr
)
1265 # Make sure that all daemons are running
1266 for i
in range(1, 2):
1267 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1268 assert fatal_error
== "", fatal_error
1271 def test_bgp_ipv6():
1273 net
= get_topogen().net
1275 # Skip if previous fatal error condition is raised
1276 if fatal_error
!= "":
1277 pytest
.skip(fatal_error
)
1279 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1281 print("\n\n** Verifying BGP IPv6")
1282 print("******************************************\n")
1284 for i
in range(1, 2):
1286 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir
, i
)):
1287 if os
.path
.isfile(refTableFile
):
1288 # Read expected result from file
1289 expected
= open(refTableFile
).read().rstrip()
1290 # Fix newlines (make them all the same)
1291 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1293 # Actual output from router
1295 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1297 # Remove summary line (changed recently)
1298 actual
= re
.sub(r
"Total number.*", "", actual
)
1299 actual
= re
.sub(r
"Displayed.*", "", actual
)
1300 actual
= actual
.rstrip()
1301 # Fix newlines (make them all the same)
1302 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1305 diff
= topotest
.get_textdiff(
1308 title1
="actual SHOW BGP IPv6",
1309 title2
="expected SHOW BGP IPv6",
1312 # Empty string if it matches, otherwise diff contains unified diff
1314 diffresult
[refTableFile
] = diff
1317 print("template %s matched: r%s ok" % (refTableFile
, i
))
1320 resultstr
= "No template matched.\n"
1321 for f
in diffresult
.keys():
1322 resultstr
+= "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1327 raise AssertionError(
1328 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i
, resultstr
)
1331 # Make sure that all daemons are running
1332 for i
in range(1, 2):
1333 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1334 assert fatal_error
== "", fatal_error
1337 def test_route_map():
1339 net
= get_topogen().net
1341 if fatal_error
!= "":
1342 pytest
.skip(fatal_error
)
1344 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1346 print("\n\n** Verifying some basic routemap forward references\n")
1347 print("*******************************************************\n")
1349 for i
in range(1, 2):
1350 refroutemap
= "%s/r%s/show_route_map.ref" % (thisDir
, i
)
1351 if os
.path
.isfile(refroutemap
):
1352 expected
= open(refroutemap
).read().rstrip()
1353 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1356 net
["r%s" % i
].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1358 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1360 diff
= topotest
.get_textdiff(
1363 title1
="actual show route-map",
1364 title2
="expected show route-map",
1369 "r%s failed show route-map command Check:\n%s\n" % (i
, diff
)
1377 ), "Show route-map command failed for router r%s:\n%s" % (i
, diff
)
1380 def test_nexthop_groups_with_route_maps():
1382 net
= get_topogen().net
1384 # Skip if previous fatal error condition is raised
1385 if fatal_error
!= "":
1386 pytest
.skip(fatal_error
)
1388 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1389 print("******************************************\n")
1391 ### Nexthop Group With Route-Map Tests
1393 # Create a lib nexthop-group
1395 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1398 ## Route-Map Proto Source
1400 route_str
= "2.2.2.1"
1401 src_str
= "192.168.0.1"
1404 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1406 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1408 net
["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str
)
1410 verify_route_nexthop_group("%s/32" % route_str
)
1412 # Only a valid test on linux using nexthop objects
1413 if sys
.platform
.startswith("linux"):
1414 output
= net
["r1"].cmd("ip route show %s/32" % route_str
)
1415 match
= re
.search(r
"src %s" % src_str
, output
)
1416 assert match
is not None, "Route %s/32 not installed with src %s" % (
1421 # Remove NHG routes and route-map
1422 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str
)
1423 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
1425 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
1427 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1429 ## Route-Map Deny/Permit with same nexthop group
1431 permit_route_str
= "3.3.3.1"
1432 deny_route_str
= "3.3.3.2"
1435 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1438 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1440 net
["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1441 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1443 # This route should be permitted
1445 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1448 verify_route_nexthop_group("%s/32" % permit_route_str
)
1450 # This route should be denied
1452 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1455 nhg_id
= route_get_nhg_id(deny_route_str
)
1456 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
1458 match
= re
.search(r
"Valid", output
)
1459 assert match
is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1461 match
= re
.search(r
"Installed", output
)
1462 assert match
is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1464 # Remove NHG routes and route-map
1465 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str
)
1466 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str
)
1467 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1468 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1469 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1470 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
1472 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1477 def test_nexthop_group_replace():
1479 net
= get_topogen().net
1481 # Skip if previous fatal error condition is raised
1482 if fatal_error
!= "":
1483 pytest
.skip(fatal_error
)
1485 print("\n\n** Verifying Nexthop Groups")
1486 print("******************************************\n")
1488 ### Nexthop Group Tests
1490 ## 2-Way ECMP Directly Connected
1493 'vtysh -c "c t" -c "nexthop-group replace" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"'
1496 # At the moment there is absolutely no real easy way to query sharpd
1497 # for the nexthop group actually installed. If it is not installed
1498 # sharpd will just transmit the nexthops down instead of the nexthop
1499 # group id. Leading to a situation where the replace is not actually
1500 # being tested. So let's just wait some time here because this
1501 # is hard and this test fails all the time
1504 # Create with sharpd using nexthop-group
1505 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1507 verify_route_nexthop_group("3.3.3.1/32")
1509 # Change the nexthop group
1511 'vtysh -c "c t" -c "nexthop-group replace" -c "no nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.3 r1-eth1 onlink" -c "nexthop 1.1.1.4 r1-eth4 onlink"'
1514 # Verify it updated. We can just check install and ecmp count here.
1515 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1518 def test_mpls_interfaces():
1520 net
= get_topogen().net
1522 # Skip if previous fatal error condition is raised
1523 if fatal_error
!= "":
1524 pytest
.skip(fatal_error
)
1526 # Skip if no LDP installed or old kernel
1527 if net
["r1"].daemon_available("ldpd") == False:
1528 pytest
.skip("No MPLS or kernel < 4.5")
1530 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1532 print("\n\n** Verifying MPLS Interfaces")
1533 print("******************************************\n")
1535 for i
in range(1, 2):
1536 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir
, i
)
1537 if os
.path
.isfile(refTableFile
):
1538 # Read expected result from file
1539 expected
= open(refTableFile
).read().rstrip()
1540 # Fix newlines (make them all the same)
1541 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1543 # Actual output from router
1546 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1549 # Mask out Timer in Uptime
1550 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
1551 # Fix newlines (make them all the same)
1552 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1555 diff
= topotest
.get_textdiff(
1558 title1
="actual MPLS LDP interface status",
1559 title2
="expected MPLS LDP interface status",
1562 # Empty string if it matches, otherwise diff contains unified diff
1565 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
1572 fatal_error
= "MPLS LDP Interface status failed"
1576 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
1578 # Make sure that all daemons are running
1579 for i
in range(1, 2):
1580 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1581 assert fatal_error
== "", fatal_error
1584 def test_resilient_nexthop_group():
1585 net
= get_topogen().net
1587 result
= required_linux_kernel_version("5.19")
1588 if result
is not True:
1589 pytest
.skip("Kernel requirements are not met, kernel version should be >= 5.19")
1592 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"'
1595 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib sharp"')
1596 output
= re
.findall(r
"Buckets", output
)
1598 verify_nexthop_group(185483878)
1599 assert len(output
) == 1, "Resilient NHG not created in zebra"
1602 def test_shutdown_check_stderr():
1604 net
= get_topogen().net
1606 # Skip if previous fatal error condition is raised
1607 if fatal_error
!= "":
1608 pytest
.skip(fatal_error
)
1610 print("\n\n** Verifying unexpected STDERR output from daemons")
1611 print("******************************************\n")
1613 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
1615 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1617 pytest
.skip("Skipping test for Stderr output")
1619 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1621 print("thisDir=" + thisDir
)
1623 net
["r1"].stopRouter()
1625 log
= net
["r1"].getStdErr("ripd")
1627 print("\nRIPd StdErr Log:\n" + log
)
1628 log
= net
["r1"].getStdErr("ripngd")
1630 print("\nRIPngd StdErr Log:\n" + log
)
1631 log
= net
["r1"].getStdErr("ospfd")
1633 print("\nOSPFd StdErr Log:\n" + log
)
1634 log
= net
["r1"].getStdErr("ospf6d")
1636 print("\nOSPF6d StdErr Log:\n" + log
)
1637 log
= net
["r1"].getStdErr("isisd")
1639 print("\nISISd StdErr Log:\n" + log
)
1640 log
= net
["r1"].getStdErr("bgpd")
1642 print("\nBGPd StdErr Log:\n" + log
)
1644 log
= net
["r1"].getStdErr("nhrpd")
1646 print("\nNHRPd StdErr Log:\n" + log
)
1648 log
= net
["r1"].getStdErr("pbrd")
1650 print("\nPBRd StdErr Log:\n" + log
)
1652 log
= net
["r1"].getStdErr("babeld")
1654 print("\nBABELd StdErr Log:\n" + log
)
1656 if net
["r1"].daemon_available("ldpd"):
1657 log
= net
["r1"].getStdErr("ldpd")
1659 print("\nLDPd StdErr Log:\n" + log
)
1660 log
= net
["r1"].getStdErr("zebra")
1662 print("\nZebra StdErr Log:\n" + log
)
1665 def test_shutdown_check_memleak():
1667 net
= get_topogen().net
1669 # Skip if previous fatal error condition is raised
1670 if fatal_error
!= "":
1671 pytest
.skip(fatal_error
)
1673 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1675 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1677 pytest
.skip("Skipping test for memory leaks")
1679 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1681 for i
in range(1, 2):
1682 net
["r%s" % i
].stopRouter()
1683 net
["r%s" % i
].report_memory_leaks(
1684 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
1688 if __name__
== "__main__":
1689 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1690 # retval = pytest.main(["-s", "--tb=no"])
1691 retval
= pytest
.main(["-s"])