]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/all_protocol_startup/test_all_protocol_startup.py
4 # test_all_protocol_startup.py
5 # Part of NetDEF Topology Tests
7 # Copyright (c) 2017 by
8 # Network Device Education Foundation, Inc. ("NetDEF")
10 # Permission to use, copy, modify, and/or distribute this software
11 # for any purpose with or without fee is hereby granted, provided
12 # that the above copyright notice and this permission notice appear
15 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26 test_all_protocol_startup.py: Test of all protocols at same time
35 from time
import sleep
48 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
49 from lib
import topotest
50 from lib
.topogen
import Topogen
, get_topogen
55 #####################################################
57 ## Network Topology Definition
59 #####################################################
63 router
= tgen
.add_router("r1")
64 for i
in range(0, 10):
65 tgen
.add_switch("sw%d" % i
).add_link(router
)
68 #####################################################
72 #####################################################
75 def setup_module(module
):
78 print("\n\n** %s: Setup Topology" % module
.__name
__)
79 print("******************************************\n")
81 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
82 tgen
= Topogen(build_topo
, module
.__name
__)
87 if net
["r1"].get_routertype() != "frr":
88 fatal_error
= "Test is only implemented for FRR"
89 sys
.stderr
.write("\n\nTest is only implemented for FRR - Skipping\n\n")
90 pytest
.skip(fatal_error
)
96 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
97 net
["r%s" % i
].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir
, i
))
98 net
["r%s" % i
].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir
, i
))
99 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
100 if net
["r1"].checkRouterVersion("<", "4.0"):
101 net
["r%s" % i
].loadConf(
102 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir
, i
)
105 net
["r%s" % i
].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir
, i
))
106 net
["r%s" % i
].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir
, i
))
107 net
["r%s" % i
].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir
, i
))
108 if net
["r%s" % i
].daemon_available("ldpd"):
109 # Only test LDPd if it's installed and Kernel >= 4.5
110 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
111 net
["r%s" % i
].loadConf("sharpd")
112 net
["r%s" % i
].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir
, i
))
113 net
["r%s" % i
].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir
, i
))
114 net
["r%s" % i
].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir
, i
))
115 tgen
.gears
["r%s" % i
].start()
117 # For debugging after starting FRR daemons, uncomment the next line
121 def teardown_module(module
):
122 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
123 print("******************************************\n")
128 def test_router_running():
130 net
= get_topogen().net
132 # Skip if previous fatal error condition is raised
133 if fatal_error
!= "":
134 pytest
.skip(fatal_error
)
136 print("\n\n** Check if FRR is running on each Router node")
137 print("******************************************\n")
141 for i
in range(1, 2):
142 fatal_error
= net
["r%s" % i
].checkRouterRunning()
143 assert fatal_error
== "", fatal_error
145 # For debugging after starting FRR daemons, uncomment the next line
149 def test_error_messages_vtysh():
151 net
= get_topogen().net
153 # Skip if previous fatal error condition is raised
154 if fatal_error
!= "":
155 pytest
.skip(fatal_error
)
157 print("\n\n** Check for error messages on VTYSH")
158 print("******************************************\n")
161 for i
in range(1, 2):
163 # First checking Standard Output
166 # VTYSH output from router
167 vtystdout
= net
["r%s" % i
].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
169 # Fix newlines (make them all the same)
170 vtystdout
= ("\n".join(vtystdout
.splitlines()) + "\n").rstrip()
171 # Drop everything starting with "FRRouting X.xx" message
172 vtystdout
= re
.sub(r
"FRRouting [0-9]+.*", "", vtystdout
, flags
=re
.DOTALL
)
175 print("r%s StdOut ok" % i
)
177 assert vtystdout
== "", "Vtysh StdOut Output check failed for router r%s" % i
180 # Second checking Standard Error
183 # VTYSH StdErr output from router
184 vtystderr
= net
["r%s" % i
].cmd('vtysh -c "show version" > /dev/null').rstrip()
186 # Fix newlines (make them all the same)
187 vtystderr
= ("\n".join(vtystderr
.splitlines()) + "\n").rstrip()
188 # # Drop everything starting with "FRRouting X.xx" message
189 # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
192 print("r%s StdErr ok" % i
)
194 assert vtystderr
== "", "Vtysh StdErr Output check failed for router r%s" % i
196 # Make sure that all daemons are running
197 for i
in range(1, 2):
198 fatal_error
= net
["r%s" % i
].checkRouterRunning()
199 assert fatal_error
== "", fatal_error
201 # For debugging after starting FRR daemons, uncomment the next line
205 def test_error_messages_daemons():
207 net
= get_topogen().net
209 # Skip if previous fatal error condition is raised
210 if fatal_error
!= "":
211 pytest
.skip(fatal_error
)
213 print("\n\n** Check for error messages in daemons")
214 print("******************************************\n")
218 for i
in range(1, 2):
219 log
= net
["r%s" % i
].getStdErr("ripd")
221 error_logs
+= "r%s RIPd StdErr Output:\n" % i
223 log
= net
["r%s" % i
].getStdErr("ripngd")
225 error_logs
+= "r%s RIPngd StdErr Output:\n" % i
227 log
= net
["r%s" % i
].getStdErr("ospfd")
229 error_logs
+= "r%s OSPFd StdErr Output:\n" % i
231 log
= net
["r%s" % i
].getStdErr("ospf6d")
233 error_logs
+= "r%s OSPF6d StdErr Output:\n" % i
235 log
= net
["r%s" % i
].getStdErr("isisd")
236 # ISIS shows debugging enabled status on StdErr
237 # Remove these messages
238 log
= re
.sub(r
"^IS-IS .* debugging is on.*", "", log
).rstrip()
240 error_logs
+= "r%s ISISd StdErr Output:\n" % i
242 log
= net
["r%s" % i
].getStdErr("bgpd")
244 error_logs
+= "r%s BGPd StdErr Output:\n" % i
246 if net
["r%s" % i
].daemon_available("ldpd"):
247 log
= net
["r%s" % i
].getStdErr("ldpd")
249 error_logs
+= "r%s LDPd StdErr Output:\n" % i
252 log
= net
["r1"].getStdErr("nhrpd")
253 # NHRPD shows YANG model not embedded messages
255 log
= re
.sub(r
".*YANG model.*not embedded.*", "", log
).rstrip()
257 error_logs
+= "r%s NHRPd StdErr Output:\n" % i
260 log
= net
["r1"].getStdErr("babeld")
262 error_logs
+= "r%s BABELd StdErr Output:\n" % i
265 log
= net
["r1"].getStdErr("pbrd")
267 error_logs
+= "r%s PBRd StdErr Output:\n" % i
270 log
= net
["r%s" % i
].getStdErr("zebra")
272 error_logs
+= "r%s Zebra StdErr Output:\n" % i
277 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
280 # Ignoring the issue if told to ignore (ie not yet fixed)
282 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
284 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
287 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
290 assert error_logs
== "", "Daemons report errors to StdErr"
292 # For debugging after starting FRR daemons, uncomment the next line
296 def test_converge_protocols():
298 net
= get_topogen().net
300 # Skip if previous fatal error condition is raised
301 if fatal_error
!= "":
302 pytest
.skip(fatal_error
)
304 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
306 print("\n\n** Waiting for protocols convergence")
307 print("******************************************\n")
309 # Not really implemented yet - just sleep 60 secs for now
312 # Make sure that all daemons are running
314 for i
in range(1, 2):
315 fatal_error
= net
["r%s" % i
].checkRouterRunning()
316 assert fatal_error
== "", fatal_error
318 print("Show that v4 routes are right\n")
319 v4_routesFile
= "%s/r%s/ipv4_routes.ref" % (thisDir
, i
)
321 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v4_routesFile
)).rstrip()
323 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
328 "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null"
332 # Drop time in last update
333 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
334 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
335 diff
= topotest
.get_textdiff(
338 title1
="Actual IP Routing Table",
339 title2
="Expected IP RoutingTable",
342 sys
.stderr
.write("r%s failed IP Routing table check:\n%s\n" % (i
, diff
))
347 assert failures
== 0, "IP Routing table failed for r%s\n%s" % (i
, diff
)
351 print("Show that v6 routes are right\n")
352 v6_routesFile
= "%s/r%s/ipv6_routes.ref" % (thisDir
, i
)
354 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v6_routesFile
)).rstrip()
356 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
361 "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null"
365 # Drop time in last update
366 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
367 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
368 diff
= topotest
.get_textdiff(
371 title1
="Actual IPv6 Routing Table",
372 title2
="Expected IPv6 RoutingTable",
375 sys
.stderr
.write("r%s failed IPv6 Routing table check:\n%s\n" % (i
, diff
))
380 assert failures
== 0, "IPv6 Routing table failed for r%s\n%s" % (i
, diff
)
382 # For debugging after starting FRR daemons, uncomment the next line
386 def route_get_nhg_id(route_str
):
387 net
= get_topogen().net
388 output
= net
["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str
)
389 match
= re
.search(r
"Nexthop Group ID: (\d+)", output
)
390 assert match
is not None, (
391 "Nexthop Group ID not found for sharpd route %s" % route_str
394 nhg_id
= int(match
.group(1))
398 def verify_nexthop_group(nhg_id
, recursive
=False, ecmp
=0):
399 net
= get_topogen().net
400 # Verify NHG is valid/installed
401 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
403 match
= re
.search(r
"Valid", output
)
404 assert match
is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
406 if ecmp
or recursive
:
407 match
= re
.search(r
"Depends:.*\n", output
)
408 assert match
is not None, "Nexthop Group ID=%d has no depends" % nhg_id
410 # list of IDs in group
411 depends
= re
.findall(r
"\((\d+)\)", match
.group(0))
414 assert len(depends
) == ecmp
, (
415 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
418 # If recursive, we need to look at its resolved group
419 assert len(depends
) == 1, (
420 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
422 resolved_id
= int(depends
[0])
423 verify_nexthop_group(resolved_id
, False)
426 match
= re
.search(r
"Installed", output
)
427 assert match
is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id
430 def verify_route_nexthop_group(route_str
, recursive
=False, ecmp
=0):
431 # Verify route and that zebra created NHGs for and they are valid/installed
432 nhg_id
= route_get_nhg_id(route_str
)
433 verify_nexthop_group(nhg_id
, recursive
, ecmp
)
436 def test_nexthop_groups():
438 net
= get_topogen().net
440 # Skip if previous fatal error condition is raised
441 if fatal_error
!= "":
442 pytest
.skip(fatal_error
)
444 print("\n\n** Verifying Nexthop Groups")
445 print("******************************************\n")
447 ### Nexthop Group Tests
451 # Create a lib nexthop-group
453 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
456 # Create with sharpd using nexthop-group
457 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
459 verify_route_nexthop_group("2.2.2.1/32")
464 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
467 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
469 verify_route_nexthop_group("2.2.2.2/32")
474 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
478 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
481 verify_route_nexthop_group("3.3.3.1/32", True)
486 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
489 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
491 verify_route_nexthop_group("3.3.3.2/32")
496 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
497 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
500 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
502 verify_route_nexthop_group("4.4.4.1/32")
505 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
506 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
509 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
511 verify_route_nexthop_group("4.4.4.2/32")
513 ## Recursive to 8-Way ECMP
516 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
520 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
523 verify_route_nexthop_group("5.5.5.1/32")
525 ## 4-way ECMP Routes Pointing to Each Other
527 # This is to check for a bug with NH resolution where
528 # routes would infintely resolve to each other blowing
529 # up the resolved-> nexthop pointer.
532 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
533 -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
536 # static route nexthops can recurse to
538 net
["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
540 # Make routes that point to themselves in ecmp
543 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
547 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
551 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
555 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
558 # Get routes and test if has too many (duplicate) nexthops
559 nhg_id
= route_get_nhg_id("6.6.6.1/32")
560 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
562 dups
= re
.findall(r
"(via 1\.1\.1\.1)", output
)
564 # Should find 3, itself is inactive
565 assert len(dups
) == 3, (
566 "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
572 ## Remove all NHG routes
574 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
575 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
576 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
577 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
578 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
579 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
580 net
["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
581 net
["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
582 net
["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
585 def test_rip_status():
587 net
= get_topogen().net
589 # Skip if previous fatal error condition is raised
590 if fatal_error
!= "":
591 pytest
.skip(fatal_error
)
593 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
595 print("\n\n** Verifying RIP status")
596 print("******************************************\n")
598 for i
in range(1, 2):
599 refTableFile
= "%s/r%s/rip_status.ref" % (thisDir
, i
)
600 if os
.path
.isfile(refTableFile
):
601 # Read expected result from file
602 expected
= open(refTableFile
).read().rstrip()
603 # Fix newlines (make them all the same)
604 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
606 # Actual output from router
609 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
612 # Drop time in next due
613 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
614 # Drop time in last update
615 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
616 # Fix newlines (make them all the same)
617 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
620 diff
= topotest
.get_textdiff(
623 title1
="actual IP RIP status",
624 title2
="expected IP RIP status",
627 # Empty string if it matches, otherwise diff contains unified diff
629 sys
.stderr
.write("r%s failed IP RIP status check:\n%s\n" % (i
, diff
))
634 assert failures
== 0, "IP RIP status failed for router r%s:\n%s" % (i
, diff
)
636 # Make sure that all daemons are running
637 for i
in range(1, 2):
638 fatal_error
= net
["r%s" % i
].checkRouterRunning()
639 assert fatal_error
== "", fatal_error
641 # For debugging after starting FRR daemons, uncomment the next line
645 def test_ripng_status():
647 net
= get_topogen().net
649 # Skip if previous fatal error condition is raised
650 if fatal_error
!= "":
651 pytest
.skip(fatal_error
)
653 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
655 print("\n\n** Verifying RIPng status")
656 print("******************************************\n")
658 for i
in range(1, 2):
659 refTableFile
= "%s/r%s/ripng_status.ref" % (thisDir
, i
)
660 if os
.path
.isfile(refTableFile
):
661 # Read expected result from file
662 expected
= open(refTableFile
).read().rstrip()
663 # Fix newlines (make them all the same)
664 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
666 # Actual output from router
669 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
672 # Mask out Link-Local mac address portion. They are random...
673 actual
= re
.sub(r
" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual
)
674 # Drop time in next due
675 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
676 # Drop time in last update
677 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
678 # Fix newlines (make them all the same)
679 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
682 diff
= topotest
.get_textdiff(
685 title1
="actual IPv6 RIPng status",
686 title2
="expected IPv6 RIPng status",
689 # Empty string if it matches, otherwise diff contains unified diff
692 "r%s failed IPv6 RIPng status check:\n%s\n" % (i
, diff
)
698 assert failures
== 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
703 # Make sure that all daemons are running
704 for i
in range(1, 2):
705 fatal_error
= net
["r%s" % i
].checkRouterRunning()
706 assert fatal_error
== "", fatal_error
708 # For debugging after starting FRR daemons, uncomment the next line
712 def test_ospfv2_interfaces():
714 net
= get_topogen().net
716 # Skip if previous fatal error condition is raised
717 if fatal_error
!= "":
718 pytest
.skip(fatal_error
)
720 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
722 print("\n\n** Verifying OSPFv2 interfaces")
723 print("******************************************\n")
725 for i
in range(1, 2):
726 refTableFile
= "%s/r%s/show_ip_ospf_interface.ref" % (thisDir
, i
)
727 if os
.path
.isfile(refTableFile
):
728 # Read expected result from file
729 expected
= open(refTableFile
).read().rstrip()
730 # Fix newlines (make them all the same)
731 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
733 # Actual output from router
736 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
739 # Mask out Bandwidth portion. They may change..
740 actual
= re
.sub(r
"BW [0-9]+ Mbit", "BW XX Mbit", actual
)
741 actual
= re
.sub(r
"ifindex [0-9]+", "ifindex X", actual
)
743 # Drop time in next due
744 actual
= re
.sub(r
"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual
)
746 r
"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
748 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
750 r
"MTU mismatch detection:([a-z]+.*)",
751 r
"MTU mismatch detection: \1",
754 # Fix newlines (make them all the same)
755 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
758 diff
= topotest
.get_textdiff(
761 title1
="actual SHOW IP OSPF INTERFACE",
762 title2
="expected SHOW IP OSPF INTERFACE",
765 # Empty string if it matches, otherwise diff contains unified diff
768 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i
, diff
)
774 # Ignoring the issue if told to ignore (ie not yet fixed)
776 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
778 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
781 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
786 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i
, diff
)
788 # Make sure that all daemons are running
789 for i
in range(1, 2):
790 fatal_error
= net
["r%s" % i
].checkRouterRunning()
791 assert fatal_error
== "", fatal_error
793 # For debugging after starting FRR daemons, uncomment the next line
797 def test_isis_interfaces():
799 net
= get_topogen().net
801 # Skip if previous fatal error condition is raised
802 if fatal_error
!= "":
803 pytest
.skip(fatal_error
)
805 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
807 print("\n\n** Verifying ISIS interfaces")
808 print("******************************************\n")
810 for i
in range(1, 2):
811 refTableFile
= "%s/r%s/show_isis_interface_detail.ref" % (thisDir
, i
)
812 if os
.path
.isfile(refTableFile
):
813 # Read expected result from file
814 expected
= open(refTableFile
).read().rstrip()
815 # Fix newlines (make them all the same)
816 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
818 # Actual output from router
821 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
824 # Mask out Link-Local mac address portion. They are random...
825 actual
= re
.sub(r
"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual
)
826 # Mask out SNPA mac address portion. They are random...
827 actual
= re
.sub(r
"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual
)
828 # Mask out Circuit ID number
829 actual
= re
.sub(r
"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual
)
830 # Fix newlines (make them all the same)
831 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
834 diff
= topotest
.get_textdiff(
837 title1
="actual SHOW ISIS INTERFACE DETAIL",
838 title2
="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
841 # Empty string if it matches, otherwise diff contains unified diff
844 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i
, diff
)
852 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i
, diff
)
854 # Make sure that all daemons are running
855 for i
in range(1, 2):
856 fatal_error
= net
["r%s" % i
].checkRouterRunning()
857 assert fatal_error
== "", fatal_error
859 # For debugging after starting FRR daemons, uncomment the next line
863 def test_bgp_summary():
865 net
= get_topogen().net
867 # Skip if previous fatal error condition is raised
868 if fatal_error
!= "":
869 pytest
.skip(fatal_error
)
871 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
873 print("\n\n** Verifying BGP Summary")
874 print("******************************************\n")
876 for i
in range(1, 2):
877 refTableFile
= "%s/r%s/show_ip_bgp_summary.ref" % (thisDir
, i
)
878 if os
.path
.isfile(refTableFile
):
879 # Read expected result from file
880 expected_original
= open(refTableFile
).read().rstrip()
884 "remote-as internal",
885 "remote-as external",
888 "neighbor 192.168.7.10",
889 "neighbor 192.168.7.10",
890 "neighbor fc00:0:0:8::1000",
893 "remote-as internal terse",
894 "remote-as external terse",
895 "remote-as 100 terse",
896 "remote-as 123 terse",
897 "neighbor 192.168.7.10 terse",
898 "neighbor 192.168.7.10 terse",
899 "neighbor fc00:0:0:8::1000 terse",
900 "neighbor 10.0.0.1 terse",
902 # Actual output from router
906 'vtysh -c "show ip bgp summary ' + arguments
+ '" 2> /dev/null'
911 # Mask out "using XXiXX bytes" portion. They are random...
912 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
913 # Mask out "using XiXXX KiB" portion. They are random...
914 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
916 # Remove extra summaries which exist with newer versions
918 # Remove summary lines (changed recently)
919 actual
= re
.sub(r
"Total number.*", "", actual
)
920 actual
= re
.sub(r
"Displayed.*", "", actual
)
921 # Remove IPv4 Unicast Summary (Title only)
922 actual
= re
.sub(r
"IPv4 Unicast Summary \(VRF default\):", "", actual
)
923 # Remove IPv4 Multicast Summary (all of it)
924 actual
= re
.sub(r
"IPv4 Multicast Summary \(VRF default\):", "", actual
)
925 actual
= re
.sub(r
"No IPv4 Multicast neighbor is configured", "", actual
)
926 # Remove IPv4 VPN Summary (all of it)
927 actual
= re
.sub(r
"IPv4 VPN Summary \(VRF default\):", "", actual
)
928 actual
= re
.sub(r
"No IPv4 VPN neighbor is configured", "", actual
)
929 # Remove IPv4 Encap Summary (all of it)
930 actual
= re
.sub(r
"IPv4 Encap Summary \(VRF default\):", "", actual
)
931 actual
= re
.sub(r
"No IPv4 Encap neighbor is configured", "", actual
)
932 # Remove Unknown Summary (all of it)
933 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
934 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
935 # Make Connect/Active/Idle the same (change them all to Active)
936 actual
= re
.sub(r
" Connect ", " Active ", actual
)
937 actual
= re
.sub(r
" Idle ", " Active ", actual
)
940 r
"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
943 r
"No IPv4 labeled-unicast neighbor is configured", "", actual
946 expected
= expected_original
947 # apply argumentss on expected output
948 if "internal" in arguments
or "remote-as 100" in arguments
:
949 expected
= re
.sub(r
".+\s+200\s+.+", "", expected
)
950 elif "external" in arguments
:
951 expected
= re
.sub(r
".+\s+100\s+.+Active.+", "", expected
)
952 elif "remote-as 123" in arguments
:
954 r
"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
958 expected
= re
.sub(r
"\nNeighbor.+Desc", "", expected
)
959 expected
= expected
+ "% No matching neighbor\n"
960 elif "192.168.7.10" in arguments
:
962 r
"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
964 elif "fc00:0:0:8::1000" in arguments
:
966 r
"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
968 elif "10.0.0.1" in arguments
:
969 expected
= "No such neighbor in this view/vrf"
971 if "terse" in arguments
:
972 expected
= re
.sub(r
"BGP table version .+", "", expected
)
973 expected
= re
.sub(r
"RIB entries .+", "", expected
)
974 expected
= re
.sub(r
"Peers [0-9]+, using .+", "", expected
)
977 actual
= actual
.lstrip().rstrip()
978 expected
= expected
.lstrip().rstrip()
979 actual
= re
.sub(r
"\n+", "\n", actual
)
980 expected
= re
.sub(r
"\n+", "\n", expected
)
982 # reapply initial formatting
983 if "terse" in arguments
:
984 actual
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", actual
)
985 expected
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", expected
)
987 actual
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", actual
)
988 expected
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", expected
)
990 # realign expected neighbor columns if needed
993 re
.search(r
"(Neighbor\s+V\s+)", actual
).group(1).find("V")
996 re
.search(r
"(Neighbor\s+V\s+)", expected
).group(1).find("V")
998 idx_diff
= idx_expected
- idx_actual
1000 # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
1001 expected
= re
.sub(" " * idx_diff
+ "V ", "V ", expected
)
1002 # 192.168.7.10 4 100 0 0 0 0 0 never Active
1003 expected
= re
.sub(" " * idx_diff
+ "4 ", "4 ", expected
)
1004 except AttributeError:
1007 # Fix newlines (make them all the same)
1008 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1009 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1012 diff
= topotest
.get_textdiff(
1015 title1
="actual SHOW IP BGP SUMMARY " + arguments
.upper(),
1016 title2
="expected SHOW IP BGP SUMMARY " + arguments
.upper(),
1019 # Empty string if it matches, otherwise diff contains unified diff
1022 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i
, diff
)
1030 ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
1035 # Make sure that all daemons are running
1036 for i
in range(1, 2):
1037 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1038 assert fatal_error
== "", fatal_error
1040 # For debugging after starting FRR daemons, uncomment the next line
1044 def test_bgp_ipv6_summary():
1046 net
= get_topogen().net
1048 # Skip if previous fatal error condition is raised
1049 if fatal_error
!= "":
1050 pytest
.skip(fatal_error
)
1052 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1054 print("\n\n** Verifying BGP IPv6 Summary")
1055 print("******************************************\n")
1057 for i
in range(1, 2):
1058 refTableFile
= "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir
, i
)
1059 if os
.path
.isfile(refTableFile
):
1060 # Read expected result from file
1061 expected
= open(refTableFile
).read().rstrip()
1062 # Fix newlines (make them all the same)
1063 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1065 # Actual output from router
1068 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
1071 # Mask out "using XXiXX bytes" portion. They are random...
1072 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
1073 # Mask out "using XiXXX KiB" portion. They are random...
1074 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
1076 # Remove extra summaries which exist with newer versions
1078 # Remove summary lines (changed recently)
1079 actual
= re
.sub(r
"Total number.*", "", actual
)
1080 actual
= re
.sub(r
"Displayed.*", "", actual
)
1081 # Remove IPv4 Unicast Summary (Title only)
1082 actual
= re
.sub(r
"IPv6 Unicast Summary \(VRF default\):", "", actual
)
1083 # Remove IPv4 Multicast Summary (all of it)
1084 actual
= re
.sub(r
"IPv6 Multicast Summary \(VRF default\):", "", actual
)
1085 actual
= re
.sub(r
"No IPv6 Multicast neighbor is configured", "", actual
)
1086 # Remove IPv4 VPN Summary (all of it)
1087 actual
= re
.sub(r
"IPv6 VPN Summary \(VRF default\):", "", actual
)
1088 actual
= re
.sub(r
"No IPv6 VPN neighbor is configured", "", actual
)
1089 # Remove IPv4 Encap Summary (all of it)
1090 actual
= re
.sub(r
"IPv6 Encap Summary \(VRF default\):", "", actual
)
1091 actual
= re
.sub(r
"No IPv6 Encap neighbor is configured", "", actual
)
1092 # Remove Unknown Summary (all of it)
1093 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
1094 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
1095 # Make Connect/Active/Idle the same (change them all to Active)
1096 actual
= re
.sub(r
" Connect ", " Active ", actual
)
1097 actual
= re
.sub(r
" Idle ", " Active ", actual
)
1099 # Remove Labeled Unicast Summary (all of it)
1101 r
"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
1104 r
"No IPv6 labeled-unicast neighbor is configured", "", actual
1108 actual
= actual
.lstrip()
1109 actual
= actual
.rstrip()
1111 # Fix newlines (make them all the same)
1112 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1115 diff
= topotest
.get_textdiff(
1118 title1
="actual SHOW BGP IPv6 SUMMARY",
1119 title2
="expected SHOW BGP IPv6 SUMMARY",
1122 # Empty string if it matches, otherwise diff contains unified diff
1125 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i
, diff
)
1131 assert failures
== 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1136 # Make sure that all daemons are running
1137 for i
in range(1, 2):
1138 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1139 assert fatal_error
== "", fatal_error
1141 # For debugging after starting FRR daemons, uncomment the next line
1146 net
= get_topogen().net
1147 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1149 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1151 for i
in range(1, 2):
1152 nhtFile
= "%s/r%s/ip_nht.ref" % (thisDir
, i
)
1153 expected
= open(nhtFile
).read().rstrip()
1154 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1156 actual
= net
["r%s" % i
].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
1157 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1158 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1160 diff
= topotest
.get_textdiff(
1163 title1
="Actual `show ip nht`",
1164 title2
="Expected `show ip nht`",
1168 assert 0, "r%s failed ip nht check:\n%s\n" % (i
, diff
)
1170 print("show ip nht is ok\n")
1172 nhtFile
= "%s/r%s/ipv6_nht.ref" % (thisDir
, i
)
1173 expected
= open(nhtFile
).read().rstrip()
1174 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1176 actual
= net
["r%s" % i
].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
1177 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1178 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1180 diff
= topotest
.get_textdiff(
1183 title1
="Actual `show ip nht`",
1184 title2
="Expected `show ip nht`",
1188 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i
, diff
)
1190 print("show ipv6 nht is ok\n")
1193 def test_bgp_ipv4():
1195 net
= get_topogen().net
1197 # Skip if previous fatal error condition is raised
1198 if fatal_error
!= "":
1199 pytest
.skip(fatal_error
)
1201 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1203 print("\n\n** Verifying BGP IPv4")
1204 print("******************************************\n")
1206 for i
in range(1, 2):
1208 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir
, i
)):
1209 if os
.path
.isfile(refTableFile
):
1210 # Read expected result from file
1211 expected
= open(refTableFile
).read().rstrip()
1212 # Fix newlines (make them all the same)
1213 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1215 # Actual output from router
1217 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1219 # Remove summary line (changed recently)
1220 actual
= re
.sub(r
"Total number.*", "", actual
)
1221 actual
= re
.sub(r
"Displayed.*", "", actual
)
1222 actual
= actual
.rstrip()
1223 # Fix newlines (make them all the same)
1224 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1227 diff
= topotest
.get_textdiff(
1230 title1
="actual SHOW BGP IPv4",
1231 title2
="expected SHOW BGP IPv4",
1234 # Empty string if it matches, otherwise diff contains unified diff
1236 diffresult
[refTableFile
] = diff
1239 print("template %s matched: r%s ok" % (refTableFile
, i
))
1243 resultstr
= "No template matched.\n"
1244 for f
in diffresult
.keys():
1245 resultstr
+= "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1250 raise AssertionError(
1251 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i
, resultstr
)
1254 # Make sure that all daemons are running
1255 for i
in range(1, 2):
1256 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1257 assert fatal_error
== "", fatal_error
1259 # For debugging after starting FRR daemons, uncomment the next line
1263 def test_bgp_ipv6():
1265 net
= get_topogen().net
1267 # Skip if previous fatal error condition is raised
1268 if fatal_error
!= "":
1269 pytest
.skip(fatal_error
)
1271 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1273 print("\n\n** Verifying BGP IPv6")
1274 print("******************************************\n")
1276 for i
in range(1, 2):
1278 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir
, i
)):
1279 if os
.path
.isfile(refTableFile
):
1280 # Read expected result from file
1281 expected
= open(refTableFile
).read().rstrip()
1282 # Fix newlines (make them all the same)
1283 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1285 # Actual output from router
1287 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1289 # Remove summary line (changed recently)
1290 actual
= re
.sub(r
"Total number.*", "", actual
)
1291 actual
= re
.sub(r
"Displayed.*", "", actual
)
1292 actual
= actual
.rstrip()
1293 # Fix newlines (make them all the same)
1294 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1297 diff
= topotest
.get_textdiff(
1300 title1
="actual SHOW BGP IPv6",
1301 title2
="expected SHOW BGP IPv6",
1304 # Empty string if it matches, otherwise diff contains unified diff
1306 diffresult
[refTableFile
] = diff
1309 print("template %s matched: r%s ok" % (refTableFile
, i
))
1312 resultstr
= "No template matched.\n"
1313 for f
in diffresult
.keys():
1314 resultstr
+= "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1319 raise AssertionError(
1320 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i
, resultstr
)
1323 # Make sure that all daemons are running
1324 for i
in range(1, 2):
1325 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1326 assert fatal_error
== "", fatal_error
1328 # For debugging after starting FRR daemons, uncomment the next line
1332 def test_route_map():
1334 net
= get_topogen().net
1336 if fatal_error
!= "":
1337 pytest
.skip(fatal_error
)
1339 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1341 print("\n\n** Verifying some basic routemap forward references\n")
1342 print("*******************************************************\n")
1344 for i
in range(1, 2):
1345 refroutemap
= "%s/r%s/show_route_map.ref" % (thisDir
, i
)
1346 if os
.path
.isfile(refroutemap
):
1347 expected
= open(refroutemap
).read().rstrip()
1348 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1351 net
["r%s" % i
].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1353 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1355 diff
= topotest
.get_textdiff(
1358 title1
="actual show route-map",
1359 title2
="expected show route-map",
1364 "r%s failed show route-map command Check:\n%s\n" % (i
, diff
)
1372 ), "Show route-map command failed for router r%s:\n%s" % (i
, diff
)
1375 def test_nexthop_groups_with_route_maps():
1377 net
= get_topogen().net
1379 # Skip if previous fatal error condition is raised
1380 if fatal_error
!= "":
1381 pytest
.skip(fatal_error
)
1383 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1384 print("******************************************\n")
1386 ### Nexthop Group With Route-Map Tests
1388 # Create a lib nexthop-group
1390 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1393 ## Route-Map Proto Source
1395 route_str
= "2.2.2.1"
1396 src_str
= "192.168.0.1"
1399 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1401 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1403 net
["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str
)
1405 verify_route_nexthop_group("%s/32" % route_str
)
1407 # Only a valid test on linux using nexthop objects
1408 if sys
.platform
.startswith("linux"):
1409 output
= net
["r1"].cmd("ip route show %s/32" % route_str
)
1410 match
= re
.search(r
"src %s" % src_str
, output
)
1411 assert match
is not None, "Route %s/32 not installed with src %s" % (
1416 # Remove NHG routes and route-map
1417 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str
)
1418 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
1420 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
1422 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1424 ## Route-Map Deny/Permit with same nexthop group
1426 permit_route_str
= "3.3.3.1"
1427 deny_route_str
= "3.3.3.2"
1430 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1433 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1435 net
["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1436 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1438 # This route should be permitted
1440 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1443 verify_route_nexthop_group("%s/32" % permit_route_str
)
1445 # This route should be denied
1447 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1450 nhg_id
= route_get_nhg_id(deny_route_str
)
1451 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
1453 match
= re
.search(r
"Valid", output
)
1454 assert match
is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1456 match
= re
.search(r
"Installed", output
)
1457 assert match
is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1459 # Remove NHG routes and route-map
1460 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str
)
1461 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str
)
1462 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1463 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1464 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1465 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
1467 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1472 def test_nexthop_group_replace():
1474 net
= get_topogen().net
1476 # Skip if previous fatal error condition is raised
1477 if fatal_error
!= "":
1478 pytest
.skip(fatal_error
)
1480 print("\n\n** Verifying Nexthop Groups")
1481 print("******************************************\n")
1483 ### Nexthop Group Tests
1485 ## 2-Way ECMP Directly Connected
1488 '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"'
1491 # Create with sharpd using nexthop-group
1492 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1494 verify_route_nexthop_group("3.3.3.1/32")
1496 # Change the nexthop group
1498 '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"'
1501 # Verify it updated. We can just check install and ecmp count here.
1502 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1505 def test_mpls_interfaces():
1507 net
= get_topogen().net
1509 # Skip if previous fatal error condition is raised
1510 if fatal_error
!= "":
1511 pytest
.skip(fatal_error
)
1513 # Skip if no LDP installed or old kernel
1514 if net
["r1"].daemon_available("ldpd") == False:
1515 pytest
.skip("No MPLS or kernel < 4.5")
1517 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1519 print("\n\n** Verifying MPLS Interfaces")
1520 print("******************************************\n")
1522 for i
in range(1, 2):
1523 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir
, i
)
1524 if os
.path
.isfile(refTableFile
):
1525 # Read expected result from file
1526 expected
= open(refTableFile
).read().rstrip()
1527 # Fix newlines (make them all the same)
1528 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1530 # Actual output from router
1533 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1536 # Mask out Timer in Uptime
1537 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
1538 # Fix newlines (make them all the same)
1539 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1542 diff
= topotest
.get_textdiff(
1545 title1
="actual MPLS LDP interface status",
1546 title2
="expected MPLS LDP interface status",
1549 # Empty string if it matches, otherwise diff contains unified diff
1552 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
1559 fatal_error
= "MPLS LDP Interface status failed"
1563 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
1565 # Make sure that all daemons are running
1566 for i
in range(1, 2):
1567 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1568 assert fatal_error
== "", fatal_error
1570 # For debugging after starting FRR daemons, uncomment the next line
1574 def test_shutdown_check_stderr():
1576 net
= get_topogen().net
1578 # Skip if previous fatal error condition is raised
1579 if fatal_error
!= "":
1580 pytest
.skip(fatal_error
)
1582 print("\n\n** Verifying unexpected STDERR output from daemons")
1583 print("******************************************\n")
1585 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
1587 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1589 pytest
.skip("Skipping test for Stderr output")
1591 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1593 print("thisDir=" + thisDir
)
1595 net
["r1"].stopRouter()
1597 log
= net
["r1"].getStdErr("ripd")
1599 print("\nRIPd StdErr Log:\n" + log
)
1600 log
= net
["r1"].getStdErr("ripngd")
1602 print("\nRIPngd StdErr Log:\n" + log
)
1603 log
= net
["r1"].getStdErr("ospfd")
1605 print("\nOSPFd StdErr Log:\n" + log
)
1606 log
= net
["r1"].getStdErr("ospf6d")
1608 print("\nOSPF6d StdErr Log:\n" + log
)
1609 log
= net
["r1"].getStdErr("isisd")
1611 print("\nISISd StdErr Log:\n" + log
)
1612 log
= net
["r1"].getStdErr("bgpd")
1614 print("\nBGPd StdErr Log:\n" + log
)
1616 log
= net
["r1"].getStdErr("nhrpd")
1618 print("\nNHRPd StdErr Log:\n" + log
)
1620 log
= net
["r1"].getStdErr("pbrd")
1622 print("\nPBRd StdErr Log:\n" + log
)
1624 log
= net
["r1"].getStdErr("babeld")
1626 print("\nBABELd StdErr Log:\n" + log
)
1628 if net
["r1"].daemon_available("ldpd"):
1629 log
= net
["r1"].getStdErr("ldpd")
1631 print("\nLDPd StdErr Log:\n" + log
)
1632 log
= net
["r1"].getStdErr("zebra")
1634 print("\nZebra StdErr Log:\n" + log
)
1637 def test_shutdown_check_memleak():
1639 net
= get_topogen().net
1641 # Skip if previous fatal error condition is raised
1642 if fatal_error
!= "":
1643 pytest
.skip(fatal_error
)
1645 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1647 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1649 pytest
.skip("Skipping test for memory leaks")
1651 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1653 for i
in range(1, 2):
1654 net
["r%s" % i
].stopRouter()
1655 net
["r%s" % i
].report_memory_leaks(
1656 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
1660 if __name__
== "__main__":
1661 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1662 # retval = pytest.main(["-s", "--tb=no"])
1663 retval
= pytest
.main(["-s"])