summaryrefslogtreecommitdiffstats
path: root/tests/topotests/multicast_pim_sm_topo1
diff options
context:
space:
mode:
Diffstat (limited to 'tests/topotests/multicast_pim_sm_topo1')
-rw-r--r--tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json146
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py1608
2 files changed, 1754 insertions, 0 deletions
diff --git a/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json b/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json
new file mode 100644
index 0000000..cc20abb
--- /dev/null
+++ b/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json
@@ -0,0 +1,146 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32},
+ "routers": {
+ "l1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "i1": {"ipv4": "auto", "pim": "enable"},
+ "i6": {"ipv4": "auto", "pim": "enable"},
+ "i7": {"ipv4": "auto", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"}
+ },
+ "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 },
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1" :{
+ "igmp":{
+ "query": {"query-max-response-time": 40, "query-interval": 5},
+ "version": "2"
+ }
+ }
+ }
+ },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.7.0/24", "10.0.6.0/24", "10.0.9.0/24"],
+ "next_hop": "10.0.12.2"
+ },
+ {
+ "network": ["1.0.1.2/32", "1.0.3.5/32", "10.0.1.0/24", "1.0.2.2/32", "10.0.4.0/24", "10.0.3.0/24"],
+ "next_hop": "10.0.2.1"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i3": {"ipv4": "auto", "pim": "enable"}
+ },
+ "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 },
+ "static_routes": [{
+ "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24"],
+ "next_hop": "10.0.7.1"
+ },
+ {
+ "network": ["1.0.1.2/32", "10.0.8.0/24", "10.0.10.0/24", "10.0.4.0/24", "10.0.0.0/24", "10.0.11.0/24", "10.0.1.0/24", "10.0.2.0/24"],
+ "next_hop": "10.0.12.1"
+ }]
+ },
+ "f1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "i2": {"ipv4": "auto", "pim": "enable"},
+ "i8": {"ipv4": "auto", "pim": "enable"}
+ },
+ "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.12.0/24", "10.0.11.0/24"],
+ "next_hop": "10.0.7.2"
+ },
+ {
+ "network": ["1.0.2.2/32", "10.0.1.0/24", "10.0.0.0/24", "10.0.4.0/24", "1.0.1.2/32"],
+ "next_hop": "10.0.3.1"
+ }]
+ },
+ "c1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "i4": {"ipv4": "auto", "pim": "enable"}
+ },
+ "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.3.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.12.0/24", "10.0.10.0/24", "10.0.11.0/24"],
+ "next_hop": "10.0.2.2"
+ },
+ {
+ "network": ["10.0.5.0/24", "10.0.7.0/24", "1.0.3.5/32", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "10.0.4.0/24"],
+ "next_hop": "10.0.0.2"
+ }]
+ },
+ "c2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i5": {"ipv4": "auto", "pim": "enable"}
+ },
+ "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.7.0/24", "10.0.10.0/24", "10.0.11.0/24"],
+ "next_hop": "10.0.3.2"
+ },
+ {
+ "network": ["1.0.1.2/32", "10.0.4.0/24", "10.0.2.0/24"],
+ "next_hop": "10.0.0.1"
+ }]
+ },
+ "i1": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i2": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ },
+ "i3": {
+ "links": {
+ "r2": {"ipv4": "auto"}
+ }
+ },
+ "i4": {
+ "links": {
+ "c1": {"ipv4": "auto"}
+ }
+ },
+ "i5": {
+ "links": {
+ "c2": {"ipv4": "auto"}
+ }
+ },
+ "i6": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i7": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i8": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ }
+ }
+}
diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
new file mode 100755
index 0000000..b46885c
--- /dev/null
+++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
@@ -0,0 +1,1608 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test multicast pim sm:
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+Following tests are covered:
+1. TC_1_1: Verify Multicast data traffic with static RP, (*,g) and
+ (s,g) OIL updated correctly
+2. TC_1_2: Verify Multicast data traffic with static RP, (*,g) and
+ (s,g) OIL updated correctly
+3. TC_4: Verify removing the RP should not impact the multicast
+ data traffic
+4. TC_5: Verify (*,G) and (S,G) entry populated again after clear the
+ PIM nbr and mroute from FRR node
+5. TC_9: Verify (s,g) timeout from FHR and RP when same receive
+ exist in LHR , FHR and RP
+6. TC_19: Verify mroute detail when same receiver joining 5
+ different sources
+7. TC_16: Verify (*,G) and (S,G) populated correctly
+ when FRR is the transit router
+8. TC_23: Verify (S,G) should not create if RP is not reachable
+9. TC_24: Verify modification of IGMP query timer should get update
+ accordingly
+10. TC_25: Verify modification of IGMP max query response timer
+ should get update accordingly
+"""
+
+import os
+import sys
+import time
+from time import sleep
+import pytest
+
+pytestmark = pytest.mark.pimd
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ step,
+ apply_raw_config,
+ reset_config_on_routers,
+ shutdown_bringup_interface,
+ required_linux_kernel_version,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ create_igmp_config,
+ verify_igmp_groups,
+ verify_mroutes,
+ get_pim_interface_traffic,
+ verify_upstream_iif,
+ verify_pim_join,
+ clear_mroute,
+ clear_pim_interface_traffic,
+ verify_igmp_config,
+ McastTesterHelper,
+)
+from lib.topolog import logger
+from lib.topojson import build_config_from_json
+
+
+pytestmark = [pytest.mark.pimd]
+
+TOPOLOGY = """
+
+
+ i4-----c1-------------c2---i5
+ | |
+ | |
+ i1-----l1------r2-----f1---i2
+ | | | |
+ | | | |
+ i7 i6 i3 i8
+
+ Description:
+ i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP
+ join and traffic
+ l1 - LHR (last hop router)
+ f1 - FHR (first hop router)
+ r2 - FRR router
+ c1 - FRR router
+ c2 - FRR router
+"""
+
+# Global variables
+GROUP_RANGE = "225.0.0.0/8"
+IGMP_JOIN = "225.1.1.1"
+GROUP_RANGE_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+GROUP_RANGE_2 = [
+ "226.1.1.1/32",
+ "226.1.1.2/32",
+ "226.1.1.3/32",
+ "226.1.1.4/32",
+ "226.1.1.5/32",
+]
+IGMP_JOIN_RANGE_2 = ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"]
+
+GROUP_RANGE_3 = [
+ "227.1.1.1/32",
+ "227.1.1.2/32",
+ "227.1.1.3/32",
+ "227.1.1.4/32",
+ "227.1.1.5/32",
+]
+IGMP_JOIN_RANGE_3 = ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"]
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.19")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+ logger.info("Master Topology: \n {}".format(TOPOLOGY))
+
+ logger.info("Running setup_module to create topology")
+
+ testdir = os.path.dirname(os.path.realpath(__file__))
+ json_file = "{}/multicast_pim_sm_topo1.json".format(testdir)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, tgen.json_topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, tgen.json_topo)
+
+ # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
+ global app_helper
+ app_helper = McastTesterHelper(tgen)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ app_helper.cleanup()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+def test_multicast_data_traffic_static_RP_send_join_then_traffic_p0(request):
+ """
+ TC_1_1: Verify Multicast data traffic with static RP, (*,g) and
+ (s,g) OIL updated correctly
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)")
+
+ step("get joinRx value before join")
+ intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ state_dict = {"r2": {intf_r2_l1: ["joinRx"]}}
+ state_before = get_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_before, dict
+ ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format(
+ tc_name, state_before
+ )
+
+ result = app_helper.run_join("i1", IGMP_JOIN, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Send the IGMP join first and then start the traffic")
+
+ step("Configure RP on R2 (loopback interface) for the" " group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip mroute' showing correct RPF and OIF"
+ " interface for (*,G) and (S,G) entries on all the nodes"
+ )
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": intf_l1_r2, "oil": intf_l1_i1},
+ {"dut": "l1", "src_address": source, "iif": intf_l1_r2, "oil": intf_l1_i1},
+ {"dut": "r2", "src_address": "*", "iif": "lo", "oil": intf_r2_l1},
+ {"dut": "r2", "src_address": source, "iif": intf_r2_f1, "oil": intf_r2_l1},
+ {"dut": "f1", "src_address": source, "iif": intf_f1_i2, "oil": intf_f1_r2},
+ ]
+
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip pim upstream' showing correct OIL and IIF" " on all the nodes"
+ )
+ for data in input_dict:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("joinRx value after join sent")
+ state_after = get_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_after, dict
+ ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "l1 sent PIM (*,G) join to r2 verify using"
+ "'show ip pim interface traffic' on RP connected interface"
+ )
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("l1 sent PIM (S,G) join to f1 , verify using 'show ip pim join'")
+ dut = "f1"
+ interface = intf_f1_r2
+ result = verify_pim_join(tgen, topo, dut, interface, IGMP_JOIN)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request):
+ """
+ TC_1_2: Verify Multicast data traffic with static RP, (*,g) and
+ (s,g) OIL updated correctly
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure RP on R2 (loopback interface) for the" " group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Start traffic first and then send the IGMP join")
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)")
+ step("joinRx value before join sent")
+ state_dict = {"r2": {"r2-l1-eth2": ["joinRx"]}}
+ state_before = get_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_before, dict
+ ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = app_helper.run_join("i1", IGMP_JOIN, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip mroute' showing correct RPF and OIF"
+ " interface for (*,G) and (S,G) entries on all the nodes"
+ )
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "l1", "src_address": source, "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "r2", "src_address": "*", "iif": "lo", "oil": "r2-l1-eth2"},
+ {"dut": "r2", "src_address": source, "iif": "r2-f1-eth0", "oil": "r2-l1-eth2"},
+ {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"},
+ ]
+ # On timeout change from default of 80 to 120: failures logs indicate times 90+
+ # seconds for success on the 2nd entry in the above table. Using 100s here restores
+ # previous 80 retries with 2s wait if we assume .5s per vtysh/show ip mroute runtime
+ # (41 * (2 + .5)) == 102.
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN,
+ data["iif"],
+ data["oil"],
+ retry_timeout=102,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip pim upstream' showing correct OIL and IIF" " on all the nodes"
+ )
+ for data in input_dict:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("joinRx value after join sent")
+ state_after = get_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_after, dict
+ ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "l1 sent PIM (*,G) join to r2 verify using"
+ "'show ip pim interface traffic' on RP connected interface"
+ )
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("l1 sent PIM (S,G) join to f1 , verify using 'show ip pim join'")
+ dut = "f1"
+ interface = "f1-r2-eth3"
+ result = verify_pim_join(tgen, topo, dut, interface, IGMP_JOIN)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_clear_pim_neighbors_and_mroute_p0(request):
+ """
+ TC_5: Verify (*,G) and (S,G) entry populated again after clear the
+ PIM nbr and mroute from FRR node
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure static RP on c1 for group (225.1.1.1-5)")
+ input_dict = {
+ "c1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["c1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Enable IGMP on FRR1 interface and send IGMP join 225.1.1.1 "
+ "to 225.1.1.5 from different interfaces"
+ )
+ result = app_helper.run_join("i1", IGMP_JOIN_RANGE_1, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3, wait for SPT switchover")
+ result = app_helper.run_traffic("i2", IGMP_JOIN_RANGE_1, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify clear ip mroute (*,g) entries are populated by using "
+ "'show ip mroute' cli"
+ )
+
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-c1-eth0", "oil": "l1-i1-eth1"}
+ ]
+
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ step("Clear mroutes on l1")
+ clear_mroute(tgen, "l1")
+
+ step(
+ "After clear ip mroute (*,g) entries are re-populated again"
+ " with same OIL and IIF, verify using 'show ip mroute' and "
+ " 'show ip pim upstream' "
+ )
+
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip pim upstream' showing correct OIL and IIF" " on all the nodes"
+ )
+ for data in input_dict:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN
+ )
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_mroute_when_same_receiver_in_FHR_LHR_and_RP_p0(request):
+ """
+ TC_9: Verify (s,g) timeout from FHR and RP when same receive
+ exist in LHR , FHR and RP
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure RP on R2 (loopback interface) for the" " group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1) to R1")
+
+ input_dict = {
+ "f1": {
+ "igmp": {
+ "interfaces": {
+ "f1-i8-eth2": {
+ "igmp": {"version": "2", "query": {"query-interval": 15}}
+ }
+ }
+ }
+ },
+ "r2": {
+ "igmp": {
+ "interfaces": {
+ "r2-i3-eth1": {
+ "igmp": {"version": "2", "query": {"query-interval": 15}}
+ }
+ }
+ }
+ },
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i1": "i1-l1-eth0", "i8": "i8-f1-eth0", "i3": "i3-r2-eth0"}
+
+ for recvr, recvr_intf in input_join.items():
+ result = app_helper.run_join(recvr, IGMP_JOIN, join_intf=recvr_intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from R3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("IGMP is received on FRR1 , FRR2 , FRR3, using " "'show ip igmp groups'")
+ igmp_groups = {"l1": "l1-i1-eth1", "r2": "r2-i3-eth1", "f1": "f1-i8-eth2"}
+ for dut, interface in igmp_groups.items():
+ result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN, retry_timeout=80)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("(*,G) present on all the node with correct OIL" " using 'show ip mroute'")
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "l1", "src_address": source, "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "r2", "src_address": "*", "iif": "lo", "oil": "r2-i3-eth1"},
+ {"dut": "r2", "src_address": source, "iif": "r2-f1-eth0", "oil": "r2-i3-eth1"},
+ {"dut": "f1", "src_address": "*", "iif": "f1-r2-eth3", "oil": "f1-i8-eth2"},
+ {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-i8-eth2"},
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_mroute_when_same_receiver_joining_5_diff_sources_p0(request):
+ """
+ TC_19: Verify mroute detail when same receiver joining 5
+ different sources
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure static RP for (226.1.1.1-5) and (232.1.1.1-5)" " in c1")
+
+ _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3
+ _IGMP_JOIN_RANGE = IGMP_JOIN_RANGE_2 + IGMP_JOIN_RANGE_3
+
+ input_dict = {
+ "c1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["c1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": _GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure IGMP interface on FRR1 and FRR3 and send IGMP join"
+ "for group (226.1.1.1-5, 232.1.1.1-5)"
+ )
+
+ result = app_helper.run_join("i1", _IGMP_JOIN_RANGE, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "f1": {
+ "igmp": {
+ "interfaces": {
+ "f1-i8-eth2": {
+ "igmp": {"version": "2", "query": {"query-interval": 15}}
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = app_helper.run_join("i8", _IGMP_JOIN_RANGE, "f1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Send multicast traffic from all the sources to all the "
+ "receivers (226.1.1.1-5, 232.1.1.1-5)"
+ )
+
+ input_traffic = {
+ "i6": "i6-l1-eth0",
+ "i7": "i7-l1-eth0",
+ "i3": "i3-r2-eth0",
+ "i4": "i4-c1-eth0",
+ "i5": "i5-c2-eth0",
+ }
+
+ for src, src_intf in input_traffic.items():
+ result = app_helper.run_traffic(src, _IGMP_JOIN_RANGE, bind_intf=src_intf)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify (*,G) are created on FRR1 and FRR3 node " " 'show ip mroute' ")
+
+ source_i7 = topo["routers"]["i7"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i6 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0]
+ source_i3 = topo["routers"]["i3"]["links"]["r2"]["ipv4"].split("/")[0]
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-c1-eth0", "oil": "l1-i1-eth1"},
+ {
+ "dut": "l1",
+ "src_address": source_i5,
+ "iif": "l1-c1-eth0",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i3,
+ "iif": "l1-r2-eth4",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": "l1-i6-eth2",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i7,
+ "iif": "l1-i7-eth3",
+ "oil": "l1-i1-eth1",
+ },
+ {"dut": "f1", "src_address": "*", "iif": "f1-c2-eth0", "oil": "f1-i8-eth2"},
+ {
+ "dut": "f1",
+ "src_address": source_i5,
+ "iif": "f1-c2-eth0",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i3,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i6,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i7,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_2,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Stop the source one by one on FRR1")
+ input_intf = {"i6": "i6-l1-eth0", "i7": "i7-l1-eth0"}
+ for dut, intf in input_intf.items():
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ "After removing the source verify traffic is stopped"
+ " immediately and (S,G) got timeout in sometime"
+ )
+
+ logger.info("After shut, waiting for SG timeout")
+
+ input_dict = [
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": "l1-i6-eth2",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i7,
+ "iif": "l1-i7-eth3",
+ "oil": "l1-i1-eth1",
+ },
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_2,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n mroutes are still present \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ step(
+ "Source which is stopped got removed , other source"
+ " after still present verify using 'show ip mroute' "
+ )
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-c1-eth0", "oil": "l1-i1-eth1"},
+ {
+ "dut": "l1",
+ "src_address": source_i5,
+ "iif": "l1-c1-eth0",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i3,
+ "iif": "l1-r2-eth4",
+ "oil": "l1-i1-eth1",
+ },
+ {"dut": "f1", "src_address": "*", "iif": "f1-c2-eth0", "oil": "f1-i8-eth2"},
+ {
+ "dut": "f1",
+ "src_address": source_i5,
+ "iif": "f1-c2-eth0",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i3,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_2,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Start all the source again for all the receivers")
+ input_intf = {"i6": "i6-l1-eth0", "i7": "i7-l1-eth0"}
+ for dut, intf in input_intf.items():
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "After starting source all the mroute entries got populated, "
+ "no duplicate entries present in mroute verify 'show ip mroute'"
+ )
+
+ input_dict = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-c1-eth0", "oil": "l1-i1-eth1"},
+ {
+ "dut": "l1",
+ "src_address": source_i5,
+ "iif": "l1-c1-eth0",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i3,
+ "iif": "l1-r2-eth4",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": "l1-i6-eth2",
+ "oil": "l1-i1-eth1",
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i7,
+ "iif": "l1-i7-eth3",
+ "oil": "l1-i1-eth1",
+ },
+ {"dut": "f1", "src_address": "*", "iif": "f1-c2-eth0", "oil": "f1-i8-eth2"},
+ {
+ "dut": "f1",
+ "src_address": source_i5,
+ "iif": "f1-c2-eth0",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i3,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i6,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i7,
+ "iif": "f1-r2-eth3",
+ "oil": "f1-i8-eth2",
+ },
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_2,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_mroute_when_frr_is_transit_router_p2(request):
+ """
+ TC_16: Verify (*,G) and (S,G) populated correctly
+ when FRR is the transit router
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure static RP for (226.1.1.1-5) in c2")
+ input_dict = {
+ "c2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["c2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-5) to FRR1")
+ result = app_helper.run_join("i1", IGMP_JOIN_RANGE_1, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1-5 receivers")
+ result = app_helper.run_traffic("i2", IGMP_JOIN_RANGE_1, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ # Stop r2 router to make r2 router disabled from topology
+ input_intf = {"l1": "l1-r2-eth4", "f1": "f1-r2-eth3"}
+ for dut, intf in input_intf.items():
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ "FRR4 has (S,G) and (*,G) ,created where incoming interface"
+ " toward FRR3 and OIL toward R2, verify using 'show ip mroute'"
+ " 'show ip pim state' "
+ )
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict = [
+ {"dut": "c2", "src_address": "*", "iif": "lo", "oil": "c2-c1-eth0"},
+ {"dut": "c2", "src_address": source, "iif": "c2-f1-eth1", "oil": "c2-c1-eth0"},
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Stop multicast traffic from FRR3")
+ dut = "i2"
+ intf = "i2-f1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ logger.info("Waiting for 20 sec to get traffic to be stopped..")
+ sleep(20)
+
+ step("top IGMP receiver from FRR1")
+ dut = "i1"
+ intf = "i1-l1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ logger.info("Waiting for 20 sec to get mroutes to be flused out..")
+ sleep(20)
+
+ step(
+ "After stopping receiver (*,G) also got timeout from transit"
+ " router 'show ip mroute'"
+ )
+
+ result = verify_mroutes(
+ tgen, "c1", "*", IGMP_JOIN, "c1-c2-eth1", "c1-l1-eth0", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n mroutes are still present \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_verify_mroute_when_RP_unreachable_p1(request):
+ """
+ TC_23: Verify (S,G) should not create if RP is not reachable
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Configure RP on FRR2 (loopback interface) for " "the group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)")
+
+ result = app_helper.run_join("i1", IGMP_JOIN, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure one IGMP interface on FRR3 node and send IGMP" " join (225.1.1.1)")
+ input_dict = {
+ "f1": {
+ "igmp": {
+ "interfaces": {
+ "f1-i8-eth2": {
+ "igmp": {"version": "2", "query": {"query-interval": 15}}
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = app_helper.run_join("i8", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ # Verify mroutes are present in FRR3(f1)
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict = [
+ {"dut": "f1", "src_address": "*", "iif": "f1-r2-eth3", "oil": "f1-i8-eth2"},
+ {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-i8-eth2"},
+ ]
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the RP connected interface from f1 ( r2 to f1) link")
+ dut = "f1"
+ intf = "f1-r2-eth3"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ logger.info("Waiting for 20 sec to get mroutes to be flushed out..")
+ sleep(20)
+
+ step("Clear the mroute on f1")
+ clear_mroute(tgen, "f1")
+
+ step(
+ "After Shut the RP interface and clear the mroute verify all "
+ "(*,G) and (S,G) got timeout from FRR3 node , verify using "
+ " 'show ip mroute' "
+ )
+
+ result = verify_mroutes(
+ tgen, "f1", "*", IGMP_JOIN, "f1-r2-eth3", "f1-i8-eth2", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n mroutes are still present \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ step("IGMP groups are present verify using 'show ip igmp group'")
+ dut = "l1"
+ interface = "l1-i1-eth1"
+ result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_modify_igmp_query_timer_p0(request):
+ """
+ TC_24:
+ Verify modification of IGMP query timer should get update
+ accordingly
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)")
+ result = app_helper.run_join("i1", IGMP_JOIN, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP on R2 (loopback interface) for the" " group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip mroute' showing correct RPF and OIF"
+ " interface for (*,G) and (S,G) entries on all the nodes"
+ )
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_4 = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "l1", "src_address": source, "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"},
+ ]
+ for data in input_dict_4:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip pim upstream' showing correct OIL and IIF" " on all the nodes"
+ )
+ for data in input_dict_4:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Modify IGMP query interval default to other timer on FRR1" "3 times")
+ input_dict_1 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"query": {"query-interval": 20}}}
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"query": {"query-interval": 25}}}
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"query": {"query-interval": 30}}}
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_modify_igmp_max_query_response_timer_p0(request):
+ """
+ TC_25:
+ Verify modification of IGMP max query response timer
+ should get update accordingly
+ """
+
+ tgen = get_topogen()
+ topo = tgen.json_topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)")
+ result = app_helper.run_join("i1", IGMP_JOIN, "l1")
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure IGMP query response time to 10 deci-sec on FRR1")
+ input_dict_1 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 10},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP on R2 (loopback interface) for the" " group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1 receiver")
+ result = app_helper.run_traffic("i2", IGMP_JOIN, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip mroute' showing correct RPF and OIF"
+ " interface for (*,G) and (S,G) entries on all the nodes"
+ )
+
+ source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_5 = [
+ {"dut": "l1", "src_address": "*", "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "l1", "src_address": source, "iif": "l1-r2-eth4", "oil": "l1-i1-eth1"},
+ {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"},
+ ]
+ for data in input_dict_5:
+ result = verify_mroutes(
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verify 'show ip pim upstream' showing correct OIL and IIF" " on all the nodes"
+ )
+ for data in input_dict_5:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Delete the PIM and IGMP on FRR1")
+ raw_config = {"l1": {"raw_config": ["interface l1-i1-eth1", "no ip pim"]}}
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "delete": True,
+ "query": {"query-max-response-time": 10, "delete": True},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure PIM on FRR")
+ result = create_pim_config(tgen, topo["routers"])
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure max query response timer 100 decisec on FRR1")
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 100},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Remove and add max query response timer cli with different"
+ "timer 5 times on FRR1 Enable IGMP and IGMP version 2 on FRR1"
+ " on FRR1"
+ )
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 105},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 110},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 115},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "version": "2",
+ "query": {"query-max-response-time": 120},
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Enable IGMP and IGMP version 2 on FRR1 on FRR1")
+
+ input_dict_4 = {
+ "l1": {"igmp": {"interfaces": {"l1-i1-eth1": {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))