]>
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
37 from mininet
.topo
import Topo
38 from mininet
.net
import Mininet
39 from mininet
.node
import Node
, OVSSwitch
, Host
40 from mininet
.log
import setLogLevel
, info
41 from mininet
.cli
import CLI
42 from mininet
.link
import Intf
44 from functools
import partial
46 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
47 from lib
import topotest
52 #####################################################
54 ## Network Topology Definition
56 #####################################################
59 class NetworkTopo(Topo
):
60 "All Protocol Startup Test"
62 def build(self
, **_opts
):
68 router
[1] = topotest
.addRouter(self
, "r1")
74 for i
in range(0, 10):
75 switch
[i
] = self
.addSwitch("sw%s" % i
, cls
=topotest
.LegacySwitch
)
76 self
.addLink(switch
[i
], router
[1], intfName2
="r1-eth%s" % i
)
79 #####################################################
83 #####################################################
86 def setup_module(module
):
90 print("\n\n** %s: Setup Topology" % module
.__name
__)
91 print("******************************************\n")
93 print("Cleanup old Mininet runs")
94 os
.system("sudo mn -c > /dev/null 2>&1")
95 os
.system("sudo rm /tmp/r* > /dev/null 2>&1")
97 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
100 net
= Mininet(controller
=None, topo
=topo
)
103 if net
["r1"].get_routertype() != "frr":
104 fatal_error
= "Test is only implemented for FRR"
105 sys
.stderr
.write("\n\nTest is only implemented for FRR - Skipping\n\n")
106 pytest
.skip(fatal_error
)
111 for i
in range(1, 2):
112 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
113 net
["r%s" % i
].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir
, i
))
114 net
["r%s" % i
].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir
, i
))
115 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
116 if net
["r1"].checkRouterVersion("<", "4.0"):
117 net
["r%s" % i
].loadConf(
118 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir
, i
)
121 net
["r%s" % i
].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir
, i
))
122 net
["r%s" % i
].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir
, i
))
123 net
["r%s" % i
].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir
, i
))
124 if net
["r%s" % i
].daemon_available("ldpd"):
125 # Only test LDPd if it's installed and Kernel >= 4.5
126 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
127 net
["r%s" % i
].loadConf("sharpd")
128 net
["r%s" % i
].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir
, i
))
129 net
["r%s" % i
].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir
, i
))
130 net
["r%s" % i
].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir
, i
))
131 net
["r%s" % i
].startRouter()
133 # For debugging after starting FRR daemons, uncomment the next line
137 def teardown_module(module
):
140 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
141 print("******************************************\n")
143 # End - Shutdown network
147 def test_router_running():
151 # Skip if previous fatal error condition is raised
152 if fatal_error
!= "":
153 pytest
.skip(fatal_error
)
155 print("\n\n** Check if FRR is running on each Router node")
156 print("******************************************\n")
160 for i
in range(1, 2):
161 fatal_error
= net
["r%s" % i
].checkRouterRunning()
162 assert fatal_error
== "", fatal_error
164 # For debugging after starting FRR daemons, uncomment the next line
168 def test_error_messages_vtysh():
172 # Skip if previous fatal error condition is raised
173 if fatal_error
!= "":
174 pytest
.skip(fatal_error
)
176 print("\n\n** Check for error messages on VTYSH")
177 print("******************************************\n")
180 for i
in range(1, 2):
182 # First checking Standard Output
185 # VTYSH output from router
186 vtystdout
= net
["r%s" % i
].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
188 # Fix newlines (make them all the same)
189 vtystdout
= ("\n".join(vtystdout
.splitlines()) + "\n").rstrip()
190 # Drop everything starting with "FRRouting X.xx" message
191 vtystdout
= re
.sub(r
"FRRouting [0-9]+.*", "", vtystdout
, flags
=re
.DOTALL
)
194 print("r%s StdOut ok" % i
)
196 assert vtystdout
== "", "Vtysh StdOut Output check failed for router r%s" % i
199 # Second checking Standard Error
202 # VTYSH StdErr output from router
203 vtystderr
= net
["r%s" % i
].cmd('vtysh -c "show version" > /dev/null').rstrip()
205 # Fix newlines (make them all the same)
206 vtystderr
= ("\n".join(vtystderr
.splitlines()) + "\n").rstrip()
207 # # Drop everything starting with "FRRouting X.xx" message
208 # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
211 print("r%s StdErr ok" % i
)
213 assert vtystderr
== "", "Vtysh StdErr Output check failed for router r%s" % i
215 # Make sure that all daemons are running
216 for i
in range(1, 2):
217 fatal_error
= net
["r%s" % i
].checkRouterRunning()
218 assert fatal_error
== "", fatal_error
220 # For debugging after starting FRR daemons, uncomment the next line
224 def test_error_messages_daemons():
228 # Skip if previous fatal error condition is raised
229 if fatal_error
!= "":
230 pytest
.skip(fatal_error
)
232 print("\n\n** Check for error messages in daemons")
233 print("******************************************\n")
237 for i
in range(1, 2):
238 log
= net
["r%s" % i
].getStdErr("ripd")
240 error_logs
+= "r%s RIPd StdErr Output:\n" % i
242 log
= net
["r%s" % i
].getStdErr("ripngd")
244 error_logs
+= "r%s RIPngd StdErr Output:\n" % i
246 log
= net
["r%s" % i
].getStdErr("ospfd")
248 error_logs
+= "r%s OSPFd StdErr Output:\n" % i
250 log
= net
["r%s" % i
].getStdErr("ospf6d")
252 error_logs
+= "r%s OSPF6d StdErr Output:\n" % i
254 log
= net
["r%s" % i
].getStdErr("isisd")
255 # ISIS shows debugging enabled status on StdErr
256 # Remove these messages
257 log
= re
.sub(r
"^IS-IS .* debugging is on.*", "", log
).rstrip()
259 error_logs
+= "r%s ISISd StdErr Output:\n" % i
261 log
= net
["r%s" % i
].getStdErr("bgpd")
263 error_logs
+= "r%s BGPd StdErr Output:\n" % i
265 if net
["r%s" % i
].daemon_available("ldpd"):
266 log
= net
["r%s" % i
].getStdErr("ldpd")
268 error_logs
+= "r%s LDPd StdErr Output:\n" % i
271 log
= net
["r1"].getStdErr("nhrpd")
273 error_logs
+= "r%s NHRPd StdErr Output:\n" % i
276 log
= net
["r1"].getStdErr("babeld")
278 error_logs
+= "r%s BABELd StdErr Output:\n" % i
281 log
= net
["r1"].getStdErr("pbrd")
283 error_logs
+= "r%s PBRd StdErr Output:\n" % i
286 log
= net
["r%s" % i
].getStdErr("zebra")
288 error_logs
+= "r%s Zebra StdErr Output:\n"
293 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
296 # Ignoring the issue if told to ignore (ie not yet fixed)
298 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
300 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
303 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
306 assert error_logs
== "", "Daemons report errors to StdErr"
308 # For debugging after starting FRR daemons, uncomment the next line
312 def test_converge_protocols():
316 # Skip if previous fatal error condition is raised
317 if fatal_error
!= "":
318 pytest
.skip(fatal_error
)
320 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
322 print("\n\n** Waiting for protocols convergence")
323 print("******************************************\n")
325 # Not really implemented yet - just sleep 60 secs for now
328 # Make sure that all daemons are running
330 for i
in range(1, 2):
331 fatal_error
= net
["r%s" % i
].checkRouterRunning()
332 assert fatal_error
== "", fatal_error
334 print("Show that v4 routes are right\n")
335 v4_routesFile
= "%s/r%s/ipv4_routes.ref" % (thisDir
, i
)
336 expected
= open(v4_routesFile
).read().rstrip()
337 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
342 'vtysh -c "show ip route" | /usr/bin/tail -n +7 | env LC_ALL=en_US.UTF-8 sort 2> /dev/null'
346 # Drop time in last update
347 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
348 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
349 diff
= topotest
.get_textdiff(
352 title1
="Actual IP Routing Table",
353 title2
="Expected IP RoutingTable",
356 sys
.stderr
.write("r%s failed IP Routing table check:\n%s\n" % (i
, diff
))
361 assert failures
== 0, "IP Routing table failed for r%s\n%s" % (i
, diff
)
365 print("Show that v6 routes are right\n")
366 v6_routesFile
= "%s/r%s/ipv6_routes.ref" % (thisDir
, i
)
367 expected
= open(v6_routesFile
).read().rstrip()
368 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
373 'vtysh -c "show ipv6 route" | /usr/bin/tail -n +7 | env LC_ALL=en_US.UTF-8 sort 2> /dev/null'
377 # Drop time in last update
378 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
379 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
380 diff
= topotest
.get_textdiff(
383 title1
="Actual IPv6 Routing Table",
384 title2
="Expected IPv6 RoutingTable",
387 sys
.stderr
.write("r%s failed IPv6 Routing table check:\n%s\n" % (i
, diff
))
392 assert failures
== 0, "IPv6 Routing table failed for r%s\n%s" % (i
, diff
)
394 # For debugging after starting FRR daemons, uncomment the next line
398 def route_get_nhg_id(route_str
):
399 output
= net
["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str
)
400 match
= re
.search(r
"Nexthop Group ID: (\d+)", output
)
401 assert match
is not None, (
402 "Nexthop Group ID not found for sharpd route %s" % route_str
405 nhg_id
= int(match
.group(1))
409 def verify_nexthop_group(nhg_id
, recursive
=False, ecmp
=0):
410 # Verify NHG is valid/installed
411 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
413 match
= re
.search(r
"Valid", output
)
414 assert match
is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
416 if ecmp
or recursive
:
417 match
= re
.search(r
"Depends:.*\n", output
)
418 assert match
is not None, "Nexthop Group ID=%d has no depends" % nhg_id
420 # list of IDs in group
421 depends
= re
.findall(r
"\((\d+)\)", match
.group(0))
424 assert len(depends
) == ecmp
, (
425 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
428 # If recursive, we need to look at its resolved group
429 assert len(depends
) == 1, (
430 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
432 resolved_id
= int(depends
[0])
433 verify_nexthop_group(resolved_id
, False)
436 match
= re
.search(r
"Installed", output
)
437 assert match
is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id
440 def verify_route_nexthop_group(route_str
, recursive
=False, ecmp
=0):
441 # Verify route and that zebra created NHGs for and they are valid/installed
442 nhg_id
= route_get_nhg_id(route_str
)
443 verify_nexthop_group(nhg_id
, recursive
, ecmp
)
446 def test_nexthop_groups():
450 # Skip if previous fatal error condition is raised
451 if fatal_error
!= "":
452 pytest
.skip(fatal_error
)
454 print("\n\n** Verifying Nexthop Groups")
455 print("******************************************\n")
457 ### Nexthop Group Tests
461 # Create a lib nexthop-group
463 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
466 # Create with sharpd using nexthop-group
467 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
469 verify_route_nexthop_group("2.2.2.1/32")
474 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
477 net
["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
479 verify_route_nexthop_group("2.2.2.2/32")
484 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
488 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
491 verify_route_nexthop_group("3.3.3.1/32", True)
496 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
499 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
501 verify_route_nexthop_group("3.3.3.2/32")
506 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
507 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
510 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
512 verify_route_nexthop_group("4.4.4.1/32")
515 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
516 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
519 net
["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
521 verify_route_nexthop_group("4.4.4.2/32")
523 ## Recursive to 8-Way ECMP
526 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
530 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
533 verify_route_nexthop_group("5.5.5.1/32")
537 ## Remove all NHG routes
539 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
540 net
["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
541 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
542 net
["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
543 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
544 net
["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
545 net
["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
548 def test_rip_status():
552 # Skip if previous fatal error condition is raised
553 if fatal_error
!= "":
554 pytest
.skip(fatal_error
)
556 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
558 print("\n\n** Verifying RIP status")
559 print("******************************************\n")
561 for i
in range(1, 2):
562 refTableFile
= "%s/r%s/rip_status.ref" % (thisDir
, i
)
563 if os
.path
.isfile(refTableFile
):
564 # Read expected result from file
565 expected
= open(refTableFile
).read().rstrip()
566 # Fix newlines (make them all the same)
567 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
569 # Actual output from router
572 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
575 # Drop time in next due
576 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
577 # Drop time in last update
578 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
579 # Fix newlines (make them all the same)
580 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
583 diff
= topotest
.get_textdiff(
586 title1
="actual IP RIP status",
587 title2
="expected IP RIP status",
590 # Empty string if it matches, otherwise diff contains unified diff
592 sys
.stderr
.write("r%s failed IP RIP status check:\n%s\n" % (i
, diff
))
597 assert failures
== 0, "IP RIP status failed for router r%s:\n%s" % (i
, diff
)
599 # Make sure that all daemons are running
600 for i
in range(1, 2):
601 fatal_error
= net
["r%s" % i
].checkRouterRunning()
602 assert fatal_error
== "", fatal_error
604 # For debugging after starting FRR daemons, uncomment the next line
608 def test_ripng_status():
612 # Skip if previous fatal error condition is raised
613 if fatal_error
!= "":
614 pytest
.skip(fatal_error
)
616 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
618 print("\n\n** Verifying RIPng status")
619 print("******************************************\n")
621 for i
in range(1, 2):
622 refTableFile
= "%s/r%s/ripng_status.ref" % (thisDir
, i
)
623 if os
.path
.isfile(refTableFile
):
624 # Read expected result from file
625 expected
= open(refTableFile
).read().rstrip()
626 # Fix newlines (make them all the same)
627 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
629 # Actual output from router
632 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
635 # Mask out Link-Local mac address portion. They are random...
636 actual
= re
.sub(r
" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual
)
637 # Drop time in next due
638 actual
= re
.sub(r
"in [0-9]+ seconds", "in XX seconds", actual
)
639 # Drop time in last update
640 actual
= re
.sub(r
" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual
)
641 # Fix newlines (make them all the same)
642 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
645 diff
= topotest
.get_textdiff(
648 title1
="actual IPv6 RIPng status",
649 title2
="expected IPv6 RIPng status",
652 # Empty string if it matches, otherwise diff contains unified diff
655 "r%s failed IPv6 RIPng status check:\n%s\n" % (i
, diff
)
661 assert failures
== 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
666 # Make sure that all daemons are running
667 for i
in range(1, 2):
668 fatal_error
= net
["r%s" % i
].checkRouterRunning()
669 assert fatal_error
== "", fatal_error
671 # For debugging after starting FRR daemons, uncomment the next line
675 def test_ospfv2_interfaces():
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 OSPFv2 interfaces")
686 print("******************************************\n")
688 for i
in range(1, 2):
689 refTableFile
= "%s/r%s/show_ip_ospf_interface.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 ip ospf interface" 2> /dev/null')
702 # Mask out Bandwidth portion. They may change..
703 actual
= re
.sub(r
"BW [0-9]+ Mbit", "BW XX Mbit", actual
)
704 actual
= re
.sub(r
"ifindex [0-9]", "ifindex X", actual
)
706 # Drop time in next due
707 actual
= re
.sub(r
"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual
)
709 r
"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
711 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
713 r
"MTU mismatch detection:([a-z]+.*)",
714 r
"MTU mismatch detection: \1",
717 # Fix newlines (make them all the same)
718 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
721 diff
= topotest
.get_textdiff(
724 title1
="actual SHOW IP OSPF INTERFACE",
725 title2
="expected SHOW IP OSPF INTERFACE",
728 # Empty string if it matches, otherwise diff contains unified diff
731 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i
, diff
)
737 # Ignoring the issue if told to ignore (ie not yet fixed)
739 if os
.environ
.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
741 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
744 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
749 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i
, diff
)
751 # Make sure that all daemons are running
752 for i
in range(1, 2):
753 fatal_error
= net
["r%s" % i
].checkRouterRunning()
754 assert fatal_error
== "", fatal_error
756 # For debugging after starting FRR daemons, uncomment the next line
760 def test_isis_interfaces():
764 # Skip if previous fatal error condition is raised
765 if fatal_error
!= "":
766 pytest
.skip(fatal_error
)
768 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
770 print("\n\n** Verifying ISIS interfaces")
771 print("******************************************\n")
773 for i
in range(1, 2):
774 refTableFile
= "%s/r%s/show_isis_interface_detail.ref" % (thisDir
, i
)
775 if os
.path
.isfile(refTableFile
):
776 # Read expected result from file
777 expected
= open(refTableFile
).read().rstrip()
778 # Fix newlines (make them all the same)
779 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
781 # Actual output from router
784 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
787 # Mask out Link-Local mac address portion. They are random...
788 actual
= re
.sub(r
"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual
)
789 # Mask out SNPA mac address portion. They are random...
790 actual
= re
.sub(r
"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual
)
791 # Mask out Circuit ID number
792 actual
= re
.sub(r
"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual
)
793 # Fix newlines (make them all the same)
794 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
797 diff
= topotest
.get_textdiff(
800 title1
="actual SHOW ISIS INTERFACE DETAIL",
801 title2
="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
804 # Empty string if it matches, otherwise diff contains unified diff
807 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i
, diff
)
815 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i
, diff
)
817 # Make sure that all daemons are running
818 for i
in range(1, 2):
819 fatal_error
= net
["r%s" % i
].checkRouterRunning()
820 assert fatal_error
== "", fatal_error
822 # For debugging after starting FRR daemons, uncomment the next line
826 def test_bgp_summary():
830 # Skip if previous fatal error condition is raised
831 if fatal_error
!= "":
832 pytest
.skip(fatal_error
)
834 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
836 print("\n\n** Verifying BGP Summary")
837 print("******************************************\n")
839 for i
in range(1, 2):
840 refTableFile
= "%s/r%s/show_ip_bgp_summary.ref" % (thisDir
, i
)
841 if os
.path
.isfile(refTableFile
):
842 # Read expected result from file
843 expected
= open(refTableFile
).read().rstrip()
844 # Fix newlines (make them all the same)
845 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
847 # Actual output from router
850 .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
853 # Mask out "using XXiXX bytes" portion. They are random...
854 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
855 # Mask out "using XiXXX KiB" portion. They are random...
856 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
858 # Remove extra summaries which exist with newer versions
860 # Remove summary lines (changed recently)
861 actual
= re
.sub(r
"Total number.*", "", actual
)
862 actual
= re
.sub(r
"Displayed.*", "", actual
)
863 # Remove IPv4 Unicast Summary (Title only)
864 actual
= re
.sub(r
"IPv4 Unicast Summary:", "", actual
)
865 # Remove IPv4 Multicast Summary (all of it)
866 actual
= re
.sub(r
"IPv4 Multicast Summary:", "", actual
)
867 actual
= re
.sub(r
"No IPv4 Multicast neighbor is configured", "", actual
)
868 # Remove IPv4 VPN Summary (all of it)
869 actual
= re
.sub(r
"IPv4 VPN Summary:", "", actual
)
870 actual
= re
.sub(r
"No IPv4 VPN neighbor is configured", "", actual
)
871 # Remove IPv4 Encap Summary (all of it)
872 actual
= re
.sub(r
"IPv4 Encap Summary:", "", actual
)
873 actual
= re
.sub(r
"No IPv4 Encap neighbor is configured", "", actual
)
874 # Remove Unknown Summary (all of it)
875 actual
= re
.sub(r
"Unknown Summary:", "", actual
)
876 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
878 actual
= re
.sub(r
"IPv4 labeled-unicast Summary:", "", actual
)
880 r
"No IPv4 labeled-unicast neighbor is configured", "", actual
884 actual
= actual
.lstrip()
885 actual
= actual
.rstrip()
887 # Fix newlines (make them all the same)
888 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
891 diff
= topotest
.get_textdiff(
894 title1
="actual SHOW IP BGP SUMMARY",
895 title2
="expected SHOW IP BGP SUMMARY",
898 # Empty string if it matches, otherwise diff contains unified diff
901 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i
, diff
)
907 assert failures
== 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
912 # Make sure that all daemons are running
913 for i
in range(1, 2):
914 fatal_error
= net
["r%s" % i
].checkRouterRunning()
915 assert fatal_error
== "", fatal_error
917 # For debugging after starting FRR daemons, uncomment the next line
921 def test_bgp_ipv6_summary():
925 # Skip if previous fatal error condition is raised
926 if fatal_error
!= "":
927 pytest
.skip(fatal_error
)
929 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
931 print("\n\n** Verifying BGP IPv6 Summary")
932 print("******************************************\n")
934 for i
in range(1, 2):
935 refTableFile
= "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir
, i
)
936 if os
.path
.isfile(refTableFile
):
937 # Read expected result from file
938 expected
= open(refTableFile
).read().rstrip()
939 # Fix newlines (make them all the same)
940 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
942 # Actual output from router
945 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
948 # Mask out "using XXiXX bytes" portion. They are random...
949 actual
= re
.sub(r
"using [0-9]+ bytes", "using XXXX bytes", actual
)
950 # Mask out "using XiXXX KiB" portion. They are random...
951 actual
= re
.sub(r
"using [0-9]+ KiB", "using XXXX KiB", actual
)
953 # Remove extra summaries which exist with newer versions
955 # Remove summary lines (changed recently)
956 actual
= re
.sub(r
"Total number.*", "", actual
)
957 actual
= re
.sub(r
"Displayed.*", "", actual
)
958 # Remove IPv4 Unicast Summary (Title only)
959 actual
= re
.sub(r
"IPv6 Unicast Summary:", "", actual
)
960 # Remove IPv4 Multicast Summary (all of it)
961 actual
= re
.sub(r
"IPv6 Multicast Summary:", "", actual
)
962 actual
= re
.sub(r
"No IPv6 Multicast neighbor is configured", "", actual
)
963 # Remove IPv4 VPN Summary (all of it)
964 actual
= re
.sub(r
"IPv6 VPN Summary:", "", actual
)
965 actual
= re
.sub(r
"No IPv6 VPN neighbor is configured", "", actual
)
966 # Remove IPv4 Encap Summary (all of it)
967 actual
= re
.sub(r
"IPv6 Encap Summary:", "", actual
)
968 actual
= re
.sub(r
"No IPv6 Encap neighbor is configured", "", actual
)
969 # Remove Unknown Summary (all of it)
970 actual
= re
.sub(r
"Unknown Summary:", "", actual
)
971 actual
= re
.sub(r
"No Unknown neighbor is configured", "", actual
)
973 # Remove Labeled Unicast Summary (all of it)
974 actual
= re
.sub(r
"IPv6 labeled-unicast Summary:", "", actual
)
976 r
"No IPv6 labeled-unicast neighbor is configured", "", actual
980 actual
= actual
.lstrip()
981 actual
= actual
.rstrip()
983 # Fix newlines (make them all the same)
984 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
987 diff
= topotest
.get_textdiff(
990 title1
="actual SHOW BGP IPv6 SUMMARY",
991 title2
="expected SHOW BGP IPv6 SUMMARY",
994 # Empty string if it matches, otherwise diff contains unified diff
997 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i
, diff
)
1003 assert failures
== 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1008 # Make sure that all daemons are running
1009 for i
in range(1, 2):
1010 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1011 assert fatal_error
== "", fatal_error
1013 # For debugging after starting FRR daemons, uncomment the next line
1017 def test_bgp_ipv4():
1021 # Skip if previous fatal error condition is raised
1022 if fatal_error
!= "":
1023 pytest
.skip(fatal_error
)
1025 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1027 print("\n\n** Verifying BGP IPv4")
1028 print("******************************************\n")
1030 for i
in range(1, 2):
1032 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir
, i
)):
1033 if os
.path
.isfile(refTableFile
):
1034 # Read expected result from file
1035 expected
= open(refTableFile
).read().rstrip()
1036 # Fix newlines (make them all the same)
1037 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1039 # Actual output from router
1041 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1043 # Remove summary line (changed recently)
1044 actual
= re
.sub(r
"Total number.*", "", actual
)
1045 actual
= re
.sub(r
"Displayed.*", "", actual
)
1046 actual
= actual
.rstrip()
1047 # Fix newlines (make them all the same)
1048 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1051 diff
= topotest
.get_textdiff(
1054 title1
="actual SHOW BGP IPv4",
1055 title2
="expected SHOW BGP IPv4",
1058 # Empty string if it matches, otherwise diff contains unified diff
1060 diffresult
[refTableFile
] = diff
1063 print("template %s matched: r%s ok" % (refTableFile
, i
))
1067 resultstr
= "No template matched.\n"
1068 for f
in diffresult
.iterkeys():
1069 resultstr
+= "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1074 raise AssertionError(
1075 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i
, resultstr
)
1078 # Make sure that all daemons are running
1079 for i
in range(1, 2):
1080 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1081 assert fatal_error
== "", fatal_error
1083 # For debugging after starting FRR daemons, uncomment the next line
1087 def test_bgp_ipv6():
1091 # Skip if previous fatal error condition is raised
1092 if fatal_error
!= "":
1093 pytest
.skip(fatal_error
)
1095 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1097 print("\n\n** Verifying BGP IPv6")
1098 print("******************************************\n")
1100 for i
in range(1, 2):
1102 for refTableFile
in glob
.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir
, i
)):
1103 if os
.path
.isfile(refTableFile
):
1104 # Read expected result from file
1105 expected
= open(refTableFile
).read().rstrip()
1106 # Fix newlines (make them all the same)
1107 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1109 # Actual output from router
1111 net
["r%s" % i
].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1113 # Remove summary line (changed recently)
1114 actual
= re
.sub(r
"Total number.*", "", actual
)
1115 actual
= re
.sub(r
"Displayed.*", "", actual
)
1116 actual
= actual
.rstrip()
1117 # Fix newlines (make them all the same)
1118 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1121 diff
= topotest
.get_textdiff(
1124 title1
="actual SHOW BGP IPv6",
1125 title2
="expected SHOW BGP IPv6",
1128 # Empty string if it matches, otherwise diff contains unified diff
1130 diffresult
[refTableFile
] = diff
1133 print("template %s matched: r%s ok" % (refTableFile
, i
))
1136 resultstr
= "No template matched.\n"
1137 for f
in diffresult
.iterkeys():
1138 resultstr
+= "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1143 raise AssertionError(
1144 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i
, resultstr
)
1147 # Make sure that all daemons are running
1148 for i
in range(1, 2):
1149 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1150 assert fatal_error
== "", fatal_error
1152 # For debugging after starting FRR daemons, uncomment the next line
1156 def test_route_map():
1160 if fatal_error
!= "":
1161 pytest
.skip(fatal_error
)
1163 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1165 print("\n\n** Verifying some basic routemap forward references\n")
1166 print("*******************************************************\n")
1168 for i
in range(1, 2):
1169 refroutemap
= "%s/r%s/show_route_map.ref" % (thisDir
, i
)
1170 if os
.path
.isfile(refroutemap
):
1171 expected
= open(refroutemap
).read().rstrip()
1172 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1175 net
["r%s" % i
].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1177 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1179 diff
= topotest
.get_textdiff(
1182 title1
="actual show route-map",
1183 title2
="expected show route-map",
1188 "r%s failed show route-map command Check:\n%s\n" % (i
, diff
)
1196 ), "Show route-map command failed for router r%s:\n%s" % (i
, diff
)
1199 def test_nexthop_groups_with_route_maps():
1203 # Skip if previous fatal error condition is raised
1204 if fatal_error
!= "":
1205 pytest
.skip(fatal_error
)
1207 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1208 print("******************************************\n")
1210 ### Nexthop Group With Route-Map Tests
1212 # Create a lib nexthop-group
1214 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1217 ## Route-Map Proto Source
1219 route_str
= "2.2.2.1"
1220 src_str
= "192.168.0.1"
1223 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1225 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1227 net
["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str
)
1229 verify_route_nexthop_group("%s/32" % route_str
)
1231 # Only a valid test on linux using nexthop objects
1232 if sys
.platform
.startswith("linux"):
1233 output
= net
["r1"].cmd("ip route show %s/32" % route_str
)
1234 match
= re
.search(r
"src %s" % src_str
, output
)
1235 assert match
is not None, "Route %s/32 not installed with src %s" % (
1240 # Remove NHG routes and route-map
1241 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str
)
1242 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
1244 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" -c "set src %s"' % src_str
1246 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1248 ## Route-Map Deny/Permit with same nexthop group
1250 permit_route_str
= "3.3.3.1"
1251 deny_route_str
= "3.3.3.2"
1254 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1257 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1259 net
["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1260 net
["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1262 # This route should be permitted
1264 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1267 verify_route_nexthop_group("%s/32" % permit_route_str
)
1269 # This route should be denied
1271 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1274 nhg_id
= route_get_nhg_id(deny_route_str
)
1275 output
= net
["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id
)
1277 match
= re
.search(r
"Valid", output
)
1278 assert match
is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1280 match
= re
.search(r
"Installed", output
)
1281 assert match
is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1283 # Remove NHG routes and route-map
1284 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str
)
1285 net
["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str
)
1286 net
["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1287 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1288 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1289 net
["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
1291 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1296 def test_nexthop_group_replace():
1300 # Skip if previous fatal error condition is raised
1301 if fatal_error
!= "":
1302 pytest
.skip(fatal_error
)
1304 print("\n\n** Verifying Nexthop Groups")
1305 print("******************************************\n")
1307 ### Nexthop Group Tests
1309 ## 2-Way ECMP Directly Connected
1312 '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"'
1315 # Create with sharpd using nexthop-group
1316 net
["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1318 verify_route_nexthop_group("3.3.3.1/32")
1320 # Change the nexthop group
1322 '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"'
1325 # Verify it updated. We can just check install and ecmp count here.
1326 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1329 def test_mpls_interfaces():
1333 # Skip if previous fatal error condition is raised
1334 if fatal_error
!= "":
1335 pytest
.skip(fatal_error
)
1337 # Skip if no LDP installed or old kernel
1338 if net
["r1"].daemon_available("ldpd") == False:
1339 pytest
.skip("No MPLS or kernel < 4.5")
1341 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1343 print("\n\n** Verifying MPLS Interfaces")
1344 print("******************************************\n")
1346 for i
in range(1, 2):
1347 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir
, i
)
1348 if os
.path
.isfile(refTableFile
):
1349 # Read expected result from file
1350 expected
= open(refTableFile
).read().rstrip()
1351 # Fix newlines (make them all the same)
1352 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
1354 # Actual output from router
1357 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1360 # Mask out Timer in Uptime
1361 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
1362 # Fix newlines (make them all the same)
1363 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
1366 diff
= topotest
.get_textdiff(
1369 title1
="actual MPLS LDP interface status",
1370 title2
="expected MPLS LDP interface status",
1373 # Empty string if it matches, otherwise diff contains unified diff
1376 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
1383 fatal_error
= "MPLS LDP Interface status failed"
1387 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
1389 # Make sure that all daemons are running
1390 for i
in range(1, 2):
1391 fatal_error
= net
["r%s" % i
].checkRouterRunning()
1392 assert fatal_error
== "", fatal_error
1394 # For debugging after starting FRR daemons, uncomment the next line
1398 def test_shutdown_check_stderr():
1402 # Skip if previous fatal error condition is raised
1403 if fatal_error
!= "":
1404 pytest
.skip(fatal_error
)
1406 print("\n\n** Verifying unexpected STDERR output from daemons")
1407 print("******************************************\n")
1409 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
1411 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1413 pytest
.skip("Skipping test for Stderr output")
1415 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1417 print("thisDir=" + thisDir
)
1419 net
["r1"].stopRouter()
1421 log
= net
["r1"].getStdErr("ripd")
1423 print("\nRIPd StdErr Log:\n" + log
)
1424 log
= net
["r1"].getStdErr("ripngd")
1426 print("\nRIPngd StdErr Log:\n" + log
)
1427 log
= net
["r1"].getStdErr("ospfd")
1429 print("\nOSPFd StdErr Log:\n" + log
)
1430 log
= net
["r1"].getStdErr("ospf6d")
1432 print("\nOSPF6d StdErr Log:\n" + log
)
1433 log
= net
["r1"].getStdErr("isisd")
1435 print("\nISISd StdErr Log:\n" + log
)
1436 log
= net
["r1"].getStdErr("bgpd")
1438 print("\nBGPd StdErr Log:\n" + log
)
1440 log
= net
["r1"].getStdErr("nhrpd")
1442 print("\nNHRPd StdErr Log:\n" + log
)
1444 log
= net
["r1"].getStdErr("pbrd")
1446 print("\nPBRd StdErr Log:\n" + log
)
1448 log
= net
["r1"].getStdErr("babeld")
1450 print("\nBABELd StdErr Log:\n" + log
)
1452 if net
["r1"].daemon_available("ldpd"):
1453 log
= net
["r1"].getStdErr("ldpd")
1455 print("\nLDPd StdErr Log:\n" + log
)
1456 log
= net
["r1"].getStdErr("zebra")
1458 print("\nZebra StdErr Log:\n" + log
)
1461 def test_shutdown_check_memleak():
1465 # Skip if previous fatal error condition is raised
1466 if fatal_error
!= "":
1467 pytest
.skip(fatal_error
)
1469 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1471 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1473 pytest
.skip("Skipping test for memory leaks")
1475 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
1477 for i
in range(1, 2):
1478 net
["r%s" % i
].stopRouter()
1479 net
["r%s" % i
].report_memory_leaks(
1480 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
1484 if __name__
== "__main__":
1487 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1488 # retval = pytest.main(["-s", "--tb=no"])
1489 retval
= pytest
.main(["-s"])