diff --git a/tests/common/utilities.py b/tests/common/utilities.py index eda6ca4b341..208356b0cc2 100644 --- a/tests/common/utilities.py +++ b/tests/common/utilities.py @@ -686,3 +686,19 @@ def get_image_type(duthost): """ return "public" + +def find_duthost_on_role(duthosts, role, tbinfo): + role_set = False + + for duthost in duthosts: + if role_set: + break + if duthost.is_supervisor_node(): + continue + + mg_facts = duthost.get_extended_minigraph_facts(tbinfo) + for interface, neighbor in mg_facts["minigraph_neighbors"].items(): + if role in neighbor["name"]: + role_host = duthost + role_set = True + return role_host diff --git a/tests/everflow/everflow_test_utilities.py b/tests/everflow/everflow_test_utilities.py index 87ace66efa8..2c132e66c59 100644 --- a/tests/everflow/everflow_test_utilities.py +++ b/tests/everflow/everflow_test_utilities.py @@ -15,6 +15,7 @@ from abc import abstractmethod from ptf.mask import Mask from tests.common.helpers.assertions import pytest_assert +from tests.common.utilities import find_duthost_on_role import json # TODO: Add suport for CONFIGLET mode @@ -47,54 +48,74 @@ UPSTREAM_NEIGHBOR_MAP = { "t0": "t1", "t1": "t2", - "m0": "m1" + "m0": "m1", + "t2": "t3" } # Describe downstream neighbor of dut in different topos DOWNSTREAM_NEIGHBOR_MAP = { "t0": "server", "t1": "t0", - "m0": "mx" + "m0": "mx", + "t2": "t1" } # Topo that downstream neighbor of DUT are servers DOWNSTREAM_SERVER_TOPO = ["t0"] -@pytest.fixture(scope="module") -def setup_info(duthosts, rand_one_dut_hostname, tbinfo): - """ - Gather all required test information. - - Args: - duthost: DUT fixture - tbinfo: tbinfo fixture - - Returns: - dict: Required test information +def gen_setup_information(downStreamDutHost, upStreamDutHost, tbinfo): + """ + Generate setup information dictionary for T0 and T1/ T2 topologies. """ - duthost = duthosts[rand_one_dut_hostname] topo = tbinfo['topo']['name'] upstream_ports_namespace_map = defaultdict(list) downstream_ports_namespace_map = defaultdict(list) upstream_ports_namespace = set() downstream_ports_namespace = set() + upstream_neigh_namespace_map = defaultdict(set) + downstream_neigh_namespace_map = defaultdict(set) + + mg_facts_list = [] # Gather test facts - mg_facts = duthost.get_extended_minigraph_facts(tbinfo) - switch_capability_facts = duthost.switch_capabilities_facts()["ansible_facts"] - acl_capability_facts = duthost.acl_capabilities_facts()["ansible_facts"] + if downStreamDutHost == upStreamDutHost: + mg_facts_list.append(downStreamDutHost.get_extended_minigraph_facts(tbinfo)) + downstream_switch_capability_facts = upstream_switch_capability_facts = downStreamDutHost.switch_capabilities_facts()["ansible_facts"] + downstream_acl_capability_facts = upstream_acl_capability_facts = downStreamDutHost.acl_capabilities_facts()["ansible_facts"] + else: + mg_facts_list.append(downStreamDutHost.get_extended_minigraph_facts(tbinfo)) + mg_facts_list.append(upStreamDutHost.get_extended_minigraph_facts(tbinfo)) + downstream_switch_capability_facts = downStreamDutHost.switch_capabilities_facts()["ansible_facts"] + downstream_acl_capability_facts = downStreamDutHost.acl_capabilities_facts()["ansible_facts"] + upstream_switch_capability_facts = upStreamDutHost.switch_capabilities_facts()["ansible_facts"] + upstream_acl_capability_facts = upStreamDutHost.acl_capabilities_facts()["ansible_facts"] topo_type = tbinfo["topo"]["type"] # Get the list of T0/T2 ports - for dut_port, neigh in mg_facts["minigraph_neighbors"].items(): - pytest_assert(topo_type in UPSTREAM_NEIGHBOR_MAP and topo_type in DOWNSTREAM_NEIGHBOR_MAP, "Unsupported topo") - if UPSTREAM_NEIGHBOR_MAP[topo_type] in neigh["name"].lower(): - upstream_ports_namespace_map[neigh['namespace']].append(dut_port) - upstream_ports_namespace.add(neigh['namespace']) - elif DOWNSTREAM_NEIGHBOR_MAP[topo_type] in neigh["name"].lower(): - downstream_ports_namespace_map[neigh['namespace']].append(dut_port) - downstream_ports_namespace.add(neigh['namespace']) - + for mg_facts in mg_facts_list: + for dut_port, neigh in mg_facts["minigraph_neighbors"].items(): + pytest_assert(topo_type in UPSTREAM_NEIGHBOR_MAP and topo_type in DOWNSTREAM_NEIGHBOR_MAP, "Unsupported topo") + if UPSTREAM_NEIGHBOR_MAP[topo_type] in neigh["name"].lower(): + upstream_ports_namespace_map[neigh['namespace']].append(dut_port) + upstream_ports_namespace.add(neigh['namespace']) + upstream_neigh_namespace_map[neigh['namespace']].add(neigh["name"]) + + elif DOWNSTREAM_NEIGHBOR_MAP[topo_type] in neigh["name"].lower(): + downstream_ports_namespace_map[neigh['namespace']].append(dut_port) + downstream_ports_namespace.add(neigh['namespace']) + downstream_neigh_namespace_map[neigh['namespace']].add(neigh["name"]) + + for ns, neigh_set in upstream_neigh_namespace_map.items(): + if len(neigh_set) < 2: + upstream_ports_namespace.remove(ns) + + for ns, neigh_set in downstream_neigh_namespace_map.items(): + if len(neigh_set) < 2: + downstream_ports_namespace.remove(ns) + + if not upstream_ports_namespace or not downstream_ports_namespace: + pytest.skip("Not enough ports for upstream or downstream neighbors to run this test") + if 't1' in topo: # Set of downstream ports only Namespace downstream_only_namespace = downstream_ports_namespace.difference(upstream_ports_namespace) @@ -102,48 +123,65 @@ def setup_info(duthosts, rand_one_dut_hostname, tbinfo): upstream_only_namespace = upstream_ports_namespace.difference(downstream_ports_namespace) # Randomly choose from downstream_only Namespace if present else just use first one downstream_namespace = random.choice(tuple(downstream_only_namespace)) \ - if downstream_only_namespace else tuple(downstream_ports_namespace)[0] + if downstream_only_namespace else random.choice(tuple(downstream_ports_namespace)) # Randomly choose from upstream_only Namespace if present else just use first one upstream_namespace = random.choice(tuple(upstream_only_namespace)) \ - if upstream_only_namespace else tuple(upstream_ports_namespace)[0] + if upstream_only_namespace else random.choice(tuple(upstream_ports_namespace)) else: # Use the default namespace - downstream_namespace = tuple(downstream_ports_namespace)[0] - upstream_namespace = tuple(upstream_ports_namespace)[0] + downstream_namespace = random.choice(tuple(downstream_ports_namespace)) + upstream_namespace = random.choice(tuple(upstream_ports_namespace)) downstream_ports = downstream_ports_namespace_map[downstream_namespace] upstream_ports = upstream_ports_namespace_map[upstream_namespace] - switch_capabilities = switch_capability_facts["switch_capabilities"]["switch"] - acl_capabilities = acl_capability_facts["acl_capabilities"] + random.shuffle(downstream_ports) + random.shuffle(upstream_ports) + + + upstream_switch_capabilities = upstream_switch_capability_facts["switch_capabilities"]["switch"] + upstream_acl_capabilities = upstream_acl_capability_facts["acl_capabilities"] + + downstream_switch_capabilities = downstream_switch_capability_facts["switch_capabilities"]["switch"] + downstream_acl_capabilities = downstream_acl_capability_facts["acl_capabilities"] + - test_mirror_v4 = switch_capabilities["MIRROR"] == "true" - test_mirror_v6 = switch_capabilities["MIRRORV6"] == "true" + test_mirror_v4 = upstream_switch_capabilities["MIRROR"] == "true" and downstream_switch_capabilities["MIRROR"] == "true" + test_mirror_v6 = upstream_switch_capabilities["MIRRORV6"] == "true" and downstream_switch_capabilities["MIRRORV6"] == "true" # NOTE: Older OS versions don't have the ACL_ACTIONS table, and those same devices # do not support egress ACLs or egress mirroring. Once we branch out the sonic-mgmt # repo we can remove this case. - if "201811" in duthost.os_version: + if "201811" in downStreamDutHost.os_version or "201811" in upStreamDutHost.os_version: test_ingress_mirror_on_ingress_acl = True test_ingress_mirror_on_egress_acl = False test_egress_mirror_on_egress_acl = False test_egress_mirror_on_ingress_acl = False - elif acl_capabilities: - test_ingress_mirror_on_ingress_acl = "MIRROR_INGRESS_ACTION" in acl_capabilities["INGRESS"]["action_list"] - test_ingress_mirror_on_egress_acl = "MIRROR_INGRESS_ACTION" in acl_capabilities["EGRESS"]["action_list"] - test_egress_mirror_on_egress_acl = "MIRROR_EGRESS_ACTION" in acl_capabilities["EGRESS"]["action_list"] - test_egress_mirror_on_ingress_acl = "MIRROR_EGRESS_ACTION" in acl_capabilities["INGRESS"]["action_list"] + elif upstream_acl_capabilities and downstream_acl_capabilities: + test_ingress_mirror_on_ingress_acl = "MIRROR_INGRESS_ACTION" in upstream_acl_capabilities["INGRESS"]["action_list"] and \ + "MIRROR_INGRESS_ACTION" in downstream_acl_capabilities["INGRESS"]["action_list"] + test_ingress_mirror_on_egress_acl = "MIRROR_INGRESS_ACTION" in upstream_acl_capabilities["EGRESS"]["action_list"] and \ + "MIRROR_INGRESS_ACTION" in downstream_acl_capabilities["EGRESS"]["action_list"] + test_egress_mirror_on_egress_acl = "MIRROR_EGRESS_ACTION" in upstream_acl_capabilities["EGRESS"]["action_list"] and \ + "MIRROR_EGRESS_ACTION" in downstream_acl_capabilities["EGRESS"]["action_list"] + test_egress_mirror_on_ingress_acl = "MIRROR_EGRESS_ACTION" in upstream_acl_capabilities["INGRESS"]["action_list"] and \ + "MIRROR_EGRESS_ACTION" in downstream_acl_capabilities["INGRESS"]["action_list"] else: logging.info("Fallback to the old source of ACL capabilities (assuming SONiC release is < 202111)") - test_ingress_mirror_on_ingress_acl = "MIRROR_INGRESS_ACTION" in switch_capabilities["ACL_ACTIONS|INGRESS"] - test_ingress_mirror_on_egress_acl = "MIRROR_INGRESS_ACTION" in switch_capabilities["ACL_ACTIONS|EGRESS"] - test_egress_mirror_on_egress_acl = "MIRROR_EGRESS_ACTION" in switch_capabilities["ACL_ACTIONS|EGRESS"] - test_egress_mirror_on_ingress_acl = "MIRROR_EGRESS_ACTION" in switch_capabilities["ACL_ACTIONS|INGRESS"] - + test_ingress_mirror_on_ingress_acl = "MIRROR_INGRESS_ACTION" in upstream_switch_capabilities["ACL_ACTIONS|INGRESS"] and \ + "MIRROR_INGRESS_ACTION" in downstream_switch_capabilities["ACL_ACTIONS|INGRESS"] + test_ingress_mirror_on_egress_acl = "MIRROR_INGRESS_ACTION" in upstream_switch_capabilities["ACL_ACTIONS|EGRESS"] and \ + "MIRROR_INGRESS_ACTION" in downstream_switch_capabilities["ACL_ACTIONS|EGRESS"] + test_egress_mirror_on_egress_acl = "MIRROR_EGRESS_ACTION" in upstream_switch_capabilities["ACL_ACTIONS|EGRESS"] and \ + "MIRROR_EGRESS_ACTION" in downstream_switch_capabilities["ACL_ACTIONS|EGRESS"] + test_egress_mirror_on_ingress_acl = "MIRROR_EGRESS_ACTION" in upstream_switch_capabilities["ACL_ACTIONS|INGRESS"] and \ + "MIRROR_EGRESS_ACTION" in downstream_switch_capabilities["ACL_ACTIONS|INGRESS"] +# # NOTE: Disable egress mirror test on broadcom platform even SAI claim EGRESS MIRRORING is supported # There is a known issue in SAI 7.1 for XGS that SAI claims the capability of EGRESS MIRRORING incorrectly. # Hence we override the capability query with below logic. Please remove it after the issue is fixed. - if duthost.facts["asic_type"] == "broadcom" and duthost.facts.get("platform_asic") != 'broadcom-dnx': + if (downStreamDutHost.facts["asic_type"] == "broadcom" or upStreamDutHost.facts["asic_type"] == "broadcom") and \ + (downStreamDutHost.facts.get("platform_asic") != 'broadcom-dnx' and upStreamDutHost.facts.get("platform_asic") != 'broadcom-dnx'): test_egress_mirror_on_egress_acl = False test_egress_mirror_on_ingress_acl = False @@ -151,7 +189,7 @@ def setup_info(duthosts, rand_one_dut_hostname, tbinfo): # if applicable. # # TODO: Add a namedtuple to make the groupings more explicit - def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_lag_name): + def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_lag_name, mg_facts): out_port_exclude_list = [] for port in in_port_list: if port not in out_port_list and port not in out_port_exclude_list and len(out_port_list) < 4: @@ -172,10 +210,16 @@ def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_la out_port_ptf_id_list.append(ptf_port_id) + + asic_id = upStreamDutHost.get_asic_id_from_namespace(upstream_namespace) + upstream_router_mac = upStreamDutHost.asic_instance(asic_id).get_router_mac() + asic_id = downStreamDutHost.get_asic_id_from_namespace(downstream_namespace) + downstream_router_mac = downStreamDutHost.asic_instance(asic_id).get_router_mac() + + setup_information = { - "router_mac": duthost.facts["router_mac"], - "test_mirror_v4": test_mirror_v4, - "test_mirror_v6": test_mirror_v6, + "test_mirror_v4": test_mirror_v4, + "test_mirror_v6": test_mirror_v6, "ingress": { "ingress": test_ingress_mirror_on_ingress_acl, "egress": test_egress_mirror_on_ingress_acl @@ -184,38 +228,32 @@ def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_la "ingress": test_ingress_mirror_on_egress_acl, "egress": test_egress_mirror_on_egress_acl }, - "port_index_map": { - k: v - for k, v in mg_facts["minigraph_ptf_indices"].items() - if k in mg_facts["minigraph_ports"] - }, - # { ptf_port_id : namespace } - "port_index_namespace_map": { - v: mg_facts["minigraph_neighbors"][k]['namespace'] - for k, v in mg_facts["minigraph_ptf_indices"].items() - if k in mg_facts["minigraph_ports"] - } } - # Downstream traffic downstream_dest_ports = [] downstream_dest_ports_ptf_id = [] downstream_dest_lag_name = None if topo_type in DOWNSTREAM_SERVER_TOPO else [] - get_port_info(downstream_ports, downstream_dest_ports, downstream_dest_ports_ptf_id, downstream_dest_lag_name) + get_port_info(downstream_ports, downstream_dest_ports, downstream_dest_ports_ptf_id, downstream_dest_lag_name, mg_facts_list[0]) # Upstream traffic upstream_dest_ports = [] upstream_dest_ports_ptf_id = [] upstream_dest_lag_name = [] - get_port_info(upstream_ports, upstream_dest_ports, upstream_dest_ports_ptf_id, upstream_dest_lag_name) + get_port_info(upstream_ports, upstream_dest_ports, upstream_dest_ports_ptf_id, upstream_dest_lag_name, mg_facts_list[1] if len(mg_facts_list) == 2 else mg_facts_list[0]) setup_information.update( { "topo": topo_type, DOWN_STREAM: { + "remote_dut": downStreamDutHost, + "everflow_dut": upStreamDutHost, + "ingress_router_mac": upstream_router_mac, + "egress_router_mac": downstream_router_mac, "src_port": upstream_ports[0], "src_port_lag_name": upstream_dest_lag_name[0], - "src_port_ptf_id": str(mg_facts["minigraph_ptf_indices"][upstream_ports[0]]), + "src_port_ptf_id": str(mg_facts_list[1]["minigraph_ptf_indices"][upstream_ports[0]]) \ + if len(mg_facts_list) == 2 else \ + str(mg_facts_list[0]["minigraph_ptf_indices"][upstream_ports[0]]), # For T0 topo, downstream traffic ingress from the first portchannel, # and mirror packet egress from other portchannels "dest_port": upstream_dest_ports[1:] \ @@ -224,18 +262,24 @@ def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_la if topo_type in DOWNSTREAM_SERVER_TOPO else downstream_dest_ports_ptf_id, "dest_port_lag_name": upstream_dest_lag_name[1:] \ if topo_type in DOWNSTREAM_SERVER_TOPO else downstream_dest_lag_name, - "namespace": downstream_namespace + "remote_namespace": upstream_namespace if topo_type in DOWNSTREAM_SERVER_TOPO else downstream_namespace, + "everflow_namespace": upstream_namespace }, UP_STREAM: { + "remote_dut": upStreamDutHost, + "everflow_dut": downStreamDutHost, + "ingress_router_mac": downstream_router_mac, + "egress_router_mac": upstream_router_mac, "src_port": downstream_ports[0], # DUT whose downstream are servers doesn't have lag connect to server "src_port_lag_name": "Not Applicable" \ if topo_type in DOWNSTREAM_SERVER_TOPO else downstream_dest_lag_name[0], - "src_port_ptf_id": str(mg_facts["minigraph_ptf_indices"][downstream_ports[0]]), + "src_port_ptf_id": str(mg_facts_list[0]["minigraph_ptf_indices"][downstream_ports[0]]), "dest_port": upstream_dest_ports, "dest_port_ptf_id": upstream_dest_ports_ptf_id, "dest_port_lag_name": upstream_dest_lag_name, - "namespace": upstream_namespace + "remote_namespace": upstream_namespace, + "everflow_namespace": downstream_namespace }, } ) @@ -247,18 +291,62 @@ def get_port_info(in_port_list, out_port_list, out_port_ptf_id_list, out_port_la } ) + return setup_information + +def get_t2_duthost(duthosts, tbinfo): + """ + Generate setup information dictionary for T2 topologies. + """ + t3_duthost = find_duthost_on_role(duthosts, "T3", tbinfo) + t1_duthost = find_duthost_on_role(duthosts, "T1", tbinfo) + return t1_duthost, t3_duthost + + +@pytest.fixture(scope="module") +def setup_info(duthosts, rand_one_dut_hostname, tbinfo, request): + """ + Gather all required test information. + + Args: + duthost: DUT fixture + tbinfo: tbinfo fixture + + Returns: + dict: Required test information + + """ + topo = tbinfo['topo']['name'] + if 't1' in topo or 't0' in topo: + downstream_duthost = upstream_duthost = duthost = duthosts[rand_one_dut_hostname] + elif 't2' in topo: + downstream_duthost, upstream_duthost = get_t2_duthost(duthosts, tbinfo) + + setup_information = gen_setup_information(downstream_duthost, upstream_duthost, tbinfo) + # Disable BGP so that we don't keep on bouncing back mirror packets # If we send TTL=1 packet we don't need this but in multi-asic TTL > 1 - duthost.command("sudo config bgp shutdown all") + + if 't2' in topo: + for duthost in duthosts.frontend_nodes: + duthost.command("sudo config bgp shutdown all") + duthost.command("mkdir -p {}".format(DUT_RUN_DIR)) + else: + duthost.command("sudo config bgp shutdown all") + duthost.command("mkdir -p {}".format(DUT_RUN_DIR)) + time.sleep(60) - duthost.command("mkdir -p {}".format(DUT_RUN_DIR)) yield setup_information # Enable BGP again - duthost.command("sudo config bgp startup all") + if 't2' in topo: + for duthost in duthosts.frontend_nodes: + duthost.command("sudo config bgp startup all") + duthost.command("rm -rf {}".format(DUT_RUN_DIR)) + else: + duthost.command("sudo config bgp startup all") + duthost.command("rm -rf {}".format(DUT_RUN_DIR)) time.sleep(60) - duthost.command("rm -rf {}".format(DUT_RUN_DIR)) # TODO: This should be refactored to some common area of sonic-mgmt. @@ -273,7 +361,7 @@ def add_route(duthost, prefix, nexthop, namespace): namespace: namsespace/asic to add the route """ - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"ip route {} {}\"".format(prefix, nexthop), namespace)) + duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"ip route {} {} tag 1\"".format(prefix, nexthop), namespace)) # TODO: This should be refactored to some common area of sonic-mgmt. @@ -288,7 +376,7 @@ def remove_route(duthost, prefix, nexthop, namespace): namespace: namsespace/asic to remove the route """ - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"no ip route {} {}\"".format(prefix, nexthop), namespace)) + duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"no ip route {} {} tag 1\"".format(prefix, nexthop), namespace)) @pytest.fixture(scope='module', autouse=True) def setup_arp_responder(duthost, ptfhost, setup_info): @@ -395,8 +483,15 @@ def config_method(self, request): """ return request.param + @staticmethod + def get_duthost_set(setup_info): + duthost_set = set() + duthost_set.add(setup_info[DOWN_STREAM]['everflow_dut']) + duthost_set.add(setup_info[UP_STREAM]['everflow_dut']) + return duthost_set + @pytest.fixture(scope="class") - def setup_mirror_session(self, duthosts, rand_one_dut_hostname, config_method): + def setup_mirror_session(self, config_method, setup_info): """ Set up a mirror session for Everflow. @@ -406,17 +501,22 @@ def setup_mirror_session(self, duthosts, rand_one_dut_hostname, config_method): Yields: dict: Information about the mirror session configuration. """ - duthost = duthosts[rand_one_dut_hostname] - session_info = BaseEverflowTest.mirror_session_info("test_session_1", duthost.facts["asic_type"]) + duthost_set = BaseEverflowTest.get_duthost_set(setup_info) - BaseEverflowTest.apply_mirror_config(duthost, session_info, config_method) + session_info = None + + for duthost in duthost_set: + if not session_info: + session_info = BaseEverflowTest.mirror_session_info("test_session_1", duthost.facts["asic_type"]) + BaseEverflowTest.apply_mirror_config(duthost, session_info, config_method) yield session_info - BaseEverflowTest.remove_mirror_config(duthost, session_info["session_name"], config_method) + for duthost in duthost_set: + BaseEverflowTest.remove_mirror_config(duthost, session_info["session_name"], config_method) @pytest.fixture(scope="class") - def policer_mirror_session(self, duthosts, rand_one_dut_hostname, config_method): + def policer_mirror_session(self, config_method, setup_info): """ Set up a mirror session with a policer for Everflow. @@ -426,21 +526,27 @@ def policer_mirror_session(self, duthosts, rand_one_dut_hostname, config_method) Yields: dict: Information about the mirror session configuration. """ - duthost = duthosts[rand_one_dut_hostname] - policer = "TEST_POLICER" + duthost_set = BaseEverflowTest.get_duthost_set(setup_info) - # Create a policer that allows 100 packets/sec through - self.apply_policer_config(duthost, policer, config_method) + + policer = "TEST_POLICER" # Create a mirror session with the TEST_POLICER attached - session_info = BaseEverflowTest.mirror_session_info("TEST_POLICER_SESSION", duthost.facts["asic_type"]) - BaseEverflowTest.apply_mirror_config(duthost, session_info, config_method, policer=policer) + session_info = {} + + for duthost in duthost_set: + if not session_info: + session_info = BaseEverflowTest.mirror_session_info("TEST_POLICER_SESSION", duthost.facts["asic_type"]) + # Create a policer that allows 100 packets/sec through + self.apply_policer_config(duthost, policer, config_method) + BaseEverflowTest.apply_mirror_config(duthost, session_info, config_method, policer=policer) yield session_info # Clean up mirror session and policer - BaseEverflowTest.remove_mirror_config(duthost, session_info["session_name"], config_method) - self.remove_policer_config(duthost, policer, config_method) + for duthost in duthost_set: + BaseEverflowTest.remove_mirror_config(duthost, session_info["session_name"], config_method) + self.remove_policer_config(duthost, policer, config_method) @staticmethod def apply_mirror_config(duthost, session_info, config_method=CONFIG_MODE_CLI, policer=None): @@ -492,7 +598,7 @@ def remove_policer_config(self, duthost, policer_name, config_method): duthost.command(command) @pytest.fixture(scope="class", autouse=True) - def setup_acl_table(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, config_method): + def setup_acl_table(self, setup_info, setup_mirror_session, config_method): """ Configure the ACL table for this set of test cases. @@ -501,7 +607,8 @@ def setup_acl_table(self, duthosts, rand_one_dut_hostname, setup_info, setup_mir setup_info: Fixture with info about the testbed setup setup_mirror_session: Fixtue with info about the mirror session """ - duthost = duthosts[rand_one_dut_hostname] + + duthost_set = BaseEverflowTest.get_duthost_set(setup_info) if not setup_info[self.acl_stage()][self.mirror_type()]: pytest.skip("{} ACL w/ {} Mirroring not supported, skipping" .format(self.acl_stage(), self.mirror_type())) @@ -509,17 +616,22 @@ def setup_acl_table(self, duthosts, rand_one_dut_hostname, setup_info, setup_mir table_name = "EVERFLOW" if self.acl_stage() == "ingress" else "EVERFLOW_EGRESS" # NOTE: We currently assume that the ingress MIRROR tables already exist. - if self.acl_stage() == "egress": - self.apply_acl_table_config(duthost, table_name, "MIRROR", config_method) + for duthost in duthost_set: + if self.acl_stage() == "egress": + inst_list = duthost.get_sonic_host_and_frontend_asic_instance() + for inst in inst_list: + self.apply_acl_table_config(duthost, table_name, "MIRROR", config_method, bind_namespace=getattr(inst, 'namespace', None)) - self.apply_acl_rule_config(duthost, table_name, setup_mirror_session["session_name"], config_method) + self.apply_acl_rule_config(duthost, table_name, setup_mirror_session["session_name"], config_method) yield - BaseEverflowTest.remove_acl_rule_config(duthost, table_name, config_method) - - if self.acl_stage() == "egress": - self.remove_acl_table_config(duthost, "EVERFLOW_EGRESS", config_method) + for duthost in duthost_set: + BaseEverflowTest.remove_acl_rule_config(duthost, table_name, config_method) + if self.acl_stage() == "egress": + inst_list = duthost.get_sonic_host_and_frontend_asic_instance() + for inst in inst_list: + self.remove_acl_table_config(duthost, "EVERFLOW_EGRESS", config_method, bind_namespace=getattr(inst, 'namespace', None)) def apply_acl_table_config(self, duthost, table_name, table_type, config_method, bind_ports_list=None, bind_namespace=None): if config_method == CONFIG_MODE_CLI: @@ -613,53 +725,63 @@ def send_and_check_mirror_packets(self, ptfadapter, duthost, mirror_packet, + direction, src_port=None, dest_ports=None, expect_recv=True, valid_across_namespace=True): - if not src_port: - src_port = self._get_random_src_port(setup) - - if not dest_ports: - dest_ports = [self._get_monitor_port(setup, mirror_session, duthost)] # In Below logic idea is to send traffic in such a way so that mirror traffic # will need to go across namespaces and within namespace. If source and mirror destination # namespace are different then traffic mirror will go across namespace via (backend asic) # else via same namespace(asic) - src_port_namespace = self._get_port_namespace(setup, int(src_port)) - dest_ports_namespace = self._get_port_namespace(setup,int (dest_ports[0])) - src_port_set = set() + src_port_set = set() + src_port_metadata_map = {} - # Some of test scenario are not valid across namespaces so test will explicltly pass - # valid_across_namespace as False (default is True) - if valid_across_namespace == True or src_port_namespace == dest_ports_namespace: - src_port_set.add(src_port) + + if 't2' in setup['topo']: + if valid_across_namespace is True: + src_port_set.add(src_port) + src_port_metadata_map[src_port] = (None, 1) - # To verify same namespace mirroring we will add destination port also to the Source Port Set - if src_port_namespace != dest_ports_namespace: src_port_set.add(dest_ports[0]) + src_port_metadata_map[dest_ports[0]] = (setup[direction]["egress_router_mac"], 0) - expected_mirror_packet_with_ttl = BaseEverflowTest.get_expected_mirror_packet(mirror_session, - setup, - duthost, - mirror_packet, - True) - expected_mirror_packet_without_ttl = BaseEverflowTest.get_expected_mirror_packet(mirror_session, + else: + src_port_namespace = setup[direction]["everflow_namespace"] + dest_ports_namespace = setup[direction]["remote_namespace"] + + if valid_across_namespace is True or src_port_namespace == dest_ports_namespace: + src_port_set.add(src_port) + src_port_metadata_map[src_port] = (None, 0) + + # To verify same namespace mirroring we will add destination port also to the Source Port Set + if src_port_namespace != dest_ports_namespace: + src_port_set.add(dest_ports[0]) + src_port_metadata_map[dest_ports[0]] = (None, 2) + + + # Loop through Source Port Set and send traffic on each source port of the set + for src_port in src_port_set: + expected_mirror_packet = BaseEverflowTest.get_expected_mirror_packet(mirror_session, setup, duthost, + direction, mirror_packet, - False) + src_port_metadata_map[src_port][1]) + if src_port_metadata_map[src_port][0]: + + mirror_packet_sent = mirror_packet.copy() + + mirror_packet_sent[packet.Ether].dst = src_port_metadata_map[src_port][0] + else: + mirror_packet_sent = mirror_packet - # Loop through Source Port Set and send traffic on each source port of the set - for src_port in src_port_set: - expected_mirror_packet = expected_mirror_packet_with_ttl \ - if self._get_port_namespace(setup, int(src_port)) == dest_ports_namespace else expected_mirror_packet_without_ttl ptfadapter.dataplane.flush() - testutils.send(ptfadapter, src_port, mirror_packet) + testutils.send(ptfadapter, src_port, mirror_packet_sent) if expect_recv: time.sleep(STABILITY_BUFFER) @@ -670,7 +792,7 @@ def send_and_check_mirror_packets(self, ) logging.info("Received packet: %s", packet.Ether(received_packet).summary()) - inner_packet = self._extract_mirror_payload(received_packet, len(mirror_packet)) + inner_packet = self._extract_mirror_payload(received_packet, len(mirror_packet_sent)) logging.info("Received inner packet: %s", inner_packet.summary()) inner_packet = Mask(inner_packet) @@ -685,19 +807,19 @@ def send_and_check_mirror_packets(self, # but DMAC and checksum are trickier. For now, update the TTL and SMAC, and # mask off the DMAC and IP Checksum to verify the packet contents. if self.mirror_type() == "egress": - mirror_packet[packet.IP].ttl -= 1 - mirror_packet[packet.Ether].src = setup["router_mac"] + mirror_packet_sent[packet.IP].ttl -= 1 + mirror_packet_sent[packet.Ether].src = setup[direction]["egress_router_mac"] inner_packet.set_do_not_care_scapy(packet.Ether, "dst") inner_packet.set_do_not_care_scapy(packet.IP, "chksum") - logging.info("Expected inner packet: %s", mirror_packet.summary()) - pytest_assert(inner_packet.pkt_match(mirror_packet), "Mirror payload does not match received packet") + logging.info("Expected inner packet: %s", mirror_packet_sent.summary()) + pytest_assert(inner_packet.pkt_match(mirror_packet_sent), "Mirror payload does not match received packet") else: testutils.verify_no_packet_any(ptfadapter, expected_mirror_packet, dest_ports) @staticmethod - def get_expected_mirror_packet(mirror_session, setup, duthost, mirror_packet, check_ttl): + def get_expected_mirror_packet(mirror_session, setup, duthost, direction, mirror_packet, ttl_dec): payload = mirror_packet.copy() # Add vendor specific padding to the packet @@ -708,12 +830,12 @@ def get_expected_mirror_packet(mirror_session, setup, duthost, mirror_packet, ch payload = binascii.unhexlify("0" * 24) + str(payload) expected_packet = testutils.simple_gre_packet( - eth_src=setup["router_mac"], + eth_src=setup[direction]["egress_router_mac"], ip_src=mirror_session["session_src_ip"], ip_dst=mirror_session["session_dst_ip"], ip_dscp=int(mirror_session["session_dscp"]), ip_id=0, - ip_ttl=int(mirror_session["session_ttl"]), + ip_ttl=int(mirror_session["session_ttl"]) - ttl_dec, inner_frame=payload ) @@ -727,8 +849,6 @@ def get_expected_mirror_packet(mirror_session, setup, duthost, mirror_packet, ch expected_packet.set_do_not_care_scapy(packet.IP, "chksum") if duthost.facts["asic_type"] in ["cisco-8000","innovium"]: expected_packet.set_do_not_care_scapy(packet.GRE, "seqnum_present") - if not check_ttl: - expected_packet.set_do_not_care_scapy(packet.IP, "ttl") # The fanout switch may modify this value en route to the PTF so we should ignore it, even # though the session does have a DSCP specified. @@ -775,87 +895,8 @@ def mirror_session_info(session_name, asic_type): "session_prefixes": session_prefixes } - def _get_port_namespace(self,setup, port): - return setup["port_index_namespace_map"][port] - - def _get_random_src_port(self, setup): - return setup["port_index_map"][random.choice(setup["port_index_map"].keys())] - - def _get_monitor_port(self, setup, mirror_session, duthost): - mirror_output = duthost.command("show mirror_session") - logging.info("Running mirror session configuration:\n%s", mirror_output["stdout"]) - - pytest_assert(mirror_session["session_name"] in mirror_output["stdout"], - "Test mirror session {} not found".format(mirror_session["session_name"])) - - lines = mirror_output["stdout_lines"] - - if "201911" in duthost.os_version: - # Because this line is not in the output in 201911, we need to add it so that the - # parser is consistent between 201911 and future versions. - lines = ["ERSPAN Sessions"] + lines - - sessions = self._parse_mirror_session_running_config(lines) - - session = [x for x in sessions["ERSPAN Sessions"]["data"] if x["Name"] == mirror_session["session_name"]] - pytest_assert(0 < len(session)) - - monitor_port = session[0]["Monitor Port"] - - pytest_assert(monitor_port in setup["port_index_map"], - "Invalid monitor port:\n{}".format(mirror_output["stdout"])) - logging.info("Selected monitor interface %s (port=%s)", monitor_port, setup["port_index_map"][monitor_port]) - - return setup["port_index_map"][monitor_port] - - def _parse_mirror_session_running_config(self, lines): - sessions = {} - while True: - session_group, lines = self._parse_mirror_session_group(lines) - if session_group is None: - break - sessions[session_group["name"]] = session_group - - return sessions - - def _parse_mirror_session_group(self, lines): - while len(lines) and lines[0].strip() == "": - lines.pop(0) - - if len(lines) < 3: - return None, lines - - table_name = lines[0] - separator_line = lines[2] - header = lines[1] - - session_group = { - "name": table_name, - "data": [] - } - - separators = separator_line.split() - - lines = lines[3:] - for ln in lines[:]: - lines.pop(0) - if ln.strip() == "": - break - - index = 0 - data = {} - for s in separators: - end = index + len(s) - name = header[index:end].strip() - value = ln[index:end].strip() - index = index + len(s) + 2 - data[name] = value - - session_group["data"].append(data) - - return session_group, lines - - def _get_tx_port_id_list(self, tx_ports): + @staticmethod + def _get_tx_port_id_list(tx_ports): tx_port_ids = [] for port in tx_ports: members = port.split(',') diff --git a/tests/everflow/test_everflow_ipv6.py b/tests/everflow/test_everflow_ipv6.py index 5228e269c77..c9743539689 100644 --- a/tests/everflow/test_everflow_ipv6.py +++ b/tests/everflow/test_everflow_ipv6.py @@ -9,7 +9,7 @@ from everflow_test_utilities import setup_info # noqa: F401, E501 lgtm[py/unused-import] pylint: disable=import-error pytestmark = [ - pytest.mark.topology("t0", "t1", "m0") + pytest.mark.topology("t0", "t1", "t2", "m0") ] EVERFLOW_V6_RULES = "ipv6_test_rules.yaml" @@ -28,39 +28,64 @@ class EverflowIPv6Tests(BaseEverflowTest): DEFAULT_SRC_IP = "2002:0225:7c6b:a982:d48b:230e:f271:0000" DEFAULT_DST_IP = "2002:0225:7c6b:a982:d48b:230e:f271:0001" + rx_port_ptf_id = None tx_port_ids = [] @pytest.fixture(scope='class', autouse=True) - def setup_mirror_session_dest_ip_route(self, duthosts, rand_one_dut_hostname, tbinfo, setup_info, setup_mirror_session): + def setup_mirror_session_dest_ip_route(self, tbinfo, setup_info, setup_mirror_session): """ Setup the route for mirror session destination ip and update monitor port list. Remove the route as part of cleanup. """ - duthost = duthosts[rand_one_dut_hostname] if setup_info['topo'] == 't0': # On T0 testbed, the collector IP is routed to T1 - namespace = setup_info[UP_STREAM]['namespace'] + namespace = setup_info[UP_STREAM]['remote_namespace'] tx_port = setup_info[UP_STREAM]["dest_port"][0] dest_port_ptf_id_list = [setup_info[UP_STREAM]["dest_port_ptf_id"][0]] + remote_dut = setup_info[UP_STREAM]['remote_dut'] + rx_port_id = setup_info[UP_STREAM]["src_port_ptf_id"] else: - namespace = setup_info[DOWN_STREAM]['namespace'] + namespace = setup_info[DOWN_STREAM]['remote_namespace'] tx_port = setup_info[DOWN_STREAM]["dest_port"][0] dest_port_ptf_id_list = [setup_info[DOWN_STREAM]["dest_port_ptf_id"][0]] - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"redistribute static\"", namespace)) - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, namespace) - EverflowIPv6Tests.tx_port_ids = self._get_tx_port_id_list(dest_port_ptf_id_list) + remote_dut = setup_info[DOWN_STREAM]['remote_dut'] + rx_port_id = setup_info[DOWN_STREAM]["src_port_ptf_id"] + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"redistribute static\"", namespace)) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, namespace) + EverflowIPv6Tests.tx_port_ids = BaseEverflowTest._get_tx_port_id_list(dest_port_ptf_id_list) + EverflowIPv6Tests.rx_port_ptf_id = rx_port_id time.sleep(5) yield - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, namespace) - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"no redistribute static\"", namespace)) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, namespace) + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"no redistribute static\"", namespace)) + + @pytest.fixture(scope='class') + def everflow_dut(self, setup_info): + if setup_info['topo'] == 't0': + dut = setup_info[UP_STREAM]['everflow_dut'] + else: + dut = setup_info[DOWN_STREAM]['everflow_dut'] + + yield dut + + @pytest.fixture(scope='class') + def everflow_direction(self, setup_info): + if setup_info['topo'] == 't0': + direction = UP_STREAM + else: + direction = DOWN_STREAM + + yield direction + - def test_src_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + + + def test_src_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on Source IPv6 addresses.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0002" @@ -69,14 +94,13 @@ def test_src_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_dst_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_dst_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on Destination IPv6 addresses.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, dst_ip="2002:0225:7c6b:a982:d48b:230e:f271:0003" @@ -85,98 +109,90 @@ def test_dst_ipv6_mirroring(self, setup_info, setup_mirror_session, ptfadapter, self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_next_header_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_next_header_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on the Next Header field.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, next_header=0x7E) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, next_header=0x7E) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_l4_src_port_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_l4_src_port_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on the L4 Source Port.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, sport=9000) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, sport=9000) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_l4_dst_port_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_l4_dst_port_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on the L4 Destination Port.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, dport=9001) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, dport=9001) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_l4_src_port_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_l4_src_port_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on a range of L4 Source Ports.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, sport=10200) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, sport=10200) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_l4_dst_port_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_l4_dst_port_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on a range of L4 Destination Ports.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, dport=10700) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, dport=10700) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_tcp_flags_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_tcp_flags_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on TCP Flags.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, flags=0x1B) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, flags=0x1B) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_dscp_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_dscp_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match on DSCP.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet(ptfadapter, setup_info, dscp=37) + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, dscp=37) self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_l4_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_l4_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match from a source port to a range of destination ports and vice-versa.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0004", @@ -188,11 +204,11 @@ def test_l4_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0005", @@ -204,14 +220,13 @@ def test_l4_range_mirroring(self, setup_info, setup_mirror_session, ptfadapter, self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_tcp_response_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_tcp_response_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match a SYN -> SYN-ACK pattern.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0006", @@ -222,11 +237,11 @@ def test_tcp_response_mirroring(self, setup_info, setup_mirror_session, ptfadapt self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0007", @@ -237,14 +252,13 @@ def test_tcp_response_mirroring(self, setup_info, setup_mirror_session, ptfadapt self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_tcp_application_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_tcp_application_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match a TCP handshake between a client and server.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0008", @@ -257,11 +271,11 @@ def test_tcp_application_mirroring(self, setup_info, setup_mirror_session, ptfad self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0009", @@ -274,14 +288,13 @@ def test_tcp_application_mirroring(self, setup_info, setup_mirror_session, ptfad self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_udp_application_mirroring(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_udp_application_mirroring(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match UDP traffic between a client and server application.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_udpv6_packet( + test_packet = self._base_udpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:000a", @@ -294,10 +307,10 @@ def test_udp_application_mirroring(self, setup_info, setup_mirror_session, ptfad self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_udpv6_packet( + test_packet = self._base_udpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:000b", @@ -310,14 +323,13 @@ def test_udp_application_mirroring(self, setup_info, setup_mirror_session, ptfad self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_any_protocol(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_any_protocol(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that the protocol number is ignored if it is not specified in the ACL rule.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:000c", @@ -327,11 +339,11 @@ def test_any_protocol(self, setup_info, setup_mirror_session, ptfadapter, duthos self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_udpv6_packet( + test_packet = self._base_udpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:000c", @@ -341,11 +353,11 @@ def test_any_protocol(self, setup_info, setup_mirror_session, ptfadapter, duthos self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_udpv6_packet( + test_packet = self._base_udpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:000c", @@ -356,14 +368,13 @@ def test_any_protocol(self, setup_info, setup_mirror_session, ptfadapter, duthos self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_any_transport_protocol(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_any_transport_protocol(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that src port and dst port rules match regardless of whether TCP or UDP traffic is sent.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:001c", @@ -375,11 +386,11 @@ def test_any_transport_protocol(self, setup_info, setup_mirror_session, ptfadapt self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - test_packet = self._base_udpv6_packet( + test_packet = self._base_udpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:001c", @@ -391,11 +402,11 @@ def test_any_transport_protocol(self, setup_info, setup_mirror_session, ptfadapt self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_invalid_tcp_rule(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_invalid_tcp_rule(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that the ASIC does not reject rules with TCP flags if the protocol is not TCP.""" pass @@ -404,10 +415,9 @@ def test_invalid_tcp_rule(self, setup_info, setup_mirror_session, ptfadapter, du # will not crash if such a rule is installed. If this does happen, we expect the whole test # suite + loganaylzer + the sanity check to fail. - def test_source_subnet(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_source_subnet(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match packets with a Source IPv6 Subnet.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:b000:0000:0000:0000:0010", @@ -419,14 +429,13 @@ def test_source_subnet(self, setup_info, setup_mirror_session, ptfadapter, dutho self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_dest_subnet(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_dest_subnet(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match packets with a Destination IPv6 Subnet.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:a982:d48b:230e:f271:0010", @@ -438,14 +447,13 @@ def test_dest_subnet(self, setup_info, setup_mirror_session, ptfadapter, duthost self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_both_subnets(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_both_subnets(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match packets with both source and destination subnets.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:c000:0000:0000:0000:0010", @@ -457,14 +465,13 @@ def test_both_subnets(self, setup_info, setup_mirror_session, ptfadapter, duthos self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) - def test_fuzzy_subnets(self, setup_info, setup_mirror_session, ptfadapter, duthosts, rand_one_dut_hostname): + def test_fuzzy_subnets(self, setup_info, setup_mirror_session, ptfadapter, everflow_dut, everflow_direction): """Verify that we can match packets with non-standard subnet sizes.""" - duthost = duthosts[rand_one_dut_hostname] - test_packet = self._base_tcpv6_packet( + test_packet = self._base_tcpv6_packet(everflow_direction, ptfadapter, setup_info, src_ip="2002:0225:7c6b:e000:0000:0000:0000:0010", @@ -476,11 +483,12 @@ def test_fuzzy_subnets(self, setup_info, setup_mirror_session, ptfadapter, dutho self.send_and_check_mirror_packets(setup_info, setup_mirror_session, ptfadapter, - duthost, - test_packet, + everflow_dut, + test_packet, everflow_direction, src_port=EverflowIPv6Tests.rx_port_ptf_id, dest_ports=EverflowIPv6Tests.tx_port_ids) def _base_tcpv6_packet(self, + direction, ptfadapter, setup, src_ip=DEFAULT_SRC_IP, @@ -492,7 +500,7 @@ def _base_tcpv6_packet(self, flags=0x10): pkt = testutils.simple_tcpv6_packet( eth_src=ptfadapter.dataplane.get_mac(0, 0), - eth_dst=setup["router_mac"], + eth_dst=setup[direction]["ingress_router_mac"], ipv6_src=src_ip, ipv6_dst=dst_ip, ipv6_dscp=dscp, @@ -508,6 +516,7 @@ def _base_tcpv6_packet(self, return pkt def _base_udpv6_packet(self, + direction, ptfadapter, setup, src_ip=DEFAULT_SRC_IP, @@ -518,7 +527,7 @@ def _base_udpv6_packet(self, dport=8080): pkt = testutils.simple_udpv6_packet( eth_src=ptfadapter.dataplane.get_mac(0, 0), - eth_dst=setup["router_mac"], + eth_dst=setup[direction]["ingress_router_mac"], ipv6_src=src_ip, ipv6_dst=dst_ip, ipv6_dscp=dscp, @@ -542,24 +551,40 @@ def mirror_type(self): return "ingress" @pytest.fixture(scope='class', autouse=True) - def setup_acl_table(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, config_method): - duthost = duthosts[rand_one_dut_hostname] - table_name = self._get_table_name(duthost) + def setup_acl_table(self, setup_info, setup_mirror_session, config_method): + + if setup_info['topo'] == 't0': + everflow_dut = setup_info[UP_STREAM]['everflow_dut'] + remote_dut = setup_info[UP_STREAM]['remote_dut'] + else: + everflow_dut = setup_info[DOWN_STREAM]['everflow_dut'] + remote_dut = setup_info[DOWN_STREAM]['remote_dut'] + + table_name = self._get_table_name(everflow_dut) temporary_table = False + duthost_set = set() + duthost_set.add(everflow_dut) + duthost_set.add(remote_dut) + if not table_name: table_name = "EVERFLOWV6" temporary_table = True - self.apply_acl_table_config(duthost, table_name, "MIRRORV6", config_method) - self.apply_acl_rule_config(duthost, table_name, setup_mirror_session["session_name"], config_method, rules=EVERFLOW_V6_RULES) + + for duthost in duthost_set: + if temporary_table: + self.apply_acl_table_config(duthost, table_name, "MIRRORV6", config_method) + + self.apply_acl_rule_config(duthost, table_name, setup_mirror_session["session_name"], config_method, rules=EVERFLOW_V6_RULES) yield - self.remove_acl_rule_config(duthost, table_name, config_method) + for duthost in duthost_set: + self.remove_acl_rule_config(duthost, table_name, config_method) - if temporary_table: - self.remove_acl_table_config(duthost, table_name, config_method) + if temporary_table: + self.remove_acl_table_config(duthost, table_name, config_method) # TODO: This can probably be refactored into a common utility method later. def _get_table_name(self, duthost): diff --git a/tests/everflow/test_everflow_per_interface.py b/tests/everflow/test_everflow_per_interface.py index 06e80bd1879..0cc9641e61b 100644 --- a/tests/everflow/test_everflow_per_interface.py +++ b/tests/everflow/test_everflow_per_interface.py @@ -7,7 +7,7 @@ import everflow_test_utilities as everflow_utils from everflow_test_utilities import BaseEverflowTest -from everflow_test_utilities import TEMPLATE_DIR, EVERFLOW_RULE_CREATE_TEMPLATE, DUT_RUN_DIR, EVERFLOW_RULE_CREATE_FILE +from everflow_test_utilities import TEMPLATE_DIR, EVERFLOW_RULE_CREATE_TEMPLATE, DUT_RUN_DIR, EVERFLOW_RULE_CREATE_FILE, UP_STREAM from tests.common.helpers.assertions import pytest_require, pytest_assert from everflow_test_utilities import setup_info, EVERFLOW_DSCP_RULES # noqa: F401, E501 lgtm[py/unused-import] pylint: disable=import-error @@ -26,9 +26,9 @@ logger = logging.getLogger(__file__) @pytest.fixture(scope="module", autouse=True) -def skip_if_not_supported(tbinfo, rand_selected_dut, ip_ver): +def skip_if_not_supported(tbinfo, setup_info, ip_ver): - asic_type = rand_selected_dut.facts["asic_type"] + asic_type = setup_info[UP_STREAM]['everflow_dut'].facts["asic_type"] unsupported_platforms = ["mellanox", "marvell", "cisco-8000"] # Skip ipv6 test on Mellanox platform is_mellanox_ipv4 = asic_type == 'mellanox' and ip_ver == 'ipv4' @@ -36,7 +36,7 @@ def skip_if_not_supported(tbinfo, rand_selected_dut, ip_ver): is_cisco_ipv4 = asic_type == 'cisco-8000' and ip_ver == 'ipv4' pytest_require(asic_type not in unsupported_platforms or is_mellanox_ipv4 or is_cisco_ipv4, "Match 'IN_PORTS' is not supported on {} platform".format(asic_type)) -def build_candidate_ports(duthost, tbinfo): +def build_candidate_ports(duthost, tbinfo, ns): """ Build candidate ports for testing """ @@ -46,17 +46,25 @@ def build_candidate_ports(duthost, tbinfo): candidate_neigh_name = 'Server' elif tbinfo['topo']['type'] == 'm0': candidate_neigh_name = 'MX' - else: + elif tbinfo['topo']['type'] == 't1': candidate_neigh_name = 'T0' + else: + candidate_neigh_name = 'T1' mg_facts = duthost.get_extended_minigraph_facts(tbinfo) + i = 0 for dut_port, neigh in mg_facts["minigraph_neighbors"].items(): + if neigh['namespace'] != ns: + continue ptf_idx = mg_facts["minigraph_ptf_indices"][dut_port] - if candidate_neigh_name in neigh['name'] and len(candidate_ports) < 4: + + if candidate_neigh_name in neigh['name'] and len(candidate_ports) < 4 and i % 2: candidate_ports.update({dut_port: ptf_idx}) if len(unselected_ports) < 4 and dut_port not in candidate_ports: unselected_ports.update({dut_port: ptf_idx}) + i = i + 1 + logger.info("Candidate testing ports are {}".format(candidate_ports)) return candidate_ports, unselected_ports @@ -72,97 +80,96 @@ def build_acl_rule_vars(candidate_ports, ip_ver): @pytest.fixture(scope='module') -def apply_mirror_session(rand_selected_dut): - mirror_session_info = BaseEverflowTest.mirror_session_info(EVERFLOW_SESSION_NAME, rand_selected_dut.facts["asic_type"]) +def apply_mirror_session(setup_info): + mirror_session_info = BaseEverflowTest.mirror_session_info(EVERFLOW_SESSION_NAME, setup_info[UP_STREAM]['everflow_dut'].facts["asic_type"]) logger.info("Applying mirror session to DUT") - BaseEverflowTest.apply_mirror_config(rand_selected_dut, mirror_session_info) + BaseEverflowTest.apply_mirror_config(setup_info[UP_STREAM]['everflow_dut'], mirror_session_info) time.sleep(10) - single_asic_cmd = 'sonic-db-cli STATE_DB hget \"MIRROR_SESSION_TABLE|{}\" \"monitor_port\"'.format(EVERFLOW_SESSION_NAME) - if rand_selected_dut.is_multi_asic: - for front_ns in rand_selected_dut.get_frontend_asic_namespace_list(): - cmd = "{} -n {}".format(single_asic_cmd, front_ns) - monitor_port = rand_selected_dut.shell(cmd=cmd)['stdout'] - pytest_assert(monitor_port != "", "Failed to retrieve monitor_port on multi-asic dut's frontend namespace: {}".format(front_ns)) - else: - monitor_port = rand_selected_dut.shell(cmd=single_asic_cmd)['stdout'] - pytest_assert(monitor_port != "", "Failed to retrieve monitor_port") - - yield mirror_session_info, monitor_port + yield mirror_session_info logger.info("Removing mirror session from DUT") - BaseEverflowTest.remove_mirror_config(rand_selected_dut, EVERFLOW_SESSION_NAME) + BaseEverflowTest.remove_mirror_config(setup_info[UP_STREAM]['everflow_dut'], EVERFLOW_SESSION_NAME) + +@pytest.fixture(scope='module') +def setup_mirror_session_dest_ip_route(tbinfo, setup_info, apply_mirror_session): + """ + Setup the route for mirror session destination ip and update monitor port list. + Remove the route as part of cleanup. + """ + namespace = setup_info[UP_STREAM]['remote_namespace'] + tx_port = setup_info[UP_STREAM]["dest_port"][0] + dest_port_ptf_id_list = [setup_info[UP_STREAM]["dest_port_ptf_id"][0]] + remote_dut = setup_info[UP_STREAM]['remote_dut'] + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"redistribute static\"", namespace)) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, apply_mirror_session["session_prefixes"][0], peer_ip, namespace) + time.sleep(5) + + yield (apply_mirror_session, BaseEverflowTest._get_tx_port_id_list(dest_port_ptf_id_list)) + + everflow_utils.remove_route(remote_dut, apply_mirror_session["session_prefixes"][0], peer_ip, namespace) + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"no redistribute static\"", namespace)) + @pytest.fixture(scope='module', params=['ipv4', 'ipv6']) def ip_ver(request): return request.param @pytest.fixture(scope='module') -def apply_acl_rule(rand_selected_dut, tbinfo, apply_mirror_session, ip_ver): +def apply_acl_rule(setup_info, tbinfo, setup_mirror_session_dest_ip_route, ip_ver): """ Apply ACL rule for matching input_ports """ # Check existence of EVERFLOW table_name = EVERFLOW_TABLE_NAME[ip_ver] - output = rand_selected_dut.shell('show acl table {}'.format(table_name))['stdout_lines'] + output = setup_info[UP_STREAM]['everflow_dut'].shell('show acl table {}'.format(table_name))['stdout_lines'] # Skip if EVERFLOW table doesn't exist pytest_require(len(output) > 2, "Skip test since {} dosen't exist".format(table_name)) - mg_facts = rand_selected_dut.get_extended_minigraph_facts(tbinfo) - mirror_session_info, monitor_port = apply_mirror_session + mg_facts = setup_info[UP_STREAM]['remote_dut'].get_extended_minigraph_facts(tbinfo) + mirror_session_info, monitor_port_ptf_ids = setup_mirror_session_dest_ip_route # Build testing port list - candidate_ports, unselected_ports = build_candidate_ports(rand_selected_dut, tbinfo) + candidate_ports, unselected_ports = build_candidate_ports(setup_info[UP_STREAM]['everflow_dut'], tbinfo, setup_info[UP_STREAM]['everflow_namespace']) pytest_require(len(candidate_ports) >= 1, "Not sufficient ports for testing") + pytest_require(len(unselected_ports) >= 1, "Not sufficient ports for testing") # Copy and apply ACL rule config_vars = build_acl_rule_vars(candidate_ports, ip_ver) - rand_selected_dut.host.options["variable_manager"].extra_vars.update(config_vars) - rand_selected_dut.command("mkdir -p {}".format(DUT_RUN_DIR)) - rand_selected_dut.template(src=os.path.join(TEMPLATE_DIR, EVERFLOW_RULE_CREATE_TEMPLATE), + setup_info[UP_STREAM]['everflow_dut'].host.options["variable_manager"].extra_vars.update(config_vars) + setup_info[UP_STREAM]['everflow_dut'].command("mkdir -p {}".format(DUT_RUN_DIR)) + setup_info[UP_STREAM]['everflow_dut'].template(src=os.path.join(TEMPLATE_DIR, EVERFLOW_RULE_CREATE_TEMPLATE), dest=os.path.join(DUT_RUN_DIR, EVERFLOW_RULE_CREATE_FILE)) logger.info("Applying acl rule config to DUT") command = "acl-loader update full {} --table_name {} --session_name {}" \ .format(os.path.join(DUT_RUN_DIR, EVERFLOW_RULE_CREATE_FILE), table_name, EVERFLOW_SESSION_NAME) - rand_selected_dut.shell(cmd=command) + setup_info[UP_STREAM]['everflow_dut'].shell(cmd=command) ret = { "candidate_ports": candidate_ports, "unselected_ports": unselected_ports, "mirror_session_info": mirror_session_info, - "monitor_port": {monitor_port: mg_facts["minigraph_ptf_indices"][monitor_port]} + "monitor_port_ptf_ids": monitor_port_ptf_ids } yield ret logger.info("Removing acl rule config from DUT") - BaseEverflowTest.remove_acl_rule_config(rand_selected_dut, table_name) + BaseEverflowTest.remove_acl_rule_config(setup_info[UP_STREAM]['everflow_dut'], table_name) -def generate_testing_packet(ptfadapter, duthost, mirror_session_info, router_mac): +def generate_testing_packet(ptfadapter, duthost, mirror_session_info, router_mac, setup): packet = testutils.simple_tcp_packet( eth_src=ptfadapter.dataplane.get_mac(0, 0), eth_dst=router_mac ) - setup = {} - setup["router_mac"] = router_mac - exp_packet = BaseEverflowTest.get_expected_mirror_packet(mirror_session_info, setup, duthost, packet, False) - return packet, exp_packet + dec_ttl = 0 -def get_uplink_ports(duthost, tbinfo): - """The collector IP is a destination reachable by default. - So we need to collect the uplink ports to do a packet capture - """ - uplink_ports = [] - mg_facts = duthost.get_extended_minigraph_facts(tbinfo) - if 't0' == tbinfo['topo']['type']: - neigh_name = 'T1' - elif 'm0' == tbinfo['topo']['type']: - neigh_name = 'M1' - else: - neigh_name = 'T2' - for dut_port, neigh in mg_facts["minigraph_neighbors"].items(): - ptf_idx = mg_facts["minigraph_ptf_indices"][dut_port] - if neigh_name in neigh['name']: - uplink_ports.append(ptf_idx) - return uplink_ports + if 't2' in setup['topo']: + dec_ttl = 1 + elif duthost.is_multi_asic: + dec_ttl = 2 + + exp_packet = BaseEverflowTest.get_expected_mirror_packet(mirror_session_info, setup, duthost, UP_STREAM, packet, dec_ttl) + return packet, exp_packet def send_and_verify_packet(ptfadapter, packet, expected_packet, tx_port, rx_ports, exp_recv): @@ -174,13 +181,15 @@ def send_and_verify_packet(ptfadapter, packet, expected_packet, tx_port, rx_port testutils.verify_no_packet_any(ptfadapter, pkt=expected_packet, ports=rx_ports) -def test_everflow_per_interface(ptfadapter, rand_selected_dut, apply_acl_rule, tbinfo): +def test_everflow_per_interface(ptfadapter, setup_info, apply_acl_rule, tbinfo): """Verify packet ingress from candidate ports are captured by EVERFLOW, while packets ingress from unselected ports are not captured """ everflow_config = apply_acl_rule - packet, exp_packet = generate_testing_packet(ptfadapter, rand_selected_dut, everflow_config['mirror_session_info'], rand_selected_dut.facts["router_mac"]) - uplink_ports = get_uplink_ports(rand_selected_dut, tbinfo) + packet, exp_packet = generate_testing_packet(ptfadapter, setup_info[UP_STREAM]['everflow_dut'], everflow_config['mirror_session_info'], + setup_info[UP_STREAM]['ingress_router_mac'], setup_info) + uplink_ports = everflow_config["monitor_port_ptf_ids"] + # Verify that packet ingressed from INPUT_PORTS (candidate ports) are mirrored for port, ptf_idx in everflow_config['candidate_ports'].items(): logger.info("Verifying packet ingress from {} is mirrored".format(port)) diff --git a/tests/everflow/test_everflow_testbed.py b/tests/everflow/test_everflow_testbed.py index 8e4c4f529ce..ff093b3a2b3 100644 --- a/tests/everflow/test_everflow_testbed.py +++ b/tests/everflow/test_everflow_testbed.py @@ -15,7 +15,7 @@ from tests.common.fixtures.ptfhost_utils import copy_arp_responder_py # noqa: F401, E501 lgtm[py/unused-import] pylint: disable=import-error pytestmark = [ - pytest.mark.topology("t0", "t1", "m0") + pytest.mark.topology("t0", "t1", "t2", "m0") ] @@ -25,22 +25,21 @@ @pytest.fixture -def partial_ptf_runner(request, duthosts, rand_one_dut_hostname, ptfhost): +def partial_ptf_runner(request, ptfhost): """ Fixture to run each Everflow PTF test case via ptf_runner. Takes all the necessary arguments to run the test case and returns a handle to the caller to execute the ptf_runner. """ - duthost = duthosts[rand_one_dut_hostname] - def _partial_ptf_runner(setup_info, session_info, acl_stage, mirror_type, expect_receive = True, test_name = None, **kwargs): + def _partial_ptf_runner(setup_info, direction, session_info, acl_stage, mirror_type, expect_receive = True, test_name = None, **kwargs): # Some of the arguments are fixed for each Everflow test case and defined here. # Arguments specific to each Everflow test case are passed in by each test via _partial_ptf_runner. # Arguments are passed in dictionary format via kwargs within each test case. params = { - 'hwsku' : duthost.facts['hwsku'], - 'asic_type' : duthost.facts['asic_type'], - 'router_mac': setup_info['router_mac'], + 'hwsku' : setup_info[direction]['everflow_dut'].facts['hwsku'], + 'asic_type' : setup_info[direction]['everflow_dut'].facts['asic_type'], + 'router_mac': setup_info[direction]['ingress_router_mac'], 'session_src_ip' : session_info['session_src_ip'], 'session_dst_ip' : session_info['session_dst_ip'], 'session_ttl' : session_info['session_ttl'], @@ -48,7 +47,7 @@ def _partial_ptf_runner(setup_info, session_info, acl_stage, mirror_type, expec 'acl_stage' : acl_stage, 'mirror_stage' : mirror_type, 'expect_received' : expect_receive, - 'check_ttl' : 'True' if not duthost.is_multi_asic else 'False' } + 'check_ttl' : 'False' if setup_info[direction]['everflow_dut'].is_multi_asic or "t2" in setup_info["topo"] else 'True' } params.update(kwargs) ptf_runner(host=ptfhost, @@ -71,38 +70,41 @@ class EverflowIPv4Tests(BaseEverflowTest): MIRROR_POLICER_UNSUPPORTED_ASIC_LIST = ["th3"] @pytest.fixture(params=[DOWN_STREAM, UP_STREAM]) - def dest_port_type(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, tbinfo, request): + def dest_port_type(self, setup_info, setup_mirror_session, tbinfo, request): """ This fixture parametrize dest_port_type and can perform action based on that. As of now cleanup is being done here. """ - duthost = duthosts[rand_one_dut_hostname] - - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"redistribute static\"",setup_info[request.param]["namespace"])) + remote_dut = setup_info[request.param]['remote_dut'] + + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"redistribute static\"", + setup_info[request.param]["remote_namespace"])) yield request.param for index in range(0, min(3, len(setup_info[request.param]["dest_port"]))): tx_port = setup_info[request.param]["dest_port"][index] - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[request.param]["namespace"]) - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[request.param]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[request.param]["remote_namespace"]) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[request.param]["remote_namespace"]) - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"no redistribute static\"",setup_info[request.param]["namespace"])) + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"config\" -c \"router bgp\" -c \"address-family ipv4\" -c \"no redistribute static\"", + setup_info[request.param]["remote_namespace"])) time.sleep(15) @pytest.fixture(autouse=True) - def add_dest_routes(self, duthosts, rand_one_dut_hostname, setup_info, tbinfo, dest_port_type): + def add_dest_routes(self, setup_info, tbinfo, dest_port_type): if self.acl_stage() != 'egress': yield return - duthost = duthosts[rand_one_dut_hostname] default_traffic_port_type = DOWN_STREAM if dest_port_type == UP_STREAM else UP_STREAM + + duthost = setup_info[default_traffic_port_type]['remote_dut'] rx_port = setup_info[default_traffic_port_type]["dest_port"][0] nexthop_ip = everflow_utils.get_neighbor_info(duthost, rx_port, tbinfo) - - ns = setup_info[default_traffic_port_type]["namespace"] + + ns = setup_info[default_traffic_port_type]["remote_namespace"] dst_mask = "30.0.0.0/28" everflow_utils.add_route(duthost, dst_mask, nexthop_ip, ns) @@ -111,8 +113,8 @@ def add_dest_routes(self, duthosts, rand_one_dut_hostname, setup_info, tbinfo, d everflow_utils.remove_route(duthost, dst_mask, nexthop_ip, ns) - - def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): + def test_everflow_basic_forwarding(self, setup_info, setup_mirror_session, + dest_port_type, ptfadapter, tbinfo): """ Verify basic forwarding scenarios for the Everflow feature. @@ -122,13 +124,15 @@ def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_ - LPM (longest prefix match) - Route creation and removal """ - duthost = duthosts[rand_one_dut_hostname] - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"no ip nht resolve-via-default\"", setup_info[dest_port_type]["namespace"])) + everflow_dut = setup_info[dest_port_type]['everflow_dut'] + remote_dut = setup_info[dest_port_type]['remote_dut'] + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"no ip nht resolve-via-default\"", setup_info[dest_port_type]["remote_namespace"])) # Add a route to the mirror session destination IP tx_port = setup_info[dest_port_type]["dest_port"][0] - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) + time.sleep(15) # Verify that mirrored traffic is sent along the route we installed @@ -138,15 +142,15 @@ def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_ ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type ) # Add a (better) unresolved route to the mirror session destination IP - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo, resolved=False) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo, resolved=False) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is still sent along the original route @@ -154,19 +158,19 @@ def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_ ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type ) # Remove the unresolved route - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["namespace"]) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["remote_namespace"]) # Add a better route to the mirror session destination IP tx_port = setup_info[dest_port_type]["dest_port"][1] - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session['session_prefixes'][1], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session['session_prefixes'][1], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic uses the new route @@ -175,14 +179,14 @@ def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_ ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type ) # Remove the better route. - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["namespace"]) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][1], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic switches back to the original route @@ -191,20 +195,25 @@ def test_everflow_basic_forwarding(self, duthosts, rand_one_dut_hostname, setup_ ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type ) - duthost.shell(duthost.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"ip nht resolve-via-default\"", setup_info[dest_port_type]["namespace"])) - def test_everflow_neighbor_mac_change(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): + + remote_dut.shell(remote_dut.get_vtysh_cmd_for_namespace("vtysh -c \"configure terminal\" -c \"ip nht resolve-via-default\"", setup_info[dest_port_type]["remote_namespace"])) + + def test_everflow_neighbor_mac_change(self, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): """Verify that session destination MAC address is changed after neighbor MAC address update.""" - duthost = duthosts[rand_one_dut_hostname] + + everflow_dut = setup_info[dest_port_type]['everflow_dut'] + remote_dut = setup_info[dest_port_type]['remote_dut'] + # Add a route to the mirror session destination IP tx_port = setup_info[dest_port_type]["dest_port"][0] - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is sent along the route we installed @@ -214,7 +223,7 @@ def test_everflow_neighbor_mac_change(self, duthosts, rand_one_dut_hostname, set ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type @@ -224,8 +233,8 @@ def test_everflow_neighbor_mac_change(self, duthosts, rand_one_dut_hostname, set if setup_info[dest_port_type]["dest_port_lag_name"][0] != "Not Applicable": tx_port = setup_info[dest_port_type]["dest_port_lag_name"][0] - duthost.shell(duthost.get_linux_ip_cmd_for_namespace("ip neigh replace {} lladdr 00:11:22:33:44:55 nud permanent dev {}". - format(peer_ip, tx_port), setup_info[dest_port_type]["namespace"])) + remote_dut.shell(remote_dut.get_linux_ip_cmd_for_namespace("ip neigh replace {} lladdr 00:11:22:33:44:55 nud permanent dev {}". + format(peer_ip, tx_port), setup_info[dest_port_type]["remote_namespace"])) time.sleep(15) try: # Verify that everything still works @@ -233,7 +242,7 @@ def test_everflow_neighbor_mac_change(self, duthosts, rand_one_dut_hostname, set ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type @@ -241,32 +250,36 @@ def test_everflow_neighbor_mac_change(self, duthosts, rand_one_dut_hostname, set finally: # Clean up the test - duthost.shell(duthost.get_linux_ip_cmd_for_namespace("ip neigh del {} dev {}".format(peer_ip, tx_port), setup_info[dest_port_type]["namespace"])) - duthost.get_asic_or_sonic_host_from_namespace(setup_info[dest_port_type]["namespace"]).command("ping {} -c3".format(peer_ip)) + remote_dut.shell(remote_dut.get_linux_ip_cmd_for_namespace("ip neigh del {} dev {}".format(peer_ip, tx_port), setup_info[dest_port_type]["remote_namespace"])) + remote_dut.get_asic_or_sonic_host_from_namespace(setup_info[dest_port_type]["remote_namespace"]).command("ping {} -c3".format(peer_ip)) # Verify that everything still works self._run_everflow_test_scenarios( ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type ) - def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): + def test_everflow_remove_unused_ecmp_next_hop(self, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): """Verify that session is still active after removal of next hop from ECMP route that was not in use.""" - duthost = duthosts[rand_one_dut_hostname] + + + everflow_dut = setup_info[dest_port_type]['everflow_dut'] + remote_dut = setup_info[dest_port_type]['remote_dut'] + # Create two ECMP next hops tx_port = setup_info[dest_port_type]["dest_port"][0] - peer_ip_0 = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["namespace"]) + peer_ip_0 = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) tx_port = setup_info[dest_port_type]["dest_port"][1] - peer_ip_1 = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_1, setup_info[dest_port_type]["namespace"]) + peer_ip_1 = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_1, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is sent to one of the next hops @@ -279,7 +292,7 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, tx_port_ptf_ids, dest_port_type @@ -291,8 +304,8 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn # Add another ECMP next hop tx_port = setup_info[dest_port_type]["dest_port"][2] - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is not sent to this new next hop @@ -301,7 +314,7 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type, @@ -310,7 +323,7 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn ) # Remove the extra hop - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is not sent to the deleted next hop @@ -318,7 +331,7 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type, @@ -331,24 +344,26 @@ def test_everflow_remove_unused_ecmp_next_hop(self, duthosts, rand_one_dut_hostn ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, tx_port_ptf_ids, dest_port_type ) - def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostname, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): + def test_everflow_remove_used_ecmp_next_hop(self, setup_info, setup_mirror_session, dest_port_type, ptfadapter, tbinfo): """Verify that session is still active after removal of next hop from ECMP route that was in use.""" - + + everflow_dut = setup_info[dest_port_type]['everflow_dut'] + remote_dut = setup_info[dest_port_type]['remote_dut'] + # Remaining Scenario not applicable for this topology if len(setup_info[dest_port_type]["dest_port"]) <= 2: pytest.skip("Skip test as not enough neighbors/ports.") - duthost = duthosts[rand_one_dut_hostname] # Add a route to the mirror session destination IP tx_port = setup_info[dest_port_type]["dest_port"][0] - peer_ip_0 = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["namespace"]) + peer_ip_0 = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is sent along the route we installed @@ -358,7 +373,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type @@ -366,12 +381,12 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam # Add two new ECMP next hops tx_port = setup_info[dest_port_type]["dest_port"][1] - peer_ip_1 = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_1, setup_info[dest_port_type]["namespace"]) + peer_ip_1 = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_1, setup_info[dest_port_type]["remote_namespace"]) tx_port = setup_info[dest_port_type]["dest_port"][2] - peer_ip_2 = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_2, setup_info[dest_port_type]["namespace"]) + peer_ip_2 = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_2, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that traffic is still sent along the original next hop @@ -379,7 +394,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type, @@ -395,7 +410,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, tx_port_ptf_ids, dest_port_type, @@ -404,7 +419,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ) # Remove the original next hop - everflow_utils.remove_route(duthost, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["namespace"]) + everflow_utils.remove_route(remote_dut, setup_mirror_session["session_prefixes"][0], peer_ip_0, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) # Verify that mirrored traffic is no longer sent along the original next hop @@ -412,7 +427,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, [tx_port_ptf_id], dest_port_type, @@ -424,7 +439,7 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam ptfadapter, setup_info, setup_mirror_session, - duthost, + everflow_dut, rx_port_ptf_id, tx_port_ptf_ids, dest_port_type @@ -432,7 +447,6 @@ def test_everflow_remove_used_ecmp_next_hop(self, duthosts, rand_one_dut_hostnam def test_everflow_dscp_with_policer( self, - duthost, setup_info, policer_mirror_session, dest_port_type, @@ -451,16 +465,21 @@ def test_everflow_dscp_with_policer( # and mirror packets can go to same interface, which causes tail drop of # police packets and impacts test case cir/cbs calculation. - vendor = duthost.facts["asic_type"] - hostvars = duthost.host.options['variable_manager']._hostvars[duthost.hostname] + everflow_dut = setup_info[dest_port_type]['everflow_dut'] + remote_dut = setup_info[dest_port_type]['remote_dut'] + + vendor = everflow_dut.facts["asic_type"] + hostvars = everflow_dut.host.options['variable_manager']._hostvars[everflow_dut.hostname] + everflow_tolerance = 10 if vendor == 'innovium': everflow_tolerance = 11 for asic in self.MIRROR_POLICER_UNSUPPORTED_ASIC_LIST: vendorAsic = "{0}_{1}_hwskus".format(vendor, asic) - if vendorAsic in hostvars.keys() and duthost.facts['hwsku'] in hostvars[vendorAsic]: - pytest.skip("Skipping test since mirror policing is not supported on {0} {1} platforms".format(vendor,asic)) + if vendorAsic in hostvars.keys() and everflow_dut.facts['hwsku'] in hostvars[vendorAsic]: + pytest.skip("Skipping test since mirror policing is not supported on {0} {1} platforms".format(vendor, asic)) + if setup_info['topo'] == 't0': default_tarffic_port_type = dest_port_type # Use the second portchannel as missor session nexthop @@ -469,19 +488,20 @@ def test_everflow_dscp_with_policer( default_tarffic_port_type = DOWN_STREAM if dest_port_type == UP_STREAM else UP_STREAM tx_port = setup_info[dest_port_type]["dest_port"][0] default_traffic_tx_port = setup_info[default_tarffic_port_type]["dest_port"][0] - default_traffic_peer_ip = everflow_utils.get_neighbor_info(duthost, default_traffic_tx_port, tbinfo) - everflow_utils.add_route(duthost, self.DEFAULT_DST_IP + "/32", default_traffic_peer_ip, setup_info[default_tarffic_port_type]["namespace"]) + default_traffic_peer_ip = everflow_utils.get_neighbor_info(everflow_dut, default_traffic_tx_port, tbinfo) + everflow_utils.add_route(everflow_dut, self.DEFAULT_DST_IP + "/32", default_traffic_peer_ip, setup_info[default_tarffic_port_type]["remote_namespace"]) time.sleep(15) # Add explicit route for the mirror session - peer_ip = everflow_utils.get_neighbor_info(duthost, tx_port, tbinfo) - everflow_utils.add_route(duthost, policer_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) + peer_ip = everflow_utils.get_neighbor_info(remote_dut, tx_port, tbinfo) + everflow_utils.add_route(remote_dut, policer_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) time.sleep(15) try: # Add MIRROR_DSCP table for test table_name = "EVERFLOW_DSCP" table_type = "MIRROR_DSCP" + bind_interface_namespace = setup_info[dest_port_type]["everflow_namespace"] rx_port_ptf_id = setup_info[dest_port_type]["src_port_ptf_id"] tx_port_ptf_id = setup_info[dest_port_type]["dest_port_ptf_id"][0] if setup_info['topo'] == 't0' and self.acl_stage() == "egress": @@ -496,12 +516,11 @@ def test_everflow_dscp_with_policer( # Temp change for multi-asic to create acl table in host and namespace # Will be removed once CLI is command is enahnced to work across all namespaces. - self.apply_acl_table_config(duthost, table_name, table_type, config_method, [bind_interface]) - bind_interface_namespace = self._get_port_namespace(setup_info, int(rx_port_ptf_id)) + self.apply_acl_table_config(everflow_dut, table_name, table_type, config_method, [bind_interface]) if bind_interface_namespace: - self.apply_acl_table_config(duthost, table_name, table_type, config_method, [bind_interface], bind_interface_namespace) + self.apply_acl_table_config(everflow_dut, table_name, table_type, config_method, [bind_interface], bind_interface_namespace) # Add rule to match on DSCP - self.apply_acl_rule_config(duthost, + self.apply_acl_rule_config(everflow_dut, table_name, policer_mirror_session["session_name"], config_method, @@ -509,6 +528,7 @@ def test_everflow_dscp_with_policer( # Run test with expected CIR/CBS in packets/sec and tolerance % partial_ptf_runner(setup_info, + dest_port_type, policer_mirror_session, self.acl_stage(), self.mirror_type(), @@ -524,12 +544,12 @@ def test_everflow_dscp_with_policer( tolerance=everflow_tolerance) finally: # Clean up ACL rules and routes - BaseEverflowTest.remove_acl_rule_config(duthost, table_name, config_method) - self.remove_acl_table_config(duthost, table_name, config_method) + BaseEverflowTest.remove_acl_rule_config(everflow_dut, table_name, config_method) + self.remove_acl_table_config(everflow_dut, table_name, config_method) if bind_interface_namespace: - self.remove_acl_table_config(duthost, table_name, config_method, bind_interface_namespace) - everflow_utils.remove_route(duthost, policer_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["namespace"]) - everflow_utils.remove_route(duthost, self.DEFAULT_DST_IP + "/32", default_traffic_peer_ip, setup_info[default_tarffic_port_type]["namespace"]) + self.remove_acl_table_config(everflow_dut, table_name, config_method, bind_interface_namespace) + everflow_utils.remove_route(remote_dut, policer_mirror_session["session_prefixes"][0], peer_ip, setup_info[dest_port_type]["remote_namespace"]) + everflow_utils.remove_route(everflow_dut, self.DEFAULT_DST_IP + "/32", default_traffic_peer_ip, setup_info[default_tarffic_port_type]["remote_namespace"]) def _run_everflow_test_scenarios(self, ptfadapter, setup, mirror_session, duthost, rx_port, tx_ports, direction, expect_recv=True, valid_across_namespace=True): # FIXME: In the ptf_runner version of these tests, LAGs were passed down to the tests as comma-separated strings of @@ -542,16 +562,18 @@ def _run_everflow_test_scenarios(self, ptfadapter, setup, mirror_session, duthos target_ip = TARGET_SERVER_IP default_ip = DEFAULT_SERVER_IP + router_mac = setup[direction]["ingress_router_mac"] + pkt_dict = { - "(src ip)": self._base_tcp_packet(ptfadapter, setup, src_ip="20.0.0.10", dst_ip=default_ip), - "(dst ip)": self._base_tcp_packet(ptfadapter, setup, dst_ip=target_ip), - "(l4 src port)": self._base_tcp_packet(ptfadapter, setup, sport=0x1235, dst_ip=default_ip), - "(l4 dst port)": self._base_tcp_packet(ptfadapter, setup, dport=0x1235, dst_ip=default_ip), - "(ip protocol)": self._base_tcp_packet(ptfadapter, setup, ip_protocol=0x7E, dst_ip=default_ip), - "(tcp flags)": self._base_tcp_packet(ptfadapter, setup, flags=0x12, dst_ip=default_ip), - "(l4 src range)": self._base_tcp_packet(ptfadapter, setup, sport=4675, dst_ip=default_ip), - "(l4 dst range)": self._base_tcp_packet(ptfadapter, setup, dport=4675, dst_ip=default_ip), - "(dscp)": self._base_tcp_packet(ptfadapter, setup, dscp=51, dst_ip=default_ip) + "(src ip)": self._base_tcp_packet(ptfadapter, setup, router_mac, src_ip="20.0.0.10", dst_ip=default_ip), + "(dst ip)": self._base_tcp_packet(ptfadapter, setup, router_mac, dst_ip=target_ip), + "(l4 src port)": self._base_tcp_packet(ptfadapter, setup, router_mac, sport=0x1235, dst_ip=default_ip), + "(l4 dst port)": self._base_tcp_packet(ptfadapter, setup, router_mac, dport=0x1235, dst_ip=default_ip), + "(ip protocol)": self._base_tcp_packet(ptfadapter, setup, router_mac, ip_protocol=0x7E, dst_ip=default_ip), + "(tcp flags)": self._base_tcp_packet(ptfadapter, setup, router_mac, flags=0x12, dst_ip=default_ip), + "(l4 src range)": self._base_tcp_packet(ptfadapter, setup, router_mac, sport=4675, dst_ip=default_ip), + "(l4 dst range)": self._base_tcp_packet(ptfadapter, setup, router_mac, dport=4675, dst_ip=default_ip), + "(dscp)": self._base_tcp_packet(ptfadapter, setup, router_mac, dscp=51, dst_ip=default_ip) } for description, pkt in pkt_dict.items(): @@ -562,16 +584,18 @@ def _run_everflow_test_scenarios(self, ptfadapter, setup, mirror_session, duthos ptfadapter, duthost, pkt, + direction, src_port=rx_port, dest_ports=tx_port_ids, expect_recv=expect_recv, - valid_across_namespace=valid_across_namespace + valid_across_namespace=valid_across_namespace, ) def _base_tcp_packet( self, ptfadapter, setup, + router_mac, src_ip=DEFAULT_SRC_IP, dst_ip=DEFAULT_DST_IP, ip_protocol=None, @@ -582,7 +606,7 @@ def _base_tcp_packet( ): pkt = testutils.simple_tcp_packet( eth_src=ptfadapter.dataplane.get_mac(0, 0), - eth_dst=setup["router_mac"], + eth_dst=router_mac, ip_src=src_ip, ip_dst=dst_ip, ip_ttl=64,