]>
Commit | Line | Data |
---|---|---|
4256a209 | 1 | #!/usr/bin/python |
2 | ||
3 | # | |
4 | # Copyright (c) 2020 by VMware, Inc. ("VMware") | |
5 | # Used Copyright (c) 2018 by Network Device Education Foundation, Inc. | |
6 | # ("NetDEF") in this file. | |
7 | # | |
8 | # Permission to use, copy, modify, and/or distribute this software | |
9 | # for any purpose with or without fee is hereby granted, provided | |
10 | # that the above copyright notice and this permission notice appear | |
11 | # in all copies. | |
12 | # | |
13 | # THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES | |
14 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR | |
16 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | |
17 | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
19 | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
20 | # OF THIS SOFTWARE. | |
21 | # | |
22 | ||
23 | ||
24 | """OSPF Basic Functionality Automation.""" | |
25 | import os | |
26 | import sys | |
27 | import time | |
28 | import pytest | |
4256a209 | 29 | from time import sleep |
4256a209 | 30 | |
31 | # Save the Current Working Directory to find configuration files. | |
32 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
33 | sys.path.append(os.path.join(CWD, "../")) | |
34 | sys.path.append(os.path.join(CWD, "../lib/")) | |
35 | ||
36 | # pylint: disable=C0413 | |
37 | # Import topogen and topotest helpers | |
4256a209 | 38 | from lib.topogen import Topogen, get_topogen |
4256a209 | 39 | |
40 | # Import topoJson from lib, to create topology and initial configuration | |
41 | from lib.common_config import ( | |
42 | start_topology, | |
43 | write_test_header, | |
44 | write_test_footer, | |
45 | reset_config_on_routers, | |
46 | verify_rib, | |
47 | create_static_routes, | |
48 | step, | |
4256a209 | 49 | shutdown_bringup_interface, |
701a0192 | 50 | topo_daemons, |
4256a209 | 51 | ) |
52 | from lib.topolog import logger | |
53 | ||
4953ca97 | 54 | from lib.topojson import build_config_from_json |
4256a209 | 55 | from lib.ospf import ( |
56 | verify_ospf_neighbor, | |
57 | config_ospf_interface, | |
4256a209 | 58 | verify_ospf_rib, |
88b7d3e7 | 59 | redistribute_ospf, |
4256a209 | 60 | ) |
61 | ||
6ff492b1 DS |
62 | pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] |
63 | ||
64 | ||
4256a209 | 65 | topo = None |
66 | ||
4256a209 | 67 | |
68 | # Global variables | |
69 | NETWORK = { | |
70 | "ipv4": [ | |
71 | "11.0.20.1/32", | |
72 | "11.0.20.2/32", | |
73 | "11.0.20.3/32", | |
74 | "11.0.20.4/32", | |
75 | "11.0.20.5/32", | |
76 | ] | |
77 | } | |
78 | """ | |
79 | TOPOLOGY : | |
80 | Please view in a fixed-width font such as Courier. | |
81 | +---+ A1 +---+ | |
82 | +R1 +------------+R2 | | |
83 | +-+-+- +--++ | |
84 | | -- -- | | |
85 | | -- A0 -- | | |
86 | A0| ---- | | |
87 | | ---- | A2 | |
88 | | -- -- | | |
89 | | -- -- | | |
90 | +-+-+- +-+-+ | |
91 | +R0 +-------------+R3 | | |
92 | +---+ A3 +---+ | |
93 | ||
94 | TESTCASES : | |
95 | 1. Verify OSPF ECMP with max path configured as 8 (ECMPconfigured at FRR level) | |
96 | 2. Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports) | |
97 | """ | |
98 | ||
99 | ||
4256a209 | 100 | def setup_module(mod): |
101 | """ | |
102 | Sets up the pytest environment | |
103 | ||
104 | * `mod`: module name | |
105 | """ | |
4256a209 | 106 | testsuite_run_time = time.asctime(time.localtime(time.time())) |
107 | logger.info("Testsuite start time: {}".format(testsuite_run_time)) | |
108 | logger.info("=" * 40) | |
109 | ||
110 | logger.info("Running setup_module to create topology") | |
111 | ||
112 | # This function initiates the topology build with Topogen... | |
e82b531d CH |
113 | json_file = "{}/ospf_ecmp.json".format(CWD) |
114 | tgen = Topogen(json_file, mod.__name__) | |
115 | global topo | |
116 | topo = tgen.json_topo | |
4256a209 | 117 | # ... and here it calls Mininet initialization functions. |
118 | ||
035267a3 | 119 | # get list of daemons needs to be started for this suite. |
120 | daemons = topo_daemons(tgen, topo) | |
121 | ||
4256a209 | 122 | # Starting topology, create tmp files which are loaded to routers |
d60a3f0e | 123 | # to start daemons and then start routers |
035267a3 | 124 | start_topology(tgen, daemons) |
4256a209 | 125 | |
126 | # Creating configuration from JSON | |
127 | build_config_from_json(tgen, topo) | |
128 | ||
129 | # Don't run this test if we have any failure. | |
130 | if tgen.routers_have_failure(): | |
131 | pytest.skip(tgen.errors) | |
132 | # Api call verify whether OSPF is converged | |
133 | ospf_covergence = verify_ospf_neighbor(tgen, topo) | |
134 | assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( | |
135 | ospf_covergence | |
136 | ) | |
137 | ||
138 | logger.info("Running setup_module() done") | |
139 | ||
140 | ||
141 | def teardown_module(mod): | |
142 | """ | |
143 | Teardown the pytest environment. | |
144 | ||
145 | * `mod`: module name | |
146 | """ | |
147 | ||
148 | logger.info("Running teardown_module to delete topology") | |
149 | ||
150 | tgen = get_topogen() | |
151 | ||
152 | # Stop toplogy and Remove tmp files | |
153 | tgen.stop_topology() | |
154 | ||
155 | logger.info( | |
156 | "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) | |
157 | ) | |
158 | logger.info("=" * 40) | |
159 | ||
160 | ||
4256a209 | 161 | # ################################## |
162 | # Test cases start here. | |
163 | # ################################## | |
164 | ||
165 | ||
166 | def test_ospf_ecmp_tc16_p0(request): | |
167 | """ | |
168 | Verify OSPF ECMP. | |
169 | ||
170 | Verify OSPF ECMP with max path configured as 8 (ECMP | |
171 | configured at FRR level) | |
172 | """ | |
173 | tc_name = request.node.name | |
174 | write_test_header(tc_name) | |
175 | tgen = get_topogen() | |
176 | ||
177 | # Don't run this test if we have any failure. | |
178 | if tgen.routers_have_failure(): | |
179 | pytest.skip(tgen.errors) | |
180 | ||
181 | global topo | |
182 | step("Bring up the base config as per the topology") | |
183 | step("Configure 8 interfaces between R1 and R2 and enable ospf in area 0.") | |
184 | reset_config_on_routers(tgen) | |
185 | step("Verify that OSPF is up with 8 neighborship sessions.") | |
186 | dut = "r1" | |
187 | ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) | |
188 | assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( | |
189 | ospf_covergence | |
190 | ) | |
191 | ||
192 | step("Configure a static route in R0 and redistribute in OSPF.") | |
193 | ||
194 | input_dict = { | |
195 | "r0": { | |
196 | "static_routes": [ | |
9fa6ec14 | 197 | { |
198 | "network": NETWORK["ipv4"][0], | |
199 | "no_of_ip": 5, | |
200 | "next_hop": "Null0", | |
201 | } | |
4256a209 | 202 | ] |
203 | } | |
204 | } | |
205 | result = create_static_routes(tgen, input_dict) | |
206 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
207 | ||
208 | dut = "r0" | |
88b7d3e7 | 209 | redistribute_ospf(tgen, topo, dut, "static") |
4256a209 | 210 | |
211 | step("Verify that route in R2 in stalled with 8 next hops.") | |
212 | nh = [] | |
213 | for item in range(1, 7): | |
214 | nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]) | |
215 | ||
216 | nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] | |
217 | ||
218 | nh.append(nh2) | |
219 | ||
220 | dut = "r1" | |
221 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
222 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
223 | ||
224 | protocol = "ospf" | |
225 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
226 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
227 | ||
228 | step("shut no shut all the interfaces on the remote router - R2") | |
229 | dut = "r1" | |
230 | for intfr in range(1, 7): | |
231 | intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] | |
232 | shutdown_bringup_interface(tgen, dut, intf, False) | |
233 | ||
234 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) | |
0b25370e DS |
235 | assert ( |
236 | result is not True | |
237 | ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( | |
4256a209 | 238 | tc_name, result |
0b25370e | 239 | ) |
4256a209 | 240 | |
241 | protocol = "ospf" | |
242 | result = verify_rib( | |
243 | tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False | |
244 | ) | |
0b25370e DS |
245 | assert ( |
246 | result is not True | |
247 | ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( | |
4256a209 | 248 | tc_name, result |
0b25370e | 249 | ) |
4256a209 | 250 | |
251 | for intfr in range(1, 7): | |
252 | intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] | |
253 | shutdown_bringup_interface(tgen, dut, intf, True) | |
254 | ||
255 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
256 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
257 | ||
258 | protocol = "ospf" | |
259 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
260 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
261 | ||
262 | step("shut no shut on all the interfaces on DUT (r1)") | |
263 | for intfr in range(1, 7): | |
264 | intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] | |
265 | shutdown_bringup_interface(tgen, dut, intf, False) | |
266 | ||
267 | for intfr in range(1, 7): | |
268 | intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] | |
269 | shutdown_bringup_interface(tgen, dut, intf, True) | |
270 | ||
271 | step( | |
272 | "Verify that all the neighbours are up and routes are installed" | |
273 | " with 8 next hop in ospf and ip route tables on R1." | |
274 | ) | |
275 | ||
276 | step("Verify that OSPF is up with 8 neighborship sessions.") | |
277 | dut = "r1" | |
278 | ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) | |
279 | assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( | |
280 | ospf_covergence | |
281 | ) | |
282 | ||
283 | dut = "r1" | |
284 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
285 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
286 | ||
287 | protocol = "ospf" | |
288 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
289 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
290 | ||
291 | step(" Un configure static route on R0") | |
292 | ||
293 | dut = "r0" | |
88b7d3e7 | 294 | redistribute_ospf(tgen, topo, dut, "static", delete=True) |
4256a209 | 295 | |
296 | # Wait for R0 to flush external LSAs. | |
297 | sleep(10) | |
298 | ||
299 | step("Verify that route is withdrawn from R2.") | |
300 | dut = "r1" | |
301 | result = verify_ospf_rib( | |
ed776e38 | 302 | tgen, dut, input_dict, next_hop=nh, retry_timeout=10, expected=False |
4256a209 | 303 | ) |
0b25370e DS |
304 | assert ( |
305 | result is not True | |
306 | ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( | |
4256a209 | 307 | tc_name, result |
0b25370e | 308 | ) |
4256a209 | 309 | |
310 | protocol = "ospf" | |
a81774ec | 311 | result = verify_rib( |
312 | tgen, | |
313 | "ipv4", | |
314 | dut, | |
315 | input_dict, | |
316 | protocol=protocol, | |
317 | next_hop=nh, | |
ed776e38 | 318 | retry_timeout=10, |
a81774ec | 319 | expected=False, |
320 | ) | |
0b25370e DS |
321 | assert ( |
322 | result is not True | |
323 | ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( | |
4256a209 | 324 | tc_name, result |
0b25370e | 325 | ) |
4256a209 | 326 | |
327 | step("Re configure the static route in R0.") | |
328 | dut = "r0" | |
88b7d3e7 | 329 | redistribute_ospf(tgen, topo, dut, "static") |
4256a209 | 330 | |
331 | dut = "r1" | |
332 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
333 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
334 | ||
335 | protocol = "ospf" | |
336 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
337 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
338 | ||
339 | write_test_footer(tc_name) | |
340 | ||
341 | ||
342 | def test_ospf_ecmp_tc17_p0(request): | |
343 | """ | |
344 | Verify OSPF ECMP. | |
345 | ||
346 | Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports) | |
347 | """ | |
348 | tc_name = request.node.name | |
349 | write_test_header(tc_name) | |
350 | tgen = get_topogen() | |
351 | ||
352 | # Don't run this test if we have any failure. | |
353 | if tgen.routers_have_failure(): | |
354 | pytest.skip(tgen.errors) | |
355 | ||
356 | global topo | |
357 | step("Bring up the base config as per the topology") | |
358 | step("Configure 2 interfaces between R1 and R2 & enable ospf in area 0.") | |
359 | reset_config_on_routers(tgen) | |
360 | step("Verify that OSPF is up with 2 neighborship sessions.") | |
361 | dut = "r1" | |
362 | ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) | |
363 | assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( | |
364 | ospf_covergence | |
365 | ) | |
366 | ||
367 | step("Configure a static route in R0 and redistribute in OSPF.") | |
368 | ||
369 | input_dict = { | |
370 | "r0": { | |
371 | "static_routes": [ | |
9fa6ec14 | 372 | { |
373 | "network": NETWORK["ipv4"][0], | |
374 | "no_of_ip": 5, | |
375 | "next_hop": "Null0", | |
376 | } | |
4256a209 | 377 | ] |
378 | } | |
379 | } | |
380 | result = create_static_routes(tgen, input_dict) | |
381 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
382 | ||
383 | dut = "r0" | |
88b7d3e7 | 384 | redistribute_ospf(tgen, topo, dut, "static") |
4256a209 | 385 | |
386 | step("Verify that route in R2 in stalled with 2 next hops.") | |
387 | ||
388 | nh1 = topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0] | |
389 | nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] | |
390 | nh = [nh1, nh2] | |
391 | ||
392 | dut = "r1" | |
393 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
394 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
395 | ||
396 | protocol = "ospf" | |
397 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
398 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
399 | ||
400 | step(" Un configure static route on R0") | |
401 | ||
402 | dut = "r0" | |
88b7d3e7 | 403 | redistribute_ospf(tgen, topo, dut, "static", delete=True) |
4256a209 | 404 | # sleep till the route gets withdrawn |
405 | sleep(10) | |
406 | ||
407 | step("Verify that route is withdrawn from R2.") | |
408 | dut = "r1" | |
a81774ec | 409 | result = verify_ospf_rib( |
ed776e38 | 410 | tgen, dut, input_dict, next_hop=nh, retry_timeout=10, expected=False |
a81774ec | 411 | ) |
0b25370e DS |
412 | assert ( |
413 | result is not True | |
414 | ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( | |
4256a209 | 415 | tc_name, result |
0b25370e | 416 | ) |
4256a209 | 417 | |
418 | protocol = "ospf" | |
a81774ec | 419 | result = verify_rib( |
420 | tgen, | |
421 | "ipv4", | |
422 | dut, | |
423 | input_dict, | |
424 | protocol=protocol, | |
425 | next_hop=nh, | |
ed776e38 | 426 | retry_timeout=10, |
a81774ec | 427 | expected=False, |
428 | ) | |
0b25370e DS |
429 | assert ( |
430 | result is not True | |
431 | ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( | |
4256a209 | 432 | tc_name, result |
0b25370e | 433 | ) |
4256a209 | 434 | |
435 | step("Reconfigure the static route in R0.Change ECMP value to 2.") | |
436 | dut = "r0" | |
88b7d3e7 | 437 | redistribute_ospf(tgen, topo, dut, "static") |
4256a209 | 438 | |
439 | step("Configure cost on R0 as 100") | |
440 | r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}} | |
441 | result = config_ospf_interface(tgen, topo, r0_ospf_cost) | |
442 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
443 | ||
444 | dut = "r1" | |
445 | result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) | |
446 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
447 | ||
448 | protocol = "ospf" | |
449 | result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) | |
450 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
451 | ||
452 | write_test_footer(tc_name) | |
453 | ||
454 | ||
455 | if __name__ == "__main__": | |
456 | args = ["-s"] + sys.argv[1:] | |
457 | sys.exit(pytest.main(args)) |