diff --git a/tests/topotests/multicast_pim6_dual_stack/multicast_pim6_dual_stack.json b/tests/topotests/multicast_pim6_dual_stack/multicast_pim6_dual_stack.json new file mode 100644 index 000000000000..c209d7f5ec6e --- /dev/null +++ b/tests/topotests/multicast_pim6_dual_stack/multicast_pim6_dual_stack.json @@ -0,0 +1,299 @@ +{ + "address_types": ["ipv4", "ipv6"], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback", "pim": "enable" ,"pim6": "enable"}, + "r2": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r3": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r4": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i1": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i2": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"} + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + }, + "r4": { + "dest_link": { + "r1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + }, + "r4": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback", "pim": "enable" ,"pim6": "enable"}, + "r1": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r4": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i3": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i4": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"} + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback", "pim": "enable" ,"pim6": "enable"}, + "r1": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r4": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i5": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i6": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"} + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback", "pim": "enable" ,"pim6": "enable"}, + "r1": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r2": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "r3": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i7": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"}, + "i8": {"ipv4": "auto", "ipv6": "auto", "pim": "enable" ,"pim6": "enable"} + }, + "bgp": { + "local_as": "400", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r4": {} + } + }, + "r2": { + "dest_link": { + "r4": {} + } + }, + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r4": {} + } + }, + "r2": { + "dest_link": { + "r4": {} + } + }, + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "i1": { + "links": { + "r1": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i2": { + "links": { + "r1": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i3": { + "links": { + "r2": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i4": { + "links": { + "r2": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i5": { + "links": { + "r3": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i6": { + "links": { + "r3": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i7": { + "links": { + "r4": {"ipv4": "auto", "ipv6": "auto"} + } + }, + "i8": { + "links": { + "r4": {"ipv4": "auto", "ipv6": "auto"} + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/multicast_pim6_dual_stack/test_multicast_pim6_dual_stack.py b/tests/topotests/multicast_pim6_dual_stack/test_multicast_pim6_dual_stack.py new file mode 100755 index 000000000000..f77e72ccc712 --- /dev/null +++ b/tests/topotests/multicast_pim6_dual_stack/test_multicast_pim6_dual_stack.py @@ -0,0 +1,5061 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 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 pim6 dual stack: + +1. Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from same interface + of FRR1 and source present on same interface in FRR4 +2. Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from different interface + of FRR1 and source present on different interface in FRR4 +3. Verify IPv4 and IPv6 mroute and upstream after killing PIMd and PIM6d +4. Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces +5. Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces +6. Verify IPv4 and IPv6 mroute and upstream after shut / no shut of upstream + interfaces when IPv4 and IPv6 mroute using different path +7. Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces +8. Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config +9. Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config +10. Verify IPv4 and IPv6 mroute and upstream after removing/adding IGMP and MLD config +11. Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config +12. Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config +""" + +import os +import sys +import json +import time +import pytest +import random +from time import sleep +import time +import datetime + +# 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, + reset_config_on_routers, + shutdown_bringup_interface, + create_static_routes, + required_linux_kernel_version, + socat_send_mld_join, + socat_send_pim6_traffic, + kill_socat, + kill_router_daemons, + start_router_daemons, + apply_raw_config, + stop_router, + start_router, +) +from lib.bgp import create_router_bgp +from lib.pim import ( + create_pim_config, + create_mld_config, + verify_mld_groups, + verify_mroutes, + verify_upstream_iif, + verify_multicast_traffic, + verify_pim_interface_traffic, + verify_pim_state, + verify_sg_traffic, + McastTesterHelper, + create_igmp_config, + verify_igmp_groups, + verify_pim_rp_info, + clear_pim6_mroute, + clear_mroute, +) +from lib.topolog import logger +from lib.topojson import build_config_from_json + +# Global variables +GROUP_RANGE_1 = [ + "ffaa::1/128", + "ffaa::2/128", + "ffaa::3/128", + "ffaa::4/128", + "ffaa::5/128", +] +MLD_JOIN_RANGE_1 = ["ffaa::1", "ffaa::2", "ffaa::3", "ffaa::4", "ffaa::5"] + +GROUP_RANGE_4 = [ + "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_1 = ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"] + + +GROUP_RANGE_2 = [ + "ffbb::1/128", + "ffbb::2/128", + "ffbb::3/128", + "ffbb::4/128", + "ffbb::5/128", +] +IGMP_JOIN_RANGE_2 = ["ffbb::1", "ffbb::2", "ffbb::3", "ffbb::4", "ffbb::5"] + +GROUP_RANGE_3 = [ + "ffcc::1/128", + "ffcc::2/128", + "ffcc::3/128", + "ffcc::4/128", + "ffcc::5/128", +] +IGMP_JOIN_RANGE_3 = ["ffcc::1", "ffcc::2", "ffcc::3", "ffcc::4", "ffcc::5"] + +r1_r2_links = [] +r1_r3_links = [] +r2_r1_links = [] +r3_r1_links = [] +r3_r4_links = [] +r2_r4_links = [] +r4_r2_links = [] +r4_r3_links = [] +HELLO_TIMER = 1 +HOLD_TIMER = 3 +SOURCE = "Static" +ASSERT_MSG = "Testcase {} : Failed Error: {}" + +pytestmark = [pytest.mark.pimd, pytest.mark.pim6d] + + +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("Running setup_module to create topology") + + testdir = os.path.dirname(os.path.realpath(__file__)) + json_file = "{}/multicast_pim6_dual_stack.json".format(testdir) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # 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() + kill_socat(tgen) + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Local APIs +# +##################################################### + + +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 verify_mroute_uptime(uptime_before, uptime_after): + """ + API to compare uptime for mroutes + + Parameters + ---------- + * `uptime_before` : Uptime dictionary for any particular instance + * `uptime_after` : Uptime dictionary for any particular instance + """ + for group in uptime_before.keys(): + for source in uptime_before[group].keys(): + if set(uptime_before[group]) != set(uptime_after[group]): + errormsg = ( + "mroute (%s, %s) has not come" + " up after mroute clear [FAILED!!]" % (source, group) + ) + return errormsg + + d1 = datetime.datetime.strptime(uptime_before[group][source], "%H:%M:%S") + d2 = datetime.datetime.strptime(uptime_after[group][source], "%H:%M:%S") + if d1 >= d2: + errormsg = "mroute (%s, %s) is not " "repopulated [FAILED!!]" % ( + source, + group, + ) + return errormsg + + logger.info("mroute (%s, %s) is " "repopulated [PASSED!!]", source, group) + + return True + + +def clear_mroute_uptime(uptime_before, uptime_after): + """ + API to compare uptime for mroutes + + Parameters + ---------- + * `uptime_before` : Uptime dictionary for any particular instance + * `uptime_after` : Uptime dictionary for any particular instance + """ + + for group in uptime_before.keys(): + for source in uptime_before[group].keys(): + if set(uptime_before[group]) != set(uptime_after[group]): + errormsg = ( + "mroute (%s, %s) has not come" + " up after mroute clear [FAILED!!]" % (source, group) + ) + return errormsg + + d1 = datetime.datetime.strptime(uptime_before[group][source], "%H:%M:%S") + d2 = datetime.datetime.strptime(uptime_after[group][source], "%H:%M:%S") + if d2 >= d1: + errormsg = "mroute (%s, %s) is not " "repopulated [FAILED!!]" % ( + source, + group, + ) + return errormsg + + logger.info("mroute (%s, %s) is " "repopulated [PASSED!!]", source, group) + + return True + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_ipv4_ipv6_mroutes_upstream_when_mld_and_igmp_join_sent_from_same_interface_p0( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from same interface + of FRR1 and source present on same interface in FRR4 + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("Verify show PIM6 interface traffic without any mld join") + intf_r1 = topo["routers"]["r1"]["links"]["r4"]["interface"] + state_dict = {"r1": {intf_r1: ["joinRx", "joinTx"]}} + + state_before_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_before_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + state_before_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_before_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif = topo["routers"]["r1"]["links"]["i1"]["interface"] + for dut, grp_addr in zip(["r1", "r1"], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, dut, oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, dut, "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i7": topo["routers"]["i7"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i7", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i7"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "Verify IP pimv6 join and IPv6 pimv6 join to FRR1 and check join is sent toward FHR" + "Join counts is increamented for both IPv4 and IPv6" + 'verify using "show ip pimv6 intrface traffic" "show ipv6 pimv6 interface traffic"' + ) + + state_after_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_after_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(state_before_v6, state_after_v6) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + state_after_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_after_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(state_before_v4, state_after_v4) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroutes_upstream_when_mld_and_igmp_join_sent_from_different_interface_p0( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from different interface + of FRR1 and source present on different interface in FRR4 + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i2: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("Verify show PIM6 interface traffic without any mld join") + intf_r1 = topo["routers"]["r1"]["links"]["r2"]["interface"] + state_dict = {"r1": {intf_r1: ["joinRx", "joinTx"]}} + + state_before_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_before_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + state_before_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_before_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i2": topo["routers"]["i2"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "Verify IP pimv6 join and IPv6 pimv6 join to FRR1 and check join is sent toward FHR" + "Join counts is increamented for both IPv4 and IPv6" + 'verify using "show ip pimv6 intrface traffic" "show ipv6 pimv6 interface traffic"' + ) + + state_after_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_after_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(state_before_v6, state_after_v6) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + state_after_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_after_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(state_before_v4, state_after_v4) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_when_mld_prune_send_igmp_still_running_visa_versa_p0( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from same interface + of FRR1 and source present on same interface in FRR4 + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif = topo["routers"]["r1"]["links"]["i1"]["interface"] + for dut, grp_addr in zip(["r1", "r1"], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, dut, oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, dut, "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i7": topo["routers"]["i7"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i7", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i7"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Kill iperf to send IGMP prune") + app_helper.stop_host("i1") + + step("No impact on IPv6 mroute and traffic") + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("IPv4 mroutes and join got removed") + result = verify_igmp_groups( + tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1, expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n IGMP join are" " still present \n Error: {}".format( + tc_name, result + ) + logger.info("Expected Behavior: {}".format(result)) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + 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)) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n upstream are" + " still present \n Error: {}".format(tc_name, result) + ) + logger.info("Expected Behavior: {}".format(result)) + + step("Send IGMP join and traffic again") + input_src = {"i7": topo["routers"]["i7"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i7", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Kill socat to send MLD prune") + kill_socat(tgen, dut="i1", action="remove_mld_join") + + step("verify no impact on IGMP traffic") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("MLD join and mroutes got removed") + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1, expected=False) + assert ( + result is not True + ), "Testcase {} : Failed \n MLD join are" " still present \n Error: {}".format( + tc_name, result + ) + logger.info("Expected Behavior: {}".format(result)) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + 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)) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n upstream are" + " still present \n Error: {}".format(tc_name, result) + ) + logger.info("Expected Behavior: {}".format(result)) + + step("send MLD join and traffic again") + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("verify IPv4 and IPv6 multicast traffic resume") + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify show PIM6 interface traffic without any mld join") + intf_r1 = topo["routers"]["r1"]["links"]["r4"]["interface"] + state_dict = {"r1": {intf_r1: ["joinRx", "joinTx"]}} + + state_before_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_before_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + state_before_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_before_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("send prune for MLD and IGMP at same time") + app_helper.stop_host("i1") + kill_socat(tgen, dut="i1", action="remove_mld_join") + + step("verify multicast traffic stopped") + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n ipv6 mcast traffic" + " still present \n Error: {}".format(tc_name, result) + ) + logger.info("Expected Behavior: {}".format(result)) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n ipv4 mcast traffic" + " still present \n Error: {}".format(tc_name, result) + ) + logger.info("Expected Behavior: {}".format(result)) + + step( + "Verify IP pimv6 join and IPv6 pimv6 join to FRR1 and check join is sent toward FHR" + "Join counts is increamented for both IPv4 and IPv6" + 'verify using "show ip pimv6 intrface traffic" "show ipv6 pimv6 interface traffic"' + ) + + state_after_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_after_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(state_before_v6, state_after_v6) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + state_after_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_after_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("Prune count increamented for IPv4 and IPv6 mcat grps ") + result = verify_state_incremented(state_before_v4, state_after_v4) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroutes_after_add_remove_ipv4_and_ipv6_RP_address_p0( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream when mld and MLD join sent from same interface + of FRR1 and source present on same interface in FRR4 + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i2: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i2": topo["routers"]["i2"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + uptime_before_v4 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_before_v4, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + uptime_before_v6 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_before_v6, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Shut PIMv4/v6 RP imterface from RP node") + shutdown_bringup_interface(tgen, "r2", "lo", False) + + step("verify PIMv4 and PIMv6 RP got removed") + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify (*,G) mroutes got removed") + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif, expected=False) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + step("verify (s,g) mroutes are intact") + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + uptime_after_v6 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v6, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + for data in input_dict_v4: + uptime_after_v4 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v4, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + result = verify_mroute_uptime(uptime_before_v4, uptime_after_v4) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroute_uptime(uptime_before_v6, uptime_after_v6) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_kill_PIMd_PIM6d_p1( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after killing PIMd and PIM6d + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i2: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("Verify show PIM6 interface traffic without any mld join") + intf_r1 = topo["routers"]["r1"]["links"]["r2"]["interface"] + state_dict = {"r1": {intf_r1: ["joinRx", "joinTx"]}} + + state_before_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_before_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + state_before_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_before_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i2": topo["routers"]["i2"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("stop PIM6d on R1 node") + kill_router_daemons(tgen, "r1", ["pim6d"]) + + step("MLD join removed form R1") + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1, expected=False) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("PIMv6 mroute removed from R1") + result = verify_upstream_iif(tgen, "r1", oif, "*", MLD_JOIN_RANGE_1, expected=False) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_mroutes( + tgen, "r1", "*", MLD_JOIN_RANGE_1, oif, iif1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + sleep(300) + + step("verfy on R4 node PIMV6 mroute OIL in none") + r4_iif = topo["routers"]["r4"]["links"]["i7"]["interface"] + result = verify_mroutes(tgen, "r4", source_v6, MLD_JOIN_RANGE_1, r4_iif, "none") + + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify no impact on PIMv4 mroutes") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Start PIM6d on R1 node") + start_router_daemons(tgen, "r1", ["pim6d"]) + sleep(20) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("stop PIM6d on R4 node") + kill_router_daemons(tgen, "r4", ["pim6d"]) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R4 for all the grps") + result = verify_sg_traffic( + tgen, "r4", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start PIM6d on R4 node") + start_router_daemons(tgen, "r1", ["pim6d"]) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R4 for all the grps") + result = verify_sg_traffic(tgen, "r4", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify killing PIMd daemon on R1 node") + step("stop PIMd on R1 node") + kill_router_daemons(tgen, "r1", ["pimd"]) + + step("IGMP joins are removed from R1") + result = verify_igmp_groups( + tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step("PIMv4 mroute and upstream removed from R1") + + result = verify_upstream_iif( + tgen, "r1", oif, "*", IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_mroutes( + tgen, "r1", "*", IGMP_JOIN_RANGE_1, oif, iif2, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + step("verify no impact on IPv6 mroutes and upstream") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verfy on R4 node PIMV4 mroute OIL in none") + r4_iif = topo["routers"]["r4"]["links"]["i8"]["interface"] + result = verify_mroutes(tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, r4_iif, "none") + + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start PIMd on R1 node") + start_router_daemons(tgen, "r1", ["pimd"]) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("stop PIMd on R4 node") + kill_router_daemons(tgen, "r4", ["pimd"]) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r4", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start PIMd on R4 node") + start_router_daemons(tgen, "r4", ["pimd"]) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r4", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_shut_noshut_receiver_interface_p1( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i2: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("Verify show PIM6 interface traffic without any mld join") + intf_r1 = topo["routers"]["r1"]["links"]["r2"]["interface"] + state_dict = {"r1": {intf_r1: ["joinRx", "joinTx"]}} + + state_before_v6 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6") + assert isinstance( + state_before_v6, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + state_before_v4 = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv4") + assert isinstance( + state_before_v4, dict + ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format( + tc_name, result + ) + + step("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i2": topo["routers"]["i2"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("shut MLD receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_i1, False) + + step("MLD join removed form R1") + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1, expected=False) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("PIMv6 mroute removed from R1") + result = verify_upstream_iif(tgen, "r1", oif, "*", MLD_JOIN_RANGE_1, expected=False) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_mroutes( + tgen, "r1", "*", MLD_JOIN_RANGE_1, oif, iif1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + step("verfy on R4 node PIMV6 mroute OIL in none") + r4_iif = topo["routers"]["r4"]["links"]["i7"]["interface"] + result = verify_mroutes(tgen, "r4", source_v6, MLD_JOIN_RANGE_1, r4_iif, "none") + + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify no impact on PIMv4 mroutes") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Noshut MLD receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_i1, True) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("shut IGMP receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_i2, False) + + step("IGMP joins are removed from R1") + result = verify_igmp_groups( + tgen, "r1", intf_r1_i2, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step("PIMv4 mroute and upstream removed from R1") + result = verify_upstream_iif( + tgen, "r1", oif, "*", IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_mroutes( + tgen, "r1", "*", IGMP_JOIN_RANGE_1, oif, iif2, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + step("verify no impact on IPv6 mroutes and upstream") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verfy on R4 node PIMV4 mroute OIL in none") + r4_iif = topo["routers"]["r4"]["links"]["i8"]["interface"] + result = verify_mroutes(tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, r4_iif, "none") + + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic not flowing on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("No shut IGMP receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_i2, True) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_shut_noshut_source_interface_p1( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD and IGMP on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i1"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + intf_r4_i7 = topo["routers"]["i7"]["links"]["r4"]["interface"] + step("shut MLD source port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r4_i7, False) + + step("MLD mroutes removed form R1 and R4") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verfy on R4 node PIMV6 mroute OIL in none") + intf_r4_i7 = topo["routers"]["r4"]["links"]["i7"]["interface"] + intf_r4_r1 = topo["routers"]["r4"]["links"]["r1"]["interface"] + + result = verify_mroutes( + tgen, "r4", source_v6, MLD_JOIN_RANGE_1, intf_r4_i7, intf_r4_r1, expected=False + ) + + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify no impact on PIMv4 mroutes") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Noshut MLD receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r4_i7, True) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + intf_r4_i8 = topo["routers"]["i8"]["links"]["r4"]["interface"] + step("shut IGMP receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r4_i8, False) + + step("IGMP mroutes are removed from R1") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verify no impact on IPv6 mroutes and upstream") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verfy on R4 node PIMV4 mroute OIL in none") + result = verify_mroutes( + tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, intf_r4_i8, intf_r4_r1 + ) + + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic not flowing on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("No shut IGMP receiver port from R1") + shutdown_bringup_interface(tgen, "r1", intf_r4_i8, True) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_shut_noshut_upstream_interface_p2( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after shut / no shut of upstream + interfaces when IPv4 and IPv6 mroute using different path + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + logger.info("shut R1 R4 interface to simulate topology") + + intf_r1_r4 = topo["routers"]["r1"]["links"]["r4"]["interface"] + shutdown_bringup_interface(tgen, "r1", intf_r1_r4, False) + + step("Enable MLD and IGMP on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r4": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r4"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r4"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "RP got configure on all the nodes OIL and IIF is updated" + 'verify using "show ip pimv6 rp-info" "show ipv6 pimv6 rp-info"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + rp_address = topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", MLD_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + rp_address = topo["routers"]["r4"]["links"]["lo"]["ipv4"].split("/")[0] + result = verify_pim_rp_info( + tgen, topo, "r1", IGMP_JOIN_RANGE_1, oif, rp_address, SOURCE + ) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i1"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i4"]["links"]["r2"]["interface"] + result = socat_send_pim6_traffic(tgen, "i4", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i5": topo["routers"]["i5"]["links"]["r3"]["interface"]} + result = app_helper.run_traffic("i5", IGMP_JOIN_RANGE_1, "r3") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i4"]["links"]["r2"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i5"]["links"]["r3"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r3"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r3", + "src_address": source_v4, + "iif": topo["routers"]["r3"]["links"]["i5"]["interface"], + "oil": topo["routers"]["r3"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r2", + "src_address": source_v6, + "iif": topo["routers"]["r2"]["links"]["i4"]["interface"], + "oil": topo["routers"]["r2"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r2"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + intf_r1_r2 = topo["routers"]["r1"]["links"]["r2"]["interface"] + step("shut IPV6 upstream interface from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_r2, False) + + step("MLD mroutes removed form R1 and R4") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("IPv6 mroute and upstream iif changed towards r3") + input_dict_v6_1 = [ + { + "dut": "r2", + "src_address": source_v6, + "iif": topo["routers"]["r2"]["links"]["i4"]["interface"], + "oil": topo["routers"]["r2"]["links"]["r4"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r3"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + for data in input_dict_v6_1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify no impact on PIMv4 mroutes") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + intf_r1_r3 = topo["routers"]["r1"]["links"]["r3"]["interface"] + step("shut IPv4 upstream interface R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_r3, False) + + step("IGMP mroutes are removed from R1") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + ## this sleep will be removed after prune issue fix #13039 + sleep(200) + step("verify IPv6 mroutes also removed from R1") + for data in input_dict_v6_1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verify ipv4 multicast traffic not flowing on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic not flowing on all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("No shut IPv4 upstream interface R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_r3, True) + step("No shut IPV6 upstream interface from R1") + shutdown_bringup_interface(tgen, "r1", intf_r1_r2, True) + + step("verify IPv4 and IPv6 mroute created and traffic resume") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_clear_ipv4_ipv6_mroutes_p2( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after shut / no shut of receiver interfaces + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD and IGMP on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i1"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + uptime_before_v4 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_before_v4, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + for data in input_dict_v6: + uptime_before_v6 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_before_v6, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + step("clear ipv4 mroute on R1") + clear_mroute(tgen, "r1") + + step("verify IPv4 mroutes after clear ipv4 mroutes") + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + uptime_after_v6 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v6, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + for data in input_dict_v4: + uptime_after_v4 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v4, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify mroutes uptime after clear ipv4 mroutes") + result = verify_mroute_uptime(uptime_before_v4, uptime_after_v4) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroute_uptime(uptime_before_v6, uptime_after_v6) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("clear ipv6 mroute on R1") + clear_pim6_mroute(tgen, "r1") + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + uptime_after_v6_1 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v6_1, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + for data in input_dict_v4: + uptime_after_v4_1 = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + return_uptime=True, + mwait=30, + ) + assert isinstance(uptime_after_v4_1, dict), ( + "Testcase {} : Failed \n uptime_before is not dictionary \n" + " Error: {}".format(tc_name, result) + ) + + step("verify mroutes uptime after clear ipv6 mroutes ") + result = verify_mroute_uptime(uptime_after_v4, uptime_after_v4_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = clear_mroute_uptime(uptime_after_v6, uptime_after_v6_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("clear IPv4 and IPv6 mroutes from R4") + clear_pim6_mroute(tgen, "r4") + clear_mroute(tgen, "r4") + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroute_upstream_after_removing_mld_and_igmp_config_p1( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after removing/adding IGMP and MLD config + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD and IGMP on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + iif1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + iif2 = topo["routers"]["r1"]["links"]["i1"]["interface"] + for iif, grp_addr in zip([iif2, iif1], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, "r1", oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, "r1", "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i8": topo["routers"]["i8"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i8", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i8"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i8"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Remove MLD config from receiver interface") + input_dict_1 = { + "r1": { + "mld": { + "interfaces": {intf_r1_i1: {"mld": {"version": "1", "delete": True}}} + } + } + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("After removing MLD config verify IPv6 (*,G) and (S,G) removed from R1 node") + result = verify_mroutes( + tgen, "r1", "*", MLD_JOIN_RANGE_1, oif, iif1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_upstream_iif(tgen, "r1", oif, "*", MLD_JOIN_RANGE_1, expected=False) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("No impact on R1 IPv4 IGMP receiver") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Remove IGMP config from receiver pots") + input_dict_1 = { + "r1": { + "igmp": { + "interfaces": {intf_r1_i1: {"igmp": {"version": "2", "delete": True}}} + } + } + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("After removing IGMP config verify IPv4 (*,G) and (S,G) removed from R1 node") + result = verify_mroutes( + tgen, "r1", "*", IGMP_JOIN_RANGE_1, oif, iif1, expected=False + ) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + result = verify_upstream_iif(tgen, "r1", oif, "*", MLD_JOIN_RANGE_1, expected=False) + assert result is not True, ASSERT_MSG.format(tc_name, result) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verify ipv4 multicast traffic on R1 for all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Add IGMP and MLD config and verify mroutes and upstream") + + step("Add MLD config from receiver interface") + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Add IGMP config from receiver pots") + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + write_test_footer(tc_name) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + r4_iif = (topo["routers"]["r4"]["links"]["i7"]["interface"],) + r4_oil = topo["routers"]["r4"]["links"]["r2"]["interface"] + + step("From source node verify OIL towards RP is removed") + result = verify_mroutes( + tgen, "r1", source_v6, MLD_JOIN_RANGE_1, r4_iif, r4_oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroutes( + tgen, "r1", source_v6, IGMP_JOIN_RANGE_1, r4_iif, r4_oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic on R1 for all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + +def test_ipv4_ipv6_mroutes_upstream_after_removing_pimv4_and_pimv6_config_p1( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + iif = topo["routers"]["r1"]["links"]["i1"]["interface"] + for dut, grp_addr in zip(["r1", "r1"], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, dut, oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, dut, "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i7": topo["routers"]["i7"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i7", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i7"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Remove pimv6 from source interface on FHR") + intf_r4_i7 = topo["routers"]["r4"]["links"]["i7"]["interface"] + raw_config = { + "r4": {"raw_config": ["interface {}".format(intf_r4_i7), "no ipv6 pim"]} + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + iif = topo["routers"]["r4"]["links"]["i7"]["interface"] + oil = topo["routers"]["r4"]["links"]["r1"]["interface"] + + step("'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf'" " removed from R4") + + result = verify_mroutes( + tgen, "r4", source_v6, MLD_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v6, MLD_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic stop all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("no impcat seen on IPv4 routes") + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("R1 IPv6 mroute timeout") + logger.info("Sleeping for 300sec for mroute timeout on R1") + sleep(300) + iif = topo["routers"]["r1"]["links"]["r4"]["interface"] + oil = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mroutes( + tgen, "r1", source_v6, MLD_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r1", iif, source_v6, MLD_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Add pimv6 from source interface on FHR") + raw_config = {"r4": {"raw_config": ["interface {}".format(intf_r4_i7), "ipv6 pim"]}} + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Remove pimv4 from source interface on FHR") + raw_config = { + "r4": {"raw_config": ["interface {}".format(intf_r4_i7), "no ip pim"]} + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroutes( + tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v4, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("no impact on IPv6 traffic") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Add pimv4 from source interface on FHR") + raw_config = {"r4": {"raw_config": ["interface {}".format(intf_r4_i7), "ip pim"]}} + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_ipv4_ipv6_mroutes_upstream_after_FRR_services_and_zebra_restart_p2( + request, +): + """ + Verify IPv4 and IPv6 mroute and upstream after removing/adding PIMd and PIM6d config + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Done in base config: " "Configure EBGP peering between all the nodes") + + step("Done in base config: " "Enable PIM6 on all the interfaces of all the nodes") + + step("Enable MLD on receiver interface") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict_1 = { + "r1": {"mld": {"interfaces": {intf_r1_i1: {"mld": {"version": "1"}}}}} + } + result = create_mld_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Enable IGMP on receiver interface on same interface") + + input_dict_1 = { + "r1": {"igmp": {"interfaces": {intf_r1_i1: {"igmp": {"version": "2"}}}}} + } + result = create_igmp_config(tgen, topo, input_dict_1) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure RP on FRR2 loopback interface for IPv4 and IPv6 group address") + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE_4, + } + ] + }, + "pim6": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv6"].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("send mld join (ffaa::1-5) from R1") + intf = topo["routers"]["i1"]["links"]["r1"]["interface"] + intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0] + result = socat_send_mld_join( + tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip + ) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Send IGMP joins from DUT for group range 225.1.1.1-5") + input_join = { + "i1": topo["routers"]["i1"]["links"]["r1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step( + "IPv4 mld and IPv6 MLD join received on R1 from same interface" + 'verify using "show ipv6 mldgroups" and "show ipv6 mld groups"' + ) + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + result = verify_mld_groups(tgen, "r1", intf_r1_i1, MLD_JOIN_RANGE_1) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_igmp_groups(tgen, "r1", intf_r1_i1, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 (*,G) mroute and upstream created OIL" + 'and IIF updated using "show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + oif = topo["routers"]["r1"]["links"]["r2"]["interface"] + iif = topo["routers"]["r1"]["links"]["i1"]["interface"] + for dut, grp_addr in zip(["r1", "r1"], [IGMP_JOIN_RANGE_1, MLD_JOIN_RANGE_1]): + step("r1: Verify upstream IIF interface") + result = verify_upstream_iif(tgen, dut, oif, "*", grp_addr) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step("r1: Verify ip mroutes") + result = verify_mroutes(tgen, dut, "*", grp_addr, oif, iif) + assert result is True, ASSERT_MSG.format(tc_name, result) + + step( + "Send IPv4 and IPv6 multicast traffic from FRR4 same interface" + "group range (FF05::1 -FF05::5 and 226.1.1.1 -226.1.1.5" + ) + + intf = topo["routers"]["i7"]["links"]["r4"]["interface"] + result = socat_send_pim6_traffic(tgen, "i7", "UDP6-SEND", MLD_JOIN_RANGE_1, intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_src = {"i7": topo["routers"]["i7"]["links"]["r4"]["interface"]} + result = app_helper.run_traffic("i7", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "(S,G) IPv4 and IPv6 mroute /upsteam created on FRR1 and FRR4" + '"IIF and OIL updated using show ipv6 mroute json" "show ipv6 mroute json"' + '"show ipv6 pim upstream json" "show ipv6 upstream json"' + ) + + source_v6 = topo["routers"]["i7"]["links"]["r4"]["ipv6"].split("/")[0] + + source_v4 = topo["routers"]["i7"]["links"]["r4"]["ipv4"].split("/")[0] + + input_dict_v4 = [ + { + "dut": "r1", + "src_address": source_v4, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r4", + "src_address": source_v4, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + ] + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + input_dict_v6 = [ + { + "dut": "r4", + "src_address": source_v6, + "iif": topo["routers"]["r4"]["links"]["i7"]["interface"], + "oil": topo["routers"]["r4"]["links"]["r1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_v6, + "iif": topo["routers"]["r1"]["links"]["r4"]["interface"], + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + ] + + step( + "'show ipv6 pim upstream' and 'show ipv6 pim upstream-rpf' showing" + " correct OIL and IIF on all the nodes" + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step( + "IPv4 and IPv6 traffic updated per (S,G)" + "show ipv6 multicast count ,show ip multicast count" + ) + + step("verify ipv6 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + tgen.mininet_cli() + step("stop FRR services on R1") + stop_router(tgen, "r1") + iif = topo["routers"]["r4"]["links"]["i7"]["interface"] + oil = topo["routers"]["r4"]["links"]["r1"]["interface"] + intf_r4_i7 = topo["routers"]["r4"]["links"]["i7"]["interface"] + result = verify_mroutes( + tgen, "r4", source_v6, MLD_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v6, MLD_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroutes( + tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v4, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start FRR services on R1 ") + start_router(tgen, "r1") + step("IPv4 and IPv6 mroutes recovered") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("stop FRR services on R4 ") + stop_router(tgen, "r4") + + for data in input_dict_v4: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + MLD_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("verify ipv4 multicast traffic on all the grps") + result = verify_sg_traffic( + tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume all the grps") + result = verify_sg_traffic( + tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6", expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start FRR services on R4 ") + start_router(tgen, "r4") + + step("IPv4 and IPv6 mroutes recovered") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("stop Zebra process on R1") + kill_router_daemons(tgen, "r1", ["zebra"]) + + step("verify Mroute removed from R4") + result = verify_mroutes( + tgen, "r4", source_v6, MLD_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v6, MLD_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_mroutes( + tgen, "r4", source_v4, IGMP_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, "r4", iif, source_v4, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("start zebra daemon on R1") + start_router_daemons(tgen, "r1", ["zebra"]) + + step("IPv4 and IPv6 mroutes recovered") + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_v6: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + MLD_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume on all the grps") + result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source_v6, "ipv6") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify ipv6 multicast traffic resume all the grps") + result = verify_sg_traffic(tgen, "r1", IGMP_JOIN_RANGE_1, source_v4, "ipv4") + assert result is True, "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))