4 # Copyright (c) 2020 by VMware, Inc. ("VMware")
5 # Used Copyright (c) 2018 by Network Device Education Foundation,
6 # Inc. ("NetDEF") in this file.
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
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
24 Following tests are covered to test multicast pim sm:
27 - Create topology (setup module)
30 Following tests are covered:
31 1. Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
39 from time
import sleep
42 # Save the Current Working Directory to find configuration files.
43 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
44 sys
.path
.append(os
.path
.join(CWD
, "../"))
45 sys
.path
.append(os
.path
.join(CWD
, "../lib/"))
47 # Required to instantiate the topology builder class.
49 # pylint: disable=C0413
50 # Import topogen and topotest helpers
51 from lib
.topogen
import Topogen
, get_topogen
53 from lib
.common_config
import (
58 reset_config_on_routers
,
60 add_interfaces_to_vlan
,
65 required_linux_kernel_version
,
72 clear_pim_interface_traffic
,
75 verify_multicast_flag_state
,
78 from lib
.topolog
import logger
79 from lib
.topojson
import build_config_from_json
84 pytestmark
= [pytest
.mark
.pimd
]
88 Descripton: Configuring static routes on r1/r2/r3/r4/r5 for RP reachablility.
89 IPs are assigned automatically to routers, start IP and subnet is defined in respective JSON file
91 "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24},
94 10.0.3.2/24| 10.0.0.2/24
97 ------------ r4 ----------
98 | 10.0.1.2/24 10.0.2.2/24 |
99 10.0.1.1/24 | | 10.0.2.1/24
100 r1 ----------- s1 ---------- r2
101 10.0.4.2/24 | 10.0.4.3/24
107 i1, i2 - FRR running iperf to send IGMP
109 r1, r2, r3, r4, r5 - FRR ruter
115 GROUP_RANGE
= "225.0.0.0/8"
116 IGMP_JOIN
= "225.1.1.1"
117 VLAN_INTF_ADRESS_1
= "10.0.8.3/24"
118 SAME_VLAN_IP_1
= {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"}
119 SAME_VLAN_IP_2
= {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"}
120 SAME_VLAN_IP_3
= {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"}
121 SAME_VLAN_IP_4
= {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"}
129 IGMP_JOIN_RANGE_1
= ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
137 IGMP_JOIN_RANGE_2
= ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"]
145 IGMP_JOIN_RANGE_3
= ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"]
148 intf_r1_s1_addr
= None
150 intf_r2_s1_addr
= None
152 intf_r3_s1_addr
= None
154 intf_i1_s1_addr
= None
157 def setup_module(mod
):
159 Sets up the pytest environment
164 # Required linux kernel version for this suite to run.
165 result
= required_linux_kernel_version("4.19")
166 if result
is not True:
167 pytest
.skip("Kernel requirements are not met")
169 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
170 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
171 logger
.info("=" * 40)
172 logger
.info("Master Topology: \n {}".format(TOPOLOGY
))
174 logger
.info("Running setup_module to create topology")
176 testdir
= os
.path
.dirname(os
.path
.realpath(__file__
))
177 json_file
= "{}/pim_dr_nondr_with_static_routes_topo1.json".format(testdir
)
178 tgen
= Topogen(json_file
, mod
.__name
__)
180 topo
= tgen
.json_topo
181 # ... and here it calls Mininet initialization functions.
183 # Starting topology, create tmp files which are loaded to routers
184 # to start deamons and then start routers
187 # Don"t run this test if we have any failure.
188 if tgen
.routers_have_failure():
189 pytest
.skip(tgen
.errors
)
191 # Creating configuration from JSON
192 build_config_from_json(tgen
, tgen
.json_topo
)
194 # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
196 app_helper
= McastTesterHelper(tgen
)
198 logger
.info("Running setup_module() done")
201 def teardown_module():
202 """Teardown the pytest environment"""
204 logger
.info("Running teardown_module to delete topology")
210 # Stop toplogy and Remove tmp files
214 "Testsuite end time: {}".format(time
.asctime(time
.localtime(time
.time())))
216 logger
.info("=" * 40)
219 #####################################################
223 #####################################################
226 def pre_config_for_receiver_dr_tests(
227 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
230 API to do common pre-configuration for receiver test cases
234 * `tgen`: topogen object
235 * `topo`: input json data
236 * `tc_name`: caller test case name
237 * `highest_priority`: router which will be having highest DR priority
238 * `lowest_priority`: router which will be having lowest DR priority
241 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
243 step("Configure IGMP and PIM on switch connected receiver nodes")
244 step("Configure PIM on all upstream interfaces")
246 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
248 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
249 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
252 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
253 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
255 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
256 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
258 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
259 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
261 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
262 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
264 if lowest_priority
== "r1":
265 lowest_pr_intf
= intf_r1_s1
267 lowest_pr_intf
= intf_r3_s1
269 if highest_priority
== "r1":
270 highest_pr_intf
= intf_r1_s1
272 highest_pr_intf
= intf_r3_s1
280 "ip": SAME_VLAN_IP_1
["ip"],
281 "subnet": SAME_VLAN_IP_1
["subnet"],
292 "ip": SAME_VLAN_IP_2
["ip"],
293 "subnet": SAME_VLAN_IP_2
["subnet"],
304 "ip": SAME_VLAN_IP_3
["ip"],
305 "subnet": SAME_VLAN_IP_3
["subnet"],
316 "ip": SAME_VLAN_IP_4
["ip"],
317 "subnet": SAME_VLAN_IP_4
["subnet"],
325 add_interfaces_to_vlan(tgen
, vlan_input
)
330 "interface {}".format(intf_r1_s1
),
331 "no ip address {}".format(intf_r1_s1_addr
),
337 "interface {}".format(intf_r2_s1
),
338 "no ip address {}".format(intf_r2_s1_addr
),
344 "interface {}".format(intf_r3_s1
),
345 "no ip address {}".format(intf_r3_s1_addr
),
351 "interface {}".format(intf_i1_s1
),
352 "no ip address {}".format(intf_i1_s1_addr
),
357 result
= apply_raw_config(tgen
, raw_config
)
358 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
363 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
364 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
372 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
373 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
381 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
382 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
390 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
391 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
396 result
= apply_raw_config(tgen
, raw_config
)
397 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
399 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
403 "interface {}.{}".format(intf
, VLAN_1
),
404 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
408 result
= apply_raw_config(tgen
, raw_config
)
409 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
411 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
418 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
421 "group_addr_range": GROUP_RANGE_1
,
428 result
= create_pim_config(tgen
, topo
, input_dict
)
429 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
431 step("Send IGMP join for groups 226.1.1.1 to 226.1.1.5")
433 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
434 result
= app_helper
.run_join("i1", IGMP_JOIN_RANGE_1
, join_intf
=vlan_intf_i1_s1
)
435 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
437 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
439 step("Start traffic from R4 connected source")
441 result
= app_helper
.run_traffic("i2", IGMP_JOIN_RANGE_1
, "r5")
442 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
447 def pre_config_for_source_dr_tests(
448 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
451 API to do common pre-configuration for source test cases
455 * `tgen`: topogen object
456 * `topo`: input json data
457 * `tc_name`: caller test case name
458 * `highest_priority`: router which will be having highest DR priority
459 * `lowest_priority`: router which will be having lowest DR priority
462 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
464 step("Configure IGMP and PIM on switch connected receiver nodes")
465 step("Configure PIM on all upstream interfaces")
467 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
469 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
470 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
473 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
474 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
476 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
477 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
479 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
480 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
482 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
483 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
485 if lowest_priority
== "r1":
486 lowest_pr_intf
= intf_r1_s1
488 lowest_pr_intf
= intf_r3_s1
490 if highest_priority
== "r1":
491 highest_pr_intf
= intf_r1_s1
493 highest_pr_intf
= intf_r3_s1
501 "ip": SAME_VLAN_IP_1
["ip"],
502 "subnet": SAME_VLAN_IP_1
["subnet"],
513 "ip": SAME_VLAN_IP_2
["ip"],
514 "subnet": SAME_VLAN_IP_2
["subnet"],
525 "ip": SAME_VLAN_IP_3
["ip"],
526 "subnet": SAME_VLAN_IP_3
["subnet"],
537 "ip": SAME_VLAN_IP_4
["ip"],
538 "subnet": SAME_VLAN_IP_4
["subnet"],
546 add_interfaces_to_vlan(tgen
, vlan_input
)
551 "interface {}".format(intf_r1_s1
),
552 "no ip address {}".format(intf_r1_s1_addr
),
558 "interface {}".format(intf_r2_s1
),
559 "no ip address {}".format(intf_r2_s1_addr
),
565 "interface {}".format(intf_r3_s1
),
566 "no ip address {}".format(intf_r3_s1_addr
),
572 "interface {}".format(intf_i1_s1
),
573 "no ip address {}".format(intf_i1_s1_addr
),
578 result
= apply_raw_config(tgen
, raw_config
)
579 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
582 "Configure IGMP and PIM on switch connected receiver nodes , "
583 "configure PIM nbr with hello timer 1"
589 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
590 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
596 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
597 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
603 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
604 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
610 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
611 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
616 result
= apply_raw_config(tgen
, raw_config
)
617 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
619 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
623 "interface {}.{}".format(intf
, VLAN_1
),
624 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
628 result
= apply_raw_config(tgen
, raw_config
)
629 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
631 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
638 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
641 "group_addr_range": GROUP_RANGE_1
,
648 result
= create_pim_config(tgen
, topo
, input_dict
)
649 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
651 step("Configure IGMP on R5 port and send IGMP join for groups " "(226.1.1.1-5)")
653 intf_r5_i2
= topo
["routers"]["r5"]["links"]["i2"]["interface"]
655 "r5": {"igmp": {"interfaces": {intf_r5_i2
: {"igmp": {"version": "2"}}}}}
657 result
= create_igmp_config(tgen
, topo
, input_dict
)
658 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
660 input_src
= {"i2": topo
["routers"]["i2"]["links"]["r5"]["interface"]}
662 result
= app_helper
.run_join("i2", IGMP_JOIN_RANGE_1
, "r5")
663 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
665 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
667 step("Start traffic from Source node")
669 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
670 result
= app_helper
.run_traffic("i1", IGMP_JOIN_RANGE_1
, bind_intf
=vlan_intf_i1_s1
)
671 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
676 #####################################################
680 #####################################################
683 def test_pim_source_dr_functionality_while_rebooting_dr_non_dr_nodes_p1(request
):
685 Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
689 tc_name
= request
.node
.name
690 write_test_header(tc_name
)
692 # Creating configuration from JSON
693 app_helper
.stop_all_hosts()
695 check_router_status(tgen
)
696 reset_config_on_routers(tgen
)
697 clear_pim_interface_traffic(tgen
, topo
)
699 # Don"t run this test if we have any failure.
700 if tgen
.routers_have_failure():
701 pytest
.skip(tgen
.errors
)
703 result
= pre_config_for_source_dr_tests(tgen
, topo
, tc_name
, "r1", "r3")
704 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
706 step("R1 is the DR , verify using 'show ip pim interface json'")
708 vlan_intf_r1_s1
= "{}.{}".format(intf_r1_s1
, VLAN_1
)
712 "interfaces": {vlan_intf_r1_s1
: {"drAddress": SAME_VLAN_IP_3
["ip"]}}
716 result
= verify_pim_config(tgen
, input_dict_dr
)
717 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
720 "R2 is transit router for I1 to reach R4, mroute should have (s, g) mroute with "
721 "OIL towards R4, using 'show ip mroute json'"
724 "R2 (s, g) upstream should be in join state verify using "
725 "'show ip pim upstream json'"
728 "R1 has (S, G) mroute with NONE OIL and upstream as not joined, verify using "
729 "'show ip mroute json' 'show ip pim upstream json'"
732 source_i1
= SAME_VLAN_IP_4
["ip"]
736 "src_address": source_i1
,
738 "iif": "{}.{}".format(
739 topo
["routers"]["r1"]["links"]["s1"]["interface"], VLAN_1
744 "src_address": source_i1
,
745 "oil": topo
["routers"]["r2"]["links"]["r4"]["interface"],
746 "iif": "{}.{}".format(
747 topo
["routers"]["r2"]["links"]["s1"]["interface"], VLAN_1
752 for data
in input_dict_r1_r2
:
753 result
= verify_mroutes(
761 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
763 if data
["dut"] == "r2":
764 result
= verify_upstream_iif(
765 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
767 assert result
is True, "Testcase {} : Failed Error: {}".format(
771 result
= verify_upstream_iif(
779 assert result
is not True, (
780 "Testcase {} : Failed \n "
781 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
784 step("Reboot R3 node")
785 stop_router(tgen
, "r3")
788 "After reboot of R3 verify R1 continues to be DR, using 'show ip pim interface json'"
791 result
= verify_pim_config(tgen
, input_dict_dr
)
792 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
794 step("R3 should not have any mroute and upstream")
795 step("R2 has mroute with OIL towards R4 /R1 , verify using 'show ip mroute'")
797 "R2 has upstream with Join RejP state verify using 'show ip pim upstream json'"
799 step("R1 has mroute with none OIL and upstream with Not Join")
801 for data
in input_dict_r1_r2
:
802 result
= verify_mroutes(
810 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
812 if data
["dut"] == "r2":
813 result
= verify_upstream_iif(
814 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
816 assert result
is True, "Testcase {} : Failed Error: {}".format(
820 result
= verify_upstream_iif(
828 assert result
is not True, (
829 "Testcase {} : Failed \n "
830 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
833 step("Reboot R2 node")
834 stop_router(tgen
, "r2")
837 "After reboot of R2, R1 continues to be DR verify using 'show ip pim interface json'"
840 result
= verify_pim_config(tgen
, input_dict_dr
)
841 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
844 "R3 and R2 should not have any mroute and upstream , verify using "
845 "'show ip mroute json' 'show ip pim upstream json'"
847 step("R1 has mroute created with empty OIL, using 'show ip mroute json'")
849 "R1 has upstream with Not Join, Rej Prune , verify using 'show ip pim upstream json'"
852 for data
in input_dict_r1_r2
:
853 if data
["dut"] == "r1":
854 result
= verify_mroutes(
862 assert result
is True, "Testcase {} : Failed Error: {}".format(
866 result
= verify_upstream_iif(
874 assert result
is not True, (
875 "Testcase {} : Failed \n "
876 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
879 step("Reboot R1 node using FRR stop")
880 stop_router(tgen
, "r1")
883 "After stop of all the routers, verify upstream and mroutes should "
884 "not present in any of them"
887 for data
in input_dict_r1_r2
:
888 result
= verify_mroutes(
899 ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format(
903 step("start FRR for all the nodes")
904 start_router(tgen
, "r1")
905 start_router(tgen
, "r2")
906 start_router(tgen
, "r3")
908 step("After start of all the routers, R1 became DR")
910 result
= verify_pim_config(tgen
, input_dict_dr
)
911 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
913 for data
in input_dict_r1_r2
:
914 result
= verify_mroutes(
922 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
924 if data
["dut"] == "r2":
925 result
= verify_upstream_iif(
926 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
928 assert result
is True, "Testcase {} : Failed Error: {}".format(
932 write_test_footer(tc_name
)
935 if __name__
== "__main__":
936 args
= ["-s"] + sys
.argv
[1:]
937 sys
.exit(pytest
.main(args
))