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