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("mgmtd", "%s/r%s/zebra.conf" % (thisDir
, i
))
86 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
87 net
["r%s" % i
].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir
, i
))
88 net
["r%s" % i
].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir
, i
))
89 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
90 if net
["r1"].checkRouterVersion("<", "4.0"):
91 net
["r%s" % i
].loadConf(
92 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir
, i
)
95 net
["r%s" % i
].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir
, i
))
96 net
["r%s" % i
].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir
, i
))
97 net
["r%s" % i
].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir
, i
))
98 if net
["r%s" % i
].daemon_available("ldpd"):
99 # Only test LDPd if it's installed and Kernel >= 4.5
100 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
101 net
["r%s" % i
].loadConf("sharpd")
102 net
["r%s" % i
].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir
, i
))
103 net
["r%s" % i
].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir
, i
))
104 net
["r%s" % i
].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir
, i
))
105 tgen
.gears
["r%s" % i
].start()
107 # For debugging after starting FRR daemons, uncomment the next line
111 def teardown_module(module
):
112 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
113 print("******************************************\n")
118 def test_router_running():
123 # Skip if previous fatal error condition is raised
124 if fatal_error
!= "":
125 pytest
.skip(fatal_error
)
127 print("\n\n** Check if FRR is running on each Router node")
128 print("******************************************\n")
132 for i
in range(1, 2):
133 fatal_error
= net
["r%s" % i
].checkRouterRunning()
134 assert fatal_error
== "", fatal_error
136 # For debugging after starting FRR daemons, uncomment the next line
140 def test_error_messages_vtysh():
142 net
= get_topogen().net
144 # Skip if previous fatal error condition is raised
145 if fatal_error
!= "":
146 pytest
.skip(fatal_error
)
148 print("\n\n** Check for error messages on VTYSH")
149 print("******************************************\n")
152 for i
in range(1, 2):
154 # First checking Standard Output
157 # VTYSH output from router
158 vtystdout
= net
["r%s" % i
].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
160 # Fix newlines (make them all the same)
161 vtystdout
= ("\n".join(vtystdout
.splitlines()) + "\n").rstrip()
162 # Drop everything starting with "FRRouting X.xx" message
163 vtystdout
= re
.sub(r
"FRRouting [0-9]+.*", "", vtystdout
, flags
=re
.DOTALL
)
166 print("r%s StdOut ok" % i
)
168 assert vtystdout
== "", "Vtysh StdOut Output check failed for router r%s" % i
171 # Second checking Standard Error
174 # VTYSH StdErr output from router
175 vtystderr
= net
["r%s" % i
].cmd('vtysh -c "show version" > /dev/null').rstrip()
177 # Fix newlines (make them all the same)
178 vtystderr
= ("\n".join(vtystderr
.splitlines()) + "\n").rstrip()
179 # # Drop everything starting with "FRRouting X.xx" message
180 # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
183 print("r%s StdErr ok" % i
)
185 assert vtystderr
== "", "Vtysh StdErr Output check failed for router r%s" % i
187 # Make sure that all daemons are running
188 for i
in range(1, 2):
189 fatal_error
= net
["r%s" % i
].checkRouterRunning()
190 assert fatal_error
== "", fatal_error
193 def test_error_messages_daemons():
195 net
= get_topogen().net
197 # Skip if previous fatal error condition is raised
198 if fatal_error
!= "":
199 pytest
.skip(fatal_error
)
201 print("\n\n** Check for error messages in daemons")
202 print("******************************************\n")
206 for i
in range(1, 2):
207 log
= net
["r%s" % i
].getStdErr("ripd")
209 error_logs
+= "r%s RIPd StdErr Output:\n" % i
211 log
= net
["r%s" % i
].getStdErr("ripngd")
213 error_logs
+= "r%s RIPngd StdErr Output:\n" % i
215 log
= net
["r%s" % i
].getStdErr("ospfd")
217 error_logs
+= "r%s OSPFd StdErr Output:\n" % i
219 log
= net
["r%s" % i
].getStdErr("ospf6d")
221 error_logs
+= "r%s OSPF6d StdErr Output:\n" % i
223 log
= net
["r%s" % i
].getStdErr("isisd")
224 # ISIS shows debugging enabled status on StdErr
225 # Remove these messages
226 log
= re
.sub(r
"^IS-IS .* debugging is on.*", "", log
).rstrip()
228 error_logs
+= "r%s ISISd StdErr Output:\n" % i
230 log
= net
["r%s" % i
].getStdErr("bgpd")
232 error_logs
+= "r%s BGPd StdErr Output:\n" % i
234 if net
["r%s" % i
].daemon_available("ldpd"):
235 log
= net
["r%s" % i
].getStdErr("ldpd")
237 error_logs
+= "r%s LDPd StdErr Output:\n" % i
240 log
= net
["r1"].getStdErr("nhrpd")
241 # NHRPD shows YANG model not embedded messages
243 log
= re
.sub(r
".*YANG model.*not embedded.*", "", log
).rstrip()
245 error_logs
+= "r%s NHRPd StdErr Output:\n" % i
248 log
= net
["r1"].getStdErr("babeld")
250 error_logs
+= "r%s BABELd StdErr Output:\n" % i
253 log
= net
["r1"].getStdErr("pbrd")
255 error_logs
+= "r%s PBRd StdErr Output:\n" % i
258 log
= net
["r%s" % i
].getStdErr("zebra")
260 error_logs
+= "r%s Zebra StdErr Output:\n" % i
265 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
268 # Ignoring the issue if told to ignore (ie not yet fixed)
270 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
272 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
275 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
278 assert error_logs
== "", "Daemons report errors to StdErr"
281 def test_converge_protocols():
283 net
= get_topogen().net
285 # Skip if previous fatal error condition is raised
286 if fatal_error
!= "":
287 pytest
.skip(fatal_error
)
289 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
291 # We need loopback to have a link local so it always is the
292 # "selected" router for fe80::/64 when we static compare below.
293 print("Adding link-local to loopback for stable results")
295 "mac=`cat /sys/class/net/lo/address`; echo lo: $mac;"
296 " [ -z \"$mac\" ] && continue; IFS=':'; set $mac; unset IFS;"
297 " ip address add dev lo scope link"
298 " fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64"
300 net
["r1"].cmd_raises(cmd
)
302 print("\n\n** Waiting for protocols convergence")
303 print("******************************************\n")
305 # Not really implemented yet - just sleep 60 secs for now
308 # Make sure that all daemons are running
310 for i
in range(1, 2):
311 fatal_error
= net
["r%s" % i
].checkRouterRunning()
312 assert fatal_error
== "", fatal_error
314 print("Show that v4 routes are right\n")
315 v4_routesFile
= "%s/r%s/ipv4_routes.ref" % (thisDir
, i
)
317 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v4_routesFile
)).rstrip()
319 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
324 "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
328 # Drop time in last update
329 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
330 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
331 diff
= topotest
.get_textdiff(
334 title1
="Actual IP Routing Table",
335 title2
="Expected IP RoutingTable",
338 sys
.stderr
.write("r%s failed IP Routing table check:\n%s\n" % (i
, diff
))
343 assert failures
== 0, "IP Routing table failed for r%s\n%s" % (i
, diff
)
347 print("Show that v6 routes are right\n")
348 v6_routesFile
= "%s/r%s/ipv6_routes.ref" % (thisDir
, i
)
350 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v6_routesFile
)).rstrip()
352 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
357 "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
361 # Drop time in last update
362 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
363 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
364 diff
= topotest
.get_textdiff(
367 title1
="Actual IPv6 Routing Table",
368 title2
="Expected IPv6 RoutingTable",
371 sys
.stderr
.write("r%s failed IPv6 Routing table check:\n%s\n" % (i
, diff
))
376 assert failures
== 0, "IPv6 Routing table failed for r%s\n%s" % (i
, diff
)
379 def route_get_nhg_id(route_str
):
380 net
= get_topogen().net
381 output
= net
["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str
)
382 match
= re
.search(r
"Nexthop Group ID: (\d+)", output
)
383 assert match
is not None, (
384 "Nexthop Group ID not found for sharpd route %s" % route_str
387 nhg_id
= int(match
.group(1))
391 def verify_nexthop_group(nhg_id
, recursive
=False, ecmp
=0):
392 net
= get_topogen().net
401 while not found
and count
< 10:
403 # Verify NHG is valid/installed
404 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
405 valid
= re
.search(r
"Valid", output
)
411 if ecmp
or recursive
:
412 ecmpcount
= re
.search(r
"Depends:.*\n", output
)
413 if ecmpcount
is None:
418 # list of IDs in group
419 depends
= re
.findall(r
"\((\d+)\)", ecmpcount
.group(0))
422 if len(depends
) != ecmp
:
427 # If recursive, we need to look at its resolved group
428 if len(depends
) != 1:
433 resolved_id
= int(depends
[0])
434 verify_nexthop_group(resolved_id
, False)
436 installed
= re
.search(r
"Installed", output
)
437 if installed
is None:
443 assert valid
is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
444 if ecmp
or recursive
:
445 assert ecmpcount
is not None, "Nexthop Group ID=%d has no depends" % nhg_id
447 assert len(depends
) == ecmp
, (
448 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
451 assert len(depends
) == 1, (
452 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
455 assert installed
is not None, (
456 "Nexthop Group ID=%d not marked Installed" % nhg_id
460 def verify_route_nexthop_group(route_str
, recursive
=False, ecmp
=0):
461 # Verify route and that zebra created NHGs for and they are valid/installed
462 nhg_id
= route_get_nhg_id(route_str
)
463 verify_nexthop_group(nhg_id
, recursive
, ecmp
)
466 def test_nexthop_groups():
468 net
= get_topogen().net
470 # Skip if previous fatal error condition is raised
471 if fatal_error
!= "":
472 pytest
.skip(fatal_error
)
474 print("\n\n** Verifying Nexthop Groups")
475 print("******************************************\n")
477 ### Nexthop Group Tests
481 # Create a lib nexthop-group
483 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
486 # Create with sharpd using nexthop-group
487 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
488 verify_route_nexthop_group("2.2.2.1/32")
493 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
496 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
497 verify_route_nexthop_group("2.2.2.2/32")
502 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
506 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
509 verify_route_nexthop_group("3.3.3.1/32", True)
514 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
517 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
519 verify_route_nexthop_group("3.3.3.2/32")
524 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
525 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
528 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
530 verify_route_nexthop_group("4.4.4.1/32")
533 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
534 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
537 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
539 verify_route_nexthop_group("4.4.4.2/32")
541 ## Recursive to 8-Way ECMP
544 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
548 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
551 verify_route_nexthop_group("5.5.5.1/32")
553 ## 4-way ECMP Routes Pointing to Each Other
555 # This is to check for a bug with NH resolution where
556 # routes would infintely resolve to each other blowing
557 # up the resolved-> nexthop pointer.
560 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
561 -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
564 # static route nexthops can recurse to
566 net
["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
568 # Make routes that point to themselves in ecmp
571 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
576 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
581 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
586 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
589 # Get routes and test if has too many (duplicate) nexthops
592 nhg_id
= route_get_nhg_id("6.6.6.1/32")
593 while (len(dups
) != 3) and count
< 10:
594 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
596 dups
= re
.findall(r
"(via 1\.1\.1\.1)", output
)
601 # Should find 3, itself is inactive
602 assert len(dups
) == 3, (
603 "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
607 ## Remove all NHG routes
609 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
610 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
611 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
612 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
613 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
614 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
615 net
["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
616 net
["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
617 net
["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
620 def test_rip_status():
622 net
= get_topogen().net
624 # Skip if previous fatal error condition is raised
625 if fatal_error
!= "":
626 pytest
.skip(fatal_error
)
628 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
630 print("\n\n** Verifying RIP status")
631 print("******************************************\n")
633 for i
in range(1, 2):
634 refTableFile
= "%s/r%s/rip_status.ref" % (thisDir
, i
)
635 if os
.path
.isfile(refTableFile
):
636 # Read expected result from file
637 expected
= open(refTableFile
).read().rstrip()
638 # Fix newlines (make them all the same)
639 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
641 # Actual output from router
644 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
647 # Drop time in next due
648 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
649 # Drop time in last update
650 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
651 # Fix newlines (make them all the same)
652 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
655 diff
= topotest
.get_textdiff(
658 title1
="actual IP RIP status",
659 title2
="expected IP RIP status",
662 # Empty string if it matches, otherwise diff contains unified diff
664 sys
.stderr
.write("r%s failed IP RIP status check:\n%s\n" % (i
, diff
))
669 assert failures
== 0, "IP RIP status failed for router r%s:\n%s" % (i
, diff
)
671 # Make sure that all daemons are running
672 for i
in range(1, 2):
673 fatal_error
= net
["r%s" % i
].checkRouterRunning()
674 assert fatal_error
== "", fatal_error
677 def test_ripng_status():
679 net
= get_topogen().net
681 # Skip if previous fatal error condition is raised
682 if fatal_error
!= "":
683 pytest
.skip(fatal_error
)
685 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
687 print("\n\n** Verifying RIPng status")
688 print("******************************************\n")
690 for i
in range(1, 2):
691 refTableFile
= "%s/r%s/ripng_status.ref" % (thisDir
, i
)
692 if os
.path
.isfile(refTableFile
):
693 # Read expected result from file
694 expected
= open(refTableFile
).read().rstrip()
695 # Fix newlines (make them all the same)
696 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
698 # Actual output from router
701 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
704 # Mask out Link-Local mac address portion. They are random...
705 actual
= re
.sub(r
" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual
)
706 # Drop time in next due
707 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
708 # Drop time in last update
709 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
710 # Fix newlines (make them all the same)
711 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
714 diff
= topotest
.get_textdiff(
717 title1
="actual IPv6 RIPng status",
718 title2
="expected IPv6 RIPng status",
721 # Empty string if it matches, otherwise diff contains unified diff
724 "r%s failed IPv6 RIPng status check:\n%s\n" % (i
, diff
)
730 assert failures
== 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
735 # Make sure that all daemons are running
736 for i
in range(1, 2):
737 fatal_error
= net
["r%s" % i
].checkRouterRunning()
738 assert fatal_error
== "", fatal_error
741 def test_ospfv2_interfaces():
743 net
= get_topogen().net
745 # Skip if previous fatal error condition is raised
746 if fatal_error
!= "":
747 pytest
.skip(fatal_error
)
749 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
751 print("\n\n** Verifying OSPFv2 interfaces")
752 print("******************************************\n")
754 for i
in range(1, 2):
755 refTableFile
= "%s/r%s/show_ip_ospf_interface.ref" % (thisDir
, i
)
756 if os
.path
.isfile(refTableFile
):
757 # Read expected result from file
758 expected
= open(refTableFile
).read().rstrip()
759 # Fix newlines (make them all the same)
760 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
762 # Actual output from router
765 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
768 # Mask out Bandwidth portion. They may change..
769 actual
= re
.sub(r
"BW [0-9]+ Mbit", "BW XX Mbit", actual
)
770 actual
= re
.sub(r
"ifindex [0-9]+", "ifindex X", actual
)
772 # Drop time in next due
773 actual
= re
.sub(r
"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual
)
775 r
"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
777 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
779 r
"MTU mismatch detection:([a-z]+.*)",
780 r
"MTU mismatch detection: \1",
783 # Fix newlines (make them all the same)
784 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
787 diff
= topotest
.get_textdiff(
790 title1
="actual SHOW IP OSPF INTERFACE",
791 title2
="expected SHOW IP OSPF INTERFACE",
794 # Empty string if it matches, otherwise diff contains unified diff
797 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i
, diff
)
803 # Ignoring the issue if told to ignore (ie not yet fixed)
805 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
807 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
810 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
815 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i
, diff
)
817 # Make sure that all daemons are running
818 for i
in range(1, 2):
819 fatal_error
= net
["r%s" % i
].checkRouterRunning()
820 assert fatal_error
== "", fatal_error
823 def test_isis_interfaces():
825 net
= get_topogen().net
827 # Skip if previous fatal error condition is raised
828 if fatal_error
!= "":
829 pytest
.skip(fatal_error
)
831 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
833 print("\n\n** Verifying ISIS interfaces")
834 print("******************************************\n")
836 for i
in range(1, 2):
837 refTableFile
= "%s/r%s/show_isis_interface_detail.ref" % (thisDir
, i
)
838 if os
.path
.isfile(refTableFile
):
839 # Read expected result from file
840 expected
= open(refTableFile
).read().rstrip()
841 # Fix newlines (make them all the same)
842 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
844 # Actual output from router
847 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
850 # Mask out Link-Local mac address portion. They are random...
851 actual
= re
.sub(r
"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual
)
852 # Mask out SNPA mac address portion. They are random...
853 actual
= re
.sub(r
"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual
)
854 # Mask out Circuit ID number
855 actual
= re
.sub(r
"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual
)
856 # Fix newlines (make them all the same)
857 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
860 diff
= topotest
.get_textdiff(
863 title1
="actual SHOW ISIS INTERFACE DETAIL",
864 title2
="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
867 # Empty string if it matches, otherwise diff contains unified diff
870 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i
, diff
)
878 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i
, diff
)
880 # Make sure that all daemons are running
881 for i
in range(1, 2):
882 fatal_error
= net
["r%s" % i
].checkRouterRunning()
883 assert fatal_error
== "", fatal_error
886 def test_bgp_summary():
888 net
= get_topogen().net
890 # Skip if previous fatal error condition is raised
891 if fatal_error
!= "":
892 pytest
.skip(fatal_error
)
894 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
896 print("\n\n** Verifying BGP Summary")
897 print("******************************************\n")
899 for i
in range(1, 2):
900 refTableFile
= "%s/r%s/show_ip_bgp_summary.ref" % (thisDir
, i
)
901 if os
.path
.isfile(refTableFile
):
902 # Read expected result from file
903 expected_original
= open(refTableFile
).read().rstrip()
907 "remote-as internal",
908 "remote-as external",
911 "neighbor 192.168.7.10",
912 "neighbor 192.168.7.10",
913 "neighbor fc00:0:0:8::1000",
916 "remote-as internal terse",
917 "remote-as external terse",
918 "remote-as 100 terse",
919 "remote-as 123 terse",
920 "neighbor 192.168.7.10 terse",
921 "neighbor 192.168.7.10 terse",
922 "neighbor fc00:0:0:8::1000 terse",
923 "neighbor 10.0.0.1 terse",
925 # Actual output from router
929 'vtysh -c "show ip bgp summary ' + arguments
+ '" 2> /dev/null'
934 # Mask out "using XXiXX bytes" portion. They are random...
935 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
936 # Mask out "using XiXXX KiB" portion. They are random...
937 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
939 # Remove extra summaries which exist with newer versions
941 # Remove summary lines (changed recently)
942 actual
= re
.sub(r
"Total number.*", "", actual
)
943 actual
= re
.sub(r
"Displayed.*", "", actual
)
944 # Remove IPv4 Unicast Summary (Title only)
945 actual
= re
.sub(r
"IPv4 Unicast Summary \(VRF default\):", "", actual
)
946 # Remove IPv4 Multicast Summary (all of it)
947 actual
= re
.sub(r
"IPv4 Multicast Summary \(VRF default\):", "", actual
)
948 actual
= re
.sub(r
"No IPv4 Multicast neighbor is configured", "", actual
)
949 # Remove IPv4 VPN Summary (all of it)
950 actual
= re
.sub(r
"IPv4 VPN Summary \(VRF default\):", "", actual
)
951 actual
= re
.sub(r
"No IPv4 VPN neighbor is configured", "", actual
)
952 # Remove IPv4 Encap Summary (all of it)
953 actual
= re
.sub(r
"IPv4 Encap Summary \(VRF default\):", "", actual
)
954 actual
= re
.sub(r
"No IPv4 Encap neighbor is configured", "", actual
)
955 # Remove Unknown Summary (all of it)
956 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
957 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
958 # Make Connect/Active/Idle the same (change them all to Active)
959 actual
= re
.sub(r
" Connect ", " Active ", actual
)
960 actual
= re
.sub(r
" Idle ", " Active ", actual
)
963 r
"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
966 r
"No IPv4 labeled-unicast neighbor is configured", "", actual
969 expected
= expected_original
970 # apply argumentss on expected output
971 if "internal" in arguments
or "remote-as 100" in arguments
:
972 expected
= re
.sub(r
".+\s+200\s+.+", "", expected
)
973 elif "external" in arguments
:
974 expected
= re
.sub(r
".+\s+100\s+.+Active.+", "", expected
)
975 elif "remote-as 123" in arguments
:
977 r
"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
981 expected
= re
.sub(r
"\nNeighbor.+Desc", "", expected
)
982 expected
= expected
+ "% No matching neighbor\n"
983 elif "192.168.7.10" in arguments
:
985 r
"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
987 elif "fc00:0:0:8::1000" in arguments
:
989 r
"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
991 elif "10.0.0.1" in arguments
:
992 expected
= "No such neighbor in this view/vrf"
994 if "terse" in arguments
:
995 expected
= re
.sub(r
"BGP table version .+", "", expected
)
996 expected
= re
.sub(r
"RIB entries .+", "", expected
)
997 expected
= re
.sub(r
"Peers [0-9]+, using .+", "", expected
)
1000 actual
= actual
.lstrip().rstrip()
1001 expected
= expected
.lstrip().rstrip()
1002 actual
= re
.sub(r
"\n+", "\n", actual
)
1003 expected
= re
.sub(r
"\n+", "\n", expected
)
1005 # reapply initial formatting
1006 if "terse" in arguments
:
1007 actual
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", actual
)
1008 expected
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", expected
)
1010 actual
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", actual
)
1011 expected
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", expected
)
1013 # realign expected neighbor columns if needed
1016 re
.search(r
"(Neighbor\s+V\s+)", actual
).group(1).find("V")
1019 re
.search(r
"(Neighbor\s+V\s+)", expected
).group(1).find("V")
1021 idx_diff
= idx_expected
- idx_actual
1023 # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
1024 expected
= re
.sub(" " * idx_diff
+ "V ", "V ", expected
)
1025 # 192.168.7.10 4 100 0 0 0 0 0 never Active
1026 expected
= re
.sub(" " * idx_diff
+ "4 ", "4 ", expected
)
1027 except AttributeError:
1030 # Fix newlines (make them all the same)
1031 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1032 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1035 diff
= topotest
.get_textdiff(
1038 title1
="actual SHOW IP BGP SUMMARY " + arguments
.upper(),
1039 title2
="expected SHOW IP BGP SUMMARY " + arguments
.upper(),
1042 # Empty string if it matches, otherwise diff contains unified diff
1045 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i
, diff
)
1053 ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
1058 # Make sure that all daemons are running
1059 for i
in range(1, 2):
1060 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1061 assert fatal_error
== "", fatal_error
1064 def test_bgp_ipv6_summary():
1066 net
= get_topogen().net
1068 # Skip if previous fatal error condition is raised
1069 if fatal_error
!= "":
1070 pytest
.skip(fatal_error
)
1072 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1074 print("\n\n** Verifying BGP IPv6 Summary")
1075 print("******************************************\n")
1077 for i
in range(1, 2):
1078 refTableFile
= "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir
, i
)
1079 if os
.path
.isfile(refTableFile
):
1080 # Read expected result from file
1081 expected
= open(refTableFile
).read().rstrip()
1082 # Fix newlines (make them all the same)
1083 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1085 # Actual output from router
1088 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
1091 # Mask out "using XXiXX bytes" portion. They are random...
1092 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
1093 # Mask out "using XiXXX KiB" portion. They are random...
1094 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
1096 # Remove extra summaries which exist with newer versions
1098 # Remove summary lines (changed recently)
1099 actual
= re
.sub(r
"Total number.*", "", actual
)
1100 actual
= re
.sub(r
"Displayed.*", "", actual
)
1101 # Remove IPv4 Unicast Summary (Title only)
1102 actual
= re
.sub(r
"IPv6 Unicast Summary \(VRF default\):", "", actual
)
1103 # Remove IPv4 Multicast Summary (all of it)
1104 actual
= re
.sub(r
"IPv6 Multicast Summary \(VRF default\):", "", actual
)
1105 actual
= re
.sub(r
"No IPv6 Multicast neighbor is configured", "", actual
)
1106 # Remove IPv4 VPN Summary (all of it)
1107 actual
= re
.sub(r
"IPv6 VPN Summary \(VRF default\):", "", actual
)
1108 actual
= re
.sub(r
"No IPv6 VPN neighbor is configured", "", actual
)
1109 # Remove IPv4 Encap Summary (all of it)
1110 actual
= re
.sub(r
"IPv6 Encap Summary \(VRF default\):", "", actual
)
1111 actual
= re
.sub(r
"No IPv6 Encap neighbor is configured", "", actual
)
1112 # Remove Unknown Summary (all of it)
1113 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
1114 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
1115 # Make Connect/Active/Idle the same (change them all to Active)
1116 actual
= re
.sub(r
" Connect ", " Active ", actual
)
1117 actual
= re
.sub(r
" Idle ", " Active ", actual
)
1119 # Remove Labeled Unicast Summary (all of it)
1121 r
"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
1124 r
"No IPv6 labeled-unicast neighbor is configured", "", actual
1128 actual
= actual
.lstrip()
1129 actual
= actual
.rstrip()
1131 # Fix newlines (make them all the same)
1132 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1135 diff
= topotest
.get_textdiff(
1138 title1
="actual SHOW BGP IPv6 SUMMARY",
1139 title2
="expected SHOW BGP IPv6 SUMMARY",
1142 # Empty string if it matches, otherwise diff contains unified diff
1145 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i
, diff
)
1151 assert failures
== 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1156 # Make sure that all daemons are running
1157 for i
in range(1, 2):
1158 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1159 assert fatal_error
== "", fatal_error
1164 net
= get_topogen().net
1166 # Skip if previous fatal error condition is raised
1167 if fatal_error
!= "":
1168 pytest
.skip(fatal_error
)
1170 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1172 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1174 for i
in range(1, 2):
1175 nhtFile
= "%s/r%s/ip_nht.ref" % (thisDir
, i
)
1176 expected
= open(nhtFile
).read().rstrip()
1177 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1179 actual
= net
["r%s" % i
].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
1180 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1181 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1183 diff
= topotest
.get_textdiff(
1186 title1
="Actual `show ip nht`",
1187 title2
="Expected `show ip nht`",
1191 assert 0, "r%s failed ip nht check:\n%s\n" % (i
, diff
)
1193 print("show ip nht is ok\n")
1195 nhtFile
= "%s/r%s/ipv6_nht.ref" % (thisDir
, i
)
1196 expected
= open(nhtFile
).read().rstrip()
1197 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1199 actual
= net
["r%s" % i
].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
1200 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1201 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1203 diff
= topotest
.get_textdiff(
1206 title1
="Actual `show ip nht`",
1207 title2
="Expected `show ip nht`",
1211 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i
, diff
)
1213 print("show ipv6 nht is ok\n")
1216 def test_bgp_ipv4():
1218 net
= get_topogen().net
1220 # Skip if previous fatal error condition is raised
1221 if fatal_error
!= "":
1222 pytest
.skip(fatal_error
)
1224 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1226 print("\n\n** Verifying BGP IPv4")
1227 print("******************************************\n")
1229 for i
in range(1, 2):
1231 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir
, i
)):
1232 if os
.path
.isfile(refTableFile
):
1233 # Read expected result from file
1234 expected
= open(refTableFile
).read().rstrip()
1235 # Fix newlines (make them all the same)
1236 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1238 # Actual output from router
1240 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1242 # Remove summary line (changed recently)
1243 actual
= re
.sub(r
"Total number.*", "", actual
)
1244 actual
= re
.sub(r
"Displayed.*", "", actual
)
1245 actual
= actual
.rstrip()
1246 # Fix newlines (make them all the same)
1247 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1250 diff
= topotest
.get_textdiff(
1253 title1
="actual SHOW BGP IPv4",
1254 title2
="expected SHOW BGP IPv4",
1257 # Empty string if it matches, otherwise diff contains unified diff
1259 diffresult
[refTableFile
] = diff
1262 print("template %s matched: r%s ok" % (refTableFile
, i
))
1266 resultstr
= "No template matched.\n"
1267 for f
in diffresult
.keys():
1268 resultstr
+= "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1273 raise AssertionError(
1274 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i
, resultstr
)
1277 # Make sure that all daemons are running
1278 for i
in range(1, 2):
1279 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1280 assert fatal_error
== "", fatal_error
1283 def test_bgp_ipv6():
1285 net
= get_topogen().net
1287 # Skip if previous fatal error condition is raised
1288 if fatal_error
!= "":
1289 pytest
.skip(fatal_error
)
1291 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1293 print("\n\n** Verifying BGP IPv6")
1294 print("******************************************\n")
1296 for i
in range(1, 2):
1298 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir
, i
)):
1299 if os
.path
.isfile(refTableFile
):
1300 # Read expected result from file
1301 expected
= open(refTableFile
).read().rstrip()
1302 # Fix newlines (make them all the same)
1303 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1305 # Actual output from router
1307 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1309 # Remove summary line (changed recently)
1310 actual
= re
.sub(r
"Total number.*", "", actual
)
1311 actual
= re
.sub(r
"Displayed.*", "", actual
)
1312 actual
= actual
.rstrip()
1313 # Fix newlines (make them all the same)
1314 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1317 diff
= topotest
.get_textdiff(
1320 title1
="actual SHOW BGP IPv6",
1321 title2
="expected SHOW BGP IPv6",
1324 # Empty string if it matches, otherwise diff contains unified diff
1326 diffresult
[refTableFile
] = diff
1329 print("template %s matched: r%s ok" % (refTableFile
, i
))
1332 resultstr
= "No template matched.\n"
1333 for f
in diffresult
.keys():
1334 resultstr
+= "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1339 raise AssertionError(
1340 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i
, resultstr
)
1343 # Make sure that all daemons are running
1344 for i
in range(1, 2):
1345 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1346 assert fatal_error
== "", fatal_error
1349 def test_route_map():
1351 net
= get_topogen().net
1353 if fatal_error
!= "":
1354 pytest
.skip(fatal_error
)
1356 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1358 print("\n\n** Verifying some basic routemap forward references\n")
1359 print("*******************************************************\n")
1361 for i
in range(1, 2):
1362 refroutemap
= "%s/r%s/show_route_map.ref" % (thisDir
, i
)
1363 if os
.path
.isfile(refroutemap
):
1364 expected
= open(refroutemap
).read().rstrip()
1365 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1368 net
["r%s" % i
].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1370 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1372 diff
= topotest
.get_textdiff(
1375 title1
="actual show route-map",
1376 title2
="expected show route-map",
1381 "r%s failed show route-map command Check:\n%s\n" % (i
, diff
)
1389 ), "Show route-map command failed for router r%s:\n%s" % (i
, diff
)
1392 def test_nexthop_groups_with_route_maps():
1394 net
= get_topogen().net
1396 # Skip if previous fatal error condition is raised
1397 if fatal_error
!= "":
1398 pytest
.skip(fatal_error
)
1400 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1401 print("******************************************\n")
1403 ### Nexthop Group With Route-Map Tests
1405 # Create a lib nexthop-group
1407 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1410 ## Route-Map Proto Source
1412 route_str
= "2.2.2.1"
1413 src_str
= "192.168.0.1"
1416 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1418 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1420 net
["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str
)
1422 verify_route_nexthop_group("%s/32" % route_str
)
1424 # Only a valid test on linux using nexthop objects
1425 if sys
.platform
.startswith("linux"):
1426 output
= net
["r1"].cmd("ip route show %s/32" % route_str
)
1427 match
= re
.search(r
"src %s" % src_str
, output
)
1428 assert match
is not None, "Route %s/32 not installed with src %s" % (
1433 # Remove NHG routes and route-map
1434 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str
)
1435 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
1437 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
1439 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1441 ## Route-Map Deny/Permit with same nexthop group
1443 permit_route_str
= "3.3.3.1"
1444 deny_route_str
= "3.3.3.2"
1447 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1450 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1452 net
["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1453 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1455 # This route should be permitted
1457 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1460 verify_route_nexthop_group("%s/32" % permit_route_str
)
1462 # This route should be denied
1464 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1467 nhg_id
= route_get_nhg_id(deny_route_str
)
1468 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
1470 match
= re
.search(r
"Valid", output
)
1471 assert match
is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1473 match
= re
.search(r
"Installed", output
)
1474 assert match
is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1476 # Remove NHG routes and route-map
1477 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str
)
1478 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str
)
1479 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1480 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1481 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1482 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
1484 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1489 def test_nexthop_group_replace():
1491 net
= get_topogen().net
1493 # Skip if previous fatal error condition is raised
1494 if fatal_error
!= "":
1495 pytest
.skip(fatal_error
)
1497 print("\n\n** Verifying Nexthop Groups")
1498 print("******************************************\n")
1500 ### Nexthop Group Tests
1502 ## 2-Way ECMP Directly Connected
1505 '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"'
1508 # At the moment there is absolutely no real easy way to query sharpd
1509 # for the nexthop group actually installed. If it is not installed
1510 # sharpd will just transmit the nexthops down instead of the nexthop
1511 # group id. Leading to a situation where the replace is not actually
1512 # being tested. So let's just wait some time here because this
1513 # is hard and this test fails all the time
1516 # Create with sharpd using nexthop-group
1517 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1519 verify_route_nexthop_group("3.3.3.1/32")
1521 # Change the nexthop group
1523 '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"'
1526 # Verify it updated. We can just check install and ecmp count here.
1527 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1530 def test_mpls_interfaces():
1532 net
= get_topogen().net
1534 # Skip if previous fatal error condition is raised
1535 if fatal_error
!= "":
1536 pytest
.skip(fatal_error
)
1538 # Skip if no LDP installed or old kernel
1539 if net
["r1"].daemon_available("ldpd") == False:
1540 pytest
.skip("No MPLS or kernel < 4.5")
1542 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1544 print("\n\n** Verifying MPLS Interfaces")
1545 print("******************************************\n")
1547 for i
in range(1, 2):
1548 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir
, i
)
1549 if os
.path
.isfile(refTableFile
):
1550 # Read expected result from file
1551 expected
= open(refTableFile
).read().rstrip()
1552 # Fix newlines (make them all the same)
1553 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1555 # Actual output from router
1558 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1561 # Mask out Timer in Uptime
1562 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
1563 # Fix newlines (make them all the same)
1564 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1567 diff
= topotest
.get_textdiff(
1570 title1
="actual MPLS LDP interface status",
1571 title2
="expected MPLS LDP interface status",
1574 # Empty string if it matches, otherwise diff contains unified diff
1577 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
1584 fatal_error
= "MPLS LDP Interface status failed"
1588 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
1590 # Make sure that all daemons are running
1591 for i
in range(1, 2):
1592 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1593 assert fatal_error
== "", fatal_error
1596 def test_resilient_nexthop_group():
1597 net
= get_topogen().net
1599 result
= required_linux_kernel_version("5.19")
1600 if result
is not True:
1601 pytest
.skip("Kernel requirements are not met, kernel version should be >= 5.19")
1604 '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"'
1607 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib sharp"')
1608 output
= re
.findall(r
"Buckets", output
)
1610 verify_nexthop_group(185483878)
1611 assert len(output
) == 1, "Resilient NHG not created in zebra"
1614 def test_shutdown_check_stderr():
1616 net
= get_topogen().net
1618 # Skip if previous fatal error condition is raised
1619 if fatal_error
!= "":
1620 pytest
.skip(fatal_error
)
1622 print("\n\n** Verifying unexpected STDERR output from daemons")
1623 print("******************************************\n")
1625 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
1627 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1629 pytest
.skip("Skipping test for Stderr output")
1631 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1633 print("thisDir=" + thisDir
)
1635 net
["r1"].stopRouter()
1637 log
= net
["r1"].getStdErr("ripd")
1639 print("\nRIPd StdErr Log:\n" + log
)
1640 log
= net
["r1"].getStdErr("ripngd")
1642 print("\nRIPngd StdErr Log:\n" + log
)
1643 log
= net
["r1"].getStdErr("ospfd")
1645 print("\nOSPFd StdErr Log:\n" + log
)
1646 log
= net
["r1"].getStdErr("ospf6d")
1648 print("\nOSPF6d StdErr Log:\n" + log
)
1649 log
= net
["r1"].getStdErr("isisd")
1651 print("\nISISd StdErr Log:\n" + log
)
1652 log
= net
["r1"].getStdErr("bgpd")
1654 print("\nBGPd StdErr Log:\n" + log
)
1656 log
= net
["r1"].getStdErr("nhrpd")
1658 print("\nNHRPd StdErr Log:\n" + log
)
1660 log
= net
["r1"].getStdErr("pbrd")
1662 print("\nPBRd StdErr Log:\n" + log
)
1664 log
= net
["r1"].getStdErr("babeld")
1666 print("\nBABELd StdErr Log:\n" + log
)
1668 if net
["r1"].daemon_available("ldpd"):
1669 log
= net
["r1"].getStdErr("ldpd")
1671 print("\nLDPd StdErr Log:\n" + log
)
1672 log
= net
["r1"].getStdErr("zebra")
1674 print("\nZebra StdErr Log:\n" + log
)
1677 def test_shutdown_check_memleak():
1679 net
= get_topogen().net
1681 # Skip if previous fatal error condition is raised
1682 if fatal_error
!= "":
1683 pytest
.skip(fatal_error
)
1685 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1687 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1689 pytest
.skip("Skipping test for memory leaks")
1691 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1693 for i
in range(1, 2):
1694 net
["r%s" % i
].stopRouter()
1695 net
["r%s" % i
].report_memory_leaks(
1696 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
1700 if __name__
== "__main__":
1701 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1702 # retval = pytest.main(["-s", "--tb=no"])
1703 retval
= pytest
.main(["-s"])