]>
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
47 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
48 from lib
import topotest
49 from lib
.topogen
import Topogen
, get_topogen
54 #####################################################
56 ## Network Topology Definition
58 #####################################################
62 router
= tgen
.add_router("r1")
63 for i
in range(0, 10):
64 tgen
.add_switch("sw%d" % i
).add_link(router
)
67 #####################################################
71 #####################################################
74 def setup_module(module
):
77 print("\n\n** %s: Setup Topology" % module
.__name
__)
78 print("******************************************\n")
80 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
81 tgen
= Topogen(build_topo
, module
.__name
__)
86 if net
["r1"].get_routertype() != "frr":
87 fatal_error
= "Test is only implemented for FRR"
88 sys
.stderr
.write("\n\nTest is only implemented for FRR - Skipping\n\n")
89 pytest
.skip(fatal_error
)
95 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
96 net
["r%s" % i
].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir
, i
))
97 net
["r%s" % i
].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir
, i
))
98 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
99 if net
["r1"].checkRouterVersion("<", "4.0"):
100 net
["r%s" % i
].loadConf(
101 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir
, i
)
104 net
["r%s" % i
].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir
, i
))
105 net
["r%s" % i
].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir
, i
))
106 net
["r%s" % i
].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir
, i
))
107 if net
["r%s" % i
].daemon_available("ldpd"):
108 # Only test LDPd if it's installed and Kernel >= 4.5
109 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
110 net
["r%s" % i
].loadConf("sharpd")
111 net
["r%s" % i
].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir
, i
))
112 net
["r%s" % i
].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir
, i
))
113 net
["r%s" % i
].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir
, i
))
114 tgen
.gears
["r%s" % i
].start()
116 # For debugging after starting FRR daemons, uncomment the next line
120 def teardown_module(module
):
121 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
122 print("******************************************\n")
127 def test_router_running():
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
202 def test_error_messages_daemons():
204 net
= get_topogen().net
206 # Skip if previous fatal error condition is raised
207 if fatal_error
!= "":
208 pytest
.skip(fatal_error
)
210 print("\n\n** Check for error messages in daemons")
211 print("******************************************\n")
215 for i
in range(1, 2):
216 log
= net
["r%s" % i
].getStdErr("ripd")
218 error_logs
+= "r%s RIPd StdErr Output:\n" % i
220 log
= net
["r%s" % i
].getStdErr("ripngd")
222 error_logs
+= "r%s RIPngd StdErr Output:\n" % i
224 log
= net
["r%s" % i
].getStdErr("ospfd")
226 error_logs
+= "r%s OSPFd StdErr Output:\n" % i
228 log
= net
["r%s" % i
].getStdErr("ospf6d")
230 error_logs
+= "r%s OSPF6d StdErr Output:\n" % i
232 log
= net
["r%s" % i
].getStdErr("isisd")
233 # ISIS shows debugging enabled status on StdErr
234 # Remove these messages
235 log
= re
.sub(r
"^IS-IS .* debugging is on.*", "", log
).rstrip()
237 error_logs
+= "r%s ISISd StdErr Output:\n" % i
239 log
= net
["r%s" % i
].getStdErr("bgpd")
241 error_logs
+= "r%s BGPd StdErr Output:\n" % i
243 if net
["r%s" % i
].daemon_available("ldpd"):
244 log
= net
["r%s" % i
].getStdErr("ldpd")
246 error_logs
+= "r%s LDPd StdErr Output:\n" % i
249 log
= net
["r1"].getStdErr("nhrpd")
250 # NHRPD shows YANG model not embedded messages
252 log
= re
.sub(r
".*YANG model.*not embedded.*", "", log
).rstrip()
254 error_logs
+= "r%s NHRPd StdErr Output:\n" % i
257 log
= net
["r1"].getStdErr("babeld")
259 error_logs
+= "r%s BABELd StdErr Output:\n" % i
262 log
= net
["r1"].getStdErr("pbrd")
264 error_logs
+= "r%s PBRd StdErr Output:\n" % i
267 log
= net
["r%s" % i
].getStdErr("zebra")
269 error_logs
+= "r%s Zebra StdErr Output:\n" % i
274 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
277 # Ignoring the issue if told to ignore (ie not yet fixed)
279 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
281 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
284 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
287 assert error_logs
== "", "Daemons report errors to StdErr"
290 def test_converge_protocols():
292 net
= get_topogen().net
294 # Skip if previous fatal error condition is raised
295 if fatal_error
!= "":
296 pytest
.skip(fatal_error
)
298 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
300 print("\n\n** Waiting for protocols convergence")
301 print("******************************************\n")
303 # Not really implemented yet - just sleep 60 secs for now
306 # Make sure that all daemons are running
308 for i
in range(1, 2):
309 fatal_error
= net
["r%s" % i
].checkRouterRunning()
310 assert fatal_error
== "", fatal_error
312 print("Show that v4 routes are right\n")
313 v4_routesFile
= "%s/r%s/ipv4_routes.ref" % (thisDir
, i
)
315 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v4_routesFile
)).rstrip()
317 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
322 "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
326 # Drop time in last update
327 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
328 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
329 diff
= topotest
.get_textdiff(
332 title1
="Actual IP Routing Table",
333 title2
="Expected IP RoutingTable",
336 sys
.stderr
.write("r%s failed IP Routing table check:\n%s\n" % (i
, diff
))
341 assert failures
== 0, "IP Routing table failed for r%s\n%s" % (i
, diff
)
345 print("Show that v6 routes are right\n")
346 v6_routesFile
= "%s/r%s/ipv6_routes.ref" % (thisDir
, i
)
348 net
["r%s" % i
].cmd("sort {} 2> /dev/null".format(v6_routesFile
)).rstrip()
350 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
355 "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
359 # Drop time in last update
360 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
361 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
362 diff
= topotest
.get_textdiff(
365 title1
="Actual IPv6 Routing Table",
366 title2
="Expected IPv6 RoutingTable",
369 sys
.stderr
.write("r%s failed IPv6 Routing table check:\n%s\n" % (i
, diff
))
374 assert failures
== 0, "IPv6 Routing table failed for r%s\n%s" % (i
, diff
)
377 def route_get_nhg_id(route_str
):
378 net
= get_topogen().net
379 output
= net
["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str
)
380 match
= re
.search(r
"Nexthop Group ID: (\d+)", output
)
381 assert match
is not None, (
382 "Nexthop Group ID not found for sharpd route %s" % route_str
385 nhg_id
= int(match
.group(1))
389 def verify_nexthop_group(nhg_id
, recursive
=False, ecmp
=0):
390 net
= get_topogen().net
399 while not found
and count
< 10:
401 # Verify NHG is valid/installed
402 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
403 valid
= re
.search(r
"Valid", output
)
409 if ecmp
or recursive
:
410 ecmpcount
= re
.search(r
"Depends:.*\n", output
)
411 if ecmpcount
is None:
416 # list of IDs in group
417 depends
= re
.findall(r
"\((\d+)\)", ecmpcount
.group(0))
420 if len(depends
) != ecmp
:
425 # If recursive, we need to look at its resolved group
426 if len(depends
) != 1:
431 resolved_id
= int(depends
[0])
432 verify_nexthop_group(resolved_id
, False)
434 installed
= re
.search(r
"Installed", output
)
435 if installed
is None:
441 assert valid
is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
442 if ecmp
or recursive
:
443 assert ecmpcount
is not None, "Nexthop Group ID=%d has no depends" % nhg_id
445 assert len(depends
) == ecmp
, (
446 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
449 assert len(depends
) == 1, (
450 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
453 assert installed
is not None, (
454 "Nexthop Group ID=%d not marked Installed" % nhg_id
458 def verify_route_nexthop_group(route_str
, recursive
=False, ecmp
=0):
459 # Verify route and that zebra created NHGs for and they are valid/installed
460 nhg_id
= route_get_nhg_id(route_str
)
461 verify_nexthop_group(nhg_id
, recursive
, ecmp
)
464 def test_nexthop_groups():
466 net
= get_topogen().net
468 # Skip if previous fatal error condition is raised
469 if fatal_error
!= "":
470 pytest
.skip(fatal_error
)
472 print("\n\n** Verifying Nexthop Groups")
473 print("******************************************\n")
475 ### Nexthop Group Tests
479 # Create a lib nexthop-group
481 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
484 # Create with sharpd using nexthop-group
485 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
486 verify_route_nexthop_group("2.2.2.1/32")
491 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
494 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
495 verify_route_nexthop_group("2.2.2.2/32")
500 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
504 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
507 verify_route_nexthop_group("3.3.3.1/32", True)
512 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
515 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
517 verify_route_nexthop_group("3.3.3.2/32")
522 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
523 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
526 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
528 verify_route_nexthop_group("4.4.4.1/32")
531 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
532 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
535 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
537 verify_route_nexthop_group("4.4.4.2/32")
539 ## Recursive to 8-Way ECMP
542 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
546 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
549 verify_route_nexthop_group("5.5.5.1/32")
551 ## 4-way ECMP Routes Pointing to Each Other
553 # This is to check for a bug with NH resolution where
554 # routes would infintely resolve to each other blowing
555 # up the resolved-> nexthop pointer.
558 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
559 -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
562 # static route nexthops can recurse to
564 net
["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
566 # Make routes that point to themselves in ecmp
569 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
574 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
579 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
584 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
587 # Get routes and test if has too many (duplicate) nexthops
590 nhg_id
= route_get_nhg_id("6.6.6.1/32")
591 while (len(dups
) != 3) and count
< 10:
592 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
594 dups
= re
.findall(r
"(via 1\.1\.1\.1)", output
)
599 # Should find 3, itself is inactive
600 assert len(dups
) == 3, (
601 "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
605 ## Remove all NHG routes
607 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
608 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
609 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
610 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
611 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
612 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
613 net
["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
614 net
["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
615 net
["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
618 def test_rip_status():
620 net
= get_topogen().net
622 # Skip if previous fatal error condition is raised
623 if fatal_error
!= "":
624 pytest
.skip(fatal_error
)
626 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
628 print("\n\n** Verifying RIP status")
629 print("******************************************\n")
631 for i
in range(1, 2):
632 refTableFile
= "%s/r%s/rip_status.ref" % (thisDir
, i
)
633 if os
.path
.isfile(refTableFile
):
634 # Read expected result from file
635 expected
= open(refTableFile
).read().rstrip()
636 # Fix newlines (make them all the same)
637 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
639 # Actual output from router
642 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
645 # Drop time in next due
646 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
647 # Drop time in last update
648 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
649 # Fix newlines (make them all the same)
650 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
653 diff
= topotest
.get_textdiff(
656 title1
="actual IP RIP status",
657 title2
="expected IP RIP status",
660 # Empty string if it matches, otherwise diff contains unified diff
662 sys
.stderr
.write("r%s failed IP RIP status check:\n%s\n" % (i
, diff
))
667 assert failures
== 0, "IP RIP status failed for router r%s:\n%s" % (i
, diff
)
669 # Make sure that all daemons are running
670 for i
in range(1, 2):
671 fatal_error
= net
["r%s" % i
].checkRouterRunning()
672 assert fatal_error
== "", fatal_error
675 def test_ripng_status():
677 net
= get_topogen().net
679 # Skip if previous fatal error condition is raised
680 if fatal_error
!= "":
681 pytest
.skip(fatal_error
)
683 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
685 print("\n\n** Verifying RIPng status")
686 print("******************************************\n")
688 for i
in range(1, 2):
689 refTableFile
= "%s/r%s/ripng_status.ref" % (thisDir
, i
)
690 if os
.path
.isfile(refTableFile
):
691 # Read expected result from file
692 expected
= open(refTableFile
).read().rstrip()
693 # Fix newlines (make them all the same)
694 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
696 # Actual output from router
699 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
702 # Mask out Link-Local mac address portion. They are random...
703 actual
= re
.sub(r
" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual
)
704 # Drop time in next due
705 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
706 # Drop time in last update
707 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
708 # Fix newlines (make them all the same)
709 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
712 diff
= topotest
.get_textdiff(
715 title1
="actual IPv6 RIPng status",
716 title2
="expected IPv6 RIPng status",
719 # Empty string if it matches, otherwise diff contains unified diff
722 "r%s failed IPv6 RIPng status check:\n%s\n" % (i
, diff
)
728 assert failures
== 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
733 # Make sure that all daemons are running
734 for i
in range(1, 2):
735 fatal_error
= net
["r%s" % i
].checkRouterRunning()
736 assert fatal_error
== "", fatal_error
739 def test_ospfv2_interfaces():
741 net
= get_topogen().net
743 # Skip if previous fatal error condition is raised
744 if fatal_error
!= "":
745 pytest
.skip(fatal_error
)
747 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
749 print("\n\n** Verifying OSPFv2 interfaces")
750 print("******************************************\n")
752 for i
in range(1, 2):
753 refTableFile
= "%s/r%s/show_ip_ospf_interface.ref" % (thisDir
, i
)
754 if os
.path
.isfile(refTableFile
):
755 # Read expected result from file
756 expected
= open(refTableFile
).read().rstrip()
757 # Fix newlines (make them all the same)
758 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
760 # Actual output from router
763 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
766 # Mask out Bandwidth portion. They may change..
767 actual
= re
.sub(r
"BW [0-9]+ Mbit", "BW XX Mbit", actual
)
768 actual
= re
.sub(r
"ifindex [0-9]+", "ifindex X", actual
)
770 # Drop time in next due
771 actual
= re
.sub(r
"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual
)
773 r
"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
775 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
777 r
"MTU mismatch detection:([a-z]+.*)",
778 r
"MTU mismatch detection: \1",
781 # Fix newlines (make them all the same)
782 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
785 diff
= topotest
.get_textdiff(
788 title1
="actual SHOW IP OSPF INTERFACE",
789 title2
="expected SHOW IP OSPF INTERFACE",
792 # Empty string if it matches, otherwise diff contains unified diff
795 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i
, diff
)
801 # Ignoring the issue if told to ignore (ie not yet fixed)
803 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
805 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
808 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
813 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i
, diff
)
815 # Make sure that all daemons are running
816 for i
in range(1, 2):
817 fatal_error
= net
["r%s" % i
].checkRouterRunning()
818 assert fatal_error
== "", fatal_error
821 def test_isis_interfaces():
823 net
= get_topogen().net
825 # Skip if previous fatal error condition is raised
826 if fatal_error
!= "":
827 pytest
.skip(fatal_error
)
829 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
831 print("\n\n** Verifying ISIS interfaces")
832 print("******************************************\n")
834 for i
in range(1, 2):
835 refTableFile
= "%s/r%s/show_isis_interface_detail.ref" % (thisDir
, i
)
836 if os
.path
.isfile(refTableFile
):
837 # Read expected result from file
838 expected
= open(refTableFile
).read().rstrip()
839 # Fix newlines (make them all the same)
840 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
842 # Actual output from router
845 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
848 # Mask out Link-Local mac address portion. They are random...
849 actual
= re
.sub(r
"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual
)
850 # Mask out SNPA mac address portion. They are random...
851 actual
= re
.sub(r
"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual
)
852 # Mask out Circuit ID number
853 actual
= re
.sub(r
"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual
)
854 # Fix newlines (make them all the same)
855 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
858 diff
= topotest
.get_textdiff(
861 title1
="actual SHOW ISIS INTERFACE DETAIL",
862 title2
="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
865 # Empty string if it matches, otherwise diff contains unified diff
868 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i
, diff
)
876 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i
, diff
)
878 # Make sure that all daemons are running
879 for i
in range(1, 2):
880 fatal_error
= net
["r%s" % i
].checkRouterRunning()
881 assert fatal_error
== "", fatal_error
884 def test_bgp_summary():
886 net
= get_topogen().net
888 # Skip if previous fatal error condition is raised
889 if fatal_error
!= "":
890 pytest
.skip(fatal_error
)
892 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
894 print("\n\n** Verifying BGP Summary")
895 print("******************************************\n")
897 for i
in range(1, 2):
898 refTableFile
= "%s/r%s/show_ip_bgp_summary.ref" % (thisDir
, i
)
899 if os
.path
.isfile(refTableFile
):
900 # Read expected result from file
901 expected_original
= open(refTableFile
).read().rstrip()
905 "remote-as internal",
906 "remote-as external",
909 "neighbor 192.168.7.10",
910 "neighbor 192.168.7.10",
911 "neighbor fc00:0:0:8::1000",
914 "remote-as internal terse",
915 "remote-as external terse",
916 "remote-as 100 terse",
917 "remote-as 123 terse",
918 "neighbor 192.168.7.10 terse",
919 "neighbor 192.168.7.10 terse",
920 "neighbor fc00:0:0:8::1000 terse",
921 "neighbor 10.0.0.1 terse",
923 # Actual output from router
927 'vtysh -c "show ip bgp summary ' + arguments
+ '" 2> /dev/null'
932 # Mask out "using XXiXX bytes" portion. They are random...
933 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
934 # Mask out "using XiXXX KiB" portion. They are random...
935 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
937 # Remove extra summaries which exist with newer versions
939 # Remove summary lines (changed recently)
940 actual
= re
.sub(r
"Total number.*", "", actual
)
941 actual
= re
.sub(r
"Displayed.*", "", actual
)
942 # Remove IPv4 Unicast Summary (Title only)
943 actual
= re
.sub(r
"IPv4 Unicast Summary \(VRF default\):", "", actual
)
944 # Remove IPv4 Multicast Summary (all of it)
945 actual
= re
.sub(r
"IPv4 Multicast Summary \(VRF default\):", "", actual
)
946 actual
= re
.sub(r
"No IPv4 Multicast neighbor is configured", "", actual
)
947 # Remove IPv4 VPN Summary (all of it)
948 actual
= re
.sub(r
"IPv4 VPN Summary \(VRF default\):", "", actual
)
949 actual
= re
.sub(r
"No IPv4 VPN neighbor is configured", "", actual
)
950 # Remove IPv4 Encap Summary (all of it)
951 actual
= re
.sub(r
"IPv4 Encap Summary \(VRF default\):", "", actual
)
952 actual
= re
.sub(r
"No IPv4 Encap neighbor is configured", "", actual
)
953 # Remove Unknown Summary (all of it)
954 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
955 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
956 # Make Connect/Active/Idle the same (change them all to Active)
957 actual
= re
.sub(r
" Connect ", " Active ", actual
)
958 actual
= re
.sub(r
" Idle ", " Active ", actual
)
961 r
"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
964 r
"No IPv4 labeled-unicast neighbor is configured", "", actual
967 expected
= expected_original
968 # apply argumentss on expected output
969 if "internal" in arguments
or "remote-as 100" in arguments
:
970 expected
= re
.sub(r
".+\s+200\s+.+", "", expected
)
971 elif "external" in arguments
:
972 expected
= re
.sub(r
".+\s+100\s+.+Active.+", "", expected
)
973 elif "remote-as 123" in arguments
:
975 r
"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
979 expected
= re
.sub(r
"\nNeighbor.+Desc", "", expected
)
980 expected
= expected
+ "% No matching neighbor\n"
981 elif "192.168.7.10" in arguments
:
983 r
"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
985 elif "fc00:0:0:8::1000" in arguments
:
987 r
"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
989 elif "10.0.0.1" in arguments
:
990 expected
= "No such neighbor in this view/vrf"
992 if "terse" in arguments
:
993 expected
= re
.sub(r
"BGP table version .+", "", expected
)
994 expected
= re
.sub(r
"RIB entries .+", "", expected
)
995 expected
= re
.sub(r
"Peers [0-9]+, using .+", "", expected
)
998 actual
= actual
.lstrip().rstrip()
999 expected
= expected
.lstrip().rstrip()
1000 actual
= re
.sub(r
"\n+", "\n", actual
)
1001 expected
= re
.sub(r
"\n+", "\n", expected
)
1003 # reapply initial formatting
1004 if "terse" in arguments
:
1005 actual
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", actual
)
1006 expected
= re
.sub(r
" vrf-id 0\n", " vrf-id 0\n\n", expected
)
1008 actual
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", actual
)
1009 expected
= re
.sub(r
"KiB of memory\n", "KiB of memory\n\n", expected
)
1011 # realign expected neighbor columns if needed
1014 re
.search(r
"(Neighbor\s+V\s+)", actual
).group(1).find("V")
1017 re
.search(r
"(Neighbor\s+V\s+)", expected
).group(1).find("V")
1019 idx_diff
= idx_expected
- idx_actual
1021 # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
1022 expected
= re
.sub(" " * idx_diff
+ "V ", "V ", expected
)
1023 # 192.168.7.10 4 100 0 0 0 0 0 never Active
1024 expected
= re
.sub(" " * idx_diff
+ "4 ", "4 ", expected
)
1025 except AttributeError:
1028 # Fix newlines (make them all the same)
1029 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1030 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1033 diff
= topotest
.get_textdiff(
1036 title1
="actual SHOW IP BGP SUMMARY " + arguments
.upper(),
1037 title2
="expected SHOW IP BGP SUMMARY " + arguments
.upper(),
1040 # Empty string if it matches, otherwise diff contains unified diff
1043 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i
, diff
)
1051 ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
1056 # Make sure that all daemons are running
1057 for i
in range(1, 2):
1058 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1059 assert fatal_error
== "", fatal_error
1062 def test_bgp_ipv6_summary():
1064 net
= get_topogen().net
1066 # Skip if previous fatal error condition is raised
1067 if fatal_error
!= "":
1068 pytest
.skip(fatal_error
)
1070 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1072 print("\n\n** Verifying BGP IPv6 Summary")
1073 print("******************************************\n")
1075 for i
in range(1, 2):
1076 refTableFile
= "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir
, i
)
1077 if os
.path
.isfile(refTableFile
):
1078 # Read expected result from file
1079 expected
= open(refTableFile
).read().rstrip()
1080 # Fix newlines (make them all the same)
1081 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1083 # Actual output from router
1086 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
1089 # Mask out "using XXiXX bytes" portion. They are random...
1090 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
1091 # Mask out "using XiXXX KiB" portion. They are random...
1092 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
1094 # Remove extra summaries which exist with newer versions
1096 # Remove summary lines (changed recently)
1097 actual
= re
.sub(r
"Total number.*", "", actual
)
1098 actual
= re
.sub(r
"Displayed.*", "", actual
)
1099 # Remove IPv4 Unicast Summary (Title only)
1100 actual
= re
.sub(r
"IPv6 Unicast Summary \(VRF default\):", "", actual
)
1101 # Remove IPv4 Multicast Summary (all of it)
1102 actual
= re
.sub(r
"IPv6 Multicast Summary \(VRF default\):", "", actual
)
1103 actual
= re
.sub(r
"No IPv6 Multicast neighbor is configured", "", actual
)
1104 # Remove IPv4 VPN Summary (all of it)
1105 actual
= re
.sub(r
"IPv6 VPN Summary \(VRF default\):", "", actual
)
1106 actual
= re
.sub(r
"No IPv6 VPN neighbor is configured", "", actual
)
1107 # Remove IPv4 Encap Summary (all of it)
1108 actual
= re
.sub(r
"IPv6 Encap Summary \(VRF default\):", "", actual
)
1109 actual
= re
.sub(r
"No IPv6 Encap neighbor is configured", "", actual
)
1110 # Remove Unknown Summary (all of it)
1111 actual
= re
.sub(r
"Unknown Summary \(VRF default\):", "", actual
)
1112 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
1113 # Make Connect/Active/Idle the same (change them all to Active)
1114 actual
= re
.sub(r
" Connect ", " Active ", actual
)
1115 actual
= re
.sub(r
" Idle ", " Active ", actual
)
1117 # Remove Labeled Unicast Summary (all of it)
1119 r
"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
1122 r
"No IPv6 labeled-unicast neighbor is configured", "", actual
1126 actual
= actual
.lstrip()
1127 actual
= actual
.rstrip()
1129 # Fix newlines (make them all the same)
1130 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1133 diff
= topotest
.get_textdiff(
1136 title1
="actual SHOW BGP IPv6 SUMMARY",
1137 title2
="expected SHOW BGP IPv6 SUMMARY",
1140 # Empty string if it matches, otherwise diff contains unified diff
1143 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i
, diff
)
1149 assert failures
== 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1154 # Make sure that all daemons are running
1155 for i
in range(1, 2):
1156 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1157 assert fatal_error
== "", fatal_error
1162 net
= get_topogen().net
1164 # Skip if previous fatal error condition is raised
1165 if fatal_error
!= "":
1166 pytest
.skip(fatal_error
)
1168 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1170 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1172 for i
in range(1, 2):
1173 nhtFile
= "%s/r%s/ip_nht.ref" % (thisDir
, i
)
1174 expected
= open(nhtFile
).read().rstrip()
1175 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1177 actual
= net
["r%s" % i
].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
1178 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1179 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1181 diff
= topotest
.get_textdiff(
1184 title1
="Actual `show ip nht`",
1185 title2
="Expected `show ip nht`",
1189 assert 0, "r%s failed ip nht check:\n%s\n" % (i
, diff
)
1191 print("show ip nht is ok\n")
1193 nhtFile
= "%s/r%s/ipv6_nht.ref" % (thisDir
, i
)
1194 expected
= open(nhtFile
).read().rstrip()
1195 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1197 actual
= net
["r%s" % i
].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
1198 actual
= re
.sub(r
"fd [0-9]+", "fd XX", actual
)
1199 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1201 diff
= topotest
.get_textdiff(
1204 title1
="Actual `show ip nht`",
1205 title2
="Expected `show ip nht`",
1209 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i
, diff
)
1211 print("show ipv6 nht is ok\n")
1214 def test_bgp_ipv4():
1216 net
= get_topogen().net
1218 # Skip if previous fatal error condition is raised
1219 if fatal_error
!= "":
1220 pytest
.skip(fatal_error
)
1222 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1224 print("\n\n** Verifying BGP IPv4")
1225 print("******************************************\n")
1227 for i
in range(1, 2):
1229 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir
, i
)):
1230 if os
.path
.isfile(refTableFile
):
1231 # Read expected result from file
1232 expected
= open(refTableFile
).read().rstrip()
1233 # Fix newlines (make them all the same)
1234 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1236 # Actual output from router
1238 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1240 # Remove summary line (changed recently)
1241 actual
= re
.sub(r
"Total number.*", "", actual
)
1242 actual
= re
.sub(r
"Displayed.*", "", actual
)
1243 actual
= actual
.rstrip()
1244 # Fix newlines (make them all the same)
1245 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1248 diff
= topotest
.get_textdiff(
1251 title1
="actual SHOW BGP IPv4",
1252 title2
="expected SHOW BGP IPv4",
1255 # Empty string if it matches, otherwise diff contains unified diff
1257 diffresult
[refTableFile
] = diff
1260 print("template %s matched: r%s ok" % (refTableFile
, i
))
1264 resultstr
= "No template matched.\n"
1265 for f
in diffresult
.keys():
1266 resultstr
+= "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1271 raise AssertionError(
1272 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i
, resultstr
)
1275 # Make sure that all daemons are running
1276 for i
in range(1, 2):
1277 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1278 assert fatal_error
== "", fatal_error
1281 def test_bgp_ipv6():
1283 net
= get_topogen().net
1285 # Skip if previous fatal error condition is raised
1286 if fatal_error
!= "":
1287 pytest
.skip(fatal_error
)
1289 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1291 print("\n\n** Verifying BGP IPv6")
1292 print("******************************************\n")
1294 for i
in range(1, 2):
1296 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir
, i
)):
1297 if os
.path
.isfile(refTableFile
):
1298 # Read expected result from file
1299 expected
= open(refTableFile
).read().rstrip()
1300 # Fix newlines (make them all the same)
1301 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1303 # Actual output from router
1305 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1307 # Remove summary line (changed recently)
1308 actual
= re
.sub(r
"Total number.*", "", actual
)
1309 actual
= re
.sub(r
"Displayed.*", "", actual
)
1310 actual
= actual
.rstrip()
1311 # Fix newlines (make them all the same)
1312 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1315 diff
= topotest
.get_textdiff(
1318 title1
="actual SHOW BGP IPv6",
1319 title2
="expected SHOW BGP IPv6",
1322 # Empty string if it matches, otherwise diff contains unified diff
1324 diffresult
[refTableFile
] = diff
1327 print("template %s matched: r%s ok" % (refTableFile
, i
))
1330 resultstr
= "No template matched.\n"
1331 for f
in diffresult
.keys():
1332 resultstr
+= "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1337 raise AssertionError(
1338 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i
, resultstr
)
1341 # Make sure that all daemons are running
1342 for i
in range(1, 2):
1343 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1344 assert fatal_error
== "", fatal_error
1347 def test_route_map():
1349 net
= get_topogen().net
1351 if fatal_error
!= "":
1352 pytest
.skip(fatal_error
)
1354 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1356 print("\n\n** Verifying some basic routemap forward references\n")
1357 print("*******************************************************\n")
1359 for i
in range(1, 2):
1360 refroutemap
= "%s/r%s/show_route_map.ref" % (thisDir
, i
)
1361 if os
.path
.isfile(refroutemap
):
1362 expected
= open(refroutemap
).read().rstrip()
1363 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1366 net
["r%s" % i
].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1368 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1370 diff
= topotest
.get_textdiff(
1373 title1
="actual show route-map",
1374 title2
="expected show route-map",
1379 "r%s failed show route-map command Check:\n%s\n" % (i
, diff
)
1387 ), "Show route-map command failed for router r%s:\n%s" % (i
, diff
)
1390 def test_nexthop_groups_with_route_maps():
1392 net
= get_topogen().net
1394 # Skip if previous fatal error condition is raised
1395 if fatal_error
!= "":
1396 pytest
.skip(fatal_error
)
1398 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1399 print("******************************************\n")
1401 ### Nexthop Group With Route-Map Tests
1403 # Create a lib nexthop-group
1405 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1408 ## Route-Map Proto Source
1410 route_str
= "2.2.2.1"
1411 src_str
= "192.168.0.1"
1414 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1416 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1418 net
["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str
)
1420 verify_route_nexthop_group("%s/32" % route_str
)
1422 # Only a valid test on linux using nexthop objects
1423 if sys
.platform
.startswith("linux"):
1424 output
= net
["r1"].cmd("ip route show %s/32" % route_str
)
1425 match
= re
.search(r
"src %s" % src_str
, output
)
1426 assert match
is not None, "Route %s/32 not installed with src %s" % (
1431 # Remove NHG routes and route-map
1432 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str
)
1433 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
1435 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
1437 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1439 ## Route-Map Deny/Permit with same nexthop group
1441 permit_route_str
= "3.3.3.1"
1442 deny_route_str
= "3.3.3.2"
1445 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1448 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1450 net
["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1451 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1453 # This route should be permitted
1455 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1458 verify_route_nexthop_group("%s/32" % permit_route_str
)
1460 # This route should be denied
1462 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1465 nhg_id
= route_get_nhg_id(deny_route_str
)
1466 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
1468 match
= re
.search(r
"Valid", output
)
1469 assert match
is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1471 match
= re
.search(r
"Installed", output
)
1472 assert match
is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1474 # Remove NHG routes and route-map
1475 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str
)
1476 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str
)
1477 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1478 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1479 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1480 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
1482 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1487 def test_nexthop_group_replace():
1489 net
= get_topogen().net
1491 # Skip if previous fatal error condition is raised
1492 if fatal_error
!= "":
1493 pytest
.skip(fatal_error
)
1495 print("\n\n** Verifying Nexthop Groups")
1496 print("******************************************\n")
1498 ### Nexthop Group Tests
1500 ## 2-Way ECMP Directly Connected
1503 '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"'
1506 # At the moment there is absolutely no real easy way to query sharpd
1507 # for the nexthop group actually installed. If it is not installed
1508 # sharpd will just transmit the nexthops down instead of the nexthop
1509 # group id. Leading to a situation where the replace is not actually
1510 # being tested. So let's just wait some time here because this
1511 # is hard and this test fails all the time
1514 # Create with sharpd using nexthop-group
1515 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1517 verify_route_nexthop_group("3.3.3.1/32")
1519 # Change the nexthop group
1521 '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"'
1524 # Verify it updated. We can just check install and ecmp count here.
1525 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1528 def test_mpls_interfaces():
1530 net
= get_topogen().net
1532 # Skip if previous fatal error condition is raised
1533 if fatal_error
!= "":
1534 pytest
.skip(fatal_error
)
1536 # Skip if no LDP installed or old kernel
1537 if net
["r1"].daemon_available("ldpd") == False:
1538 pytest
.skip("No MPLS or kernel < 4.5")
1540 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1542 print("\n\n** Verifying MPLS Interfaces")
1543 print("******************************************\n")
1545 for i
in range(1, 2):
1546 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir
, i
)
1547 if os
.path
.isfile(refTableFile
):
1548 # Read expected result from file
1549 expected
= open(refTableFile
).read().rstrip()
1550 # Fix newlines (make them all the same)
1551 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1553 # Actual output from router
1556 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1559 # Mask out Timer in Uptime
1560 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
1561 # Fix newlines (make them all the same)
1562 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1565 diff
= topotest
.get_textdiff(
1568 title1
="actual MPLS LDP interface status",
1569 title2
="expected MPLS LDP interface status",
1572 # Empty string if it matches, otherwise diff contains unified diff
1575 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
1582 fatal_error
= "MPLS LDP Interface status failed"
1586 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
1588 # Make sure that all daemons are running
1589 for i
in range(1, 2):
1590 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1591 assert fatal_error
== "", fatal_error
1594 def test_shutdown_check_stderr():
1596 net
= get_topogen().net
1598 # Skip if previous fatal error condition is raised
1599 if fatal_error
!= "":
1600 pytest
.skip(fatal_error
)
1602 print("\n\n** Verifying unexpected STDERR output from daemons")
1603 print("******************************************\n")
1605 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
1607 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1609 pytest
.skip("Skipping test for Stderr output")
1611 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1613 print("thisDir=" + thisDir
)
1615 net
["r1"].stopRouter()
1617 log
= net
["r1"].getStdErr("ripd")
1619 print("\nRIPd StdErr Log:\n" + log
)
1620 log
= net
["r1"].getStdErr("ripngd")
1622 print("\nRIPngd StdErr Log:\n" + log
)
1623 log
= net
["r1"].getStdErr("ospfd")
1625 print("\nOSPFd StdErr Log:\n" + log
)
1626 log
= net
["r1"].getStdErr("ospf6d")
1628 print("\nOSPF6d StdErr Log:\n" + log
)
1629 log
= net
["r1"].getStdErr("isisd")
1631 print("\nISISd StdErr Log:\n" + log
)
1632 log
= net
["r1"].getStdErr("bgpd")
1634 print("\nBGPd StdErr Log:\n" + log
)
1636 log
= net
["r1"].getStdErr("nhrpd")
1638 print("\nNHRPd StdErr Log:\n" + log
)
1640 log
= net
["r1"].getStdErr("pbrd")
1642 print("\nPBRd StdErr Log:\n" + log
)
1644 log
= net
["r1"].getStdErr("babeld")
1646 print("\nBABELd StdErr Log:\n" + log
)
1648 if net
["r1"].daemon_available("ldpd"):
1649 log
= net
["r1"].getStdErr("ldpd")
1651 print("\nLDPd StdErr Log:\n" + log
)
1652 log
= net
["r1"].getStdErr("zebra")
1654 print("\nZebra StdErr Log:\n" + log
)
1657 def test_shutdown_check_memleak():
1659 net
= get_topogen().net
1661 # Skip if previous fatal error condition is raised
1662 if fatal_error
!= "":
1663 pytest
.skip(fatal_error
)
1665 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1667 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1669 pytest
.skip("Skipping test for memory leaks")
1671 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1673 for i
in range(1, 2):
1674 net
["r%s" % i
].stopRouter()
1675 net
["r%s" % i
].report_memory_leaks(
1676 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
1680 if __name__
== "__main__":
1681 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1682 # retval = pytest.main(["-s", "--tb=no"])
1683 retval
= pytest
.main(["-s"])