]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/all-protocol-startup/test_all_protocol_startup.py
tests: Add pytest.mark.ospfd to tests
[mirror_frr.git] / tests / topotests / all-protocol-startup / test_all_protocol_startup.py
CommitLineData
4501fbca
MW
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"""
26test_all_protocol_startup.py: Test of all protocols at same time
27
28"""
29
30import os
31import re
32import sys
4501fbca 33import pytest
6a57e103 34import glob
4501fbca
MW
35from time import sleep
36
37from mininet.topo import Topo
38from mininet.net import Mininet
39from mininet.node import Node, OVSSwitch, Host
40from mininet.log import setLogLevel, info
41from mininet.cli import CLI
42from mininet.link import Intf
43
44from functools import partial
45
6907ac7e
DS
46pytestmark = [pytest.mark.isisd, pytest.mark.ospfd, pytest.mark.ripd]
47
4501fbca
MW
48sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
49from lib import topotest
50
51fatal_error = ""
52
53
54#####################################################
55##
56## Network Topology Definition
57##
58#####################################################
59
701a0192 60
4501fbca
MW
61class NetworkTopo(Topo):
62 "All Protocol Startup Test"
63
64 def build(self, **_opts):
65
66 # Setup Routers
67 router = {}
68 #
69 # Setup Main Router
701a0192 70 router[1] = topotest.addRouter(self, "r1")
4501fbca
MW
71 #
72
73 # Setup Switches
74 switch = {}
75 #
76 for i in range(0, 10):
701a0192 77 switch[i] = self.addSwitch("sw%s" % i, cls=topotest.LegacySwitch)
78 self.addLink(switch[i], router[1], intfName2="r1-eth%s" % i)
4501fbca
MW
79
80
81#####################################################
82##
83## Tests starting
84##
85#####################################################
86
13f93db3 87
4501fbca
MW
88def setup_module(module):
89 global topo, net
90 global fatal_error
91
92 print("\n\n** %s: Setup Topology" % module.__name__)
93 print("******************************************\n")
94
95 print("Cleanup old Mininet runs")
701a0192 96 os.system("sudo mn -c > /dev/null 2>&1")
97 os.system("sudo rm /tmp/r* > /dev/null 2>&1")
4501fbca
MW
98
99 thisDir = os.path.dirname(os.path.realpath(__file__))
100 topo = NetworkTopo()
101
102 net = Mininet(controller=None, topo=topo)
103 net.start()
104
701a0192 105 if net["r1"].get_routertype() != "frr":
4501fbca 106 fatal_error = "Test is only implemented for FRR"
701a0192 107 sys.stderr.write("\n\nTest is only implemented for FRR - Skipping\n\n")
4501fbca 108 pytest.skip(fatal_error)
701a0192 109
4501fbca
MW
110 # Starting Routers
111 #
112 # Main router
113 for i in range(1, 2):
701a0192 114 net["r%s" % i].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir, i))
115 net["r%s" % i].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir, i))
116 net["r%s" % i].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir, i))
117 net["r%s" % i].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir, i))
118 if net["r1"].checkRouterVersion("<", "4.0"):
119 net["r%s" % i].loadConf(
120 "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir, i)
121 )
11761ab0 122 else:
701a0192 123 net["r%s" % i].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir, i))
124 net["r%s" % i].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir, i))
125 net["r%s" % i].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir, i))
126 if net["r%s" % i].daemon_available("ldpd"):
4501fbca 127 # Only test LDPd if it's installed and Kernel >= 4.5
701a0192 128 net["r%s" % i].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir, i))
129 net["r%s" % i].loadConf("sharpd")
130 net["r%s" % i].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir, i))
131 net["r%s" % i].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir, i))
132 net["r%s" % i].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir, i))
133 net["r%s" % i].startRouter()
4501fbca 134
622c4996 135 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
136 # CLI(net)
137
138
139def teardown_module(module):
140 global net
141
142 print("\n\n** %s: Shutdown Topology" % module.__name__)
143 print("******************************************\n")
144
145 # End - Shutdown network
146 net.stop()
147
148
149def test_router_running():
150 global fatal_error
151 global net
152
153 # Skip if previous fatal error condition is raised
701a0192 154 if fatal_error != "":
4501fbca
MW
155 pytest.skip(fatal_error)
156
622c4996 157 print("\n\n** Check if FRR is running on each Router node")
4501fbca
MW
158 print("******************************************\n")
159 sleep(5)
160
161 # Starting Routers
162 for i in range(1, 2):
701a0192 163 fatal_error = net["r%s" % i].checkRouterRunning()
4501fbca
MW
164 assert fatal_error == "", fatal_error
165
622c4996 166 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
167 # CLI(net)
168
169
170def test_error_messages_vtysh():
171 global fatal_error
172 global net
173
174 # Skip if previous fatal error condition is raised
701a0192 175 if fatal_error != "":
4501fbca
MW
176 pytest.skip(fatal_error)
177
178 print("\n\n** Check for error messages on VTYSH")
179 print("******************************************\n")
180
181 failures = 0
182 for i in range(1, 2):
183 #
184 # First checking Standard Output
185 #
186
187 # VTYSH output from router
701a0192 188 vtystdout = net["r%s" % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
4501fbca
MW
189
190 # Fix newlines (make them all the same)
701a0192 191 vtystdout = ("\n".join(vtystdout.splitlines()) + "\n").rstrip()
4501fbca
MW
192 # Drop everything starting with "FRRouting X.xx" message
193 vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL)
194
701a0192 195 if vtystdout == "":
4501fbca
MW
196 print("r%s StdOut ok" % i)
197
701a0192 198 assert vtystdout == "", "Vtysh StdOut Output check failed for router r%s" % i
798fb593 199
4501fbca
MW
200 #
201 # Second checking Standard Error
202 #
203
204 # VTYSH StdErr output from router
701a0192 205 vtystderr = net["r%s" % i].cmd('vtysh -c "show version" > /dev/null').rstrip()
4501fbca
MW
206
207 # Fix newlines (make them all the same)
701a0192 208 vtystderr = ("\n".join(vtystderr.splitlines()) + "\n").rstrip()
4501fbca 209 # # Drop everything starting with "FRRouting X.xx" message
701a0192 210 # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
4501fbca 211
701a0192 212 if vtystderr == "":
4501fbca
MW
213 print("r%s StdErr ok" % i)
214
701a0192 215 assert vtystderr == "", "Vtysh StdErr Output check failed for router r%s" % i
4501fbca 216
7e7fc73b
MW
217 # Make sure that all daemons are running
218 for i in range(1, 2):
701a0192 219 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
220 assert fatal_error == "", fatal_error
221
622c4996 222 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
223 # CLI(net)
224
225
226def test_error_messages_daemons():
227 global fatal_error
228 global net
229
230 # Skip if previous fatal error condition is raised
701a0192 231 if fatal_error != "":
4501fbca
MW
232 pytest.skip(fatal_error)
233
234 print("\n\n** Check for error messages in daemons")
235 print("******************************************\n")
236
237 error_logs = ""
238
239 for i in range(1, 2):
701a0192 240 log = net["r%s" % i].getStdErr("ripd")
4501fbca
MW
241 if log:
242 error_logs += "r%s RIPd StdErr Output:\n" % i
243 error_logs += log
701a0192 244 log = net["r%s" % i].getStdErr("ripngd")
4501fbca
MW
245 if log:
246 error_logs += "r%s RIPngd StdErr Output:\n" % i
247 error_logs += log
701a0192 248 log = net["r%s" % i].getStdErr("ospfd")
4501fbca
MW
249 if log:
250 error_logs += "r%s OSPFd StdErr Output:\n" % i
251 error_logs += log
701a0192 252 log = net["r%s" % i].getStdErr("ospf6d")
4501fbca
MW
253 if log:
254 error_logs += "r%s OSPF6d StdErr Output:\n" % i
255 error_logs += log
701a0192 256 log = net["r%s" % i].getStdErr("isisd")
4501fbca
MW
257 # ISIS shows debugging enabled status on StdErr
258 # Remove these messages
259 log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip()
260 if log:
261 error_logs += "r%s ISISd StdErr Output:\n" % i
262 error_logs += log
701a0192 263 log = net["r%s" % i].getStdErr("bgpd")
4501fbca
MW
264 if log:
265 error_logs += "r%s BGPd StdErr Output:\n" % i
266 error_logs += log
701a0192 267 if net["r%s" % i].daemon_available("ldpd"):
268 log = net["r%s" % i].getStdErr("ldpd")
4501fbca
MW
269 if log:
270 error_logs += "r%s LDPd StdErr Output:\n" % i
271 error_logs += log
af39fbe7 272
701a0192 273 log = net["r1"].getStdErr("nhrpd")
960c3f25
MW
274 # NHRPD shows YANG model not embedded messages
275 # Ignore these
276 log = re.sub(r".*YANG model.*not embedded.*", "", log).rstrip()
af39fbe7
MS
277 if log:
278 error_logs += "r%s NHRPd StdErr Output:\n" % i
279 error_logs += log
280
701a0192 281 log = net["r1"].getStdErr("babeld")
af39fbe7
MS
282 if log:
283 error_logs += "r%s BABELd StdErr Output:\n" % i
284 error_logs += log
285
701a0192 286 log = net["r1"].getStdErr("pbrd")
af39fbe7
MS
287 if log:
288 error_logs += "r%s PBRd StdErr Output:\n" % i
289 error_logs += log
290
701a0192 291 log = net["r%s" % i].getStdErr("zebra")
4501fbca 292 if log:
960c3f25 293 error_logs += "r%s Zebra StdErr Output:\n" % i
4501fbca
MW
294 error_logs += log
295
296 if error_logs:
701a0192 297 sys.stderr.write(
298 "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
299 )
4501fbca 300
08fa1af7 301 # Ignoring the issue if told to ignore (ie not yet fixed)
701a0192 302 if error_logs != "":
303 if os.environ.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
304 sys.stderr.write(
305 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
306 )
307 pytest.skip(
308 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
309 )
08fa1af7 310
4501fbca
MW
311 assert error_logs == "", "Daemons report errors to StdErr"
312
622c4996 313 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
314 # CLI(net)
315
316
317def test_converge_protocols():
318 global fatal_error
319 global net
320
321 # Skip if previous fatal error condition is raised
701a0192 322 if fatal_error != "":
4501fbca
MW
323 pytest.skip(fatal_error)
324
325 thisDir = os.path.dirname(os.path.realpath(__file__))
326
327 print("\n\n** Waiting for protocols convergence")
328 print("******************************************\n")
329
330 # Not really implemented yet - just sleep 60 secs for now
331 sleep(60)
332
7e7fc73b 333 # Make sure that all daemons are running
556f76e1 334 failures = 0
7e7fc73b 335 for i in range(1, 2):
701a0192 336 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
337 assert fatal_error == "", fatal_error
338
701a0192 339 print("Show that v4 routes are right\n")
340 v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i)
556f76e1 341 expected = open(v4_routesFile).read().rstrip()
701a0192 342 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
343
344 actual = (
345 net["r%s" % i]
346 .cmd(
ec20380c 347 'vtysh -c "show ip route" | sed -e \'/^Codes: /,/^\s*$/d\' | env LC_ALL=en_US.UTF-8 sort 2> /dev/null'
701a0192 348 )
349 .rstrip()
350 )
556f76e1
DS
351 # Drop time in last update
352 actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
701a0192 353 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
354 diff = topotest.get_textdiff(
355 actual,
356 expected,
357 title1="Actual IP Routing Table",
358 title2="Expected IP RoutingTable",
359 )
556f76e1 360 if diff:
701a0192 361 sys.stderr.write("r%s failed IP Routing table check:\n%s\n" % (i, diff))
556f76e1
DS
362 failures += 1
363 else:
701a0192 364 print("r%s ok" % i)
556f76e1
DS
365
366 assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff)
367
368 failures = 0
369
370 print("Show that v6 routes are right\n")
701a0192 371 v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i)
556f76e1 372 expected = open(v6_routesFile).read().rstrip()
701a0192 373 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
374
375 actual = (
376 net["r%s" % i]
377 .cmd(
ec20380c 378 'vtysh -c "show ipv6 route" | sed -e \'/^Codes: /,/^\s*$/d\' | env LC_ALL=en_US.UTF-8 sort 2> /dev/null'
701a0192 379 )
380 .rstrip()
381 )
556f76e1
DS
382 # Drop time in last update
383 actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
701a0192 384 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
385 diff = topotest.get_textdiff(
386 actual,
387 expected,
388 title1="Actual IPv6 Routing Table",
389 title2="Expected IPv6 RoutingTable",
390 )
556f76e1 391 if diff:
701a0192 392 sys.stderr.write("r%s failed IPv6 Routing table check:\n%s\n" % (i, diff))
556f76e1
DS
393 failures += 1
394 else:
701a0192 395 print("r%s ok" % i)
556f76e1
DS
396
397 assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff)
398
622c4996 399 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
400 ## CLI(net)
401
701a0192 402
887a232c
SW
403def route_get_nhg_id(route_str):
404 output = net["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str)
405 match = re.search(r"Nexthop Group ID: (\d+)", output)
701a0192 406 assert match is not None, (
407 "Nexthop Group ID not found for sharpd route %s" % route_str
408 )
887a232c
SW
409
410 nhg_id = int(match.group(1))
411 return nhg_id
412
701a0192 413
8f4d7212 414def verify_nexthop_group(nhg_id, recursive=False, ecmp=0):
887a232c
SW
415 # Verify NHG is valid/installed
416 output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
417
418 match = re.search(r"Valid", output)
419 assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
420
8f4d7212
SW
421 if ecmp or recursive:
422 match = re.search(r"Depends:.*\n", output)
423 assert match is not None, "Nexthop Group ID=%d has no depends" % nhg_id
424
425 # list of IDs in group
426 depends = re.findall(r"\((\d+)\)", match.group(0))
427
428 if ecmp:
701a0192 429 assert len(depends) == ecmp, (
430 "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
431 )
8f4d7212
SW
432 else:
433 # If recursive, we need to look at its resolved group
701a0192 434 assert len(depends) == 1, (
435 "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
436 )
8f4d7212
SW
437 resolved_id = int(depends[0])
438 verify_nexthop_group(resolved_id, False)
439
887a232c
SW
440 else:
441 match = re.search(r"Installed", output)
442 assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id
443
701a0192 444
8f4d7212 445def verify_route_nexthop_group(route_str, recursive=False, ecmp=0):
887a232c
SW
446 # Verify route and that zebra created NHGs for and they are valid/installed
447 nhg_id = route_get_nhg_id(route_str)
8f4d7212 448 verify_nexthop_group(nhg_id, recursive, ecmp)
887a232c 449
701a0192 450
8058df22
SW
451def test_nexthop_groups():
452 global fatal_error
453 global net
454
455 # Skip if previous fatal error condition is raised
701a0192 456 if fatal_error != "":
8058df22
SW
457 pytest.skip(fatal_error)
458
459 print("\n\n** Verifying Nexthop Groups")
460 print("******************************************\n")
461
887a232c
SW
462 ### Nexthop Group Tests
463
464 ## Basic test
465
8058df22 466 # Create a lib nexthop-group
701a0192 467 net["r1"].cmd(
468 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
469 )
8058df22
SW
470
471 # Create with sharpd using nexthop-group
887a232c 472 net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
8058df22 473
887a232c 474 verify_route_nexthop_group("2.2.2.1/32")
8058df22 475
887a232c 476 ## Connected
8058df22 477
701a0192 478 net["r1"].cmd(
479 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
480 )
8058df22 481
887a232c
SW
482 net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
483
484 verify_route_nexthop_group("2.2.2.2/32")
485
486 ## Recursive
487
701a0192 488 net["r1"].cmd(
489 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
490 )
887a232c 491
701a0192 492 net["r1"].cmd(
493 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
494 )
887a232c
SW
495
496 verify_route_nexthop_group("3.3.3.1/32", True)
497
498 ## Duplicate
499
701a0192 500 net["r1"].cmd(
501 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
502 )
887a232c
SW
503
504 net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
505
506 verify_route_nexthop_group("3.3.3.2/32")
507
508 ## Two 4-Way ECMP
509
701a0192 510 net["r1"].cmd(
511 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
512 -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
513 )
887a232c
SW
514
515 net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
516
517 verify_route_nexthop_group("4.4.4.1/32")
518
701a0192 519 net["r1"].cmd(
520 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
521 -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
522 )
887a232c
SW
523
524 net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
525
526 verify_route_nexthop_group("4.4.4.2/32")
527
528 ## Recursive to 8-Way ECMP
529
701a0192 530 net["r1"].cmd(
531 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
532 )
887a232c 533
701a0192 534 net["r1"].cmd(
535 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
536 )
887a232c
SW
537
538 verify_route_nexthop_group("5.5.5.1/32")
539
13f93db3
SW
540 ## 4-way ECMP Routes Pointing to Each Other
541
542 # This is to check for a bug with NH resolution where
543 # routes would infintely resolve to each other blowing
544 # up the resolved-> nexthop pointer.
545
546 net["r1"].cmd(
547 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
548 -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
549 )
550
551 # static route nexthops can recurse to
552
553 net["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
554
555 # Make routes that point to themselves in ecmp
556
557 net["r1"].cmd(
558 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
559 )
560
561 net["r1"].cmd(
562 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
563 )
564
565 net["r1"].cmd(
566 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
567 )
568
569 net["r1"].cmd(
570 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
571 )
572
573 # Get routes and test if has too many (duplicate) nexthops
574 nhg_id = route_get_nhg_id("6.6.6.1/32")
575 output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
576
577 dups = re.findall(r"(via 1\.1\.1\.1)", output)
578
579 # Should find 3, itself is inactive
580 assert len(dups) == 3, (
581 "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
582 % nhg_id
583 )
584
887a232c
SW
585 ##CLI(net)
586
587 ## Remove all NHG routes
588
589 net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
590 net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
591 net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
592 net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
593 net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
594 net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
595 net["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
13f93db3
SW
596 net["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
597 net["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
4501fbca 598
701a0192 599
4501fbca
MW
600def test_rip_status():
601 global fatal_error
602 global net
603
604 # Skip if previous fatal error condition is raised
701a0192 605 if fatal_error != "":
4501fbca
MW
606 pytest.skip(fatal_error)
607
608 thisDir = os.path.dirname(os.path.realpath(__file__))
609
b2764f90 610 print("\n\n** Verifying RIP status")
4501fbca
MW
611 print("******************************************\n")
612 failures = 0
613 for i in range(1, 2):
701a0192 614 refTableFile = "%s/r%s/rip_status.ref" % (thisDir, i)
4501fbca
MW
615 if os.path.isfile(refTableFile):
616 # Read expected result from file
617 expected = open(refTableFile).read().rstrip()
618 # Fix newlines (make them all the same)
701a0192 619 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
620
621 # Actual output from router
701a0192 622 actual = (
623 net["r%s" % i]
624 .cmd('vtysh -c "show ip rip status" 2> /dev/null')
625 .rstrip()
626 )
627 # Drop time in next due
4501fbca
MW
628 actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual)
629 # Drop time in last update
630 actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
631 # Fix newlines (make them all the same)
701a0192 632 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
633
634 # Generate Diff
701a0192 635 diff = topotest.get_textdiff(
636 actual,
637 expected,
17070436 638 title1="actual IP RIP status",
701a0192 639 title2="expected IP RIP status",
640 )
4501fbca
MW
641
642 # Empty string if it matches, otherwise diff contains unified diff
643 if diff:
701a0192 644 sys.stderr.write("r%s failed IP RIP status check:\n%s\n" % (i, diff))
4501fbca
MW
645 failures += 1
646 else:
647 print("r%s ok" % i)
648
649 assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff)
650
7e7fc73b
MW
651 # Make sure that all daemons are running
652 for i in range(1, 2):
701a0192 653 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
654 assert fatal_error == "", fatal_error
655
622c4996 656 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
657 # CLI(net)
658
659
660def test_ripng_status():
661 global fatal_error
662 global net
663
664 # Skip if previous fatal error condition is raised
701a0192 665 if fatal_error != "":
4501fbca
MW
666 pytest.skip(fatal_error)
667
668 thisDir = os.path.dirname(os.path.realpath(__file__))
669
b2764f90 670 print("\n\n** Verifying RIPng status")
4501fbca
MW
671 print("******************************************\n")
672 failures = 0
673 for i in range(1, 2):
701a0192 674 refTableFile = "%s/r%s/ripng_status.ref" % (thisDir, i)
4501fbca
MW
675 if os.path.isfile(refTableFile):
676 # Read expected result from file
677 expected = open(refTableFile).read().rstrip()
678 # Fix newlines (make them all the same)
701a0192 679 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
680
681 # Actual output from router
701a0192 682 actual = (
683 net["r%s" % i]
684 .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
685 .rstrip()
686 )
4501fbca
MW
687 # Mask out Link-Local mac address portion. They are random...
688 actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
701a0192 689 # Drop time in next due
4501fbca
MW
690 actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual)
691 # Drop time in last update
692 actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
693 # Fix newlines (make them all the same)
701a0192 694 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
695
696 # Generate Diff
701a0192 697 diff = topotest.get_textdiff(
698 actual,
699 expected,
17070436 700 title1="actual IPv6 RIPng status",
701a0192 701 title2="expected IPv6 RIPng status",
702 )
4501fbca
MW
703
704 # Empty string if it matches, otherwise diff contains unified diff
705 if diff:
701a0192 706 sys.stderr.write(
707 "r%s failed IPv6 RIPng status check:\n%s\n" % (i, diff)
708 )
4501fbca
MW
709 failures += 1
710 else:
711 print("r%s ok" % i)
712
701a0192 713 assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
714 i,
715 diff,
716 )
4501fbca 717
7e7fc73b
MW
718 # Make sure that all daemons are running
719 for i in range(1, 2):
701a0192 720 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
721 assert fatal_error == "", fatal_error
722
622c4996 723 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
724 # CLI(net)
725
726
727def test_ospfv2_interfaces():
728 global fatal_error
729 global net
730
731 # Skip if previous fatal error condition is raised
701a0192 732 if fatal_error != "":
4501fbca
MW
733 pytest.skip(fatal_error)
734
735 thisDir = os.path.dirname(os.path.realpath(__file__))
736
b2764f90 737 print("\n\n** Verifying OSPFv2 interfaces")
4501fbca
MW
738 print("******************************************\n")
739 failures = 0
740 for i in range(1, 2):
701a0192 741 refTableFile = "%s/r%s/show_ip_ospf_interface.ref" % (thisDir, i)
4501fbca
MW
742 if os.path.isfile(refTableFile):
743 # Read expected result from file
744 expected = open(refTableFile).read().rstrip()
745 # Fix newlines (make them all the same)
701a0192 746 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
747
748 # Actual output from router
701a0192 749 actual = (
750 net["r%s" % i]
751 .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
752 .rstrip()
753 )
4501fbca
MW
754 # Mask out Bandwidth portion. They may change..
755 actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual)
11761ab0 756 actual = re.sub(r"ifindex [0-9]", "ifindex X", actual)
c9d72a0b 757
701a0192 758 # Drop time in next due
4501fbca 759 actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual)
701a0192 760 actual = re.sub(
761 r"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
762 )
985e6d50 763 # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
701a0192 764 actual = re.sub(
765 r"MTU mismatch detection:([a-z]+.*)",
766 r"MTU mismatch detection: \1",
767 actual,
768 )
4501fbca 769 # Fix newlines (make them all the same)
701a0192 770 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
771
772 # Generate Diff
701a0192 773 diff = topotest.get_textdiff(
774 actual,
775 expected,
17070436 776 title1="actual SHOW IP OSPF INTERFACE",
701a0192 777 title2="expected SHOW IP OSPF INTERFACE",
778 )
4501fbca
MW
779
780 # Empty string if it matches, otherwise diff contains unified diff
781 if diff:
701a0192 782 sys.stderr.write(
783 "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i, diff)
784 )
4501fbca
MW
785 failures += 1
786 else:
787 print("r%s ok" % i)
788
08fa1af7 789 # Ignoring the issue if told to ignore (ie not yet fixed)
701a0192 790 if failures != 0:
791 if os.environ.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
792 sys.stderr.write(
793 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
794 )
795 pytest.skip(
796 "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
797 )
798
799 assert (
800 failures == 0
801 ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff)
4501fbca 802
7e7fc73b
MW
803 # Make sure that all daemons are running
804 for i in range(1, 2):
701a0192 805 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
806 assert fatal_error == "", fatal_error
807
622c4996 808 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
809 # CLI(net)
810
811
812def test_isis_interfaces():
813 global fatal_error
814 global net
815
816 # Skip if previous fatal error condition is raised
701a0192 817 if fatal_error != "":
4501fbca
MW
818 pytest.skip(fatal_error)
819
820 thisDir = os.path.dirname(os.path.realpath(__file__))
821
b2764f90 822 print("\n\n** Verifying ISIS interfaces")
4501fbca
MW
823 print("******************************************\n")
824 failures = 0
825 for i in range(1, 2):
701a0192 826 refTableFile = "%s/r%s/show_isis_interface_detail.ref" % (thisDir, i)
4501fbca
MW
827 if os.path.isfile(refTableFile):
828 # Read expected result from file
829 expected = open(refTableFile).read().rstrip()
830 # Fix newlines (make them all the same)
701a0192 831 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
832
833 # Actual output from router
701a0192 834 actual = (
835 net["r%s" % i]
836 .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
837 .rstrip()
838 )
4501fbca
MW
839 # Mask out Link-Local mac address portion. They are random...
840 actual = re.sub(r"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual)
841 # Mask out SNPA mac address portion. They are random...
842 actual = re.sub(r"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual)
6ae351e8 843 # Mask out Circuit ID number
701a0192 844 actual = re.sub(r"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual)
4501fbca 845 # Fix newlines (make them all the same)
701a0192 846 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
847
848 # Generate Diff
701a0192 849 diff = topotest.get_textdiff(
850 actual,
851 expected,
17070436 852 title1="actual SHOW ISIS INTERFACE DETAIL",
701a0192 853 title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
854 )
4501fbca
MW
855
856 # Empty string if it matches, otherwise diff contains unified diff
857 if diff:
701a0192 858 sys.stderr.write(
859 "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i, diff)
860 )
4501fbca
MW
861 failures += 1
862 else:
863 print("r%s ok" % i)
864
701a0192 865 assert (
866 failures == 0
867 ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff)
4501fbca 868
7e7fc73b
MW
869 # Make sure that all daemons are running
870 for i in range(1, 2):
701a0192 871 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
872 assert fatal_error == "", fatal_error
873
622c4996 874 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
875 # CLI(net)
876
877
878def test_bgp_summary():
879 global fatal_error
880 global net
881
882 # Skip if previous fatal error condition is raised
701a0192 883 if fatal_error != "":
4501fbca
MW
884 pytest.skip(fatal_error)
885
886 thisDir = os.path.dirname(os.path.realpath(__file__))
887
b2764f90 888 print("\n\n** Verifying BGP Summary")
4501fbca
MW
889 print("******************************************\n")
890 failures = 0
891 for i in range(1, 2):
701a0192 892 refTableFile = "%s/r%s/show_ip_bgp_summary.ref" % (thisDir, i)
4501fbca
MW
893 if os.path.isfile(refTableFile):
894 # Read expected result from file
895 expected = open(refTableFile).read().rstrip()
896 # Fix newlines (make them all the same)
701a0192 897 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
898
899 # Actual output from router
701a0192 900 actual = (
901 net["r%s" % i]
902 .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
903 .rstrip()
904 )
4501fbca
MW
905 # Mask out "using XXiXX bytes" portion. They are random...
906 actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
907 # Mask out "using XiXXX KiB" portion. They are random...
908 actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
08fa1af7
MW
909 #
910 # Remove extra summaries which exist with newer versions
911 #
912 # Remove summary lines (changed recently)
701a0192 913 actual = re.sub(r"Total number.*", "", actual)
914 actual = re.sub(r"Displayed.*", "", actual)
08fa1af7 915 # Remove IPv4 Unicast Summary (Title only)
701a0192 916 actual = re.sub(r"IPv4 Unicast Summary:", "", actual)
08fa1af7 917 # Remove IPv4 Multicast Summary (all of it)
701a0192 918 actual = re.sub(r"IPv4 Multicast Summary:", "", actual)
919 actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
08fa1af7 920 # Remove IPv4 VPN Summary (all of it)
701a0192 921 actual = re.sub(r"IPv4 VPN Summary:", "", actual)
922 actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
08fa1af7 923 # Remove IPv4 Encap Summary (all of it)
701a0192 924 actual = re.sub(r"IPv4 Encap Summary:", "", actual)
925 actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
08fa1af7 926 # Remove Unknown Summary (all of it)
701a0192 927 actual = re.sub(r"Unknown Summary:", "", actual)
928 actual = re.sub(r"No Unknown neighbor is configured", "", actual)
8b2e59e9 929
701a0192 930 actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual)
931 actual = re.sub(
932 r"No IPv4 labeled-unicast neighbor is configured", "", actual
933 )
8b2e59e9 934
08fa1af7
MW
935 # Strip empty lines
936 actual = actual.lstrip()
937 actual = actual.rstrip()
938 #
4501fbca 939 # Fix newlines (make them all the same)
701a0192 940 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
941
942 # Generate Diff
701a0192 943 diff = topotest.get_textdiff(
944 actual,
945 expected,
17070436 946 title1="actual SHOW IP BGP SUMMARY",
701a0192 947 title2="expected SHOW IP BGP SUMMARY",
948 )
4501fbca
MW
949
950 # Empty string if it matches, otherwise diff contains unified diff
951 if diff:
701a0192 952 sys.stderr.write(
953 "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff)
954 )
4501fbca
MW
955 failures += 1
956 else:
957 print("r%s ok" % i)
958
701a0192 959 assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
960 i,
961 diff,
962 )
4501fbca 963
7e7fc73b
MW
964 # Make sure that all daemons are running
965 for i in range(1, 2):
701a0192 966 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
967 assert fatal_error == "", fatal_error
968
622c4996 969 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
970 # CLI(net)
971
972
973def test_bgp_ipv6_summary():
974 global fatal_error
975 global net
976
977 # Skip if previous fatal error condition is raised
701a0192 978 if fatal_error != "":
4501fbca
MW
979 pytest.skip(fatal_error)
980
981 thisDir = os.path.dirname(os.path.realpath(__file__))
982
b2764f90 983 print("\n\n** Verifying BGP IPv6 Summary")
4501fbca
MW
984 print("******************************************\n")
985 failures = 0
986 for i in range(1, 2):
701a0192 987 refTableFile = "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir, i)
4501fbca
MW
988 if os.path.isfile(refTableFile):
989 # Read expected result from file
990 expected = open(refTableFile).read().rstrip()
991 # Fix newlines (make them all the same)
701a0192 992 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
993
994 # Actual output from router
701a0192 995 actual = (
996 net["r%s" % i]
997 .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
998 .rstrip()
999 )
4501fbca
MW
1000 # Mask out "using XXiXX bytes" portion. They are random...
1001 actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
1002 # Mask out "using XiXXX KiB" portion. They are random...
1003 actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
08fa1af7
MW
1004 #
1005 # Remove extra summaries which exist with newer versions
1006 #
1007 # Remove summary lines (changed recently)
701a0192 1008 actual = re.sub(r"Total number.*", "", actual)
1009 actual = re.sub(r"Displayed.*", "", actual)
08fa1af7 1010 # Remove IPv4 Unicast Summary (Title only)
701a0192 1011 actual = re.sub(r"IPv6 Unicast Summary:", "", actual)
08fa1af7 1012 # Remove IPv4 Multicast Summary (all of it)
701a0192 1013 actual = re.sub(r"IPv6 Multicast Summary:", "", actual)
1014 actual = re.sub(r"No IPv6 Multicast neighbor is configured", "", actual)
08fa1af7 1015 # Remove IPv4 VPN Summary (all of it)
701a0192 1016 actual = re.sub(r"IPv6 VPN Summary:", "", actual)
1017 actual = re.sub(r"No IPv6 VPN neighbor is configured", "", actual)
08fa1af7 1018 # Remove IPv4 Encap Summary (all of it)
701a0192 1019 actual = re.sub(r"IPv6 Encap Summary:", "", actual)
1020 actual = re.sub(r"No IPv6 Encap neighbor is configured", "", actual)
08fa1af7 1021 # Remove Unknown Summary (all of it)
701a0192 1022 actual = re.sub(r"Unknown Summary:", "", actual)
1023 actual = re.sub(r"No Unknown neighbor is configured", "", actual)
8b2e59e9
DS
1024
1025 # Remove Labeled Unicast Summary (all of it)
701a0192 1026 actual = re.sub(r"IPv6 labeled-unicast Summary:", "", actual)
1027 actual = re.sub(
1028 r"No IPv6 labeled-unicast neighbor is configured", "", actual
1029 )
8b2e59e9 1030
08fa1af7
MW
1031 # Strip empty lines
1032 actual = actual.lstrip()
1033 actual = actual.rstrip()
1034 #
4501fbca 1035 # Fix newlines (make them all the same)
701a0192 1036 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
1037
1038 # Generate Diff
701a0192 1039 diff = topotest.get_textdiff(
1040 actual,
1041 expected,
17070436 1042 title1="actual SHOW BGP IPv6 SUMMARY",
701a0192 1043 title2="expected SHOW BGP IPv6 SUMMARY",
1044 )
4501fbca
MW
1045
1046 # Empty string if it matches, otherwise diff contains unified diff
1047 if diff:
701a0192 1048 sys.stderr.write(
1049 "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i, diff)
1050 )
4501fbca
MW
1051 failures += 1
1052 else:
1053 print("r%s ok" % i)
1054
701a0192 1055 assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
1056 i,
1057 diff,
1058 )
4501fbca 1059
7e7fc73b
MW
1060 # Make sure that all daemons are running
1061 for i in range(1, 2):
701a0192 1062 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
1063 assert fatal_error == "", fatal_error
1064
622c4996 1065 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
1066 # CLI(net)
1067
9fa6ec14 1068
dda33b6e
DS
1069def test_nht():
1070 print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
1071
1072 thisDir = os.path.dirname(os.path.realpath(__file__))
1073
1074 for i in range(1, 2):
1075 nhtFile = "%s/r%s/ip_nht.ref" % (thisDir, i)
1076 expected = open(nhtFile).read().rstrip()
1077 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
1078
9fa6ec14 1079 actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
dda33b6e
DS
1080 actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
1081 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
1082
9fa6ec14 1083 diff = topotest.get_textdiff(
1084 actual,
1085 expected,
1086 title1="Actual `show ip nht`",
1087 title2="Expected `show ip nht`",
1088 )
dda33b6e
DS
1089
1090 if diff:
1091 assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff)
1092 else:
1093 print("show ip nht is ok\n")
1094
1095 nhtFile = "%s/r%s/ipv6_nht.ref" % (thisDir, i)
1096 expected = open(nhtFile).read().rstrip()
1097 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
1098
9fa6ec14 1099 actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
dda33b6e
DS
1100 actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
1101 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
1102
9fa6ec14 1103 diff = topotest.get_textdiff(
1104 actual,
1105 expected,
1106 title1="Actual `show ip nht`",
1107 title2="Expected `show ip nht`",
1108 )
dda33b6e
DS
1109
1110 if diff:
1111 assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff)
1112 else:
1113 print("show ipv6 nht is ok\n")
4501fbca 1114
9fa6ec14 1115
4501fbca
MW
1116def test_bgp_ipv4():
1117 global fatal_error
1118 global net
1119
1120 # Skip if previous fatal error condition is raised
701a0192 1121 if fatal_error != "":
4501fbca
MW
1122 pytest.skip(fatal_error)
1123
1124 thisDir = os.path.dirname(os.path.realpath(__file__))
1125
b2764f90 1126 print("\n\n** Verifying BGP IPv4")
4501fbca 1127 print("******************************************\n")
6a57e103 1128 diffresult = {}
4501fbca 1129 for i in range(1, 2):
11761ab0 1130 success = 0
701a0192 1131 for refTableFile in glob.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir, i)):
11761ab0
MS
1132 if os.path.isfile(refTableFile):
1133 # Read expected result from file
1134 expected = open(refTableFile).read().rstrip()
1135 # Fix newlines (make them all the same)
701a0192 1136 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
11761ab0
MS
1137
1138 # Actual output from router
701a0192 1139 actual = (
1140 net["r%s" % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
1141 )
11761ab0 1142 # Remove summary line (changed recently)
701a0192 1143 actual = re.sub(r"Total number.*", "", actual)
1144 actual = re.sub(r"Displayed.*", "", actual)
11761ab0
MS
1145 actual = actual.rstrip()
1146 # Fix newlines (make them all the same)
701a0192 1147 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
11761ab0
MS
1148
1149 # Generate Diff
701a0192 1150 diff = topotest.get_textdiff(
1151 actual,
1152 expected,
11761ab0 1153 title1="actual SHOW BGP IPv4",
701a0192 1154 title2="expected SHOW BGP IPv4",
1155 )
11761ab0
MS
1156
1157 # Empty string if it matches, otherwise diff contains unified diff
1158 if diff:
1159 diffresult[refTableFile] = diff
1160 else:
1161 success = 1
1162 print("template %s matched: r%s ok" % (refTableFile, i))
1163 break
1164
1165 if not success:
701a0192 1166 resultstr = "No template matched.\n"
e7294b32 1167 for f in diffresult.keys():
701a0192 1168 resultstr += "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
1169 f,
1170 i,
1171 diffresult[f],
1172 )
11761ab0 1173 raise AssertionError(
701a0192 1174 "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr)
1175 )
4501fbca 1176
7e7fc73b
MW
1177 # Make sure that all daemons are running
1178 for i in range(1, 2):
701a0192 1179 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
1180 assert fatal_error == "", fatal_error
1181
622c4996 1182 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
1183 # CLI(net)
1184
1185
1186def test_bgp_ipv6():
1187 global fatal_error
1188 global net
1189
1190 # Skip if previous fatal error condition is raised
701a0192 1191 if fatal_error != "":
4501fbca
MW
1192 pytest.skip(fatal_error)
1193
1194 thisDir = os.path.dirname(os.path.realpath(__file__))
1195
b2764f90 1196 print("\n\n** Verifying BGP IPv6")
4501fbca 1197 print("******************************************\n")
6a57e103 1198 diffresult = {}
4501fbca 1199 for i in range(1, 2):
11761ab0 1200 success = 0
701a0192 1201 for refTableFile in glob.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir, i)):
11761ab0
MS
1202 if os.path.isfile(refTableFile):
1203 # Read expected result from file
1204 expected = open(refTableFile).read().rstrip()
1205 # Fix newlines (make them all the same)
701a0192 1206 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
11761ab0
MS
1207
1208 # Actual output from router
701a0192 1209 actual = (
1210 net["r%s" % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
1211 )
11761ab0 1212 # Remove summary line (changed recently)
701a0192 1213 actual = re.sub(r"Total number.*", "", actual)
1214 actual = re.sub(r"Displayed.*", "", actual)
11761ab0
MS
1215 actual = actual.rstrip()
1216 # Fix newlines (make them all the same)
701a0192 1217 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
11761ab0
MS
1218
1219 # Generate Diff
701a0192 1220 diff = topotest.get_textdiff(
1221 actual,
1222 expected,
11761ab0 1223 title1="actual SHOW BGP IPv6",
701a0192 1224 title2="expected SHOW BGP IPv6",
1225 )
11761ab0
MS
1226
1227 # Empty string if it matches, otherwise diff contains unified diff
1228 if diff:
1229 diffresult[refTableFile] = diff
1230 else:
1231 success = 1
1232 print("template %s matched: r%s ok" % (refTableFile, i))
1233
1234 if not success:
701a0192 1235 resultstr = "No template matched.\n"
e7294b32 1236 for f in diffresult.keys():
701a0192 1237 resultstr += "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
1238 f,
1239 i,
1240 diffresult[f],
1241 )
11761ab0 1242 raise AssertionError(
701a0192 1243 "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr)
1244 )
4501fbca 1245
7e7fc73b
MW
1246 # Make sure that all daemons are running
1247 for i in range(1, 2):
701a0192 1248 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
1249 assert fatal_error == "", fatal_error
1250
622c4996 1251 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
1252 # CLI(net)
1253
701a0192 1254
41fce07c
DS
1255def test_route_map():
1256 global fatal_error
1257 global net
1258
701a0192 1259 if fatal_error != "":
41fce07c
DS
1260 pytest.skip(fatal_error)
1261
1262 thisDir = os.path.dirname(os.path.realpath(__file__))
1263
1264 print("\n\n** Verifying some basic routemap forward references\n")
1265 print("*******************************************************\n")
1266 failures = 0
1267 for i in range(1, 2):
701a0192 1268 refroutemap = "%s/r%s/show_route_map.ref" % (thisDir, i)
41fce07c
DS
1269 if os.path.isfile(refroutemap):
1270 expected = open(refroutemap).read().rstrip()
701a0192 1271 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
41fce07c 1272
701a0192 1273 actual = (
1274 net["r%s" % i].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
1275 )
1276 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
41fce07c 1277
701a0192 1278 diff = topotest.get_textdiff(
1279 actual,
1280 expected,
1281 title1="actual show route-map",
1282 title2="expected show route-map",
1283 )
41fce07c
DS
1284
1285 if diff:
701a0192 1286 sys.stderr.write(
1287 "r%s failed show route-map command Check:\n%s\n" % (i, diff)
1288 )
41fce07c
DS
1289 failures += 1
1290 else:
701a0192 1291 print("r%s ok" % i)
1292
1293 assert (
1294 failures == 0
1295 ), "Show route-map command failed for router r%s:\n%s" % (i, diff)
4501fbca
MW
1296
1297
887a232c
SW
1298def test_nexthop_groups_with_route_maps():
1299 global fatal_error
1300 global net
1301
1302 # Skip if previous fatal error condition is raised
701a0192 1303 if fatal_error != "":
887a232c
SW
1304 pytest.skip(fatal_error)
1305
1306 print("\n\n** Verifying Nexthop Groups With Route-Maps")
1307 print("******************************************\n")
1308
1309 ### Nexthop Group With Route-Map Tests
1310
1311 # Create a lib nexthop-group
701a0192 1312 net["r1"].cmd(
1313 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
1314 )
887a232c
SW
1315
1316 ## Route-Map Proto Source
1317
1318 route_str = "2.2.2.1"
1319 src_str = "192.168.0.1"
1320
701a0192 1321 net["r1"].cmd(
1322 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
1323 )
887a232c
SW
1324 net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
1325
1326 net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str)
1327
1328 verify_route_nexthop_group("%s/32" % route_str)
1329
1330 # Only a valid test on linux using nexthop objects
1331 if sys.platform.startswith("linux"):
701a0192 1332 output = net["r1"].cmd("ip route show %s/32" % route_str)
887a232c 1333 match = re.search(r"src %s" % src_str, output)
701a0192 1334 assert match is not None, "Route %s/32 not installed with src %s" % (
1335 route_str,
1336 src_str,
1337 )
887a232c
SW
1338
1339 # Remove NHG routes and route-map
1340 net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str)
1341 net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
701a0192 1342 net["r1"].cmd(
1343 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" -c "set src %s"' % src_str
1344 )
887a232c
SW
1345 net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
1346
1347 ## Route-Map Deny/Permit with same nexthop group
1348
1349 permit_route_str = "3.3.3.1"
1350 deny_route_str = "3.3.3.2"
1351
701a0192 1352 net["r1"].cmd(
1353 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
1354 )
1355 net["r1"].cmd(
1356 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
1357 )
887a232c
SW
1358 net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
1359 net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
1360
1361 # This route should be permitted
701a0192 1362 net["r1"].cmd(
1363 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
1364 )
887a232c
SW
1365
1366 verify_route_nexthop_group("%s/32" % permit_route_str)
1367
1368 # This route should be denied
701a0192 1369 net["r1"].cmd(
1370 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
1371 )
887a232c
SW
1372
1373 nhg_id = route_get_nhg_id(deny_route_str)
1374 output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
1375
1376 match = re.search(r"Valid", output)
1377 assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
1378
1379 match = re.search(r"Installed", output)
1380 assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
1381
1382 # Remove NHG routes and route-map
1383 net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str)
1384 net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str)
1385 net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
1386 net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
1387 net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
1388 net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
701a0192 1389 net["r1"].cmd(
1390 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
1391 % permit_route_str
1392 )
1393
887a232c 1394
8f4d7212
SW
1395def test_nexthop_group_replace():
1396 global fatal_error
1397 global net
1398
1399 # Skip if previous fatal error condition is raised
701a0192 1400 if fatal_error != "":
8f4d7212
SW
1401 pytest.skip(fatal_error)
1402
1403 print("\n\n** Verifying Nexthop Groups")
1404 print("******************************************\n")
1405
1406 ### Nexthop Group Tests
1407
1408 ## 2-Way ECMP Directly Connected
1409
701a0192 1410 net["r1"].cmd(
1411 '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"'
1412 )
8f4d7212
SW
1413
1414 # Create with sharpd using nexthop-group
1415 net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
1416
1417 verify_route_nexthop_group("3.3.3.1/32")
1418
1419 # Change the nexthop group
701a0192 1420 net["r1"].cmd(
1421 '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"'
1422 )
8f4d7212
SW
1423
1424 # Verify it updated. We can just check install and ecmp count here.
1425 verify_route_nexthop_group("3.3.3.1/32", False, 3)
1426
701a0192 1427
4501fbca
MW
1428def test_mpls_interfaces():
1429 global fatal_error
1430 global net
1431
1432 # Skip if previous fatal error condition is raised
701a0192 1433 if fatal_error != "":
4501fbca
MW
1434 pytest.skip(fatal_error)
1435
1436 # Skip if no LDP installed or old kernel
701a0192 1437 if net["r1"].daemon_available("ldpd") == False:
4501fbca
MW
1438 pytest.skip("No MPLS or kernel < 4.5")
1439
1440 thisDir = os.path.dirname(os.path.realpath(__file__))
1441
b2764f90 1442 print("\n\n** Verifying MPLS Interfaces")
4501fbca
MW
1443 print("******************************************\n")
1444 failures = 0
1445 for i in range(1, 2):
701a0192 1446 refTableFile = "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir, i)
4501fbca
MW
1447 if os.path.isfile(refTableFile):
1448 # Read expected result from file
1449 expected = open(refTableFile).read().rstrip()
1450 # Fix newlines (make them all the same)
701a0192 1451 expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
4501fbca
MW
1452
1453 # Actual output from router
701a0192 1454 actual = (
1455 net["r%s" % i]
1456 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
1457 .rstrip()
1458 )
4501fbca
MW
1459 # Mask out Timer in Uptime
1460 actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual)
1461 # Fix newlines (make them all the same)
701a0192 1462 actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
4501fbca
MW
1463
1464 # Generate Diff
701a0192 1465 diff = topotest.get_textdiff(
1466 actual,
1467 expected,
17070436 1468 title1="actual MPLS LDP interface status",
701a0192 1469 title2="expected MPLS LDP interface status",
1470 )
4501fbca
MW
1471
1472 # Empty string if it matches, otherwise diff contains unified diff
1473 if diff:
701a0192 1474 sys.stderr.write(
1475 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i, diff)
1476 )
4501fbca
MW
1477 failures += 1
1478 else:
1479 print("r%s ok" % i)
1480
701a0192 1481 if failures > 0:
4501fbca
MW
1482 fatal_error = "MPLS LDP Interface status failed"
1483
701a0192 1484 assert (
1485 failures == 0
1486 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff)
4501fbca 1487
7e7fc73b
MW
1488 # Make sure that all daemons are running
1489 for i in range(1, 2):
701a0192 1490 fatal_error = net["r%s" % i].checkRouterRunning()
7e7fc73b
MW
1491 assert fatal_error == "", fatal_error
1492
622c4996 1493 # For debugging after starting FRR daemons, uncomment the next line
4501fbca
MW
1494 # CLI(net)
1495
1496
1497def test_shutdown_check_stderr():
1498 global fatal_error
1499 global net
1500
1501 # Skip if previous fatal error condition is raised
701a0192 1502 if fatal_error != "":
4501fbca
MW
1503 pytest.skip(fatal_error)
1504
b2764f90 1505 print("\n\n** Verifying unexpected STDERR output from daemons")
4501fbca
MW
1506 print("******************************************\n")
1507
701a0192 1508 if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
1509 print(
1510 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
1511 )
1512 pytest.skip("Skipping test for Stderr output")
4501fbca
MW
1513
1514 thisDir = os.path.dirname(os.path.realpath(__file__))
1515
50c40bde
MW
1516 print("thisDir=" + thisDir)
1517
701a0192 1518 net["r1"].stopRouter()
4501fbca 1519
701a0192 1520 log = net["r1"].getStdErr("ripd")
8e957dbb
MW
1521 if log:
1522 print("\nRIPd StdErr Log:\n" + log)
701a0192 1523 log = net["r1"].getStdErr("ripngd")
8e957dbb
MW
1524 if log:
1525 print("\nRIPngd StdErr Log:\n" + log)
701a0192 1526 log = net["r1"].getStdErr("ospfd")
8e957dbb
MW
1527 if log:
1528 print("\nOSPFd StdErr Log:\n" + log)
701a0192 1529 log = net["r1"].getStdErr("ospf6d")
8e957dbb
MW
1530 if log:
1531 print("\nOSPF6d StdErr Log:\n" + log)
701a0192 1532 log = net["r1"].getStdErr("isisd")
8e957dbb
MW
1533 if log:
1534 print("\nISISd StdErr Log:\n" + log)
701a0192 1535 log = net["r1"].getStdErr("bgpd")
8e957dbb
MW
1536 if log:
1537 print("\nBGPd StdErr Log:\n" + log)
af39fbe7 1538
701a0192 1539 log = net["r1"].getStdErr("nhrpd")
af39fbe7
MS
1540 if log:
1541 print("\nNHRPd StdErr Log:\n" + log)
1542
701a0192 1543 log = net["r1"].getStdErr("pbrd")
af39fbe7
MS
1544 if log:
1545 print("\nPBRd StdErr Log:\n" + log)
1546
701a0192 1547 log = net["r1"].getStdErr("babeld")
af39fbe7
MS
1548 if log:
1549 print("\nBABELd StdErr Log:\n" + log)
1550
701a0192 1551 if net["r1"].daemon_available("ldpd"):
1552 log = net["r1"].getStdErr("ldpd")
8e957dbb
MW
1553 if log:
1554 print("\nLDPd StdErr Log:\n" + log)
701a0192 1555 log = net["r1"].getStdErr("zebra")
8e957dbb
MW
1556 if log:
1557 print("\nZebra StdErr Log:\n" + log)
4501fbca
MW
1558
1559
50c40bde
MW
1560def test_shutdown_check_memleak():
1561 global fatal_error
1562 global net
1563
1564 # Skip if previous fatal error condition is raised
701a0192 1565 if fatal_error != "":
50c40bde
MW
1566 pytest.skip(fatal_error)
1567
701a0192 1568 if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None:
1569 print(
1570 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
1571 )
1572 pytest.skip("Skipping test for memory leaks")
1573
50c40bde
MW
1574 thisDir = os.path.dirname(os.path.realpath(__file__))
1575
1576 for i in range(1, 2):
701a0192 1577 net["r%s" % i].stopRouter()
1578 net["r%s" % i].report_memory_leaks(
1579 os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__)
1580 )
50c40bde
MW
1581
1582
701a0192 1583if __name__ == "__main__":
4501fbca 1584
701a0192 1585 setLogLevel("info")
4501fbca
MW
1586 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
1587 # retval = pytest.main(["-s", "--tb=no"])
1588 retval = pytest.main(["-s"])
1589 sys.exit(retval)