2 # SPDX-License-Identifier: ISC
5 # Copyright (c) 2020 by VMware, Inc. ("VMware")
6 # Used Copyright (c) 2018 by Network Device Education Foundation,
7 # Inc. ("NetDEF") in this file.
11 Following tests are covered to test multicast pim sm:
14 - Create topology (setup module)
17 Following tests are covered:
18 1. Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
26 from time
import sleep
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/"))
34 # Required to instantiate the topology builder class.
36 # pylint: disable=C0413
37 # Import topogen and topotest helpers
38 from lib
.topogen
import Topogen
, get_topogen
40 from lib
.common_config
import (
45 reset_config_on_routers
,
47 add_interfaces_to_vlan
,
52 required_linux_kernel_version
,
59 clear_pim_interface_traffic
,
62 verify_multicast_flag_state
,
65 from lib
.topolog
import logger
66 from lib
.topojson
import build_config_from_json
71 pytestmark
= [pytest
.mark
.pimd
]
75 Descripton: Configuring static routes on r1/r2/r3/r4/r5 for RP reachablility.
76 IPs are assigned automatically to routers, start IP and subnet is defined in respective JSON file
78 "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24},
81 10.0.3.2/24| 10.0.0.2/24
84 ------------ r4 ----------
85 | 10.0.1.2/24 10.0.2.2/24 |
86 10.0.1.1/24 | | 10.0.2.1/24
87 r1 ----------- s1 ---------- r2
88 10.0.4.2/24 | 10.0.4.3/24
94 i1, i2 - FRR running iperf to send IGMP
96 r1, r2, r3, r4, r5 - FRR ruter
102 GROUP_RANGE
= "225.0.0.0/8"
103 IGMP_JOIN
= "225.1.1.1"
104 VLAN_INTF_ADRESS_1
= "10.0.8.3/24"
105 SAME_VLAN_IP_1
= {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"}
106 SAME_VLAN_IP_2
= {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"}
107 SAME_VLAN_IP_3
= {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"}
108 SAME_VLAN_IP_4
= {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"}
116 IGMP_JOIN_RANGE_1
= ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
124 IGMP_JOIN_RANGE_2
= ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"]
132 IGMP_JOIN_RANGE_3
= ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"]
135 intf_r1_s1_addr
= None
137 intf_r2_s1_addr
= None
139 intf_r3_s1_addr
= None
141 intf_i1_s1_addr
= None
144 def setup_module(mod
):
146 Sets up the pytest environment
151 # Required linux kernel version for this suite to run.
152 result
= required_linux_kernel_version("4.19")
153 if result
is not True:
154 pytest
.skip("Kernel requirements are not met")
156 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
157 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
158 logger
.info("=" * 40)
159 logger
.info("Master Topology: \n {}".format(TOPOLOGY
))
161 logger
.info("Running setup_module to create topology")
163 testdir
= os
.path
.dirname(os
.path
.realpath(__file__
))
164 json_file
= "{}/pim_dr_nondr_with_static_routes_topo1.json".format(testdir
)
165 tgen
= Topogen(json_file
, mod
.__name
__)
167 topo
= tgen
.json_topo
168 # ... and here it calls Mininet initialization functions.
170 # Starting topology, create tmp files which are loaded to routers
171 # to start deamons and then start routers
174 # Don"t run this test if we have any failure.
175 if tgen
.routers_have_failure():
176 pytest
.skip(tgen
.errors
)
178 # Creating configuration from JSON
179 build_config_from_json(tgen
, tgen
.json_topo
)
181 # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
183 app_helper
= McastTesterHelper(tgen
)
185 logger
.info("Running setup_module() done")
188 def teardown_module():
189 """Teardown the pytest environment"""
191 logger
.info("Running teardown_module to delete topology")
197 # Stop toplogy and Remove tmp files
201 "Testsuite end time: {}".format(time
.asctime(time
.localtime(time
.time())))
203 logger
.info("=" * 40)
206 #####################################################
210 #####################################################
213 def pre_config_for_receiver_dr_tests(
214 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
217 API to do common pre-configuration for receiver test cases
221 * `tgen`: topogen object
222 * `topo`: input json data
223 * `tc_name`: caller test case name
224 * `highest_priority`: router which will be having highest DR priority
225 * `lowest_priority`: router which will be having lowest DR priority
228 global intf_r1_s1
, intf_r1_s1_addr
, intf_r2_s1
, intf_r2_s1_addr
, intf_r3_s1
, intf_r3_s1_addr
, intf_i1_s1
, intf_i1_s1_addr
230 step("Configure IGMP and PIM on switch connected receiver nodes")
231 step("Configure PIM on all upstream interfaces")
233 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
235 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
236 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
239 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
240 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
242 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
243 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
245 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
246 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
248 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
249 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
251 if lowest_priority
== "r1":
252 lowest_pr_intf
= intf_r1_s1
254 lowest_pr_intf
= intf_r3_s1
256 if highest_priority
== "r1":
257 highest_pr_intf
= intf_r1_s1
259 highest_pr_intf
= intf_r3_s1
267 "ip": SAME_VLAN_IP_1
["ip"],
268 "subnet": SAME_VLAN_IP_1
["subnet"],
279 "ip": SAME_VLAN_IP_2
["ip"],
280 "subnet": SAME_VLAN_IP_2
["subnet"],
291 "ip": SAME_VLAN_IP_3
["ip"],
292 "subnet": SAME_VLAN_IP_3
["subnet"],
303 "ip": SAME_VLAN_IP_4
["ip"],
304 "subnet": SAME_VLAN_IP_4
["subnet"],
312 add_interfaces_to_vlan(tgen
, vlan_input
)
317 "interface {}".format(intf_r1_s1
),
318 "no ip address {}".format(intf_r1_s1_addr
),
324 "interface {}".format(intf_r2_s1
),
325 "no ip address {}".format(intf_r2_s1_addr
),
331 "interface {}".format(intf_r3_s1
),
332 "no ip address {}".format(intf_r3_s1_addr
),
338 "interface {}".format(intf_i1_s1
),
339 "no ip address {}".format(intf_i1_s1_addr
),
344 result
= apply_raw_config(tgen
, raw_config
)
345 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
350 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
351 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
359 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
360 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
368 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
369 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
377 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
378 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
383 result
= apply_raw_config(tgen
, raw_config
)
384 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
386 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
390 "interface {}.{}".format(intf
, VLAN_1
),
391 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
395 result
= apply_raw_config(tgen
, raw_config
)
396 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
398 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
405 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
408 "group_addr_range": GROUP_RANGE_1
,
415 result
= create_pim_config(tgen
, topo
, input_dict
)
416 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
418 step("Send IGMP join for groups 226.1.1.1 to 226.1.1.5")
420 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
421 result
= app_helper
.run_join("i1", IGMP_JOIN_RANGE_1
, join_intf
=vlan_intf_i1_s1
)
422 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
424 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
426 step("Start traffic from R4 connected source")
428 result
= app_helper
.run_traffic("i2", IGMP_JOIN_RANGE_1
, "r5")
429 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
434 def pre_config_for_source_dr_tests(
435 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
438 API to do common pre-configuration for source test cases
442 * `tgen`: topogen object
443 * `topo`: input json data
444 * `tc_name`: caller test case name
445 * `highest_priority`: router which will be having highest DR priority
446 * `lowest_priority`: router which will be having lowest DR priority
449 global intf_r1_s1
, intf_r1_s1_addr
, intf_r2_s1
, intf_r2_s1_addr
, intf_r3_s1
, intf_r3_s1_addr
, intf_i1_s1
, intf_i1_s1_addr
451 step("Configure IGMP and PIM on switch connected receiver nodes")
452 step("Configure PIM on all upstream interfaces")
454 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
456 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
457 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
460 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
461 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
463 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
464 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
466 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
467 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
469 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
470 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
472 if lowest_priority
== "r1":
473 lowest_pr_intf
= intf_r1_s1
475 lowest_pr_intf
= intf_r3_s1
477 if highest_priority
== "r1":
478 highest_pr_intf
= intf_r1_s1
480 highest_pr_intf
= intf_r3_s1
488 "ip": SAME_VLAN_IP_1
["ip"],
489 "subnet": SAME_VLAN_IP_1
["subnet"],
500 "ip": SAME_VLAN_IP_2
["ip"],
501 "subnet": SAME_VLAN_IP_2
["subnet"],
512 "ip": SAME_VLAN_IP_3
["ip"],
513 "subnet": SAME_VLAN_IP_3
["subnet"],
524 "ip": SAME_VLAN_IP_4
["ip"],
525 "subnet": SAME_VLAN_IP_4
["subnet"],
533 add_interfaces_to_vlan(tgen
, vlan_input
)
538 "interface {}".format(intf_r1_s1
),
539 "no ip address {}".format(intf_r1_s1_addr
),
545 "interface {}".format(intf_r2_s1
),
546 "no ip address {}".format(intf_r2_s1_addr
),
552 "interface {}".format(intf_r3_s1
),
553 "no ip address {}".format(intf_r3_s1_addr
),
559 "interface {}".format(intf_i1_s1
),
560 "no ip address {}".format(intf_i1_s1_addr
),
565 result
= apply_raw_config(tgen
, raw_config
)
566 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
569 "Configure IGMP and PIM on switch connected receiver nodes , "
570 "configure PIM nbr with hello timer 1"
576 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
577 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
583 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
584 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
590 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
591 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
597 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
598 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
603 result
= apply_raw_config(tgen
, raw_config
)
604 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
606 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
610 "interface {}.{}".format(intf
, VLAN_1
),
611 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
615 result
= apply_raw_config(tgen
, raw_config
)
616 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
618 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
625 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
628 "group_addr_range": GROUP_RANGE_1
,
635 result
= create_pim_config(tgen
, topo
, input_dict
)
636 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
638 step("Configure IGMP on R5 port and send IGMP join for groups " "(226.1.1.1-5)")
640 intf_r5_i2
= topo
["routers"]["r5"]["links"]["i2"]["interface"]
642 "r5": {"igmp": {"interfaces": {intf_r5_i2
: {"igmp": {"version": "2"}}}}}
644 result
= create_igmp_config(tgen
, topo
, input_dict
)
645 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
647 input_src
= {"i2": topo
["routers"]["i2"]["links"]["r5"]["interface"]}
649 result
= app_helper
.run_join("i2", IGMP_JOIN_RANGE_1
, "r5")
650 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
652 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
654 step("Start traffic from Source node")
656 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
657 result
= app_helper
.run_traffic("i1", IGMP_JOIN_RANGE_1
, bind_intf
=vlan_intf_i1_s1
)
658 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
663 #####################################################
667 #####################################################
670 def test_pim_source_dr_functionality_while_rebooting_dr_non_dr_nodes_p1(request
):
672 Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
676 tc_name
= request
.node
.name
677 write_test_header(tc_name
)
679 # Creating configuration from JSON
680 app_helper
.stop_all_hosts()
682 check_router_status(tgen
)
683 reset_config_on_routers(tgen
)
684 clear_pim_interface_traffic(tgen
, topo
)
686 # Don"t run this test if we have any failure.
687 if tgen
.routers_have_failure():
688 pytest
.skip(tgen
.errors
)
690 result
= pre_config_for_source_dr_tests(tgen
, topo
, tc_name
, "r1", "r3")
691 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
693 step("R1 is the DR , verify using 'show ip pim interface json'")
695 vlan_intf_r1_s1
= "{}.{}".format(intf_r1_s1
, VLAN_1
)
699 "interfaces": {vlan_intf_r1_s1
: {"drAddress": SAME_VLAN_IP_3
["ip"]}}
703 result
= verify_pim_config(tgen
, input_dict_dr
)
704 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
707 "R2 is transit router for I1 to reach R4, mroute should have (s, g) mroute with "
708 "OIL towards R4, using 'show ip mroute json'"
711 "R2 (s, g) upstream should be in join state verify using "
712 "'show ip pim upstream json'"
715 "R1 has (S, G) mroute with NONE OIL and upstream as not joined, verify using "
716 "'show ip mroute json' 'show ip pim upstream json'"
719 source_i1
= SAME_VLAN_IP_4
["ip"]
723 "src_address": source_i1
,
725 "iif": "{}.{}".format(
726 topo
["routers"]["r1"]["links"]["s1"]["interface"], VLAN_1
731 "src_address": source_i1
,
732 "oil": topo
["routers"]["r2"]["links"]["r4"]["interface"],
733 "iif": "{}.{}".format(
734 topo
["routers"]["r2"]["links"]["s1"]["interface"], VLAN_1
739 for data
in input_dict_r1_r2
:
740 result
= verify_mroutes(
748 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
750 if data
["dut"] == "r2":
751 result
= verify_upstream_iif(
752 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
754 assert result
is True, "Testcase {} : Failed Error: {}".format(
758 result
= verify_upstream_iif(
766 assert result
is not True, (
767 "Testcase {} : Failed \n "
768 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
771 step("Reboot R3 node")
772 stop_router(tgen
, "r3")
775 "After reboot of R3 verify R1 continues to be DR, using 'show ip pim interface json'"
778 result
= verify_pim_config(tgen
, input_dict_dr
)
779 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
781 step("R3 should not have any mroute and upstream")
782 step("R2 has mroute with OIL towards R4 /R1 , verify using 'show ip mroute'")
784 "R2 has upstream with Join RejP state verify using 'show ip pim upstream json'"
786 step("R1 has mroute with none OIL and upstream with Not Join")
788 for data
in input_dict_r1_r2
:
789 result
= verify_mroutes(
797 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
799 if data
["dut"] == "r2":
800 result
= verify_upstream_iif(
801 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
803 assert result
is True, "Testcase {} : Failed Error: {}".format(
807 result
= verify_upstream_iif(
815 assert result
is not True, (
816 "Testcase {} : Failed \n "
817 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
820 step("Reboot R2 node")
821 stop_router(tgen
, "r2")
824 "After reboot of R2, R1 continues to be DR verify using 'show ip pim interface json'"
827 result
= verify_pim_config(tgen
, input_dict_dr
)
828 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
831 "R3 and R2 should not have any mroute and upstream , verify using "
832 "'show ip mroute json' 'show ip pim upstream json'"
834 step("R1 has mroute created with empty OIL, using 'show ip mroute json'")
836 "R1 has upstream with Not Join, Rej Prune , verify using 'show ip pim upstream json'"
839 for data
in input_dict_r1_r2
:
840 if data
["dut"] == "r1":
841 result
= verify_mroutes(
849 assert result
is True, "Testcase {} : Failed Error: {}".format(
853 result
= verify_upstream_iif(
861 assert result
is not True, (
862 "Testcase {} : Failed \n "
863 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
866 step("Reboot R1 node using FRR stop")
867 stop_router(tgen
, "r1")
870 "After stop of all the routers, verify upstream and mroutes should "
871 "not present in any of them"
874 for data
in input_dict_r1_r2
:
875 result
= verify_mroutes(
886 ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format(
890 step("start FRR for all the nodes")
891 start_router(tgen
, "r1")
892 start_router(tgen
, "r2")
893 start_router(tgen
, "r3")
895 step("After start of all the routers, R1 became DR")
897 result
= verify_pim_config(tgen
, input_dict_dr
)
898 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
900 for data
in input_dict_r1_r2
:
901 result
= verify_mroutes(
909 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
911 if data
["dut"] == "r2":
912 result
= verify_upstream_iif(
913 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
915 assert result
is True, "Testcase {} : Failed Error: {}".format(
919 write_test_footer(tc_name
)
922 if __name__
== "__main__":
923 args
= ["-s"] + sys
.argv
[1:]
924 sys
.exit(pytest
.main(args
))