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