]>
Commit | Line | Data |
---|---|---|
4501fbca MW |
1 | #!/usr/bin/env python |
2 | ||
3 | # | |
4 | # test_all_protocol_startup.py | |
5 | # Part of NetDEF Topology Tests | |
6 | # | |
7 | # Copyright (c) 2017 by | |
8 | # Network Device Education Foundation, Inc. ("NetDEF") | |
9 | # | |
10 | # Permission to use, copy, modify, and/or distribute this software | |
11 | # for any purpose with or without fee is hereby granted, provided | |
12 | # that the above copyright notice and this permission notice appear | |
13 | # in all copies. | |
14 | # | |
15 | # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES | |
16 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
17 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR | |
18 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | |
19 | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
20 | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
21 | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
22 | # OF THIS SOFTWARE. | |
23 | # | |
24 | ||
25 | """ | |
26 | test_all_protocol_startup.py: Test of all protocols at same time | |
27 | ||
28 | """ | |
29 | ||
30 | import os | |
31 | import re | |
32 | import sys | |
4501fbca | 33 | import pytest |
6a57e103 | 34 | import glob |
4501fbca MW |
35 | from time import sleep |
36 | ||
37 | from mininet.topo import Topo | |
38 | from mininet.net import Mininet | |
39 | from mininet.node import Node, OVSSwitch, Host | |
40 | from mininet.log import setLogLevel, info | |
41 | from mininet.cli import CLI | |
42 | from mininet.link import Intf | |
43 | ||
44 | from functools import partial | |
45 | ||
46 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
47 | from lib import topotest | |
48 | ||
49 | fatal_error = "" | |
50 | ||
51 | ||
52 | ##################################################### | |
53 | ## | |
54 | ## Network Topology Definition | |
55 | ## | |
56 | ##################################################### | |
57 | ||
58 | class NetworkTopo(Topo): | |
59 | "All Protocol Startup Test" | |
60 | ||
61 | def build(self, **_opts): | |
62 | ||
63 | # Setup Routers | |
64 | router = {} | |
65 | # | |
66 | # Setup Main Router | |
67 | router[1] = topotest.addRouter(self, 'r1') | |
68 | # | |
69 | ||
70 | # Setup Switches | |
71 | switch = {} | |
72 | # | |
73 | for i in range(0, 10): | |
74 | switch[i] = self.addSwitch('sw%s' % i, cls=topotest.LegacySwitch) | |
75 | self.addLink(switch[i], router[1], intfName2='r1-eth%s' % i ) | |
76 | ||
77 | ||
78 | ##################################################### | |
79 | ## | |
80 | ## Tests starting | |
81 | ## | |
82 | ##################################################### | |
83 | ||
84 | def setup_module(module): | |
85 | global topo, net | |
86 | global fatal_error | |
87 | ||
88 | print("\n\n** %s: Setup Topology" % module.__name__) | |
89 | print("******************************************\n") | |
90 | ||
91 | print("Cleanup old Mininet runs") | |
92 | os.system('sudo mn -c > /dev/null 2>&1') | |
93 | os.system('sudo rm /tmp/r* > /dev/null 2>&1') | |
94 | ||
95 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
96 | topo = NetworkTopo() | |
97 | ||
98 | net = Mininet(controller=None, topo=topo) | |
99 | net.start() | |
100 | ||
101 | if net['r1'].get_routertype() != 'frr': | |
102 | fatal_error = "Test is only implemented for FRR" | |
103 | sys.stderr.write('\n\nTest is only implemented for FRR - Skipping\n\n') | |
104 | pytest.skip(fatal_error) | |
105 | ||
106 | # Starting Routers | |
107 | # | |
108 | # Main router | |
109 | for i in range(1, 2): | |
110 | net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) | |
111 | net['r%s' % i].loadConf('ripd', '%s/r%s/ripd.conf' % (thisDir, i)) | |
112 | net['r%s' % i].loadConf('ripngd', '%s/r%s/ripngd.conf' % (thisDir, i)) | |
113 | net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i)) | |
fa2adbc5 MW |
114 | if net['r1'].checkRouterVersion('<', '4.0'): |
115 | net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf-pre-v4' % (thisDir, i)) | |
116 | else: | |
117 | net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) | |
4501fbca MW |
118 | net['r%s' % i].loadConf('isisd', '%s/r%s/isisd.conf' % (thisDir, i)) |
119 | net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) | |
120 | if net['r%s' % i].daemon_available('ldpd'): | |
121 | # Only test LDPd if it's installed and Kernel >= 4.5 | |
122 | net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) | |
8058df22 | 123 | net['r%s' % i].loadConf('sharpd') |
a0764a36 DS |
124 | net['r%s' % i].loadConf('nhrpd', '%s/r%s/nhrpd.conf' % (thisDir, i)) |
125 | net['r%s' % i].loadConf('babeld', '%s/r%s/babeld.conf' % (thisDir, i)) | |
223f87f4 | 126 | net['r%s' % i].loadConf('pbrd', '%s/r%s/pbrd.conf' % (thisDir, i)) |
4501fbca MW |
127 | net['r%s' % i].startRouter() |
128 | ||
129 | # For debugging after starting Quagga/FRR daemons, uncomment the next line | |
130 | # CLI(net) | |
131 | ||
132 | ||
133 | def teardown_module(module): | |
134 | global net | |
135 | ||
136 | print("\n\n** %s: Shutdown Topology" % module.__name__) | |
137 | print("******************************************\n") | |
138 | ||
139 | # End - Shutdown network | |
140 | net.stop() | |
141 | ||
142 | ||
143 | def test_router_running(): | |
144 | global fatal_error | |
145 | global net | |
146 | ||
147 | # Skip if previous fatal error condition is raised | |
148 | if (fatal_error != ""): | |
149 | pytest.skip(fatal_error) | |
150 | ||
151 | print("\n\n** Check if FRR/Quagga is running on each Router node") | |
152 | print("******************************************\n") | |
153 | sleep(5) | |
154 | ||
155 | # Starting Routers | |
156 | for i in range(1, 2): | |
157 | fatal_error = net['r%s' % i].checkRouterRunning() | |
158 | assert fatal_error == "", fatal_error | |
159 | ||
160 | # For debugging after starting FRR/Quagga daemons, uncomment the next line | |
161 | # CLI(net) | |
162 | ||
163 | ||
164 | def test_error_messages_vtysh(): | |
165 | global fatal_error | |
166 | global net | |
167 | ||
168 | # Skip if previous fatal error condition is raised | |
169 | if (fatal_error != ""): | |
170 | pytest.skip(fatal_error) | |
171 | ||
172 | print("\n\n** Check for error messages on VTYSH") | |
173 | print("******************************************\n") | |
174 | ||
175 | failures = 0 | |
176 | for i in range(1, 2): | |
177 | # | |
178 | # First checking Standard Output | |
179 | # | |
180 | ||
181 | # VTYSH output from router | |
182 | vtystdout = net['r%s' % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip() | |
183 | ||
184 | # Fix newlines (make them all the same) | |
185 | vtystdout = ('\n'.join(vtystdout.splitlines()) + '\n').rstrip() | |
186 | # Drop everything starting with "FRRouting X.xx" message | |
187 | vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL) | |
188 | ||
555451fa | 189 | if (vtystdout == ''): |
4501fbca MW |
190 | print("r%s StdOut ok" % i) |
191 | ||
555451fa | 192 | assert vtystdout == '', "Vtysh StdOut Output check failed for router r%s" % i |
798fb593 | 193 | |
4501fbca MW |
194 | # |
195 | # Second checking Standard Error | |
196 | # | |
197 | ||
198 | # VTYSH StdErr output from router | |
199 | vtystderr = net['r%s' % i].cmd('vtysh -c "show version" > /dev/null').rstrip() | |
200 | ||
201 | # Fix newlines (make them all the same) | |
202 | vtystderr = ('\n'.join(vtystderr.splitlines()) + '\n').rstrip() | |
203 | # # Drop everything starting with "FRRouting X.xx" message | |
204 | # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL) | |
205 | ||
555451fa | 206 | if (vtystderr == ''): |
4501fbca MW |
207 | print("r%s StdErr ok" % i) |
208 | ||
555451fa | 209 | assert vtystderr == '', "Vtysh StdErr Output check failed for router r%s" % i |
4501fbca | 210 | |
7e7fc73b MW |
211 | # Make sure that all daemons are running |
212 | for i in range(1, 2): | |
213 | fatal_error = net['r%s' % i].checkRouterRunning() | |
214 | assert fatal_error == "", fatal_error | |
215 | ||
4501fbca MW |
216 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
217 | # CLI(net) | |
218 | ||
219 | ||
220 | def test_error_messages_daemons(): | |
221 | global fatal_error | |
222 | global net | |
223 | ||
224 | # Skip if previous fatal error condition is raised | |
225 | if (fatal_error != ""): | |
226 | pytest.skip(fatal_error) | |
227 | ||
228 | print("\n\n** Check for error messages in daemons") | |
229 | print("******************************************\n") | |
230 | ||
231 | error_logs = "" | |
232 | ||
233 | for i in range(1, 2): | |
234 | log = net['r%s' % i].getStdErr('ripd') | |
235 | if log: | |
236 | error_logs += "r%s RIPd StdErr Output:\n" % i | |
237 | error_logs += log | |
238 | log = net['r%s' % i].getStdErr('ripngd') | |
239 | if log: | |
240 | error_logs += "r%s RIPngd StdErr Output:\n" % i | |
241 | error_logs += log | |
242 | log = net['r%s' % i].getStdErr('ospfd') | |
243 | if log: | |
244 | error_logs += "r%s OSPFd StdErr Output:\n" % i | |
245 | error_logs += log | |
246 | log = net['r%s' % i].getStdErr('ospf6d') | |
247 | if log: | |
248 | error_logs += "r%s OSPF6d StdErr Output:\n" % i | |
249 | error_logs += log | |
250 | log = net['r%s' % i].getStdErr('isisd') | |
251 | # ISIS shows debugging enabled status on StdErr | |
252 | # Remove these messages | |
253 | log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip() | |
254 | if log: | |
255 | error_logs += "r%s ISISd StdErr Output:\n" % i | |
256 | error_logs += log | |
257 | log = net['r%s' % i].getStdErr('bgpd') | |
258 | if log: | |
259 | error_logs += "r%s BGPd StdErr Output:\n" % i | |
260 | error_logs += log | |
261 | if (net['r%s' % i].daemon_available('ldpd')): | |
262 | log = net['r%s' % i].getStdErr('ldpd') | |
263 | if log: | |
264 | error_logs += "r%s LDPd StdErr Output:\n" % i | |
265 | error_logs += log | |
af39fbe7 MS |
266 | |
267 | log = net['r1'].getStdErr('nhrpd') | |
268 | if log: | |
269 | error_logs += "r%s NHRPd StdErr Output:\n" % i | |
270 | error_logs += log | |
271 | ||
272 | log = net['r1'].getStdErr('babeld') | |
273 | if log: | |
274 | error_logs += "r%s BABELd StdErr Output:\n" % i | |
275 | error_logs += log | |
276 | ||
277 | log = net['r1'].getStdErr('pbrd') | |
278 | if log: | |
279 | error_logs += "r%s PBRd StdErr Output:\n" % i | |
280 | error_logs += log | |
281 | ||
4501fbca MW |
282 | log = net['r%s' % i].getStdErr('zebra') |
283 | if log: | |
284 | error_logs += "r%s Zebra StdErr Output:\n" | |
285 | error_logs += log | |
286 | ||
287 | if error_logs: | |
288 | sys.stderr.write('Failed check for StdErr Output on daemons:\n%s\n' % error_logs) | |
289 | ||
08fa1af7 MW |
290 | # Ignoring the issue if told to ignore (ie not yet fixed) |
291 | if (error_logs != ""): | |
1026c19a | 292 | if (os.environ.get('bamboo_TOPOTESTS_ISSUE_349') == "IGNORE"): |
08fa1af7 MW |
293 | sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n') |
294 | pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349') | |
295 | ||
4501fbca MW |
296 | assert error_logs == "", "Daemons report errors to StdErr" |
297 | ||
298 | # For debugging after starting FRR/Quagga daemons, uncomment the next line | |
299 | # CLI(net) | |
300 | ||
301 | ||
302 | def test_converge_protocols(): | |
303 | global fatal_error | |
304 | global net | |
305 | ||
306 | # Skip if previous fatal error condition is raised | |
307 | if (fatal_error != ""): | |
308 | pytest.skip(fatal_error) | |
309 | ||
310 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
311 | ||
312 | print("\n\n** Waiting for protocols convergence") | |
313 | print("******************************************\n") | |
314 | ||
315 | # Not really implemented yet - just sleep 60 secs for now | |
316 | sleep(60) | |
317 | ||
7e7fc73b | 318 | # Make sure that all daemons are running |
556f76e1 | 319 | failures = 0 |
7e7fc73b MW |
320 | for i in range(1, 2): |
321 | fatal_error = net['r%s' % i].checkRouterRunning() | |
322 | assert fatal_error == "", fatal_error | |
323 | ||
556f76e1 DS |
324 | print("Show that v4 routes are right\n"); |
325 | v4_routesFile = '%s/r%s/ipv4_routes.ref' % (thisDir, i) | |
326 | expected = open(v4_routesFile).read().rstrip() | |
327 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
328 | ||
14c40525 | 329 | actual = net['r%s' %i].cmd('vtysh -c "show ip route" | /usr/bin/tail -n +7 | env LC_ALL=en_US.UTF-8 sort 2> /dev/null').rstrip() |
556f76e1 DS |
330 | # Drop time in last update |
331 | actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) | |
332 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
333 | diff = topotest.get_textdiff(actual, expected, | |
334 | title1="Actual IP Routing Table", | |
335 | title2="Expected IP RoutingTable") | |
336 | if diff: | |
337 | sys.stderr.write('r%s failed IP Routing table check:\n%s\n' % (i, diff)) | |
338 | failures += 1 | |
339 | else: | |
340 | print("r%s ok" %i) | |
341 | ||
342 | assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff) | |
343 | ||
344 | failures = 0 | |
345 | ||
346 | print("Show that v6 routes are right\n") | |
347 | v6_routesFile = '%s/r%s/ipv6_routes.ref' % (thisDir, i) | |
348 | expected = open(v6_routesFile).read().rstrip() | |
349 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
350 | ||
14c40525 | 351 | actual = net['r%s' %i].cmd('vtysh -c "show ipv6 route" | /usr/bin/tail -n +7 | env LC_ALL=en_US.UTF-8 sort 2> /dev/null').rstrip() |
556f76e1 DS |
352 | # Drop time in last update |
353 | actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) | |
354 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
355 | diff = topotest.get_textdiff(actual, expected, | |
356 | title1="Actual IPv6 Routing Table", | |
357 | title2="Expected IPv6 RoutingTable") | |
358 | if diff: | |
359 | sys.stderr.write('r%s failed IPv6 Routing table check:\n%s\n' % (i, diff)) | |
360 | failures += 1 | |
361 | else: | |
362 | print("r%s ok" %i) | |
363 | ||
364 | assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff) | |
365 | ||
4501fbca MW |
366 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
367 | ## CLI(net) | |
368 | ||
887a232c SW |
369 | def route_get_nhg_id(route_str): |
370 | output = net["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str) | |
371 | match = re.search(r"Nexthop Group ID: (\d+)", output) | |
372 | assert match is not None, "Nexthop Group ID not found for sharpd route %s" % route_str | |
373 | ||
374 | nhg_id = int(match.group(1)) | |
375 | return nhg_id | |
376 | ||
377 | def verify_nexthop_group(nhg_id, recursive=False): | |
378 | # Verify NHG is valid/installed | |
379 | output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) | |
380 | ||
381 | match = re.search(r"Valid", output) | |
382 | assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id | |
383 | ||
384 | # If recursive, we need to look at its resolved group | |
385 | if recursive: | |
386 | match = re.search(r"Depends: \((\d+)\)", output) | |
387 | resolved_id = int(match.group(1)) | |
388 | verify_nexthop_group(resolved_id, False) | |
389 | else: | |
390 | match = re.search(r"Installed", output) | |
391 | assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id | |
392 | ||
393 | def verify_route_nexthop_group(route_str, recursive=False): | |
394 | # Verify route and that zebra created NHGs for and they are valid/installed | |
395 | nhg_id = route_get_nhg_id(route_str) | |
396 | verify_nexthop_group(nhg_id, recursive) | |
397 | ||
8058df22 SW |
398 | def test_nexthop_groups(): |
399 | global fatal_error | |
400 | global net | |
401 | ||
402 | # Skip if previous fatal error condition is raised | |
403 | if (fatal_error != ""): | |
404 | pytest.skip(fatal_error) | |
405 | ||
406 | print("\n\n** Verifying Nexthop Groups") | |
407 | print("******************************************\n") | |
408 | ||
887a232c SW |
409 | ### Nexthop Group Tests |
410 | ||
411 | ## Basic test | |
412 | ||
8058df22 | 413 | # Create a lib nexthop-group |
887a232c | 414 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') |
8058df22 SW |
415 | |
416 | # Create with sharpd using nexthop-group | |
887a232c | 417 | net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"') |
8058df22 | 418 | |
887a232c | 419 | verify_route_nexthop_group("2.2.2.1/32") |
8058df22 | 420 | |
887a232c | 421 | ## Connected |
8058df22 | 422 | |
887a232c | 423 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"') |
8058df22 | 424 | |
887a232c SW |
425 | net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"') |
426 | ||
427 | verify_route_nexthop_group("2.2.2.2/32") | |
428 | ||
429 | ## Recursive | |
430 | ||
431 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"') | |
432 | ||
433 | net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"') | |
434 | ||
435 | verify_route_nexthop_group("3.3.3.1/32", True) | |
436 | ||
437 | ## Duplicate | |
438 | ||
439 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"') | |
440 | ||
441 | net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"') | |
442 | ||
443 | verify_route_nexthop_group("3.3.3.2/32") | |
444 | ||
445 | ## Two 4-Way ECMP | |
446 | ||
447 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \ | |
448 | -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"') | |
449 | ||
450 | net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"') | |
451 | ||
452 | verify_route_nexthop_group("4.4.4.1/32") | |
453 | ||
454 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \ | |
455 | -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"') | |
456 | ||
457 | net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"') | |
458 | ||
459 | verify_route_nexthop_group("4.4.4.2/32") | |
460 | ||
461 | ## Recursive to 8-Way ECMP | |
462 | ||
463 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"') | |
464 | ||
465 | net["r1"].cmd('vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"') | |
466 | ||
467 | verify_route_nexthop_group("5.5.5.1/32") | |
468 | ||
469 | ##CLI(net) | |
470 | ||
471 | ## Remove all NHG routes | |
472 | ||
473 | net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"') | |
474 | net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"') | |
475 | net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"') | |
476 | net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"') | |
477 | net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"') | |
478 | net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"') | |
479 | net["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"') | |
4501fbca MW |
480 | |
481 | def test_rip_status(): | |
482 | global fatal_error | |
483 | global net | |
484 | ||
485 | # Skip if previous fatal error condition is raised | |
486 | if (fatal_error != ""): | |
487 | pytest.skip(fatal_error) | |
488 | ||
489 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
490 | ||
b2764f90 | 491 | print("\n\n** Verifying RIP status") |
4501fbca MW |
492 | print("******************************************\n") |
493 | failures = 0 | |
494 | for i in range(1, 2): | |
495 | refTableFile = '%s/r%s/rip_status.ref' % (thisDir, i) | |
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) | |
500 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
501 | ||
502 | # Actual output from router | |
503 | actual = net['r%s' % i].cmd('vtysh -c "show ip rip status" 2> /dev/null').rstrip() | |
504 | # Drop time in next due | |
505 | actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) | |
506 | # Drop time in last update | |
507 | actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) | |
508 | # Fix newlines (make them all the same) | |
509 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
510 | ||
511 | # Generate Diff | |
17070436 MW |
512 | diff = topotest.get_textdiff(actual, expected, |
513 | title1="actual IP RIP status", | |
514 | title2="expected IP RIP status") | |
4501fbca MW |
515 | |
516 | # Empty string if it matches, otherwise diff contains unified diff | |
517 | if diff: | |
518 | sys.stderr.write('r%s failed IP RIP status check:\n%s\n' % (i, diff)) | |
519 | failures += 1 | |
520 | else: | |
521 | print("r%s ok" % i) | |
522 | ||
523 | assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) | |
524 | ||
7e7fc73b MW |
525 | # Make sure that all daemons are running |
526 | for i in range(1, 2): | |
527 | fatal_error = net['r%s' % i].checkRouterRunning() | |
528 | assert fatal_error == "", fatal_error | |
529 | ||
4501fbca MW |
530 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
531 | # CLI(net) | |
532 | ||
533 | ||
534 | def test_ripng_status(): | |
535 | global fatal_error | |
536 | global net | |
537 | ||
538 | # Skip if previous fatal error condition is raised | |
539 | if (fatal_error != ""): | |
540 | pytest.skip(fatal_error) | |
541 | ||
542 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
543 | ||
b2764f90 | 544 | print("\n\n** Verifying RIPng status") |
4501fbca MW |
545 | print("******************************************\n") |
546 | failures = 0 | |
547 | for i in range(1, 2): | |
548 | refTableFile = '%s/r%s/ripng_status.ref' % (thisDir, i) | |
549 | if os.path.isfile(refTableFile): | |
550 | # Read expected result from file | |
551 | expected = open(refTableFile).read().rstrip() | |
552 | # Fix newlines (make them all the same) | |
553 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
554 | ||
555 | # Actual output from router | |
556 | actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null').rstrip() | |
557 | # Mask out Link-Local mac address portion. They are random... | |
558 | actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) | |
559 | # Drop time in next due | |
560 | actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) | |
561 | # Drop time in last update | |
562 | actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) | |
563 | # Fix newlines (make them all the same) | |
564 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
565 | ||
566 | # Generate Diff | |
17070436 MW |
567 | diff = topotest.get_textdiff(actual, expected, |
568 | title1="actual IPv6 RIPng status", | |
569 | title2="expected IPv6 RIPng status") | |
4501fbca MW |
570 | |
571 | # Empty string if it matches, otherwise diff contains unified diff | |
572 | if diff: | |
573 | sys.stderr.write('r%s failed IPv6 RIPng status check:\n%s\n' % (i, diff)) | |
574 | failures += 1 | |
575 | else: | |
576 | print("r%s ok" % i) | |
577 | ||
578 | assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) | |
579 | ||
7e7fc73b MW |
580 | # Make sure that all daemons are running |
581 | for i in range(1, 2): | |
582 | fatal_error = net['r%s' % i].checkRouterRunning() | |
583 | assert fatal_error == "", fatal_error | |
584 | ||
4501fbca MW |
585 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
586 | # CLI(net) | |
587 | ||
588 | ||
589 | def test_ospfv2_interfaces(): | |
590 | global fatal_error | |
591 | global net | |
592 | ||
593 | # Skip if previous fatal error condition is raised | |
594 | if (fatal_error != ""): | |
595 | pytest.skip(fatal_error) | |
596 | ||
597 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
598 | ||
b2764f90 | 599 | print("\n\n** Verifying OSPFv2 interfaces") |
4501fbca MW |
600 | print("******************************************\n") |
601 | failures = 0 | |
602 | for i in range(1, 2): | |
603 | refTableFile = '%s/r%s/show_ip_ospf_interface.ref' % (thisDir, i) | |
604 | if os.path.isfile(refTableFile): | |
605 | # Read expected result from file | |
606 | expected = open(refTableFile).read().rstrip() | |
607 | # Fix newlines (make them all the same) | |
608 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
609 | ||
610 | # Actual output from router | |
611 | actual = net['r%s' % i].cmd('vtysh -c "show ip ospf interface" 2> /dev/null').rstrip() | |
612 | # Mask out Bandwidth portion. They may change.. | |
613 | actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual) | |
c9d72a0b DS |
614 | actual = re.sub(r"ifindex [0-9]", "ifindex X", actual) |
615 | ||
4501fbca MW |
616 | # Drop time in next due |
617 | actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual) | |
a2ab6fd8 | 618 | actual = re.sub(r"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual) |
985e6d50 MW |
619 | # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both |
620 | actual = re.sub(r"MTU mismatch detection:([a-z]+.*)", r"MTU mismatch detection: \1", actual) | |
4501fbca MW |
621 | # Fix newlines (make them all the same) |
622 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
623 | ||
624 | # Generate Diff | |
17070436 MW |
625 | diff = topotest.get_textdiff(actual, expected, |
626 | title1="actual SHOW IP OSPF INTERFACE", | |
627 | title2="expected SHOW IP OSPF INTERFACE") | |
4501fbca MW |
628 | |
629 | # Empty string if it matches, otherwise diff contains unified diff | |
630 | if diff: | |
631 | sys.stderr.write('r%s failed SHOW IP OSPF INTERFACE check:\n%s\n' % (i, diff)) | |
632 | failures += 1 | |
633 | else: | |
634 | print("r%s ok" % i) | |
635 | ||
08fa1af7 MW |
636 | # Ignoring the issue if told to ignore (ie not yet fixed) |
637 | if (failures != 0): | |
1026c19a | 638 | if (os.environ.get('bamboo_TOPOTESTS_ISSUE_348') == "IGNORE"): |
08fa1af7 MW |
639 | sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n') |
640 | pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348') | |
641 | ||
4501fbca MW |
642 | assert failures == 0, "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) |
643 | ||
7e7fc73b MW |
644 | # Make sure that all daemons are running |
645 | for i in range(1, 2): | |
646 | fatal_error = net['r%s' % i].checkRouterRunning() | |
647 | assert fatal_error == "", fatal_error | |
648 | ||
4501fbca MW |
649 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
650 | # CLI(net) | |
651 | ||
652 | ||
653 | def test_isis_interfaces(): | |
654 | global fatal_error | |
655 | global net | |
656 | ||
657 | # Skip if previous fatal error condition is raised | |
658 | if (fatal_error != ""): | |
659 | pytest.skip(fatal_error) | |
660 | ||
661 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
662 | ||
b2764f90 | 663 | print("\n\n** Verifying ISIS interfaces") |
4501fbca MW |
664 | print("******************************************\n") |
665 | failures = 0 | |
666 | for i in range(1, 2): | |
667 | refTableFile = '%s/r%s/show_isis_interface_detail.ref' % (thisDir, i) | |
668 | if os.path.isfile(refTableFile): | |
669 | # Read expected result from file | |
670 | expected = open(refTableFile).read().rstrip() | |
671 | # Fix newlines (make them all the same) | |
672 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
673 | ||
674 | # Actual output from router | |
675 | actual = net['r%s' % i].cmd('vtysh -c "show isis interface detail" 2> /dev/null').rstrip() | |
676 | # Mask out Link-Local mac address portion. They are random... | |
677 | actual = re.sub(r"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual) | |
678 | # Mask out SNPA mac address portion. They are random... | |
679 | actual = re.sub(r"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual) | |
6ae351e8 MW |
680 | # Mask out Circuit ID number |
681 | actual = re.sub(r"Circuit Id: 0x[0-9]+", "Circuit Id: 0xXX", actual) | |
4501fbca MW |
682 | # Fix newlines (make them all the same) |
683 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
684 | ||
685 | # Generate Diff | |
17070436 MW |
686 | diff = topotest.get_textdiff(actual, expected, |
687 | title1="actual SHOW ISIS INTERFACE DETAIL", | |
688 | title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL") | |
4501fbca MW |
689 | |
690 | # Empty string if it matches, otherwise diff contains unified diff | |
691 | if diff: | |
692 | sys.stderr.write('r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n' % (i, diff)) | |
693 | failures += 1 | |
694 | else: | |
695 | print("r%s ok" % i) | |
696 | ||
697 | assert failures == 0, "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff) | |
698 | ||
7e7fc73b MW |
699 | # Make sure that all daemons are running |
700 | for i in range(1, 2): | |
701 | fatal_error = net['r%s' % i].checkRouterRunning() | |
702 | assert fatal_error == "", fatal_error | |
703 | ||
4501fbca MW |
704 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
705 | # CLI(net) | |
706 | ||
707 | ||
708 | def test_bgp_summary(): | |
709 | global fatal_error | |
710 | global net | |
711 | ||
712 | # Skip if previous fatal error condition is raised | |
713 | if (fatal_error != ""): | |
714 | pytest.skip(fatal_error) | |
715 | ||
716 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
717 | ||
b2764f90 | 718 | print("\n\n** Verifying BGP Summary") |
4501fbca MW |
719 | print("******************************************\n") |
720 | failures = 0 | |
721 | for i in range(1, 2): | |
08fa1af7 | 722 | refTableFile = '%s/r%s/show_ip_bgp_summary.ref' % (thisDir, i) |
4501fbca MW |
723 | if os.path.isfile(refTableFile): |
724 | # Read expected result from file | |
725 | expected = open(refTableFile).read().rstrip() | |
726 | # Fix newlines (make them all the same) | |
727 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
728 | ||
729 | # Actual output from router | |
08fa1af7 | 730 | actual = net['r%s' % i].cmd('vtysh -c "show ip bgp summary" 2> /dev/null').rstrip() |
4501fbca MW |
731 | # Mask out "using XXiXX bytes" portion. They are random... |
732 | actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) | |
733 | # Mask out "using XiXXX KiB" portion. They are random... | |
734 | actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) | |
08fa1af7 MW |
735 | # |
736 | # Remove extra summaries which exist with newer versions | |
737 | # | |
738 | # Remove summary lines (changed recently) | |
739 | actual = re.sub(r'Total number.*', '', actual) | |
740 | actual = re.sub(r'Displayed.*', '', actual) | |
741 | # Remove IPv4 Unicast Summary (Title only) | |
742 | actual = re.sub(r'IPv4 Unicast Summary:', '', actual) | |
743 | # Remove IPv4 Multicast Summary (all of it) | |
744 | actual = re.sub(r'IPv4 Multicast Summary:', '', actual) | |
745 | actual = re.sub(r'No IPv4 Multicast neighbor is configured', '', actual) | |
746 | # Remove IPv4 VPN Summary (all of it) | |
747 | actual = re.sub(r'IPv4 VPN Summary:', '', actual) | |
748 | actual = re.sub(r'No IPv4 VPN neighbor is configured', '', actual) | |
749 | # Remove IPv4 Encap Summary (all of it) | |
750 | actual = re.sub(r'IPv4 Encap Summary:', '', actual) | |
751 | actual = re.sub(r'No IPv4 Encap neighbor is configured', '', actual) | |
752 | # Remove Unknown Summary (all of it) | |
753 | actual = re.sub(r'Unknown Summary:', '', actual) | |
754 | actual = re.sub(r'No Unknown neighbor is configured', '', actual) | |
8b2e59e9 DS |
755 | |
756 | actual = re.sub(r'IPv4 labeled-unicast Summary:', '', actual) | |
757 | actual = re.sub(r'No IPv4 labeled-unicast neighbor is configured', '', actual) | |
758 | ||
08fa1af7 MW |
759 | # Strip empty lines |
760 | actual = actual.lstrip() | |
761 | actual = actual.rstrip() | |
762 | # | |
4501fbca MW |
763 | # Fix newlines (make them all the same) |
764 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
765 | ||
766 | # Generate Diff | |
17070436 MW |
767 | diff = topotest.get_textdiff(actual, expected, |
768 | title1="actual SHOW IP BGP SUMMARY", | |
769 | title2="expected SHOW IP BGP SUMMARY") | |
4501fbca MW |
770 | |
771 | # Empty string if it matches, otherwise diff contains unified diff | |
772 | if diff: | |
08fa1af7 | 773 | sys.stderr.write('r%s failed SHOW IP BGP SUMMARY check:\n%s\n' % (i, diff)) |
4501fbca MW |
774 | failures += 1 |
775 | else: | |
776 | print("r%s ok" % i) | |
777 | ||
08fa1af7 | 778 | assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (i, diff) |
4501fbca | 779 | |
7e7fc73b MW |
780 | # Make sure that all daemons are running |
781 | for i in range(1, 2): | |
782 | fatal_error = net['r%s' % i].checkRouterRunning() | |
783 | assert fatal_error == "", fatal_error | |
784 | ||
4501fbca MW |
785 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
786 | # CLI(net) | |
787 | ||
788 | ||
789 | def test_bgp_ipv6_summary(): | |
790 | global fatal_error | |
791 | global net | |
792 | ||
793 | # Skip if previous fatal error condition is raised | |
794 | if (fatal_error != ""): | |
795 | pytest.skip(fatal_error) | |
796 | ||
797 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
798 | ||
b2764f90 | 799 | print("\n\n** Verifying BGP IPv6 Summary") |
4501fbca MW |
800 | print("******************************************\n") |
801 | failures = 0 | |
802 | for i in range(1, 2): | |
803 | refTableFile = '%s/r%s/show_bgp_ipv6_summary.ref' % (thisDir, i) | |
804 | if os.path.isfile(refTableFile): | |
805 | # Read expected result from file | |
806 | expected = open(refTableFile).read().rstrip() | |
807 | # Fix newlines (make them all the same) | |
808 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
809 | ||
810 | # Actual output from router | |
811 | actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null').rstrip() | |
812 | # Mask out "using XXiXX bytes" portion. They are random... | |
813 | actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) | |
814 | # Mask out "using XiXXX KiB" portion. They are random... | |
815 | actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) | |
08fa1af7 MW |
816 | # |
817 | # Remove extra summaries which exist with newer versions | |
818 | # | |
819 | # Remove summary lines (changed recently) | |
820 | actual = re.sub(r'Total number.*', '', actual) | |
821 | actual = re.sub(r'Displayed.*', '', actual) | |
822 | # Remove IPv4 Unicast Summary (Title only) | |
823 | actual = re.sub(r'IPv6 Unicast Summary:', '', actual) | |
824 | # Remove IPv4 Multicast Summary (all of it) | |
825 | actual = re.sub(r'IPv6 Multicast Summary:', '', actual) | |
826 | actual = re.sub(r'No IPv6 Multicast neighbor is configured', '', actual) | |
827 | # Remove IPv4 VPN Summary (all of it) | |
828 | actual = re.sub(r'IPv6 VPN Summary:', '', actual) | |
829 | actual = re.sub(r'No IPv6 VPN neighbor is configured', '', actual) | |
830 | # Remove IPv4 Encap Summary (all of it) | |
831 | actual = re.sub(r'IPv6 Encap Summary:', '', actual) | |
832 | actual = re.sub(r'No IPv6 Encap neighbor is configured', '', actual) | |
833 | # Remove Unknown Summary (all of it) | |
834 | actual = re.sub(r'Unknown Summary:', '', actual) | |
835 | actual = re.sub(r'No Unknown neighbor is configured', '', actual) | |
8b2e59e9 DS |
836 | |
837 | # Remove Labeled Unicast Summary (all of it) | |
838 | actual = re.sub(r'IPv6 labeled-unicast Summary:', '', actual) | |
839 | actual = re.sub(r'No IPv6 labeled-unicast neighbor is configured', '', actual) | |
840 | ||
08fa1af7 MW |
841 | # Strip empty lines |
842 | actual = actual.lstrip() | |
843 | actual = actual.rstrip() | |
844 | # | |
4501fbca MW |
845 | # Fix newlines (make them all the same) |
846 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
847 | ||
848 | # Generate Diff | |
17070436 MW |
849 | diff = topotest.get_textdiff(actual, expected, |
850 | title1="actual SHOW BGP IPv6 SUMMARY", | |
851 | title2="expected SHOW BGP IPv6 SUMMARY") | |
4501fbca MW |
852 | |
853 | # Empty string if it matches, otherwise diff contains unified diff | |
854 | if diff: | |
855 | sys.stderr.write('r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n' % (i, diff)) | |
856 | failures += 1 | |
857 | else: | |
858 | print("r%s ok" % i) | |
859 | ||
860 | assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (i, diff) | |
861 | ||
7e7fc73b MW |
862 | # Make sure that all daemons are running |
863 | for i in range(1, 2): | |
864 | fatal_error = net['r%s' % i].checkRouterRunning() | |
865 | assert fatal_error == "", fatal_error | |
866 | ||
4501fbca MW |
867 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
868 | # CLI(net) | |
869 | ||
870 | ||
871 | def test_bgp_ipv4(): | |
872 | global fatal_error | |
873 | global net | |
874 | ||
875 | # Skip if previous fatal error condition is raised | |
876 | if (fatal_error != ""): | |
877 | pytest.skip(fatal_error) | |
878 | ||
879 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
880 | ||
b2764f90 | 881 | print("\n\n** Verifying BGP IPv4") |
4501fbca | 882 | print("******************************************\n") |
6a57e103 | 883 | diffresult = {} |
4501fbca | 884 | for i in range(1, 2): |
6a57e103 PZ |
885 | success = 0 |
886 | for refTableFile in (glob.glob( | |
887 | '%s/r%s/show_bgp_ipv4*.ref' % (thisDir, i))): | |
888 | if os.path.isfile(refTableFile): | |
889 | # Read expected result from file | |
890 | expected = open(refTableFile).read().rstrip() | |
891 | # Fix newlines (make them all the same) | |
892 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
893 | ||
894 | # Actual output from router | |
895 | actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip() | |
896 | # Remove summary line (changed recently) | |
897 | actual = re.sub(r'Total number.*', '', actual) | |
898 | actual = re.sub(r'Displayed.*', '', actual) | |
899 | actual = actual.rstrip() | |
900 | # Fix newlines (make them all the same) | |
901 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
902 | ||
903 | # Generate Diff | |
904 | diff = topotest.get_textdiff(actual, expected, | |
905 | title1="actual SHOW BGP IPv4", | |
906 | title2="expected SHOW BGP IPv4") | |
907 | ||
908 | # Empty string if it matches, otherwise diff contains unified diff | |
909 | if diff: | |
910 | diffresult[refTableFile] = diff | |
911 | else: | |
912 | success = 1 | |
913 | print("template %s matched: r%s ok" % (refTableFile, i)) | |
914 | break | |
915 | ||
916 | if not success: | |
917 | resultstr = 'No template matched.\n' | |
918 | for f in diffresult.iterkeys(): | |
919 | resultstr += ( | |
920 | 'template %s: r%s failed SHOW BGP IPv4 check:\n%s\n' | |
921 | % (f, i, diffresult[f])) | |
922 | raise AssertionError( | |
923 | "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr)) | |
4501fbca | 924 | |
7e7fc73b MW |
925 | # Make sure that all daemons are running |
926 | for i in range(1, 2): | |
927 | fatal_error = net['r%s' % i].checkRouterRunning() | |
928 | assert fatal_error == "", fatal_error | |
929 | ||
4501fbca MW |
930 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
931 | # CLI(net) | |
932 | ||
933 | ||
934 | def test_bgp_ipv6(): | |
935 | global fatal_error | |
936 | global net | |
937 | ||
938 | # Skip if previous fatal error condition is raised | |
939 | if (fatal_error != ""): | |
940 | pytest.skip(fatal_error) | |
941 | ||
942 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
943 | ||
b2764f90 | 944 | print("\n\n** Verifying BGP IPv6") |
4501fbca | 945 | print("******************************************\n") |
6a57e103 | 946 | diffresult = {} |
4501fbca | 947 | for i in range(1, 2): |
6a57e103 PZ |
948 | success = 0 |
949 | for refTableFile in (glob.glob( | |
950 | '%s/r%s/show_bgp_ipv6*.ref' % (thisDir, i))): | |
951 | if os.path.isfile(refTableFile): | |
952 | # Read expected result from file | |
953 | expected = open(refTableFile).read().rstrip() | |
954 | # Fix newlines (make them all the same) | |
955 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
956 | ||
957 | # Actual output from router | |
958 | actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip() | |
959 | # Remove summary line (changed recently) | |
960 | actual = re.sub(r'Total number.*', '', actual) | |
961 | actual = re.sub(r'Displayed.*', '', actual) | |
962 | actual = actual.rstrip() | |
963 | # Fix newlines (make them all the same) | |
964 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
965 | ||
966 | # Generate Diff | |
967 | diff = topotest.get_textdiff(actual, expected, | |
968 | title1="actual SHOW BGP IPv6", | |
969 | title2="expected SHOW BGP IPv6") | |
970 | ||
971 | # Empty string if it matches, otherwise diff contains unified diff | |
972 | if diff: | |
973 | diffresult[refTableFile] = diff | |
974 | else: | |
975 | success = 1 | |
976 | print("template %s matched: r%s ok" % (refTableFile, i)) | |
977 | ||
978 | if not success: | |
979 | resultstr = 'No template matched.\n' | |
980 | for f in diffresult.iterkeys(): | |
981 | resultstr += ( | |
982 | 'template %s: r%s failed SHOW BGP IPv6 check:\n%s\n' | |
983 | % (f, i, diffresult[f])) | |
984 | raise AssertionError( | |
985 | "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr)) | |
4501fbca | 986 | |
7e7fc73b MW |
987 | # Make sure that all daemons are running |
988 | for i in range(1, 2): | |
989 | fatal_error = net['r%s' % i].checkRouterRunning() | |
990 | assert fatal_error == "", fatal_error | |
991 | ||
4501fbca MW |
992 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
993 | # CLI(net) | |
994 | ||
41fce07c DS |
995 | def test_route_map(): |
996 | global fatal_error | |
997 | global net | |
998 | ||
999 | if (fatal_error != ""): | |
1000 | pytest.skip(fatal_error) | |
1001 | ||
1002 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
1003 | ||
1004 | print("\n\n** Verifying some basic routemap forward references\n") | |
1005 | print("*******************************************************\n") | |
1006 | failures = 0 | |
1007 | for i in range(1, 2): | |
1008 | refroutemap = '%s/r%s/show_route_map.ref' % (thisDir, i) | |
1009 | if os.path.isfile(refroutemap): | |
1010 | expected = open(refroutemap).read().rstrip() | |
1011 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
1012 | ||
1013 | actual = net['r%s' %i].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip() | |
1014 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
1015 | ||
1016 | diff = topotest.get_textdiff(actual, expected, | |
1017 | title1="actual show route-map", | |
1018 | title2="expected show route-map") | |
1019 | ||
1020 | if diff: | |
1021 | sys.stderr.write('r%s failed show route-map command Check:\n%s\n' % (i, diff)) | |
1022 | failures += 1 | |
1023 | else: | |
1024 | print("r%s ok" %i) | |
4501fbca | 1025 | |
41fce07c | 1026 | assert failures == 0, "Show route-map command failed for router r%s:\n%s" % (i, diff) |
4501fbca | 1027 | |
887a232c SW |
1028 | def test_nexthop_groups_with_route_maps(): |
1029 | global fatal_error | |
1030 | global net | |
1031 | ||
1032 | # Skip if previous fatal error condition is raised | |
1033 | if (fatal_error != ""): | |
1034 | pytest.skip(fatal_error) | |
1035 | ||
1036 | print("\n\n** Verifying Nexthop Groups With Route-Maps") | |
1037 | print("******************************************\n") | |
1038 | ||
1039 | ### Nexthop Group With Route-Map Tests | |
1040 | ||
1041 | # Create a lib nexthop-group | |
1042 | net["r1"].cmd('vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') | |
1043 | ||
1044 | ## Route-Map Proto Source | |
1045 | ||
1046 | route_str = "2.2.2.1" | |
1047 | src_str = "192.168.0.1" | |
1048 | ||
1049 | net["r1"].cmd('vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str) | |
1050 | net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"') | |
1051 | ||
1052 | net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str) | |
1053 | ||
1054 | verify_route_nexthop_group("%s/32" % route_str) | |
1055 | ||
1056 | # Only a valid test on linux using nexthop objects | |
1057 | if sys.platform.startswith("linux"): | |
1058 | output = net["r1"].cmd('ip route show %s/32' % route_str) | |
1059 | match = re.search(r"src %s" % src_str, output) | |
1060 | assert match is not None, "Route %s/32 not installed with src %s" % (route_str, src_str) | |
1061 | ||
1062 | # Remove NHG routes and route-map | |
1063 | net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str) | |
1064 | net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"') | |
1065 | net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC permit 111" -c "set src %s"' % src_str) | |
1066 | net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"') | |
1067 | ||
1068 | ## Route-Map Deny/Permit with same nexthop group | |
1069 | ||
1070 | permit_route_str = "3.3.3.1" | |
1071 | deny_route_str = "3.3.3.2" | |
1072 | ||
1073 | net["r1"].cmd('vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str) | |
1074 | net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"') | |
1075 | net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"') | |
1076 | net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"') | |
1077 | ||
1078 | # This route should be permitted | |
1079 | net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str) | |
1080 | ||
1081 | verify_route_nexthop_group("%s/32" % permit_route_str) | |
1082 | ||
1083 | # This route should be denied | |
1084 | net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str) | |
1085 | ||
1086 | nhg_id = route_get_nhg_id(deny_route_str) | |
1087 | output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) | |
1088 | ||
1089 | match = re.search(r"Valid", output) | |
1090 | assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id | |
1091 | ||
1092 | match = re.search(r"Installed", output) | |
1093 | assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id | |
1094 | ||
1095 | # Remove NHG routes and route-map | |
1096 | net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str) | |
1097 | net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str) | |
1098 | net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"') | |
1099 | net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"') | |
1100 | net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"') | |
1101 | net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"') | |
1102 | net["r1"].cmd('vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str) | |
1103 | ||
4501fbca MW |
1104 | def test_mpls_interfaces(): |
1105 | global fatal_error | |
1106 | global net | |
1107 | ||
1108 | # Skip if previous fatal error condition is raised | |
1109 | if (fatal_error != ""): | |
1110 | pytest.skip(fatal_error) | |
1111 | ||
1112 | # Skip if no LDP installed or old kernel | |
1113 | if (net['r1'].daemon_available('ldpd') == False): | |
1114 | pytest.skip("No MPLS or kernel < 4.5") | |
1115 | ||
1116 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
1117 | ||
b2764f90 | 1118 | print("\n\n** Verifying MPLS Interfaces") |
4501fbca MW |
1119 | print("******************************************\n") |
1120 | failures = 0 | |
1121 | for i in range(1, 2): | |
1122 | refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' % (thisDir, i) | |
1123 | if os.path.isfile(refTableFile): | |
1124 | # Read expected result from file | |
1125 | expected = open(refTableFile).read().rstrip() | |
1126 | # Fix newlines (make them all the same) | |
1127 | expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) | |
1128 | ||
1129 | # Actual output from router | |
1130 | actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp interface" 2> /dev/null').rstrip() | |
1131 | # Mask out Timer in Uptime | |
1132 | actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual) | |
1133 | # Fix newlines (make them all the same) | |
1134 | actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) | |
1135 | ||
1136 | # Generate Diff | |
17070436 MW |
1137 | diff = topotest.get_textdiff(actual, expected, |
1138 | title1="actual MPLS LDP interface status", | |
1139 | title2="expected MPLS LDP interface status") | |
4501fbca MW |
1140 | |
1141 | # Empty string if it matches, otherwise diff contains unified diff | |
1142 | if diff: | |
1143 | sys.stderr.write('r%s failed MPLS LDP Interface status Check:\n%s\n' % (i, diff)) | |
1144 | failures += 1 | |
1145 | else: | |
1146 | print("r%s ok" % i) | |
1147 | ||
1148 | if failures>0: | |
1149 | fatal_error = "MPLS LDP Interface status failed" | |
1150 | ||
1151 | assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) | |
1152 | ||
7e7fc73b MW |
1153 | # Make sure that all daemons are running |
1154 | for i in range(1, 2): | |
1155 | fatal_error = net['r%s' % i].checkRouterRunning() | |
1156 | assert fatal_error == "", fatal_error | |
1157 | ||
4501fbca MW |
1158 | # For debugging after starting FRR/Quagga daemons, uncomment the next line |
1159 | # CLI(net) | |
1160 | ||
1161 | ||
1162 | def test_shutdown_check_stderr(): | |
1163 | global fatal_error | |
1164 | global net | |
1165 | ||
1166 | # Skip if previous fatal error condition is raised | |
1167 | if (fatal_error != ""): | |
1168 | pytest.skip(fatal_error) | |
1169 | ||
b2764f90 | 1170 | print("\n\n** Verifying unexpected STDERR output from daemons") |
4501fbca MW |
1171 | print("******************************************\n") |
1172 | ||
1173 | if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: | |
50c40bde MW |
1174 | print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") |
1175 | pytest.skip('Skipping test for Stderr output') | |
4501fbca MW |
1176 | |
1177 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
1178 | ||
50c40bde MW |
1179 | print("thisDir=" + thisDir) |
1180 | ||
4501fbca MW |
1181 | net['r1'].stopRouter() |
1182 | ||
1183 | log = net['r1'].getStdErr('ripd') | |
8e957dbb MW |
1184 | if log: |
1185 | print("\nRIPd StdErr Log:\n" + log) | |
4501fbca | 1186 | log = net['r1'].getStdErr('ripngd') |
8e957dbb MW |
1187 | if log: |
1188 | print("\nRIPngd StdErr Log:\n" + log) | |
4501fbca | 1189 | log = net['r1'].getStdErr('ospfd') |
8e957dbb MW |
1190 | if log: |
1191 | print("\nOSPFd StdErr Log:\n" + log) | |
4501fbca | 1192 | log = net['r1'].getStdErr('ospf6d') |
8e957dbb MW |
1193 | if log: |
1194 | print("\nOSPF6d StdErr Log:\n" + log) | |
4501fbca | 1195 | log = net['r1'].getStdErr('isisd') |
8e957dbb MW |
1196 | if log: |
1197 | print("\nISISd StdErr Log:\n" + log) | |
4501fbca | 1198 | log = net['r1'].getStdErr('bgpd') |
8e957dbb MW |
1199 | if log: |
1200 | print("\nBGPd StdErr Log:\n" + log) | |
af39fbe7 MS |
1201 | |
1202 | log = net['r1'].getStdErr('nhrpd') | |
1203 | if log: | |
1204 | print("\nNHRPd StdErr Log:\n" + log) | |
1205 | ||
1206 | log = net['r1'].getStdErr('pbrd') | |
1207 | if log: | |
1208 | print("\nPBRd StdErr Log:\n" + log) | |
1209 | ||
1210 | log = net['r1'].getStdErr('babeld') | |
1211 | if log: | |
1212 | print("\nBABELd StdErr Log:\n" + log) | |
1213 | ||
4501fbca MW |
1214 | if (net['r1'].daemon_available('ldpd')): |
1215 | log = net['r1'].getStdErr('ldpd') | |
8e957dbb MW |
1216 | if log: |
1217 | print("\nLDPd StdErr Log:\n" + log) | |
4501fbca | 1218 | log = net['r1'].getStdErr('zebra') |
8e957dbb MW |
1219 | if log: |
1220 | print("\nZebra StdErr Log:\n" + log) | |
4501fbca MW |
1221 | |
1222 | ||
50c40bde MW |
1223 | def test_shutdown_check_memleak(): |
1224 | global fatal_error | |
1225 | global net | |
1226 | ||
1227 | # Skip if previous fatal error condition is raised | |
1228 | if (fatal_error != ""): | |
1229 | pytest.skip(fatal_error) | |
1230 | ||
1231 | if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: | |
1232 | print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") | |
1233 | pytest.skip('Skipping test for memory leaks') | |
1234 | ||
1235 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
1236 | ||
1237 | for i in range(1, 2): | |
1238 | net['r%s' % i].stopRouter() | |
1239 | net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) | |
1240 | ||
1241 | ||
4501fbca MW |
1242 | if __name__ == '__main__': |
1243 | ||
1244 | setLogLevel('info') | |
1245 | # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli | |
1246 | # retval = pytest.main(["-s", "--tb=no"]) | |
1247 | retval = pytest.main(["-s"]) | |
1248 | sys.exit(retval) |