]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/ldp-topo1/test_ldp_topo1.py
(all tests): Add extra check to make sure daemons are still running after each essent...
[mirror_frr.git] / tests / topotests / ldp-topo1 / test_ldp_topo1.py
CommitLineData
f03e38f3
MW
1#!/usr/bin/env python
2
3#
4# test_bgp_multiview_topo1.py
5# Part of NetDEF Topology Tests
6#
7# Copyright (c) 2016 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_ldp_topo1.py: Simple FRR/Quagga LDP Test
27
28 +---------+
29 | r1 |
30 | 1.1.1.1 |
31 +----+----+
32 | .1 r1-eth0
33 |
34 ~~~~~~~~~~~~~
35 ~~ sw0 ~~
36 ~~ 10.0.1.0/24 ~~
37 ~~~~~~~~~~~~~
38 |10.0.1.0/24
39 |
40 | .2 r2-eth0
41 +----+----+
42 | r2 |
43 | 2.2.2.2 |
44 +--+---+--+
45 r2-eth2 .2 | | .2 r2-eth1
46 ______/ \______
47 / \
48 ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
49~~ sw2 ~~ ~~ sw1 ~~
50~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~
51 ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
52 | / |
53 \ _________/ |
54 \ / \
55r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0
56 +----+--+---+ +----+----+
57 | r3 | | r4 |
58 | 3.3.3.3 | | 4.4.4.4 |
59 +-----------+ +---------+
60"""
61
62import os
63import re
64import sys
65import difflib
594b1259
MW
66import pytest
67from time import sleep
f03e38f3
MW
68
69from mininet.topo import Topo
70from mininet.net import Mininet
71from mininet.node import Node, OVSSwitch, Host
72from mininet.log import setLogLevel, info
73from mininet.cli import CLI
74from mininet.link import Intf
75
594b1259
MW
76sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
77from lib import topotest
f03e38f3
MW
78
79fatal_error = ""
80
3eaafbd9
MW
81# Expected version of CLI Output - Appendix to filename
82# empty string = current, latest output (default)
83# "-1" ... "-NNN" previous versions (incrementing with each version)
84cli_version = ""
85
86
f03e38f3
MW
87#####################################################
88##
89## Network Topology Definition
90##
91#####################################################
92
93class NetworkTopo(Topo):
594b1259 94 "LDP Test Topology 1"
f03e38f3
MW
95
96 def build(self, **_opts):
97
f03e38f3
MW
98 # Setup Routers
99 router = {}
100 for i in range(1, 5):
594b1259 101 router[i] = topotest.addRouter(self, 'r%s' % i)
f03e38f3 102
594b1259 103 # Setup Switches, add Interfaces and Connections
f03e38f3
MW
104 switch = {}
105 # First switch
594b1259 106 switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch)
f03e38f3
MW
107 self.addLink(switch[0], router[1], intfName2='r1-eth0', addr1='80:AA:00:00:00:00', addr2='00:11:00:01:00:00')
108 self.addLink(switch[0], router[2], intfName2='r2-eth0', addr1='80:AA:00:00:00:01', addr2='00:11:00:02:00:00')
109 # Second switch
594b1259 110 switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch)
f03e38f3
MW
111 self.addLink(switch[1], router[2], intfName2='r2-eth1', addr1='80:AA:00:01:00:00', addr2='00:11:00:02:00:01')
112 self.addLink(switch[1], router[3], intfName2='r3-eth0', addr1='80:AA:00:01:00:01', addr2='00:11:00:03:00:00')
113 self.addLink(switch[1], router[4], intfName2='r4-eth0', addr1='80:AA:00:01:00:02', addr2='00:11:00:04:00:00')
114 # Third switch
594b1259 115 switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch)
f03e38f3
MW
116 self.addLink(switch[2], router[2], intfName2='r2-eth2', addr1='80:AA:00:02:00:00', addr2='00:11:00:02:00:02')
117 self.addLink(switch[2], router[3], intfName2='r3-eth1', addr1='80:AA:00:02:00:01', addr2='00:11:00:03:00:01')
118
594b1259 119
f03e38f3
MW
120#####################################################
121##
122## Tests starting
123##
124#####################################################
125
126def setup_module(module):
127 global topo, net
594b1259 128 global fatal_error
f03e38f3
MW
129
130 print("\n\n** %s: Setup Topology" % module.__name__)
131 print("******************************************\n")
132
133 print("Cleanup old Mininet runs")
134 os.system('sudo mn -c > /dev/null 2>&1')
135
136 thisDir = os.path.dirname(os.path.realpath(__file__))
137 topo = NetworkTopo()
138
139 net = Mininet(controller=None, topo=topo)
140 net.start()
141
142 # Starting Routers
143 for i in range(1, 5):
144 net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
145 net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i))
146 net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i))
594b1259
MW
147 fatal_error = net['r%s' % i].startRouter()
148
149 if fatal_error != "":
150 break
f03e38f3
MW
151
152 # For debugging after starting FRR/Quagga daemons, uncomment the next line
153 # CLI(net)
154
155def teardown_module(module):
156 global net
157
158 print("\n\n** %s: Shutdown Topology" % module.__name__)
159 print("******************************************\n")
160
161 # End - Shutdown network
162 net.stop()
163
164
594b1259 165def test_router_running():
f03e38f3
MW
166 global fatal_error
167 global net
3eaafbd9 168 global cli_version
f03e38f3
MW
169
170 # Skip if previous fatal error condition is raised
171 if (fatal_error != ""):
172 pytest.skip(fatal_error)
173
174 print("\n\n** Check if FRR/Quagga is running on each Router node")
175 print("******************************************\n")
176 sleep(5)
177
178 # Starting Routers
179 for i in range(1, 5):
594b1259
MW
180 fatal_error = net['r%s' % i].checkRouterRunning()
181 assert fatal_error == "", fatal_error
f03e38f3 182
3eaafbd9
MW
183 # Detect CLI Version
184 # At this time, there are only 2 possible outputs, so simple check
185 output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
186
187 # Check if old or new format of CLI Output. Default is to current format
188 #
189 # Old (v1) output looks like this:
190 # Local LDP Identifier: 1.1.1.1:0
191 # Discovery Sources:
192 # Interfaces:
193 # r1-eth0: xmit/recv
194 # LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
195 # Hold time: 15 sec
196 # Targeted Hellos:
197 #
198 # Current (v0) output looks like this:
199 # AF ID Type Source Holdtime
200 # ipv4 2.2.2.2 Link r1-eth0 15
201 pattern = re.compile("^Local LDP Identifier.*")
202 if pattern.match(output):
203 cli_version = "-1"
204
594b1259
MW
205 # For debugging after starting FRR/Quagga daemons, uncomment the next line
206 # CLI(net)
f03e38f3
MW
207
208def test_mpls_interfaces():
209 global fatal_error
210 global net
3eaafbd9 211 global cli_version
f03e38f3
MW
212
213 # Skip if previous fatal error condition is raised
214 if (fatal_error != ""):
215 pytest.skip(fatal_error)
216
217 thisDir = os.path.dirname(os.path.realpath(__file__))
218
219 # Verify OSPFv3 Routing Table
b2764f90 220 print("\n\n** Verifying MPLS Interfaces")
f03e38f3
MW
221 print("******************************************\n")
222 failures = 0
223 for i in range(1, 5):
3eaafbd9 224 refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
225 if os.path.isfile(refTableFile):
226 # Read expected result from file
227 expected = open(refTableFile).read().rstrip()
228 # Fix newlines (make them all the same)
229 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
230
231 # Actual output from router
232 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp interface" 2> /dev/null').rstrip()
233 # Mask out Timer in Uptime
234 actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual)
235 # Fix newlines (make them all the same)
236 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
237
238 # Generate Diff
239 diff = ''.join(difflib.context_diff(actual, expected,
240 fromfile="actual MPLS LDP interface status",
241 tofile="expected MPLS LDP interface status"))
242
243 # Empty string if it matches, otherwise diff contains unified diff
244 if diff:
245 sys.stderr.write('r%s failed MPLS LDP Interface status Check:\n%s\n' % (i, diff))
246 failures += 1
247 else:
248 print("r%s ok" % i)
249
594b1259
MW
250 if failures>0:
251 fatal_error = "MPLS LDP Interface status failed"
252
f03e38f3
MW
253 assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff)
254
7e7fc73b
MW
255 # Make sure that all daemons are running
256 for i in range(1, 5):
257 fatal_error = net['r%s' % i].checkRouterRunning()
258 assert fatal_error == "", fatal_error
259
f03e38f3
MW
260 # For debugging after starting FRR/Quagga daemons, uncomment the next line
261 # CLI(net)
262
263
264def test_mpls_ldp_neighbor_establish():
265 global fatal_error
266 global net
3eaafbd9 267 global cli_version
f03e38f3
MW
268
269 # Skip if previous fatal error condition is raised
270 if (fatal_error != ""):
271 pytest.skip(fatal_error)
272
273 # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
274 print("\n\n** Verify MPLS LDP neighbors to establish")
275 print("******************************************\n")
276 timeout = 90
277 while timeout > 0:
278 print("Timeout in %s: " % timeout),
279 sys.stdout.flush()
280 # Look for any node not yet converged
281 for i in range(1, 5):
3eaafbd9
MW
282 established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
283 if cli_version != "-1":
284 # On current version, we need to make sure they all turn to OPERATIONAL on all lines
285 #
286 lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
287 # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
288 header = r'^AF.*'
289 operational = r'^ip.*OPERATIONAL.*'
290 found_operational = 0
291 for j in range(1, len(lines)):
292 if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
293 established = "" # Empty string shows NOT established
294 if re.search(operational, lines[j]):
295 found_operational += 1
296 if found_operational < 1:
297 # Need at least one operational neighbor
298 established = "" # Empty string shows NOT established
f03e38f3
MW
299 if not established:
300 print('Waiting for r%s' %i)
301 sys.stdout.flush()
302 break
303 if not established:
304 sleep(5)
305 timeout -= 5
306 else:
307 print('Done')
308 break
309 else:
310 # Bail out with error if a router fails to converge
311 fatal_error = "MPLS LDP neighbors did not establish"
312 assert False, "MPLS LDP neighbors did not establish" % ospfStatus
313
314 print("MPLS LDP neighbors established.")
315
316 if timeout < 60:
317 # Only wait if we actually went through a convergence
318 print("\nwaiting 15s for LDP sessions to establish")
319 sleep(15)
320
7e7fc73b
MW
321 # Make sure that all daemons are running
322 for i in range(1, 5):
323 fatal_error = net['r%s' % i].checkRouterRunning()
324 assert fatal_error == "", fatal_error
325
f03e38f3
MW
326
327def test_mpls_ldp_discovery():
328 global fatal_error
329 global net
3eaafbd9 330 global cli_version
f03e38f3
MW
331
332 # Skip if previous fatal error condition is raised
333 if (fatal_error != ""):
334 pytest.skip(fatal_error)
335
336 thisDir = os.path.dirname(os.path.realpath(__file__))
337
338 # Verify OSPFv3 Routing Table
b2764f90 339 print("\n\n** Verifying MPLS LDP discovery")
f03e38f3
MW
340 print("******************************************\n")
341 failures = 0
342 for i in range(1, 5):
3eaafbd9 343 refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version)
f03e38f3 344 if os.path.isfile(refTableFile):
3eaafbd9
MW
345 # Actual output from router
346 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
347
f03e38f3
MW
348 # Read expected result from file
349 expected = open(refTableFile).read().rstrip()
350 # Fix newlines (make them all the same)
351 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
352
353 # Actual output from router
354 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
355
356 # Fix newlines (make them all the same)
357 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
358
359 # Generate Diff
360 diff = ''.join(difflib.context_diff(actual, expected,
361 fromfile="actual MPLS LDP discovery output",
362 tofile="expected MPLS LDP discovery output"))
363
364 # Empty string if it matches, otherwise diff contains unified diff
365 if diff:
366 sys.stderr.write('r%s failed MPLS LDP discovery output Check:\n%s\n' % (i, diff))
367 failures += 1
368 else:
369 print("r%s ok" % i)
370
371 assert failures == 0, "MPLS LDP Interface discovery output for router r%s:\n%s" % (i, diff)
372
7e7fc73b
MW
373 # Make sure that all daemons are running
374 for i in range(1, 5):
375 fatal_error = net['r%s' % i].checkRouterRunning()
376 assert fatal_error == "", fatal_error
377
f03e38f3
MW
378 # For debugging after starting FRR/Quagga daemons, uncomment the next line
379 # CLI(net)
380
381
382def test_mpls_ldp_neighbor():
383 global fatal_error
384 global net
3eaafbd9 385 global cli_version
f03e38f3
MW
386
387 # Skip if previous fatal error condition is raised
388 if (fatal_error != ""):
389 pytest.skip(fatal_error)
390
391 thisDir = os.path.dirname(os.path.realpath(__file__))
392
393 # Verify OSPFv3 Routing Table
b2764f90 394 print("\n\n** Verifying MPLS LDP neighbor")
f03e38f3
MW
395 print("******************************************\n")
396 failures = 0
397 for i in range(1, 5):
3eaafbd9 398 refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
399 if os.path.isfile(refTableFile):
400 # Read expected result from file
401 expected = open(refTableFile).read().rstrip()
402 # Fix newlines (make them all the same)
403 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
404
405 # Actual output from router
406 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
3eaafbd9
MW
407
408 # Mask out changing parts in output
409 if cli_version == "-1":
410 # Mask out Timer in Uptime
411 actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual)
412 # Mask out Port numbers in TCP connection
413 actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+",
414 r"TCP connection: \1:xxx - \2:xxx", actual)
415 else:
416 # Current Version
417 #
418 # Mask out Timer in Uptime
419 actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual)
f03e38f3
MW
420
421 # Fix newlines (make them all the same)
422 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
423
424 # Generate Diff
425 diff = ''.join(difflib.context_diff(actual, expected,
426 fromfile="actual MPLS LDP neighbor output",
427 tofile="expected MPLS LDP neighbor output"))
428
429 # Empty string if it matches, otherwise diff contains unified diff
430 if diff:
431 sys.stderr.write('r%s failed MPLS LDP neighbor output Check:\n%s\n' % (i, diff))
432 failures += 1
433 else:
434 print("r%s ok" % i)
435
436 assert failures == 0, "MPLS LDP Interface neighbor output for router r%s:\n%s" % (i, diff)
437
7e7fc73b
MW
438 # Make sure that all daemons are running
439 for i in range(1, 5):
440 fatal_error = net['r%s' % i].checkRouterRunning()
441 assert fatal_error == "", fatal_error
442
f03e38f3
MW
443 # For debugging after starting FRR/Quagga daemons, uncomment the next line
444 #CLI(net)
445
446
447def test_mpls_ldp_binding():
448 global fatal_error
449 global net
3eaafbd9 450 global cli_version
f03e38f3
MW
451
452 # Skip this test for now until proper sorting of the output
453 # is implemented
454 # pytest.skip("Skipping test_mpls_ldp_binding")
455
456 # Skip if previous fatal error condition is raised
457 if (fatal_error != ""):
458 pytest.skip(fatal_error)
459
460 thisDir = os.path.dirname(os.path.realpath(__file__))
461
462 # Verify OSPFv3 Routing Table
b2764f90 463 print("\n\n** Verifying MPLS LDP binding")
f03e38f3
MW
464 print("******************************************\n")
465 failures = 0
466 for i in range(1, 5):
3eaafbd9 467 refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
468 if os.path.isfile(refTableFile):
469 # Read expected result from file
470 expected = open(refTableFile).read().rstrip()
471 # Fix newlines (make them all the same)
472 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
473
474 # Actual output from router
475 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip()
3eaafbd9
MW
476
477 # Mask out changing parts in output
478 if cli_version == "-1":
479 # Mask out label
480 actual = re.sub(r"label: [0-9]+", "label: xxx", actual)
481 actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual)
482 else:
483 # Current Version
484 #
485 # Mask out label
486 actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
487 actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
488
f03e38f3
MW
489 # Fix newlines (make them all the same)
490 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
491
492 # Sort lines which start with "xx via inet "
493 pattern = r'^\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+'
494 swapped = True
495 while swapped:
496 swapped = False
497 for j in range(1, len(actual)):
498 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
499 if actual[j-1] > actual[j]:
500 temp = actual[j-1]
501 actual[j-1] = actual[j]
502 actual[j] = temp
503 swapped = True
504
505 # Generate Diff
506 diff = ''.join(difflib.context_diff(actual, expected,
507 fromfile="actual MPLS LDP binding output",
508 tofile="expected MPLS LDP binding output"))
509
510 # Empty string if it matches, otherwise diff contains unified diff
511 if diff:
512 sys.stderr.write('r%s failed MPLS LDP binding output Check:\n%s\n' % (i, diff))
513 failures += 1
514 else:
515 print("r%s ok" % i)
516
517 assert failures == 0, "MPLS LDP Interface binding output for router r%s:\n%s" % (i, diff)
518
7e7fc73b
MW
519 # Make sure that all daemons are running
520 for i in range(1, 5):
521 fatal_error = net['r%s' % i].checkRouterRunning()
522 assert fatal_error == "", fatal_error
523
f03e38f3
MW
524 # For debugging after starting FRR/Quagga daemons, uncomment the next line
525 #CLI(net)
526
527
528def test_zebra_ipv4_routingTable():
529 global fatal_error
530 global net
3eaafbd9 531 global cli_version
f03e38f3
MW
532
533 # Skip if previous fatal error condition is raised
534 if (fatal_error != ""):
535 pytest.skip(fatal_error)
536
537 thisDir = os.path.dirname(os.path.realpath(__file__))
538
539 # Verify OSPFv3 Routing Table
b2764f90 540 print("\n\n** Verifying Zebra IPv4 Routing Table")
f03e38f3
MW
541 print("******************************************\n")
542 failures = 0
543 for i in range(1, 5):
3eaafbd9 544 refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
545 if os.path.isfile(refTableFile):
546 # Read expected result from file
547 expected = open(refTableFile).read().rstrip()
548 # Fix newlines (make them all the same)
549 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
550
551 # Actual output from router
552 actual = net['r%s' % i].cmd('vtysh -c "show ip route" 2> /dev/null | grep "^O"').rstrip()
553 # Drop timers on end of line (older Quagga Versions)
554 actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
555 # Mask out label
556 actual = re.sub(r" label [0-9]+", " label xxx", actual)
faf94e5a
MW
557 # Add missing comma before label (for old version)
558 actual = re.sub(r"([0-9]) label xxx", r"\1, label xxx", actual)
f03e38f3
MW
559
560 # Fix newlines (make them all the same)
561 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
562
563 # Generate Diff
564 diff = ''.join(difflib.context_diff(actual, expected,
565 fromfile="actual IPv4 zebra routing table",
566 tofile="expected IPv4 zera routing table"))
567
568 # Empty string if it matches, otherwise diff contains unified diff
569 if diff:
570 sys.stderr.write('r%s failed IPv4 Zebra Routing Table Check:\n%s\n' % (i, diff))
571 failures += 1
572 else:
573 print("r%s ok" % i)
574
575 assert failures == 0, "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (i, diff)
576
7e7fc73b
MW
577 # Make sure that all daemons are running
578 for i in range(1, 5):
579 fatal_error = net['r%s' % i].checkRouterRunning()
580 assert fatal_error == "", fatal_error
581
f03e38f3
MW
582 # For debugging after starting FRR/Quagga daemons, uncomment the next line
583 # CLI(net)
584
585
586def test_mpls_table():
587 global fatal_error
588 global net
3eaafbd9 589 global cli_version
f03e38f3
MW
590
591 # Skip if previous fatal error condition is raised
592 if (fatal_error != ""):
593 pytest.skip(fatal_error)
594
595 thisDir = os.path.dirname(os.path.realpath(__file__))
596
597 # Verify OSPFv3 Routing Table
b2764f90 598 print("\n\n** Verifying MPLS table")
f03e38f3
MW
599 print("******************************************\n")
600 failures = 0
601 for i in range(1, 5):
3eaafbd9 602 refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
603 if os.path.isfile(refTableFile):
604 # Read expected result from file
605 expected = open(refTableFile).read().rstrip()
606 # Fix newlines (make them all the same)
607 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
608
609 # Actual output from router
610 actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
611
612 # Fix inconsistent Label numbers at beginning of line
613 actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual)
614 # Fix inconsistent Label numbers at end of line
615 actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+)[0-9][0-9]", r"\1XX", actual)
616
617 # Fix newlines (make them all the same)
618 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
619
620 # Sort lines which start with " XX LDP"
621 pattern = r'^\s+[0-9X]+\s+LDP'
622 swapped = True
623 while swapped:
624 swapped = False
625 for j in range(1, len(actual)):
626 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
627 if actual[j-1] > actual[j]:
628 temp = actual[j-1]
629 actual[j-1] = actual[j]
630 actual[j] = temp
631 swapped = True
632
633 # Generate Diff
634 diff = ''.join(difflib.context_diff(actual, expected,
635 fromfile="actual MPLS table output",
636 tofile="expected MPLS table output"))
637
638 # Empty string if it matches, otherwise diff contains unified diff
639 if diff:
640 sys.stderr.write('r%s failed MPLS table output Check:\n%s\n' % (i, diff))
641 failures += 1
642 else:
643 print("r%s ok" % i)
644
645 assert failures == 0, "MPLS table output for router r%s:\n%s" % (i, diff)
646
7e7fc73b
MW
647 # Make sure that all daemons are running
648 for i in range(1, 5):
649 fatal_error = net['r%s' % i].checkRouterRunning()
650 assert fatal_error == "", fatal_error
651
f03e38f3
MW
652 # For debugging after starting FRR/Quagga daemons, uncomment the next line
653 # CLI(net)
654
655
656def test_linux_mpls_routes():
657 global fatal_error
658 global net
3eaafbd9 659 global cli_version
f03e38f3
MW
660
661 # Skip if previous fatal error condition is raised
662 if (fatal_error != ""):
663 pytest.skip(fatal_error)
664
665 thisDir = os.path.dirname(os.path.realpath(__file__))
666
667 # Verify OSPFv3 Routing Table
b2764f90 668 print("\n\n** Verifying Linux Kernel MPLS routes")
f03e38f3
MW
669 print("******************************************\n")
670 failures = 0
671 for i in range(1, 5):
3eaafbd9 672 refTableFile = '%s/r%s/ip_mpls_route.ref%s' % (thisDir, i, cli_version)
f03e38f3
MW
673 if os.path.isfile(refTableFile):
674 # Read expected result from file
675 expected = open(refTableFile).read().rstrip()
676 # Fix newlines (make them all the same)
677 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
678
679 # Actual output from router
680 actual = net['r%s' % i].cmd('ip -family mpls route 2> /dev/null').rstrip()
681 # Mask out label
682 actual = re.sub(r"[0-9][0-9] via inet ", "xx via inet ", actual)
683 actual = re.sub(r"[0-9][0-9] proto zebra", "xx proto zebra", actual)
684 actual = re.sub(r"[0-9][0-9] as to ", "xx as to ", actual)
685 actual = re.sub(r"proto zebra ", "proto zebra", actual)
686
687 # Fix newlines (make them all the same)
688 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
689
690 # Sort lines which start with "xx via inet "
691 pattern = r'^xx via inet '
692 swapped = True
693 while swapped:
694 swapped = False
695 for j in range(1, len(actual)):
696 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
697 if actual[j-1] > actual[j]:
698 temp = actual[j-1]
699 actual[j-1] = actual[j]
700 actual[j] = temp
701 swapped = True
702
703 # Sort lines which start with " nexthopvia"
704 pattern = r'^\snexthopvia '
705 swapped = True
706 while swapped:
707 swapped = False
708 for j in range(1, len(actual)):
709 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
710 if actual[j-1] > actual[j]:
711 temp = actual[j-1]
712 actual[j-1] = actual[j]
713 actual[j] = temp
714 swapped = True
715
716 # Sort Sections of "xx proto zebra" (with all the indented lines below)
717 pattern = r'^xx via inet '
718 # Join paragraphs first
719 j = 0
720 temp = [actual[0].rstrip()]
721 for k in range(1, len(actual)):
722 if re.search(r'^\s', actual[k]):
723 # Continue line
724 temp[j] += '\n' + actual[k].rstrip()
725 else:
726 j += 1
727 temp.append(actual[k].rstrip())
728 # sort Array
729 temp.sort()
730 # Now write sort array back
731 actual = []
732 for k in range(0, len(temp)):
733 actual.extend(temp[k].splitlines())
734 # put \n back at line ends
735 actual = ('\n'.join(actual) + '\n').splitlines(1)
736
737 # Generate Diff
738 diff = ''.join(difflib.context_diff(actual, expected,
739 fromfile="actual Linux Kernel MPLS route",
740 tofile="expected Linux Kernel MPLS route"))
741
742 # Empty string if it matches, otherwise diff contains unified diff
743 if diff:
744 sys.stderr.write('r%s failed Linux Kernel MPLS route output Check:\n%s\n' % (i, diff))
745 failures += 1
746 else:
747 print("r%s ok" % i)
748
749 assert failures == 0, "Linux Kernel MPLS route output for router r%s:\n%s" % (i, diff)
750
7e7fc73b
MW
751 # Make sure that all daemons are running
752 for i in range(1, 5):
753 fatal_error = net['r%s' % i].checkRouterRunning()
754 assert fatal_error == "", fatal_error
755
f03e38f3
MW
756 # For debugging after starting FRR/Quagga daemons, uncomment the next line
757 # CLI(net)
758
759
99561211
MW
760def test_shutdown_check_stderr():
761 global fatal_error
762 global net
763
764 # Skip if previous fatal error condition is raised
765 if (fatal_error != ""):
766 pytest.skip(fatal_error)
767
768 if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
50c40bde
MW
769 print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
770 pytest.skip('Skipping test for Stderr output')
99561211
MW
771
772 thisDir = os.path.dirname(os.path.realpath(__file__))
773
b2764f90 774 print("\n\n** Verifying unexpected STDERR output from daemons")
99561211
MW
775 print("******************************************\n")
776
777 for i in range(1, 5):
778 net['r%s' % i].stopRouter()
779 log = net['r%s' % i].getStdErr('ldpd')
780 print("\nRouter r%s LDPd StdErr Log:\n%s" % (i, log))
781 log = net['r%s' % i].getStdErr('ospfd')
782 print("\nRouter r%s OSPFd StdErr Log:\n%s" % (i, log))
783 log = net['r%s' % i].getStdErr('zebra')
784 print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
785
786
50c40bde
MW
787def test_shutdown_check_memleak():
788 global fatal_error
789 global net
790
791 # Skip if previous fatal error condition is raised
792 if (fatal_error != ""):
793 pytest.skip(fatal_error)
794
795 if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
796 print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
797 pytest.skip('Skipping test for memory leaks')
798
799 thisDir = os.path.dirname(os.path.realpath(__file__))
800
801 for i in range(1, 5):
802 net['r%s' % i].stopRouter()
803 net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
804
99561211 805
f03e38f3
MW
806if __name__ == '__main__':
807
808 setLogLevel('info')
809 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
810 # retval = pytest.main(["-s", "--tb=no"])
811 retval = pytest.main(["-s"])
812 sys.exit(retval)