]>
Commit | Line | Data |
---|---|---|
40c28c86 | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: ISC |
40c28c86 | 3 | |
4 | # | |
5 | # Copyright (c) 2020 by VMware, Inc. ("VMware") | |
6 | # Used Copyright (c) 2018 by Network Device Education Foundation, | |
7 | # Inc. ("NetDEF") in this file. | |
8 | # | |
40c28c86 | 9 | |
10 | """ | |
11 | Following tests are covered to test multicast pim sm: | |
12 | ||
13 | Test steps | |
14 | - Create topology (setup module) | |
15 | - Bring up topology | |
16 | ||
17 | Following tests are covered: | |
18 | 1. Verify mroutes when transit router present between RP and Source DR | |
19 | """ | |
20 | ||
21 | import os | |
22 | import sys | |
23 | import json | |
24 | import time | |
25 | import datetime | |
26 | from time import sleep | |
27 | import pytest | |
28 | ||
29 | # Save the Current Working Directory to find configuration files. | |
30 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
31 | sys.path.append(os.path.join(CWD, "../")) | |
32 | sys.path.append(os.path.join(CWD, "../lib/")) | |
33 | ||
34 | # Required to instantiate the topology builder class. | |
35 | ||
36 | # pylint: disable=C0413 | |
37 | # Import topogen and topotest helpers | |
38 | from lib.topogen import Topogen, get_topogen | |
39 | ||
40 | from lib.common_config import ( | |
41 | start_topology, | |
42 | write_test_header, | |
43 | write_test_footer, | |
44 | step, | |
45 | reset_config_on_routers, | |
46 | apply_raw_config, | |
47 | add_interfaces_to_vlan, | |
48 | check_router_status, | |
49 | topo_daemons, | |
50 | required_linux_kernel_version, | |
51 | ) | |
52 | from lib.pim import ( | |
53 | create_pim_config, | |
54 | create_igmp_config, | |
4fafd29f KK |
55 | verify_mroutes, |
56 | clear_mroute, | |
57 | clear_pim_interface_traffic, | |
40c28c86 | 58 | verify_pim_config, |
59 | verify_upstream_iif, | |
60 | verify_multicast_traffic, | |
61 | McastTesterHelper, | |
62 | ) | |
63 | from lib.topolog import logger | |
64 | from lib.topojson import build_config_from_json | |
65 | ||
66 | HELLO_TIMER = 1 | |
67 | HOLD_TIMER = 3 | |
68 | ||
69 | pytestmark = [pytest.mark.pimd] | |
70 | ||
71 | TOPOLOGY = """ | |
72 | ||
73 | Descripton: Configuring OSPF on r1/r2/r4/r5/r6 for RP reachablility, We have r6 as a transit router between | |
74 | r1/r2 and r4. | |
75 | IPs are assigned automatically to routers, start IP and subnet is defined in respective JSON file | |
76 | JSON snippet: | |
77 | "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24}, | |
78 | ||
79 | r5 ------- i2 | |
80 | 10.0.3.2/24| 10.0.0.2/24 | |
81 | | | |
82 | 10.0.3.1/24| | |
83 | r4 | |
84 | |10.0.4.1/24 | |
85 | | | |
86 | 10.0.4.2/24| | |
87 | ------------ r6 ---------- | |
88 | | 10.0.1.2/24 10.0.2.2/24 | | |
89 | 10.0.1.1/24 | | 10.0.2.1/24 | |
90 | r1 ----------- s1 ---------- r2 | |
91 | 10.0.5.2/24 | 10.0.5.3/24 | |
92 | | | |
93 | |10.0.5.1/24 | |
94 | i1 | |
95 | ||
96 | ||
97 | ||
98 | Description: | |
99 | i1, i2 - FRR running iperf to send IGMP | |
100 | join and traffic | |
101 | r1, r2, r4, r5, r6 - FRR ruter | |
102 | s1 - OVS switch | |
103 | """ | |
104 | ||
105 | # Global variables | |
106 | VLAN_1 = 2501 | |
107 | GROUP_RANGE = "225.0.0.0/8" | |
108 | IGMP_JOIN = "225.1.1.1" | |
109 | VLAN_INTF_ADRESS_1 = "10.0.8.3/24" | |
110 | SAME_VLAN_IP_1 = {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"} | |
111 | SAME_VLAN_IP_2 = {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"} | |
112 | SAME_VLAN_IP_3 = {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"} | |
113 | SAME_VLAN_IP_4 = {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"} | |
114 | GROUP_RANGE_1 = [ | |
115 | "225.1.1.1/32", | |
116 | "225.1.1.2/32", | |
117 | "225.1.1.3/32", | |
118 | "225.1.1.4/32", | |
119 | "225.1.1.5/32", | |
120 | ] | |
121 | IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"] | |
122 | GROUP_RANGE_2 = [ | |
123 | "226.1.1.1/32", | |
124 | "226.1.1.2/32", | |
125 | "226.1.1.3/32", | |
126 | "226.1.1.4/32", | |
127 | "226.1.1.5/32", | |
128 | ] | |
129 | IGMP_JOIN_RANGE_2 = ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"] | |
130 | GROUP_RANGE_3 = [ | |
131 | "227.1.1.1/32", | |
132 | "227.1.1.2/32", | |
133 | "227.1.1.3/32", | |
134 | "227.1.1.4/32", | |
135 | "227.1.1.5/32", | |
136 | ] | |
137 | IGMP_JOIN_RANGE_3 = ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"] | |
138 | ||
139 | intf_r1_s1 = None | |
140 | intf_r1_s1_addr = None | |
141 | intf_r2_s1 = None | |
142 | intf_r2_s1_addr = None | |
143 | intf_r3_s1 = None | |
144 | intf_r3_s1_addr = None | |
145 | intf_i1_s1 = None | |
146 | intf_i1_s1_addr = None | |
147 | ||
148 | ||
149 | def setup_module(mod): | |
150 | """ | |
151 | Sets up the pytest environment | |
152 | ||
153 | * `mod`: module name | |
154 | """ | |
155 | ||
156 | # Required linux kernel version for this suite to run. | |
157 | result = required_linux_kernel_version("4.19") | |
158 | if result is not True: | |
159 | pytest.skip("Kernel requirements are not met") | |
160 | ||
161 | testsuite_run_time = time.asctime(time.localtime(time.time())) | |
162 | logger.info("Testsuite start time: {}".format(testsuite_run_time)) | |
163 | logger.info("=" * 40) | |
164 | logger.info("Master Topology: \n {}".format(TOPOLOGY)) | |
165 | ||
166 | logger.info("Running setup_module to create topology") | |
167 | ||
168 | testdir = os.path.dirname(os.path.realpath(__file__)) | |
169 | json_file = "{}/pim_dr_nondr_with_transit_router_topo3.json".format(testdir) | |
170 | tgen = Topogen(json_file, mod.__name__) | |
171 | global topo | |
172 | topo = tgen.json_topo | |
173 | # ... and here it calls Mininet initialization functions. | |
174 | ||
40c28c86 | 175 | # Starting topology, create tmp files which are loaded to routers |
176 | # to start deamons and then start routers | |
991a971f | 177 | start_topology(tgen) |
40c28c86 | 178 | |
179 | # Don"t run this test if we have any failure. | |
180 | if tgen.routers_have_failure(): | |
181 | pytest.skip(tgen.errors) | |
182 | ||
183 | # Creating configuration from JSON | |
184 | build_config_from_json(tgen, tgen.json_topo) | |
185 | ||
186 | # XXX Replace this using "with McastTesterHelper()... " in each test if possible. | |
187 | global app_helper | |
188 | app_helper = McastTesterHelper(tgen) | |
189 | ||
190 | logger.info("Running setup_module() done") | |
191 | ||
192 | ||
193 | def teardown_module(): | |
194 | """Teardown the pytest environment""" | |
195 | ||
196 | logger.info("Running teardown_module to delete topology") | |
197 | ||
198 | tgen = get_topogen() | |
199 | ||
200 | app_helper.cleanup() | |
201 | ||
202 | # Stop toplogy and Remove tmp files | |
203 | tgen.stop_topology() | |
204 | ||
205 | logger.info( | |
206 | "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) | |
207 | ) | |
208 | logger.info("=" * 40) | |
209 | ||
210 | ||
211 | ##################################################### | |
212 | # | |
213 | # Local APIs | |
214 | # | |
215 | ##################################################### | |
216 | ||
217 | ||
218 | def pre_config_for_receiver_dr_tests( | |
219 | tgen, topo, tc_name, highest_priority, lowest_priority | |
220 | ): | |
221 | """ | |
222 | API to do common pre-configuration for receiver test cases | |
223 | ||
224 | parameters: | |
225 | ----------- | |
226 | * `tgen`: topogen object | |
227 | * `topo`: input json data | |
228 | * `tc_name`: caller test case name | |
229 | * `highest_priority`: router which will be having highest DR priority | |
230 | * `lowest_priority`: router which will be having lowest DR priority | |
231 | """ | |
232 | ||
233 | global intf_r1_s1, intf_r1_s1_addr, intf_r2_s1, intf_r2_s1_addr, intf_i1_s1, intf_i1_s1_addr | |
234 | ||
235 | step("Configure IGMP and PIM on switch connected receiver nodes") | |
236 | step("Configure PIM on all upstream interfaces") | |
237 | ||
238 | step("Configure link between R1, R2 ,R3 and receiver on" " same vlan") | |
239 | step( | |
240 | "Make sure {0} is DR initially configuring highest IP on {0} and R2 " | |
241 | "second highest, {1} is lower".format(highest_priority, lowest_priority) | |
242 | ) | |
243 | ||
244 | intf_r1_s1 = topo["routers"]["r1"]["links"]["s1"]["interface"] | |
245 | intf_r1_s1_addr = topo["routers"]["r1"]["links"]["s1"]["ipv4"] | |
246 | ||
247 | intf_r2_s1 = topo["routers"]["r2"]["links"]["s1"]["interface"] | |
248 | intf_r2_s1_addr = topo["routers"]["r2"]["links"]["s1"]["ipv4"] | |
249 | ||
250 | intf_i1_s1 = topo["routers"]["i1"]["links"]["s1"]["interface"] | |
251 | intf_i1_s1_addr = topo["routers"]["i1"]["links"]["s1"]["ipv4"] | |
252 | ||
253 | if lowest_priority == "r1": | |
254 | lowest_pr_intf = intf_r1_s1 | |
255 | else: | |
256 | lowest_pr_intf = intf_r2_s1 | |
257 | ||
258 | if highest_priority == "r1": | |
259 | highest_pr_intf = intf_r1_s1 | |
260 | else: | |
261 | highest_pr_intf = intf_r2_s1 | |
262 | ||
263 | vlan_input = { | |
264 | lowest_priority: { | |
265 | "vlan": { | |
266 | VLAN_1: [ | |
267 | { | |
268 | lowest_pr_intf: { | |
269 | "ip": SAME_VLAN_IP_1["ip"], | |
270 | "subnet": SAME_VLAN_IP_1["subnet"], | |
271 | } | |
272 | } | |
273 | ] | |
274 | } | |
275 | }, | |
276 | highest_priority: { | |
277 | "vlan": { | |
278 | VLAN_1: [ | |
279 | { | |
280 | highest_pr_intf: { | |
281 | "ip": SAME_VLAN_IP_2["ip"], | |
282 | "subnet": SAME_VLAN_IP_2["subnet"], | |
283 | } | |
284 | } | |
285 | ] | |
286 | } | |
287 | }, | |
288 | "i1": { | |
289 | "vlan": { | |
290 | VLAN_1: [ | |
291 | { | |
292 | intf_i1_s1: { | |
293 | "ip": SAME_VLAN_IP_4["ip"], | |
294 | "subnet": SAME_VLAN_IP_4["subnet"], | |
295 | } | |
296 | } | |
297 | ] | |
298 | } | |
299 | }, | |
300 | } | |
301 | ||
302 | add_interfaces_to_vlan(tgen, vlan_input) | |
303 | ||
304 | raw_config = { | |
305 | "r1": { | |
306 | "raw_config": [ | |
307 | "interface {}".format(intf_r1_s1), | |
308 | "no ip address {}".format(intf_r1_s1_addr), | |
309 | "no ip pim", | |
310 | ] | |
311 | }, | |
312 | "r2": { | |
313 | "raw_config": [ | |
314 | "interface {}".format(intf_r2_s1), | |
315 | "no ip address {}".format(intf_r2_s1_addr), | |
316 | "no ip pim", | |
317 | ] | |
318 | }, | |
319 | "i1": { | |
320 | "raw_config": [ | |
321 | "interface {}".format(intf_i1_s1), | |
322 | "no ip address {}".format(intf_i1_s1_addr), | |
323 | ] | |
324 | }, | |
325 | } | |
326 | ||
327 | result = apply_raw_config(tgen, raw_config) | |
328 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
329 | ||
330 | raw_config = { | |
331 | lowest_priority: { | |
332 | "raw_config": [ | |
333 | "interface {}.{}".format(lowest_pr_intf, VLAN_1), | |
334 | "ip address {}/{}".format(SAME_VLAN_IP_1["ip"], SAME_VLAN_IP_1["cidr"]), | |
335 | "ip pim", | |
336 | "ip igmp", | |
337 | "ip igmp version 2", | |
338 | ] | |
339 | }, | |
340 | highest_priority: { | |
341 | "raw_config": [ | |
342 | "interface {}.{}".format(highest_pr_intf, VLAN_1), | |
343 | "ip address {}/{}".format(SAME_VLAN_IP_2["ip"], SAME_VLAN_IP_2["cidr"]), | |
344 | "ip pim", | |
345 | "ip igmp", | |
346 | "ip igmp version 2", | |
347 | ] | |
348 | }, | |
349 | "i1": { | |
350 | "raw_config": [ | |
351 | "interface {}.{}".format(intf_i1_s1, VLAN_1), | |
352 | "ip address {}/{}".format(SAME_VLAN_IP_4["ip"], SAME_VLAN_IP_4["cidr"]), | |
353 | ] | |
354 | }, | |
355 | } | |
356 | ||
357 | result = apply_raw_config(tgen, raw_config) | |
358 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
359 | ||
360 | for dut, intf in zip(["r1", "r2"], [intf_r1_s1, intf_r2_s1]): | |
361 | raw_config = { | |
362 | dut: { | |
363 | "raw_config": [ | |
364 | "interface {}.{}".format(intf, VLAN_1), | |
365 | "ip pim hello {} {}".format(HELLO_TIMER, HOLD_TIMER), | |
366 | ] | |
367 | } | |
368 | } | |
369 | result = apply_raw_config(tgen, raw_config) | |
370 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
371 | ||
372 | step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24") | |
373 | ||
374 | input_dict = { | |
375 | "r4": { | |
376 | "pim": { | |
377 | "rp": [ | |
378 | { | |
379 | "rp_addr": topo["routers"]["r4"]["links"]["lo"]["ipv4"].split( | |
380 | "/" | |
381 | )[0], | |
382 | "group_addr_range": GROUP_RANGE_1, | |
383 | } | |
384 | ] | |
385 | } | |
386 | } | |
387 | } | |
388 | ||
389 | result = create_pim_config(tgen, topo, input_dict) | |
390 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
391 | ||
392 | step("Send IGMP join for groups 226.1.1.1 to 226.1.1.5") | |
393 | ||
394 | vlan_intf_i1_s1 = "{}.{}".format(intf_i1_s1, VLAN_1) | |
395 | result = app_helper.run_join("i1", IGMP_JOIN_RANGE_1, join_intf=vlan_intf_i1_s1) | |
396 | assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) | |
397 | ||
398 | step("Enable OSPF between r1 and r2") | |
399 | ||
400 | for dut, intf in zip(["r1", "r2"], [intf_r1_s1, intf_r2_s1]): | |
401 | raw_config = { | |
402 | dut: { | |
403 | "raw_config": [ | |
404 | "interface {}.{}".format(intf, VLAN_1), | |
405 | "ip ospf area 0.0.0.0", | |
406 | "ip ospf dead-interval 4", | |
407 | "ip ospf hello-interval 1", | |
408 | ] | |
409 | } | |
410 | } | |
411 | result = apply_raw_config(tgen, raw_config) | |
412 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
413 | ||
414 | step("Start traffic from R4 connected source") | |
415 | ||
416 | result = app_helper.run_traffic("i2", IGMP_JOIN_RANGE_1, "r5") | |
417 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
418 | ||
419 | return True | |
420 | ||
421 | ||
422 | def pre_config_for_source_dr_tests( | |
423 | tgen, topo, tc_name, highest_priority, lowest_priority | |
424 | ): | |
425 | """ | |
426 | API to do common pre-configuration for source test cases | |
427 | ||
428 | parameters: | |
429 | ----------- | |
430 | * `tgen`: topogen object | |
431 | * `topo`: input json data | |
432 | * `tc_name`: caller test case name | |
433 | * `highest_priority`: router which will be having highest DR priority | |
434 | * `lowest_priority`: router which will be having lowest DR priority | |
435 | """ | |
436 | ||
437 | global intf_r1_s1, intf_r1_s1_addr, intf_r2_s1, intf_r2_s1_addr, intf_i1_s1, intf_i1_s1_addr | |
438 | ||
439 | step("Configure IGMP and PIM on switch connected receiver nodes") | |
440 | step("Configure PIM on all upstream interfaces") | |
441 | ||
442 | step("Configure link between R1, R2 ,R3 and receiver on" " same vlan") | |
443 | step( | |
444 | "Make sure {0} is DR initially configuring highest IP on {0} and R2 " | |
445 | "second highest, {1} is lower".format(highest_priority, lowest_priority) | |
446 | ) | |
447 | ||
448 | intf_r1_s1 = topo["routers"]["r1"]["links"]["s1"]["interface"] | |
449 | intf_r1_s1_addr = topo["routers"]["r1"]["links"]["s1"]["ipv4"] | |
450 | ||
451 | intf_r2_s1 = topo["routers"]["r2"]["links"]["s1"]["interface"] | |
452 | intf_r2_s1_addr = topo["routers"]["r2"]["links"]["s1"]["ipv4"] | |
453 | ||
454 | intf_i1_s1 = topo["routers"]["i1"]["links"]["s1"]["interface"] | |
455 | intf_i1_s1_addr = topo["routers"]["i1"]["links"]["s1"]["ipv4"] | |
456 | ||
457 | if lowest_priority == "r1": | |
458 | lowest_pr_intf = intf_r1_s1 | |
459 | else: | |
460 | lowest_pr_intf = intf_r2_s1 | |
461 | ||
462 | if highest_priority == "r1": | |
463 | highest_pr_intf = intf_r1_s1 | |
464 | else: | |
465 | highest_pr_intf = intf_r2_s1 | |
466 | ||
467 | vlan_input = { | |
468 | lowest_priority: { | |
469 | "vlan": { | |
470 | VLAN_1: [ | |
471 | { | |
472 | lowest_pr_intf: { | |
473 | "ip": SAME_VLAN_IP_1["ip"], | |
474 | "subnet": SAME_VLAN_IP_1["subnet"], | |
475 | } | |
476 | } | |
477 | ] | |
478 | } | |
479 | }, | |
480 | highest_priority: { | |
481 | "vlan": { | |
482 | VLAN_1: [ | |
483 | { | |
484 | highest_pr_intf: { | |
485 | "ip": SAME_VLAN_IP_2["ip"], | |
486 | "subnet": SAME_VLAN_IP_2["subnet"], | |
487 | } | |
488 | } | |
489 | ] | |
490 | } | |
491 | }, | |
492 | "i1": { | |
493 | "vlan": { | |
494 | VLAN_1: [ | |
495 | { | |
496 | intf_i1_s1: { | |
497 | "ip": SAME_VLAN_IP_4["ip"], | |
498 | "subnet": SAME_VLAN_IP_4["subnet"], | |
499 | } | |
500 | } | |
501 | ] | |
502 | } | |
503 | }, | |
504 | } | |
505 | ||
506 | add_interfaces_to_vlan(tgen, vlan_input) | |
507 | ||
508 | raw_config = { | |
509 | "r1": { | |
510 | "raw_config": [ | |
511 | "interface {}".format(intf_r1_s1), | |
512 | "no ip address {}".format(intf_r1_s1_addr), | |
513 | "no ip pim", | |
514 | ] | |
515 | }, | |
516 | "r2": { | |
517 | "raw_config": [ | |
518 | "interface {}".format(intf_r2_s1), | |
519 | "no ip address {}".format(intf_r2_s1_addr), | |
520 | "no ip pim", | |
521 | ] | |
522 | }, | |
523 | "i1": { | |
524 | "raw_config": [ | |
525 | "interface {}".format(intf_i1_s1), | |
526 | "no ip address {}".format(intf_i1_s1_addr), | |
527 | ] | |
528 | }, | |
529 | } | |
530 | ||
531 | result = apply_raw_config(tgen, raw_config) | |
532 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
533 | ||
534 | step( | |
535 | "Configure IGMP and PIM on switch connected receiver nodes , " | |
536 | "configure PIM nbr with hello timer 1" | |
537 | ) | |
538 | ||
539 | raw_config = { | |
540 | lowest_priority: { | |
541 | "raw_config": [ | |
542 | "interface {}.{}".format(lowest_pr_intf, VLAN_1), | |
543 | "ip address {}/{}".format(SAME_VLAN_IP_1["ip"], SAME_VLAN_IP_1["cidr"]), | |
544 | "ip pim", | |
545 | ] | |
546 | }, | |
547 | highest_priority: { | |
548 | "raw_config": [ | |
549 | "interface {}.{}".format(highest_pr_intf, VLAN_1), | |
550 | "ip address {}/{}".format(SAME_VLAN_IP_2["ip"], SAME_VLAN_IP_2["cidr"]), | |
551 | "ip pim", | |
552 | ] | |
553 | }, | |
554 | "i1": { | |
555 | "raw_config": [ | |
556 | "interface {}.{}".format(intf_i1_s1, VLAN_1), | |
557 | "ip address {}/{}".format(SAME_VLAN_IP_4["ip"], SAME_VLAN_IP_4["cidr"]), | |
558 | ] | |
559 | }, | |
560 | } | |
561 | ||
562 | result = apply_raw_config(tgen, raw_config) | |
563 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
564 | ||
565 | for dut, intf in zip(["r1", "r2"], [intf_r1_s1, intf_r2_s1]): | |
566 | raw_config = { | |
567 | dut: { | |
568 | "raw_config": [ | |
569 | "interface {}.{}".format(intf, VLAN_1), | |
570 | "ip pim hello {} {}".format(HELLO_TIMER, HOLD_TIMER), | |
571 | ] | |
572 | } | |
573 | } | |
574 | result = apply_raw_config(tgen, raw_config) | |
575 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
576 | ||
577 | step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24") | |
578 | ||
579 | input_dict = { | |
580 | "r4": { | |
581 | "pim": { | |
582 | "rp": [ | |
583 | { | |
584 | "rp_addr": topo["routers"]["r4"]["links"]["lo"]["ipv4"].split( | |
585 | "/" | |
586 | )[0], | |
587 | "group_addr_range": GROUP_RANGE_1, | |
588 | } | |
589 | ] | |
590 | } | |
591 | } | |
592 | } | |
593 | ||
594 | result = create_pim_config(tgen, topo, input_dict) | |
595 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
596 | ||
597 | step("Configure IGMP on R5 port and send IGMP join for groups " "(226.1.1.1-5)") | |
598 | ||
599 | intf_r5_i2 = topo["routers"]["r5"]["links"]["i2"]["interface"] | |
600 | input_dict = { | |
601 | "r5": {"igmp": {"interfaces": {intf_r5_i2: {"igmp": {"version": "2"}}}}} | |
602 | } | |
603 | result = create_igmp_config(tgen, topo, input_dict) | |
604 | assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) | |
605 | ||
606 | result = app_helper.run_join("i2", IGMP_JOIN_RANGE_1, "r5") | |
607 | assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) | |
608 | ||
609 | step("Enable OSPF between r1 and r2") | |
610 | ||
611 | for dut, intf in zip(["r1", "r2"], [intf_r1_s1, intf_r2_s1]): | |
612 | raw_config = { | |
613 | dut: { | |
614 | "raw_config": [ | |
615 | "interface {}.{}".format(intf, VLAN_1), | |
616 | "ip ospf area 0.0.0.0", | |
617 | "ip ospf dead-interval 4", | |
618 | "ip ospf hello-interval 1", | |
619 | ] | |
620 | } | |
621 | } | |
622 | result = apply_raw_config(tgen, raw_config) | |
623 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
624 | ||
625 | step("Start traffic from Source node") | |
626 | ||
627 | vlan_intf_i1_s1 = "{}.{}".format(intf_i1_s1, VLAN_1) | |
628 | result = app_helper.run_traffic("i1", IGMP_JOIN_RANGE_1, bind_intf=vlan_intf_i1_s1) | |
629 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
630 | ||
631 | return True | |
632 | ||
633 | ||
634 | ##################################################### | |
635 | # | |
636 | # Testcases | |
637 | # | |
638 | ##################################################### | |
639 | ||
640 | ||
641 | def test_mroute_when_transit_router_present_between_rp_and_source_dr_p1(request): | |
642 | """ | |
643 | Verify mroutes when transit router present between RP and Source DR | |
644 | """ | |
645 | ||
646 | tgen = get_topogen() | |
647 | tc_name = request.node.name | |
648 | write_test_header(tc_name) | |
649 | ||
650 | # Creating configuration from JSON | |
651 | app_helper.stop_all_hosts() | |
4fafd29f | 652 | clear_mroute(tgen) |
40c28c86 | 653 | check_router_status(tgen) |
654 | reset_config_on_routers(tgen) | |
4fafd29f | 655 | clear_pim_interface_traffic(tgen, topo) |
40c28c86 | 656 | |
657 | # Don"t run this test if we have any failure. | |
658 | if tgen.routers_have_failure(): | |
659 | pytest.skip(tgen.errors) | |
660 | ||
661 | result = pre_config_for_source_dr_tests(tgen, topo, tc_name, "r1", "r2") | |
662 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
663 | ||
664 | step("Taken care in base config: Add router R6 between RP and R1 , R2") | |
665 | ||
666 | step("R1 is the DR, mroute and upstream created on R1") | |
667 | ||
668 | vlan_intf_r1_s1 = "{}.{}".format(intf_r1_s1, VLAN_1) | |
669 | input_dict_dr = { | |
670 | "r1": { | |
671 | "pim": { | |
672 | "interfaces": {vlan_intf_r1_s1: {"drAddress": SAME_VLAN_IP_2["ip"]}} | |
673 | } | |
674 | } | |
675 | } | |
676 | result = verify_pim_config(tgen, input_dict_dr) | |
677 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
678 | ||
679 | step("On R1 Mroute OIL towards R6, upstream in join Rej Prune state") | |
680 | ||
681 | source_i1 = SAME_VLAN_IP_4["ip"] | |
682 | input_dict_r1 = [ | |
683 | { | |
684 | "dut": "r1", | |
685 | "src_address": source_i1, | |
686 | "oil": topo["routers"]["r1"]["links"]["r6"]["interface"], | |
687 | "iif": "{}.{}".format( | |
688 | topo["routers"]["r1"]["links"]["s1"]["interface"], VLAN_1 | |
689 | ), | |
690 | } | |
691 | ] | |
692 | ||
693 | for data in input_dict_r1: | |
4fafd29f | 694 | result = verify_mroutes( |
40c28c86 | 695 | tgen, |
696 | data["dut"], | |
697 | data["src_address"], | |
698 | IGMP_JOIN_RANGE_1, | |
699 | data["iif"], | |
700 | data["oil"], | |
701 | ) | |
702 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
703 | ||
704 | result = verify_upstream_iif( | |
705 | tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 | |
706 | ) | |
707 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
708 | ||
709 | step( | |
710 | "R5 have mroute created and traffic is received, verify using " | |
711 | "'show ip mroute json' 'show ip multicast json'" | |
712 | ) | |
713 | ||
714 | input_dict_r5 = [ | |
715 | { | |
716 | "dut": "r5", | |
717 | "src_address": "*", | |
718 | "iif": topo["routers"]["r5"]["links"]["r4"]["interface"], | |
719 | "oil": topo["routers"]["r5"]["links"]["i2"]["interface"], | |
720 | }, | |
721 | { | |
722 | "dut": "r5", | |
723 | "src_address": source_i1, | |
724 | "iif": topo["routers"]["r5"]["links"]["r4"]["interface"], | |
725 | "oil": topo["routers"]["r5"]["links"]["i2"]["interface"], | |
726 | }, | |
727 | ] | |
728 | ||
729 | for data in input_dict_r5: | |
4fafd29f | 730 | result = verify_mroutes( |
40c28c86 | 731 | tgen, |
732 | data["dut"], | |
733 | data["src_address"], | |
734 | IGMP_JOIN_RANGE_1, | |
735 | data["iif"], | |
736 | data["oil"], | |
737 | ) | |
738 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
739 | ||
740 | input_dict_traffic_r5 = { | |
741 | "r5": { | |
742 | "traffic_received": [topo["routers"]["r5"]["links"]["r4"]["interface"]], | |
743 | "traffic_sent": [topo["routers"]["r5"]["links"]["i2"]["interface"]], | |
744 | } | |
745 | } | |
746 | ||
747 | result = verify_multicast_traffic(tgen, input_dict_traffic_r5) | |
748 | assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) | |
749 | ||
750 | step("Make R2 as DR configuring higher priority value") | |
751 | ||
752 | raw_config = { | |
753 | "r1": { | |
754 | "raw_config": [ | |
755 | "interface {}.{}".format(intf_r1_s1, VLAN_1), | |
756 | "no ip address {}/{}".format( | |
757 | SAME_VLAN_IP_2["ip"], SAME_VLAN_IP_1["cidr"] | |
758 | ), | |
759 | "ip address {}/{}".format(SAME_VLAN_IP_1["ip"], SAME_VLAN_IP_1["cidr"]), | |
760 | ] | |
761 | }, | |
762 | "r2": { | |
763 | "raw_config": [ | |
764 | "interface {}.{}".format(intf_r2_s1, VLAN_1), | |
765 | "no ip address {}/{}".format( | |
766 | SAME_VLAN_IP_1["ip"], SAME_VLAN_IP_1["cidr"] | |
767 | ), | |
768 | "ip address {}/{}".format(SAME_VLAN_IP_2["ip"], SAME_VLAN_IP_2["cidr"]), | |
769 | ] | |
770 | }, | |
771 | } | |
772 | ||
773 | result = apply_raw_config(tgen, raw_config) | |
774 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
775 | ||
776 | step("R2 is the DR, mroute and upstream created on R2") | |
777 | ||
778 | vlan_intf_r2_s1 = "{}.{}".format(intf_r2_s1, VLAN_1) | |
779 | input_dict_dr = { | |
780 | "r2": { | |
781 | "pim": { | |
782 | "interfaces": {vlan_intf_r2_s1: {"drAddress": SAME_VLAN_IP_2["ip"]}} | |
783 | } | |
784 | } | |
785 | } | |
786 | result = verify_pim_config(tgen, input_dict_dr) | |
787 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
788 | ||
789 | step( | |
790 | "R5 have mroute created and traffic is received, verify using " | |
791 | "'show ip mroute json' 'show ip multicast json'" | |
792 | ) | |
793 | ||
794 | for data in input_dict_r5: | |
4fafd29f | 795 | result = verify_mroutes( |
40c28c86 | 796 | tgen, |
797 | data["dut"], | |
798 | data["src_address"], | |
799 | IGMP_JOIN_RANGE_1, | |
800 | data["iif"], | |
801 | data["oil"], | |
802 | ) | |
803 | assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) | |
804 | ||
805 | result = verify_multicast_traffic(tgen, input_dict_traffic_r5) | |
806 | assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) | |
807 | ||
808 | write_test_footer(tc_name) | |
809 | ||
810 | ||
811 | if __name__ == "__main__": | |
812 | args = ["-s"] + sys.argv[1:] | |
813 | sys.exit(pytest.main(args)) |