]>
Commit | Line | Data |
---|---|---|
d6df723b MW |
1 | #!/usr/bin/env python |
2 | ||
3 | # | |
4 | # test_rip_topo1.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_rip_topo1.py: Testing RIPv2 | |
27 | ||
28 | """ | |
29 | ||
30 | import os | |
31 | import re | |
32 | import sys | |
d6df723b MW |
33 | import pytest |
34 | from time import sleep | |
35 | ||
36 | from mininet.topo import Topo | |
37 | from mininet.net import Mininet | |
38 | from mininet.node import Node, OVSSwitch, Host | |
39 | from mininet.log import setLogLevel, info | |
40 | from mininet.cli import CLI | |
41 | from mininet.link import Intf | |
42 | ||
43 | from functools import partial | |
44 | ||
45 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
46 | from lib import topotest | |
47 | ||
48 | fatal_error = "" | |
49 | ||
50 | ||
51 | ##################################################### | |
52 | ## | |
53 | ## Network Topology Definition | |
54 | ## | |
55 | ##################################################### | |
56 | ||
787e7624 | 57 | |
d6df723b MW |
58 | class NetworkTopo(Topo): |
59 | "RIP Topology 1" | |
60 | ||
61 | def build(self, **_opts): | |
62 | ||
63 | # Setup Routers | |
64 | router = {} | |
65 | # | |
66 | # Setup Main Router | |
787e7624 | 67 | router[1] = topotest.addRouter(self, "r1") |
d6df723b MW |
68 | # |
69 | # Setup RIP Routers | |
70 | for i in range(2, 4): | |
787e7624 | 71 | router[i] = topotest.addRouter(self, "r%s" % i) |
d6df723b MW |
72 | # |
73 | # Setup Switches | |
74 | switch = {} | |
75 | # | |
76 | # On main router | |
77 | # First switch is for a dummy interface (for local network) | |
787e7624 | 78 | switch[1] = self.addSwitch("sw1", cls=topotest.LegacySwitch) |
79 | self.addLink(switch[1], router[1], intfName2="r1-eth0") | |
d6df723b MW |
80 | # |
81 | # Switches for RIP | |
82 | # switch 2 switch is for connection to RIP router | |
787e7624 | 83 | switch[2] = self.addSwitch("sw2", cls=topotest.LegacySwitch) |
84 | self.addLink(switch[2], router[1], intfName2="r1-eth1") | |
85 | self.addLink(switch[2], router[2], intfName2="r2-eth0") | |
d6df723b | 86 | # switch 3 is between RIP routers |
787e7624 | 87 | switch[3] = self.addSwitch("sw3", cls=topotest.LegacySwitch) |
88 | self.addLink(switch[3], router[2], intfName2="r2-eth1") | |
89 | self.addLink(switch[3], router[3], intfName2="r3-eth1") | |
d6df723b | 90 | # switch 4 is stub on remote RIP router |
787e7624 | 91 | switch[4] = self.addSwitch("sw4", cls=topotest.LegacySwitch) |
92 | self.addLink(switch[4], router[3], intfName2="r3-eth0") | |
d6df723b | 93 | |
11761ab0 MS |
94 | switch[5] = self.addSwitch("sw5", cls=topotest.LegacySwitch) |
95 | self.addLink(switch[5], router[1], intfName2="r1-eth2") | |
cfe9a587 | 96 | |
11761ab0 MS |
97 | switch[6] = self.addSwitch("sw6", cls=topotest.LegacySwitch) |
98 | self.addLink(switch[6], router[1], intfName2="r1-eth3") | |
cfe9a587 | 99 | |
d6df723b MW |
100 | |
101 | ##################################################### | |
102 | ## | |
103 | ## Tests starting | |
104 | ## | |
105 | ##################################################### | |
106 | ||
787e7624 | 107 | |
d6df723b MW |
108 | def setup_module(module): |
109 | global topo, net | |
110 | ||
111 | print("\n\n** %s: Setup Topology" % module.__name__) | |
112 | print("******************************************\n") | |
113 | ||
114 | print("Cleanup old Mininet runs") | |
787e7624 | 115 | os.system("sudo mn -c > /dev/null 2>&1") |
d6df723b MW |
116 | |
117 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
118 | topo = NetworkTopo() | |
119 | ||
120 | net = Mininet(controller=None, topo=topo) | |
121 | net.start() | |
122 | ||
123 | # Starting Routers | |
124 | # | |
125 | for i in range(1, 4): | |
787e7624 | 126 | net["r%s" % i].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir, i)) |
127 | net["r%s" % i].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir, i)) | |
128 | net["r%s" % i].startRouter() | |
d6df723b | 129 | |
622c4996 | 130 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
131 | # CLI(net) |
132 | ||
133 | ||
134 | def teardown_module(module): | |
135 | global net | |
136 | ||
137 | print("\n\n** %s: Shutdown Topology" % module.__name__) | |
138 | print("******************************************\n") | |
139 | ||
140 | # End - Shutdown network | |
141 | net.stop() | |
142 | ||
143 | ||
144 | def test_router_running(): | |
145 | global fatal_error | |
146 | global net | |
147 | ||
148 | # Skip if previous fatal error condition is raised | |
787e7624 | 149 | if fatal_error != "": |
d6df723b MW |
150 | pytest.skip(fatal_error) |
151 | ||
622c4996 | 152 | print("\n\n** Check if FRR is running on each Router node") |
d6df723b | 153 | print("******************************************\n") |
d6df723b | 154 | |
28aa9ae6 | 155 | # Make sure that all daemons are running |
d6df723b | 156 | for i in range(1, 4): |
787e7624 | 157 | fatal_error = net["r%s" % i].checkRouterRunning() |
d6df723b MW |
158 | assert fatal_error == "", fatal_error |
159 | ||
622c4996 | 160 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
161 | # CLI(net) |
162 | ||
163 | ||
164 | def test_converge_protocols(): | |
165 | global fatal_error | |
166 | global net | |
167 | ||
168 | # Skip if previous fatal error condition is raised | |
787e7624 | 169 | if fatal_error != "": |
d6df723b MW |
170 | pytest.skip(fatal_error) |
171 | ||
172 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
173 | ||
174 | print("\n\n** Waiting for protocols convergence") | |
175 | print("******************************************\n") | |
176 | ||
b01c46b9 DS |
177 | # Not really implemented yet - just sleep 11 secs for now |
178 | sleep(11) | |
d6df723b | 179 | |
28aa9ae6 MW |
180 | # Make sure that all daemons are still running |
181 | for i in range(1, 4): | |
787e7624 | 182 | fatal_error = net["r%s" % i].checkRouterRunning() |
28aa9ae6 MW |
183 | assert fatal_error == "", fatal_error |
184 | ||
622c4996 | 185 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
186 | # CLI(net) |
187 | ||
188 | ||
189 | def test_rip_status(): | |
190 | global fatal_error | |
191 | global net | |
192 | ||
193 | # Skip if previous fatal error condition is raised | |
787e7624 | 194 | if fatal_error != "": |
d6df723b MW |
195 | pytest.skip(fatal_error) |
196 | ||
197 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
198 | ||
199 | # Verify RIP Status | |
200 | print("\n\n** Verifing RIP status") | |
201 | print("******************************************\n") | |
202 | failures = 0 | |
203 | for i in range(1, 4): | |
787e7624 | 204 | refTableFile = "%s/r%s/rip_status.ref" % (thisDir, i) |
d6df723b MW |
205 | if os.path.isfile(refTableFile): |
206 | # Read expected result from file | |
207 | expected = open(refTableFile).read().rstrip() | |
208 | # Fix newlines (make them all the same) | |
787e7624 | 209 | expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
210 | |
211 | # Actual output from router | |
787e7624 | 212 | actual = ( |
213 | net["r%s" % i] | |
214 | .cmd('vtysh -c "show ip rip status" 2> /dev/null') | |
215 | .rstrip() | |
216 | ) | |
217 | # Drop time in next due | |
d6df723b MW |
218 | actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) |
219 | # Drop time in last update | |
220 | actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) | |
221 | # Fix newlines (make them all the same) | |
787e7624 | 222 | actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
223 | |
224 | # Generate Diff | |
787e7624 | 225 | diff = topotest.get_textdiff( |
226 | actual, | |
227 | expected, | |
17070436 | 228 | title1="actual IP RIP status", |
787e7624 | 229 | title2="expected IP RIP status", |
230 | ) | |
d6df723b MW |
231 | |
232 | # Empty string if it matches, otherwise diff contains unified diff | |
233 | if diff: | |
787e7624 | 234 | sys.stderr.write("r%s failed IP RIP status check:\n%s\n" % (i, diff)) |
d6df723b MW |
235 | failures += 1 |
236 | else: | |
237 | print("r%s ok" % i) | |
238 | ||
239 | assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) | |
240 | ||
28aa9ae6 MW |
241 | # Make sure that all daemons are still running |
242 | for i in range(1, 4): | |
787e7624 | 243 | fatal_error = net["r%s" % i].checkRouterRunning() |
28aa9ae6 MW |
244 | assert fatal_error == "", fatal_error |
245 | ||
622c4996 | 246 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
247 | # CLI(net) |
248 | ||
249 | ||
250 | def test_rip_routes(): | |
251 | global fatal_error | |
252 | global net | |
253 | ||
254 | # Skip if previous fatal error condition is raised | |
787e7624 | 255 | if fatal_error != "": |
d6df723b MW |
256 | pytest.skip(fatal_error) |
257 | ||
258 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
259 | ||
260 | # Verify RIP Status | |
261 | print("\n\n** Verifing RIP routes") | |
262 | print("******************************************\n") | |
263 | failures = 0 | |
264 | for i in range(1, 4): | |
787e7624 | 265 | refTableFile = "%s/r%s/show_ip_rip.ref" % (thisDir, i) |
d6df723b MW |
266 | if os.path.isfile(refTableFile): |
267 | # Read expected result from file | |
268 | expected = open(refTableFile).read().rstrip() | |
269 | # Fix newlines (make them all the same) | |
787e7624 | 270 | expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
271 | |
272 | # Actual output from router | |
787e7624 | 273 | actual = net["r%s" % i].cmd('vtysh -c "show ip rip" 2> /dev/null').rstrip() |
d6df723b MW |
274 | # Drop Time |
275 | actual = re.sub(r"[0-9][0-9]:[0-5][0-9]", "XX:XX", actual) | |
276 | # Fix newlines (make them all the same) | |
787e7624 | 277 | actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
278 | |
279 | # Generate Diff | |
787e7624 | 280 | diff = topotest.get_textdiff( |
281 | actual, | |
282 | expected, | |
17070436 | 283 | title1="actual SHOW IP RIP", |
787e7624 | 284 | title2="expected SHOW IP RIP", |
285 | ) | |
d6df723b MW |
286 | |
287 | # Empty string if it matches, otherwise diff contains unified diff | |
288 | if diff: | |
787e7624 | 289 | sys.stderr.write("r%s failed SHOW IP RIP check:\n%s\n" % (i, diff)) |
d6df723b MW |
290 | failures += 1 |
291 | else: | |
292 | print("r%s ok" % i) | |
293 | ||
294 | assert failures == 0, "SHOW IP RIP failed for router r%s:\n%s" % (i, diff) | |
295 | ||
28aa9ae6 MW |
296 | # Make sure that all daemons are still running |
297 | for i in range(1, 4): | |
787e7624 | 298 | fatal_error = net["r%s" % i].checkRouterRunning() |
28aa9ae6 MW |
299 | assert fatal_error == "", fatal_error |
300 | ||
622c4996 | 301 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
302 | # CLI(net) |
303 | ||
304 | ||
305 | def test_zebra_ipv4_routingTable(): | |
306 | global fatal_error | |
307 | global net | |
308 | ||
309 | # Skip if previous fatal error condition is raised | |
787e7624 | 310 | if fatal_error != "": |
d6df723b MW |
311 | pytest.skip(fatal_error) |
312 | ||
313 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
314 | ||
315 | # Verify OSPFv3 Routing Table | |
316 | print("\n\n** Verifing Zebra IPv4 Routing Table") | |
317 | print("******************************************\n") | |
318 | failures = 0 | |
319 | for i in range(1, 4): | |
787e7624 | 320 | refTableFile = "%s/r%s/show_ip_route.ref" % (thisDir, i) |
d6df723b MW |
321 | if os.path.isfile(refTableFile): |
322 | # Read expected result from file | |
323 | expected = open(refTableFile).read().rstrip() | |
324 | # Fix newlines (make them all the same) | |
787e7624 | 325 | expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
326 | |
327 | # Actual output from router | |
787e7624 | 328 | actual = ( |
329 | net["r%s" % i] | |
330 | .cmd('vtysh -c "show ip route" 2> /dev/null | grep "^R"') | |
331 | .rstrip() | |
332 | ) | |
622c4996 | 333 | # Drop timers on end of line |
d6df723b MW |
334 | actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) |
335 | # Fix newlines (make them all the same) | |
787e7624 | 336 | actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) |
d6df723b MW |
337 | |
338 | # Generate Diff | |
787e7624 | 339 | diff = topotest.get_textdiff( |
340 | actual, | |
341 | expected, | |
17070436 | 342 | title1="actual Zebra IPv4 routing table", |
787e7624 | 343 | title2="expected Zebra IPv4 routing table", |
344 | ) | |
d6df723b MW |
345 | |
346 | # Empty string if it matches, otherwise diff contains unified diff | |
347 | if diff: | |
787e7624 | 348 | sys.stderr.write( |
349 | "r%s failed Zebra IPv4 Routing Table Check:\n%s\n" % (i, diff) | |
350 | ) | |
d6df723b MW |
351 | failures += 1 |
352 | else: | |
353 | print("r%s ok" % i) | |
354 | ||
787e7624 | 355 | assert failures == 0, ( |
356 | "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" | |
357 | % (i, diff) | |
358 | ) | |
d6df723b | 359 | |
28aa9ae6 MW |
360 | # Make sure that all daemons are still running |
361 | for i in range(1, 4): | |
787e7624 | 362 | fatal_error = net["r%s" % i].checkRouterRunning() |
28aa9ae6 MW |
363 | assert fatal_error == "", fatal_error |
364 | ||
622c4996 | 365 | # For debugging after starting FRR daemons, uncomment the next line |
d6df723b MW |
366 | # CLI(net) |
367 | ||
368 | ||
369 | def test_shutdown_check_stderr(): | |
370 | global fatal_error | |
371 | global net | |
372 | ||
373 | # Skip if previous fatal error condition is raised | |
787e7624 | 374 | if fatal_error != "": |
d6df723b MW |
375 | pytest.skip(fatal_error) |
376 | ||
787e7624 | 377 | if os.environ.get("TOPOTESTS_CHECK_STDERR") is None: |
378 | pytest.skip("Skipping test for Stderr output and memory leaks") | |
d6df723b MW |
379 | |
380 | thisDir = os.path.dirname(os.path.realpath(__file__)) | |
381 | ||
382 | print("\n\n** Verifing unexpected STDERR output from daemons") | |
383 | print("******************************************\n") | |
384 | ||
787e7624 | 385 | net["r1"].stopRouter() |
d6df723b | 386 | |
787e7624 | 387 | log = net["r1"].getStdErr("ripd") |
8e957dbb MW |
388 | if log: |
389 | print("\nRIPd StdErr Log:\n" + log) | |
787e7624 | 390 | log = net["r1"].getStdErr("zebra") |
8e957dbb MW |
391 | if log: |
392 | print("\nZebra StdErr Log:\n" + log) | |
d6df723b MW |
393 | |
394 | ||
787e7624 | 395 | if __name__ == "__main__": |
d6df723b | 396 | |
787e7624 | 397 | setLogLevel("info") |
d6df723b MW |
398 | # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli |
399 | # retval = pytest.main(["-s", "--tb=no"]) | |
400 | retval = pytest.main(["-s"]) | |
401 | sys.exit(retval) |