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