summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/topotests/example-test/test_template.py12
-rwxr-xr-xtests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py13
-rwxr-xr-xtests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py13
-rwxr-xr-xtests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py13
-rw-r--r--tests/topotests/lib/pim.py161
-rw-r--r--tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json140
-rw-r--r--tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json137
-rwxr-xr-xtests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py4607
-rwxr-xr-xtests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py1120
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_chaos.json166
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_chaos.py576
-rw-r--r--tests/topotests/pytest.ini31
12 files changed, 6930 insertions, 59 deletions
diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py
index 4305e0199f..973303b830 100644
--- a/tests/topotests/example-test/test_template.py
+++ b/tests/topotests/example-test/test_template.py
@@ -44,6 +44,18 @@ from lib.topolog import logger
from mininet.topo import Topo
+#TODO: select markers based on daemons used during test
+# pytest module level markers
+"""
+pytestmark = pytest.mark.bfdd # single marker
+pytestmark = [
+ pytest.mark.bgpd,
+ pytest.mark.ospfd,
+ pytest.mark.ospf6d
+] # multiple markers
+"""
+
+
class TemplateTopo(Topo):
"Test topology builder"
diff --git a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py
index f24f463b8a..cd48716905 100755
--- a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py
+++ b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py
@@ -53,6 +53,19 @@ from lib.topolog import logger
from lib.bgp import verify_bgp_convergence
from lib.topojson import build_topo_from_json, build_config_from_json
+
+#TODO: select markers based on daemons used during test
+# pytest module level markers
+"""
+pytestmark = pytest.mark.bfdd # single marker
+pytestmark = [
+ pytest.mark.bgpd,
+ pytest.mark.ospfd,
+ pytest.mark.ospf6d
+] # multiple markers
+"""
+
+
# Reading the data from JSON File for topology and configuration creation
jsonFile = "{}/example_topojson_multiple_links.json".format(CWD)
try:
diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py
index 3ae3c9f4fe..0c72e30044 100755
--- a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py
+++ b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py
@@ -52,6 +52,19 @@ from lib.topolog import logger
from lib.bgp import verify_bgp_convergence
from lib.topojson import build_topo_from_json, build_config_from_json
+
+#TODO: select markers based on daemons used during test
+# pytest module level markers
+"""
+pytestmark = pytest.mark.bfdd # single marker
+pytestmark = [
+ pytest.mark.bgpd,
+ pytest.mark.ospfd,
+ pytest.mark.ospf6d
+] # multiple markers
+"""
+
+
# Reading the data from JSON File for topology and configuration creation
jsonFile = "{}/example_topojson.json".format(CWD)
diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py
index 06fa2f4626..d05ad6db21 100755
--- a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py
+++ b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py
@@ -54,6 +54,19 @@ from lib.topolog import logger
from lib.bgp import verify_bgp_convergence
from lib.topojson import build_topo_from_json, build_config_from_json
+
+#TODO: select markers based on daemons used during test
+# pytest module level markers
+"""
+pytestmark = pytest.mark.bfdd # single marker
+pytestmark = [
+ pytest.mark.bgpd,
+ pytest.mark.ospfd,
+ pytest.mark.ospf6d
+] # multiple markers
+"""
+
+
# Reading the data from JSON File for topology and configuration creation
jsonFile = "{}/example_topojson.json".format(CWD)
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index 6bb1326519..294f60bf68 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -539,7 +539,8 @@ def configure_pim_force_expire(tgen, topo, input_dict, build=False):
#############################################
# Verification APIs
#############################################
-def verify_pim_neighbors(tgen, topo, dut=None, iface=None):
+@retry(attempts=6, wait=2, return_is_str=True)
+def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
"""
Verify all PIM neighbors are up and running, config is verified
using "show ip pim neighbor" cli
@@ -550,10 +551,11 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None):
* `topo` : json file data
* `dut` : dut info
* `iface` : link for which PIM nbr need to check
+ * `nbr_ip` : neighbor ip of interface
Usage
-----
- result = verify_pim_neighbors(tgen, topo, dut, link)
+ result = verify_pim_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)
Returns
-------
@@ -1530,8 +1532,8 @@ def verify_pim_interface_traffic(tgen, input_dict):
return output_dict
-@retry(attempts=31, wait=2, return_is_str=True)
-def verify_pim_interface(tgen, topo, dut):
+@retry(attempts=21, wait=2, return_is_str=True)
+def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
"""
Verify all PIM interface are up and running, config is verified
using "show ip pim interface" cli
@@ -1541,10 +1543,12 @@ def verify_pim_interface(tgen, topo, dut):
* `tgen`: topogen object
* `topo` : json file data
* `dut` : device under test
+ * `interface` : interface name
+ * `interface_ip` : interface ip address
Usage
-----
- result = verify_pim_interfacetgen, topo, dut)
+ result = verify_pim_interfacetgen, topo, dut, interface=ens192, interface_ip=20.1.1.1)
Returns
-------
@@ -1560,56 +1564,55 @@ def verify_pim_interface(tgen, topo, dut):
logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
rnode = tgen.routers()[dut]
- show_ip_pim_interface_json = run_frr_cmd(
- rnode, "show ip pim interface json", isjson=True
- )
-
- for destLink, data in topo["routers"][dut]["links"].items():
- if "type" in data and data["type"] == "loopback":
- continue
+ show_ip_pim_interface_json = rnode.\
+ vtysh_cmd("show ip pim interface json", isjson=True)
+
+ logger.info("show_ip_pim_interface_json: \n %s",
+ show_ip_pim_interface_json)
+
+ if interface_ip:
+ if interface in show_ip_pim_interface_json:
+ pim_intf_json = show_ip_pim_interface_json[interface]
+ if pim_intf_json["address"] != interface_ip:
+ errormsg = ("[DUT %s]: PIM interface "
+ "ip is not correct "
+ "[FAILED]!! Expected : %s, Found : %s"
+ %(dut, pim_intf_json["address"],interface_ip))
+ return errormsg
+ else:
+ logger.info("[DUT %s]: PIM interface "
+ "ip is correct "
+ "[Passed]!! Expected : %s, Found : %s"
+ %(dut, pim_intf_json["address"],interface_ip))
+ return True
+ else:
+ for destLink, data in topo["routers"][dut]["links"].items():
+ if "type" in data and data["type"] == "loopback":
+ continue
- if "pim" in data and data["pim"] == "enable":
- pim_interface = data["interface"]
- pim_intf_ip = data["ipv4"].split("/")[0]
+ if "pim" in data and data["pim"] == "enable":
+ pim_interface = data["interface"]
+ pim_intf_ip = data["ipv4"].split("/")[0]
- if pim_interface in show_ip_pim_interface_json:
- pim_intf_json = show_ip_pim_interface_json[pim_interface]
+ if pim_interface in show_ip_pim_interface_json:
+ pim_intf_json = show_ip_pim_interface_json\
+ [pim_interface]
# Verifying PIM interface
- if (
- pim_intf_json["address"] != pim_intf_ip
- and pim_intf_json["state"] != "up"
- ):
- errormsg = (
- "[DUT %s]: PIM interface: %s "
- "PIM interface ip: %s, status check "
- "[FAILED]!! Expected : %s, Found : %s"
- % (
- dut,
- pim_interface,
- pim_intf_ip,
- pim_interface,
- pim_intf_json["state"],
- )
- )
+ if pim_intf_json["address"] != pim_intf_ip and \
+ pim_intf_json["state"] != "up":
+ errormsg = ("[DUT %s]: PIM interface: %s "
+ "PIM interface ip: %s, status check "
+ "[FAILED]!! Expected : %s, Found : %s"
+ %(dut, pim_interface, pim_intf_ip,
+ pim_interface, pim_intf_json["state"]))
return errormsg
- logger.info(
- "[DUT %s]: PIM interface: %s, "
- "interface ip: %s, status: %s"
- " [PASSED]!!",
- dut,
- pim_interface,
- pim_intf_ip,
- pim_intf_json["state"],
- )
- else:
- errormsg = (
- "[DUT %s]: PIM interface: %s "
- "PIM interface ip: %s, is not present "
- % (dut, pim_interface, pim_intf_ip,)
- )
- return errormsg
+ logger.info("[DUT %s]: PIM interface: %s, "
+ "interface ip: %s, status: %s"
+ " [PASSED]!!",
+ dut, pim_interface, pim_intf_ip,
+ pim_intf_json["state"])
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1846,7 +1849,6 @@ def clear_ip_mroute_verify(tgen, dut):
rnode = tgen.routers()[dut]
- # sleep(60)
logger.info("[DUT: %s]: IP mroutes uptime before clear", dut)
mroute_json_1 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
@@ -3387,3 +3389,62 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
+
+
+@retry(attempts=21, wait=2, return_is_str=True)
+def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
+ """
+ Verify all IGMP interface are up and running, config is verified
+ using "show ip igmp interface" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo` : json file data
+ * `dut` : device under test
+ * `igmp_iface` : interface name
+ * `interface_ip` : interface ip address
+
+ Usage
+ -----
+ result = verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router in tgen.routers():
+ if router != dut:
+ continue
+
+ logger.info("[DUT: %s]: Verifying PIM interface status:",
+ dut)
+
+ rnode = tgen.routers()[dut]
+ show_ip_igmp_interface_json = \
+ run_frr_cmd(rnode, "show ip igmp interface json", isjson=True)
+
+ if igmp_iface in show_ip_igmp_interface_json:
+ igmp_intf_json = show_ip_igmp_interface_json[igmp_iface]
+ # Verifying igmp interface
+ if igmp_intf_json["address"] != interface_ip:
+ errormsg = ("[DUT %s]: igmp interface ip is not correct "
+ "[FAILED]!! Expected : %s, Found : %s"
+ %(dut, igmp_intf_json["address"], interface_ip))
+ return errormsg
+
+ logger.info("[DUT %s]: igmp interface: %s, "
+ "interface ip: %s"
+ " [PASSED]!!",
+ dut, igmp_iface, interface_ip)
+ else:
+ errormsg = ("[DUT %s]: igmp interface: %s "
+ "igmp interface ip: %s, is not present "
+ %(dut, igmp_iface, interface_ip))
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
diff --git a/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json
new file mode 100644
index 0000000000..f582f4929d
--- /dev/null
+++ b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json
@@ -0,0 +1,140 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32},
+ "routers": {
+ "l1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "i1": {"ipv4": "auto", "pim": "enable"},
+ "i6": {"ipv4": "auto", "pim": "enable"},
+ "i7": {"ipv4": "auto", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"}
+ },
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1" :{
+ "igmp":{
+ "version": "2"
+ }
+ }
+ }
+ },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.9.0/24", "1.0.3.5/32"],
+ "next_hop": "10.0.12.2"
+ },
+ {
+ "network": ["1.0.1.2/32", "1.0.3.5/32", "10.0.1.0/24", "1.0.2.2/32", "10.0.4.0/24"],
+ "next_hop": "10.0.2.1"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i3": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "1.0.3.5/32"],
+ "next_hop": "10.0.7.1"
+ },
+ {
+ "network": ["1.0.1.2/32", "10.0.8.0/24", "10.0.10.0/24", "10.0.4.0/24", "10.0.11.0/24", "10.0.1.0/24"],
+ "next_hop": "10.0.12.1"
+ }]
+ },
+ "f1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "i2": {"ipv4": "auto", "pim": "enable"},
+ "i8": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"],
+ "next_hop": "10.0.7.2"
+ },
+ {
+ "network": ["1.0.2.2/32", "10.0.1.0/24", "10.0.4.0/24", "1.0.1.2/32"],
+ "next_hop": "10.0.3.1"
+ }]
+ },
+ "c1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "i4": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"],
+ "next_hop": "10.0.2.2"
+ },
+ {
+ "network": ["10.0.5.0/24", "10.0.7.0/24", "1.0.3.5/32", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "10.0.4.0/24"],
+ "next_hop": "10.0.0.2"
+ }]
+ },
+ "c2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i5": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"],
+ "next_hop": "10.0.3.2"
+ },
+ {
+ "network": ["1.0.1.2/32", "10.0.4.0/24"],
+ "next_hop": "10.0.0.1"
+ }]
+ },
+ "i1": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i2": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ },
+ "i3": {
+ "links": {
+ "r2": {"ipv4": "auto"}
+ }
+ },
+ "i4": {
+ "links": {
+ "c1": {"ipv4": "auto"}
+ }
+ },
+ "i5": {
+ "links": {
+ "c2": {"ipv4": "auto"}
+ }
+ },
+ "i6": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i7": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i8": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ }
+ }
+}
diff --git a/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json
new file mode 100644
index 0000000000..4635dac7d2
--- /dev/null
+++ b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json
@@ -0,0 +1,137 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32},
+ "routers": {
+ "l1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "i1": {"ipv4": "auto", "pim": "enable"},
+ "i6": {"ipv4": "auto", "pim": "enable"},
+ "i7": {"ipv4": "auto", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"}
+ },
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1" :{
+ "igmp":{
+ "version": "2"
+ }
+ }
+ }
+ },
+ "static_routes": [{
+ "network": ["10.0.4.0/24", "10.0.3.1/24"],
+ "next_hop": "10.0.12.2"
+ },
+ {
+ "network": ["10.0.1.2/24"],
+ "next_hop": "10.0.2.1"
+ }]
+
+ },
+
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i3": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["10.0.4.0/24","10.0.3.1/24"],
+ "next_hop": "10.0.7.1"
+ },
+ {
+ "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"],
+ "next_hop": "10.0.12.1"
+ }]
+ },
+ "f1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r2": {"ipv4": "auto", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "i2": {"ipv4": "auto", "pim": "enable"},
+ "i8": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["10.0.4.0/24","10.0.3.1/24"],
+ "next_hop": "10.0.3.1"
+ },
+ {
+ "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"],
+ "next_hop": "10.0.7.2"
+ }]
+ },
+ "c1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c2": {"ipv4": "auto", "pim": "enable"},
+ "l1": {"ipv4": "auto", "pim": "enable"},
+ "i4": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [{
+ "network": ["1.0.4.11/32","10.0.4.2/24", "10.0.3.1/24"],
+ "next_hop": "10.0.2.2"
+ }]
+
+
+ },
+ "c2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "c1": {"ipv4": "auto", "pim": "enable"},
+ "f1": {"ipv4": "auto", "pim": "enable"},
+ "i5": {"ipv4": "auto", "pim": "enable"}
+ },
+ "static_routes": [
+ {
+ "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"],
+ "next_hop": "10.0.3.2"
+ }]
+ },
+ "i1": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i2": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ },
+ "i3": {
+ "links": {
+ "r2": {"ipv4": "auto"}
+ }
+ },
+ "i4": {
+ "links": {
+ "c1": {"ipv4": "auto"}
+ }
+ },
+ "i5": {
+ "links": {
+ "c2": {"ipv4": "auto"}
+ }
+ },
+ "i6": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i7": {
+ "links": {
+ "l1": {"ipv4": "auto"}
+ }
+ },
+ "i8": {
+ "links": {
+ "f1": {"ipv4": "auto"}
+ }
+ }
+ }
+}
diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py
new file mode 100755
index 0000000000..d31d7ace92
--- /dev/null
+++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py
@@ -0,0 +1,4607 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test multicast pim sm:
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+Following tests are covered:
+
+1. verify oil when join prune sent scenario_1 p0
+2. verify oil when join prune sent scenario_2 p0
+3. shut noshut source interface when upstream cleared from LHR p0(
+4. shut noshut receiver interface when upstream cleared from LHR p0(
+5. verify igmp clis p0
+6. verify igmp cli generate query once p0
+7. verify remove add igmp config to receiver interface p0
+8. verify remove add igmp commands when pim configured p0
+9. verify remove add pim commands when igmp configured p0
+10. pim dr priority p0
+11. pim hello timer p0
+12. Verify mroute after removing RP sending IGMP prune p2
+13. Verify prune is sent to LHR and FHR when PIM nbr went down
+14. Verify mroute flag in LHR and FHR node
+15. Verify IGMP prune processed correctly when same join received from IGMP and PIM
+16. Verify multicast traffic flowing fine, when LHR connected to RP
+17. Verify multicast traffic is flowing fine when FHR is connected to RP
+"""
+
+import os
+import re
+import sys
+import json
+import time
+import datetime
+import pytest
+
+# 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 mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ step,
+ iperfSendIGMPJoin,
+ addKernelRoute,
+ reset_config_on_routers,
+ iperfSendTraffic,
+ kill_iperf,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router,
+ start_router_daemons,
+ stop_router,
+ apply_raw_config,
+ add_interfaces_to_vlan,
+ tcpdump_capture_start,
+ tcpdump_capture_stop,
+ LOGDIR,
+ check_router_status,
+ required_linux_kernel_version,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ create_igmp_config,
+ verify_igmp_groups,
+ verify_ip_mroutes,
+ clear_ip_mroute_verify,
+ clear_ip_mroute,
+ clear_ip_pim_interface_traffic,
+ verify_igmp_config,
+ verify_pim_neighbors,
+ verify_pim_config,
+ verify_pim_interface,
+ verify_upstream_iif,
+ verify_multicast_traffic,
+ verify_pim_rp_info,
+ get_refCount_for_mroute,
+ verify_multicast_flag_state,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/multicast_pim_sm_topo3.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+TOPOLOGY = """
+
+ i4-----c1-------------c2---i5
+ | |
+ | |
+ i1-----l1------r2-----f1---i2
+ | | | |
+ | | | |
+ i7 i6 i3 i8
+
+ Description:
+ i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP
+ join and traffic
+ l1 - LHR
+ f1 - FHR
+ r2 - FRR router
+ c1 - FRR router
+ c2 - FRR router
+"""
+
+# Global variables
+VLAN_1 = 2501
+GROUP_RANGE = "225.0.0.0/8"
+IGMP_GROUP = "225.1.1.1/32"
+IGMP_JOIN = "225.1.1.1"
+VLAN_INTF_ADRESS_1 = "10.0.8.3/24"
+GROUP_RANGE_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+GROUP_RANGE_2 = [
+ "226.1.1.1/32",
+ "226.1.1.2/32",
+ "226.1.1.3/32",
+ "226.1.1.4/32",
+ "226.1.1.5/32",
+]
+IGMP_JOIN_RANGE_2 = ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"]
+GROUP_RANGE_3 = [
+ "227.1.1.1/32",
+ "227.1.1.2/32",
+ "227.1.1.3/32",
+ "227.1.1.4/32",
+ "227.1.1.5/32",
+]
+IGMP_JOIN_RANGE_3 = ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"]
+
+SAME_VLAN_IP_1 = {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"}
+SAME_VLAN_IP_2 = {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"}
+SAME_VLAN_IP_3 = {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"}
+SAME_VLAN_IP_4 = {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"}
+TCPDUMP_FILE = "{}/{}".format(LOGDIR, "v2query.txt")
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - topology 1
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.19")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+ logger.info("Master Topology: \n {}".format(TOPOLOGY))
+
+ logger.info("Running setup_module to create topology")
+
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False
+):
+ """
+ API to do pre-configuration to send IGMP join and multicast
+ traffic
+
+ parameters:
+ -----------
+ * `tgen`: topogen object
+ * `topo`: input json data
+ * `tc_name`: caller test case name
+ * `iperf`: router running iperf
+ * `iperf_intf`: interface name router running iperf
+ * `GROUP_RANGE`: group range
+ * `join`: IGMP join, default False
+ * `traffic`: multicast traffic, default False
+ """
+
+ if join:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ if traffic:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ router_list = tgen.routers()
+ for router in router_list.keys():
+ if router == iperf:
+ continue
+
+ rnode = router_list[router]
+ rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter")
+
+ for router in topo["routers"].keys():
+ if "static_routes" in topo["routers"][router]:
+ static_routes = topo["routers"][router]["static_routes"]
+ for static_route in static_routes:
+ network = static_route["network"]
+ next_hop = static_route["next_hop"]
+ if type(network) is not list:
+ network = [network]
+ for net in network:
+ addKernelRoute(tgen, router, iperf_intf, net, next_hop)
+ return True
+
+
+def verify_mroute_repopulated(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
+
+
+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 find_v2_query_msg_in_tcpdump(tgen, router, message, count, cap_file):
+ """
+ Find v2 query messages in tcpdump file
+
+ Parameters
+ ----------
+ * `tgen` : Topology handler
+ * `router` : Device under test
+ * `cap_file` : tcp dump file name
+
+ """
+
+ filepath = os.path.join(LOGDIR, tgen.modname, router, cap_file)
+ with open(filepath) as f:
+ if len(re.findall("{}".format(message), f.read())) < count:
+ errormsg = "[DUT: %s]: Verify Message: %s in tcpdump" " [FAILED!!]" % (
+ router,
+ message,
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: Found message: %s in tcpdump " " count: %s [PASSED!!]",
+ router,
+ message,
+ count,
+ )
+ return True
+
+
+def find_tos_in_tcpdump(tgen, router, message, cap_file):
+ """
+ Find v2 query messages in tcpdump file
+
+ Parameters
+ ----------
+ * `tgen` : Topology handler
+ * `router` : Device under test
+ * `cap_file` : tcp dump file name
+
+ """
+
+ filepath = os.path.join(LOGDIR, tgen.modname, router, cap_file)
+ with open(filepath) as f:
+
+ if len(re.findall(message, f.read())) < 1:
+ errormsg = "[DUT: %s]: Verify Message: %s in tcpdump" " [FAILED!!]" % (
+ router,
+ message,
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: Found message: %s in tcpdump " "[PASSED!!]", router, message
+ )
+ return True
+
+
+def test_verify_oil_when_join_prune_sent_scenario_1_p1(request):
+ """
+ TC_21_1:
+ Verify OIL detail updated in (S,G) and (*,G) mroute when IGMP
+ join/prune is sent
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (226.1.1.1-5)"
+ )
+ step(
+ "Enable IGMP of FRR3 interface and send IGMP joins "
+ " from FRR3 node for group range (226.1.1.1-5)"
+ )
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_dict = {
+ "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {
+ "i1": topo["routers"]["i1"]["links"]["l1"]["interface"],
+ "i8": topo["routers"]["i8"]["links"]["f1"]["interface"],
+ }
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (226.1.1.1-5) in R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure one source on FRR3 for all the groups and send" " multicast traffic"
+ )
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i2,
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR1 node")
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False)
+
+ step(
+ "After receiving the IGMP prune from FRR1 , verify traffic "
+ "immediately stopped for this receiver 'show ip multicast'"
+ )
+
+ input_traffic = {"l1": {"traffic_sent": [intf_l1_i1]}}
+ result = verify_multicast_traffic(tgen, input_traffic, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ " Traffic is not stopped yet \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step(
+ "IGMP groups are remove from FRR1 node 'show ip igmp groups'"
+ " FRR3 IGMP still present"
+ )
+
+ dut = "l1"
+ result = verify_igmp_groups(
+ tgen, dut, intf_l1_i1, IGMP_JOIN_RANGE_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "IGMP groups are not deleted \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ dut = "f1"
+ result = verify_igmp_groups(tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "(*,G) and (S,G) OIL got removed immediately after receiving"
+ " prune 'show ip pim state' and 'show ip mroute' on FRR1 node,"
+ " no impact on FRR3 receiver"
+ )
+
+ input_dict_l1 = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_l1:
+ result = verify_ip_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 Behaviour: {}".format(result))
+
+ for data in input_dict_l1:
+ 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 entries are still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ input_dict_f1 = [
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_f1:
+ result = verify_ip_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)
+
+ for data in input_dict_f1:
+ 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("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " " FRR3 node")
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i8, False)
+
+ step(
+ "After receiving the IGMP prune from FRR3s , verify traffic "
+ "immediately stopped for this receiver 'show ip multicast'"
+ )
+
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ result = verify_multicast_traffic(tgen, input_traffic, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ " Traffic is not stopped yet \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step(
+ "IGMP groups are remove from FRR1 node 'show ip igmp groups'"
+ " FRR3 IGMP still present"
+ )
+
+ dut = "f1"
+ result = verify_igmp_groups(
+ tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "IGMP groups are not deleted \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step(
+ "(*,G) and (S,G) OIL got prune state (none) from all the nodes"
+ "FRR1, FRR3 verify using 'show ip mroute'"
+ )
+
+ input_dict_l1 = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_l1:
+ result = verify_ip_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 Behaviour: {}".format(result))
+
+ for data in input_dict_l1:
+ 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 entries are still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i8, True)
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True)
+
+ for data in input_dict_l1:
+ 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)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_oil_when_join_prune_sent_scenario_2_p1(request):
+ """
+ TC_21_2: Verify OIL detail updated in (S,G) and (*,G) mroute when IGMP
+ join/prune is sent
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Removing FRR3 to simulate topo " "FHR(FRR1)---LHR(FRR2)")
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_r2, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (226.1.1.1-5)"
+ )
+ step(
+ "Enable IGMP of FRR3 interface and send IGMP joins "
+ " from FRR3 node for group range (226.1.1.1-5)"
+ )
+
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ input_dict = {
+ "r2": {"igmp": {"interfaces": {intf_r2_i3: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {
+ "i1": topo["routers"]["i1"]["links"]["l1"]["interface"],
+ "i3": topo["routers"]["i3"]["links"]["r2"]["interface"],
+ }
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (226.1.1.1-5) in R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR3(r2) node")
+
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False)
+
+ step(
+ "After sending IGMP prune from FRR3(r2) node verify (*,G) OIL "
+ "immediately removed for local receiver mroute should have "
+ " PIM protocol , IGMP should be removed verify using "
+ "'show ip mroute' no impact seen on FRR1(l1) (*,G)"
+ )
+
+ input_dict_r2 = [
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ }
+ ]
+
+ for data in input_dict_r2:
+ result = verify_ip_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 Behaviour: {}".format(result))
+
+ input_dict_l1_r2 = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_l1_r2:
+ result = verify_ip_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)
+
+ step("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR1(l1) node")
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False)
+
+ step(
+ "After sending IGMP prune from FRR1 node verify (*,G) OIL"
+ "got removed immediately from FRR1 node"
+ )
+
+ input_dict_l1 = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ }
+ ]
+
+ for data in input_dict_l1:
+ result = verify_ip_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 Behaviour: {}".format(result))
+
+ step("After prune is sent verify upstream got removed in FRR1 node")
+
+ for data in input_dict_l1:
+ 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 entries are still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_shut_noshut_source_interface_when_upstream_cleared_from_LHR_p1(request):
+ """
+ TC_26: Verify shut/no shut of source interface after upstream got cleared
+ from LHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP on R2 (loopback interface) for " "the group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver")
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "'show ip mroute' showing correct RPF and OIF interface for (*,G)"
+ " and (S,G) entries on all the nodes"
+ )
+
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i2,
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ step(
+ "'show ip pim upstream' and 'show ip pim upstream-rpf' showing"
+ " correct OIL and IIF on all the nodes"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Shut the source interface from FRR3")
+ intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"]
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False)
+
+ step(
+ "After shut of source interface verify (S,G) mroutes are cleared"
+ " from all the nodes"
+ )
+
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ result = verify_ip_mroutes(
+ tgen, "f1", source_i2, IGMP_JOIN_RANGE_1, intf_f1_i2, intf_f1_r2, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n mroutes are"
+ " still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ step(
+ "After waiting for (S,G) timeout from FRR1 for same"
+ " source verify that (S,G) is flushed from FRR1 node"
+ " 'show ip pim upstream' 'show ip mroute' "
+ )
+
+ done_flag = False
+ for retry in range(1, 11):
+ result = verify_upstream_iif(
+ tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False
+ )
+ if result is not True:
+ done_flag = True
+ else:
+ continue
+ if done_flag:
+ logger.info("Expected Behavior: {}".format(result))
+ break
+
+ assert done_flag is True, (
+ "Testcase {} : Failed Error: \n "
+ "mroutes are still present, after waiting for 10 mins".format(tc_name)
+ )
+
+ step("No shut the Source interface just after the upstream is expired" " from FRR1")
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True)
+
+ step(
+ "After no shut of source interface , verify all the (S,G) is "
+ " populated again on 'show ip mroute' 'show ip pim upstream' "
+ " with proper OIL and IIF detail"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("shut and no shut the source interface immediately")
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True)
+
+ step(
+ "All the mroutes got updated with proper OIL after no shut of"
+ "interface verify using 'show ip mroute'"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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)
+
+ write_test_footer(tc_name)
+
+
+def test_shut_noshut_receiver_interface_when_upstream_cleared_from_LHR_p1(request):
+ """
+ TC_27: Verify shut/no shut of receiver interface after upstream got
+ cleared from LHR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP on R2 (loopback interface) for " "the group range 225.0.0.0/8")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver")
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "'show ip mroute' showing correct RPF and OIF interface for (*,G)"
+ " and (S,G) entries on all the nodes"
+ )
+
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i2,
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ step(
+ "'show ip pim upstream' and 'show ip pim upstream-rpf' showing"
+ " correct OIL and IIF on all the nodes"
+ )
+
+ for data in input_dict_all:
+ 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("Shut the source interface FRR1")
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False)
+
+ step(
+ "After waiting for (S,G) timeout from FRR1 for same"
+ " source verify that (S,G) is flushed from FRR1 node"
+ " 'show ip pim upstream' 'show ip mroute' "
+ )
+
+ done_flag = False
+ for retry in range(1, 11):
+ result = verify_upstream_iif(
+ tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False
+ )
+ if result is not True:
+ done_flag = True
+ else:
+ continue
+ if done_flag:
+ logger.info("Expected Behavior: {}".format(result))
+ break
+
+ assert done_flag is True, (
+ "Testcase {} : Failed Error: \n "
+ "mroutes are still present, after waiting for 10 mins".format(tc_name)
+ )
+
+ step("No shut the Source interface just after the upstream is expired" " from FRR1")
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True)
+
+ step(
+ "After no shut of source interface , verify all the (S,G) is "
+ " populated again on 'show ip mroute' 'show ip pim upstream' "
+ " with proper OIL and IIF detail"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("shut and no shut the source interface immediately")
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True)
+
+ step(
+ "After no shut of receiver interface , verify all the (S,G) is "
+ "populated again on 'show ip mroute' 'show ip pim upstream' "
+ "with proper OIL and IIF detail"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request):
+ """
+ TC_33: Verify removing and adding IGMP config from the receiver interface
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable PIM on all routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure source on FRR3 and start the traffic for" " (225.1.1.1-225.1.1.10)")
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure source on FRR1 and start the traffic for" " (225.1.1.1-225.1.1.10)")
+
+ input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i6 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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(
+ "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from"
+ " receiver interface of FRR1"
+ )
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}}
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("IGMP join removed from FRR1 , verify using " "'show ip igmp groups json'")
+
+ dut = "l1"
+ interface = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Groups are not"
+ " present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"]
+ input_traffic = {
+ "l1": {"traffic_received": [intf_l1_r2], "traffic_sent": [intf_l1_i1]},
+ "f1": {"traffic_sent": [intf_f1_r2], "traffic_received": [intf_f1_i2]},
+ }
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure igmp 'ip igmp' and 'ip igmp version 2' from "
+ "receiver interface of FRR1"
+ )
+
+ input_dict_2 = {
+ "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "After adding IGMP on receiver interface verify (S,G) and (*,G)"
+ " entries got populated and traffic is resumed on FRR1 and FRR3 node"
+ )
+
+ step(
+ "Verify OIL/IIF and drJoinDesired using 'show ip mroute , and traffic"
+ " using show ip pim upstream and show ip multicast'"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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)
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from"
+ " receiver interface of FRR1"
+ )
+
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}}
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("IGMP join removed from FRR1 , verify using " "'show ip igmp groups json'")
+
+ dut = "l1"
+ interface = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Groups are not"
+ " present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure igmp 'ip igmp' and 'ip igmp version 2' from "
+ "receiver interface of FRR1"
+ )
+
+ input_dict_2 = {
+ "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "After adding IGMP on receiver interface verify (S,G) and (*,G)"
+ " entries got populated and traffic is resumed on FRR1 and FRR3 node"
+ )
+
+ step(
+ "Verify OIL/IIF and drJoinDesired using 'show ip mroute , and traffic"
+ " using show ip pim upstream and show ip multicast'"
+ )
+
+ input_dict_l1_f1 = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_l1_f1:
+ result = verify_ip_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)
+
+ for data in input_dict_l1_f1:
+ 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)
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Remove ip igmp and send igmp prune from FRR1 interface")
+
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}}
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+ step(
+ "Verification: After removing igmp 'no ip igmp' and "
+ " sending prune verify mroute and upstream got removed"
+ " from FRR1 verify using 'show ip mroute' and "
+ "'show ip pim upstream'"
+ )
+
+ dut = "l1"
+ iif = topo["routers"]["l1"]["links"]["i6"]["interface"]
+ oil = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ source = source_i6
+ result = verify_ip_mroutes(
+ tgen, dut, source, IGMP_JOIN_RANGE_1, iif, oil, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n routes are still"
+ " present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_verify_remove_add_igmp_commands_when_pim_configured_p0(request):
+ """
+ TC_34: Verify removing and adding IGMP commands when PIM is already
+ configured
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Enable PIM on all routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure source on FRR3 and start the traffic for" " (225.1.1.1-225.1.1.10)")
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure source on FRR1 and start the traffic for" " (225.1.1.1-225.1.1.10)")
+
+ input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i6 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i6,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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(
+ "Verification: After configuring IGMP related config , "
+ "verify config is present in the interface "
+ "'show ip igmp interface ensxx json'"
+ )
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ input_dict_1 = {
+ "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}}
+ }
+
+ result = verify_igmp_config(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from"
+ " receiver interface of FRR1"
+ )
+
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}}
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verification: After removing the config CLI got removed "
+ "'show ip igmp interface ensxx json'"
+ )
+
+ result = verify_igmp_config(tgen, input_dict_1, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "IGMP interface is not removed \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure 'ip igmp last-member-query-count 10' on FRR1" " receiver interface")
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"query": {"last-member-query-count": 5}}}
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'ip igmp last-member-query-count 10' on FRR1" " receiver interface")
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "query": {"last-member-query-count": "", "delete": True}
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"query": {"last-member-query-count": 2}}}
+ }
+ }
+ }
+ }
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure 'ip igmp last-member-query-interval 20' on FRR1"
+ " receiver interface"
+ )
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {"query": {"last-member-query-interval": 20}}
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'ip igmp last-member-query-count 10' on FRR1" " receiver interface")
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {
+ "query": {"last-member-query-interval": "", "delete": True}
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_dict_3 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "igmp": {"query": {"last-member-query-interval": 10}}
+ }
+ }
+ }
+ }
+ }
+ result = verify_igmp_config(tgen, input_dict_3)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_remove_add_pim_commands_when_igmp_configured_p1(request):
+ """
+ TC_35: Verify removing and adding PIM commands when IGMP is already
+ configured
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 'ip pim' on receiver interface on FRR1")
+ step("Enable PIM on all routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim' on receiver interface on FRR1")
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ input_dict_1 = {"l1": {"pim": {"disable": intf_l1_i1}}}
+ result = create_pim_config(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure 'ip pim bsm' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim bsm"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim bsm' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim bsm"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure 'ip pim drpriority' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {
+ "raw_config": ["interface {}".format(intf_l1_i1), "ip pim drpriority 10"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verification: After configuring PIM related config, "
+ "verify config is present in the interface "
+ "'show ip pim interface ensxx json'"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"drPriority": 10}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim drpriority' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {
+ "raw_config": ["interface {}".format(intf_l1_i1), "no ip pim drpriority 10"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verification: After removing the config CLI got removed "
+ "'show ip pim interface ensxx json'"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"drPriority": 1}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure 'ip pim hello' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim hello 50"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verification: After configuring PIM related config, "
+ "verify config is present in the interface "
+ "'show ip pim interface ensxx json'"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"helloPeriod": 50}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim hello' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim hello"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Verification: After removing the config CLI got removed "
+ "'show ip pim interface ensxx json'"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"helloPeriod": 30}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure 'ip pim unicast-bsm' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim unicast-bsm"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim hello' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {
+ "raw_config": ["interface {}".format(intf_l1_i1), "no ip pim unicast-bsm"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim_dr_priority_p0(request):
+ """
+ TC_36: Verify highest DR priority become the PIM DR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 'ip pim' on receiver interface on FRR1")
+ step("Enable PIM on all routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Configure 'ip pim drpriority 10' on receiver interface on FRR1(LHR)")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ raw_config = {
+ "l1": {
+ "raw_config": ["interface {}".format(intf_l1_r2), "ip pim drpriority 10"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "DR config is successful on FRR1 node , verify using "
+ " 'show ip pim interface json'"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_r2: {"drPriority": 10}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Configure 'ip pim drpriority 20' on receiver interface on FRR3(FHR)")
+
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ raw_config = {
+ "f1": {
+ "raw_config": ["interface {}".format(intf_f1_r2), "ip pim drpriority 20"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "DR config is successful on FRR3 node , verify using "
+ " 'show ip pim interface json'"
+ )
+
+ input_dict_dr = {"f1": {"pim": {"interfaces": {intf_f1_r2: {"drPriority": 20}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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(
+ "PIM is enable on FRR1, FRR2 interface and neighbor is up, "
+ " verify using 'show ip pim interface'"
+ )
+
+ result = verify_pim_interface(tgen, topo, "l1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_pim_interface(tgen, topo, "f1")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Highet IP become PIM DR , verify using "
+ "'show ip pim interface json' and 'show ip pim neighbor'"
+ )
+ step("Highest priority become PIM DR")
+
+ dr_address = topo["routers"]["l1"]["links"]["r2"]["ipv4"].split("/")[0]
+ input_dict_dr = {
+ "l1": {"pim": {"interfaces": {intf_l1_r2: {"drAddress": dr_address}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ dr_address = topo["routers"]["f1"]["links"]["r2"]["ipv4"].split("/")[0]
+ input_dict_dr = {
+ "f1": {"pim": {"interfaces": {intf_f1_r2: {"drAddress": dr_address}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim drpriority' on receiver interface on FRR1")
+
+ raw_config = {
+ "l1": {
+ "raw_config": ["interface {}".format(intf_l1_r2), "no ip pim drpriority 10"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Remove 'no ip pim drpriority' on receiver interface on FRR3")
+
+ raw_config = {
+ "f1": {
+ "raw_config": ["interface {}".format(intf_f1_r2), "no ip pim drpriority 20"]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "After removing drpriority , config got removed from both the "
+ "nodes and highest IP become PIM DR"
+ )
+
+ input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_r2: {"drPriority": 1}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ input_dict_dr = {"f1": {"pim": {"interfaces": {intf_f1_r2: {"drPriority": 1}}}}}
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ dr_address = topo["routers"]["r2"]["links"]["l1"]["ipv4"].split("/")[0]
+ input_dict_dr = {
+ "l1": {"pim": {"interfaces": {intf_l1_r2: {"drAddress": dr_address}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ dr_address = topo["routers"]["r2"]["links"]["f1"]["ipv4"].split("/")[0]
+ input_dict_dr = {
+ "f1": {"pim": {"interfaces": {intf_f1_r2: {"drAddress": dr_address}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_dr)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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)
+
+ write_test_footer(tc_name)
+
+
+def test_pim_hello_timer_p1(request):
+ """
+ TC_37: Verify PIM hello is sent on configured timer
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 'ip pim' on receiver interface on FRR1")
+ step("Enable PIM on all routers")
+ step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)")
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure PIM hello interval timer 100 on FRR1 node (FRR1-FRR2 link)")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 100"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "PIM hello interval is configured on interface verify using "
+ "'show ip pim interface'"
+ )
+
+ input_dict_hello = {
+ "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 100}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_hello)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Modify hello timer to 180 and then 50sec")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 180"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "PIM hello interval is configured on interface verify using "
+ "'show ip pim interface'"
+ )
+
+ input_dict_hello = {
+ "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 180}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_hello)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ raw_config = {
+ "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 50"]}
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "PIM hello interval is configured on interface verify using "
+ "'show ip pim interface'"
+ )
+
+ input_dict_hello = {
+ "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 50}}}}
+ }
+ result = verify_pim_config(tgen, input_dict_hello)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify that no core is observed")
+ if tgen.routers_have_failure():
+ assert False, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_mroute_after_removing_RP_sending_IGMP_prune_p2(request):
+ """
+ TC_39 Verify mroute after removing the RP and sending IGMP prune
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove cisco connected link to simulate topo "
+ "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))"
+ )
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_dict = {
+ "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send"
+ " multicast traffic"
+ )
+
+ input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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("Remove the RP config for both the range from all the nodes")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ input_dict_starg = [
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ }
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ for data in input_dict_starg:
+ result = verify_ip_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 "
+ "mroute still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ for data in input_dict_sg:
+ result = verify_ip_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)
+
+ step("Send prune from receiver-1 (using ctrl+c) on iperf interface")
+ kill_iperf(tgen)
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ traffic_before = verify_multicast_traffic(
+ tgen, input_traffic, return_traffic=True, expected=False
+ )
+ assert isinstance(traffic_before, dict), (
+ "Testcase {} : Failed \n traffic_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+ )
+
+ step("IGMP groups are remove from FRR1 node 'show ip igmp groups'")
+
+ dut = "f1"
+ result = verify_igmp_groups(
+ tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "IGMP groups still present still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step(
+ "After receiving the IGMP prune from FRR1 , verify traffic "
+ "immediately stopped for this receiver 'show ip multicast'"
+ )
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ traffic_after = verify_multicast_traffic(
+ tgen, input_traffic, return_traffic=True, expected=False
+ )
+ assert isinstance(traffic_after, dict), (
+ "Testcase {} : Failed \n traffic_after is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+ )
+
+ result = verify_state_incremented(traffic_before, traffic_after)
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("Configure static RP for (225.1.1.1-5) as R2 loopback interface")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send IGMP joins again from LHR,check IGMP joins and starg received")
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ step("Send traffic from FHR and verify mroute upstream")
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+
+ for data in input_dict_sg:
+ result = verify_ip_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)
+
+ write_test_footer(tc_name)
+
+
+def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request):
+ """
+ TC_38 Verify prune is sent to LHR and FHR when PIM nbr went down
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove cisco connected link to simulate topo "
+ "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))"
+ )
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_dict = {
+ "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send"
+ " multicast traffic"
+ )
+
+ input_src = {
+ "i6": topo["routers"]["i6"]["links"]["l1"]["interface"],
+ "i2": topo["routers"]["i2"]["links"]["f1"]["interface"],
+ }
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i1 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i1,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ for data in input_dict_all:
+ 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 mcast traffic received")
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the link from LHR to RP from RP node")
+
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False)
+
+ step("Verify RP info after Shut the link from LHR to RP from RP node")
+ dut = "f1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_starg = [
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ }
+ ]
+
+ input_dict_sg_i2 = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ input_dict_sg_i1 = [
+ {
+ "dut": "f1",
+ "src_address": source_i1,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ }
+ ]
+
+ input_dict_sg_i2_l1 = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ }
+ ]
+
+ step("Verify mroute after Shut the link from LHR to RP from RP node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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 "
+ "mroute still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify upstream after Shut the link from LHR to RP from RP node")
+
+ for data in input_dict_starg:
+ 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 still present \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ for data in input_dict_sg_i1:
+ 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("No shut the link from LHR to RP from RP node")
+
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_f1, True)
+
+ step("Verify RP info after No shut the link from LHR to RP from RP node")
+ dut = "f1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "RP iif is not updated \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("Verify mroute after No shut the link from LHR to RP from RP node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i2:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify upstrem after No shut the link from LHR to RP from RP node")
+
+ for data in input_dict_starg:
+ 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_sg_i1:
+ 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_sg_i2:
+ 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 mcast traffic received after noshut LHR to RP from RP node")
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the link from FHR to RP from RP node")
+
+ intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_l1, False)
+
+ kill_iperf(tgen, dut="i2", action="remove_traffic")
+
+ step("Verify RP info after Shut the link from FHR to RP from RP node")
+ dut = "l1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify mroute after Shut the link from FHR to RP from RP node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify upstream after Shut the link from FHR to RP from RP node")
+
+ for data in input_dict_starg:
+ 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_sg_i1:
+ 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_sg_i2_l1:
+ 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
+ )
+
+ step(" No shut the link from FHR to RP from RP node")
+
+ intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_l1, True)
+
+ step("Verify RP info after Noshut the link from FHR to RP from RP node")
+
+ dut = "l1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "RP iif is not updated \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("Verify mroute after Noshut the link from FHR to RP from RP node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i2:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify mroute after Noshut the link from FHR to RP from RP node")
+
+ for data in input_dict_starg:
+ 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_sg_i1:
+ 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_sg_i2:
+ 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 mcast traffic received after noshut FHR to RP from RP node")
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the link from FHR to RP from FHR node")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_r2, False)
+
+ step("Verify PIM Nbrs after Shut the link from FHR to RP from FHR node")
+
+ kill_iperf(tgen, dut="i6", action="remove_traffic")
+
+ step("Verify RP info after Shut the link from FHR to RP from FHR node")
+ dut = "l1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify mroute after Shut the link from FHR to RP from FHR node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify upstream after Shut the link from FHR to RP from FHR node")
+ for data in input_dict_starg:
+ 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_sg_i1:
+ 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_sg_i2_l1:
+ 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
+ )
+
+ step(" No shut the link from FHR to RP from FHR node")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_r2, True)
+
+ step("Verify RP info after No Shut the link from FHR to RP from FHR node")
+ dut = "l1"
+ rp_address = "1.0.5.17"
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "RP iif is not updated \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("Verify mroute after No Shut the link from FHR to RP from FHR node")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i2:
+ result = verify_ip_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)
+
+ for data in input_dict_sg_i1:
+ result = verify_ip_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)
+
+ step("Verify upstream after No Shut the link from FHR to RP from FHR node")
+
+ for data in input_dict_starg:
+ 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_sg_i1:
+ 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_sg_i2:
+ 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 mcast traffic received after noshut FHR to RP from FHR node")
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}}
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_mroute_flags_p1(request):
+ """
+ TC_47 Verify mroute flag in LHR and FHR node
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove cisco connected link to simulate topo "
+ "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))"
+ )
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"]
+ input_dict = {
+ "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send"
+ " multicast traffic"
+ )
+
+ input_src = {
+ "i6": topo["routers"]["i6"]["links"]["l1"]["interface"],
+ "i2": topo["routers"]["i2"]["links"]["f1"]["interface"],
+ }
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0]
+ source_i1 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
+
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["l1"]["links"]["i6"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i1,
+ "iif": topo["routers"]["f1"]["links"]["i2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": source_i2,
+ "iif": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["f1"]["links"]["i8"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_all:
+ result = verify_ip_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)
+
+ dut = "f1"
+ step("verify flag for (*,G) on f1")
+ src_address = "*"
+ flag = "SC"
+ result = verify_multicast_flag_state(
+ tgen, dut, src_address, IGMP_JOIN_RANGE_1, flag
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify flag for (S,G) on f1 for Remote spurce ")
+ src_address = source_i2
+ flag = "ST"
+ result = verify_multicast_flag_state(
+ tgen, dut, src_address, IGMP_JOIN_RANGE_1, flag
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request):
+ """
+ TC_11: Verify multicast traffic flowing fine, when LHR connected to RP
+ Topology used:
+ FHR(FRR3(l1))---LHR(FRR1(r2)----RP(FRR2(f1))
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Remove FRR3 to cisco connected link to simulate topo "
+ "FHR(FRR3(l1))---LHR(FRR1(r2)----RP(FRR2(f1))"
+ )
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+
+ step("Disable IGMP config from l1")
+ input_dict_2 = {
+ "l1": {
+ "igmp": {
+ "interfaces": {
+ "l1-i1-eth1": {"igmp": {"version": "2", "delete": True,}}
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers")
+ step(
+ "Enable IGMP on FRR1(r2) interface and send IGMP join (226.1.1.1-5)"
+ " and (232.1.1.1-5)"
+ )
+
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ input_dict = {
+ "r2": {"igmp": {"interfaces": {intf_r2_i3: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3
+ _IGMP_JOIN_RANGE = IGMP_JOIN_RANGE_2 + IGMP_JOIN_RANGE_3
+
+ input_join = {"i3": topo["routers"]["i3"]["links"]["r2"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, _GROUP_RANGE, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, _IGMP_JOIN_RANGE, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in (f1)")
+
+ input_dict = {
+ "f1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["f1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": _GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver")
+
+ input_src = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, _GROUP_RANGE, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, _IGMP_JOIN_RANGE, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "'show ip mroute' showing correct RPF and OIF interface for (*,G)"
+ " and (S,G) entries on all the nodes"
+ )
+
+ source_i1 = topo["routers"]["i1"]["links"]["l1"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": source_i1,
+ "iif": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i1,
+ "iif": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Multicast traffic is flowing for all the groups verify"
+ "using 'show ip multicast'"
+ )
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ input_traffic = {
+ "l1": {"traffic_received": [intf_l1_i1]},
+ "r2": {"traffic_received": [intf_r2_l1], "traffic_sent": [intf_r2_i3]},
+ }
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut and No shut the receiver port")
+
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False)
+
+ step(
+ "Verification: After Shut of receiver port, Verify (*,G) and "
+ "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'"
+ )
+
+ input_dict_r2 = [
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i1,
+ "iif": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ ]
+
+ for data in input_dict_r2:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " Expected Behaviour: mroutes are cleared \n Error: {}".format(
+ tc_name, result
+ )
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ shutdown_bringup_interface(tgen, "r2", intf_r2_i3, True)
+
+ step(
+ "Verification: After No shut of receiver port , Verify (*,G)"
+ " and (S,G) got populated on LHR node (FRR1) using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_r2:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_r2:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Multicast traffic is resumed for all the groups verify "
+ "using 'show ip multicast'"
+ )
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut and No shut the source port")
+
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False)
+
+ step(
+ "Verification: After Shut of source port, Verify (*,G) and "
+ "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'"
+ )
+
+ input_dict_l1 = [
+ {
+ "dut": "l1",
+ "src_address": source_i1,
+ "iif": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ }
+ ]
+
+ for data in input_dict_l1:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ "mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True)
+
+ step(
+ "Verification: After No shut of source port , Verify (*,G)"
+ " and (S,G) got populated on LHR node (FRR1) using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_l1:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_l1:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Multicast traffic is resumed for all the groups verify "
+ "using 'show ip multicast'"
+ )
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut and No shut of LHR to cisco port from LHR side")
+
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False)
+
+ step(
+ "Verification: After Shut of source port, Verify (S,G) got "
+ "removed from LHR and FHR using 'show ip mroute'"
+ )
+
+ input_dict_r2_f1 = [
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_r2_f1:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ shutdown_bringup_interface(tgen, "r2", intf_r2_f1, True)
+
+ step(
+ "Verification: After No shut of source port , Verify (*,G)"
+ " and (S,G) got populated on LHR node (FRR1) using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Multicast traffic is resumed for all the groups verify "
+ "using 'show ip multicast'"
+ )
+
+ input_traffic_r2 = {
+ "r2": {"traffic_received": [intf_r2_l1], "traffic_sent": [intf_r2_i3]}
+ }
+ result = verify_multicast_traffic(tgen, input_traffic_r2)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut and no shut of FHR to LHR port from FHR side")
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_r2, False)
+
+ step(
+ "Verification: After Shut of LHR to FHR port, Verify (S,G)"
+ "got removed from LHR 'show ip mroute'"
+ )
+
+ dut = "r2"
+ src_address = "*"
+ iif = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ oil = topo["routers"]["r2"]["links"]["i3"]["interface"]
+
+ result = verify_ip_mroutes(tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ src_address = source_i1
+ iif = topo["routers"]["r2"]["links"]["l1"]["interface"]
+ oil = topo["routers"]["r2"]["links"]["i3"]["interface"]
+
+ result = verify_ip_mroutes(
+ tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ shutdown_bringup_interface(tgen, "l1", intf_l1_r2, True)
+
+ step(
+ "Verification: After No shut of source port , Verify (*,G)"
+ " and (S,G) got populated on LHR node (FRR1) using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_all:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Multicast traffic is resumed for all the groups verify "
+ "using 'show ip multicast'"
+ )
+
+ result = verify_multicast_traffic(tgen, input_traffic_r2)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request):
+ """
+ TC_12: Verify multicast traffic is flowing fine when FHR is connected to RP
+ Topology used:
+ LHR(FRR1)---FHR(FRR3)----RP(FRR2)
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+ check_router_status(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Remove FRR3 to FRR2 connected link to simulate topo "
+ "FHR(FRR3)---LHR(FRR1)----RP(FFR2)"
+ )
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"]
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+ shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers")
+ step("Enable IGMP on FRR1(l1) interface and send IGMP join " " and (225.1.1.1-5)")
+
+ _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3
+ _IGMP_JOIN_RANGE = IGMP_JOIN_RANGE_2 + IGMP_JOIN_RANGE_3
+
+ input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, _GROUP_RANGE, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, _IGMP_JOIN_RANGE, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure RP for (225.1.1.1-5) in (f1)")
+
+ input_dict = {
+ "f1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["f1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": _GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send multicast traffic from FRR3(r2) to 225.1.1.1-225.1.1.10" " receiver")
+
+ input_src = {"i3": topo["routers"]["i3"]["links"]["r2"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, _GROUP_RANGE, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, _IGMP_JOIN_RANGE, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "'show ip mroute' showing correct RPF and OIF interface for (*,G)"
+ " and (S,G) entries on all the nodes"
+ )
+
+ source_i3 = topo["routers"]["i3"]["links"]["r2"]["ipv4"].split("/")[0]
+ input_dict_all = [
+ {
+ "dut": "l1",
+ "src_address": "*",
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "l1",
+ "src_address": source_i3,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "r2",
+ "src_address": source_i3,
+ "iif": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_all:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"]
+ intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"]
+ intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"]
+ input_traffic = {
+ "l1": {"traffic_received": [intf_l1_r2], "traffic_sent": [intf_l1_i1]}
+ }
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the receiver(l1) port in 1 min interval")
+
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False)
+
+ step(
+ "Verification: After Shut of receiver port, Verify (*,G) and "
+ "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'"
+ )
+
+ input_dict_l1 = [
+ {
+ "dut": "l1",
+ "src_address": source_i3,
+ "iif": topo["routers"]["l1"]["links"]["r2"]["interface"],
+ "oil": topo["routers"]["l1"]["links"]["i1"]["interface"],
+ }
+ ]
+
+ for data in input_dict_l1:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("No shut the receiver(l1) port in 1 min interval")
+
+ shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True)
+
+ step(
+ "Verification: After No shut of receiver port , Verify (*,G)"
+ " and (S,G) got populated on LHR node (FRR1) using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_l1:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_l1:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut the source(r2) port in 1 min interval")
+
+ intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False)
+
+ step(
+ "Verification: After Shut of source port, Verify (S,G) got "
+ "removed from FHR using 'show ip mroute'"
+ )
+
+ input_dict_r2 = [
+ {
+ "dut": "r2",
+ "src_address": source_i3,
+ "iif": topo["routers"]["r2"]["links"]["i3"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ }
+ ]
+
+ for data in input_dict_r2:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ step("No shut the source(r2) port in 1 min interval")
+
+ shutdown_bringup_interface(tgen, "r2", intf_r2_i3, True)
+
+ step(
+ "Verification: After No shut of source port , Verify (*,G)"
+ " and (S,G) got populated on LHR and FHR using "
+ "'show ip mroute' 'show ip pim upstream'"
+ )
+
+ for data in input_dict_r2:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ for data in input_dict_r2:
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_multicast_traffic(tgen, input_traffic)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Shut FHR to RP port from FHR side")
+
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"]
+ shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False)
+
+ step(
+ "Verification: After Shut of FHR to cisco port, Verify (*,G) "
+ "got removed from FHR and cisco node using 'show ip mroute'"
+ )
+
+ input_dict_all_star = [
+ {
+ "dut": "r2",
+ "src_address": "*",
+ "iif": topo["routers"]["r2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["r2"]["links"]["l1"]["interface"],
+ },
+ {
+ "dut": "f1",
+ "src_address": "*",
+ "iif": "lo",
+ "oil": topo["routers"]["f1"]["links"]["r2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_all_star:
+ result = verify_ip_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ _IGMP_JOIN_RANGE,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n"
+ " mroutes are cleared \n Error: {}".format(tc_name, result)
+ )
+ logger.info("Expected Behaviour: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py
new file mode 100755
index 0000000000..33c57f209a
--- /dev/null
+++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py
@@ -0,0 +1,1120 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test multicast pim sm:
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+Following tests are covered:
+
+1. TC:48 Verify mroute after configuring black-hole route for RP and source
+2. TC:49 Verify mroute when RP is reachable using default route
+3. TC:50 Verify mroute when LHR,FHR,RP and transit routers reachable
+ using default routes
+4. TC:52 Verify PIM nbr after changing interface ip
+5. TC:53 Verify IGMP interface updated with correct detail after changing interface config
+6. TC:54 Verify received and transmit hello stats are getting cleared after PIM nbr reset
+
+
+"""
+
+import os
+import re
+import sys
+import json
+import time
+import datetime
+from time import sleep
+import pytest
+
+# 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 mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ step,
+ iperfSendIGMPJoin,
+ addKernelRoute,
+ reset_config_on_routers,
+ iperfSendTraffic,
+ kill_iperf,
+ shutdown_bringup_interface,
+ start_router,
+ stop_router,
+ apply_raw_config,
+ create_static_routes,
+ required_linux_kernel_version,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ create_igmp_config,
+ verify_igmp_groups,
+ verify_ip_mroutes,
+ clear_ip_pim_interface_traffic,
+ verify_igmp_config,
+ verify_pim_neighbors,
+ verify_pim_config,
+ verify_pim_interface,
+ verify_upstream_iif,
+ clear_ip_mroute,
+ verify_multicast_traffic,
+ verify_pim_rp_info,
+ verify_pim_interface_traffic,
+ verify_igmp_interface,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/multicast_pim_sm_topo4.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+TOPOLOGY = """
+
+
+ i4-----c1-------------c2---i5
+ | |
+ | |
+ i1-----l1------r2-----f1---i2
+ | | | |
+ | | | |
+ i7 i6 i3 i8
+
+ Description:
+ i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP
+ join and traffic
+ l1 - LHR
+ f1 - FHR
+ r2 - FRR router
+ c1 - FRR router
+ c2 - FRR router
+"""
+
+# Global variables
+
+GROUP_RANGE = "224.0.0.0/4"
+IGMP_GROUP = "225.1.1.1/32"
+IGMP_JOIN = "225.1.1.1"
+GROUP_RANGE_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+NEW_ADDRESS_1 = "192.168.20.1"
+NEW_ADDRESS_2 = "192.168.20.2"
+NEW_ADDRESS_1_SUBNET = "192.168.20.1/24"
+NEW_ADDRESS_2_SUBNET = "192.168.20.2/24"
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - topology 1
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.19")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+ logger.info("Master Topology: \n {}".format(TOPOLOGY))
+
+ logger.info("Running setup_module to create topology")
+
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False
+):
+ """
+ API to do pre-configuration to send IGMP join and multicast
+ traffic
+
+ parameters:
+ -----------
+ * `tgen`: topogen object
+ * `topo`: input json data
+ * `tc_name`: caller test case name
+ * `iperf`: router running iperf
+ * `iperf_intf`: interface name router running iperf
+ * `GROUP_RANGE`: group range
+ * `join`: IGMP join, default False
+ * `traffic`: multicast traffic, default False
+ """
+
+ if join:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ if traffic:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ router_list = tgen.routers()
+ for router in router_list.keys():
+ if router == iperf:
+ continue
+
+ rnode = router_list[router]
+ rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter")
+
+ for router in topo["routers"].keys():
+ if "static_routes" in topo["routers"][router]:
+ static_routes = topo["routers"][router]["static_routes"]
+ for static_route in static_routes:
+ network = static_route["network"]
+ next_hop = static_route["next_hop"]
+ if type(network) is not list:
+ network = [network]
+
+ return True
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+def test_mroute_when_RP_reachable_default_route_p2(request):
+ """
+ TC_49 Verify mroute when and source RP is reachable using default route
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove c1-c2 connected link to simulate topo "
+ "c1(FHR)---l1(RP)----r2---f1-----c2(LHR)"
+ )
+
+ intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"]
+ intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"]
+ shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False)
+ shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_c2_i5 = topo["routers"]["c2"]["links"]["i5"]["interface"]
+ input_dict = {
+ "c2": {"igmp": {"interfaces": {intf_c2_i5: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "l1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send traffic from C1 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+ input_src = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i4 = topo["routers"]["i4"]["links"]["c1"]["ipv4"].split("/")[0]
+
+ input_dict_starg = [
+ {
+ "dut": "c2",
+ "src_address": "*",
+ "iif": topo["routers"]["c2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["c2"]["links"]["i5"]["interface"],
+ }
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "c2",
+ "src_address": source_i4,
+ "iif": topo["routers"]["c2"]["links"]["f1"]["interface"],
+ "oil": topo["routers"]["c2"]["links"]["i5"]["interface"],
+ }
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_sg:
+ result = verify_ip_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_starg:
+ result = verify_ip_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("Delete static routes on c2")
+ input_dict = {
+ "c2": {
+ "static_routes": [
+ {
+ "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"],
+ "next_hop": "10.0.3.2",
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ step("Verify RP info unknown after removing static route from c2 ")
+ dut = "c2"
+ rp_address = topo["routers"]["l1"]["links"]["lo"]["ipv4"].split("/")[0]
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify mroute not present after Delete of static routes on c1")
+
+ for data in input_dict_sg:
+ result = verify_ip_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_starg:
+ result = verify_ip_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
+ )
+
+ step("Configure default routes on c2")
+
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["ipv4"].split("/")[0]
+
+ input_dict = {
+ "c2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_f1_c2}]}
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ step("applying ip nht config on c2")
+
+ raw_config = {"c2": {"raw_config": ["ip nht resolve-via-default"]}}
+
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify RP info is NOT unknown after removing static route from c2 ")
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False
+ )
+ assert result is not True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify (s,g) populated after adding default route ")
+
+ for data in input_dict_sg:
+ result = verify_ip_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 (*,g) populated after adding default route ")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ write_test_footer(tc_name)
+
+
+def test_mroute_with_RP_default_route_all_nodes_p2(request):
+ """
+ TC_50 Verify mroute when LHR,FHR,RP and transit routers reachable
+ using default routes
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove c1-c2 connected link to simulate topo "
+ "c1(LHR)---l1(RP)----r2---f1-----c2(FHR)"
+ )
+
+ intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"]
+ intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"]
+ shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False)
+ shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_c1_i4 = topo["routers"]["c1"]["links"]["i4"]["interface"]
+ input_dict = {
+ "c1": {"igmp": {"interfaces": {intf_c1_i4: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "l1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send traffic from C2 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+ input_src = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0]
+
+ input_dict_starg = [
+ {
+ "dut": "c1",
+ "src_address": "*",
+ "iif": topo["routers"]["c1"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+ }
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "c1",
+ "src_address": source_i5,
+ "iif": topo["routers"]["c1"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+ }
+ ]
+
+ step("Verify mroutes and iff upstream")
+
+ for data in input_dict_sg:
+ result = verify_ip_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_starg:
+ result = verify_ip_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("Delete static routes RP on all the nodes")
+ input_dict = {
+ "c2": {
+ "static_routes": [
+ {"network": ["1.0.4.11/32"], "next_hop": "10.0.3.2", "delete": True}
+ ]
+ },
+ "c1": {
+ "static_routes": [
+ {"network": ["1.0.4.11/32"], "next_hop": "10.0.2.2", "delete": True}
+ ]
+ },
+ "r2": {
+ "static_routes": [
+ {"network": ["1.0.4.11/32"], "next_hop": "10.0.12.1", "delete": True}
+ ]
+ },
+ "f1": {
+ "static_routes": [
+ {"network": ["1.0.4.11/32"], "next_hop": "10.0.7.2", "delete": True}
+ ]
+ },
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ step("Verify RP info unknown after removing static route from c2 ")
+ dut = "c2"
+ rp_address = topo["routers"]["l1"]["links"]["lo"]["ipv4"].split("/")[0]
+ SOURCE = "Static"
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ for data in input_dict_starg:
+ result = verify_ip_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
+ )
+
+ step("Configure default routes on all the nodes")
+
+ intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["ipv4"].split("/")[0]
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["ipv4"].split("/")[0]
+ intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["ipv4"].split("/")[0]
+ intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["ipv4"].split("/")[0]
+
+ input_dict = {
+ "c1": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_l1_c1}]},
+ "c2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_f1_c2}]},
+ "r2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_l1_r2}]},
+ "f1": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_r2_f1}]},
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ step("applying ip nht config on c2")
+
+ raw_config = {
+ "c1": {"raw_config": ["ip nht resolve-via-default"]},
+ "c2": {"raw_config": ["ip nht resolve-via-default"]},
+ "r2": {"raw_config": ["ip nht resolve-via-default"]},
+ "f1": {"raw_config": ["ip nht resolve-via-default"]},
+ "l1": {"raw_config": ["ip nht resolve-via-default"]},
+ }
+
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify RP info Not unknown after removing static route from c2 ")
+ dut = "c2"
+ step("Verify RP info is NOT unknown after removing static route from c2 ")
+ result = verify_pim_rp_info(
+ tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False
+ )
+ assert result is not True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify (s,g) populated after adding default route ")
+
+ for data in input_dict_sg:
+ result = verify_ip_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 (*,g) populated after adding default route ")
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ write_test_footer(tc_name)
+
+
+def test_PIM_hello_tx_rx_p1(request):
+ """
+ TC_54 Verify received and transmit hello stats
+ are getting cleared after PIM nbr reset
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ kill_iperf(tgen)
+ clear_ip_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_ip_pim_interface_traffic(tgen, topo)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ step(
+ "Remove c1-c2 connected link to simulate topo "
+ "c1(LHR)---l1(RP)----r2---f1-----c2(FHR)"
+ )
+
+ intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"]
+ intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"]
+ shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False)
+ shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False)
+
+ step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+ step(
+ "Enable IGMP of FRR1 interface and send IGMP joins "
+ " from FRR1 node for group range (225.1.1.1-5)"
+ )
+
+ intf_c1_i4 = topo["routers"]["c1"]["links"]["i4"]["interface"]
+ input_dict = {
+ "c1": {"igmp": {"interfaces": {intf_c1_i4: {"igmp": {"version": "2"}}}}}
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ input_join = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]}
+
+ for recvr, recvr_intf in input_join.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "l1": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Send Mcast traffic from C2 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+ input_src = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]}
+
+ for src, src_intf in input_src.items():
+ result = config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0]
+
+ input_dict_starg = [
+ {
+ "dut": "c1",
+ "src_address": "*",
+ "iif": topo["routers"]["c1"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+ }
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "c1",
+ "src_address": source_i5,
+ "iif": topo["routers"]["c1"]["links"]["l1"]["interface"],
+ "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+ }
+ ]
+
+ step("(*,G) and (S,G) created on f1 and node verify using 'show ip mroute'")
+ for data in input_dict_sg:
+ result = verify_ip_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)
+
+ for data in input_dict_starg:
+ result = verify_ip_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)
+
+ intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"]
+ intf_c1_l1 = topo["routers"]["c1"]["links"]["l1"]["interface"]
+
+ step("verify before stats on C1")
+ state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}}
+
+ c1_state_before = verify_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ c1_state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("Flap PIM nbr while doing interface c1-l1 interface shut from f1 side")
+ shutdown_bringup_interface(tgen, "c1", intf_c1_l1, False)
+
+ step(
+ "After shut of local interface from c1 , verify rx/tx hello counters are cleared on c1 side"
+ "verify using 'show ip pim interface traffic'"
+ )
+ shutdown_bringup_interface(tgen, "c1", intf_c1_l1, True)
+
+ step("verify stats after on c1")
+ c1_state_after = verify_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ c1_state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("verify stats not increamented on c1")
+ result = verify_state_incremented(c1_state_before, c1_state_after)
+ assert (
+ result is not True
+ ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result)
+
+ step("verify before stats on l1")
+ l1_state_dict = {"l1": {intf_l1_c1: ["helloTx", "helloRx"],}}
+
+ l1_state_before = verify_pim_interface_traffic(tgen, l1_state_dict)
+ assert isinstance(
+ l1_state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("Flap PIM nbr while doing interface r2-c1 shut from r2 side")
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False)
+
+ step(
+ "After shut the interface from r2 side , verify r2 side rx and tx of hello"
+ "counters are resetted show ip pim interface traffic"
+ )
+ shutdown_bringup_interface(tgen, "l1", intf_l1_c1, True)
+
+ step("verify stats after on l1")
+ l1_state_after = verify_pim_interface_traffic(tgen, l1_state_dict)
+ assert isinstance(
+ l1_state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("verify stats not increamented on l1")
+ result = verify_state_incremented(l1_state_before, l1_state_after)
+ assert (
+ result is not True
+ ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result)
+
+ step("Reinit the dict")
+ c1_state_before = {}
+ l1_state_before = {}
+ c1_state_after = {}
+ l1_state_after = {}
+
+ step("verify before stats on C1")
+ state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}}
+
+ c1_state_before = verify_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ c1_state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("Flap c1-r2 pim nbr while changing ip address from c1 side")
+ c1_l1_ip_subnet = topo["routers"]["c1"]["links"]["l1"]["ipv4"]
+
+ raw_config = {
+ "c1": {
+ "raw_config": [
+ "interface {}".format(intf_c1_l1),
+ "no ip address {}".format(c1_l1_ip_subnet),
+ "ip address {}".format(NEW_ADDRESS_2_SUBNET),
+ ]
+ }
+ }
+
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify stats after on c1")
+ c1_state_after = verify_pim_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ c1_state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n "
+ "Error: {}".format(tc_name, result)
+
+ step("verify stats not increamented on c1")
+ result = verify_state_incremented(c1_state_before, c1_state_after)
+ assert (
+ result is not True
+ ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/ospf_chaos.json b/tests/topotests/ospf_basic_functionality/ospf_chaos.json
new file mode 100644
index 0000000000..ed199f181b
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_chaos.json
@@ -0,0 +1,166 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r1": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py
new file mode 100644
index 0000000000..37b7528490
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py
@@ -0,0 +1,576 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+from copy import deepcopy
+import json
+
+# 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/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ topo_daemons,
+ verify_rib,
+ stop_router, start_router,
+ create_static_routes,
+ start_router_daemons,
+ kill_router_daemons
+)
+
+from lib.ospf import (
+ verify_ospf_neighbor, verify_ospf_rib,
+ create_router_ospf)
+
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+from ipaddress import IPv4Address
+
+
+
+# Global variables
+topo = None
+
+NETWORK = {
+ "ipv4": ["11.0.20.1/32", "11.0.20.2/32", "11.0.20.3/32", "11.0.20.4/32",
+ "11.0.20.5/32"]
+}
+"""
+Topology:
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. Verify ospf functionality after restart ospfd.
+2. Verify ospf functionality after restart FRR service.
+3. Verify ospf functionality when staticd is restarted.
+ """
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_chaos.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ 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")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+def test_ospf_chaos_tc31_p1(request):
+ """Verify ospf functionality after restart ospfd."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Create static routes(10.0.20.1/32) in R1 and redistribute "
+ "to OSPF using route map.")
+
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK['ipv4'][0],
+ "no_of_ip": 5,
+ "next_hop": 'Null0',
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ ospf_red_r0 = {
+ "r0": {
+ "ospf": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify OSPF neighbors after base config is done.")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step("Verify that route is advertised to R1.")
+ dut = 'r1'
+ protocol = 'ospf'
+ nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0]
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Kill OSPFd daemon on R0.")
+ kill_router_daemons(tgen, "r0", ["ospfd"])
+
+ step("Verify OSPF neighbors are down after killing ospfd in R0")
+ dut = 'r0'
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut,
+ expected=False)
+ assert ospf_covergence is not True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step("Verify that route advertised to R1 are deleted from RIB and FIB.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Bring up OSPFd daemon on R0.")
+ start_router_daemons(tgen, "r0", ["ospfd"])
+
+ step("Verify OSPF neighbors are up after bringing back ospfd in R0")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Kill OSPFd daemon on R1.")
+ kill_router_daemons(tgen, "r1", ["ospfd"])
+
+ step("Verify OSPF neighbors are down after killing ospfd in R1")
+ dut = 'r1'
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut,
+ expected=False)
+ assert ospf_covergence is not True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step("Bring up OSPFd daemon on R1.")
+ start_router_daemons(tgen, "r1", ["ospfd"])
+
+ step("Verify OSPF neighbors are up after bringing back ospfd in R1")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_chaos_tc32_p1(request):
+ """Verify ospf functionality after restart FRR service. """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Create static routes(10.0.20.1/32) in R1 and redistribute "
+ "to OSPF using route map.")
+
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK['ipv4'][0],
+ "no_of_ip": 5,
+ "next_hop": 'Null0',
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ ospf_red_r0 = {
+ "r0": {
+ "ospf": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify OSPF neighbors after base config is done.")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step("Verify that route is advertised to R1.")
+ dut = 'r1'
+ protocol = 'ospf'
+
+ nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0]
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Restart frr on R0")
+ stop_router(tgen, 'r0')
+ start_router(tgen, 'r0')
+
+ step("Verify OSPF neighbors are up after restarting R0")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Restart frr on R1")
+ stop_router(tgen, 'r1')
+ start_router(tgen, 'r1')
+
+ step("Verify OSPF neighbors are up after restarting R1")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_chaos_tc34_p1(request):
+ """
+ verify ospf functionality when staticd is restarted.
+
+ Verify ospf functionalitywhen staticroutes are
+ redistributed & Staticd is restarted.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Create static routes(10.0.20.1/32) in R1 and redistribute "
+ "to OSPF using route map.")
+
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK['ipv4'][0],
+ "no_of_ip": 5,
+ "next_hop": 'Null0',
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ ospf_red_r0 = {
+ "r0": {
+ "ospf": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify OSPF neighbors after base config is done.")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step("Verify that route is advertised to R1.")
+ dut = 'r1'
+ protocol = 'ospf'
+ nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0]
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Kill staticd daemon on R0.")
+ kill_router_daemons(tgen, "r0", ["staticd"])
+
+ step("Verify that route advertised to R1 are deleted from RIB and FIB.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Bring up staticd daemon on R0.")
+ start_router_daemons(tgen, "r0", ["staticd"])
+
+ step("Verify OSPF neighbors are up after bringing back ospfd in R0")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Kill staticd daemon on R1.")
+ kill_router_daemons(tgen, "r1", ["staticd"])
+
+ step("Bring up staticd daemon on R1.")
+ start_router_daemons(tgen, "r1", ["staticd"])
+
+ step("Verify OSPF neighbors are up after bringing back ospfd in R1")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(ospf_covergence))
+
+ step(
+ "All the neighbours are up and routes are installed before the"
+ " restart. Verify OSPF route table and ip route table.")
+
+ dut = 'r1'
+ protocol = 'ospf'
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
+ next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index d1b18a57bb..0c45a09445 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -1,16 +1,29 @@
# Skip pytests example directory
[pytest]
norecursedirs = .git example-test example-topojson-test lib docker
+
+# Markers
+#
+# Please consult the documentation and discuss with TSC members before applying
+# any changes to this list.
markers =
- babel: Tests that run against BABEL
- bfd: Tests that run against BFDD
- eigrp: Tests that run against EIGRPD
- isis: Tests that run against ISISD
- ldp: Tests that run against LDPD
- ospf: Tests that run against OSPF( v2 and v3 )
- pbr: Tests that run against PBRD
- pim: Tests that run against pim
- rip: Tests that run against RIP, both v4 and v6
+ babeld: Tests that run against BABELD
+ bfdd: Tests that run against BFDD
+ bgpd: Tests that run against BGPD
+ eigrpd: Tests that run against EIGRPD
+ isisd: Tests that run against ISISD
+ ldpd: Tests that run against LDPD
+ nhrpd: Tests that run against NHRPD
+ ospf6d: Tests that run against OSPF6D
+ ospfd: Tests that run against OSPFD
+ pathd: Tests that run against PATHD
+ pbrd: Tests that run against PBRD
+ pimd: Tests that run against PIMD
+ ripd: Tests that run against RIPD
+ ripngd: Tests that run against RIPNGD
+ sharpd: Tests that run against SHARPD
+ staticd: Tests that run against STATICD
+ vrrpd: Tests that run against VRRPD
[topogen]
# Default configuration values