diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:16:35 +0000 |
commit | e2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch) | |
tree | f0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /tests/topotests/multicast_pim_sm_topo3 | |
parent | Initial commit. (diff) | |
download | frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip |
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/topotests/multicast_pim_sm_topo3')
11 files changed, 6382 insertions, 0 deletions
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json new file mode 100644 index 0000000..715aa1d --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json new file mode 100644 index 0000000..3bbcce1 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json @@ -0,0 +1,51 @@ +{ + "totalGroups":5, + "watermarkLimit":0, + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "state":"up", + "address":"10.0.8.2", + "index":"*", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "groups":[ + { + "group":"225.1.1.1", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.2", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.3", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.4", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.5", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + } + ] + } +} + diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json new file mode 100644 index 0000000..876befa --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json new file mode 100644 index 0000000..a3fb496 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json @@ -0,0 +1,22 @@ +{ + "totalGroups":5, + "watermarkLimit":0, + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "state":"up", + "address":"10.0.8.2", + "index":"*", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "groups":[ + { + "group":"225.1.1.5", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + } + ] + } +} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json new file mode 100644 index 0000000..11ac5a0 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json new file mode 100644 index 0000000..10ae1af --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json @@ -0,0 +1,61 @@ +{ + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "225.1.1.1":{ + "group":"225.1.1.1", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.2":{ + "group":"225.1.1.2", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.3":{ + "group":"225.1.1.3", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.4":{ + "group":"225.1.1.4", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.5":{ + "group":"225.1.1.5", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + } + } +} + diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json new file mode 100644 index 0000000..7a19975 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json @@ -0,0 +1,16 @@ +{ + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "225.1.1.4":{ + "group":"225.1.1.4", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + } + } +} 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 0000000..89c54a4 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo3.json @@ -0,0 +1,146 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"}, + "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, + "routers": { + "l1": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "i1": {"ipv4": "auto", "pim": "enable"}, + "i6": {"ipv4": "auto", "pim": "enable"}, + "i7": {"ipv4": "auto", "pim": "enable"}, + "r2": {"ipv4": "auto", "pim": "enable"}, + "c1": {"ipv4": "auto", "pim": "enable"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "igmp": { + "interfaces": { + "l1-i1-eth1" :{ + "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, + "version": "2" + } + } + } + }, + "static_routes": [{ + "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "static_routes": [{ + "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "static_routes": [{ + "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "static_routes": [{ + "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "static_routes": [{ + "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.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 0000000..afb5599 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo4.json @@ -0,0 +1,143 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"}, + "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, + "routers": { + "l1": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "i1": {"ipv4": "auto", "pim": "enable"}, + "i6": {"ipv4": "auto", "pim": "enable"}, + "i7": {"ipv4": "auto", "pim": "enable"}, + "r2": {"ipv4": "auto", "pim": "enable"}, + "c1": {"ipv4": "auto", "pim": "enable"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "igmp": { + "interfaces": { + "l1-i1-eth1" :{ + "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, + "version": "2" + } + } + } + }, + "static_routes": [{ + "network": ["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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "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"} + }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, + "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 0000000..2c1241c --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -0,0 +1,4856 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# + +""" +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 time +import datetime +import pytest +from time import sleep +import json +import functools + +pytestmark = pytest.mark.pimd + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + step, + reset_config_on_routers, + shutdown_bringup_interface, + apply_raw_config, + check_router_status, + required_linux_kernel_version, + topo_daemons, +) +from lib.pim import ( + create_pim_config, + create_igmp_config, + verify_igmp_groups, + verify_mroutes, + clear_mroute, + clear_pim_interface_traffic, + verify_igmp_config, + verify_pim_config, + verify_pim_interface, + verify_upstream_iif, + verify_multicast_traffic, + verify_pim_rp_info, + verify_multicast_flag_state, + McastTesterHelper, + verify_pim_interface_traffic, +) +from lib.topolog import logger +from lib.topojson import build_config_from_json + +CWD = os.path.dirname(os.path.realpath(__file__)) +pytestmark = pytest.mark.pimd + +TOPOLOGY = """ + + i4-----c1-------------c2---i5 + | | + | | + i1-----l1------r2-----f1---i2 + | | | | + | | | | + i7 i6 i3 i8 + + Description: + i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP + join and traffic + l1 - LHR + 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"} + + +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 version should be >= 4.19") + + 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") + + json_file = "{}/multicast_pim_sm_topo3.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # XXX Replace this using "with McastTesterHelper()... " in each test if possible. + global app_helper + app_helper = McastTesterHelper(tgen) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + app_helper.cleanup() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + + +def verify_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 ttype, v1 in state_before.items(): + for intf, v2 in v1.items(): + for state, value in v2.items(): + if value >= state_after[ttype][intf][state]: + errormsg = "[DUT: %s]: state %s value has not incremented, Initial value: %s, Current value: %s [FAILED!!]" % ( + intf, + state, + value, + state_after[ttype][intf][state], + ) + return errormsg + + logger.info( + "[DUT: %s]: State %s value is incremented, Initial value: %s, Current value: %s [PASSED!!]", + intf, + state, + value, + state_after[ttype][intf][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(tgen.logdir, 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(tgen.logdir, 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 verify_pim_stats_increament(stats_before, stats_after): + """ + API to compare pim interface control plane traffic + + Parameters + ---------- + * `stats_before` : Stats dictionary for any particular instance + * `stats_after` : Stats dictionary for any particular instance + """ + + for router, stats_data in stats_before.items(): + for stats, value in stats_data.items(): + if stats_before[router][stats] >= stats_after[router][stats]: + errormsg = ( + "[DUT: %s]: state %s value has not" + " incremented, Initial value: %s, " + "Current value: %s [FAILED!!]" + % ( + router, + stats, + stats_before[router][stats], + stats_after[router][stats], + ) + ) + return errormsg + + logger.info( + "[DUT: %s]: State %s value is " + "incremented, Initial value: %s, Current value: %s" + " [PASSED!!]", + router, + stats, + stats_before[router][stats], + stats_after[router][stats], + ) + + 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_join = { + "i1": topo["routers"]["i1"]["links"]["l1"]["interface"], + "i8": topo["routers"]["i8"]["links"]["f1"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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 " + "Expected: [{}]: Multicast traffic should be stopped \n " + "Found: {}".format(tc_name, "l1", 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 " + "Expected: [{}]: IGMP groups should be deleted \n " + "Found: {}".format(tc_name, dut, 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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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 " + "Expected: [{}]: Upstream IIF {} should not be present \n " + "Found: {}".format(tc_name, data["dut"], data["iif"], 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_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 " + "Expected: [{}]: Multicast traffic should be stopped \n " + "Found: {}".format(tc_name, "f1", 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 " + "Expected: [{}]: IGMP groups should be deleted \n " + "Found: {}".format(tc_name, dut, 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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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 " + "Expected: [{}]: Upstream IIF {} should not be present \n " + "Found: {}".format(tc_name, data["dut"], data["iif"], 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_join = { + "i1": topo["routers"]["i1"]["links"]["l1"]["interface"], + "i3": topo["routers"]["i3"]["links"]["r2"]["interface"], + } + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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 " + "Expected: [{}]: Upstream IIF {} should not be present \n " + "Found: {}".format(tc_name, data["dut"], data["iif"], 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, "f1", 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' " + ) + + result = verify_upstream_iif( + tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: Upstream IIF should be Unknown \n " + "Found: {}".format(tc_name, "l1", result) + ) + + 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_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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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' " + ) + + result = verify_upstream_iif( + tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: Upstream IIF should be Unknown \n " + "Found: {}".format(tc_name, "l1", result) + ) + + 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_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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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) + + # IGMP JSON verification + step("Verify IGMP group and source JSON for single interface and group") + router = tgen.gears["l1"] + + reffile = os.path.join(CWD, "igmp_group_all_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for all interfaces and all groups is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_group_all_brief.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group output on l1 for all groups in interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_group_all_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for all groups in interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_single_group_brief.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 225.1.1.5 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group output on l1 for interface l1-i1-eth1 and group 225.1.1.5 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_single_group_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 225.1.1.5 detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for interface l1-i1-eth1 and group 225.1.1.5 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_source_single_if_group_all.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp sources l1-i1-eth1 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP source output on l1 for interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_source_single_if_single_group.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp sources l1-i1-eth1 225.1.1.4 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP source output on l1 for interface l1-i1-eth1 and group 225.1.1.4 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + 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 " + "Expected: [{}]: IGMP groups should not be present \n " + "Found: {}".format(tc_name, dut, 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", "query": {"query-interval": 15}} + } + } + } + } + } + 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_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 " + "Expected: [{}]: IGMP groups should not be present \n " + "Found: {}".format(tc_name, dut, 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", "query": {"query-interval": 15}} + } + } + } + } + } + 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_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_mroutes( + tgen, dut, source, IGMP_JOIN_RANGE_1, iif, oil, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, dut, 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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", + "query": { + "query-max-response-time": 40, + "query-interval": 5, + }, + } + } + } + } + } + } + + 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 " + "Expected: [{}]: IGMP interface should be removed \n " + "Found: {}".format(tc_name, data["dut"], 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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"] + raw_config = { + "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim"]} + } + 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 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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_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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + for data in input_dict_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Send prune from receiver-1 (using ctrl+c) on iperf interface") + app_helper.stop_all_hosts() + + 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) + 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 " + "Expected: [{}]: IGMP groups should not present \n " + "Found: {}".format(tc_name, dut, 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) + 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Send traffic from FHR and verify mroute upstream") + + for src, src_intf in input_src.items(): + result = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + for data in input_dict_sg_i1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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 " + "Expected: [{}]: Upstream IIF interface {} should not be present\n" + "Found: {}".format(tc_name, data["dut"], data["iif"], 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 " + "Expected: [{}]: RP IIF should be updated as Unknown \n " + "Found: {}".format(tc_name, dut, result) + ) + + step("Verify mroute after No shut the link from LHR to RP from RP node") + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i2: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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) + + 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_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_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 \n " + "Expected: [{}]: Upstream IIF interface {} should not be present" + " after shutting link from RP to FHR \n" + "Found: {}".format(tc_name, data["dut"], data["iif"], 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 " + "Expected: [{}]: RP IIF should be updated as Unknown \n" + "Found: {}".format(tc_name, dut, result) + ) + + step("Verify mroute after Noshut the link from FHR to RP from RP node") + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i2: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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") + + 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_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_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 \n " + "Expected: [{}]: Upstream IIF interface {} should not be present" + " after shutting link from FHR to RP \n" + "Found: {}".format(tc_name, data["dut"], data["iif"], 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 " + "Expected: [{}]: RP IIF should be updated as Unknown \n" + "Found: {}".format(tc_name, dut, result) + ) + + step("Verify mroute after No Shut the link from FHR to RP from FHR node") + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i2: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg_i1: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + + for recvr, recvr_intf in input_join.items(): + result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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", "query": {"query-interval": 15}} + } + } + } + } + } + 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 = app_helper.run_join(recvr, _IGMP_JOIN_RANGE, join_intf=recvr_intf) + 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 = app_helper.run_traffic(src, _IGMP_JOIN_RANGE, bind_intf=src_intf) + 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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_mroutes( + tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, dut, 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_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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + check_router_status(tgen) + + 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 = app_helper.run_join(recvr, _IGMP_JOIN_RANGE, join_intf=recvr_intf) + 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 = app_helper.run_traffic(src, _IGMP_JOIN_RANGE, bind_intf=src_intf) + 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], 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_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_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: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + write_test_footer(tc_name) + + +def test_PIM_passive_p1(request): + """ + TC Verify PIM passive functionality" + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + app_helper.stop_all_hosts() + # Creating configuration from JSON + clear_mroute(tgen) + if tgen.routers_have_failure(): + check_router_status(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + 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"] + + step( + "configure PIM passive on receiver interface to verify no impact on IGMP join" + "and multicast traffic on pim passive interface" + ) + + raw_config = { + "c1": {"raw_config": ["interface {}".format(intf_c1_i4), "ip pim passive"]} + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("configure IGMPv2 and send IGMP joinon on PIM passive 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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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_1, + } + ] + } + } + } + + 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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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"]["c2"]["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_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: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"] + intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"] + + step( + "configure PIM passive on upstream interface to verify" + "hello tx/rx counts are not incremented" + ) + + # Changing hello timer to 3sec for checking more number of packets + + raw_config = { + "c1": { + "raw_config": [ + "interface {}".format(intf_c1_c2), + "ip pim passive", + "ip pim hello 3", + ] + }, + "c2": {"raw_config": ["interface {}".format(intf_c2_c1), "ip pim hello 3"]}, + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify PIM hello tx/rx stats on C1") + state_dict = { + "c1": { + intf_c1_c2: ["helloTx", "helloRx"], + } + } + + logger.info("waiting for 5 sec config to get apply and hello count update") + sleep(5) + + 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 + ) + + logger.info( + "sleeping for 30 sec hello interval timer to verify count are not increamented" + ) + sleep(35) + + 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_pim_stats_increament(c1_state_before, c1_state_after) + assert ( + result is not True + ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) + + step("No impact observed on mroutes") + for data in input_dict_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("remove PIM passive and verify hello tx/rx is increamented") + raw_config = { + "c1": { + "raw_config": [ + "interface {}".format(intf_c1_c2), + "no ip pim passive", + "ip pim hello 3", + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + logger.info("waiting for 30 sec for pim hello to receive") + sleep(30) + + 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 increamented on c1 after removing pim passive") + result = verify_pim_stats_increament(c1_state_before, c1_state_after) + assert result is 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/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 0000000..825281a --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py @@ -0,0 +1,1084 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# + +""" +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 sys +import time +import pytest + +pytestmark = pytest.mark.pimd + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + step, + reset_config_on_routers, + shutdown_bringup_interface, + apply_raw_config, + create_static_routes, + required_linux_kernel_version, + topo_daemons, +) +from lib.pim import ( + create_pim_config, + create_igmp_config, + verify_mroutes, + clear_pim_interface_traffic, + verify_upstream_iif, + clear_mroute, + verify_pim_rp_info, + get_pim_interface_traffic, + McastTesterHelper, +) +from lib.topolog import logger +from lib.topojson import build_config_from_json +from time import sleep + + +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" + + +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 version should be >= 4.19") + + 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") + + json_file = "{}/multicast_pim_sm_topo4.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # XXX Replace this using "with McastTesterHelper()... " in each test if possible. + global app_helper + app_helper = McastTesterHelper(tgen) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + app_helper.cleanup() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + + +def reset_stats(stats): + """ + API to reset the stats + + Parameters + ---------- + * `stats` : State dictionary holding helloRx and helloTx values + """ + + for router, state_data in stats.items(): + for state, value in state_data.items(): + stats[router][state] = 0 + logger.info( + "[DUT: %s]: stats %s value has reset" " reset, Current value: %s", + router, + state, + stats[router][state], + ) + + 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + step( + "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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: Upstream IIF interface {} should not be present\n " + "Found: {}".format(tc_name, data["dut"], data["iif"], result) + ) + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: Upstream IIF interface {} should not be present\n " + "Found: {}".format(tc_name, data["dut"], data["iif"], 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 " + "Expected: [{}]: RP Info should not be Unknown after removing static" + " route from c2 \n" + "Found: {}".format(tc_name, data["dut"], result) + ) + + step("Verify (s,g) populated after adding default route ") + + for data in input_dict_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify (*,g) populated after adding default route ") + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + step( + "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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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_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 " + "Expected: [{}]: mroute (S, G) should not be present in mroute table \n " + "Found: {}".format(tc_name, data["dut"], result) + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: [{}]: Upstream IIF interface {} should not be present\n " + "Found: {}".format(tc_name, data["dut"], data["iif"], 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 " + "Expected: [{}]: RP Info should not be Unknown after removing static" + " route from c2 \n" + "Found: {}".format(tc_name, data["dut"], result) + ) + + step("Verify (s,g) populated after adding default route ") + + for data in input_dict_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify (*,g) populated after adding default route ") + + for data in input_dict_starg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + 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) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + step( + "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 = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("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 = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf) + 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_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_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"] + + state_dict = { + "c1": { + intf_c1_l1: ["helloTx", "helloRx"], + } + } + + c1_state_before = get_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) + + """ Resetting the stats here since shutdown resets the stats. + """ + reset_stats(c1_state_before) + shutdown_bringup_interface(tgen, "c1", intf_c1_l1, True) + + step("verify stats after no shutdown on c1 and that they are incremented") + + count = 0 + done = False + while not done and count <= 7: + c1_state_after = get_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 + ) + + result = verify_state_incremented(c1_state_before, c1_state_after) + if result is not True: + sleep(5) + count += 1 + else: + done = True + + assert ( + result is True + ), "Testcase{} : Failed Error: {}" "stats is not incremented".format( + tc_name, result + ) + + step("verify before stats on l1") + l1_state_dict = { + "l1": { + intf_l1_c1: ["helloTx", "helloRx"], + } + } + + l1_state_before = get_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 are incremented") + count = 0 + done = False + while not done and count <= 7: + l1_state_after = get_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 + ) + + result = verify_state_incremented(l1_state_before, l1_state_after) + if result is True: + sleep(5) + count += 1 + else: + done = True + + 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 = get_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 are incremented") + count = 0 + done = False + while not done and count <= 7: + c1_state_after = get_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 + ) + + result = verify_state_incremented(c1_state_before, c1_state_after) + if result is not True: + sleep(5) + count += 1 + else: + done = True + + assert result is 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)) |