Merge pull request #11736 from kuldeepkash/pim_v6

[PIMv6] Add new scenarios to multicast static_rp suite
This commit is contained in:
Donatas Abraitis 2022-11-09 17:56:32 +02:00 committed by GitHub
commit 12853c02c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 3865 additions and 478 deletions

View File

@ -3244,33 +3244,29 @@ def configure_interface_mac(tgen, input_dict):
return True
def socat_send_igmp_join_traffic(
def socat_send_mld_join(
tgen,
server,
protocol_option,
igmp_groups,
mld_groups,
send_from_intf,
send_from_intf_ip=None,
port=12345,
reuseaddr=True,
join=False,
traffic=False,
):
"""
API to send IGMP join using SOCAT tool
API to send MLD join using SOCAT tool
Parameters:
-----------
* `tgen` : Topogen object
* `server`: iperf server, from where IGMP join would be sent
* `protocol_option`: Protocol options, ex: UDP6-RECV
* `igmp_groups`: IGMP group for which join has to be sent
* `mld_groups`: IGMP group for which join has to be sent
* `send_from_intf`: Interface from which join would be sent
* `send_from_intf_ip`: Interface IP, default is None
* `port`: Port to be used, default is 12345
* `reuseaddr`: True|False, bydefault True
* `join`: If join needs to be sent
* `traffic`: If traffic needs to be sent
returns:
--------
@ -3280,36 +3276,32 @@ def socat_send_igmp_join_traffic(
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
rnode = tgen.routers()[server]
socat_cmd = "socat -u "
socat_args = "socat -u "
# UDP4/TCP4/UDP6/UDP6-RECV
# UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
if protocol_option:
socat_cmd += "{}".format(protocol_option)
socat_args += "{}".format(protocol_option)
if port:
socat_cmd += ":{},".format(port)
socat_args += ":{},".format(port)
if reuseaddr:
socat_cmd += "{},".format("reuseaddr")
socat_args += "{},".format("reuseaddr")
# Group address range to cover
if igmp_groups:
if not isinstance(igmp_groups, list):
igmp_groups = [igmp_groups]
if mld_groups:
if not isinstance(mld_groups, list):
mld_groups = [mld_groups]
for igmp_group in igmp_groups:
if join:
join_traffic_option = "ipv6-join-group"
elif traffic:
join_traffic_option = "ipv6-join-group-source"
for mld_group in mld_groups:
socat_cmd = socat_args
join_option = "ipv6-join-group"
if send_from_intf and not send_from_intf_ip:
socat_cmd += "{}='[{}]:{}'".format(
join_traffic_option, igmp_group, send_from_intf
)
socat_cmd += "{}='[{}]:{}'".format(join_option, mld_group, send_from_intf)
else:
socat_cmd += "{}='[{}]:{}:[{}]'".format(
join_traffic_option, igmp_group, send_from_intf, send_from_intf_ip
join_option, mld_group, send_from_intf, send_from_intf_ip
)
socat_cmd += " STDOUT"
@ -3324,6 +3316,124 @@ def socat_send_igmp_join_traffic(
return True
def socat_send_pim6_traffic(
tgen,
server,
protocol_option,
mld_groups,
send_from_intf,
port=12345,
multicast_hops=True,
):
"""
API to send pim6 data taffic using SOCAT tool
Parameters:
-----------
* `tgen` : Topogen object
* `server`: iperf server, from where IGMP join would be sent
* `protocol_option`: Protocol options, ex: UDP6-RECV
* `mld_groups`: MLD group for which join has to be sent
* `send_from_intf`: Interface from which join would be sent
* `port`: Port to be used, default is 12345
* `multicast_hops`: multicast-hops count, default is 255
returns:
--------
errormsg or True
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
rnode = tgen.routers()[server]
socat_args = "socat -u STDIO "
# UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
if protocol_option:
socat_args += "'{}".format(protocol_option)
# Group address range to cover
if mld_groups:
if not isinstance(mld_groups, list):
mld_groups = [mld_groups]
for mld_group in mld_groups:
socat_cmd = socat_args
if port:
socat_cmd += ":[{}]:{},".format(mld_group, port)
if send_from_intf:
socat_cmd += "interface={0},so-bindtodevice={0},".format(send_from_intf)
if multicast_hops:
socat_cmd += "multicast-hops=255'"
socat_cmd += " &>{}/socat.logs &".format(tgen.logdir)
# Run socat command to send pim6 traffic
logger.info(
"[DUT: {}]: Running command: [set +m; ( while sleep 1; do date; done ) | {}]".format(
server, socat_cmd
)
)
# Open a shell script file and write data to it, which will be
# used to send pim6 traffic continously
traffic_shell_script = "{}/{}/traffic.sh".format(tgen.logdir, server)
with open("{}".format(traffic_shell_script), "w") as taffic_sh:
taffic_sh.write(
"#!/usr/bin/env bash\n( while sleep 1; do date; done ) | {}\n".format(
socat_cmd
)
)
rnode.run("chmod 755 {}".format(traffic_shell_script))
output = rnode.run("{} &> /dev/null".format(traffic_shell_script))
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
def kill_socat(tgen, dut=None, action=None):
"""
Killing socat process if running for any router in topology
Parameters:
-----------
* `tgen` : Topogen object
* `dut` : Any iperf hostname to send igmp prune
* `action`: to kill mld join using socat
to kill mld traffic using socat
Usage:
------
kill_socat(tgen, dut ="i6", action="remove_mld_join")
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
router_list = tgen.routers()
for router, rnode in router_list.items():
if dut is not None and router != dut:
continue
if action == "remove_mld_join":
cmd = "ps -ef | grep socat | grep UDP6-RECV | grep {}".format(router)
elif action == "remove_mld_traffic":
cmd = "ps -ef | grep socat | grep UDP6-SEND | grep {}".format(router)
else:
cmd = "ps -ef | grep socat".format(router)
awk_cmd = "awk -F' ' '{print $2}' | xargs kill -9 &>/dev/null &"
cmd = "{} | {}".format(cmd, awk_cmd)
logger.debug("[DUT: {}]: Running command: [{}]".format(router, cmd))
rnode.run(cmd)
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
#############################################
# Verification APIs
#############################################

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,414 +0,0 @@
#!/usr/bin/env python
#
# Copyright (c) 2022 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation,
# Inc. ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
Following tests are covered to test Multicast basic functionality:
Topology:
_______r2_____
| |
iperf | | iperf
r0-----r1-------------r3-----r5
| |
|_____________|
r4
Test steps
- Create topology (setup module)
- Bring up topology
TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
after adding and deleting the static RP
TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
adding and deleting the static RP
TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
same path
"""
import os
import sys
import json
import time
import pytest
from time import sleep
import datetime
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# Required to instantiate the topology builder class.
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
step,
shutdown_bringup_interface,
kill_router_daemons,
start_router_daemons,
create_static_routes,
check_router_status,
socat_send_igmp_join_traffic,
topo_daemons
)
from lib.pim import (
create_pim_config,
verify_igmp_groups,
verify_upstream_iif,
verify_join_state_and_timer,
verify_mroutes,
verify_pim_neighbors,
verify_pim_interface_traffic,
verify_pim_rp_info,
verify_pim_state,
clear_pim_interface_traffic,
clear_igmp_interfaces,
clear_pim_interfaces,
clear_mroute,
clear_mroute_verify,
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
# Global variables
GROUP_RANGE_V6 = "ff08::/64"
IGMP_JOIN_V6 = "ff08::1"
STAR = "*"
SOURCE = "Static"
pytestmark = [pytest.mark.pimd]
def build_topo(tgen):
"""Build function"""
# Building topology from json file
build_topo_from_json(tgen, TOPO)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: %s", testsuite_run_time)
logger.info("=" * 40)
topology = """
_______r2_____
| |
iperf | | iperf
r0-----r1-------------r3-----r5
| |
|_____________|
r4
"""
logger.info("Master Topology: \n %s", topology)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
json_file = "{}/multicast_pimv6_static_rp.json".format(CWD)
tgen = Topogen(json_file, mod.__name__)
global TOPO
TOPO = tgen.json_topo
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, TOPO)
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
start_topology(tgen, daemons)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Creating configuration from JSON
build_config_from_json(tgen, TOPO)
# Verify PIM neighbors
result = verify_pim_neighbors(tgen, TOPO)
assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
logger.info("Running setup_module() done")
def teardown_module():
"""Teardown the pytest environment"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info("Testsuite end time: %s", time.asctime(time.localtime(time.time())))
logger.info("=" * 40)
#####################################################
#
# Testcases
#
#####################################################
def verify_state_incremented(state_before, state_after):
"""
API to compare interface traffic state incrementing
Parameters
----------
* `state_before` : State dictionary for any particular instance
* `state_after` : State dictionary for any particular instance
"""
for router, state_data in state_before.items():
for state, value in state_data.items():
if state_before[router][state] >= state_after[router][state]:
errormsg = (
"[DUT: %s]: state %s value has not"
" incremented, Initial value: %s, "
"Current value: %s [FAILED!!]"
% (
router,
state,
state_before[router][state],
state_after[router][state],
)
)
return errormsg
logger.info(
"[DUT: %s]: State %s value is "
"incremented, Initial value: %s, Current value: %s"
" [PASSED!!]",
router,
state,
state_before[router][state],
state_after[router][state],
)
return True
#####################################################
def test_pimv6_add_delete_static_RP_p0(request):
"""
TC_1: Verify upstream interfaces(IIF) and join state are updated
properly after adding and deleting the static RP
TC_2: Verify IIF and OIL in "show ip pim state" updated properly
after adding and deleting the static RP
TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
TC_4: Verify (*,G) prune is send towards the RP after deleting the
static RP
TOPOlogy used:
r0------r1-----r2
iperf DUT RP
"""
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():
check_router_status(tgen)
step("Shut link b/w R1 and R3 and R1 and R4 as per tescase topology")
intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
for intf in [intf_r1_r3, intf_r1_r4]:
shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
step("Enable PIM between r1 and r2")
step("Enable MLD on r1 interface and send IGMP " "join (FF08::1) to r1")
step("Configure r2 loopback interface as RP")
input_dict = {
"r2": {
"pim6": {
"rp": [
{
"rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
"/"
)[0],
"group_addr_range": GROUP_RANGE_V6,
}
]
}
}
}
result = create_pim_config(tgen, TOPO, input_dict)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
step("Verify show ip pim interface traffic without any mld join")
state_dict = {
"r1": {TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["pruneTx"]}
}
state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
assert isinstance(
state_before, dict
), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
tc_name, result
)
step("send mld join (FF08::1) to R1")
intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
result = socat_send_igmp_join_traffic(
tgen, "r0", "UDP6-RECV", IGMP_JOIN_V6, intf, intf_ip, join=True
)
assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
step("r1: Verify RP info")
dut = "r1"
oif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
iif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
result = verify_pim_rp_info(
tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE
)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Verify upstream IIF interface")
result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Verify upstream join state and join timer")
result = verify_join_state_and_timer(tgen, dut, oif, STAR, IGMP_JOIN_V6)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Verify PIM state")
result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Verify ip mroutes")
result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Delete RP configuration")
input_dict = {
"r2": {
"pim6": {
"rp": [
{
"rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
"/"
)[0],
"group_addr_range": GROUP_RANGE_V6,
"delete": True,
}
]
}
}
}
result = create_pim_config(tgen, TOPO, input_dict)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
step("r1: Verify RP info")
result = verify_pim_rp_info(
tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE, expected=False
)
assert (
result is not True
), "Testcase {} :Failed \n " "RP: {} info is still present \n Error: {}".format(
tc_name, rp_address, result
)
step("r1: Verify upstream IIF interface")
result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False)
assert result is not True, (
"Testcase {} :Failed \n "
"Upstream ({}, {}) is still in join state \n Error: {}".format(
tc_name, STAR, IGMP_JOIN_V6, result
)
)
step("r1: Verify upstream join state and join timer")
result = verify_join_state_and_timer(
tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False
)
assert result is not True, (
"Testcase {} :Failed \n "
"Upstream ({}, {}) timer is still running \n Error: {}".format(
tc_name, STAR, IGMP_JOIN_V6, result
)
)
step("r1: Verify PIM state")
result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6, expected=False)
assert result is not True, (
"Testcase {} :Failed \n "
"PIM state for group: {} is still Active \n Error: {}".format(
tc_name, IGMP_JOIN_V6, result
)
)
step("r1: Verify ip mroutes")
result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif, expected=False)
assert result is not True, (
"Testcase {} :Failed \n "
"mroute ({}, {}) is still present \n Error: {}".format(
tc_name, STAR, IGMP_JOIN_V6, result
)
)
step("r1: Verify show ip pim interface traffic without any IGMP join")
state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
assert isinstance(
state_after, dict
), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
tc_name, result
)
result = verify_state_incremented(state_before, state_after)
assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -46,6 +46,7 @@ markers =
pathd: Tests that run against PATHD
pbrd: Tests that run against PBRD
pimd: Tests that run against PIMD
pim6d: Tests that run against PIM6D
ripd: Tests that run against RIPD
ripngd: Tests that run against RIPNGD
sharpd: Tests that run against SHARPD