]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/all_protocol_startup/test_all_protocol_startup.py
Merge pull request #9655 from yyuanam/first_commit
[mirror_frr.git] / tests / topotests / all_protocol_startup / test_all_protocol_startup.py
1 #!/usr/bin/env python
2
3 #
4 # test_all_protocol_startup.py
5 # Part of NetDEF Topology Tests
6 #
7 # Copyright (c) 2017 by
8 # Network Device Education Foundation, Inc. ("NetDEF")
9 #
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
13 # in all copies.
14 #
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
22 # OF THIS SOFTWARE.
23 #
24
25 """
26 test_all_protocol_startup.py: Test of all protocols at same time
27
28 """
29
30 import os
31 import re
32 import sys
33 import pytest
34 import glob
35 from time import sleep
36
37
38 pytestmark = [
39 pytest.mark.babeld,
40 pytest.mark.bgpd,
41 pytest.mark.isisd,
42 pytest.mark.nhrpd,
43 pytest.mark.ospfd,
44 pytest.mark.pbrd,
45 pytest.mark.ripd,
46 ]
47
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
51
52 fatal_error = ""
53
54
55 #####################################################
56 ##
57 ## Network Topology Definition
58 ##
59 #####################################################
60
61
62 def build_topo(tgen):
63 router = tgen.add_router("r1")
64 for i in range(0, 10):
65 tgen.add_switch("sw%d" % i).add_link(router)
66
67
68 #####################################################
69 ##
70 ## Tests starting
71 ##
72 #####################################################
73
74
75 def setup_module(module):
76 global fatal_error
77
78 print("\n\n** %s: Setup Topology" % module.__name__)
79 print("******************************************\n")
80
81 thisDir = os.path.dirname(os.path.realpath(__file__))
82 tgen = Topogen(build_topo, module.__name__)
83 tgen.start_topology()
84
85 net = tgen.net
86
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)
91
92 # Starting Routers
93 #
94 # Main router
95 for i in range(1, 2):
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)
103 )
104 else:
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()
116
117 # For debugging after starting FRR daemons, uncomment the next line
118 # CLI(net)
119
120
121 def teardown_module(module):
122 print("\n\n** %s: Shutdown Topology" % module.__name__)
123 print("******************************************\n")
124 tgen = get_topogen()
125 tgen.stop_topology()
126
127
128 def test_router_running():
129 global fatal_error
130 net = get_topogen().net
131
132 # Skip if previous fatal error condition is raised
133 if fatal_error != "":
134 pytest.skip(fatal_error)
135
136 print("\n\n** Check if FRR is running on each Router node")
137 print("******************************************\n")
138 sleep(5)
139
140 # Starting Routers
141 for i in range(1, 2):
142 fatal_error = net["r%s" % i].checkRouterRunning()
143 assert fatal_error == "", fatal_error
144
145 # For debugging after starting FRR daemons, uncomment the next line
146 # CLI(net)
147
148
149 def test_error_messages_vtysh():
150 global fatal_error
151 net = get_topogen().net
152
153 # Skip if previous fatal error condition is raised
154 if fatal_error != "":
155 pytest.skip(fatal_error)
156
157 print("\n\n** Check for error messages on VTYSH")
158 print("******************************************\n")
159
160 failures = 0
161 for i in range(1, 2):
162 #
163 # First checking Standard Output
164 #
165
166 # VTYSH output from router
167 vtystdout = net["r%s" % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
168
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)
173
174 if vtystdout == "":
175 print("r%s StdOut ok" % i)
176
177 assert vtystdout == "", "Vtysh StdOut Output check failed for router r%s" % i
178
179 #
180 # Second checking Standard Error
181 #
182
183 # VTYSH StdErr output from router
184 vtystderr = net["r%s" % i].cmd('vtysh -c "show version" > /dev/null').rstrip()
185
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)
190
191 if vtystderr == "":
192 print("r%s StdErr ok" % i)
193
194 assert vtystderr == "", "Vtysh StdErr Output check failed for router r%s" % i
195
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
200
201 # For debugging after starting FRR daemons, uncomment the next line
202 # CLI(net)
203
204
205 def test_error_messages_daemons():
206 global fatal_error
207 net = get_topogen().net
208
209 # Skip if previous fatal error condition is raised
210 if fatal_error != "":
211 pytest.skip(fatal_error)
212
213 print("\n\n** Check for error messages in daemons")
214 print("******************************************\n")
215
216 error_logs = ""
217
218 for i in range(1, 2):
219 log = net["r%s" % i].getStdErr("ripd")
220 if log:
221 error_logs += "r%s RIPd StdErr Output:\n" % i
222 error_logs += log
223 log = net["r%s" % i].getStdErr("ripngd")
224 if log:
225 error_logs += "r%s RIPngd StdErr Output:\n" % i
226 error_logs += log
227 log = net["r%s" % i].getStdErr("ospfd")
228 if log:
229 error_logs += "r%s OSPFd StdErr Output:\n" % i
230 error_logs += log
231 log = net["r%s" % i].getStdErr("ospf6d")
232 if log:
233 error_logs += "r%s OSPF6d StdErr Output:\n" % i
234 error_logs += log
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()
239 if log:
240 error_logs += "r%s ISISd StdErr Output:\n" % i
241 error_logs += log
242 log = net["r%s" % i].getStdErr("bgpd")
243 if log:
244 error_logs += "r%s BGPd StdErr Output:\n" % i
245 error_logs += log
246 if net["r%s" % i].daemon_available("ldpd"):
247 log = net["r%s" % i].getStdErr("ldpd")
248 if log:
249 error_logs += "r%s LDPd StdErr Output:\n" % i
250 error_logs += log
251
252 log = net["r1"].getStdErr("nhrpd")
253 # NHRPD shows YANG model not embedded messages
254 # Ignore these
255 log = re.sub(r".*YANG model.*not embedded.*", "", log).rstrip()
256 if log:
257 error_logs += "r%s NHRPd StdErr Output:\n" % i
258 error_logs += log
259
260 log = net["r1"].getStdErr("babeld")
261 if log:
262 error_logs += "r%s BABELd StdErr Output:\n" % i
263 error_logs += log
264
265 log = net["r1"].getStdErr("pbrd")
266 if log:
267 error_logs += "r%s PBRd StdErr Output:\n" % i
268 error_logs += log
269
270 log = net["r%s" % i].getStdErr("zebra")
271 if log:
272 error_logs += "r%s Zebra StdErr Output:\n" % i
273 error_logs += log
274
275 if error_logs:
276 sys.stderr.write(
277 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
278 )
279
280 # Ignoring the issue if told to ignore (ie not yet fixed)
281 if error_logs != "":
282 if os.environ.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
283 sys.stderr.write(
284 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
285 )
286 pytest.skip(
287 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
288 )
289
290 assert error_logs == "", "Daemons report errors to StdErr"
291
292 # For debugging after starting FRR daemons, uncomment the next line
293 # CLI(net)
294
295
296 def test_converge_protocols():
297 global fatal_error
298 net = get_topogen().net
299
300 # Skip if previous fatal error condition is raised
301 if fatal_error != "":
302 pytest.skip(fatal_error)
303
304 thisDir = os.path.dirname(os.path.realpath(__file__))
305
306 print("\n\n** Waiting for protocols convergence")
307 print("******************************************\n")
308
309 # Not really implemented yet - just sleep 60 secs for now
310 sleep(60)
311
312 # Make sure that all daemons are running
313 failures = 0
314 for i in range(1, 2):
315 fatal_error = net["r%s" % i].checkRouterRunning()
316 assert fatal_error == "", fatal_error
317
318 print("Show that v4 routes are right\n")
319 v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i)
320 expected = (
321 net["r%s" % i].cmd("sort {} 2> /dev/null".format(v4_routesFile)).rstrip()
322 )
323 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
324
325 actual = (
326 net["r%s" % i]
327 .cmd(
328 "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null"
329 )
330 .rstrip()
331 )
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(
336 actual,
337 expected,
338 title1="Actual IP Routing Table",
339 title2="Expected IP RoutingTable",
340 )
341 if diff:
342 sys.stderr.write("r%s failed IP Routing table check:\n%s\n" % (i, diff))
343 failures += 1
344 else:
345 print("r%s ok" % i)
346
347 assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff)
348
349 failures = 0
350
351 print("Show that v6 routes are right\n")
352 v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i)
353 expected = (
354 net["r%s" % i].cmd("sort {} 2> /dev/null".format(v6_routesFile)).rstrip()
355 )
356 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
357
358 actual = (
359 net["r%s" % i]
360 .cmd(
361 "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null"
362 )
363 .rstrip()
364 )
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(
369 actual,
370 expected,
371 title1="Actual IPv6 Routing Table",
372 title2="Expected IPv6 RoutingTable",
373 )
374 if diff:
375 sys.stderr.write("r%s failed IPv6 Routing table check:\n%s\n" % (i, diff))
376 failures += 1
377 else:
378 print("r%s ok" % i)
379
380 assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff)
381
382 # For debugging after starting FRR daemons, uncomment the next line
383 ## CLI(net)
384
385
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
392 )
393
394 nhg_id = int(match.group(1))
395 return nhg_id
396
397
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)
402
403 match = re.search(r"Valid", output)
404 assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
405
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
409
410 # list of IDs in group
411 depends = re.findall(r"\((\d+)\)", match.group(0))
412
413 if ecmp:
414 assert len(depends) == ecmp, (
415 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
416 )
417 else:
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
421 )
422 resolved_id = int(depends[0])
423 verify_nexthop_group(resolved_id, False)
424
425 else:
426 match = re.search(r"Installed", output)
427 assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id
428
429
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)
434
435
436 def test_nexthop_groups():
437 global fatal_error
438 net = get_topogen().net
439
440 # Skip if previous fatal error condition is raised
441 if fatal_error != "":
442 pytest.skip(fatal_error)
443
444 print("\n\n** Verifying Nexthop Groups")
445 print("******************************************\n")
446
447 ### Nexthop Group Tests
448
449 ## Basic test
450
451 # Create a lib nexthop-group
452 net["r1"].cmd(
453 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
454 )
455
456 # Create with sharpd using nexthop-group
457 net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
458
459 verify_route_nexthop_group("2.2.2.1/32")
460
461 ## Connected
462
463 net["r1"].cmd(
464 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
465 )
466
467 net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
468
469 verify_route_nexthop_group("2.2.2.2/32")
470
471 ## Recursive
472
473 net["r1"].cmd(
474 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
475 )
476
477 net["r1"].cmd(
478 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
479 )
480
481 verify_route_nexthop_group("3.3.3.1/32", True)
482
483 ## Duplicate
484
485 net["r1"].cmd(
486 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
487 )
488
489 net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
490
491 verify_route_nexthop_group("3.3.3.2/32")
492
493 ## Two 4-Way ECMP
494
495 net["r1"].cmd(
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"'
498 )
499
500 net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
501
502 verify_route_nexthop_group("4.4.4.1/32")
503
504 net["r1"].cmd(
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"'
507 )
508
509 net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
510
511 verify_route_nexthop_group("4.4.4.2/32")
512
513 ## Recursive to 8-Way ECMP
514
515 net["r1"].cmd(
516 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
517 )
518
519 net["r1"].cmd(
520 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
521 )
522
523 verify_route_nexthop_group("5.5.5.1/32")
524
525 ## 4-way ECMP Routes Pointing to Each Other
526
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.
530
531 net["r1"].cmd(
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"'
534 )
535
536 # static route nexthops can recurse to
537
538 net["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
539
540 # Make routes that point to themselves in ecmp
541
542 net["r1"].cmd(
543 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
544 )
545
546 net["r1"].cmd(
547 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
548 )
549
550 net["r1"].cmd(
551 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
552 )
553
554 net["r1"].cmd(
555 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
556 )
557
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)
561
562 dups = re.findall(r"(via 1\.1\.1\.1)", output)
563
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"
567 % nhg_id
568 )
569
570 ##CLI(net)
571
572 ## Remove all NHG routes
573
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"')
583
584
585 def test_rip_status():
586 global fatal_error
587 net = get_topogen().net
588
589 # Skip if previous fatal error condition is raised
590 if fatal_error != "":
591 pytest.skip(fatal_error)
592
593 thisDir = os.path.dirname(os.path.realpath(__file__))
594
595 print("\n\n** Verifying RIP status")
596 print("******************************************\n")
597 failures = 0
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)
605
606 # Actual output from router
607 actual = (
608 net["r%s" % i]
609 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
610 .rstrip()
611 )
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)
618
619 # Generate Diff
620 diff = topotest.get_textdiff(
621 actual,
622 expected,
623 title1="actual IP RIP status",
624 title2="expected IP RIP status",
625 )
626
627 # Empty string if it matches, otherwise diff contains unified diff
628 if diff:
629 sys.stderr.write("r%s failed IP RIP status check:\n%s\n" % (i, diff))
630 failures += 1
631 else:
632 print("r%s ok" % i)
633
634 assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff)
635
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
640
641 # For debugging after starting FRR daemons, uncomment the next line
642 # CLI(net)
643
644
645 def test_ripng_status():
646 global fatal_error
647 net = get_topogen().net
648
649 # Skip if previous fatal error condition is raised
650 if fatal_error != "":
651 pytest.skip(fatal_error)
652
653 thisDir = os.path.dirname(os.path.realpath(__file__))
654
655 print("\n\n** Verifying RIPng status")
656 print("******************************************\n")
657 failures = 0
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)
665
666 # Actual output from router
667 actual = (
668 net["r%s" % i]
669 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
670 .rstrip()
671 )
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)
680
681 # Generate Diff
682 diff = topotest.get_textdiff(
683 actual,
684 expected,
685 title1="actual IPv6 RIPng status",
686 title2="expected IPv6 RIPng status",
687 )
688
689 # Empty string if it matches, otherwise diff contains unified diff
690 if diff:
691 sys.stderr.write(
692 "r%s failed IPv6 RIPng status check:\n%s\n" % (i, diff)
693 )
694 failures += 1
695 else:
696 print("r%s ok" % i)
697
698 assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
699 i,
700 diff,
701 )
702
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
707
708 # For debugging after starting FRR daemons, uncomment the next line
709 # CLI(net)
710
711
712 def test_ospfv2_interfaces():
713 global fatal_error
714 net = get_topogen().net
715
716 # Skip if previous fatal error condition is raised
717 if fatal_error != "":
718 pytest.skip(fatal_error)
719
720 thisDir = os.path.dirname(os.path.realpath(__file__))
721
722 print("\n\n** Verifying OSPFv2 interfaces")
723 print("******************************************\n")
724 failures = 0
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)
732
733 # Actual output from router
734 actual = (
735 net["r%s" % i]
736 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
737 .rstrip()
738 )
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)
742
743 # Drop time in next due
744 actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual)
745 actual = re.sub(
746 r"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
747 )
748 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
749 actual = re.sub(
750 r"MTU mismatch detection:([a-z]+.*)",
751 r"MTU mismatch detection: \1",
752 actual,
753 )
754 # Fix newlines (make them all the same)
755 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
756
757 # Generate Diff
758 diff = topotest.get_textdiff(
759 actual,
760 expected,
761 title1="actual SHOW IP OSPF INTERFACE",
762 title2="expected SHOW IP OSPF INTERFACE",
763 )
764
765 # Empty string if it matches, otherwise diff contains unified diff
766 if diff:
767 sys.stderr.write(
768 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i, diff)
769 )
770 failures += 1
771 else:
772 print("r%s ok" % i)
773
774 # Ignoring the issue if told to ignore (ie not yet fixed)
775 if failures != 0:
776 if os.environ.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
777 sys.stderr.write(
778 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
779 )
780 pytest.skip(
781 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
782 )
783
784 assert (
785 failures == 0
786 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff)
787
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
792
793 # For debugging after starting FRR daemons, uncomment the next line
794 # CLI(net)
795
796
797 def test_isis_interfaces():
798 global fatal_error
799 net = get_topogen().net
800
801 # Skip if previous fatal error condition is raised
802 if fatal_error != "":
803 pytest.skip(fatal_error)
804
805 thisDir = os.path.dirname(os.path.realpath(__file__))
806
807 print("\n\n** Verifying ISIS interfaces")
808 print("******************************************\n")
809 failures = 0
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)
817
818 # Actual output from router
819 actual = (
820 net["r%s" % i]
821 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
822 .rstrip()
823 )
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)
832
833 # Generate Diff
834 diff = topotest.get_textdiff(
835 actual,
836 expected,
837 title1="actual SHOW ISIS INTERFACE DETAIL",
838 title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
839 )
840
841 # Empty string if it matches, otherwise diff contains unified diff
842 if diff:
843 sys.stderr.write(
844 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i, diff)
845 )
846 failures += 1
847 else:
848 print("r%s ok" % i)
849
850 assert (
851 failures == 0
852 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff)
853
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
858
859 # For debugging after starting FRR daemons, uncomment the next line
860 # CLI(net)
861
862
863 def test_bgp_summary():
864 global fatal_error
865 net = get_topogen().net
866
867 # Skip if previous fatal error condition is raised
868 if fatal_error != "":
869 pytest.skip(fatal_error)
870
871 thisDir = os.path.dirname(os.path.realpath(__file__))
872
873 print("\n\n** Verifying BGP Summary")
874 print("******************************************\n")
875 failures = 0
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()
881
882 for arguments in [
883 "",
884 "remote-as internal",
885 "remote-as external",
886 "remote-as 100",
887 "remote-as 123",
888 "neighbor 192.168.7.10",
889 "neighbor 192.168.7.10",
890 "neighbor fc00:0:0:8::1000",
891 "neighbor 10.0.0.1",
892 "terse",
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",
901 ]:
902 # Actual output from router
903 actual = (
904 net["r%s" % i]
905 .cmd(
906 'vtysh -c "show ip bgp summary ' + arguments + '" 2> /dev/null'
907 )
908 .rstrip()
909 )
910
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)
915
916 # Remove extra summaries which exist with newer versions
917
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)
938
939 actual = re.sub(
940 r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
941 )
942 actual = re.sub(
943 r"No IPv4 labeled-unicast neighbor is configured", "", actual
944 )
945
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:
953 expected = re.sub(
954 r"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
955 "",
956 expected,
957 )
958 expected = re.sub(r"\nNeighbor.+Desc", "", expected)
959 expected = expected + "% No matching neighbor\n"
960 elif "192.168.7.10" in arguments:
961 expected = re.sub(
962 r"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
963 )
964 elif "fc00:0:0:8::1000" in arguments:
965 expected = re.sub(
966 r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
967 )
968 elif "10.0.0.1" in arguments:
969 expected = "No such neighbor in this view/vrf"
970
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)
975
976 # Strip empty lines
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)
981
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)
986 else:
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)
989
990 # realign expected neighbor columns if needed
991 try:
992 idx_actual = (
993 re.search(r"(Neighbor\s+V\s+)", actual).group(1).find("V")
994 )
995 idx_expected = (
996 re.search(r"(Neighbor\s+V\s+)", expected).group(1).find("V")
997 )
998 idx_diff = idx_expected - idx_actual
999 if idx_diff > 0:
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:
1005 pass
1006
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)
1010
1011 # Generate Diff
1012 diff = topotest.get_textdiff(
1013 actual,
1014 expected,
1015 title1="actual SHOW IP BGP SUMMARY " + arguments.upper(),
1016 title2="expected SHOW IP BGP SUMMARY " + arguments.upper(),
1017 )
1018
1019 # Empty string if it matches, otherwise diff contains unified diff
1020 if diff:
1021 sys.stderr.write(
1022 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff)
1023 )
1024 failures += 1
1025 else:
1026 print("r%s ok" % i)
1027
1028 assert (
1029 failures == 0
1030 ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
1031 i,
1032 diff,
1033 )
1034
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
1039
1040 # For debugging after starting FRR daemons, uncomment the next line
1041 # CLI(net)
1042
1043
1044 def test_bgp_ipv6_summary():
1045 global fatal_error
1046 net = get_topogen().net
1047
1048 # Skip if previous fatal error condition is raised
1049 if fatal_error != "":
1050 pytest.skip(fatal_error)
1051
1052 thisDir = os.path.dirname(os.path.realpath(__file__))
1053
1054 print("\n\n** Verifying BGP IPv6 Summary")
1055 print("******************************************\n")
1056 failures = 0
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)
1064
1065 # Actual output from router
1066 actual = (
1067 net["r%s" % i]
1068 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
1069 .rstrip()
1070 )
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)
1075 #
1076 # Remove extra summaries which exist with newer versions
1077 #
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)
1098
1099 # Remove Labeled Unicast Summary (all of it)
1100 actual = re.sub(
1101 r"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
1102 )
1103 actual = re.sub(
1104 r"No IPv6 labeled-unicast neighbor is configured", "", actual
1105 )
1106
1107 # Strip empty lines
1108 actual = actual.lstrip()
1109 actual = actual.rstrip()
1110 #
1111 # Fix newlines (make them all the same)
1112 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
1113
1114 # Generate Diff
1115 diff = topotest.get_textdiff(
1116 actual,
1117 expected,
1118 title1="actual SHOW BGP IPv6 SUMMARY",
1119 title2="expected SHOW BGP IPv6 SUMMARY",
1120 )
1121
1122 # Empty string if it matches, otherwise diff contains unified diff
1123 if diff:
1124 sys.stderr.write(
1125 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i, diff)
1126 )
1127 failures += 1
1128 else:
1129 print("r%s ok" % i)
1130
1131 assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1132 i,
1133 diff,
1134 )
1135
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
1140
1141 # For debugging after starting FRR daemons, uncomment the next line
1142 # CLI(net)
1143
1144
1145 def test_nht():
1146 net = get_topogen().net
1147 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1148
1149 thisDir = os.path.dirname(os.path.realpath(__file__))
1150
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)
1155
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)
1159
1160 diff = topotest.get_textdiff(
1161 actual,
1162 expected,
1163 title1="Actual `show ip nht`",
1164 title2="Expected `show ip nht`",
1165 )
1166
1167 if diff:
1168 assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff)
1169 else:
1170 print("show ip nht is ok\n")
1171
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)
1175
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)
1179
1180 diff = topotest.get_textdiff(
1181 actual,
1182 expected,
1183 title1="Actual `show ip nht`",
1184 title2="Expected `show ip nht`",
1185 )
1186
1187 if diff:
1188 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff)
1189 else:
1190 print("show ipv6 nht is ok\n")
1191
1192
1193 def test_bgp_ipv4():
1194 global fatal_error
1195 net = get_topogen().net
1196
1197 # Skip if previous fatal error condition is raised
1198 if fatal_error != "":
1199 pytest.skip(fatal_error)
1200
1201 thisDir = os.path.dirname(os.path.realpath(__file__))
1202
1203 print("\n\n** Verifying BGP IPv4")
1204 print("******************************************\n")
1205 diffresult = {}
1206 for i in range(1, 2):
1207 success = 0
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)
1214
1215 # Actual output from router
1216 actual = (
1217 net["r%s" % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1218 )
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)
1225
1226 # Generate Diff
1227 diff = topotest.get_textdiff(
1228 actual,
1229 expected,
1230 title1="actual SHOW BGP IPv4",
1231 title2="expected SHOW BGP IPv4",
1232 )
1233
1234 # Empty string if it matches, otherwise diff contains unified diff
1235 if diff:
1236 diffresult[refTableFile] = diff
1237 else:
1238 success = 1
1239 print("template %s matched: r%s ok" % (refTableFile, i))
1240 break
1241
1242 if not success:
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" % (
1246 f,
1247 i,
1248 diffresult[f],
1249 )
1250 raise AssertionError(
1251 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr)
1252 )
1253
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
1258
1259 # For debugging after starting FRR daemons, uncomment the next line
1260 # CLI(net)
1261
1262
1263 def test_bgp_ipv6():
1264 global fatal_error
1265 net = get_topogen().net
1266
1267 # Skip if previous fatal error condition is raised
1268 if fatal_error != "":
1269 pytest.skip(fatal_error)
1270
1271 thisDir = os.path.dirname(os.path.realpath(__file__))
1272
1273 print("\n\n** Verifying BGP IPv6")
1274 print("******************************************\n")
1275 diffresult = {}
1276 for i in range(1, 2):
1277 success = 0
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)
1284
1285 # Actual output from router
1286 actual = (
1287 net["r%s" % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1288 )
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)
1295
1296 # Generate Diff
1297 diff = topotest.get_textdiff(
1298 actual,
1299 expected,
1300 title1="actual SHOW BGP IPv6",
1301 title2="expected SHOW BGP IPv6",
1302 )
1303
1304 # Empty string if it matches, otherwise diff contains unified diff
1305 if diff:
1306 diffresult[refTableFile] = diff
1307 else:
1308 success = 1
1309 print("template %s matched: r%s ok" % (refTableFile, i))
1310
1311 if not success:
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" % (
1315 f,
1316 i,
1317 diffresult[f],
1318 )
1319 raise AssertionError(
1320 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr)
1321 )
1322
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
1327
1328 # For debugging after starting FRR daemons, uncomment the next line
1329 # CLI(net)
1330
1331
1332 def test_route_map():
1333 global fatal_error
1334 net = get_topogen().net
1335
1336 if fatal_error != "":
1337 pytest.skip(fatal_error)
1338
1339 thisDir = os.path.dirname(os.path.realpath(__file__))
1340
1341 print("\n\n** Verifying some basic routemap forward references\n")
1342 print("*******************************************************\n")
1343 failures = 0
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)
1349
1350 actual = (
1351 net["r%s" % i].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1352 )
1353 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
1354
1355 diff = topotest.get_textdiff(
1356 actual,
1357 expected,
1358 title1="actual show route-map",
1359 title2="expected show route-map",
1360 )
1361
1362 if diff:
1363 sys.stderr.write(
1364 "r%s failed show route-map command Check:\n%s\n" % (i, diff)
1365 )
1366 failures += 1
1367 else:
1368 print("r%s ok" % i)
1369
1370 assert (
1371 failures == 0
1372 ), "Show route-map command failed for router r%s:\n%s" % (i, diff)
1373
1374
1375 def test_nexthop_groups_with_route_maps():
1376 global fatal_error
1377 net = get_topogen().net
1378
1379 # Skip if previous fatal error condition is raised
1380 if fatal_error != "":
1381 pytest.skip(fatal_error)
1382
1383 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1384 print("******************************************\n")
1385
1386 ### Nexthop Group With Route-Map Tests
1387
1388 # Create a lib nexthop-group
1389 net["r1"].cmd(
1390 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1391 )
1392
1393 ## Route-Map Proto Source
1394
1395 route_str = "2.2.2.1"
1396 src_str = "192.168.0.1"
1397
1398 net["r1"].cmd(
1399 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1400 )
1401 net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1402
1403 net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str)
1404
1405 verify_route_nexthop_group("%s/32" % route_str)
1406
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" % (
1412 route_str,
1413 src_str,
1414 )
1415
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"')
1419 net["r1"].cmd(
1420 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
1421 )
1422 net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1423
1424 ## Route-Map Deny/Permit with same nexthop group
1425
1426 permit_route_str = "3.3.3.1"
1427 deny_route_str = "3.3.3.2"
1428
1429 net["r1"].cmd(
1430 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1431 )
1432 net["r1"].cmd(
1433 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1434 )
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"')
1437
1438 # This route should be permitted
1439 net["r1"].cmd(
1440 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1441 )
1442
1443 verify_route_nexthop_group("%s/32" % permit_route_str)
1444
1445 # This route should be denied
1446 net["r1"].cmd(
1447 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1448 )
1449
1450 nhg_id = route_get_nhg_id(deny_route_str)
1451 output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
1452
1453 match = re.search(r"Valid", output)
1454 assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1455
1456 match = re.search(r"Installed", output)
1457 assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1458
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"')
1466 net["r1"].cmd(
1467 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1468 % permit_route_str
1469 )
1470
1471
1472 def test_nexthop_group_replace():
1473 global fatal_error
1474 net = get_topogen().net
1475
1476 # Skip if previous fatal error condition is raised
1477 if fatal_error != "":
1478 pytest.skip(fatal_error)
1479
1480 print("\n\n** Verifying Nexthop Groups")
1481 print("******************************************\n")
1482
1483 ### Nexthop Group Tests
1484
1485 ## 2-Way ECMP Directly Connected
1486
1487 net["r1"].cmd(
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"'
1489 )
1490
1491 # Create with sharpd using nexthop-group
1492 net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1493
1494 verify_route_nexthop_group("3.3.3.1/32")
1495
1496 # Change the nexthop group
1497 net["r1"].cmd(
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"'
1499 )
1500
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)
1503
1504
1505 def test_mpls_interfaces():
1506 global fatal_error
1507 net = get_topogen().net
1508
1509 # Skip if previous fatal error condition is raised
1510 if fatal_error != "":
1511 pytest.skip(fatal_error)
1512
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")
1516
1517 thisDir = os.path.dirname(os.path.realpath(__file__))
1518
1519 print("\n\n** Verifying MPLS Interfaces")
1520 print("******************************************\n")
1521 failures = 0
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)
1529
1530 # Actual output from router
1531 actual = (
1532 net["r%s" % i]
1533 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1534 .rstrip()
1535 )
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)
1540
1541 # Generate Diff
1542 diff = topotest.get_textdiff(
1543 actual,
1544 expected,
1545 title1="actual MPLS LDP interface status",
1546 title2="expected MPLS LDP interface status",
1547 )
1548
1549 # Empty string if it matches, otherwise diff contains unified diff
1550 if diff:
1551 sys.stderr.write(
1552 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i, diff)
1553 )
1554 failures += 1
1555 else:
1556 print("r%s ok" % i)
1557
1558 if failures > 0:
1559 fatal_error = "MPLS LDP Interface status failed"
1560
1561 assert (
1562 failures == 0
1563 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff)
1564
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
1569
1570 # For debugging after starting FRR daemons, uncomment the next line
1571 # CLI(net)
1572
1573
1574 def test_shutdown_check_stderr():
1575 global fatal_error
1576 net = get_topogen().net
1577
1578 # Skip if previous fatal error condition is raised
1579 if fatal_error != "":
1580 pytest.skip(fatal_error)
1581
1582 print("\n\n** Verifying unexpected STDERR output from daemons")
1583 print("******************************************\n")
1584
1585 if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
1586 print(
1587 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1588 )
1589 pytest.skip("Skipping test for Stderr output")
1590
1591 thisDir = os.path.dirname(os.path.realpath(__file__))
1592
1593 print("thisDir=" + thisDir)
1594
1595 net["r1"].stopRouter()
1596
1597 log = net["r1"].getStdErr("ripd")
1598 if log:
1599 print("\nRIPd StdErr Log:\n" + log)
1600 log = net["r1"].getStdErr("ripngd")
1601 if log:
1602 print("\nRIPngd StdErr Log:\n" + log)
1603 log = net["r1"].getStdErr("ospfd")
1604 if log:
1605 print("\nOSPFd StdErr Log:\n" + log)
1606 log = net["r1"].getStdErr("ospf6d")
1607 if log:
1608 print("\nOSPF6d StdErr Log:\n" + log)
1609 log = net["r1"].getStdErr("isisd")
1610 if log:
1611 print("\nISISd StdErr Log:\n" + log)
1612 log = net["r1"].getStdErr("bgpd")
1613 if log:
1614 print("\nBGPd StdErr Log:\n" + log)
1615
1616 log = net["r1"].getStdErr("nhrpd")
1617 if log:
1618 print("\nNHRPd StdErr Log:\n" + log)
1619
1620 log = net["r1"].getStdErr("pbrd")
1621 if log:
1622 print("\nPBRd StdErr Log:\n" + log)
1623
1624 log = net["r1"].getStdErr("babeld")
1625 if log:
1626 print("\nBABELd StdErr Log:\n" + log)
1627
1628 if net["r1"].daemon_available("ldpd"):
1629 log = net["r1"].getStdErr("ldpd")
1630 if log:
1631 print("\nLDPd StdErr Log:\n" + log)
1632 log = net["r1"].getStdErr("zebra")
1633 if log:
1634 print("\nZebra StdErr Log:\n" + log)
1635
1636
1637 def test_shutdown_check_memleak():
1638 global fatal_error
1639 net = get_topogen().net
1640
1641 # Skip if previous fatal error condition is raised
1642 if fatal_error != "":
1643 pytest.skip(fatal_error)
1644
1645 if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1646 print(
1647 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1648 )
1649 pytest.skip("Skipping test for memory leaks")
1650
1651 thisDir = os.path.dirname(os.path.realpath(__file__))
1652
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__)
1657 )
1658
1659
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"])
1664 sys.exit(retval)