]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ldp-topo1/test_ldp_topo1.py
ldp-topo1: Adjust to accept new format in "show ip route" as introduced with PR 495...
[mirror_frr.git] / tests / topotests / ldp-topo1 / test_ldp_topo1.py
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 """
26 test_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 \ / \
55 r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0
56 +----+--+---+ +----+----+
57 | r3 | | r4 |
58 | 3.3.3.3 | | 4.4.4.4 |
59 +-----------+ +---------+
60 """
61
62 import os
63 import re
64 import sys
65 import difflib
66 import pytest
67 from time import sleep
68
69 from mininet.topo import Topo
70 from mininet.net import Mininet
71 from mininet.node import Node, OVSSwitch, Host
72 from mininet.log import setLogLevel, info
73 from mininet.cli import CLI
74 from mininet.link import Intf
75
76 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
77 from lib import topotest
78
79 fatal_error = ""
80
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)
84 cli_version = ""
85
86
87 #####################################################
88 ##
89 ## Network Topology Definition
90 ##
91 #####################################################
92
93 class NetworkTopo(Topo):
94 "LDP Test Topology 1"
95
96 def build(self, **_opts):
97
98 # Setup Routers
99 router = {}
100 for i in range(1, 5):
101 router[i] = topotest.addRouter(self, 'r%s' % i)
102
103 # Setup Switches, add Interfaces and Connections
104 switch = {}
105 # First switch
106 switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch)
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
110 switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch)
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
115 switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch)
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
119
120 #####################################################
121 ##
122 ## Tests starting
123 ##
124 #####################################################
125
126 def setup_module(module):
127 global topo, net
128 global fatal_error
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))
147 fatal_error = net['r%s' % i].startRouter()
148
149 if fatal_error != "":
150 break
151
152 # For debugging after starting FRR/Quagga daemons, uncomment the next line
153 # CLI(net)
154
155 def 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
165 def test_router_running():
166 global fatal_error
167 global net
168 global cli_version
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):
180 fatal_error = net['r%s' % i].checkRouterRunning()
181 assert fatal_error == "", fatal_error
182
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
205 # For debugging after starting FRR/Quagga daemons, uncomment the next line
206 # CLI(net)
207
208 def test_mpls_interfaces():
209 global fatal_error
210 global net
211 global cli_version
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
220 print("\n\n** Verifying MPLS Interfaces")
221 print("******************************************\n")
222 failures = 0
223 for i in range(1, 5):
224 refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version)
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
250 if failures>0:
251 fatal_error = "MPLS LDP Interface status failed"
252
253 assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff)
254
255 # For debugging after starting FRR/Quagga daemons, uncomment the next line
256 # CLI(net)
257
258
259 def test_mpls_ldp_neighbor_establish():
260 global fatal_error
261 global net
262 global cli_version
263
264 # Skip if previous fatal error condition is raised
265 if (fatal_error != ""):
266 pytest.skip(fatal_error)
267
268 # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
269 print("\n\n** Verify MPLS LDP neighbors to establish")
270 print("******************************************\n")
271 timeout = 90
272 while timeout > 0:
273 print("Timeout in %s: " % timeout),
274 sys.stdout.flush()
275 # Look for any node not yet converged
276 for i in range(1, 5):
277 established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
278 if cli_version != "-1":
279 # On current version, we need to make sure they all turn to OPERATIONAL on all lines
280 #
281 lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
282 # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
283 header = r'^AF.*'
284 operational = r'^ip.*OPERATIONAL.*'
285 found_operational = 0
286 for j in range(1, len(lines)):
287 if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
288 established = "" # Empty string shows NOT established
289 if re.search(operational, lines[j]):
290 found_operational += 1
291 if found_operational < 1:
292 # Need at least one operational neighbor
293 established = "" # Empty string shows NOT established
294 if not established:
295 print('Waiting for r%s' %i)
296 sys.stdout.flush()
297 break
298 if not established:
299 sleep(5)
300 timeout -= 5
301 else:
302 print('Done')
303 break
304 else:
305 # Bail out with error if a router fails to converge
306 fatal_error = "MPLS LDP neighbors did not establish"
307 assert False, "MPLS LDP neighbors did not establish" % ospfStatus
308
309 print("MPLS LDP neighbors established.")
310
311 if timeout < 60:
312 # Only wait if we actually went through a convergence
313 print("\nwaiting 15s for LDP sessions to establish")
314 sleep(15)
315
316
317 def test_mpls_ldp_discovery():
318 global fatal_error
319 global net
320 global cli_version
321
322 # Skip if previous fatal error condition is raised
323 if (fatal_error != ""):
324 pytest.skip(fatal_error)
325
326 thisDir = os.path.dirname(os.path.realpath(__file__))
327
328 # Verify OSPFv3 Routing Table
329 print("\n\n** Verifying MPLS LDP discovery")
330 print("******************************************\n")
331 failures = 0
332 for i in range(1, 5):
333 refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version)
334 if os.path.isfile(refTableFile):
335 # Actual output from router
336 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
337
338 # Read expected result from file
339 expected = open(refTableFile).read().rstrip()
340 # Fix newlines (make them all the same)
341 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
342
343 # Actual output from router
344 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
345
346 # Fix newlines (make them all the same)
347 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
348
349 # Generate Diff
350 diff = ''.join(difflib.context_diff(actual, expected,
351 fromfile="actual MPLS LDP discovery output",
352 tofile="expected MPLS LDP discovery output"))
353
354 # Empty string if it matches, otherwise diff contains unified diff
355 if diff:
356 sys.stderr.write('r%s failed MPLS LDP discovery output Check:\n%s\n' % (i, diff))
357 failures += 1
358 else:
359 print("r%s ok" % i)
360
361 assert failures == 0, "MPLS LDP Interface discovery output for router r%s:\n%s" % (i, diff)
362
363 # For debugging after starting FRR/Quagga daemons, uncomment the next line
364 # CLI(net)
365
366
367 def test_mpls_ldp_neighbor():
368 global fatal_error
369 global net
370 global cli_version
371
372 # Skip if previous fatal error condition is raised
373 if (fatal_error != ""):
374 pytest.skip(fatal_error)
375
376 thisDir = os.path.dirname(os.path.realpath(__file__))
377
378 # Verify OSPFv3 Routing Table
379 print("\n\n** Verifying MPLS LDP neighbor")
380 print("******************************************\n")
381 failures = 0
382 for i in range(1, 5):
383 refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version)
384 if os.path.isfile(refTableFile):
385 # Read expected result from file
386 expected = open(refTableFile).read().rstrip()
387 # Fix newlines (make them all the same)
388 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
389
390 # Actual output from router
391 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
392
393 # Mask out changing parts in output
394 if cli_version == "-1":
395 # Mask out Timer in Uptime
396 actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual)
397 # Mask out Port numbers in TCP connection
398 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]+",
399 r"TCP connection: \1:xxx - \2:xxx", actual)
400 else:
401 # Current Version
402 #
403 # Mask out Timer in Uptime
404 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)
405
406 # Fix newlines (make them all the same)
407 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
408
409 # Generate Diff
410 diff = ''.join(difflib.context_diff(actual, expected,
411 fromfile="actual MPLS LDP neighbor output",
412 tofile="expected MPLS LDP neighbor output"))
413
414 # Empty string if it matches, otherwise diff contains unified diff
415 if diff:
416 sys.stderr.write('r%s failed MPLS LDP neighbor output Check:\n%s\n' % (i, diff))
417 failures += 1
418 else:
419 print("r%s ok" % i)
420
421 assert failures == 0, "MPLS LDP Interface neighbor output for router r%s:\n%s" % (i, diff)
422
423 # For debugging after starting FRR/Quagga daemons, uncomment the next line
424 #CLI(net)
425
426
427 def test_mpls_ldp_binding():
428 global fatal_error
429 global net
430 global cli_version
431
432 # Skip this test for now until proper sorting of the output
433 # is implemented
434 # pytest.skip("Skipping test_mpls_ldp_binding")
435
436 # Skip if previous fatal error condition is raised
437 if (fatal_error != ""):
438 pytest.skip(fatal_error)
439
440 thisDir = os.path.dirname(os.path.realpath(__file__))
441
442 # Verify OSPFv3 Routing Table
443 print("\n\n** Verifying MPLS LDP binding")
444 print("******************************************\n")
445 failures = 0
446 for i in range(1, 5):
447 refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version)
448 if os.path.isfile(refTableFile):
449 # Read expected result from file
450 expected = open(refTableFile).read().rstrip()
451 # Fix newlines (make them all the same)
452 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
453
454 # Actual output from router
455 actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip()
456
457 # Mask out changing parts in output
458 if cli_version == "-1":
459 # Mask out label
460 actual = re.sub(r"label: [0-9]+", "label: xxx", actual)
461 actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual)
462 else:
463 # Current Version
464 #
465 # Mask out label
466 actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
467 actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
468
469 # Fix newlines (make them all the same)
470 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
471
472 # Sort lines which start with "xx via inet "
473 pattern = r'^\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+'
474 swapped = True
475 while swapped:
476 swapped = False
477 for j in range(1, len(actual)):
478 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
479 if actual[j-1] > actual[j]:
480 temp = actual[j-1]
481 actual[j-1] = actual[j]
482 actual[j] = temp
483 swapped = True
484
485 # Generate Diff
486 diff = ''.join(difflib.context_diff(actual, expected,
487 fromfile="actual MPLS LDP binding output",
488 tofile="expected MPLS LDP binding output"))
489
490 # Empty string if it matches, otherwise diff contains unified diff
491 if diff:
492 sys.stderr.write('r%s failed MPLS LDP binding output Check:\n%s\n' % (i, diff))
493 failures += 1
494 else:
495 print("r%s ok" % i)
496
497 assert failures == 0, "MPLS LDP Interface binding output for router r%s:\n%s" % (i, diff)
498
499 # For debugging after starting FRR/Quagga daemons, uncomment the next line
500 #CLI(net)
501
502
503 def test_zebra_ipv4_routingTable():
504 global fatal_error
505 global net
506 global cli_version
507
508 # Skip if previous fatal error condition is raised
509 if (fatal_error != ""):
510 pytest.skip(fatal_error)
511
512 thisDir = os.path.dirname(os.path.realpath(__file__))
513
514 # Verify OSPFv3 Routing Table
515 print("\n\n** Verifying Zebra IPv4 Routing Table")
516 print("******************************************\n")
517 failures = 0
518 for i in range(1, 5):
519 refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version)
520 if os.path.isfile(refTableFile):
521 # Read expected result from file
522 expected = open(refTableFile).read().rstrip()
523 # Fix newlines (make them all the same)
524 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
525
526 # Actual output from router
527 actual = net['r%s' % i].cmd('vtysh -c "show ip route" 2> /dev/null | grep "^O"').rstrip()
528 # Drop timers on end of line (older Quagga Versions)
529 actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
530 # Mask out label
531 actual = re.sub(r" label [0-9]+", " label xxx", actual)
532 # Add missing comma before label (for old version)
533 actual = re.sub(r"([0-9]) label xxx", r"\1, label xxx", actual)
534
535 # Fix newlines (make them all the same)
536 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
537
538 # Generate Diff
539 diff = ''.join(difflib.context_diff(actual, expected,
540 fromfile="actual IPv4 zebra routing table",
541 tofile="expected IPv4 zera routing table"))
542
543 # Empty string if it matches, otherwise diff contains unified diff
544 if diff:
545 sys.stderr.write('r%s failed IPv4 Zebra Routing Table Check:\n%s\n' % (i, diff))
546 failures += 1
547 else:
548 print("r%s ok" % i)
549
550 assert failures == 0, "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (i, diff)
551
552 # For debugging after starting FRR/Quagga daemons, uncomment the next line
553 # CLI(net)
554
555
556 def test_mpls_table():
557 global fatal_error
558 global net
559 global cli_version
560
561 # Skip if previous fatal error condition is raised
562 if (fatal_error != ""):
563 pytest.skip(fatal_error)
564
565 thisDir = os.path.dirname(os.path.realpath(__file__))
566
567 # Verify OSPFv3 Routing Table
568 print("\n\n** Verifying MPLS table")
569 print("******************************************\n")
570 failures = 0
571 for i in range(1, 5):
572 refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, cli_version)
573 if os.path.isfile(refTableFile):
574 # Read expected result from file
575 expected = open(refTableFile).read().rstrip()
576 # Fix newlines (make them all the same)
577 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
578
579 # Actual output from router
580 actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
581
582 # Fix inconsistent Label numbers at beginning of line
583 actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual)
584 # Fix inconsistent Label numbers at end of line
585 actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+)[0-9][0-9]", r"\1XX", actual)
586
587 # Fix newlines (make them all the same)
588 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
589
590 # Sort lines which start with " XX LDP"
591 pattern = r'^\s+[0-9X]+\s+LDP'
592 swapped = True
593 while swapped:
594 swapped = False
595 for j in range(1, len(actual)):
596 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
597 if actual[j-1] > actual[j]:
598 temp = actual[j-1]
599 actual[j-1] = actual[j]
600 actual[j] = temp
601 swapped = True
602
603 # Generate Diff
604 diff = ''.join(difflib.context_diff(actual, expected,
605 fromfile="actual MPLS table output",
606 tofile="expected MPLS table output"))
607
608 # Empty string if it matches, otherwise diff contains unified diff
609 if diff:
610 sys.stderr.write('r%s failed MPLS table output Check:\n%s\n' % (i, diff))
611 failures += 1
612 else:
613 print("r%s ok" % i)
614
615 assert failures == 0, "MPLS table output for router r%s:\n%s" % (i, diff)
616
617 # For debugging after starting FRR/Quagga daemons, uncomment the next line
618 # CLI(net)
619
620
621 def test_linux_mpls_routes():
622 global fatal_error
623 global net
624 global cli_version
625
626 # Skip if previous fatal error condition is raised
627 if (fatal_error != ""):
628 pytest.skip(fatal_error)
629
630 thisDir = os.path.dirname(os.path.realpath(__file__))
631
632 # Verify OSPFv3 Routing Table
633 print("\n\n** Verifying Linux Kernel MPLS routes")
634 print("******************************************\n")
635 failures = 0
636 for i in range(1, 5):
637 refTableFile = '%s/r%s/ip_mpls_route.ref%s' % (thisDir, i, cli_version)
638 if os.path.isfile(refTableFile):
639 # Read expected result from file
640 expected = open(refTableFile).read().rstrip()
641 # Fix newlines (make them all the same)
642 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
643
644 # Actual output from router
645 actual = net['r%s' % i].cmd('ip -family mpls route 2> /dev/null').rstrip()
646 # Mask out label
647 actual = re.sub(r"[0-9][0-9] via inet ", "xx via inet ", actual)
648 actual = re.sub(r"[0-9][0-9] proto zebra", "xx proto zebra", actual)
649 actual = re.sub(r"[0-9][0-9] as to ", "xx as to ", actual)
650 actual = re.sub(r"proto zebra ", "proto zebra", actual)
651
652 # Fix newlines (make them all the same)
653 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
654
655 # Sort lines which start with "xx via inet "
656 pattern = r'^xx via inet '
657 swapped = True
658 while swapped:
659 swapped = False
660 for j in range(1, len(actual)):
661 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
662 if actual[j-1] > actual[j]:
663 temp = actual[j-1]
664 actual[j-1] = actual[j]
665 actual[j] = temp
666 swapped = True
667
668 # Sort lines which start with " nexthopvia"
669 pattern = r'^\snexthopvia '
670 swapped = True
671 while swapped:
672 swapped = False
673 for j in range(1, len(actual)):
674 if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]):
675 if actual[j-1] > actual[j]:
676 temp = actual[j-1]
677 actual[j-1] = actual[j]
678 actual[j] = temp
679 swapped = True
680
681 # Sort Sections of "xx proto zebra" (with all the indented lines below)
682 pattern = r'^xx via inet '
683 # Join paragraphs first
684 j = 0
685 temp = [actual[0].rstrip()]
686 for k in range(1, len(actual)):
687 if re.search(r'^\s', actual[k]):
688 # Continue line
689 temp[j] += '\n' + actual[k].rstrip()
690 else:
691 j += 1
692 temp.append(actual[k].rstrip())
693 # sort Array
694 temp.sort()
695 # Now write sort array back
696 actual = []
697 for k in range(0, len(temp)):
698 actual.extend(temp[k].splitlines())
699 # put \n back at line ends
700 actual = ('\n'.join(actual) + '\n').splitlines(1)
701
702 # Generate Diff
703 diff = ''.join(difflib.context_diff(actual, expected,
704 fromfile="actual Linux Kernel MPLS route",
705 tofile="expected Linux Kernel MPLS route"))
706
707 # Empty string if it matches, otherwise diff contains unified diff
708 if diff:
709 sys.stderr.write('r%s failed Linux Kernel MPLS route output Check:\n%s\n' % (i, diff))
710 failures += 1
711 else:
712 print("r%s ok" % i)
713
714 assert failures == 0, "Linux Kernel MPLS route output for router r%s:\n%s" % (i, diff)
715
716 # For debugging after starting FRR/Quagga daemons, uncomment the next line
717 # CLI(net)
718
719
720 def test_shutdown_check_stderr():
721 global fatal_error
722 global net
723
724 # Skip if previous fatal error condition is raised
725 if (fatal_error != ""):
726 pytest.skip(fatal_error)
727
728 if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
729 print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
730 pytest.skip('Skipping test for Stderr output')
731
732 thisDir = os.path.dirname(os.path.realpath(__file__))
733
734 print("\n\n** Verifying unexpected STDERR output from daemons")
735 print("******************************************\n")
736
737 for i in range(1, 5):
738 net['r%s' % i].stopRouter()
739 log = net['r%s' % i].getStdErr('ldpd')
740 print("\nRouter r%s LDPd StdErr Log:\n%s" % (i, log))
741 log = net['r%s' % i].getStdErr('ospfd')
742 print("\nRouter r%s OSPFd StdErr Log:\n%s" % (i, log))
743 log = net['r%s' % i].getStdErr('zebra')
744 print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
745
746
747 def test_shutdown_check_memleak():
748 global fatal_error
749 global net
750
751 # Skip if previous fatal error condition is raised
752 if (fatal_error != ""):
753 pytest.skip(fatal_error)
754
755 if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
756 print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
757 pytest.skip('Skipping test for memory leaks')
758
759 thisDir = os.path.dirname(os.path.realpath(__file__))
760
761 for i in range(1, 5):
762 net['r%s' % i].stopRouter()
763 net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
764
765
766 if __name__ == '__main__':
767
768 setLogLevel('info')
769 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
770 # retval = pytest.main(["-s", "--tb=no"])
771 retval = pytest.main(["-s"])
772 sys.exit(retval)