From 62c8aa740df0ff4081b5be7a008a55acf187c50d Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Mon, 5 May 2025 12:28:02 -0700 Subject: [PATCH 01/17] Updated helper.py to incorporate new snappi changes in toggle_dut_port_state fixture --- tests/snappi_tests/ecn/files/helper.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/snappi_tests/ecn/files/helper.py b/tests/snappi_tests/ecn/files/helper.py index 1e9babb9c3b..2e36975eed4 100644 --- a/tests/snappi_tests/ecn/files/helper.py +++ b/tests/snappi_tests/ecn/files/helper.py @@ -465,21 +465,23 @@ def toggle_dut_port_state(api): config = api.get_config() # Collect all port names port_names = [port.name for port in config.ports] - # Create a link state object for all ports - link_state = api.link_state() + # Create a control state object for all ports + cs = api.control_state() + # Create a control state object for all ports + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK # Apply the state to all ports - link_state.port_names = port_names + cs.link.port_names = port_names # Set all ports down (shut) - link_state.state = link_state.DOWN - api.set_link_state(link_state) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) logger.info("All Snappi ports are set to DOWN") time.sleep(0.2) # Unshut all ports - link_state.state = link_state.UP - api.set_link_state(link_state) + cs.port.link.state = cs.port.link.UP + api.set_control_state(cs) logger.info("All Snappi ports are set to UP") - def _generate_traffic_config(testbed_config, snappi_extra_params, port_config_list, From f7974909322a2273dc95ae7a6c1af88c27bf9385 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Mon, 5 May 2025 12:29:47 -0700 Subject: [PATCH 02/17] Updated ecnhelper.py to incorporate new snappi changes to run_ecn_test_cisco8000 fixture --- tests/snappi_tests/ecn/files/ecnhelper.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index d307859ab08..1c70f3e41e3 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -197,18 +197,21 @@ def run_ecn_test_cisco8000(api, config = api.get_config() # Collect all port names port_names = [port.name for port in config.ports] - # Create a link state object for all ports - link_state = api.link_state() + # Create a control state object for all ports + cs = api.control_state() + # Create a control state object for all ports + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK # Apply the state to all ports - link_state.port_names = port_names + cs.link.port_names = port_names # Set all ports down (shut) - link_state.state = link_state.DOWN - api.set_link_state(link_state) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) logger.info("All Snappi ports are set to DOWN") time.sleep(0.2) # Unshut all ports - link_state.state = link_state.UP - api.set_link_state(link_state) + cs.port.link.state = cs.port.link.UP + api.set_control_state(cs) logger.info("All Snappi ports are set to UP") init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) From f6cb96bebed08728deef3be94757d331e71b793c Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Mon, 5 May 2025 12:30:47 -0700 Subject: [PATCH 03/17] Updated bpfabric_helper.py to incorporate new snappi changes in start and stop traffic --- tests/snappi_tests/ecn/files/bpfabric_helper.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/snappi_tests/ecn/files/bpfabric_helper.py b/tests/snappi_tests/ecn/files/bpfabric_helper.py index 2d8058bba6d..1125c3ab8ca 100644 --- a/tests/snappi_tests/ecn/files/bpfabric_helper.py +++ b/tests/snappi_tests/ecn/files/bpfabric_helper.py @@ -192,16 +192,16 @@ def adjust_shaper_and_verify(dut, egress_intfs, test_prio_list, api): queue_counters[intf] = init_ctr - # Start traffic again - ts = api.transmit_state() - ts.state = ts.START - api.set_transmit_state(ts) + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.START + api.set_control_state(cs) time.sleep(DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC) # Stop traffic - ts.state = ts.STOP - api.set_transmit_state(ts) + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.STOP + api.set_control_state(cs) for intf in egress_intfs: post_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) From d36aabf092d8ff26edffac186fcf92e512b19417 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Mon, 5 May 2025 12:32:20 -0700 Subject: [PATCH 04/17] Updated helper.py to incorporate new snappi changes to run_tx_drop_counter fixture. --- tests/snappi_tests/pfc/files/helper.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/snappi_tests/pfc/files/helper.py b/tests/snappi_tests/pfc/files/helper.py index 5bce0a58787..8c170f211d8 100644 --- a/tests/snappi_tests/pfc/files/helper.py +++ b/tests/snappi_tests/pfc/files/helper.py @@ -412,13 +412,16 @@ def run_tx_drop_counter( # Set port name of the Ixia port connected to dut_port port_names = snappi_extra_params.base_flow_config["rx_port_name"] - # Create a link state object for ports - link_state = api.link_state() + # Create a control state object for all ports + cs = api.control_state() + # Create a control state object for all ports + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK # Apply the state to port - link_state.port_names = [port_names] + cs.link.port_names = [port_names] # Set port down (shut) - link_state.state = link_state.DOWN - api.set_link_state(link_state) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) logger.info("Snappi port {} is set to DOWN".format(port_names)) time.sleep(1) # Collect metrics from DUT again From 4bd7bbee3e67c96e5481a54e959826316cc4f522 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 14 May 2025 15:51:17 -0700 Subject: [PATCH 05/17] Update bpfabric_helper.py fixed static analysis --- .../snappi_tests/ecn/files/bpfabric_helper.py | 487 +++++++++--------- 1 file changed, 246 insertions(+), 241 deletions(-) diff --git a/tests/snappi_tests/ecn/files/bpfabric_helper.py b/tests/snappi_tests/ecn/files/bpfabric_helper.py index 1125c3ab8ca..dfa53958716 100644 --- a/tests/snappi_tests/ecn/files/bpfabric_helper.py +++ b/tests/snappi_tests/ecn/files/bpfabric_helper.py @@ -2,18 +2,17 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts # noqa: F401 from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ - snappi_api # noqa: F401 +snappi_api # noqa: F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector, config_wred, \ - enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ - config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_all_port_stats # noqa: F401 +enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ +config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_all_port_stats # noqa: F401 from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ - generate_pause_flows, run_traffic # noqa: F401 +generate_pause_flows, run_traffic # noqa: F401 from tests.snappi_tests.files.helper import get_fabric_mapping, load_port_stats, \ - infer_ecmp_backplane_ports, set_cir_cisco_8000, get_npu_voq_queue_counters, compute_expected_packets +infer_ecmp_backplane_ports, set_cir_cisco_8000, get_npu_voq_queue_counters, compute_expected_packets import time - logger = logging.getLogger(__name__) DATA_FLOW_PKT_SIZE = 1350 @@ -22,281 +21,287 @@ DATA_FLOW_NAME = 'Data Flow' PAUSE_FLOW_NAME = 'Pause Storm' - def verify_ecn_marking_counters(ecn_counters, lossless_prio, intf): - # verify that each flow had packets - init_ctr, post_ctr = ecn_counters[0] - - flow_total = post_ctr['SAI_QUEUE_STAT_PACKETS'] - init_ctr['SAI_QUEUE_STAT_PACKETS'] - - pytest_assert(flow_total > 0, - 'Queue {} counters at start {} at end {} did not increment of {}'.format( - lossless_prio, init_ctr['SAI_QUEUE_STAT_PACKETS'], post_ctr['SAI_QUEUE_STAT_PACKETS'], intf)) - - flow_ecn = post_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - - pytest_assert(flow_ecn > 0, - 'Must have ecn marked packets on queue {} of {}'.format(lossless_prio, intf)) - - -def _generate_traffic_config(testbed_config, - snappi_extra_params, - port_config_list, - test_prio_list, - test_flow_percent, - prio_dscp_map, - congested=False): - TEST_FLOW_NAME = DATA_FLOW_NAME + ' ' + str(test_prio_list[0]) - - port_id = 0 - # Generate base traffic config - base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - - # Create a dictionary with priorities as keys and flow rates as values - flow_rate_dict = { - prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) +\# verify that each flow had packets +init_ctr, post_ctr = ecn_counters\[0\] + +``` +flow_total = post_ctr['SAI_QUEUE_STAT_PACKETS'] - init_ctr['SAI_QUEUE_STAT_PACKETS'] + +pytest_assert(flow_total > 0, + 'Queue {} counters at start {} at end {} did not increment of {}'.format( + lossless_prio, init_ctr['SAI_QUEUE_STAT_PACKETS'], post_ctr['SAI_QUEUE_STAT_PACKETS'], intf)) + +flow_ecn = post_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + +pytest_assert(flow_ecn > 0, + 'Must have ecn marked packets on queue {} of {}'.format(lossless_prio, intf)) +``` + +def \_generate_traffic_config(testbed_config, +snappi_extra_params, +port_config_list, +test_prio_list, +test_flow_percent, +prio_dscp_map, +congested=False): +TEST_FLOW_NAME = DATA_FLOW_NAME + ' ' + str(test_prio_list\[0\]) + +``` +port_id = 0 +# Generate base traffic config +base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + +# Create a dictionary with priorities as keys and flow rates as values +flow_rate_dict = { + prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) +} + +snappi_extra_params.base_flow_config = base_flow_config1 + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION } - snappi_extra_params.base_flow_config = base_flow_config1 - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=1) - +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=1) +``` def get_traffic_path( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - snappi_extra_params): +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +snappi_extra_params): - """ - Returns: - list: Returns traffic path [ingress_port, tx_bp, fabric_rx, fabric_tx, rx_bp, egress_port] - """ +``` +""" +Returns: + list: Returns traffic path [ingress_port, tx_bp, fabric_rx, fabric_tx, rx_bp, egress_port] +""" - test_flow_percent = [49] * len(test_prio_list) +test_flow_percent = [49] * len(test_prio_list) - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() - # Traffic flow: - # tx_port (TGEN) --- ingress DUT ---Fabric---- egress DUT --- rx_port (TGEN) +# Traffic flow: +# tx_port (TGEN) --- ingress DUT ---Fabric---- egress DUT --- rx_port (TGEN) - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] - tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost = tx_port['duthost'] +tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost = tx_port['duthost'] - # Append the duthost here for run_traffic to clear its counters - snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost) - snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) +# Append the duthost here for run_traffic to clear its counters +snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost) +snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) - duthost = egress_duthost +duthost = egress_duthost - _generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map) +_generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map) - flows = testbed_config.flows +flows = testbed_config.flows - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - speed_str = testbed_config.layer1[0].speed - speed_gbps = int(speed_str.split('_')[1]) +speed_str = testbed_config.layer1[0].speed +speed_gbps = int(speed_str.split('_')[1]) - # Find the expected packets for the given traffic duration and flow percent. - # This helps find the bp interfaces involved in the traffic path more accurately - pkt_threshold = compute_expected_packets(speed_gbps * 10**9 * test_flow_percent[0]/100, - DATA_FLOW_PKT_SIZE, DATA_FLOW_DURATION_SEC) +# Find the expected packets for the given traffic duration and flow percent. +# This helps find the bp interfaces involved in the traffic path more accurately +pkt_threshold = compute_expected_packets(speed_gbps * 10**9 * test_flow_percent[0]/100, + DATA_FLOW_PKT_SIZE, DATA_FLOW_DURATION_SEC) - """ Run traffic """ - _, _, _ = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) +""" Run traffic """ +_, _, _ = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) - # get all the port stats - ingress_stats = get_all_port_stats(ingress_duthost) - egress_stats = get_all_port_stats(egress_duthost) +# get all the port stats +ingress_stats = get_all_port_stats(ingress_duthost) +egress_stats = get_all_port_stats(egress_duthost) - # Find the active data path interfaces using the expected pkt threshold. - ingress_active_interfaces = load_port_stats(ingress_stats, pkt_threshold, direction="tx") - egress_active_interfaces = load_port_stats(egress_stats, pkt_threshold, direction="rx") +# Find the active data path interfaces using the expected pkt threshold. +ingress_active_interfaces = load_port_stats(ingress_stats, pkt_threshold, direction="tx") +egress_active_interfaces = load_port_stats(egress_stats, pkt_threshold, direction="rx") - # Find the fabric mapping from the CLI - ingress_fabric_mapping = get_fabric_mapping(ingress_duthost) - egress_fabric_mapping = get_fabric_mapping(egress_duthost) +# Find the fabric mapping from the CLI +ingress_fabric_mapping = get_fabric_mapping(ingress_duthost) +egress_fabric_mapping = get_fabric_mapping(egress_duthost) - # Infer the traffic path from ingress to egress port via BP and Fabric port - traffic_paths = infer_ecmp_backplane_ports(ingress_active_interfaces, egress_active_interfaces, - snappi_extra_params.multi_dut_params.multi_dut_ports[1]['peer_port'], - dut_port, ingress_fabric_mapping, egress_fabric_mapping) +# Infer the traffic path from ingress to egress port via BP and Fabric port +traffic_paths = infer_ecmp_backplane_ports(ingress_active_interfaces, egress_active_interfaces, + snappi_extra_params.multi_dut_params.multi_dut_ports[1]['peer_port'], + dut_port, ingress_fabric_mapping, egress_fabric_mapping) - pytest_assert(traffic_paths, "Unable to find traffic path for the given ingress and egress port") - - logger.info("Traffic paths {}".format(traffic_paths)) - return traffic_paths +pytest_assert(traffic_paths, "Unable to find traffic path for the given ingress and egress port") +logger.info("Traffic paths {}".format(traffic_paths)) +return traffic_paths +``` def adjust_shaper_and_verify(dut, egress_intfs, test_prio_list, api): - egress_asic_map = {} - - # Create a map of asic instance and egress ports involved in the traffic path - for intf in egress_intfs: - asic_instance = dut.get_port_asic_instance(intf) - if asic_instance not in egress_asic_map: - egress_asic_map[asic_instance] = [] +egress_asic_map = {} - egress_asic_map[asic_instance].append(intf) +``` +# Create a map of asic instance and egress ports involved in the traffic path +for intf in egress_intfs: + asic_instance = dut.get_port_asic_instance(intf) + if asic_instance not in egress_asic_map: + egress_asic_map[asic_instance] = [] - try: - # Iterate over the egress port map and call set_cir_cisco_8000 - for asic_instance, intf_list in egress_asic_map.items(): - # Set the shaper to 5GB to induce congestion on the egress ports - set_cir_cisco_8000(dut, intf_list, asic_instance, speed=5 * 1000 * 1000 * 1000) + egress_asic_map[asic_instance].append(intf) - queue_counters = {} - for intf in egress_intfs: - init_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) +try: + # Iterate over the egress port map and call set_cir_cisco_8000 + for asic_instance, intf_list in egress_asic_map.items(): + # Set the shaper to 5GB to induce congestion on the egress ports + set_cir_cisco_8000(dut, intf_list, asic_instance, speed=5 * 1000 * 1000 * 1000) - queue_counters[intf] = init_ctr + queue_counters = {} + for intf in egress_intfs: + init_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) - cs = api.control_state() - cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.START - api.set_control_state(cs) + queue_counters[intf] = init_ctr - time.sleep(DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC) + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.START + api.set_control_state(cs) - # Stop traffic - cs = api.control_state() - cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.STOP - api.set_control_state(cs) + time.sleep(DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC) - for intf in egress_intfs: - post_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) + # Stop traffic + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.STOP + api.set_control_state(cs) - init_ctr = queue_counters[intf] + for intf in egress_intfs: + post_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) - ecn_counters = [ - (init_ctr, post_ctr) - ] + init_ctr = queue_counters[intf] - verify_ecn_marking_counters(ecn_counters, test_prio_list[0], intf) - finally: - # Iterate over the fabric egress port map and call set_cir_cisco_8000 - for asic_instance, intf_list in egress_asic_map.items(): - # Reset the shaper on the egress ports - set_cir_cisco_8000(dut, intf_list, asic_instance) + ecn_counters = [ + (init_ctr, post_ctr) + ] + verify_ecn_marking_counters(ecn_counters, test_prio_list[0], intf) +finally: + # Iterate over the fabric egress port map and call set_cir_cisco_8000 + for asic_instance, intf_list in egress_asic_map.items(): + # Reset the shaper on the egress ports + set_cir_cisco_8000(dut, intf_list, asic_instance) +``` def run_fabric_ecn_marking_test(api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - supervisor_dut, - snappi_extra_params=None): - - """ - Run a ECN test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priority of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - supervisor_dut (duthost): dutHost obj for supervisor in case of multi-DUT - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') - - traffic_paths = get_traffic_path(api, - testbed_config, port_config_list, - dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) - - # Get list of Fabric egress ports only - fabric_egress = [path[3] for path in traffic_paths] - - adjust_shaper_and_verify(supervisor_dut, fabric_egress, test_prio_list, api) - +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +supervisor_dut, +snappi_extra_params=None): + +``` +""" +Run a ECN test +Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priority of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + supervisor_dut (duthost): dutHost obj for supervisor in case of multi-DUT + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') + +traffic_paths = get_traffic_path(api, + testbed_config, port_config_list, + dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) + +# Get list of Fabric egress ports only +fabric_egress = [path[3] for path in traffic_paths] + +adjust_shaper_and_verify(supervisor_dut, fabric_egress, test_prio_list, api) +``` def run_backplane_ecn_marking_test( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - snappi_extra_params=None): - - """ - Run a ECN test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priority of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') - - traffic_paths = get_traffic_path(api, - testbed_config, port_config_list, - dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) - - # Get list of backplane egress ports only - backplane_egress = [path[1] for path in traffic_paths] - - tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost = tx_port['duthost'] - - adjust_shaper_and_verify(ingress_duthost, backplane_egress, test_prio_list, api) +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +snappi_extra_params=None): + +``` +""" +Run a ECN test +Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priority of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') + +traffic_paths = get_traffic_path(api, + testbed_config, port_config_list, + dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) + +# Get list of backplane egress ports only +backplane_egress = [path[1] for path in traffic_paths] + +tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost = tx_port['duthost'] + +adjust_shaper_and_verify(ingress_duthost, backplane_egress, test_prio_list, api) +``` From e13dbc526559a3de45210014a706682ad2e593aa Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 14 May 2025 15:52:12 -0700 Subject: [PATCH 06/17] Update ecnhelper.py fixed static analysis --- tests/snappi_tests/ecn/files/ecnhelper.py | 416 +++++++++++----------- 1 file changed, 210 insertions(+), 206 deletions(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index 1c70f3e41e3..fb3076657ff 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -3,17 +3,17 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ - fanout_graph_facts # noqa F401 +fanout_graph_facts # noqa F401 from tests.common.snappi_tests.snappi_helpers import get_dut_port_id from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector,\ - get_lossless_buffer_size, get_pg_dropped_packets,\ - stop_pfcwd, disable_packet_aging, sec_to_nanosec,\ - get_pfc_frame_count, packet_capture, config_capture_pkt,\ - traffic_flow_mode, calc_pfc_pause_flow_rate # noqa F401 +get_lossless_buffer_size, get_pg_dropped_packets,\ +stop_pfcwd, disable_packet_aging, sec_to_nanosec,\ +get_pfc_frame_count, packet_capture, config_capture_pkt,\ +traffic_flow_mode, calc_pfc_pause_flow_rate # noqa F401 from tests.common.snappi_tests.port import select_ports, select_tx_port # noqa F401 from tests.common.snappi_tests.snappi_helpers import wait_for_arp # noqa F401 from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows,\ - run_traffic +run_traffic from tests.snappi_tests.files.helper import get_npu_voq_queue_counters from tests.common.snappi_tests.snappi_test_params import SnappiTestParams @@ -22,218 +22,222 @@ DATA_FLOW_PKT_SIZE = 1024 DATA_FLOW_DURATION_SEC = 2 DATA_FLOW_DELAY_SEC = 1 -TEST_FLOW_NAME = ['Test Flow 3', 'Test Flow 4'] +TEST_FLOW_NAME = \['Test Flow 3', 'Test Flow 4'\] PAUSE_FLOW_NAME = 'Pause Storm' - def verify_ecn_counters(ecn_counters, link_state_toggled=False): - toggle_msg = " post link state toggle" if link_state_toggled else "" - # verify that each flow had packets - init_ctr_3, post_ctr_3 = ecn_counters[0] - init_ctr_4, post_ctr_4 = ecn_counters[1] - flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] - - pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment{}'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) +``` +toggle_msg = " post link state toggle" if link_state_toggled else "" +# verify that each flow had packets +init_ctr_3, post_ctr_3 = ecn_counters[0] +init_ctr_4, post_ctr_4 = ecn_counters[1] +flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] - flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] +pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment{}'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment{}'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) +flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] - flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] +pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment{}'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - pytest_assert(flow3_ecn > 0, - 'Must have ecn marked packets on flow 3{}'. - format(toggle_msg)) +flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] +flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - pytest_assert(flow4_ecn > 0, - 'Must have ecn marked packets on flow 4{}'. - format(toggle_msg)) +pytest_assert(flow3_ecn > 0, + 'Must have ecn marked packets on flow 3{}'. + format(toggle_msg)) +pytest_assert(flow4_ecn > 0, + 'Must have ecn marked packets on flow 4{}'. + format(toggle_msg)) +``` # line rate percent for TC 3, 4 from tx port a, b + # ecn counter is per TC, both TC has same dwrr weight -def run_ecn_test_cisco8000(api, - testbed_config, - port_config_list, - conn_data, - fanout_data, - duthost, - dut_port, - test_prio_list, - prio_dscp_map, - snappi_extra_params=None): - """ - Run a PFC test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - duthost (Ansible host instance): device under test - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - stop_pfcwd(duthost) - disable_packet_aging(duthost) - - init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - # Get the ID of the port to test - port_id = get_dut_port_id(dut_hostname=duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) - - pytest_assert(port_id is not None, - 'Fail to get ID for port {}'.format(dut_port)) - - # Generate base traffic config - base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] - base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - - # Generate test flow config - traffic_rate = 99.98 - test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) - - snappi_extra_params.base_flow_config = base_flow_config1 - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - - snappi_extra_params.base_flow_config = base_flow_config2 +def run_ecn_test_cisco8000(api, +testbed_config, +port_config_list, +conn_data, +fanout_data, +duthost, +dut_port, +test_prio_list, +prio_dscp_map, +snappi_extra_params=None): +""" +Run a PFC test +Args: +api (obj): snappi session +testbed_config (obj): testbed L1/L2/L3 configuration +port_config_list (list): list of port configuration +conn_data (dict): the dictionary returned by conn_graph_fact. +fanout_data (dict): the dictionary returned by fanout_graph_fact. +duthost (Ansible host instance): device under test +dut_port (str): DUT port to test +test_prio_list (list): priorities of test flows +prio_dscp_map (dict): Priority vs. DSCP map (key = priority). +snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +``` +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +stop_pfcwd(duthost) +disable_packet_aging(duthost) + +init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +# Get the ID of the port to test +port_id = get_dut_port_id(dut_hostname=duthost.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) + +pytest_assert(port_id is not None, + 'Fail to get ID for port {}'.format(dut_port)) + +# Generate base traffic config +base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) +port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] +base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list2, + port_id=port_id) + +# Generate test flow config +traffic_rate = 99.98 +test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) + +snappi_extra_params.base_flow_config = base_flow_config1 + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[1], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - - flows = testbed_config.flows - - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - - # Clear PFC and queue counters before traffic run - duthost.command("pfcstat -c") - duthost.command("sonic-clear queuecounters") - - """ Run traffic """ - _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - - post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) - ] - - verify_ecn_counters(ecn_counters) - - # Get the current configuration - config = api.get_config() - # Collect all port names - port_names = [port.name for port in config.ports] - # Create a control state object for all ports - cs = api.control_state() - # Create a control state object for all ports - cs.choice = cs.PORT - cs.port.choice = cs.port.LINK - # Apply the state to all ports - cs.link.port_names = port_names - # Set all ports down (shut) - cs.port.link.state = cs.port.link.DOWN - api.set_control_state(cs) - logger.info("All Snappi ports are set to DOWN") - time.sleep(0.2) - # Unshut all ports - cs.port.link.state = cs.port.link.UP - api.set_control_state(cs) - logger.info("All Snappi ports are set to UP") - - init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - """ Run traffic """ - _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - - post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) - ] - - verify_ecn_counters(ecn_counters, link_state_toggled=True) + "flow_name": TEST_FLOW_NAME[0], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=2) + +snappi_extra_params.base_flow_config = base_flow_config2 + +snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[1], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=2) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +# Clear PFC and queue counters before traffic run +duthost.command("pfcstat -c") +duthost.command("sonic-clear queuecounters") + +""" Run traffic """ +_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + +post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) +] + +verify_ecn_counters(ecn_counters) + +# Get the current configuration +config = api.get_config() +# Collect all port names +port_names = [port.name for port in config.ports] +# Create a control state object for all ports +cs = api.control_state() +# Create a control state object for all ports +cs.choice = cs.PORT +cs.port.choice = cs.port.LINK +# Apply the state to all ports +cs.link.port_names = port_names +# Set all ports down (shut) +cs.port.link.state = cs.port.link.DOWN +api.set_control_state(cs) +logger.info("All Snappi ports are set to DOWN") +time.sleep(0.2) +# Unshut all ports +cs.port.link.state = cs.port.link.UP +api.set_control_state(cs) +logger.info("All Snappi ports are set to UP") + +init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +""" Run traffic """ +_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + +post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) +] + +verify_ecn_counters(ecn_counters, link_state_toggled=True) +``` From 2a79a2f6c95f40653a53dd180e594eedcffbe3b5 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 14 May 2025 15:52:50 -0700 Subject: [PATCH 07/17] Update helper.py fixed static analysis --- tests/snappi_tests/ecn/files/helper.py | 1938 ++++++++++++------------ 1 file changed, 979 insertions(+), 959 deletions(-) diff --git a/tests/snappi_tests/ecn/files/helper.py b/tests/snappi_tests/ecn/files/helper.py index 2e36975eed4..104a222274c 100644 --- a/tests/snappi_tests/ecn/files/helper.py +++ b/tests/snappi_tests/ecn/files/helper.py @@ -5,15 +5,15 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts # noqa: F401 from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ - snappi_api # noqa: F401 +snappi_api # noqa: F401 from tests.common.snappi_tests.snappi_helpers import get_dut_port_id from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector, config_wred, \ - enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ - config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_pfc_frame_count # noqa: F401 +enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ +config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_pfc_frame_count # noqa: F401 from tests.common.snappi_tests.read_pcap import get_ipv4_pkts from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ - generate_pause_flows, run_traffic # noqa: F401 +generate_pause_flows, run_traffic # noqa: F401 import json from tests.snappi_tests.files.helper import get_fabric_mapping @@ -25,729 +25,903 @@ PAUSE_FLOW_NAME = 'Pause Storm' DATA_FLOW_NAME = 'Data Flow' - def get_npu_voq_queue_counters(duthost, interface, priority, clear=False): - asic_namespace_string = "" - if duthost.is_multi_asic: - asic = duthost.get_port_asic_instance(interface) - asic_namespace_string = " -n " + asic.namespace - - clear_cmd = "" - if clear: - clear_cmd = " -c" - - full_line = "".join(duthost.shell( - "show platform npu voq queue_counters -t {} -i {} -d{}{}". - format(priority, interface, asic_namespace_string, clear_cmd))['stdout_lines']) - dict_output = json.loads(full_line) - for entry, value in zip(dict_output['stats_name'], dict_output['counters']): - dict_output[entry] = value - - return dict_output - -# When bp_fabric_ecn_marking_check is True -# -# The traffic is flowing from short link to long link -# -# Step 1: Clear all counters on egress, fabric, and ingress DUT -# Step 2: Send traffic for the test. -# Step 3: Verify egress port queue counter at possible congestion points. -# Step 4: If no marking, -# - check and log backpressure -# - Fail the testcase - +``` +asic_namespace_string = "" +if duthost.is_multi_asic: + asic = duthost.get_port_asic_instance(interface) + asic_namespace_string = " -n " + asic.namespace -def clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): - """ - Clears VOQ queue counters of the ingress DUT BP ports and the Fabric ports connected to the Egress DUT. - """ - for priority in test_prio_list: - for fabric_egress_bp in egress_fabric_mapping.values(): - get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority, clear=True) +clear_cmd = "" +if clear: + clear_cmd = " -c" - for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): - for fabric_mapping in ingress_fabric_mappings.values(): - for lc_egress_bp in fabric_mapping.keys(): - get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority, clear=True) +full_line = "".join(duthost.shell( + "show platform npu voq queue_counters -t {} -i {} -d{}{}". + format(priority, interface, asic_namespace_string, clear_cmd))['stdout_lines']) +dict_output = json.loads(full_line) +for entry, value in zip(dict_output['stats_name'], dict_output['counters']): + dict_output[entry] = value - logger.info("Counters cleared for ingress DUT BP ports and Fabric Egress ports") +return dict_output +``` +# When bp_fabric_ecn_marking_check is True -def check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): - """ - Checks for ECN marked packets across ingress and egress fabric mappings. - Returns True if ECN marking is found, otherwise False. - """ +# - all_priorities_marked = True +# The traffic is flowing from short link to long link - for priority in test_prio_list: - ecn_marked_for_priority = False - - ecn_marked_packets_egress = 0 - for fabric_egress_bp in egress_fabric_mapping.values(): - ctr_egress = get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority) - ecn_marked_fb = ctr_egress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - ecn_marked_packets_egress += ecn_marked_fb - if ecn_marked_fb > 0: - logging.info("ECN marking : {} on Fabric interface: {}, priority: {}".format( - ecn_marked_fb, fabric_egress_bp, priority)) - ecn_marked_for_priority = True - - if ecn_marked_packets_egress: - logging.info("Total Fabric ECN marking detected: {} on priority: {} ".format( - ecn_marked_packets_egress, priority)) - - ecn_marked_packets_ingress = 0 - for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): - for fabric_mapping in ingress_fabric_mappings.values(): - for lc_egress_bp in fabric_mapping.keys(): - ctr_ingress = get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority) - ecn_marked_bp = ctr_ingress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - ecn_marked_packets_ingress += ecn_marked_bp - if ecn_marked_bp > 0: - logging.info("ECN marking : {} on ingress DUT {}, interface: {}, priority: {}".format( - ecn_marked_bp, ingress_duthost, lc_egress_bp, priority)) - ecn_marked_for_priority = True - - if ecn_marked_packets_ingress: - logging.info("Total Ingress BP ECN marking detected: {} on priority: {} ".format( - ecn_marked_packets_ingress, priority)) - - if not ecn_marked_for_priority: - all_priorities_marked = False - - if all_priorities_marked: - logger.info("ECN Marking detected for all priorities") - return True - else: - logger.info("ECN Marking missing for some priorities") - return False +# +# Step 1: Clear all counters on egress, fabric, and ingress DUT -def verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required=False, link_state_toggled=False): +# Step 2: Send traffic for the test. - toggle_msg = " post link state toggle" if link_state_toggled else "" - # verify that each flow had packets - init_ctr_3, post_ctr_3 = ecn_counters[0] - init_ctr_4, post_ctr_4 = ecn_counters[1] - flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] - flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] +# Step 3: Verify egress port queue counter at possible congestion points. - logging.info("Flow 3 total packets: {}, Flow 4 total packets: {}".format(flow3_total, flow4_total)) +# Step 4: If no marking, - pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment{}'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) +# - check and log backpressure - pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment{}'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) +# - Fail the testcase - flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] +def clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): +""" +Clears VOQ queue counters of the ingress DUT BP ports and the Fabric ports connected to the Egress DUT. +""" +for priority in test_prio_list: +for fabric_egress_bp in egress_fabric_mapping.values(): +get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority, clear=True) + +``` + for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): + for fabric_mapping in ingress_fabric_mappings.values(): + for lc_egress_bp in fabric_mapping.keys(): + get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority, clear=True) + +logger.info("Counters cleared for ingress DUT BP ports and Fabric Egress ports") +``` - if is_bp_fabric_ecn_check_required: - if flow3_ecn == 0: - logging.info("ECN marking check failed on flow 3 on egress port") - return False # Flow 3 ECN marking failed - elif flow4_ecn == 0: - logging.info("ECN marking check failed on flow 4 on egress port") - return False # Flow 4 ECN marking failed - else: - logging.info("ECN marking check passed on both flow 3 and 4 on egress port") - return True # Both flows had ECN marked packets (success) - - pytest_assert(flow3_ecn > 0, - 'Must have ecn marked packets on flow 3{}'. - format(toggle_msg)) - - pytest_assert(flow4_ecn > 0, - 'Must have ecn marked packets on flow 4{}'. - format(toggle_msg)) +def check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): +""" +Checks for ECN marked packets across ingress and egress fabric mappings. +Returns True if ECN marking is found, otherwise False. +""" + +``` +all_priorities_marked = True + +for priority in test_prio_list: + ecn_marked_for_priority = False + + ecn_marked_packets_egress = 0 + for fabric_egress_bp in egress_fabric_mapping.values(): + ctr_egress = get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority) + ecn_marked_fb = ctr_egress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + ecn_marked_packets_egress += ecn_marked_fb + if ecn_marked_fb > 0: + logging.info("ECN marking : {} on Fabric interface: {}, priority: {}".format( + ecn_marked_fb, fabric_egress_bp, priority)) + ecn_marked_for_priority = True + + if ecn_marked_packets_egress: + logging.info("Total Fabric ECN marking detected: {} on priority: {} ".format( + ecn_marked_packets_egress, priority)) + + ecn_marked_packets_ingress = 0 + for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): + for fabric_mapping in ingress_fabric_mappings.values(): + for lc_egress_bp in fabric_mapping.keys(): + ctr_ingress = get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority) + ecn_marked_bp = ctr_ingress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + ecn_marked_packets_ingress += ecn_marked_bp + if ecn_marked_bp > 0: + logging.info("ECN marking : {} on ingress DUT {}, interface: {}, priority: {}".format( + ecn_marked_bp, ingress_duthost, lc_egress_bp, priority)) + ecn_marked_for_priority = True + + if ecn_marked_packets_ingress: + logging.info("Total Ingress BP ECN marking detected: {} on priority: {} ".format( + ecn_marked_packets_ingress, priority)) + + if not ecn_marked_for_priority: + all_priorities_marked = False + +if all_priorities_marked: + logger.info("ECN Marking detected for all priorities") return True +else: + logger.info("ECN Marking missing for some priorities") + return False +``` +def verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required=False, link_state_toggled=False): -def verify_ecn_counters_for_flow_percent( - ecn_counters, - test_flow_percent, - number_of_streams, - input_port_same_asic, - input_port_same_dut, - single_dut): - - # verify that each flow had packets - init_ctr_3, post_ctr_3 = ecn_counters[0] - init_ctr_4, post_ctr_4 = ecn_counters[1] - flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] - - drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] - wred_drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] - - drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] - wred_drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] - - pytest_assert(drop_ctr_3 == 0 and wred_drop_ctr_3 == 0, 'Queue 3 Drop not expected') - - pytest_assert(drop_ctr_4 == 0 and wred_drop_ctr_4 == 0, 'Queue 4 Drop not expected') +``` +toggle_msg = " post link state toggle" if link_state_toggled else "" +# verify that each flow had packets +init_ctr_3, post_ctr_3 = ecn_counters[0] +init_ctr_4, post_ctr_4 = ecn_counters[1] +flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] +flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] + +logging.info("Flow 3 total packets: {}, Flow 4 total packets: {}".format(flow3_total, flow4_total)) + +pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment{}'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) + +pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment{}'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) + +flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] +flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + +if is_bp_fabric_ecn_check_required: + if flow3_ecn == 0: + logging.info("ECN marking check failed on flow 3 on egress port") + return False # Flow 3 ECN marking failed + elif flow4_ecn == 0: + logging.info("ECN marking check failed on flow 4 on egress port") + return False # Flow 4 ECN marking failed + else: + logging.info("ECN marking check passed on both flow 3 and 4 on egress port") + return True # Both flows had ECN marked packets (success) - pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'])) +pytest_assert(flow3_ecn > 0, + 'Must have ecn marked packets on flow 3{}'. + format(toggle_msg)) - flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] +pytest_assert(flow4_ecn > 0, + 'Must have ecn marked packets on flow 4{}'. + format(toggle_msg)) +return True +``` - pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'])) +def verify_ecn_counters_for_flow_percent( +ecn_counters, +test_flow_percent, +number_of_streams, +input_port_same_asic, +input_port_same_dut, +single_dut): + +``` +# verify that each flow had packets +init_ctr_3, post_ctr_3 = ecn_counters[0] +init_ctr_4, post_ctr_4 = ecn_counters[1] +flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] + +drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] +wred_drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] + +drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] +wred_drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] + +pytest_assert(drop_ctr_3 == 0 and wred_drop_ctr_3 == 0, 'Queue 3 Drop not expected') + +pytest_assert(drop_ctr_4 == 0 and wred_drop_ctr_4 == 0, 'Queue 4 Drop not expected') + +pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'])) + +flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] + +pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'])) + +flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] +flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + +if sum(test_flow_percent) < 100: + pytest_assert( + flow3_ecn == 0, + 'Must have no ecn marked packets on flow 3 without congestion, percent {}'. + format(test_flow_percent)) + pytest_assert( + flow4_ecn == 0, + 'Must have no ecn marked packets on flow 4 without congestion, percent {}'. + format(test_flow_percent)) +elif sum(test_flow_percent) >= 100: + if test_flow_percent[0] > 50: + pytest_assert( + flow3_ecn > 0, + 'Must have ecn marked packets on flow 3, percent {}'. + format(test_flow_percent)) - flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + if test_flow_percent[1] > 50: + pytest_assert( + flow4_ecn > 0, + 'Must have ecn marked packets on flow 4, percent {}'. + format(test_flow_percent)) - if sum(test_flow_percent) < 100: + if test_flow_percent[0] < 50: pytest_assert( flow3_ecn == 0, - 'Must have no ecn marked packets on flow 3 without congestion, percent {}'. + 'Must not have ecn marked packets on flow 3, percent {}'. format(test_flow_percent)) + + if test_flow_percent[1] < 50: pytest_assert( flow4_ecn == 0, - 'Must have no ecn marked packets on flow 4 without congestion, percent {}'. + 'Must not have ecn marked packets on flow 4, percent {}'. format(test_flow_percent)) - elif sum(test_flow_percent) >= 100: - if test_flow_percent[0] > 50: - pytest_assert( - flow3_ecn > 0, - 'Must have ecn marked packets on flow 3, percent {}'. - format(test_flow_percent)) - - if test_flow_percent[1] > 50: - pytest_assert( - flow4_ecn > 0, - 'Must have ecn marked packets on flow 4, percent {}'. - format(test_flow_percent)) - - if test_flow_percent[0] < 50: - pytest_assert( - flow3_ecn == 0, - 'Must not have ecn marked packets on flow 3, percent {}'. - format(test_flow_percent)) - if test_flow_percent[1] < 50: - pytest_assert( - flow4_ecn == 0, - 'Must not have ecn marked packets on flow 4, percent {}'. - format(test_flow_percent)) - - if test_flow_percent[0] > 50 and test_flow_percent[1] > 50: + if test_flow_percent[0] > 50 and test_flow_percent[1] > 50: + pytest_assert( + flow3_ecn > 0 and flow4_ecn > 0, + 'Must have ecn marked packets on flows 3, 4, percent {}'. + format(test_flow_percent)) + percent3_mark = round(float(flow3_ecn/flow3_total), 2) * 100 + percent4_mark = round(float(flow4_ecn/flow4_total), 2) * 100 + flow_mark_diff = int(abs(percent3_mark - percent4_mark)) + logging.info( + "Stream count {}, inputs on {} asic, inputs on {} dut, " + "flow 3 percent {}, ecn {}, flow 4 percent {}, ecn {}, " + "flow_mark_diff {}".format( + number_of_streams, + "same" if input_port_same_asic else "different", + "same" if input_port_same_dut else "different", + test_flow_percent[0], + flow3_ecn, + test_flow_percent[1], + flow4_ecn, + flow_mark_diff)) + if number_of_streams == 1 and input_port_same_asic and \ + (test_flow_percent[0] == test_flow_percent[1]): pytest_assert( - flow3_ecn > 0 and flow4_ecn > 0, - 'Must have ecn marked packets on flows 3, 4, percent {}'. - format(test_flow_percent)) - percent3_mark = round(float(flow3_ecn/flow3_total), 2) * 100 - percent4_mark = round(float(flow4_ecn/flow4_total), 2) * 100 - flow_mark_diff = int(abs(percent3_mark - percent4_mark)) - logging.info( - "Stream count {}, inputs on {} asic, inputs on {} dut, " - "flow 3 percent {}, ecn {}, flow 4 percent {}, ecn {}, " - "flow_mark_diff {}".format( - number_of_streams, - "same" if input_port_same_asic else "different", - "same" if input_port_same_dut else "different", - test_flow_percent[0], + flow_mark_diff <= 5, + "For flow rates {}: the flow marking deviation {} is more " + "than 5% tolerance: flow 3 ecn: {} flow 4 ecn: {}". + format( + test_flow_percent, + flow_mark_diff, flow3_ecn, - test_flow_percent[1], - flow4_ecn, - flow_mark_diff)) - if number_of_streams == 1 and input_port_same_asic and \ - (test_flow_percent[0] == test_flow_percent[1]): + flow4_ecn)) + # if number_of_streams > 1, the streams will be spread across voq from backplane ports with shallow + # occupancy. Restrict marking check to single dut in such a case (or relax marking check) + elif input_port_same_dut and (number_of_streams == 1 or (number_of_streams > 1 and single_dut)): + if test_flow_percent[0] > test_flow_percent[1]: pytest_assert( - flow_mark_diff <= 5, - "For flow rates {}: the flow marking deviation {} is more " - "than 5% tolerance: flow 3 ecn: {} flow 4 ecn: {}". - format( - test_flow_percent, - flow_mark_diff, + flow3_ecn > flow4_ecn, + "For flow percent {}, ecn count {} must be higher than " + "flow percent {}, ecn count {}".format( + test_flow_percent[0], flow3_ecn, + test_flow_percent[1], flow4_ecn)) - # if number_of_streams > 1, the streams will be spread across voq from backplane ports with shallow - # occupancy. Restrict marking check to single dut in such a case (or relax marking check) - elif input_port_same_dut and (number_of_streams == 1 or (number_of_streams > 1 and single_dut)): - if test_flow_percent[0] > test_flow_percent[1]: - pytest_assert( - flow3_ecn > flow4_ecn, - "For flow percent {}, ecn count {} must be higher than " - "flow percent {}, ecn count {}".format( - test_flow_percent[0], - flow3_ecn, - test_flow_percent[1], - flow4_ecn)) - elif test_flow_percent[0] < test_flow_percent[1]: - pytest_assert( - flow3_ecn < flow4_ecn, - "For flow percent {}, ecn count {} must be lower than flow percent {}, ecn count {}". - format(test_flow_percent[0], flow3_ecn, test_flow_percent[1], flow4_ecn)) - + elif test_flow_percent[0] < test_flow_percent[1]: + pytest_assert( + flow3_ecn < flow4_ecn, + "For flow percent {}, ecn count {} must be lower than flow percent {}, ecn count {}". + format(test_flow_percent[0], flow3_ecn, test_flow_percent[1], flow4_ecn)) +``` def run_ecn_test(api, - testbed_config, - port_config_list, - conn_data, - fanout_data, - dut_port, - lossless_prio, - prio_dscp_map, - iters, - snappi_extra_params=None): - """ - Run multidut ECN test - - Args: - api (obj): SNAPPI session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - lossless_prio (int): lossless priority - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - - Returns: - Return captured IP packets (list of list) - """ - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost = tx_port['duthost'] - - pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') - - logger.info("Stopping PFC watchdog") - stop_pfcwd(egress_duthost, rx_port['asic_value']) - stop_pfcwd(ingress_duthost, tx_port['asic_value']) - logger.info("Disabling packet aging if necessary") - disable_packet_aging(egress_duthost) - disable_packet_aging(ingress_duthost) - - # Configure WRED/ECN thresholds - logger.info("Configuring WRED and ECN thresholds") - config_result = config_wred(host_ans=egress_duthost, - kmin=snappi_extra_params.ecn_params["kmin"], - kmax=snappi_extra_params.ecn_params["kmax"], - pmax=snappi_extra_params.ecn_params["pmax"]) - pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') - config_result = config_wred(host_ans=ingress_duthost, - kmin=snappi_extra_params.ecn_params["kmin"], - kmax=snappi_extra_params.ecn_params["kmax"], - pmax=snappi_extra_params.ecn_params["pmax"]) - pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') - - # Enable ECN marking - logger.info("Enabling ECN markings") - pytest_assert(enable_ecn(host_ans=egress_duthost, prio=lossless_prio), 'Unable to enable ecn') - pytest_assert(enable_ecn(host_ans=ingress_duthost, prio=lossless_prio), 'Unable to enable ecn') - - config_result = config_ingress_lossless_buffer_alpha(host_ans=egress_duthost, - alpha_log2=3) - - pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') - config_result = config_ingress_lossless_buffer_alpha(host_ans=ingress_duthost, - alpha_log2=3) - - pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') - - # Get the ID of the port to test - port_id = get_dut_port_id(dut_hostname=egress_duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) - - pytest_assert(port_id is not None, - 'Failed to get ID for port {}'.format(dut_port)) - - speed_str = testbed_config.layer1[0].speed - speed_gbps = int(speed_str.split('_')[1]) - - # Generate base traffic config - port_id = 0 - logger.info("Generating base flow config") - snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - - logger.info("Setting test flow config params") - snappi_extra_params.traffic_flow_config.data_flow_config.update({ - "flow_name": DATA_FLOW_NAME, - "flow_rate_percent": 100, - "flow_delay_sec": DATA_START_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS - }) - - logger.info("Setting pause flow config params") - snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": EXP_DURATION_SEC, - "flow_rate_percent": None, - "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), +testbed_config, +port_config_list, +conn_data, +fanout_data, +dut_port, +lossless_prio, +prio_dscp_map, +iters, +snappi_extra_params=None): +""" +Run multidut ECN test + +``` +Args: + api (obj): SNAPPI session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + lossless_prio (int): lossless priority + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + +Returns: + Return captured IP packets (list of list) +""" + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] + +tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost = tx_port['duthost'] + +pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + +logger.info("Stopping PFC watchdog") +stop_pfcwd(egress_duthost, rx_port['asic_value']) +stop_pfcwd(ingress_duthost, tx_port['asic_value']) +logger.info("Disabling packet aging if necessary") +disable_packet_aging(egress_duthost) +disable_packet_aging(ingress_duthost) + +# Configure WRED/ECN thresholds +logger.info("Configuring WRED and ECN thresholds") +config_result = config_wred(host_ans=egress_duthost, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) +pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') +config_result = config_wred(host_ans=ingress_duthost, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) +pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + +# Enable ECN marking +logger.info("Enabling ECN markings") +pytest_assert(enable_ecn(host_ans=egress_duthost, prio=lossless_prio), 'Unable to enable ecn') +pytest_assert(enable_ecn(host_ans=ingress_duthost, prio=lossless_prio), 'Unable to enable ecn') + +config_result = config_ingress_lossless_buffer_alpha(host_ans=egress_duthost, + alpha_log2=3) + +pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') +config_result = config_ingress_lossless_buffer_alpha(host_ans=ingress_duthost, + alpha_log2=3) + +pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') + +# Get the ID of the port to test +port_id = get_dut_port_id(dut_hostname=egress_duthost.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) + +pytest_assert(port_id is not None, + 'Failed to get ID for port {}'.format(dut_port)) + +speed_str = testbed_config.layer1[0].speed +speed_gbps = int(speed_str.split('_')[1]) + +# Generate base traffic config +port_id = 0 +logger.info("Generating base flow config") +snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + +logger.info("Setting test flow config params") +snappi_extra_params.traffic_flow_config.data_flow_config.update({ + "flow_name": DATA_FLOW_NAME, + "flow_rate_percent": 100, + "flow_delay_sec": DATA_START_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS + }) + +logger.info("Setting pause flow config params") +snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": EXP_DURATION_SEC, + "flow_rate_percent": None, + "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": None, + "flow_delay_sec": 0, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +# Generate traffic config of one test flow and one pause storm +logger.info("Generating test flows") +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=[lossless_prio], + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=10) + +logger.info("Generating pause flows") +generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=[lossless_prio], + global_pause=False, + snappi_extra_params=snappi_extra_params) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +logger.info("Setting packet capture port to {}".format(testbed_config.ports[port_id].name)) +snappi_extra_params.packet_capture_ports = [testbed_config.ports[port_id].name] + +result = [] +logger.info("Running {} iteration(s)".format(iters)) +for i in range(iters): + logger.info("Running iteration {}".format(i)) + snappi_extra_params.packet_capture_file = "ECN_cap-{}".format(i) + logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) + + config_capture_pkt(testbed_config=testbed_config, + port_names=snappi_extra_params.packet_capture_ports, + capture_type=snappi_extra_params.packet_capture_type, + capture_name=snappi_extra_params.packet_capture_file) + + logger.info("Running traffic") + run_traffic(duthost=egress_duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=EXP_DURATION_SEC, + snappi_extra_params=snappi_extra_params) + + result.append(get_ipv4_pkts(snappi_extra_params.packet_capture_file + ".pcapng", protocol_num=17)) + +return result +``` + +def toggle_dut_port_state(api): +\# Get the current configuration +config = api.get_config() +\# Collect all port names +port_names = \[port.name for port in config.ports\] +\# Create a control state object for all ports +cs = api.control_state() +\# Create a control state object for all ports +cs.choice = cs.PORT +cs.port.choice = cs.port.LINK +\# Apply the state to all ports +cs.link.port_names = port_names +\# Set all ports down (shut) +cs.port.link.state = cs.port.link.DOWN +api.set_control_state(cs) +logger.info("All Snappi ports are set to DOWN") +time.sleep(0.2) +\# Unshut all ports +cs.port.link.state = cs.port.link.UP +api.set_control_state(cs) +logger.info("All Snappi ports are set to UP") + +def \_generate_traffic_config(testbed_config, +snappi_extra_params, +port_config_list, +test_prio_list, +test_flow_percent, +prio_dscp_map, +number_of_streams=10, +congested=False): +TEST_FLOW_NAME = \['Test Flow 3', 'Test Flow 4'\] +DATA_FLOW_PKT_SIZE = 1350 +DATA_FLOW_DURATION_SEC = 2 +DATA_FLOW_DELAY_SEC = 1 + +``` +port_id = 0 +# Generate base traffic config +base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) +port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] +base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list2, + port_id=port_id) + +# Create a dictionary with priorities as keys and flow rates as values +flow_rate_dict = { + prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) +} + +snappi_extra_params.base_flow_config = base_flow_config1 + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[0], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, "flow_rate_bps": None, - "flow_pkt_size": 64, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, "flow_pkt_count": None, - "flow_delay_sec": 0, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } + } - # Generate traffic config of one test flow and one pause storm - logger.info("Generating test flows") - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=[lossless_prio], - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=10) +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=10) - logger.info("Generating pause flows") - generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=[lossless_prio], - global_pause=False, - snappi_extra_params=snappi_extra_params) +snappi_extra_params.base_flow_config = base_flow_config2 - flows = testbed_config.flows +snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[1], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=10) +``` - logger.info("Setting packet capture port to {}".format(testbed_config.ports[port_id].name)) - snappi_extra_params.packet_capture_ports = [testbed_config.ports[port_id].name] - - result = [] - logger.info("Running {} iteration(s)".format(iters)) - for i in range(iters): - logger.info("Running iteration {}".format(i)) - snappi_extra_params.packet_capture_file = "ECN_cap-{}".format(i) - logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) - - config_capture_pkt(testbed_config=testbed_config, - port_names=snappi_extra_params.packet_capture_ports, - capture_type=snappi_extra_params.packet_capture_type, - capture_name=snappi_extra_params.packet_capture_file) - - logger.info("Running traffic") - run_traffic(duthost=egress_duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=EXP_DURATION_SEC, - snappi_extra_params=snappi_extra_params) +def run_ecn_marking_port_toggle_test( +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +supervisor_dut=None, +is_bp_fabric_ecn_check_required=False, +snappi_extra_params=None): + +``` +""" +Run a ECN test +Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + supervisor_dut (obj): Supervisor DUT, if ECN check is required + is_bp_fabric_ecn_check_required (bool): Flag to indicate if BP fabric ECN check is required + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + +test_flow_percent = [99.98] * len(test_prio_list) + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +DATA_FLOW_DURATION_SEC = 2 +DATA_FLOW_DELAY_SEC = 1 + +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] + +duthost = egress_duthost + +tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost_1 = tx_port_1['duthost'] + +tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost_2 = tx_port_2['duthost'] + +# Append the duthost here for run_traffic to clear its counters +snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) +snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) +snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) + +# Find fabric mapping per ASIC instance +ingress_fabric_mapping_dict = {} +for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) + fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) + ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping + +egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) +egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) + +_generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +link_state_toggled = False + +# Function to clear ECN counters +def clear_ecn_counters(): + if is_bp_fabric_ecn_check_required: + snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) + clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list) - result.append(get_ipv4_pkts(snappi_extra_params.packet_capture_file + ".pcapng", protocol_num=17)) + for priority in test_prio_list: + get_npu_voq_queue_counters(duthost, dut_port, priority, True) - return result +# Function to run traffic and check ECN marking +def run_traffic_and_check_ecn(): + """Run traffic and verify ECN marking""" + initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + run_traffic( + duthost, api=api, config=testbed_config, data_flow_names=data_flow_names, + all_flow_names=all_flow_names, exp_dur_sec=DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params + ) -def toggle_dut_port_state(api): - # Get the current configuration - config = api.get_config() - # Collect all port names - port_names = [port.name for port in config.ports] - # Create a control state object for all ports - cs = api.control_state() - # Create a control state object for all ports - cs.choice = cs.PORT - cs.port.choice = cs.port.LINK - # Apply the state to all ports - cs.link.port_names = port_names - # Set all ports down (shut) - cs.port.link.state = cs.port.link.DOWN - api.set_control_state(cs) - logger.info("All Snappi ports are set to DOWN") - time.sleep(0.2) - # Unshut all ports - cs.port.link.state = cs.port.link.UP - api.set_control_state(cs) - logger.info("All Snappi ports are set to UP") - -def _generate_traffic_config(testbed_config, - snappi_extra_params, - port_config_list, - test_prio_list, - test_flow_percent, - prio_dscp_map, - number_of_streams=10, - congested=False): - TEST_FLOW_NAME = ['Test Flow 3', 'Test Flow 4'] - DATA_FLOW_PKT_SIZE = 1350 - DATA_FLOW_DURATION_SEC = 2 - DATA_FLOW_DELAY_SEC = 1 - - port_id = 0 - # Generate base traffic config - base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] - base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - - # Create a dictionary with priorities as keys and flow rates as values - flow_rate_dict = { - prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) - } + post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] - snappi_extra_params.base_flow_config = base_flow_config1 - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=10) - - snappi_extra_params.base_flow_config = base_flow_config2 + return verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required, link_state_toggled) - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[1], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=10) +def check_ecn_marking(): + """Check ECN marking before or after port toggle""" + clear_ecn_counters() + ecn_marking_verified_on_egress = run_traffic_and_check_ecn() + if not ecn_marking_verified_on_egress: + if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list): + # Log PFC frame counts + for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + for priority in test_prio_list: + pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) + logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( + dut.hostname, tx_port['peer_port'], priority, pfc_count)) + pytest_assert(False, "No ECN marking in the data path") -def run_ecn_marking_port_toggle_test( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - supervisor_dut=None, - is_bp_fabric_ecn_check_required=False, - snappi_extra_params=None): - - """ - Run a ECN test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - supervisor_dut (obj): Supervisor DUT, if ECN check is required - is_bp_fabric_ecn_check_required (bool): Flag to indicate if BP fabric ECN check is required - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - - test_flow_percent = [99.98] * len(test_prio_list) - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - DATA_FLOW_DURATION_SEC = 2 - DATA_FLOW_DELAY_SEC = 1 - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - duthost = egress_duthost - - tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost_1 = tx_port_1['duthost'] - - tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost_2 = tx_port_2['duthost'] - - # Append the duthost here for run_traffic to clear its counters - snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) - snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) - snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) - - # Find fabric mapping per ASIC instance - ingress_fabric_mapping_dict = {} - for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) - fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) - ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping - - egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) - egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) - - _generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map) +# Initial ECN verification +check_ecn_marking() - flows = testbed_config.flows +# Toggle port state +toggle_dut_port_state(api) - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] +link_state_toggled = True - link_state_toggled = False +# Post toggle ECN verification +check_ecn_marking() +``` - # Function to clear ECN counters - def clear_ecn_counters(): - if is_bp_fabric_ecn_check_required: - snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) - clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list) +def run_ecn_marking_test(api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +test_flow_percent, +number_of_streams, +input_port_same_asic, +input_port_same_dut, +single_dut, +snappi_extra_params=None): + +``` +""" +Run a ECN test +Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + +pytest_assert(len(test_flow_percent) == len(test_prio_list), + "The length of test_flow_percent must match the length of test_prio_list") + +DATA_FLOW_DURATION_SEC = 2 +DATA_FLOW_DELAY_SEC = 1 + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] + +duthost = egress_duthost + +init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +_generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map, + number_of_streams=number_of_streams) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +""" Run traffic """ +_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + +post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) +] + +verify_ecn_counters_for_flow_percent( + ecn_counters, + test_flow_percent, + number_of_streams, + input_port_same_asic, + input_port_same_dut, + single_dut) +``` - for priority in test_prio_list: - get_npu_voq_queue_counters(duthost, dut_port, priority, True) +def run_ecn_marking_with_pfc_quanta_variance( +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +test_ecn_config, +log_dir=None, +snappi_extra_params=None): - # Function to run traffic and check ECN marking - def run_traffic_and_check_ecn(): - """Run traffic and verify ECN marking""" - initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} +``` +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 1, 'Must have atleast two lossless priorities') - run_traffic( - duthost, api=api, config=testbed_config, data_flow_names=data_flow_names, - all_flow_names=all_flow_names, exp_dur_sec=DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params - ) +DATA_FLOW_PKT_SIZE = 1350 +DATA_FLOW_DURATION_SEC = 5 +DATA_FLOW_DELAY_SEC = 0 - post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} - ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() - return verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required, link_state_toggled) +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - def check_ecn_marking(): - """Check ECN marking before or after port toggle""" - clear_ecn_counters() - ecn_marking_verified_on_egress = run_traffic_and_check_ecn() +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] - if not ecn_marking_verified_on_egress: - if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list): - # Log PFC frame counts - for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - for priority in test_prio_list: - pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) - logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( - dut.hostname, tx_port['peer_port'], priority, pfc_count)) - pytest_assert(False, "No ECN marking in the data path") +duthost = egress_duthost - # Initial ECN verification - check_ecn_marking() +port_id = 0 +# Generate base traffic config +base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) - # Toggle port state - toggle_dut_port_state(api) +snappi_extra_params.base_flow_config = base_flow_config - link_state_toggled = True +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": DATA_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": 50, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } - # Post toggle ECN verification - check_ecn_marking() +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=[test_prio_list[0]], + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) +PAUSE_FLOW_NAME = "Pause flow" -def run_ecn_marking_test(api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - test_flow_percent, - number_of_streams, - input_port_same_asic, - input_port_same_dut, - single_dut, - snappi_extra_params=None): - - """ - Run a ECN test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - - pytest_assert(len(test_flow_percent) == len(test_prio_list), - "The length of test_flow_percent must match the length of test_prio_list") - - DATA_FLOW_DURATION_SEC = 2 - DATA_FLOW_DELAY_SEC = 1 - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - duthost = egress_duthost - - init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - _generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map, - number_of_streams=number_of_streams) +# 10 PFC frames at 2 frames/sec. +# The pauses caused by each PFC frame do not overlap. + +PAUSE_FLOW_PKT_COUNT = 10 +PAUSE_FLOW_DELAY_SEC = 1 + +if snappi_extra_params.traffic_flow_config.pause_flow_config is None: + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": None, + "flow_rate_percent": None, + "flow_rate_pps": 2, + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": PAUSE_FLOW_PKT_COUNT, + "flow_delay_sec": PAUSE_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS + } + +asic_namespace = None +if duthost.is_multi_asic: + asic = duthost.get_port_asic_instance(dut_port) + asic_namespace = asic.namespace +gmin, gmax, gdrop = test_ecn_config + +# Configure WRED/ECN thresholds +logger.info("Configuring WRED and ECN thresholds gmin {}MB gmax {}MB gdrop {}%".format(gmin, gmax, gdrop)) + +config_result = config_wred(host_ans=duthost, + kmin=gmin * 1024 * 1024, + kmax=gmax * 1024 * 1024, + pmax=0, + kdrop=gdrop, + asic_value=asic_namespace) + +pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + +start_quanta = 500 +end_quanta = 65000 +n = 15 # Number of quanta values + +step = (end_quanta - start_quanta) // (n - 1) +# Generate all but the last value +pause_quanta_list = [start_quanta + i * step for i in range(n - 1)] +# The last value is exactly `end_quanta` +pause_quanta_list.append(end_quanta) + +logging.info("PFC quanta list: {}".format(pause_quanta_list)) + +_ = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0], True) +results = [] +for quanta in pause_quanta_list: + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_quanta"] = quanta + + # Remove any existing pause flow + for index, flow in enumerate(testbed_config.flows): + if PAUSE_FLOW_NAME in flow.name: + testbed_config.flows.remove(index) + + # Generate pause flow config + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=[test_prio_list[0]], + global_pause=False, + snappi_extra_params=snappi_extra_params) flows = testbed_config.flows @@ -765,313 +939,159 @@ def run_ecn_marking_test(api, DATA_FLOW_DELAY_SEC, snappi_extra_params=snappi_extra_params) - post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) - ] - - verify_ecn_counters_for_flow_percent( - ecn_counters, - test_flow_percent, - number_of_streams, - input_port_same_asic, - input_port_same_dut, - single_dut) - - -def run_ecn_marking_with_pfc_quanta_variance( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - test_ecn_config, - log_dir=None, - snappi_extra_params=None): - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 1, 'Must have atleast two lossless priorities') - - DATA_FLOW_PKT_SIZE = 1350 - DATA_FLOW_DURATION_SEC = 5 - DATA_FLOW_DELAY_SEC = 0 - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - duthost = egress_duthost - - port_id = 0 - # Generate base traffic config - base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - - snappi_extra_params.base_flow_config = base_flow_config - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": DATA_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": 50, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=[test_prio_list[0]], - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) - - PAUSE_FLOW_NAME = "Pause flow" - - # 10 PFC frames at 2 frames/sec. - # The pauses caused by each PFC frame do not overlap. - - PAUSE_FLOW_PKT_COUNT = 10 - PAUSE_FLOW_DELAY_SEC = 1 - - if snappi_extra_params.traffic_flow_config.pause_flow_config is None: - snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": None, - "flow_rate_percent": None, - "flow_rate_pps": 2, - "flow_rate_bps": None, - "flow_pkt_size": 64, - "flow_pkt_count": PAUSE_FLOW_PKT_COUNT, - "flow_delay_sec": PAUSE_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS - } - - asic_namespace = None - if duthost.is_multi_asic: - asic = duthost.get_port_asic_instance(dut_port) - asic_namespace = asic.namespace - gmin, gmax, gdrop = test_ecn_config - - # Configure WRED/ECN thresholds - logger.info("Configuring WRED and ECN thresholds gmin {}MB gmax {}MB gdrop {}%".format(gmin, gmax, gdrop)) - - config_result = config_wred(host_ans=duthost, - kmin=gmin * 1024 * 1024, - kmax=gmax * 1024 * 1024, - pmax=0, - kdrop=gdrop, - asic_value=asic_namespace) - - pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') - - start_quanta = 500 - end_quanta = 65000 - n = 15 # Number of quanta values - - step = (end_quanta - start_quanta) // (n - 1) - # Generate all but the last value - pause_quanta_list = [start_quanta + i * step for i in range(n - 1)] - # The last value is exactly `end_quanta` - pause_quanta_list.append(end_quanta) - - logging.info("PFC quanta list: {}".format(pause_quanta_list)) - - _ = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0], True) - results = [] - for quanta in pause_quanta_list: - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_quanta"] = quanta - - # Remove any existing pause flow - for index, flow in enumerate(testbed_config.flows): - if PAUSE_FLOW_NAME in flow.name: - testbed_config.flows.remove(index) - - # Generate pause flow config - generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=[test_prio_list[0]], - global_pause=False, - snappi_extra_params=snappi_extra_params) - - flows = testbed_config.flows - - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - - """ Run traffic """ - _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - - ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - stats_only = {key: ctr_3[key] for key in ctr_3['stats_name']} - results.append((quanta, stats_only)) - - file_name = "xoff_quanta_variance_results_{}_{}_{}.csv".format(gmin, gmax, gdrop) - if log_dir: - file_name = os.path.join(log_dir, file_name) - - with open(file_name, 'w', newline='') as csvfile: - if results: - first_ctr = results[0][1] - fieldnames = ['quanta'] + list(first_ctr.keys()) + ['AVERAGE_ECN_MARKING'] - - writer = csv.DictWriter(csvfile, fieldnames=fieldnames) - writer.writeheader() - - prev_ecn_marked = 0 - for quanta, ctr in results: - row = {'quanta': quanta} - row.update(ctr) - current_ecn_marked = ctr.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - average_ecn_marking = round((current_ecn_marked - prev_ecn_marked) / PAUSE_FLOW_PKT_COUNT) - row['AVERAGE_ECN_MARKING'] = average_ecn_marking - prev_ecn_marked = current_ecn_marked - writer.writerow(row) - - for i in range(len(results) - 1): - ecn_i = results[i][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - ecn_i_plus_1 = results[i + 1][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - - if ecn_i > 0: - pytest_assert(ecn_i_plus_1 > ecn_i, - "ecn marked {} at quanta {} should be less than ecn marked {} at quanta {}". - format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) - else: - pytest_assert(ecn_i_plus_1 >= ecn_i, - "ecn marked {} at quanta {} should not be greater than ecn marked {} at quanta {}". - format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) - + ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + stats_only = {key: ctr_3[key] for key in ctr_3['stats_name']} + results.append((quanta, stats_only)) + +file_name = "xoff_quanta_variance_results_{}_{}_{}.csv".format(gmin, gmax, gdrop) +if log_dir: + file_name = os.path.join(log_dir, file_name) + +with open(file_name, 'w', newline='') as csvfile: + if results: + first_ctr = results[0][1] + fieldnames = ['quanta'] + list(first_ctr.keys()) + ['AVERAGE_ECN_MARKING'] + + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + prev_ecn_marked = 0 + for quanta, ctr in results: + row = {'quanta': quanta} + row.update(ctr) + current_ecn_marked = ctr.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + average_ecn_marking = round((current_ecn_marked - prev_ecn_marked) / PAUSE_FLOW_PKT_COUNT) + row['AVERAGE_ECN_MARKING'] = average_ecn_marking + prev_ecn_marked = current_ecn_marked + writer.writerow(row) + +for i in range(len(results) - 1): + ecn_i = results[i][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + ecn_i_plus_1 = results[i + 1][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + + if ecn_i > 0: + pytest_assert(ecn_i_plus_1 > ecn_i, + "ecn marked {} at quanta {} should be less than ecn marked {} at quanta {}". + format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) + else: + pytest_assert(ecn_i_plus_1 >= ecn_i, + "ecn marked {} at quanta {} should not be greater than ecn marked {} at quanta {}". + format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) +``` def run_ecn_marking_ect_marked_pkts( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - supervisor_dut=None, - is_bp_fabric_ecn_check_required=False, - snappi_extra_params=None): - - """ - Run a ECN test on congestion marker pkts - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - - test_flow_percent = [99.98] * len(test_prio_list) - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - DATA_FLOW_DURATION_SEC = 2 - DATA_FLOW_DELAY_SEC = 1 - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - duthost = egress_duthost - - tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost_1 = tx_port_1['duthost'] - - tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost_2 = tx_port_2['duthost'] - - # Append the duthost here for run_traffic to clear its counters - snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) - snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) - snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) - - # Find fabric mapping per ASIC instance - ingress_fabric_mapping_dict = {} - for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) - fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) - ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping - - egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) - egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +supervisor_dut=None, +is_bp_fabric_ecn_check_required=False, +snappi_extra_params=None): + +``` +""" +Run a ECN test on congestion marker pkts +Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + +test_flow_percent = [99.98] * len(test_prio_list) + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +DATA_FLOW_DURATION_SEC = 2 +DATA_FLOW_DELAY_SEC = 1 + +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +egress_duthost = rx_port['duthost'] +duthost = egress_duthost + +tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost_1 = tx_port_1['duthost'] + +tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] +ingress_duthost_2 = tx_port_2['duthost'] + +# Append the duthost here for run_traffic to clear its counters +snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) +snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) +snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) + +# Find fabric mapping per ASIC instance +ingress_fabric_mapping_dict = {} +for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) + fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) + ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping + +egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) +egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) + +if is_bp_fabric_ecn_check_required: + snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) + clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, + egress_fabric_mapping, supervisor_dut, test_prio_list) - if is_bp_fabric_ecn_check_required: - snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) - clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, - egress_fabric_mapping, supervisor_dut, test_prio_list) - - for priority in test_prio_list: - get_npu_voq_queue_counters(duthost, dut_port, priority, True) - - initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} - - _generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map, - congested=True) - - flows = testbed_config.flows - - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - - """ Run traffic """ - _, _, _ = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) + for priority in test_prio_list: + get_npu_voq_queue_counters(duthost, dut_port, priority, True) + +initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + +_generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map, + congested=True) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +""" Run traffic """ +_, _, _ = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) - post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} - ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] +post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} +ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] - ecn_marking_verified_on_egress = verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required) - if not ecn_marking_verified_on_egress: - if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list): - # Log PFC frame counts - for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - for priority in test_prio_list: - pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) - logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( - dut.hostname, tx_port['peer_port'], priority, pfc_count)) +ecn_marking_verified_on_egress = verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required) +if not ecn_marking_verified_on_egress: + if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list): + # Log PFC frame counts + for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + for priority in test_prio_list: + pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) + logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( + dut.hostname, tx_port['peer_port'], priority, pfc_count)) - pytest_assert(False, "No ECN marking in the data path") + pytest_assert(False, "No ECN marking in the data path") +``` From 0db563fd1633be03b476e8e6c24665a90bc8ead1 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 14 May 2025 15:53:26 -0700 Subject: [PATCH 08/17] Update helper.py fixed static analysis --- tests/snappi_tests/pfc/files/helper.py | 807 +++++++++++++------------ 1 file changed, 404 insertions(+), 403 deletions(-) diff --git a/tests/snappi_tests/pfc/files/helper.py b/tests/snappi_tests/pfc/files/helper.py index 8c170f211d8..c5dd02500c0 100644 --- a/tests/snappi_tests/pfc/files/helper.py +++ b/tests/snappi_tests/pfc/files/helper.py @@ -4,26 +4,25 @@ from tests.common.cisco_data import is_cisco_device from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ - fanout_graph_facts # noqa F401 +fanout_graph_facts # noqa F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector,\ - get_lossless_buffer_size, get_pg_dropped_packets,\ - disable_packet_aging, enable_packet_aging, sec_to_nanosec,\ - get_pfc_frame_count, packet_capture, config_capture_pkt,\ - traffic_flow_mode, calc_pfc_pause_flow_rate, get_tx_frame_count # noqa F401 +get_lossless_buffer_size, get_pg_dropped_packets,\ +disable_packet_aging, enable_packet_aging, sec_to_nanosec,\ +get_pfc_frame_count, packet_capture, config_capture_pkt,\ +traffic_flow_mode, calc_pfc_pause_flow_rate, get_tx_frame_count # noqa F401 from tests.common.snappi_tests.port import select_ports, select_tx_port # noqa F401 from tests.common.snappi_tests.snappi_helpers import get_dut_port_id, wait_for_arp # noqa F401 from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ - generate_background_flows, generate_pause_flows, run_traffic, verify_pause_flow, verify_basic_test_flow, \ - verify_background_flow, verify_pause_frame_count_dut, verify_egress_queue_frame_count, \ - verify_in_flight_buffer_pkts, verify_unset_cev_pause_frame_count, verify_tx_frame_count_dut, \ - verify_rx_frame_count_dut +generate_background_flows, generate_pause_flows, run_traffic, verify_pause_flow, verify_basic_test_flow, \ +verify_background_flow, verify_pause_frame_count_dut, verify_egress_queue_frame_count, \ +verify_in_flight_buffer_pkts, verify_unset_cev_pause_frame_count, verify_tx_frame_count_dut, \ +verify_rx_frame_count_dut from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.read_pcap import validate_pfc_frame, validate_pfc_frame_cisco - logger = logging.getLogger(__name__) -dut_port_config = [] +dut_port_config = \[\] PAUSE_FLOW_NAME = 'Pause Storm' TEST_FLOW_NAME = 'Test Flow' TEST_FLOW_AGGR_RATE_PERCENT = 45 @@ -38,406 +37,408 @@ CONTINUOUS_MODE = -5 ANSIBLE_POLL_DELAY_SEC = 4 - def run_pfc_test(api, - testbed_config, - port_config_list, - conn_data, - fanout_data, - global_pause, - pause_prio_list, - test_prio_list, - bg_prio_list, - prio_dscp_map, - test_traffic_pause, - duthost=None, - dut_port=None, - test_flow_is_lossless=True, - snappi_extra_params=None, - flow_factor=1): - """ - Run a multidut PFC test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - duthost (Ansible host instance): device under test - dut_port (str): DUT port to test - global_pause (bool): if pause frame is IEEE 802.3X pause - pause_prio_list (list): priorities to pause for pause frames - test_prio_list (list): priorities of test flows - bg_prio_list (list): priorities of background flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - test_traffic_pause (bool): if test flows are expected to be paused - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - # Traffic flow: - # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - - # initialize the (duthost, port) set. - - rx_port = {} - egress_duthost = duthost - - tx_port = {} - ingress_duthost = duthost - - if not duthost: - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost = tx_port['duthost'] - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - - global DATA_FLOW_DURATION_SEC - global data_flow_delay_sec - - # Port id of Rx port for traffic config - port_id = 0 - - if dut_port and duthost: - port_id = get_dut_port_id(dut_hostname=duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) - - # Rate percent must be an integer - bg_flow_rate_percent = int((BG_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(bg_prio_list)) - test_flow_rate_percent = int((TEST_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(test_prio_list)) - - # Generate base traffic config - snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - - speed_str = testbed_config.layer1[0].speed - speed_gbps = int(float(speed_str.split('_')[1])) - - if snappi_extra_params.headroom_test_params is not None: - DATA_FLOW_DURATION_SEC += 10 - data_flow_delay_sec += 2 - - # Set up pfc delay parameter - l1_config = testbed_config.layer1[0] - pfc = l1_config.flow_control.ieee_802_1qbb - pfc.pfc_delay = snappi_extra_params.headroom_test_params[0] - - if snappi_extra_params.poll_device_runtime: - # If the switch needs to be polled as traffic is running for stats, - # then the test runtime needs to be increased for the polling delay - DATA_FLOW_DURATION_SEC += ANSIBLE_POLL_DELAY_SEC - data_flow_delay_sec = ANSIBLE_POLL_DELAY_SEC - - if snappi_extra_params.packet_capture_type != packet_capture.NO_CAPTURE: - # Setup capture config - if snappi_extra_params.is_snappi_ingress_port_cap: - # packet capture is required on the ingress snappi port - snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["rx_port_name"]] - else: - # packet capture will be on the egress snappi port - snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["tx_port_name"]] - - snappi_extra_params.packet_capture_file = snappi_extra_params.packet_capture_type.value - - config_capture_pkt(testbed_config=testbed_config, - port_names=snappi_extra_params.packet_capture_ports, - capture_type=snappi_extra_params.packet_capture_type, - capture_name=snappi_extra_params.packet_capture_file) - logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - if snappi_extra_params.traffic_flow_config.background_flow_config is None and \ - snappi_extra_params.gen_background_traffic: - snappi_extra_params.traffic_flow_config.background_flow_config = { - "flow_name": BG_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": bg_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - if snappi_extra_params.traffic_flow_config.pause_flow_config is None: - snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": None, - "flow_rate_percent": None, - "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), - "flow_rate_bps": None, - "flow_pkt_size": 64, - "flow_pkt_count": None, - "flow_delay_sec": 0, - "flow_traffic_type": traffic_flow_mode.CONTINUOUS - } - - if snappi_extra_params.packet_capture_type == packet_capture.PFC_CAPTURE: - # PFC pause frame capture is requested - valid_pfc_frame_test = True - else: - # PFC pause frame capture is not requested - valid_pfc_frame_test = False - - if valid_pfc_frame_test and not is_cisco_device(egress_duthost): - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_dur_sec"] = DATA_FLOW_DURATION_SEC + \ - data_flow_delay_sec + SNAPPI_POLL_DELAY_SEC + PAUSE_FLOW_DUR_BASE_SEC - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_traffic_type"] = \ - traffic_flow_mode.FIXED_DURATION - - no_of_streams = 1 - if egress_duthost.facts['asic_type'] == "cisco-8000": - if not test_flow_is_lossless: - no_of_streams = 6 - - # Generate test flow config - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - number_of_streams=no_of_streams, - snappi_extra_params=snappi_extra_params) - - if snappi_extra_params.gen_background_traffic: - # Generate background flow config - generate_background_flows(testbed_config=testbed_config, - bg_flow_prio_list=bg_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) - - # Generate pause storm config - generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=pause_prio_list, - global_pause=global_pause, - snappi_extra_params=snappi_extra_params) - - flows = testbed_config.flows - - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - - # Clear PFC, queue and interface counters before traffic run - duthost = egress_duthost - - for dut in [egress_duthost, ingress_duthost]: - dut.command("pfcstat -c") - time.sleep(1) - dut.command("sonic-clear queuecounters") - time.sleep(1) - dut.command("sonic-clear counters") - time.sleep(1) - - """ Run traffic """ - tgen_flow_stats, switch_flow_stats, in_flight_flow_metrics = run_traffic(duthost=duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - data_flow_delay_sec, - snappi_extra_params=snappi_extra_params) - - # Reset pfc delay parameter - pfc = testbed_config.layer1[0].flow_control.ieee_802_1qbb - pfc.pfc_delay = 0 - - # Verify PFC pause frames - if valid_pfc_frame_test: - if not is_cisco_device(duthost): - is_valid_pfc_frame, error_msg = validate_pfc_frame(snappi_extra_params.packet_capture_file + ".pcapng") - else: - is_valid_pfc_frame, error_msg = validate_pfc_frame_cisco( - snappi_extra_params.packet_capture_file + ".pcapng") - pytest_assert(is_valid_pfc_frame, error_msg) - return - - # Verify pause flows - verify_pause_flow(flow_metrics=tgen_flow_stats, - pause_flow_name=PAUSE_FLOW_NAME) - - if snappi_extra_params.gen_background_traffic: - # Verify background flows - verify_background_flow(flow_metrics=tgen_flow_stats, - speed_gbps=speed_gbps, - tolerance=TOLERANCE_THRESHOLD, - snappi_extra_params=snappi_extra_params) - - # Verify basic test flows metrics from ixia - verify_basic_test_flow(flow_metrics=tgen_flow_stats, - speed_gbps=speed_gbps, - tolerance=TOLERANCE_THRESHOLD, - test_flow_pause=test_traffic_pause, - snappi_extra_params=snappi_extra_params) +testbed_config, +port_config_list, +conn_data, +fanout_data, +global_pause, +pause_prio_list, +test_prio_list, +bg_prio_list, +prio_dscp_map, +test_traffic_pause, +duthost=None, +dut_port=None, +test_flow_is_lossless=True, +snappi_extra_params=None, +flow_factor=1): +""" +Run a multidut PFC test +Args: +api (obj): snappi session +testbed_config (obj): testbed L1/L2/L3 configuration +port_config_list (list): list of port configuration +conn_data (dict): the dictionary returned by conn_graph_fact. +fanout_data (dict): the dictionary returned by fanout_graph_fact. +duthost (Ansible host instance): device under test +dut_port (str): DUT port to test +global_pause (bool): if pause frame is IEEE 802.3X pause +pause_prio_list (list): priorities to pause for pause frames +test_prio_list (list): priorities of test flows +bg_prio_list (list): priorities of background flows +prio_dscp_map (dict): Priority vs. DSCP map (key = priority). +test_traffic_pause (bool): if test flows are expected to be paused +snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +``` +Returns: + N/A +""" + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +# Traffic flow: +# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + +# initialize the (duthost, port) set. + +rx_port = {} +egress_duthost = duthost + +tx_port = {} +ingress_duthost = duthost + +if not duthost: + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] - # Verify PFC pause frame count on the DUT - verify_pause_frame_count_dut(rx_dut=ingress_duthost, - tx_dut=egress_duthost, - test_traffic_pause=test_traffic_pause, - global_pause=global_pause, - snappi_extra_params=snappi_extra_params) - - # Verify in flight TX lossless packets do not leave the DUT when traffic is expected - # to be paused, or leave the DUT when the traffic is not expected to be paused - # Verifying the packets on DUT egress, especially for multi line card scenario - verify_egress_queue_frame_count(duthost=egress_duthost, - switch_flow_stats=switch_flow_stats, - test_traffic_pause=test_traffic_pause, - snappi_extra_params=snappi_extra_params) + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost = tx_port['duthost'] - if test_traffic_pause: - # Verify in flight TX packets count relative to switch buffer size - verify_in_flight_buffer_pkts(egress_duthost=egress_duthost, - ingress_duthost=ingress_duthost, - flow_metrics=in_flight_flow_metrics, - snappi_extra_params=snappi_extra_params, - asic_value=tx_port.get('asic_value')) - else: - # Verify zero pause frames are counted when the PFC class enable vector is not set - verify_unset_cev_pause_frame_count(duthost=duthost, - snappi_extra_params=snappi_extra_params) +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - if test_traffic_pause and not snappi_extra_params.gen_background_traffic: - # Verify TX frame count on the DUT when traffic is expected to be paused - # and only test traffic flows are generated - verify_tx_frame_count_dut(duthost=egress_duthost, - api=api, - snappi_extra_params=snappi_extra_params) +global DATA_FLOW_DURATION_SEC +global data_flow_delay_sec - # Verify TX frame count on the DUT when traffic is expected to be paused - # and only test traffic flows are generated - verify_rx_frame_count_dut(duthost=ingress_duthost, - api=api, - snappi_extra_params=snappi_extra_params) +# Port id of Rx port for traffic config +port_id = 0 +if dut_port and duthost: + port_id = get_dut_port_id(dut_hostname=duthost.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) -def run_tx_drop_counter( - api, - testbed_config, - port_config_list, - dut_port, - test_prio_list, - prio_dscp_map, - snappi_extra_params=None): +# Rate percent must be an integer +bg_flow_rate_percent = int((BG_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(bg_prio_list)) +test_flow_rate_percent = int((TEST_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(test_prio_list)) - pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') +# Generate base traffic config +snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() +speed_str = testbed_config.layer1[0].speed +speed_gbps = int(float(speed_str.split('_')[1])) - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - duthost = rx_port['duthost'] - port_id = 0 - - # Generate base traffic config - snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - - test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / len(test_prio_list)) - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - # Generate test flow config - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) - - flows = testbed_config.flows - - all_flow_names = [flow.name for flow in flows] - data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - - duthost.command("sonic-clear counters") - duthost.command("sonic-clear queuecounters") - # Collect metrics from DUT before traffic - tx_ok_frame_count, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) - - """ Run traffic """ - tgen_flow_stats, _, _ = run_traffic( - duthost=duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - data_flow_delay_sec, - snappi_extra_params=snappi_extra_params) - link_state = None - try: - time.sleep(1) - # Collect metrics from DUT once again - tx_ok_frame_count_1, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) - - pytest_assert(tx_ok_frame_count_1 > tx_ok_frame_count and tx_dut_drop_frames_1 == tx_dut_drop_frames, - "DUT Port {} : TX ok counter before {} after {}, Tx drop counter before {} after {} not expected". - format(dut_port, tx_ok_frame_count, tx_ok_frame_count_1, - tx_dut_drop_frames, tx_dut_drop_frames_1)) - - # Set port name of the Ixia port connected to dut_port - port_names = snappi_extra_params.base_flow_config["rx_port_name"] - # Create a control state object for all ports - cs = api.control_state() - # Create a control state object for all ports - cs.choice = cs.PORT - cs.port.choice = cs.port.LINK - # Apply the state to port - cs.link.port_names = [port_names] - # Set port down (shut) - cs.port.link.state = cs.port.link.DOWN - api.set_control_state(cs) - logger.info("Snappi port {} is set to DOWN".format(port_names)) - time.sleep(1) - # Collect metrics from DUT again - _, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) - - logger.info("Sleeping for 90 seconds") - time.sleep(90) - # Collect metrics from DUT once again - _, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) - - pytest_assert(tx_dut_drop_frames == tx_dut_drop_frames_1, - "Mismatch in TX drop counters post DUT port {} oper down".format(dut_port)) - finally: - if link_state: - # Bring the link back up - link_state.state = link_state.UP - api.set_link_state(link_state) - logger.info("Snappi port {} is set to UP".format(port_names)) +if snappi_extra_params.headroom_test_params is not None: + DATA_FLOW_DURATION_SEC += 10 + data_flow_delay_sec += 2 + + # Set up pfc delay parameter + l1_config = testbed_config.layer1[0] + pfc = l1_config.flow_control.ieee_802_1qbb + pfc.pfc_delay = snappi_extra_params.headroom_test_params[0] + +if snappi_extra_params.poll_device_runtime: + # If the switch needs to be polled as traffic is running for stats, + # then the test runtime needs to be increased for the polling delay + DATA_FLOW_DURATION_SEC += ANSIBLE_POLL_DELAY_SEC + data_flow_delay_sec = ANSIBLE_POLL_DELAY_SEC + +if snappi_extra_params.packet_capture_type != packet_capture.NO_CAPTURE: + # Setup capture config + if snappi_extra_params.is_snappi_ingress_port_cap: + # packet capture is required on the ingress snappi port + snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["rx_port_name"]] + else: + # packet capture will be on the egress snappi port + snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["tx_port_name"]] + + snappi_extra_params.packet_capture_file = snappi_extra_params.packet_capture_type.value + + config_capture_pkt(testbed_config=testbed_config, + port_names=snappi_extra_params.packet_capture_ports, + capture_type=snappi_extra_params.packet_capture_type, + capture_name=snappi_extra_params.packet_capture_file) + logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +if snappi_extra_params.traffic_flow_config.background_flow_config is None and \ + snappi_extra_params.gen_background_traffic: + snappi_extra_params.traffic_flow_config.background_flow_config = { + "flow_name": BG_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": bg_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +if snappi_extra_params.traffic_flow_config.pause_flow_config is None: + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": None, + "flow_rate_percent": None, + "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": None, + "flow_delay_sec": 0, + "flow_traffic_type": traffic_flow_mode.CONTINUOUS + } + +if snappi_extra_params.packet_capture_type == packet_capture.PFC_CAPTURE: + # PFC pause frame capture is requested + valid_pfc_frame_test = True +else: + # PFC pause frame capture is not requested + valid_pfc_frame_test = False + +if valid_pfc_frame_test and not is_cisco_device(egress_duthost): + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_dur_sec"] = DATA_FLOW_DURATION_SEC + \ + data_flow_delay_sec + SNAPPI_POLL_DELAY_SEC + PAUSE_FLOW_DUR_BASE_SEC + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_traffic_type"] = \ + traffic_flow_mode.FIXED_DURATION + +no_of_streams = 1 +if egress_duthost.facts['asic_type'] == "cisco-8000": + if not test_flow_is_lossless: + no_of_streams = 6 + +# Generate test flow config +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + number_of_streams=no_of_streams, + snappi_extra_params=snappi_extra_params) + +if snappi_extra_params.gen_background_traffic: + # Generate background flow config + generate_background_flows(testbed_config=testbed_config, + bg_flow_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) + +# Generate pause storm config +generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=pause_prio_list, + global_pause=global_pause, + snappi_extra_params=snappi_extra_params) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +# Clear PFC, queue and interface counters before traffic run +duthost = egress_duthost + +for dut in [egress_duthost, ingress_duthost]: + dut.command("pfcstat -c") + time.sleep(1) + dut.command("sonic-clear queuecounters") + time.sleep(1) + dut.command("sonic-clear counters") + time.sleep(1) + +""" Run traffic """ +tgen_flow_stats, switch_flow_stats, in_flight_flow_metrics = run_traffic(duthost=duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + data_flow_delay_sec, + snappi_extra_params=snappi_extra_params) + +# Reset pfc delay parameter +pfc = testbed_config.layer1[0].flow_control.ieee_802_1qbb +pfc.pfc_delay = 0 + +# Verify PFC pause frames +if valid_pfc_frame_test: + if not is_cisco_device(duthost): + is_valid_pfc_frame, error_msg = validate_pfc_frame(snappi_extra_params.packet_capture_file + ".pcapng") + else: + is_valid_pfc_frame, error_msg = validate_pfc_frame_cisco( + snappi_extra_params.packet_capture_file + ".pcapng") + pytest_assert(is_valid_pfc_frame, error_msg) return + +# Verify pause flows +verify_pause_flow(flow_metrics=tgen_flow_stats, + pause_flow_name=PAUSE_FLOW_NAME) + +if snappi_extra_params.gen_background_traffic: + # Verify background flows + verify_background_flow(flow_metrics=tgen_flow_stats, + speed_gbps=speed_gbps, + tolerance=TOLERANCE_THRESHOLD, + snappi_extra_params=snappi_extra_params) + +# Verify basic test flows metrics from ixia +verify_basic_test_flow(flow_metrics=tgen_flow_stats, + speed_gbps=speed_gbps, + tolerance=TOLERANCE_THRESHOLD, + test_flow_pause=test_traffic_pause, + snappi_extra_params=snappi_extra_params) + +# Verify PFC pause frame count on the DUT +verify_pause_frame_count_dut(rx_dut=ingress_duthost, + tx_dut=egress_duthost, + test_traffic_pause=test_traffic_pause, + global_pause=global_pause, + snappi_extra_params=snappi_extra_params) + +# Verify in flight TX lossless packets do not leave the DUT when traffic is expected +# to be paused, or leave the DUT when the traffic is not expected to be paused +# Verifying the packets on DUT egress, especially for multi line card scenario +verify_egress_queue_frame_count(duthost=egress_duthost, + switch_flow_stats=switch_flow_stats, + test_traffic_pause=test_traffic_pause, + snappi_extra_params=snappi_extra_params) + +if test_traffic_pause: + # Verify in flight TX packets count relative to switch buffer size + verify_in_flight_buffer_pkts(egress_duthost=egress_duthost, + ingress_duthost=ingress_duthost, + flow_metrics=in_flight_flow_metrics, + snappi_extra_params=snappi_extra_params, + asic_value=tx_port.get('asic_value')) +else: + # Verify zero pause frames are counted when the PFC class enable vector is not set + verify_unset_cev_pause_frame_count(duthost=duthost, + snappi_extra_params=snappi_extra_params) + +if test_traffic_pause and not snappi_extra_params.gen_background_traffic: + # Verify TX frame count on the DUT when traffic is expected to be paused + # and only test traffic flows are generated + verify_tx_frame_count_dut(duthost=egress_duthost, + api=api, + snappi_extra_params=snappi_extra_params) + + # Verify TX frame count on the DUT when traffic is expected to be paused + # and only test traffic flows are generated + verify_rx_frame_count_dut(duthost=ingress_duthost, + api=api, + snappi_extra_params=snappi_extra_params) +``` + +def run_tx_drop_counter( +api, +testbed_config, +port_config_list, +dut_port, +test_prio_list, +prio_dscp_map, +snappi_extra_params=None): + +``` +pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] +duthost = rx_port['duthost'] +port_id = 0 + +# Generate base traffic config +snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + +test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / len(test_prio_list)) + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +# Generate test flow config +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) + +flows = testbed_config.flows + +all_flow_names = [flow.name for flow in flows] +data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + +duthost.command("sonic-clear counters") +duthost.command("sonic-clear queuecounters") +# Collect metrics from DUT before traffic +tx_ok_frame_count, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) + +""" Run traffic """ +tgen_flow_stats, _, _ = run_traffic( + duthost=duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + data_flow_delay_sec, + snappi_extra_params=snappi_extra_params) +link_state = None +try: + time.sleep(1) + # Collect metrics from DUT once again + tx_ok_frame_count_1, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) + + pytest_assert(tx_ok_frame_count_1 > tx_ok_frame_count and tx_dut_drop_frames_1 == tx_dut_drop_frames, + "DUT Port {} : TX ok counter before {} after {}, Tx drop counter before {} after {} not expected". + format(dut_port, tx_ok_frame_count, tx_ok_frame_count_1, + tx_dut_drop_frames, tx_dut_drop_frames_1)) + + # Set port name of the Ixia port connected to dut_port + port_names = snappi_extra_params.base_flow_config["rx_port_name"] + # Create a control state object for all ports + cs = api.control_state() + # Create a control state object for all ports + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK + # Apply the state to port + cs.link.port_names = [port_names] + # Set port down (shut) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) + logger.info("Snappi port {} is set to DOWN".format(port_names)) + time.sleep(1) + # Collect metrics from DUT again + _, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) + + logger.info("Sleeping for 90 seconds") + time.sleep(90) + # Collect metrics from DUT once again + _, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) + + pytest_assert(tx_dut_drop_frames == tx_dut_drop_frames_1, + "Mismatch in TX drop counters post DUT port {} oper down".format(dut_port)) +finally: + if link_state: + # Bring the link back up + link_state.state = link_state.UP + api.set_link_state(link_state) + logger.info("Snappi port {} is set to UP".format(port_names)) +return +``` From d6683f0752ec90928cc61bb4f8c6a2a13d4a268f Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 14 May 2025 16:09:21 -0700 Subject: [PATCH 09/17] Update ecnhelper.py updated --- tests/snappi_tests/ecn/files/ecnhelper.py | 173 +++++++++++----------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index 11fd625e017..b68c1ea8299 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -3,7 +3,7 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ - fanout_graph_facts # noqa F401 +fanout_graph_facts # noqa F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector,\ get_lossless_buffer_size, get_pg_dropped_packets,\ stop_pfcwd, disable_packet_aging, sec_to_nanosec,\ @@ -62,92 +62,93 @@ def verify_ecn_counters(ecn_counters, link_state_toggled=False): # ecn counter is per TC, both TC has same dwrr weight def run_ecn_test_cisco8000(api, - testbed_config, - port_config_list, - conn_data, - fanout_data, - duthost, - dut_port, - test_prio_list, - prio_dscp_map, - snappi_extra_params=None, - snappi_ports=None): - """ - Run a PFC test - Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - duthost (Ansible host instance): device under test - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - - Returns: - N/A - """ - - pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - - if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - - stop_pfcwd(duthost) - disable_packet_aging(duthost) - - init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - - # Get the ID of the port to test - for i in range(len(snappi_ports)): - if snappi_ports[i]['peer_port'] == dut_port: - port_id = snappi_ports[i]['port_id'] - break - - pytest_assert(port_id is not None, - 'Fail to get ID for port {}'.format(dut_port)) - - # Generate base traffic config - base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] - base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - - # Generate test flow config - traffic_rate = 99.98 - test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) - - snappi_extra_params.base_flow_config = base_flow_config1 - - # Set default traffic flow configs if not set - if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - - generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - - snappi_extra_params.base_flow_config = base_flow_config2 +testbed_config, +port_config_list, +conn_data, +fanout_data, +duthost, +dut_port, +test_prio_list, +prio_dscp_map, +snappi_extra_params=None, +snappi_ports=None): +""" +Run a PFC test +Args: +api (obj): snappi session +testbed_config (obj): testbed L1/L2/L3 configuration +port_config_list (list): list of port configuration +conn_data (dict): the dictionary returned by conn_graph_fact. +fanout_data (dict): the dictionary returned by fanout_graph_fact. +duthost (Ansible host instance): device under test +dut_port (str): DUT port to test +test_prio_list (list): priorities of test flows +prio_dscp_map (dict): Priority vs. DSCP map (key = priority). +snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + +``` +Returns: + N/A +""" + +pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') +pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + +if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + +stop_pfcwd(duthost) +disable_packet_aging(duthost) + +init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) +init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + +# Get the ID of the port to test +for i in range(len(snappi_ports)): + if snappi_ports[i]['peer_port'] == dut_port: + port_id = snappi_ports[i]['port_id'] + break +pytest_assert(port_id is not None, + 'Fail to get ID for port {}'.format(dut_port)) + +# Generate base traffic config +base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) +port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] +base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list2, + port_id=port_id) + +# Generate test flow config +traffic_rate = 99.98 +test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) + +snappi_extra_params.base_flow_config = base_flow_config1 + +# Set default traffic flow configs if not set +if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[0], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + +generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=2) + +snappi_extra_params.base_flow_config = base_flow_config2 +``` def run_ecn_test_cisco8000(api, testbed_config, From 1e7f65b4828c8d560a9752cff1d206542524ae28 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Thu, 15 May 2025 09:03:15 -0700 Subject: [PATCH 10/17] Update ecnhelper.py formatted ecnhelpler file. --- tests/snappi_tests/ecn/files/ecnhelper.py | 504 +++++++++------------- 1 file changed, 206 insertions(+), 298 deletions(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index b68c1ea8299..ccf624a1778 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -3,16 +3,16 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ -fanout_graph_facts # noqa F401 + fanout_graph_facts # noqa F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector,\ -get_lossless_buffer_size, get_pg_dropped_packets,\ -stop_pfcwd, disable_packet_aging, sec_to_nanosec,\ -get_pfc_frame_count, packet_capture, config_capture_pkt,\ -traffic_flow_mode, calc_pfc_pause_flow_rate # noqa F401 + get_lossless_buffer_size, get_pg_dropped_packets,\ + stop_pfcwd, disable_packet_aging, sec_to_nanosec,\ + get_pfc_frame_count, packet_capture, config_capture_pkt,\ + traffic_flow_mode, calc_pfc_pause_flow_rate # noqa F401 from tests.common.snappi_tests.port import select_ports, select_tx_port # noqa F401 from tests.common.snappi_tests.snappi_helpers import wait_for_arp # noqa F401 from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows,\ -run_traffic + run_traffic from tests.snappi_tests.files.helper import get_npu_voq_queue_counters from tests.common.snappi_tests.snappi_test_params import SnappiTestParams @@ -21,311 +21,219 @@ DATA_FLOW_PKT_SIZE = 1024 DATA_FLOW_DURATION_SEC = 2 DATA_FLOW_DELAY_SEC = 1 -TEST_FLOW_NAME = \['Test Flow 3', 'Test Flow 4'\] +TEST_FLOW_NAME = ['Test Flow 3', 'Test Flow 4'] PAUSE_FLOW_NAME = 'Pause Storm' + def verify_ecn_counters(ecn_counters, link_state_toggled=False): -``` -toggle_msg = " post link state toggle" if link_state_toggled else "" -# verify that each flow had packets -init_ctr_3, post_ctr_3 = ecn_counters[0] -init_ctr_4, post_ctr_4 = ecn_counters[1] -flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] + toggle_msg = " post link state toggle" if link_state_toggled else "" + # verify that each flow had packets + init_ctr_3, post_ctr_3 = ecn_counters[0] + init_ctr_4, post_ctr_4 = ecn_counters[1] + flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] -pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment{}'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) + pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment{}'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) -flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] + flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] -pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment{}'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) + pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment{}'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) -flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -pytest_assert(flow3_ecn > 0, - 'Must have ecn marked packets on flow 3{}'. - format(toggle_msg)) + pytest_assert(flow3_ecn > 0, + 'Must have ecn marked packets on flow 3{}'. + format(toggle_msg)) -pytest_assert(flow4_ecn > 0, - 'Must have ecn marked packets on flow 4{}'. - format(toggle_msg)) -``` + pytest_assert(flow4_ecn > 0, + 'Must have ecn marked packets on flow 4{}'. + format(toggle_msg)) -# line rate percent for TC 3, 4 from tx port a, b +# line rate percent for TC 3, 4 from tx port a, b # ecn counter is per TC, both TC has same dwrr weight - def run_ecn_test_cisco8000(api, -testbed_config, -port_config_list, -conn_data, -fanout_data, -duthost, -dut_port, -test_prio_list, -prio_dscp_map, -snappi_extra_params=None, -snappi_ports=None): -""" -Run a PFC test -Args: -api (obj): snappi session -testbed_config (obj): testbed L1/L2/L3 configuration -port_config_list (list): list of port configuration -conn_data (dict): the dictionary returned by conn_graph_fact. -fanout_data (dict): the dictionary returned by fanout_graph_fact. -duthost (Ansible host instance): device under test -dut_port (str): DUT port to test -test_prio_list (list): priorities of test flows -prio_dscp_map (dict): Priority vs. DSCP map (key = priority). -snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -``` -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -stop_pfcwd(duthost) -disable_packet_aging(duthost) - -init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -# Get the ID of the port to test -for i in range(len(snappi_ports)): - if snappi_ports[i]['peer_port'] == dut_port: - port_id = snappi_ports[i]['port_id'] - break - -pytest_assert(port_id is not None, - 'Fail to get ID for port {}'.format(dut_port)) - -# Generate base traffic config -base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) -port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] -base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - -# Generate test flow config -traffic_rate = 99.98 -test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) - -snappi_extra_params.base_flow_config = base_flow_config1 - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - -snappi_extra_params.base_flow_config = base_flow_config2 -``` + testbed_config, + port_config_list, + conn_data, + fanout_data, + duthost, + dut_port, + test_prio_list, + prio_dscp_map, + snappi_extra_params=None, + snappi_ports=None): + """ + Run a PFC test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + duthost (Ansible host instance): device under test + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + stop_pfcwd(duthost) + disable_packet_aging(duthost) + + init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + + # Get the ID of the port to test + for i in range(len(snappi_ports)): + if snappi_ports[i]['peer_port'] == dut_port: + port_id = snappi_ports[i]['port_id'] + break + + pytest_assert(port_id is not None, + 'Fail to get ID for port {}'.format(dut_port)) + + # Generate base traffic config + base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] + base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list2, + port_id=port_id) + + # Generate test flow config + traffic_rate = 99.98 + test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) + + snappi_extra_params.base_flow_config = base_flow_config1 + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[0], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=2) + + snappi_extra_params.base_flow_config = base_flow_config2 -def run_ecn_test_cisco8000(api, -testbed_config, -port_config_list, -conn_data, -fanout_data, -duthost, -dut_port, -test_prio_list, -prio_dscp_map, -snappi_extra_params=None): -""" -Run a PFC test -Args: -api (obj): snappi session -testbed_config (obj): testbed L1/L2/L3 configuration -port_config_list (list): list of port configuration -conn_data (dict): the dictionary returned by conn_graph_fact. -fanout_data (dict): the dictionary returned by fanout_graph_fact. -duthost (Ansible host instance): device under test -dut_port (str): DUT port to test -test_prio_list (list): priorities of test flows -prio_dscp_map (dict): Priority vs. DSCP map (key = priority). -snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -``` -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -stop_pfcwd(duthost) -disable_packet_aging(duthost) - -init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -# Get the ID of the port to test -port_id = get_dut_port_id(dut_hostname=duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) - -pytest_assert(port_id is not None, - 'Fail to get ID for port {}'.format(dut_port)) - -# Generate base traffic config -base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) -port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] -base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - -# Generate test flow config -traffic_rate = 99.98 -test_flow_rate_percent = int(traffic_rate / len(test_prio_list)) - -snappi_extra_params.base_flow_config = base_flow_config1 - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - -snappi_extra_params.base_flow_config = base_flow_config2 - -snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[1], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=2) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -# Clear PFC and queue counters before traffic run -duthost.command("pfcstat -c") -duthost.command("sonic-clear queuecounters") - -""" Run traffic """ -_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - -post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) -] - -verify_ecn_counters(ecn_counters) - -# Get the current configuration -config = api.get_config() -# Collect all port names -port_names = [port.name for port in config.ports] -# Create a control state object for all ports -cs = api.control_state() -# Create a control state object for all ports -cs.choice = cs.PORT -cs.port.choice = cs.port.LINK -# Apply the state to all ports -cs.link.port_names = port_names -# Set all ports down (shut) -cs.port.link.state = cs.port.link.DOWN -api.set_control_state(cs) -logger.info("All Snappi ports are set to DOWN") -time.sleep(0.2) -# Unshut all ports -cs.port.link.state = cs.port.link.UP -api.set_control_state(cs) -logger.info("All Snappi ports are set to UP") - -init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -""" Run traffic """ -_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - -post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) -] - -verify_ecn_counters(ecn_counters, link_state_toggled=True) -``` + "flow_name": TEST_FLOW_NAME[1], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=2) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + # Clear PFC and queue counters before traffic run + duthost.command("pfcstat -c") + duthost.command("sonic-clear queuecounters") + + """ Run traffic """ + _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + + post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + + ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) + ] + + verify_ecn_counters(ecn_counters) + + # Get the current configuration + config = api.get_config() + # Collect all port names + port_names = [port.name for port in config.ports] + # Create a control state object for all ports + link_state = api.link_state() + cs = api.control_state() + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK + # Apply the state to all ports + cs.link.port_names = port_names + # Set all ports down (shut) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) + logger.info("All Snappi ports are set to DOWN") + time.sleep(0.2) + # Unshut all ports + cs.port.link.state = cs.port.link.UP + api.set_control_state(cs) + logger.info("All Snappi ports are set to UP") + + init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + + """ Run traffic """ + _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + + post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + + ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) + ] + + verify_ecn_counters(ecn_counters, link_state_toggled=True) From 7b60e1ea85495e47554c71173a4a1618974b1883 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Thu, 15 May 2025 09:09:51 -0700 Subject: [PATCH 11/17] Update bpfabric_helper.py formatted bpfabric_helper file. --- .../snappi_tests/ecn/files/bpfabric_helper.py | 488 +++++++++--------- 1 file changed, 242 insertions(+), 246 deletions(-) diff --git a/tests/snappi_tests/ecn/files/bpfabric_helper.py b/tests/snappi_tests/ecn/files/bpfabric_helper.py index dfa53958716..9ad672f8ffa 100644 --- a/tests/snappi_tests/ecn/files/bpfabric_helper.py +++ b/tests/snappi_tests/ecn/files/bpfabric_helper.py @@ -2,17 +2,18 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts # noqa: F401 from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ -snappi_api # noqa: F401 + snappi_api # noqa: F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector, config_wred, \ -enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ -config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_all_port_stats # noqa: F401 + enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ + config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_all_port_stats # noqa: F401 from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ -generate_pause_flows, run_traffic # noqa: F401 + generate_pause_flows, run_traffic # noqa: F401 from tests.snappi_tests.files.helper import get_fabric_mapping, load_port_stats, \ -infer_ecmp_backplane_ports, set_cir_cisco_8000, get_npu_voq_queue_counters, compute_expected_packets + infer_ecmp_backplane_ports, set_cir_cisco_8000, get_npu_voq_queue_counters, compute_expected_packets import time + logger = logging.getLogger(__name__) DATA_FLOW_PKT_SIZE = 1350 @@ -21,287 +22,282 @@ DATA_FLOW_NAME = 'Data Flow' PAUSE_FLOW_NAME = 'Pause Storm' + def verify_ecn_marking_counters(ecn_counters, lossless_prio, intf): -\# verify that each flow had packets -init_ctr, post_ctr = ecn_counters\[0\] - -``` -flow_total = post_ctr['SAI_QUEUE_STAT_PACKETS'] - init_ctr['SAI_QUEUE_STAT_PACKETS'] - -pytest_assert(flow_total > 0, - 'Queue {} counters at start {} at end {} did not increment of {}'.format( - lossless_prio, init_ctr['SAI_QUEUE_STAT_PACKETS'], post_ctr['SAI_QUEUE_STAT_PACKETS'], intf)) - -flow_ecn = post_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - -pytest_assert(flow_ecn > 0, - 'Must have ecn marked packets on queue {} of {}'.format(lossless_prio, intf)) -``` - -def \_generate_traffic_config(testbed_config, -snappi_extra_params, -port_config_list, -test_prio_list, -test_flow_percent, -prio_dscp_map, -congested=False): -TEST_FLOW_NAME = DATA_FLOW_NAME + ' ' + str(test_prio_list\[0\]) - -``` -port_id = 0 -# Generate base traffic config -base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - -# Create a dictionary with priorities as keys and flow rates as values -flow_rate_dict = { - prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) -} - -snappi_extra_params.base_flow_config = base_flow_config1 - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + # verify that each flow had packets + init_ctr, post_ctr = ecn_counters[0] + + flow_total = post_ctr['SAI_QUEUE_STAT_PACKETS'] - init_ctr['SAI_QUEUE_STAT_PACKETS'] + + pytest_assert(flow_total > 0, + 'Queue {} counters at start {} at end {} did not increment of {}'.format( + lossless_prio, init_ctr['SAI_QUEUE_STAT_PACKETS'], post_ctr['SAI_QUEUE_STAT_PACKETS'], intf)) + + flow_ecn = post_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + + pytest_assert(flow_ecn > 0, + 'Must have ecn marked packets on queue {} of {}'.format(lossless_prio, intf)) + + +def _generate_traffic_config(testbed_config, + snappi_extra_params, + port_config_list, + test_prio_list, + test_flow_percent, + prio_dscp_map, + congested=False): + TEST_FLOW_NAME = DATA_FLOW_NAME + ' ' + str(test_prio_list[0]) + + port_id = 0 + # Generate base traffic config + base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + # Create a dictionary with priorities as keys and flow rates as values + flow_rate_dict = { + prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) } -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=1) -``` + snappi_extra_params.base_flow_config = base_flow_config1 + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=1) + def get_traffic_path( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -snappi_extra_params): + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + snappi_extra_params): -``` -""" -Returns: - list: Returns traffic path [ingress_port, tx_bp, fabric_rx, fabric_tx, rx_bp, egress_port] -""" + """ + Returns: + list: Returns traffic path [ingress_port, tx_bp, fabric_rx, fabric_tx, rx_bp, egress_port] + """ -test_flow_percent = [49] * len(test_prio_list) + test_flow_percent = [49] * len(test_prio_list) -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() -# Traffic flow: -# tx_port (TGEN) --- ingress DUT ---Fabric---- egress DUT --- rx_port (TGEN) + # Traffic flow: + # tx_port (TGEN) --- ingress DUT ---Fabric---- egress DUT --- rx_port (TGEN) -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] -tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost = tx_port['duthost'] + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost = tx_port['duthost'] -# Append the duthost here for run_traffic to clear its counters -snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost) -snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) + # Append the duthost here for run_traffic to clear its counters + snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost) + snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) -duthost = egress_duthost + duthost = egress_duthost -_generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map) + _generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map) -flows = testbed_config.flows + flows = testbed_config.flows -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] -speed_str = testbed_config.layer1[0].speed -speed_gbps = int(speed_str.split('_')[1]) + speed_str = testbed_config.layer1[0].speed + speed_gbps = int(speed_str.split('_')[1]) -# Find the expected packets for the given traffic duration and flow percent. -# This helps find the bp interfaces involved in the traffic path more accurately -pkt_threshold = compute_expected_packets(speed_gbps * 10**9 * test_flow_percent[0]/100, - DATA_FLOW_PKT_SIZE, DATA_FLOW_DURATION_SEC) + # Find the expected packets for the given traffic duration and flow percent. + # This helps find the bp interfaces involved in the traffic path more accurately + pkt_threshold = compute_expected_packets(speed_gbps * 10**9 * test_flow_percent[0]/100, + DATA_FLOW_PKT_SIZE, DATA_FLOW_DURATION_SEC) -""" Run traffic """ -_, _, _ = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) + """ Run traffic """ + _, _, _ = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) -# get all the port stats -ingress_stats = get_all_port_stats(ingress_duthost) -egress_stats = get_all_port_stats(egress_duthost) + # get all the port stats + ingress_stats = get_all_port_stats(ingress_duthost) + egress_stats = get_all_port_stats(egress_duthost) -# Find the active data path interfaces using the expected pkt threshold. -ingress_active_interfaces = load_port_stats(ingress_stats, pkt_threshold, direction="tx") -egress_active_interfaces = load_port_stats(egress_stats, pkt_threshold, direction="rx") + # Find the active data path interfaces using the expected pkt threshold. + ingress_active_interfaces = load_port_stats(ingress_stats, pkt_threshold, direction="tx") + egress_active_interfaces = load_port_stats(egress_stats, pkt_threshold, direction="rx") -# Find the fabric mapping from the CLI -ingress_fabric_mapping = get_fabric_mapping(ingress_duthost) -egress_fabric_mapping = get_fabric_mapping(egress_duthost) + # Find the fabric mapping from the CLI + ingress_fabric_mapping = get_fabric_mapping(ingress_duthost) + egress_fabric_mapping = get_fabric_mapping(egress_duthost) -# Infer the traffic path from ingress to egress port via BP and Fabric port -traffic_paths = infer_ecmp_backplane_ports(ingress_active_interfaces, egress_active_interfaces, - snappi_extra_params.multi_dut_params.multi_dut_ports[1]['peer_port'], - dut_port, ingress_fabric_mapping, egress_fabric_mapping) + # Infer the traffic path from ingress to egress port via BP and Fabric port + traffic_paths = infer_ecmp_backplane_ports(ingress_active_interfaces, egress_active_interfaces, + snappi_extra_params.multi_dut_params.multi_dut_ports[1]['peer_port'], + dut_port, ingress_fabric_mapping, egress_fabric_mapping) -pytest_assert(traffic_paths, "Unable to find traffic path for the given ingress and egress port") + pytest_assert(traffic_paths, "Unable to find traffic path for the given ingress and egress port") + + logger.info("Traffic paths {}".format(traffic_paths)) + return traffic_paths -logger.info("Traffic paths {}".format(traffic_paths)) -return traffic_paths -``` def adjust_shaper_and_verify(dut, egress_intfs, test_prio_list, api): -egress_asic_map = {} + egress_asic_map = {} + + # Create a map of asic instance and egress ports involved in the traffic path + for intf in egress_intfs: + asic_instance = dut.get_port_asic_instance(intf) + if asic_instance not in egress_asic_map: + egress_asic_map[asic_instance] = [] -``` -# Create a map of asic instance and egress ports involved in the traffic path -for intf in egress_intfs: - asic_instance = dut.get_port_asic_instance(intf) - if asic_instance not in egress_asic_map: - egress_asic_map[asic_instance] = [] + egress_asic_map[asic_instance].append(intf) - egress_asic_map[asic_instance].append(intf) + try: + # Iterate over the egress port map and call set_cir_cisco_8000 + for asic_instance, intf_list in egress_asic_map.items(): + # Set the shaper to 5GB to induce congestion on the egress ports + set_cir_cisco_8000(dut, intf_list, asic_instance, speed=5 * 1000 * 1000 * 1000) -try: - # Iterate over the egress port map and call set_cir_cisco_8000 - for asic_instance, intf_list in egress_asic_map.items(): - # Set the shaper to 5GB to induce congestion on the egress ports - set_cir_cisco_8000(dut, intf_list, asic_instance, speed=5 * 1000 * 1000 * 1000) + queue_counters = {} + for intf in egress_intfs: + init_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) - queue_counters = {} - for intf in egress_intfs: - init_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) + queue_counters[intf] = init_ctr - queue_counters[intf] = init_ctr + # Start traffic again + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.START + api.set_control_state(cs) - cs = api.control_state() - cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.START - api.set_control_state(cs) + time.sleep(DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC) - time.sleep(DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC) + # Stop traffic + cs = api.control_state() + cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.STOP + api.set_control_state(cs) - # Stop traffic - cs = api.control_state() - cs.traffic.flow_transmit.state = cs.traffic.flow_transmit.STOP - api.set_control_state(cs) + for intf in egress_intfs: + post_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) - for intf in egress_intfs: - post_ctr = get_npu_voq_queue_counters(dut, intf, test_prio_list[0]) + init_ctr = queue_counters[intf] - init_ctr = queue_counters[intf] + ecn_counters = [ + (init_ctr, post_ctr) + ] - ecn_counters = [ - (init_ctr, post_ctr) - ] + verify_ecn_marking_counters(ecn_counters, test_prio_list[0], intf) + finally: + # Iterate over the fabric egress port map and call set_cir_cisco_8000 + for asic_instance, intf_list in egress_asic_map.items(): + # Reset the shaper on the egress ports + set_cir_cisco_8000(dut, intf_list, asic_instance) - verify_ecn_marking_counters(ecn_counters, test_prio_list[0], intf) -finally: - # Iterate over the fabric egress port map and call set_cir_cisco_8000 - for asic_instance, intf_list in egress_asic_map.items(): - # Reset the shaper on the egress ports - set_cir_cisco_8000(dut, intf_list, asic_instance) -``` def run_fabric_ecn_marking_test(api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -supervisor_dut, -snappi_extra_params=None): - -``` -""" -Run a ECN test -Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priority of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - supervisor_dut (duthost): dutHost obj for supervisor in case of multi-DUT - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') - -traffic_paths = get_traffic_path(api, - testbed_config, port_config_list, - dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) - -# Get list of Fabric egress ports only -fabric_egress = [path[3] for path in traffic_paths] - -adjust_shaper_and_verify(supervisor_dut, fabric_egress, test_prio_list, api) -``` + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + supervisor_dut, + snappi_extra_params=None): + + """ + Run a ECN test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priority of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + supervisor_dut (duthost): dutHost obj for supervisor in case of multi-DUT + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') + + traffic_paths = get_traffic_path(api, + testbed_config, port_config_list, + dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) + + # Get list of Fabric egress ports only + fabric_egress = [path[3] for path in traffic_paths] + + adjust_shaper_and_verify(supervisor_dut, fabric_egress, test_prio_list, api) + def run_backplane_ecn_marking_test( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -snappi_extra_params=None): - -``` -""" -Run a ECN test -Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priority of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') - -traffic_paths = get_traffic_path(api, - testbed_config, port_config_list, - dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) - -# Get list of backplane egress ports only -backplane_egress = [path[1] for path in traffic_paths] - -tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost = tx_port['duthost'] - -adjust_shaper_and_verify(ingress_duthost, backplane_egress, test_prio_list, api) -``` + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + snappi_extra_params=None): + + """ + Run a ECN test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priority of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 1, 'Must have atleast one lossless priorities') + + traffic_paths = get_traffic_path(api, + testbed_config, port_config_list, + dut_port, test_prio_list, prio_dscp_map, snappi_extra_params) + + # Get list of backplane egress ports only + backplane_egress = [path[1] for path in traffic_paths] + + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost = tx_port['duthost'] + + adjust_shaper_and_verify(ingress_duthost, backplane_egress, test_prio_list, api) From 477ed434f347f02bf61fa16106edcb290475b843 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Thu, 15 May 2025 09:16:46 -0700 Subject: [PATCH 12/17] Update ecnhelper.py removed additional line --- tests/snappi_tests/ecn/files/ecnhelper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index ccf624a1778..6e9f24fae21 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -198,7 +198,6 @@ def run_ecn_test_cisco8000(api, # Collect all port names port_names = [port.name for port in config.ports] # Create a control state object for all ports - link_state = api.link_state() cs = api.control_state() cs.choice = cs.PORT cs.port.choice = cs.port.LINK From f3eaa5732a448df162593a0bd86b0225a2851de1 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Thu, 15 May 2025 09:21:37 -0700 Subject: [PATCH 13/17] Update helper.py formatted helper file --- tests/snappi_tests/ecn/files/helper.py | 1938 ++++++++++++------------ 1 file changed, 959 insertions(+), 979 deletions(-) diff --git a/tests/snappi_tests/ecn/files/helper.py b/tests/snappi_tests/ecn/files/helper.py index 104a222274c..cf3446b08bb 100644 --- a/tests/snappi_tests/ecn/files/helper.py +++ b/tests/snappi_tests/ecn/files/helper.py @@ -5,15 +5,15 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts # noqa: F401 from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ -snappi_api # noqa: F401 + snappi_api # noqa: F401 from tests.common.snappi_tests.snappi_helpers import get_dut_port_id from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector, config_wred, \ -enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ -config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_pfc_frame_count # noqa: F401 + enable_ecn, config_ingress_lossless_buffer_alpha, stop_pfcwd, disable_packet_aging,\ + config_capture_pkt, traffic_flow_mode, calc_pfc_pause_flow_rate, get_pfc_frame_count # noqa: F401 from tests.common.snappi_tests.read_pcap import get_ipv4_pkts from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ -generate_pause_flows, run_traffic # noqa: F401 + generate_pause_flows, run_traffic # noqa: F401 import json from tests.snappi_tests.files.helper import get_fabric_mapping @@ -25,903 +25,729 @@ PAUSE_FLOW_NAME = 'Pause Storm' DATA_FLOW_NAME = 'Data Flow' -def get_npu_voq_queue_counters(duthost, interface, priority, clear=False): - -``` -asic_namespace_string = "" -if duthost.is_multi_asic: - asic = duthost.get_port_asic_instance(interface) - asic_namespace_string = " -n " + asic.namespace - -clear_cmd = "" -if clear: - clear_cmd = " -c" -full_line = "".join(duthost.shell( - "show platform npu voq queue_counters -t {} -i {} -d{}{}". - format(priority, interface, asic_namespace_string, clear_cmd))['stdout_lines']) -dict_output = json.loads(full_line) -for entry, value in zip(dict_output['stats_name'], dict_output['counters']): - dict_output[entry] = value - -return dict_output -``` +def get_npu_voq_queue_counters(duthost, interface, priority, clear=False): -# When bp_fabric_ecn_marking_check is True + asic_namespace_string = "" + if duthost.is_multi_asic: + asic = duthost.get_port_asic_instance(interface) + asic_namespace_string = " -n " + asic.namespace -# + clear_cmd = "" + if clear: + clear_cmd = " -c" -# The traffic is flowing from short link to long link + full_line = "".join(duthost.shell( + "show platform npu voq queue_counters -t {} -i {} -d{}{}". + format(priority, interface, asic_namespace_string, clear_cmd))['stdout_lines']) + dict_output = json.loads(full_line) + for entry, value in zip(dict_output['stats_name'], dict_output['counters']): + dict_output[entry] = value -# + return dict_output +# When bp_fabric_ecn_marking_check is True +# +# The traffic is flowing from short link to long link +# # Step 1: Clear all counters on egress, fabric, and ingress DUT - # Step 2: Send traffic for the test. - # Step 3: Verify egress port queue counter at possible congestion points. - # Step 4: If no marking, - # - check and log backpressure - # - Fail the testcase + def clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): -""" -Clears VOQ queue counters of the ingress DUT BP ports and the Fabric ports connected to the Egress DUT. -""" -for priority in test_prio_list: -for fabric_egress_bp in egress_fabric_mapping.values(): -get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority, clear=True) - -``` - for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): - for fabric_mapping in ingress_fabric_mappings.values(): - for lc_egress_bp in fabric_mapping.keys(): - get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority, clear=True) - -logger.info("Counters cleared for ingress DUT BP ports and Fabric Egress ports") -``` + """ + Clears VOQ queue counters of the ingress DUT BP ports and the Fabric ports connected to the Egress DUT. + """ + for priority in test_prio_list: + for fabric_egress_bp in egress_fabric_mapping.values(): + get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority, clear=True) + + for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): + for fabric_mapping in ingress_fabric_mappings.values(): + for lc_egress_bp in fabric_mapping.keys(): + get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority, clear=True) + + logger.info("Counters cleared for ingress DUT BP ports and Fabric Egress ports") + def check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, supervisor_dut, test_prio_list): -""" -Checks for ECN marked packets across ingress and egress fabric mappings. -Returns True if ECN marking is found, otherwise False. -""" - -``` -all_priorities_marked = True - -for priority in test_prio_list: - ecn_marked_for_priority = False - - ecn_marked_packets_egress = 0 - for fabric_egress_bp in egress_fabric_mapping.values(): - ctr_egress = get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority) - ecn_marked_fb = ctr_egress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - ecn_marked_packets_egress += ecn_marked_fb - if ecn_marked_fb > 0: - logging.info("ECN marking : {} on Fabric interface: {}, priority: {}".format( - ecn_marked_fb, fabric_egress_bp, priority)) - ecn_marked_for_priority = True - - if ecn_marked_packets_egress: - logging.info("Total Fabric ECN marking detected: {} on priority: {} ".format( - ecn_marked_packets_egress, priority)) - - ecn_marked_packets_ingress = 0 - for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): - for fabric_mapping in ingress_fabric_mappings.values(): - for lc_egress_bp in fabric_mapping.keys(): - ctr_ingress = get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority) - ecn_marked_bp = ctr_ingress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - ecn_marked_packets_ingress += ecn_marked_bp - if ecn_marked_bp > 0: - logging.info("ECN marking : {} on ingress DUT {}, interface: {}, priority: {}".format( - ecn_marked_bp, ingress_duthost, lc_egress_bp, priority)) - ecn_marked_for_priority = True - - if ecn_marked_packets_ingress: - logging.info("Total Ingress BP ECN marking detected: {} on priority: {} ".format( - ecn_marked_packets_ingress, priority)) - - if not ecn_marked_for_priority: - all_priorities_marked = False - -if all_priorities_marked: - logger.info("ECN Marking detected for all priorities") - return True -else: - logger.info("ECN Marking missing for some priorities") - return False -``` + """ + Checks for ECN marked packets across ingress and egress fabric mappings. + Returns True if ECN marking is found, otherwise False. + """ -def verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required=False, link_state_toggled=False): + all_priorities_marked = True -``` -toggle_msg = " post link state toggle" if link_state_toggled else "" -# verify that each flow had packets -init_ctr_3, post_ctr_3 = ecn_counters[0] -init_ctr_4, post_ctr_4 = ecn_counters[1] -flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] -flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] - -logging.info("Flow 3 total packets: {}, Flow 4 total packets: {}".format(flow3_total, flow4_total)) - -pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment{}'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - -pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment{}'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - -flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - -if is_bp_fabric_ecn_check_required: - if flow3_ecn == 0: - logging.info("ECN marking check failed on flow 3 on egress port") - return False # Flow 3 ECN marking failed - elif flow4_ecn == 0: - logging.info("ECN marking check failed on flow 4 on egress port") - return False # Flow 4 ECN marking failed + for priority in test_prio_list: + ecn_marked_for_priority = False + + ecn_marked_packets_egress = 0 + for fabric_egress_bp in egress_fabric_mapping.values(): + ctr_egress = get_npu_voq_queue_counters(supervisor_dut, fabric_egress_bp, priority) + ecn_marked_fb = ctr_egress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + ecn_marked_packets_egress += ecn_marked_fb + if ecn_marked_fb > 0: + logging.info("ECN marking : {} on Fabric interface: {}, priority: {}".format( + ecn_marked_fb, fabric_egress_bp, priority)) + ecn_marked_for_priority = True + + if ecn_marked_packets_egress: + logging.info("Total Fabric ECN marking detected: {} on priority: {} ".format( + ecn_marked_packets_egress, priority)) + + ecn_marked_packets_ingress = 0 + for ingress_duthost, ingress_fabric_mappings in ingress_fabric_mapping_dict.items(): + for fabric_mapping in ingress_fabric_mappings.values(): + for lc_egress_bp in fabric_mapping.keys(): + ctr_ingress = get_npu_voq_queue_counters(ingress_duthost, lc_egress_bp, priority) + ecn_marked_bp = ctr_ingress.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + ecn_marked_packets_ingress += ecn_marked_bp + if ecn_marked_bp > 0: + logging.info("ECN marking : {} on ingress DUT {}, interface: {}, priority: {}".format( + ecn_marked_bp, ingress_duthost, lc_egress_bp, priority)) + ecn_marked_for_priority = True + + if ecn_marked_packets_ingress: + logging.info("Total Ingress BP ECN marking detected: {} on priority: {} ".format( + ecn_marked_packets_ingress, priority)) + + if not ecn_marked_for_priority: + all_priorities_marked = False + + if all_priorities_marked: + logger.info("ECN Marking detected for all priorities") + return True else: - logging.info("ECN marking check passed on both flow 3 and 4 on egress port") - return True # Both flows had ECN marked packets (success) + logger.info("ECN Marking missing for some priorities") + return False -pytest_assert(flow3_ecn > 0, - 'Must have ecn marked packets on flow 3{}'. - format(toggle_msg)) -pytest_assert(flow4_ecn > 0, - 'Must have ecn marked packets on flow 4{}'. - format(toggle_msg)) -return True -``` +def verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required=False, link_state_toggled=False): -def verify_ecn_counters_for_flow_percent( -ecn_counters, -test_flow_percent, -number_of_streams, -input_port_same_asic, -input_port_same_dut, -single_dut): - -``` -# verify that each flow had packets -init_ctr_3, post_ctr_3 = ecn_counters[0] -init_ctr_4, post_ctr_4 = ecn_counters[1] -flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] - -drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] -wred_drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] - -drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] -wred_drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] - -pytest_assert(drop_ctr_3 == 0 and wred_drop_ctr_3 == 0, 'Queue 3 Drop not expected') - -pytest_assert(drop_ctr_4 == 0 and wred_drop_ctr_4 == 0, 'Queue 4 Drop not expected') - -pytest_assert(flow3_total > 0, - 'Queue 3 counters at start {} at end {} did not increment'.format( - init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'])) - -flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] - -pytest_assert(flow4_total > 0, - 'Queue 4 counters at start {} at end {} did not increment'.format( - init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'])) - -flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ - init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - -if sum(test_flow_percent) < 100: - pytest_assert( - flow3_ecn == 0, - 'Must have no ecn marked packets on flow 3 without congestion, percent {}'. - format(test_flow_percent)) - pytest_assert( - flow4_ecn == 0, - 'Must have no ecn marked packets on flow 4 without congestion, percent {}'. - format(test_flow_percent)) -elif sum(test_flow_percent) >= 100: - if test_flow_percent[0] > 50: - pytest_assert( - flow3_ecn > 0, - 'Must have ecn marked packets on flow 3, percent {}'. - format(test_flow_percent)) + toggle_msg = " post link state toggle" if link_state_toggled else "" + # verify that each flow had packets + init_ctr_3, post_ctr_3 = ecn_counters[0] + init_ctr_4, post_ctr_4 = ecn_counters[1] + flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] + flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] - if test_flow_percent[1] > 50: - pytest_assert( - flow4_ecn > 0, - 'Must have ecn marked packets on flow 4, percent {}'. - format(test_flow_percent)) + logging.info("Flow 3 total packets: {}, Flow 4 total packets: {}".format(flow3_total, flow4_total)) - if test_flow_percent[0] < 50: - pytest_assert( - flow3_ecn == 0, - 'Must not have ecn marked packets on flow 3, percent {}'. - format(test_flow_percent)) + pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment{}'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - if test_flow_percent[1] < 50: - pytest_assert( - flow4_ecn == 0, - 'Must not have ecn marked packets on flow 4, percent {}'. - format(test_flow_percent)) + pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment{}'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'], toggle_msg)) - if test_flow_percent[0] > 50 and test_flow_percent[1] > 50: - pytest_assert( - flow3_ecn > 0 and flow4_ecn > 0, - 'Must have ecn marked packets on flows 3, 4, percent {}'. - format(test_flow_percent)) - percent3_mark = round(float(flow3_ecn/flow3_total), 2) * 100 - percent4_mark = round(float(flow4_ecn/flow4_total), 2) * 100 - flow_mark_diff = int(abs(percent3_mark - percent4_mark)) - logging.info( - "Stream count {}, inputs on {} asic, inputs on {} dut, " - "flow 3 percent {}, ecn {}, flow 4 percent {}, ecn {}, " - "flow_mark_diff {}".format( - number_of_streams, - "same" if input_port_same_asic else "different", - "same" if input_port_same_dut else "different", - test_flow_percent[0], - flow3_ecn, - test_flow_percent[1], - flow4_ecn, - flow_mark_diff)) - if number_of_streams == 1 and input_port_same_asic and \ - (test_flow_percent[0] == test_flow_percent[1]): - pytest_assert( - flow_mark_diff <= 5, - "For flow rates {}: the flow marking deviation {} is more " - "than 5% tolerance: flow 3 ecn: {} flow 4 ecn: {}". - format( - test_flow_percent, - flow_mark_diff, - flow3_ecn, - flow4_ecn)) - # if number_of_streams > 1, the streams will be spread across voq from backplane ports with shallow - # occupancy. Restrict marking check to single dut in such a case (or relax marking check) - elif input_port_same_dut and (number_of_streams == 1 or (number_of_streams > 1 and single_dut)): - if test_flow_percent[0] > test_flow_percent[1]: - pytest_assert( - flow3_ecn > flow4_ecn, - "For flow percent {}, ecn count {} must be higher than " - "flow percent {}, ecn count {}".format( - test_flow_percent[0], - flow3_ecn, - test_flow_percent[1], - flow4_ecn)) - elif test_flow_percent[0] < test_flow_percent[1]: - pytest_assert( - flow3_ecn < flow4_ecn, - "For flow percent {}, ecn count {} must be lower than flow percent {}, ecn count {}". - format(test_flow_percent[0], flow3_ecn, test_flow_percent[1], flow4_ecn)) -``` + flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -def run_ecn_test(api, -testbed_config, -port_config_list, -conn_data, -fanout_data, -dut_port, -lossless_prio, -prio_dscp_map, -iters, -snappi_extra_params=None): -""" -Run multidut ECN test - -``` -Args: - api (obj): SNAPPI session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - lossless_prio (int): lossless priority - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - -Returns: - Return captured IP packets (list of list) -""" - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] - -tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost = tx_port['duthost'] - -pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') - -logger.info("Stopping PFC watchdog") -stop_pfcwd(egress_duthost, rx_port['asic_value']) -stop_pfcwd(ingress_duthost, tx_port['asic_value']) -logger.info("Disabling packet aging if necessary") -disable_packet_aging(egress_duthost) -disable_packet_aging(ingress_duthost) - -# Configure WRED/ECN thresholds -logger.info("Configuring WRED and ECN thresholds") -config_result = config_wred(host_ans=egress_duthost, - kmin=snappi_extra_params.ecn_params["kmin"], - kmax=snappi_extra_params.ecn_params["kmax"], - pmax=snappi_extra_params.ecn_params["pmax"]) -pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') -config_result = config_wred(host_ans=ingress_duthost, - kmin=snappi_extra_params.ecn_params["kmin"], - kmax=snappi_extra_params.ecn_params["kmax"], - pmax=snappi_extra_params.ecn_params["pmax"]) -pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') - -# Enable ECN marking -logger.info("Enabling ECN markings") -pytest_assert(enable_ecn(host_ans=egress_duthost, prio=lossless_prio), 'Unable to enable ecn') -pytest_assert(enable_ecn(host_ans=ingress_duthost, prio=lossless_prio), 'Unable to enable ecn') - -config_result = config_ingress_lossless_buffer_alpha(host_ans=egress_duthost, - alpha_log2=3) - -pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') -config_result = config_ingress_lossless_buffer_alpha(host_ans=ingress_duthost, - alpha_log2=3) - -pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') - -# Get the ID of the port to test -port_id = get_dut_port_id(dut_hostname=egress_duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) - -pytest_assert(port_id is not None, - 'Failed to get ID for port {}'.format(dut_port)) - -speed_str = testbed_config.layer1[0].speed -speed_gbps = int(speed_str.split('_')[1]) - -# Generate base traffic config -port_id = 0 -logger.info("Generating base flow config") -snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - -logger.info("Setting test flow config params") -snappi_extra_params.traffic_flow_config.data_flow_config.update({ - "flow_name": DATA_FLOW_NAME, - "flow_rate_percent": 100, - "flow_delay_sec": DATA_START_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS - }) - -logger.info("Setting pause flow config params") -snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": EXP_DURATION_SEC, - "flow_rate_percent": None, - "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), - "flow_rate_bps": None, - "flow_pkt_size": 64, - "flow_pkt_count": None, - "flow_delay_sec": 0, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } + if is_bp_fabric_ecn_check_required: + if flow3_ecn == 0: + logging.info("ECN marking check failed on flow 3 on egress port") + return False # Flow 3 ECN marking failed + elif flow4_ecn == 0: + logging.info("ECN marking check failed on flow 4 on egress port") + return False # Flow 4 ECN marking failed + else: + logging.info("ECN marking check passed on both flow 3 and 4 on egress port") + return True # Both flows had ECN marked packets (success) + + pytest_assert(flow3_ecn > 0, + 'Must have ecn marked packets on flow 3{}'. + format(toggle_msg)) + + pytest_assert(flow4_ecn > 0, + 'Must have ecn marked packets on flow 4{}'. + format(toggle_msg)) + return True -# Generate traffic config of one test flow and one pause storm -logger.info("Generating test flows") -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=[lossless_prio], - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - number_of_streams=10) - -logger.info("Generating pause flows") -generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=[lossless_prio], - global_pause=False, - snappi_extra_params=snappi_extra_params) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -logger.info("Setting packet capture port to {}".format(testbed_config.ports[port_id].name)) -snappi_extra_params.packet_capture_ports = [testbed_config.ports[port_id].name] - -result = [] -logger.info("Running {} iteration(s)".format(iters)) -for i in range(iters): - logger.info("Running iteration {}".format(i)) - snappi_extra_params.packet_capture_file = "ECN_cap-{}".format(i) - logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) - - config_capture_pkt(testbed_config=testbed_config, - port_names=snappi_extra_params.packet_capture_ports, - capture_type=snappi_extra_params.packet_capture_type, - capture_name=snappi_extra_params.packet_capture_file) - - logger.info("Running traffic") - run_traffic(duthost=egress_duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=EXP_DURATION_SEC, - snappi_extra_params=snappi_extra_params) - - result.append(get_ipv4_pkts(snappi_extra_params.packet_capture_file + ".pcapng", protocol_num=17)) - -return result -``` -def toggle_dut_port_state(api): -\# Get the current configuration -config = api.get_config() -\# Collect all port names -port_names = \[port.name for port in config.ports\] -\# Create a control state object for all ports -cs = api.control_state() -\# Create a control state object for all ports -cs.choice = cs.PORT -cs.port.choice = cs.port.LINK -\# Apply the state to all ports -cs.link.port_names = port_names -\# Set all ports down (shut) -cs.port.link.state = cs.port.link.DOWN -api.set_control_state(cs) -logger.info("All Snappi ports are set to DOWN") -time.sleep(0.2) -\# Unshut all ports -cs.port.link.state = cs.port.link.UP -api.set_control_state(cs) -logger.info("All Snappi ports are set to UP") - -def \_generate_traffic_config(testbed_config, -snappi_extra_params, -port_config_list, -test_prio_list, -test_flow_percent, -prio_dscp_map, -number_of_streams=10, -congested=False): -TEST_FLOW_NAME = \['Test Flow 3', 'Test Flow 4'\] -DATA_FLOW_PKT_SIZE = 1350 -DATA_FLOW_DURATION_SEC = 2 -DATA_FLOW_DELAY_SEC = 1 - -``` -port_id = 0 -# Generate base traffic config -base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) -port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] -base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list2, - port_id=port_id) - -# Create a dictionary with priorities as keys and flow rates as values -flow_rate_dict = { - prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) -} - -snappi_extra_params.base_flow_config = base_flow_config1 - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[0], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } +def verify_ecn_counters_for_flow_percent( + ecn_counters, + test_flow_percent, + number_of_streams, + input_port_same_asic, + input_port_same_dut, + single_dut): -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=10) + # verify that each flow had packets + init_ctr_3, post_ctr_3 = ecn_counters[0] + init_ctr_4, post_ctr_4 = ecn_counters[1] + flow3_total = post_ctr_3['SAI_QUEUE_STAT_PACKETS'] - init_ctr_3['SAI_QUEUE_STAT_PACKETS'] -snappi_extra_params.base_flow_config = base_flow_config2 + drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_DROPPED_PACKETS'] + wred_drop_ctr_3 = post_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME[1], - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": flow_rate_dict, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } + drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_DROPPED_PACKETS'] + wred_drop_ctr_4 = post_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_DROPPED_PACKETS'] -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params, - congested=congested, - number_of_streams=10) -``` + pytest_assert(drop_ctr_3 == 0 and wred_drop_ctr_3 == 0, 'Queue 3 Drop not expected') -def run_ecn_marking_port_toggle_test( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -supervisor_dut=None, -is_bp_fabric_ecn_check_required=False, -snappi_extra_params=None): - -``` -""" -Run a ECN test -Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - supervisor_dut (obj): Supervisor DUT, if ECN check is required - is_bp_fabric_ecn_check_required (bool): Flag to indicate if BP fabric ECN check is required - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - -test_flow_percent = [99.98] * len(test_prio_list) - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -DATA_FLOW_DURATION_SEC = 2 -DATA_FLOW_DELAY_SEC = 1 - -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] - -duthost = egress_duthost - -tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost_1 = tx_port_1['duthost'] - -tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost_2 = tx_port_2['duthost'] - -# Append the duthost here for run_traffic to clear its counters -snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) -snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) -snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) - -# Find fabric mapping per ASIC instance -ingress_fabric_mapping_dict = {} -for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) - fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) - ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping - -egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) -egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) - -_generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -link_state_toggled = False - -# Function to clear ECN counters -def clear_ecn_counters(): - if is_bp_fabric_ecn_check_required: - snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) - clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list) + pytest_assert(drop_ctr_4 == 0 and wred_drop_ctr_4 == 0, 'Queue 4 Drop not expected') - for priority in test_prio_list: - get_npu_voq_queue_counters(duthost, dut_port, priority, True) + pytest_assert(flow3_total > 0, + 'Queue 3 counters at start {} at end {} did not increment'.format( + init_ctr_3['SAI_QUEUE_STAT_PACKETS'], post_ctr_3['SAI_QUEUE_STAT_PACKETS'])) -# Function to run traffic and check ECN marking -def run_traffic_and_check_ecn(): - """Run traffic and verify ECN marking""" - initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} + flow4_total = post_ctr_4['SAI_QUEUE_STAT_PACKETS'] - init_ctr_4['SAI_QUEUE_STAT_PACKETS'] - run_traffic( - duthost, api=api, config=testbed_config, data_flow_names=data_flow_names, - all_flow_names=all_flow_names, exp_dur_sec=DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params - ) + pytest_assert(flow4_total > 0, + 'Queue 4 counters at start {} at end {} did not increment'.format( + init_ctr_4['SAI_QUEUE_STAT_PACKETS'], post_ctr_4['SAI_QUEUE_STAT_PACKETS'])) - post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} - ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] + flow3_ecn = post_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_3['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + flow4_ecn = post_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] -\ + init_ctr_4['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - return verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required, link_state_toggled) + if sum(test_flow_percent) < 100: + pytest_assert( + flow3_ecn == 0, + 'Must have no ecn marked packets on flow 3 without congestion, percent {}'. + format(test_flow_percent)) + pytest_assert( + flow4_ecn == 0, + 'Must have no ecn marked packets on flow 4 without congestion, percent {}'. + format(test_flow_percent)) + elif sum(test_flow_percent) >= 100: + if test_flow_percent[0] > 50: + pytest_assert( + flow3_ecn > 0, + 'Must have ecn marked packets on flow 3, percent {}'. + format(test_flow_percent)) -def check_ecn_marking(): - """Check ECN marking before or after port toggle""" - clear_ecn_counters() - ecn_marking_verified_on_egress = run_traffic_and_check_ecn() + if test_flow_percent[1] > 50: + pytest_assert( + flow4_ecn > 0, + 'Must have ecn marked packets on flow 4, percent {}'. + format(test_flow_percent)) - if not ecn_marking_verified_on_egress: - if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list): - # Log PFC frame counts - for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - for priority in test_prio_list: - pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) - logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( - dut.hostname, tx_port['peer_port'], priority, pfc_count)) - pytest_assert(False, "No ECN marking in the data path") + if test_flow_percent[0] < 50: + pytest_assert( + flow3_ecn == 0, + 'Must not have ecn marked packets on flow 3, percent {}'. + format(test_flow_percent)) -# Initial ECN verification -check_ecn_marking() + if test_flow_percent[1] < 50: + pytest_assert( + flow4_ecn == 0, + 'Must not have ecn marked packets on flow 4, percent {}'. + format(test_flow_percent)) -# Toggle port state -toggle_dut_port_state(api) + if test_flow_percent[0] > 50 and test_flow_percent[1] > 50: + pytest_assert( + flow3_ecn > 0 and flow4_ecn > 0, + 'Must have ecn marked packets on flows 3, 4, percent {}'. + format(test_flow_percent)) + percent3_mark = round(float(flow3_ecn/flow3_total), 2) * 100 + percent4_mark = round(float(flow4_ecn/flow4_total), 2) * 100 + flow_mark_diff = int(abs(percent3_mark - percent4_mark)) + logging.info( + "Stream count {}, inputs on {} asic, inputs on {} dut, " + "flow 3 percent {}, ecn {}, flow 4 percent {}, ecn {}, " + "flow_mark_diff {}".format( + number_of_streams, + "same" if input_port_same_asic else "different", + "same" if input_port_same_dut else "different", + test_flow_percent[0], + flow3_ecn, + test_flow_percent[1], + flow4_ecn, + flow_mark_diff)) + if number_of_streams == 1 and input_port_same_asic and \ + (test_flow_percent[0] == test_flow_percent[1]): + pytest_assert( + flow_mark_diff <= 5, + "For flow rates {}: the flow marking deviation {} is more " + "than 5% tolerance: flow 3 ecn: {} flow 4 ecn: {}". + format( + test_flow_percent, + flow_mark_diff, + flow3_ecn, + flow4_ecn)) + # if number_of_streams > 1, the streams will be spread across voq from backplane ports with shallow + # occupancy. Restrict marking check to single dut in such a case (or relax marking check) + elif input_port_same_dut and (number_of_streams == 1 or (number_of_streams > 1 and single_dut)): + if test_flow_percent[0] > test_flow_percent[1]: + pytest_assert( + flow3_ecn > flow4_ecn, + "For flow percent {}, ecn count {} must be higher than " + "flow percent {}, ecn count {}".format( + test_flow_percent[0], + flow3_ecn, + test_flow_percent[1], + flow4_ecn)) + elif test_flow_percent[0] < test_flow_percent[1]: + pytest_assert( + flow3_ecn < flow4_ecn, + "For flow percent {}, ecn count {} must be lower than flow percent {}, ecn count {}". + format(test_flow_percent[0], flow3_ecn, test_flow_percent[1], flow4_ecn)) -link_state_toggled = True -# Post toggle ECN verification -check_ecn_marking() -``` +def run_ecn_test(api, + testbed_config, + port_config_list, + conn_data, + fanout_data, + dut_port, + lossless_prio, + prio_dscp_map, + iters, + snappi_extra_params=None): + """ + Run multidut ECN test + + Args: + api (obj): SNAPPI session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + lossless_prio (int): lossless priority + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + + Returns: + Return captured IP packets (list of list) + """ + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost = tx_port['duthost'] + + pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') + + logger.info("Stopping PFC watchdog") + stop_pfcwd(egress_duthost, rx_port['asic_value']) + stop_pfcwd(ingress_duthost, tx_port['asic_value']) + logger.info("Disabling packet aging if necessary") + disable_packet_aging(egress_duthost) + disable_packet_aging(ingress_duthost) + + # Configure WRED/ECN thresholds + logger.info("Configuring WRED and ECN thresholds") + config_result = config_wred(host_ans=egress_duthost, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) + pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + config_result = config_wred(host_ans=ingress_duthost, + kmin=snappi_extra_params.ecn_params["kmin"], + kmax=snappi_extra_params.ecn_params["kmax"], + pmax=snappi_extra_params.ecn_params["pmax"]) + pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + + # Enable ECN marking + logger.info("Enabling ECN markings") + pytest_assert(enable_ecn(host_ans=egress_duthost, prio=lossless_prio), 'Unable to enable ecn') + pytest_assert(enable_ecn(host_ans=ingress_duthost, prio=lossless_prio), 'Unable to enable ecn') + + config_result = config_ingress_lossless_buffer_alpha(host_ans=egress_duthost, + alpha_log2=3) + + pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') + config_result = config_ingress_lossless_buffer_alpha(host_ans=ingress_duthost, + alpha_log2=3) + + pytest_assert(config_result is True, 'Failed to configure PFC threshold to 8') + + # Get the ID of the port to test + port_id = get_dut_port_id(dut_hostname=egress_duthost.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) + + pytest_assert(port_id is not None, + 'Failed to get ID for port {}'.format(dut_port)) + + speed_str = testbed_config.layer1[0].speed + speed_gbps = int(speed_str.split('_')[1]) + + # Generate base traffic config + port_id = 0 + logger.info("Generating base flow config") + snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + logger.info("Setting test flow config params") + snappi_extra_params.traffic_flow_config.data_flow_config.update({ + "flow_name": DATA_FLOW_NAME, + "flow_rate_percent": 100, + "flow_delay_sec": DATA_START_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS + }) + + logger.info("Setting pause flow config params") + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": EXP_DURATION_SEC, + "flow_rate_percent": None, + "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": None, + "flow_delay_sec": 0, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } -def run_ecn_marking_test(api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -test_flow_percent, -number_of_streams, -input_port_same_asic, -input_port_same_dut, -single_dut, -snappi_extra_params=None): - -``` -""" -Run a ECN test -Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - -pytest_assert(len(test_flow_percent) == len(test_prio_list), - "The length of test_flow_percent must match the length of test_prio_list") - -DATA_FLOW_DURATION_SEC = 2 -DATA_FLOW_DELAY_SEC = 1 - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] - -duthost = egress_duthost - -init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -_generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map, - number_of_streams=number_of_streams) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -""" Run traffic """ -_tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, - snappi_extra_params=snappi_extra_params) - -post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) -post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) - -ecn_counters = [ - (init_ctr_3, post_ctr_3), - (init_ctr_4, post_ctr_4) -] - -verify_ecn_counters_for_flow_percent( - ecn_counters, - test_flow_percent, - number_of_streams, - input_port_same_asic, - input_port_same_dut, - single_dut) -``` + # Generate traffic config of one test flow and one pause storm + logger.info("Generating test flows") + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=[lossless_prio], + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + number_of_streams=10) -def run_ecn_marking_with_pfc_quanta_variance( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -test_ecn_config, -log_dir=None, -snappi_extra_params=None): + logger.info("Generating pause flows") + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=[lossless_prio], + global_pause=False, + snappi_extra_params=snappi_extra_params) -``` -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 1, 'Must have atleast two lossless priorities') + flows = testbed_config.flows -DATA_FLOW_PKT_SIZE = 1350 -DATA_FLOW_DURATION_SEC = 5 -DATA_FLOW_DELAY_SEC = 0 + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() + logger.info("Setting packet capture port to {}".format(testbed_config.ports[port_id].name)) + snappi_extra_params.packet_capture_ports = [testbed_config.ports[port_id].name] + + result = [] + logger.info("Running {} iteration(s)".format(iters)) + for i in range(iters): + logger.info("Running iteration {}".format(i)) + snappi_extra_params.packet_capture_file = "ECN_cap-{}".format(i) + logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) + + config_capture_pkt(testbed_config=testbed_config, + port_names=snappi_extra_params.packet_capture_ports, + capture_type=snappi_extra_params.packet_capture_type, + capture_name=snappi_extra_params.packet_capture_file) + + logger.info("Running traffic") + run_traffic(duthost=egress_duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=EXP_DURATION_SEC, + snappi_extra_params=snappi_extra_params) -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + result.append(get_ipv4_pkts(snappi_extra_params.packet_capture_file + ".pcapng", protocol_num=17)) -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] + return result -duthost = egress_duthost -port_id = 0 -# Generate base traffic config -base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) +def toggle_dut_port_state(api): + # Get the current configuration + config = api.get_config() + # Collect all port names + port_names = [port.name for port in config.ports] + # Create a control state object for all ports + cs = api.control_state() + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK + # Apply the state to all ports + cs.link.port_names = port_names + # Set all ports down (shut) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) + logger.info("All Snappi ports are set to DOWN") + time.sleep(0.2) + # Unshut all ports + cs.port.link.state = cs.port.link.UP + api.set_control_state(cs) + logger.info("All Snappi ports are set to UP") + + +def _generate_traffic_config(testbed_config, + snappi_extra_params, + port_config_list, + test_prio_list, + test_flow_percent, + prio_dscp_map, + number_of_streams=10, + congested=False): + TEST_FLOW_NAME = ['Test Flow 3', 'Test Flow 4'] + DATA_FLOW_PKT_SIZE = 1350 + DATA_FLOW_DURATION_SEC = 2 + DATA_FLOW_DELAY_SEC = 1 + + port_id = 0 + # Generate base traffic config + base_flow_config1 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + port_config_list2 = [x for x in port_config_list if x != base_flow_config1['tx_port_config']] + base_flow_config2 = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list2, + port_id=port_id) + + # Create a dictionary with priorities as keys and flow rates as values + flow_rate_dict = { + prio: round(flow / len(test_prio_list), 2) for prio, flow in zip(test_prio_list, test_flow_percent) + } -snappi_extra_params.base_flow_config = base_flow_config + snappi_extra_params.base_flow_config = base_flow_config1 + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME[0], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=10) + + snappi_extra_params.base_flow_config = base_flow_config2 -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": DATA_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": 50, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": DATA_FLOW_PKT_SIZE, - "flow_pkt_count": None, - "flow_delay_sec": DATA_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } + "flow_name": TEST_FLOW_NAME[1], + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": flow_rate_dict, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params, + congested=congested, + number_of_streams=10) -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=[test_prio_list[0]], - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) -PAUSE_FLOW_NAME = "Pause flow" +def run_ecn_marking_port_toggle_test( + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + supervisor_dut=None, + is_bp_fabric_ecn_check_required=False, + snappi_extra_params=None): + + """ + Run a ECN test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + supervisor_dut (obj): Supervisor DUT, if ECN check is required + is_bp_fabric_ecn_check_required (bool): Flag to indicate if BP fabric ECN check is required + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + + test_flow_percent = [99.98] * len(test_prio_list) + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + DATA_FLOW_DURATION_SEC = 2 + DATA_FLOW_DELAY_SEC = 1 + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + + duthost = egress_duthost + + tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost_1 = tx_port_1['duthost'] + + tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost_2 = tx_port_2['duthost'] + + # Append the duthost here for run_traffic to clear its counters + snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) + snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) + snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) + + # Find fabric mapping per ASIC instance + ingress_fabric_mapping_dict = {} + for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) + fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) + ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping + + egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) + egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) + + _generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map) -# 10 PFC frames at 2 frames/sec. -# The pauses caused by each PFC frame do not overlap. + flows = testbed_config.flows -PAUSE_FLOW_PKT_COUNT = 10 -PAUSE_FLOW_DELAY_SEC = 1 + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] -if snappi_extra_params.traffic_flow_config.pause_flow_config is None: - snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": None, - "flow_rate_percent": None, - "flow_rate_pps": 2, - "flow_rate_bps": None, - "flow_pkt_size": 64, - "flow_pkt_count": PAUSE_FLOW_PKT_COUNT, - "flow_delay_sec": PAUSE_FLOW_DELAY_SEC, - "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS - } + link_state_toggled = False -asic_namespace = None -if duthost.is_multi_asic: - asic = duthost.get_port_asic_instance(dut_port) - asic_namespace = asic.namespace -gmin, gmax, gdrop = test_ecn_config + # Function to clear ECN counters + def clear_ecn_counters(): + if is_bp_fabric_ecn_check_required: + snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) + clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list) -# Configure WRED/ECN thresholds -logger.info("Configuring WRED and ECN thresholds gmin {}MB gmax {}MB gdrop {}%".format(gmin, gmax, gdrop)) + for priority in test_prio_list: + get_npu_voq_queue_counters(duthost, dut_port, priority, True) -config_result = config_wred(host_ans=duthost, - kmin=gmin * 1024 * 1024, - kmax=gmax * 1024 * 1024, - pmax=0, - kdrop=gdrop, - asic_value=asic_namespace) + # Function to run traffic and check ECN marking + def run_traffic_and_check_ecn(): + """Run traffic and verify ECN marking""" + initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} -pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + run_traffic( + duthost, api=api, config=testbed_config, data_flow_names=data_flow_names, + all_flow_names=all_flow_names, exp_dur_sec=DATA_FLOW_DURATION_SEC + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params + ) -start_quanta = 500 -end_quanta = 65000 -n = 15 # Number of quanta values + post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] -step = (end_quanta - start_quanta) // (n - 1) -# Generate all but the last value -pause_quanta_list = [start_quanta + i * step for i in range(n - 1)] -# The last value is exactly `end_quanta` -pause_quanta_list.append(end_quanta) + return verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required, link_state_toggled) -logging.info("PFC quanta list: {}".format(pause_quanta_list)) + def check_ecn_marking(): + """Check ECN marking before or after port toggle""" + clear_ecn_counters() + ecn_marking_verified_on_egress = run_traffic_and_check_ecn() -_ = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0], True) -results = [] -for quanta in pause_quanta_list: - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_quanta"] = quanta + if not ecn_marking_verified_on_egress: + if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list): + # Log PFC frame counts + for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + for priority in test_prio_list: + pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) + logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( + dut.hostname, tx_port['peer_port'], priority, pfc_count)) + pytest_assert(False, "No ECN marking in the data path") - # Remove any existing pause flow - for index, flow in enumerate(testbed_config.flows): - if PAUSE_FLOW_NAME in flow.name: - testbed_config.flows.remove(index) + # Initial ECN verification + check_ecn_marking() + + # Toggle port state + toggle_dut_port_state(api) + + link_state_toggled = True + + # Post toggle ECN verification + check_ecn_marking() - # Generate pause flow config - generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=[test_prio_list[0]], - global_pause=False, - snappi_extra_params=snappi_extra_params) + +def run_ecn_marking_test(api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + test_flow_percent, + number_of_streams, + input_port_same_asic, + input_port_same_dut, + single_dut, + snappi_extra_params=None): + + """ + Run a ECN test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + + pytest_assert(len(test_flow_percent) == len(test_prio_list), + "The length of test_flow_percent must match the length of test_prio_list") + + DATA_FLOW_DURATION_SEC = 2 + DATA_FLOW_DELAY_SEC = 1 + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + + duthost = egress_duthost + + init_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + init_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) + + _generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map, + number_of_streams=number_of_streams) flows = testbed_config.flows @@ -939,159 +765,313 @@ def run_ecn_marking_with_pfc_quanta_variance( DATA_FLOW_DELAY_SEC, snappi_extra_params=snappi_extra_params) - ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) - stats_only = {key: ctr_3[key] for key in ctr_3['stats_name']} - results.append((quanta, stats_only)) - -file_name = "xoff_quanta_variance_results_{}_{}_{}.csv".format(gmin, gmax, gdrop) -if log_dir: - file_name = os.path.join(log_dir, file_name) - -with open(file_name, 'w', newline='') as csvfile: - if results: - first_ctr = results[0][1] - fieldnames = ['quanta'] + list(first_ctr.keys()) + ['AVERAGE_ECN_MARKING'] - - writer = csv.DictWriter(csvfile, fieldnames=fieldnames) - writer.writeheader() - - prev_ecn_marked = 0 - for quanta, ctr in results: - row = {'quanta': quanta} - row.update(ctr) - current_ecn_marked = ctr.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) - average_ecn_marking = round((current_ecn_marked - prev_ecn_marked) / PAUSE_FLOW_PKT_COUNT) - row['AVERAGE_ECN_MARKING'] = average_ecn_marking - prev_ecn_marked = current_ecn_marked - writer.writerow(row) - -for i in range(len(results) - 1): - ecn_i = results[i][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - ecn_i_plus_1 = results[i + 1][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] - - if ecn_i > 0: - pytest_assert(ecn_i_plus_1 > ecn_i, - "ecn marked {} at quanta {} should be less than ecn marked {} at quanta {}". - format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) - else: - pytest_assert(ecn_i_plus_1 >= ecn_i, - "ecn marked {} at quanta {} should not be greater than ecn marked {} at quanta {}". - format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) -``` + post_ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + post_ctr_4 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[1]) -def run_ecn_marking_ect_marked_pkts( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -supervisor_dut=None, -is_bp_fabric_ecn_check_required=False, -snappi_extra_params=None): - -``` -""" -Run a ECN test on congestion marker pkts -Args: - api (obj): snappi session - testbed_config (obj): testbed L1/L2/L3 configuration - port_config_list (list): list of port configuration - conn_data (dict): the dictionary returned by conn_graph_fact. - fanout_data (dict): the dictionary returned by fanout_graph_fact. - dut_port (str): DUT port to test - test_prio_list (list): priorities of test flows - prio_dscp_map (dict): Priority vs. DSCP map (key = priority). - snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic -Returns: - N/A -""" - -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') -pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') - -test_flow_percent = [99.98] * len(test_prio_list) - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -DATA_FLOW_DURATION_SEC = 2 -DATA_FLOW_DELAY_SEC = 1 - -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -egress_duthost = rx_port['duthost'] -duthost = egress_duthost - -tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost_1 = tx_port_1['duthost'] - -tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] -ingress_duthost_2 = tx_port_2['duthost'] - -# Append the duthost here for run_traffic to clear its counters -snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) -snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) -snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) - -# Find fabric mapping per ASIC instance -ingress_fabric_mapping_dict = {} -for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) - fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) - ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping - -egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) -egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) - -if is_bp_fabric_ecn_check_required: - snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) - clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, - egress_fabric_mapping, supervisor_dut, test_prio_list) + ecn_counters = [ + (init_ctr_3, post_ctr_3), + (init_ctr_4, post_ctr_4) + ] - for priority in test_prio_list: - get_npu_voq_queue_counters(duthost, dut_port, priority, True) - -initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} - -_generate_traffic_config(testbed_config, snappi_extra_params, - port_config_list, test_prio_list, - test_flow_percent, prio_dscp_map, - congested=True) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -""" Run traffic """ -_, _, _ = run_traffic( - duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - DATA_FLOW_DELAY_SEC, + verify_ecn_counters_for_flow_percent( + ecn_counters, + test_flow_percent, + number_of_streams, + input_port_same_asic, + input_port_same_dut, + single_dut) + + +def run_ecn_marking_with_pfc_quanta_variance( + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + test_ecn_config, + log_dir=None, + snappi_extra_params=None): + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 1, 'Must have atleast two lossless priorities') + + DATA_FLOW_PKT_SIZE = 1350 + DATA_FLOW_DURATION_SEC = 5 + DATA_FLOW_DELAY_SEC = 0 + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + + duthost = egress_duthost + + port_id = 0 + # Generate base traffic config + base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + snappi_extra_params.base_flow_config = base_flow_config + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": DATA_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": 50, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": DATA_FLOW_PKT_SIZE, + "flow_pkt_count": None, + "flow_delay_sec": DATA_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=[test_prio_list[0]], + prio_dscp_map=prio_dscp_map, snappi_extra_params=snappi_extra_params) -post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) - for priority in test_prio_list} -ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] + PAUSE_FLOW_NAME = "Pause flow" + + # 10 PFC frames at 2 frames/sec. + # The pauses caused by each PFC frame do not overlap. + + PAUSE_FLOW_PKT_COUNT = 10 + PAUSE_FLOW_DELAY_SEC = 1 + + if snappi_extra_params.traffic_flow_config.pause_flow_config is None: + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": None, + "flow_rate_percent": None, + "flow_rate_pps": 2, + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": PAUSE_FLOW_PKT_COUNT, + "flow_delay_sec": PAUSE_FLOW_DELAY_SEC, + "flow_traffic_type": traffic_flow_mode.FIXED_PACKETS + } + + asic_namespace = None + if duthost.is_multi_asic: + asic = duthost.get_port_asic_instance(dut_port) + asic_namespace = asic.namespace + gmin, gmax, gdrop = test_ecn_config + + # Configure WRED/ECN thresholds + logger.info("Configuring WRED and ECN thresholds gmin {}MB gmax {}MB gdrop {}%".format(gmin, gmax, gdrop)) + + config_result = config_wred(host_ans=duthost, + kmin=gmin * 1024 * 1024, + kmax=gmax * 1024 * 1024, + pmax=0, + kdrop=gdrop, + asic_value=asic_namespace) + + pytest_assert(config_result is True, 'Failed to configure WRED/ECN at the DUT') + + start_quanta = 500 + end_quanta = 65000 + n = 15 # Number of quanta values + + step = (end_quanta - start_quanta) // (n - 1) + # Generate all but the last value + pause_quanta_list = [start_quanta + i * step for i in range(n - 1)] + # The last value is exactly `end_quanta` + pause_quanta_list.append(end_quanta) + + logging.info("PFC quanta list: {}".format(pause_quanta_list)) + + _ = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0], True) + results = [] + for quanta in pause_quanta_list: + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_quanta"] = quanta + + # Remove any existing pause flow + for index, flow in enumerate(testbed_config.flows): + if PAUSE_FLOW_NAME in flow.name: + testbed_config.flows.remove(index) + + # Generate pause flow config + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=[test_prio_list[0]], + global_pause=False, + snappi_extra_params=snappi_extra_params) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + """ Run traffic """ + _tgen_flow_stats, _switch_flow_stats, _in_flight_flow_metrics = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + + ctr_3 = get_npu_voq_queue_counters(duthost, dut_port, test_prio_list[0]) + stats_only = {key: ctr_3[key] for key in ctr_3['stats_name']} + results.append((quanta, stats_only)) + + file_name = "xoff_quanta_variance_results_{}_{}_{}.csv".format(gmin, gmax, gdrop) + if log_dir: + file_name = os.path.join(log_dir, file_name) + + with open(file_name, 'w', newline='') as csvfile: + if results: + first_ctr = results[0][1] + fieldnames = ['quanta'] + list(first_ctr.keys()) + ['AVERAGE_ECN_MARKING'] + + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + prev_ecn_marked = 0 + for quanta, ctr in results: + row = {'quanta': quanta} + row.update(ctr) + current_ecn_marked = ctr.get('SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS', 0) + average_ecn_marking = round((current_ecn_marked - prev_ecn_marked) / PAUSE_FLOW_PKT_COUNT) + row['AVERAGE_ECN_MARKING'] = average_ecn_marking + prev_ecn_marked = current_ecn_marked + writer.writerow(row) + + for i in range(len(results) - 1): + ecn_i = results[i][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + ecn_i_plus_1 = results[i + 1][1]['SAI_QUEUE_STAT_WRED_ECN_MARKED_PACKETS'] + + if ecn_i > 0: + pytest_assert(ecn_i_plus_1 > ecn_i, + "ecn marked {} at quanta {} should be less than ecn marked {} at quanta {}". + format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) + else: + pytest_assert(ecn_i_plus_1 >= ecn_i, + "ecn marked {} at quanta {} should not be greater than ecn marked {} at quanta {}". + format(ecn_i, results[i][0], ecn_i_plus_1, results[i+1][0])) -ecn_marking_verified_on_egress = verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required) -if not ecn_marking_verified_on_egress: - if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, - supervisor_dut, test_prio_list): - # Log PFC frame counts - for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: - for priority in test_prio_list: - pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) - logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( - dut.hostname, tx_port['peer_port'], priority, pfc_count)) - pytest_assert(False, "No ECN marking in the data path") -``` +def run_ecn_marking_ect_marked_pkts( + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + supervisor_dut=None, + is_bp_fabric_ecn_check_required=False, + snappi_extra_params=None): + + """ + Run a ECN test on congestion marker pkts + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + dut_port (str): DUT port to test + test_prio_list (list): priorities of test flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + Returns: + N/A + """ + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + pytest_assert(len(test_prio_list) >= 2, 'Must have atleast two lossless priorities') + + test_flow_percent = [99.98] * len(test_prio_list) + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + DATA_FLOW_DURATION_SEC = 2 + DATA_FLOW_DELAY_SEC = 1 + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + duthost = egress_duthost + + tx_port_1 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost_1 = tx_port_1['duthost'] + + tx_port_2 = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost_2 = tx_port_2['duthost'] + + # Append the duthost here for run_traffic to clear its counters + snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_1) + snappi_extra_params.multi_dut_params.ingress_duthosts.append(ingress_duthost_2) + snappi_extra_params.multi_dut_params.egress_duthosts.append(egress_duthost) + + # Find fabric mapping per ASIC instance + ingress_fabric_mapping_dict = {} + for ingress_duthost, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + asic_instance = ingress_duthost.get_port_asic_instance(tx_port['peer_port']) + fabric_mapping = get_fabric_mapping(ingress_duthost, asic_instance) + ingress_fabric_mapping_dict.setdefault(ingress_duthost, {})[asic_instance] = fabric_mapping + + egress_asic_instance = egress_duthost.get_port_asic_instance(rx_port['peer_port']) + egress_fabric_mapping = get_fabric_mapping(egress_duthost, egress_asic_instance) + + if is_bp_fabric_ecn_check_required: + snappi_extra_params.multi_dut_params.ingress_duthosts.append(supervisor_dut) + clear_bp_fabric_queue_counters(ingress_fabric_mapping_dict, + egress_fabric_mapping, supervisor_dut, test_prio_list) + + for priority in test_prio_list: + get_npu_voq_queue_counters(duthost, dut_port, priority, True) + + initial_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + + _generate_traffic_config(testbed_config, snappi_extra_params, + port_config_list, test_prio_list, + test_flow_percent, prio_dscp_map, + congested=True) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + """ Run traffic """ + _, _, _ = run_traffic( + duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + DATA_FLOW_DELAY_SEC, + snappi_extra_params=snappi_extra_params) + + post_counters = {priority: get_npu_voq_queue_counters(duthost, dut_port, priority) + for priority in test_prio_list} + ecn_counters = [(initial_counters[p], post_counters[p]) for p in test_prio_list] + + ecn_marking_verified_on_egress = verify_ecn_counters(ecn_counters, is_bp_fabric_ecn_check_required) + if not ecn_marking_verified_on_egress: + if not check_bp_fabric_ecn_marking(ingress_fabric_mapping_dict, egress_fabric_mapping, + supervisor_dut, test_prio_list): + # Log PFC frame counts + for dut, tx_port in [(ingress_duthost_1, tx_port_1), (ingress_duthost_2, tx_port_2)]: + for priority in test_prio_list: + pfc_count = get_pfc_frame_count(dut, tx_port['peer_port'], priority, True) + logging.info("PFC Tx frame count for DUT {}, Port {}, Priority {}: {}".format( + dut.hostname, tx_port['peer_port'], priority, pfc_count)) + + pytest_assert(False, "No ECN marking in the data path") From 9e623df5f14bcc5003e394bff2c4ec533cc4614f Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Thu, 15 May 2025 09:29:52 -0700 Subject: [PATCH 14/17] Update helper.py formatted helper file --- tests/snappi_tests/pfc/files/helper.py | 806 ++++++++++++------------- 1 file changed, 402 insertions(+), 404 deletions(-) diff --git a/tests/snappi_tests/pfc/files/helper.py b/tests/snappi_tests/pfc/files/helper.py index c5dd02500c0..7fee5274b9a 100644 --- a/tests/snappi_tests/pfc/files/helper.py +++ b/tests/snappi_tests/pfc/files/helper.py @@ -4,25 +4,26 @@ from tests.common.cisco_data import is_cisco_device from tests.common.helpers.assertions import pytest_assert from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ -fanout_graph_facts # noqa F401 + fanout_graph_facts # noqa F401 from tests.common.snappi_tests.common_helpers import pfc_class_enable_vector,\ -get_lossless_buffer_size, get_pg_dropped_packets,\ -disable_packet_aging, enable_packet_aging, sec_to_nanosec,\ -get_pfc_frame_count, packet_capture, config_capture_pkt,\ -traffic_flow_mode, calc_pfc_pause_flow_rate, get_tx_frame_count # noqa F401 + get_lossless_buffer_size, get_pg_dropped_packets,\ + disable_packet_aging, enable_packet_aging, sec_to_nanosec,\ + get_pfc_frame_count, packet_capture, config_capture_pkt,\ + traffic_flow_mode, calc_pfc_pause_flow_rate, get_tx_frame_count # noqa F401 from tests.common.snappi_tests.port import select_ports, select_tx_port # noqa F401 from tests.common.snappi_tests.snappi_helpers import get_dut_port_id, wait_for_arp # noqa F401 from tests.common.snappi_tests.traffic_generation import setup_base_traffic_config, generate_test_flows, \ -generate_background_flows, generate_pause_flows, run_traffic, verify_pause_flow, verify_basic_test_flow, \ -verify_background_flow, verify_pause_frame_count_dut, verify_egress_queue_frame_count, \ -verify_in_flight_buffer_pkts, verify_unset_cev_pause_frame_count, verify_tx_frame_count_dut, \ -verify_rx_frame_count_dut + generate_background_flows, generate_pause_flows, run_traffic, verify_pause_flow, verify_basic_test_flow, \ + verify_background_flow, verify_pause_frame_count_dut, verify_egress_queue_frame_count, \ + verify_in_flight_buffer_pkts, verify_unset_cev_pause_frame_count, verify_tx_frame_count_dut, \ + verify_rx_frame_count_dut from tests.common.snappi_tests.snappi_test_params import SnappiTestParams from tests.common.snappi_tests.read_pcap import validate_pfc_frame, validate_pfc_frame_cisco + logger = logging.getLogger(__name__) -dut_port_config = \[\] +dut_port_config = [] PAUSE_FLOW_NAME = 'Pause Storm' TEST_FLOW_NAME = 'Test Flow' TEST_FLOW_AGGR_RATE_PERCENT = 45 @@ -37,408 +38,405 @@ CONTINUOUS_MODE = -5 ANSIBLE_POLL_DELAY_SEC = 4 -def run_pfc_test(api, -testbed_config, -port_config_list, -conn_data, -fanout_data, -global_pause, -pause_prio_list, -test_prio_list, -bg_prio_list, -prio_dscp_map, -test_traffic_pause, -duthost=None, -dut_port=None, -test_flow_is_lossless=True, -snappi_extra_params=None, -flow_factor=1): -""" -Run a multidut PFC test -Args: -api (obj): snappi session -testbed_config (obj): testbed L1/L2/L3 configuration -port_config_list (list): list of port configuration -conn_data (dict): the dictionary returned by conn_graph_fact. -fanout_data (dict): the dictionary returned by fanout_graph_fact. -duthost (Ansible host instance): device under test -dut_port (str): DUT port to test -global_pause (bool): if pause frame is IEEE 802.3X pause -pause_prio_list (list): priorities to pause for pause frames -test_prio_list (list): priorities of test flows -bg_prio_list (list): priorities of background flows -prio_dscp_map (dict): Priority vs. DSCP map (key = priority). -test_traffic_pause (bool): if test flows are expected to be paused -snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic - -``` -Returns: - N/A -""" - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -# Traffic flow: -# tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) - -# initialize the (duthost, port) set. - -rx_port = {} -egress_duthost = duthost - -tx_port = {} -ingress_duthost = duthost - -if not duthost: - rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] - egress_duthost = rx_port['duthost'] - - tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] - ingress_duthost = tx_port['duthost'] -pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') - -global DATA_FLOW_DURATION_SEC -global data_flow_delay_sec +def run_pfc_test(api, + testbed_config, + port_config_list, + conn_data, + fanout_data, + global_pause, + pause_prio_list, + test_prio_list, + bg_prio_list, + prio_dscp_map, + test_traffic_pause, + duthost=None, + dut_port=None, + test_flow_is_lossless=True, + snappi_extra_params=None, + flow_factor=1): + """ + Run a multidut PFC test + Args: + api (obj): snappi session + testbed_config (obj): testbed L1/L2/L3 configuration + port_config_list (list): list of port configuration + conn_data (dict): the dictionary returned by conn_graph_fact. + fanout_data (dict): the dictionary returned by fanout_graph_fact. + duthost (Ansible host instance): device under test + dut_port (str): DUT port to test + global_pause (bool): if pause frame is IEEE 802.3X pause + pause_prio_list (list): priorities to pause for pause frames + test_prio_list (list): priorities of test flows + bg_prio_list (list): priorities of background flows + prio_dscp_map (dict): Priority vs. DSCP map (key = priority). + test_traffic_pause (bool): if test flows are expected to be paused + snappi_extra_params (SnappiTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() + + # Traffic flow: + # tx_port (TGEN) --- ingress DUT --- egress DUT --- rx_port (TGEN) + + # initialize the (duthost, port) set. + + rx_port = {} + egress_duthost = duthost + + tx_port = {} + ingress_duthost = duthost + + if not duthost: + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + egress_duthost = rx_port['duthost'] + + tx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[1] + ingress_duthost = tx_port['duthost'] + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + + global DATA_FLOW_DURATION_SEC + global data_flow_delay_sec + + # Port id of Rx port for traffic config + port_id = 0 + + if dut_port and duthost: + port_id = get_dut_port_id(dut_hostname=duthost.hostname, + dut_port=dut_port, + conn_data=conn_data, + fanout_data=fanout_data) + + # Rate percent must be an integer + bg_flow_rate_percent = int((BG_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(bg_prio_list)) + test_flow_rate_percent = int((TEST_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(test_prio_list)) + + # Generate base traffic config + snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + speed_str = testbed_config.layer1[0].speed + speed_gbps = int(float(speed_str.split('_')[1])) + + if snappi_extra_params.headroom_test_params is not None: + DATA_FLOW_DURATION_SEC += 10 + data_flow_delay_sec += 2 + + # Set up pfc delay parameter + l1_config = testbed_config.layer1[0] + pfc = l1_config.flow_control.ieee_802_1qbb + pfc.pfc_delay = snappi_extra_params.headroom_test_params[0] + + if snappi_extra_params.poll_device_runtime: + # If the switch needs to be polled as traffic is running for stats, + # then the test runtime needs to be increased for the polling delay + DATA_FLOW_DURATION_SEC += ANSIBLE_POLL_DELAY_SEC + data_flow_delay_sec = ANSIBLE_POLL_DELAY_SEC + + if snappi_extra_params.packet_capture_type != packet_capture.NO_CAPTURE: + # Setup capture config + if snappi_extra_params.is_snappi_ingress_port_cap: + # packet capture is required on the ingress snappi port + snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["rx_port_name"]] + else: + # packet capture will be on the egress snappi port + snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["tx_port_name"]] + + snappi_extra_params.packet_capture_file = snappi_extra_params.packet_capture_type.value + + config_capture_pkt(testbed_config=testbed_config, + port_names=snappi_extra_params.packet_capture_ports, + capture_type=snappi_extra_params.packet_capture_type, + capture_name=snappi_extra_params.packet_capture_file) + logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + if snappi_extra_params.traffic_flow_config.background_flow_config is None and \ + snappi_extra_params.gen_background_traffic: + snappi_extra_params.traffic_flow_config.background_flow_config = { + "flow_name": BG_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": bg_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + if snappi_extra_params.traffic_flow_config.pause_flow_config is None: + snappi_extra_params.traffic_flow_config.pause_flow_config = { + "flow_name": PAUSE_FLOW_NAME, + "flow_dur_sec": None, + "flow_rate_percent": None, + "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), + "flow_rate_bps": None, + "flow_pkt_size": 64, + "flow_pkt_count": None, + "flow_delay_sec": 0, + "flow_traffic_type": traffic_flow_mode.CONTINUOUS + } + + if snappi_extra_params.packet_capture_type == packet_capture.PFC_CAPTURE: + # PFC pause frame capture is requested + valid_pfc_frame_test = True + else: + # PFC pause frame capture is not requested + valid_pfc_frame_test = False + + if valid_pfc_frame_test and not is_cisco_device(egress_duthost): + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_dur_sec"] = DATA_FLOW_DURATION_SEC + \ + data_flow_delay_sec + SNAPPI_POLL_DELAY_SEC + PAUSE_FLOW_DUR_BASE_SEC + snappi_extra_params.traffic_flow_config.pause_flow_config["flow_traffic_type"] = \ + traffic_flow_mode.FIXED_DURATION + + no_of_streams = 1 + if egress_duthost.facts['asic_type'] == "cisco-8000": + if not test_flow_is_lossless: + no_of_streams = 6 + + # Generate test flow config + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + number_of_streams=no_of_streams, + snappi_extra_params=snappi_extra_params) + + if snappi_extra_params.gen_background_traffic: + # Generate background flow config + generate_background_flows(testbed_config=testbed_config, + bg_flow_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) + + # Generate pause storm config + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=pause_prio_list, + global_pause=global_pause, + snappi_extra_params=snappi_extra_params) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + # Clear PFC, queue and interface counters before traffic run + duthost = egress_duthost + + for dut in [egress_duthost, ingress_duthost]: + dut.command("pfcstat -c") + time.sleep(1) + dut.command("sonic-clear queuecounters") + time.sleep(1) + dut.command("sonic-clear counters") + time.sleep(1) + + """ Run traffic """ + tgen_flow_stats, switch_flow_stats, in_flight_flow_metrics = run_traffic(duthost=duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + data_flow_delay_sec, + snappi_extra_params=snappi_extra_params) + + # Reset pfc delay parameter + pfc = testbed_config.layer1[0].flow_control.ieee_802_1qbb + pfc.pfc_delay = 0 + + # Verify PFC pause frames + if valid_pfc_frame_test: + if not is_cisco_device(duthost): + is_valid_pfc_frame, error_msg = validate_pfc_frame(snappi_extra_params.packet_capture_file + ".pcapng") + else: + is_valid_pfc_frame, error_msg = validate_pfc_frame_cisco( + snappi_extra_params.packet_capture_file + ".pcapng") + pytest_assert(is_valid_pfc_frame, error_msg) + return + + # Verify pause flows + verify_pause_flow(flow_metrics=tgen_flow_stats, + pause_flow_name=PAUSE_FLOW_NAME) + + if snappi_extra_params.gen_background_traffic: + # Verify background flows + verify_background_flow(flow_metrics=tgen_flow_stats, + speed_gbps=speed_gbps, + tolerance=TOLERANCE_THRESHOLD, + snappi_extra_params=snappi_extra_params) + + # Verify basic test flows metrics from ixia + verify_basic_test_flow(flow_metrics=tgen_flow_stats, + speed_gbps=speed_gbps, + tolerance=TOLERANCE_THRESHOLD, + test_flow_pause=test_traffic_pause, + snappi_extra_params=snappi_extra_params) -# Port id of Rx port for traffic config -port_id = 0 + # Verify PFC pause frame count on the DUT + verify_pause_frame_count_dut(rx_dut=ingress_duthost, + tx_dut=egress_duthost, + test_traffic_pause=test_traffic_pause, + global_pause=global_pause, + snappi_extra_params=snappi_extra_params) + + # Verify in flight TX lossless packets do not leave the DUT when traffic is expected + # to be paused, or leave the DUT when the traffic is not expected to be paused + # Verifying the packets on DUT egress, especially for multi line card scenario + verify_egress_queue_frame_count(duthost=egress_duthost, + switch_flow_stats=switch_flow_stats, + test_traffic_pause=test_traffic_pause, + snappi_extra_params=snappi_extra_params) -if dut_port and duthost: - port_id = get_dut_port_id(dut_hostname=duthost.hostname, - dut_port=dut_port, - conn_data=conn_data, - fanout_data=fanout_data) + if test_traffic_pause: + # Verify in flight TX packets count relative to switch buffer size + verify_in_flight_buffer_pkts(egress_duthost=egress_duthost, + ingress_duthost=ingress_duthost, + flow_metrics=in_flight_flow_metrics, + snappi_extra_params=snappi_extra_params, + asic_value=tx_port.get('asic_value')) + else: + # Verify zero pause frames are counted when the PFC class enable vector is not set + verify_unset_cev_pause_frame_count(duthost=duthost, + snappi_extra_params=snappi_extra_params) -# Rate percent must be an integer -bg_flow_rate_percent = int((BG_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(bg_prio_list)) -test_flow_rate_percent = int((TEST_FLOW_AGGR_RATE_PERCENT / flow_factor) / len(test_prio_list)) + if test_traffic_pause and not snappi_extra_params.gen_background_traffic: + # Verify TX frame count on the DUT when traffic is expected to be paused + # and only test traffic flows are generated + verify_tx_frame_count_dut(duthost=egress_duthost, + api=api, + snappi_extra_params=snappi_extra_params) -# Generate base traffic config -snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) + # Verify TX frame count on the DUT when traffic is expected to be paused + # and only test traffic flows are generated + verify_rx_frame_count_dut(duthost=ingress_duthost, + api=api, + snappi_extra_params=snappi_extra_params) -speed_str = testbed_config.layer1[0].speed -speed_gbps = int(float(speed_str.split('_')[1])) -if snappi_extra_params.headroom_test_params is not None: - DATA_FLOW_DURATION_SEC += 10 - data_flow_delay_sec += 2 +def run_tx_drop_counter( + api, + testbed_config, + port_config_list, + dut_port, + test_prio_list, + prio_dscp_map, + snappi_extra_params=None): - # Set up pfc delay parameter - l1_config = testbed_config.layer1[0] - pfc = l1_config.flow_control.ieee_802_1qbb - pfc.pfc_delay = snappi_extra_params.headroom_test_params[0] + pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') -if snappi_extra_params.poll_device_runtime: - # If the switch needs to be polled as traffic is running for stats, - # then the test runtime needs to be increased for the polling delay - DATA_FLOW_DURATION_SEC += ANSIBLE_POLL_DELAY_SEC - data_flow_delay_sec = ANSIBLE_POLL_DELAY_SEC + if snappi_extra_params is None: + snappi_extra_params = SnappiTestParams() -if snappi_extra_params.packet_capture_type != packet_capture.NO_CAPTURE: - # Setup capture config - if snappi_extra_params.is_snappi_ingress_port_cap: - # packet capture is required on the ingress snappi port - snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["rx_port_name"]] - else: - # packet capture will be on the egress snappi port - snappi_extra_params.packet_capture_ports = [snappi_extra_params.base_flow_config["tx_port_name"]] - - snappi_extra_params.packet_capture_file = snappi_extra_params.packet_capture_type.value - - config_capture_pkt(testbed_config=testbed_config, - port_names=snappi_extra_params.packet_capture_ports, - capture_type=snappi_extra_params.packet_capture_type, - capture_name=snappi_extra_params.packet_capture_file) - logger.info("Packet capture file: {}.pcapng".format(snappi_extra_params.packet_capture_file)) - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - -if snappi_extra_params.traffic_flow_config.background_flow_config is None and \ - snappi_extra_params.gen_background_traffic: - snappi_extra_params.traffic_flow_config.background_flow_config = { - "flow_name": BG_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": bg_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - -if snappi_extra_params.traffic_flow_config.pause_flow_config is None: - snappi_extra_params.traffic_flow_config.pause_flow_config = { - "flow_name": PAUSE_FLOW_NAME, - "flow_dur_sec": None, - "flow_rate_percent": None, - "flow_rate_pps": calc_pfc_pause_flow_rate(speed_gbps), - "flow_rate_bps": None, - "flow_pkt_size": 64, - "flow_pkt_count": None, - "flow_delay_sec": 0, - "flow_traffic_type": traffic_flow_mode.CONTINUOUS - } - -if snappi_extra_params.packet_capture_type == packet_capture.PFC_CAPTURE: - # PFC pause frame capture is requested - valid_pfc_frame_test = True -else: - # PFC pause frame capture is not requested - valid_pfc_frame_test = False - -if valid_pfc_frame_test and not is_cisco_device(egress_duthost): - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_dur_sec"] = DATA_FLOW_DURATION_SEC + \ - data_flow_delay_sec + SNAPPI_POLL_DELAY_SEC + PAUSE_FLOW_DUR_BASE_SEC - snappi_extra_params.traffic_flow_config.pause_flow_config["flow_traffic_type"] = \ - traffic_flow_mode.FIXED_DURATION - -no_of_streams = 1 -if egress_duthost.facts['asic_type'] == "cisco-8000": - if not test_flow_is_lossless: - no_of_streams = 6 - -# Generate test flow config -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - number_of_streams=no_of_streams, - snappi_extra_params=snappi_extra_params) - -if snappi_extra_params.gen_background_traffic: - # Generate background flow config - generate_background_flows(testbed_config=testbed_config, - bg_flow_prio_list=bg_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) - -# Generate pause storm config -generate_pause_flows(testbed_config=testbed_config, - pause_prio_list=pause_prio_list, - global_pause=global_pause, - snappi_extra_params=snappi_extra_params) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -# Clear PFC, queue and interface counters before traffic run -duthost = egress_duthost - -for dut in [egress_duthost, ingress_duthost]: - dut.command("pfcstat -c") - time.sleep(1) - dut.command("sonic-clear queuecounters") - time.sleep(1) - dut.command("sonic-clear counters") - time.sleep(1) - -""" Run traffic """ -tgen_flow_stats, switch_flow_stats, in_flight_flow_metrics = run_traffic(duthost=duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - data_flow_delay_sec, - snappi_extra_params=snappi_extra_params) - -# Reset pfc delay parameter -pfc = testbed_config.layer1[0].flow_control.ieee_802_1qbb -pfc.pfc_delay = 0 - -# Verify PFC pause frames -if valid_pfc_frame_test: - if not is_cisco_device(duthost): - is_valid_pfc_frame, error_msg = validate_pfc_frame(snappi_extra_params.packet_capture_file + ".pcapng") - else: - is_valid_pfc_frame, error_msg = validate_pfc_frame_cisco( - snappi_extra_params.packet_capture_file + ".pcapng") - pytest_assert(is_valid_pfc_frame, error_msg) + rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] + duthost = rx_port['duthost'] + port_id = 0 + + # Generate base traffic config + snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + port_id=port_id) + + test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / len(test_prio_list)) + + # Set default traffic flow configs if not set + if snappi_extra_params.traffic_flow_config.data_flow_config is None: + snappi_extra_params.traffic_flow_config.data_flow_config = { + "flow_name": TEST_FLOW_NAME, + "flow_dur_sec": DATA_FLOW_DURATION_SEC, + "flow_rate_percent": test_flow_rate_percent, + "flow_rate_pps": None, + "flow_rate_bps": None, + "flow_pkt_size": data_flow_pkt_size, + "flow_pkt_count": None, + "flow_delay_sec": data_flow_delay_sec, + "flow_traffic_type": traffic_flow_mode.FIXED_DURATION + } + + # Generate test flow config + generate_test_flows(testbed_config=testbed_config, + test_flow_prio_list=test_prio_list, + prio_dscp_map=prio_dscp_map, + snappi_extra_params=snappi_extra_params) + + flows = testbed_config.flows + + all_flow_names = [flow.name for flow in flows] + data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] + + duthost.command("sonic-clear counters") + duthost.command("sonic-clear queuecounters") + # Collect metrics from DUT before traffic + tx_ok_frame_count, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) + + """ Run traffic """ + tgen_flow_stats, _, _ = run_traffic( + duthost=duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=DATA_FLOW_DURATION_SEC + + data_flow_delay_sec, + snappi_extra_params=snappi_extra_params) + link_state = None + try: + time.sleep(1) + # Collect metrics from DUT once again + tx_ok_frame_count_1, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) + + pytest_assert(tx_ok_frame_count_1 > tx_ok_frame_count and tx_dut_drop_frames_1 == tx_dut_drop_frames, + "DUT Port {} : TX ok counter before {} after {}, Tx drop counter before {} after {} not expected". + format(dut_port, tx_ok_frame_count, tx_ok_frame_count_1, + tx_dut_drop_frames, tx_dut_drop_frames_1)) + + # Set port name of the Ixia port connected to dut_port + port_names = snappi_extra_params.base_flow_config["rx_port_name"] + # Create a control state object for ports + cs = api.control_state() + cs.choice = cs.PORT + cs.port.choice = cs.port.LINK + # Apply the state to port + cs.link.port_names = [port_names] + # Set port down (shut) + cs.port.link.state = cs.port.link.DOWN + api.set_control_state(cs) + logger.info("Snappi port {} is set to DOWN".format(port_names)) + time.sleep(1) + # Collect metrics from DUT again + _, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) + + logger.info("Sleeping for 90 seconds") + time.sleep(90) + # Collect metrics from DUT once again + _, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) + + pytest_assert(tx_dut_drop_frames == tx_dut_drop_frames_1, + "Mismatch in TX drop counters post DUT port {} oper down".format(dut_port)) + finally: + if link_state: + # Bring the link back up + cs.port.link.state = cs.port.link.UP + api.set_control_state(cs) + logger.info("Snappi port {} is set to UP".format(port_names)) return - -# Verify pause flows -verify_pause_flow(flow_metrics=tgen_flow_stats, - pause_flow_name=PAUSE_FLOW_NAME) - -if snappi_extra_params.gen_background_traffic: - # Verify background flows - verify_background_flow(flow_metrics=tgen_flow_stats, - speed_gbps=speed_gbps, - tolerance=TOLERANCE_THRESHOLD, - snappi_extra_params=snappi_extra_params) - -# Verify basic test flows metrics from ixia -verify_basic_test_flow(flow_metrics=tgen_flow_stats, - speed_gbps=speed_gbps, - tolerance=TOLERANCE_THRESHOLD, - test_flow_pause=test_traffic_pause, - snappi_extra_params=snappi_extra_params) - -# Verify PFC pause frame count on the DUT -verify_pause_frame_count_dut(rx_dut=ingress_duthost, - tx_dut=egress_duthost, - test_traffic_pause=test_traffic_pause, - global_pause=global_pause, - snappi_extra_params=snappi_extra_params) - -# Verify in flight TX lossless packets do not leave the DUT when traffic is expected -# to be paused, or leave the DUT when the traffic is not expected to be paused -# Verifying the packets on DUT egress, especially for multi line card scenario -verify_egress_queue_frame_count(duthost=egress_duthost, - switch_flow_stats=switch_flow_stats, - test_traffic_pause=test_traffic_pause, - snappi_extra_params=snappi_extra_params) - -if test_traffic_pause: - # Verify in flight TX packets count relative to switch buffer size - verify_in_flight_buffer_pkts(egress_duthost=egress_duthost, - ingress_duthost=ingress_duthost, - flow_metrics=in_flight_flow_metrics, - snappi_extra_params=snappi_extra_params, - asic_value=tx_port.get('asic_value')) -else: - # Verify zero pause frames are counted when the PFC class enable vector is not set - verify_unset_cev_pause_frame_count(duthost=duthost, - snappi_extra_params=snappi_extra_params) - -if test_traffic_pause and not snappi_extra_params.gen_background_traffic: - # Verify TX frame count on the DUT when traffic is expected to be paused - # and only test traffic flows are generated - verify_tx_frame_count_dut(duthost=egress_duthost, - api=api, - snappi_extra_params=snappi_extra_params) - - # Verify TX frame count on the DUT when traffic is expected to be paused - # and only test traffic flows are generated - verify_rx_frame_count_dut(duthost=ingress_duthost, - api=api, - snappi_extra_params=snappi_extra_params) -``` - -def run_tx_drop_counter( -api, -testbed_config, -port_config_list, -dut_port, -test_prio_list, -prio_dscp_map, -snappi_extra_params=None): - -``` -pytest_assert(testbed_config is not None, 'Failed to get L2/3 testbed config') - -if snappi_extra_params is None: - snappi_extra_params = SnappiTestParams() - -rx_port = snappi_extra_params.multi_dut_params.multi_dut_ports[0] -duthost = rx_port['duthost'] -port_id = 0 - -# Generate base traffic config -snappi_extra_params.base_flow_config = setup_base_traffic_config(testbed_config=testbed_config, - port_config_list=port_config_list, - port_id=port_id) - -test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / len(test_prio_list)) - -# Set default traffic flow configs if not set -if snappi_extra_params.traffic_flow_config.data_flow_config is None: - snappi_extra_params.traffic_flow_config.data_flow_config = { - "flow_name": TEST_FLOW_NAME, - "flow_dur_sec": DATA_FLOW_DURATION_SEC, - "flow_rate_percent": test_flow_rate_percent, - "flow_rate_pps": None, - "flow_rate_bps": None, - "flow_pkt_size": data_flow_pkt_size, - "flow_pkt_count": None, - "flow_delay_sec": data_flow_delay_sec, - "flow_traffic_type": traffic_flow_mode.FIXED_DURATION - } - -# Generate test flow config -generate_test_flows(testbed_config=testbed_config, - test_flow_prio_list=test_prio_list, - prio_dscp_map=prio_dscp_map, - snappi_extra_params=snappi_extra_params) - -flows = testbed_config.flows - -all_flow_names = [flow.name for flow in flows] -data_flow_names = [flow.name for flow in flows if PAUSE_FLOW_NAME not in flow.name] - -duthost.command("sonic-clear counters") -duthost.command("sonic-clear queuecounters") -# Collect metrics from DUT before traffic -tx_ok_frame_count, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) - -""" Run traffic """ -tgen_flow_stats, _, _ = run_traffic( - duthost=duthost, - api=api, - config=testbed_config, - data_flow_names=data_flow_names, - all_flow_names=all_flow_names, - exp_dur_sec=DATA_FLOW_DURATION_SEC + - data_flow_delay_sec, - snappi_extra_params=snappi_extra_params) -link_state = None -try: - time.sleep(1) - # Collect metrics from DUT once again - tx_ok_frame_count_1, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) - - pytest_assert(tx_ok_frame_count_1 > tx_ok_frame_count and tx_dut_drop_frames_1 == tx_dut_drop_frames, - "DUT Port {} : TX ok counter before {} after {}, Tx drop counter before {} after {} not expected". - format(dut_port, tx_ok_frame_count, tx_ok_frame_count_1, - tx_dut_drop_frames, tx_dut_drop_frames_1)) - - # Set port name of the Ixia port connected to dut_port - port_names = snappi_extra_params.base_flow_config["rx_port_name"] - # Create a control state object for all ports - cs = api.control_state() - # Create a control state object for all ports - cs.choice = cs.PORT - cs.port.choice = cs.port.LINK - # Apply the state to port - cs.link.port_names = [port_names] - # Set port down (shut) - cs.port.link.state = cs.port.link.DOWN - api.set_control_state(cs) - logger.info("Snappi port {} is set to DOWN".format(port_names)) - time.sleep(1) - # Collect metrics from DUT again - _, tx_dut_drop_frames = get_tx_frame_count(duthost, dut_port) - - logger.info("Sleeping for 90 seconds") - time.sleep(90) - # Collect metrics from DUT once again - _, tx_dut_drop_frames_1 = get_tx_frame_count(duthost, dut_port) - - pytest_assert(tx_dut_drop_frames == tx_dut_drop_frames_1, - "Mismatch in TX drop counters post DUT port {} oper down".format(dut_port)) -finally: - if link_state: - # Bring the link back up - link_state.state = link_state.UP - api.set_link_state(link_state) - logger.info("Snappi port {} is set to UP".format(port_names)) -return -``` From 9ffdd157078abf7f88d06b4c83aad7a8498a0d20 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 21 May 2025 00:44:40 -0700 Subject: [PATCH 15/17] Update helper.py updated the port_name field. --- tests/snappi_tests/ecn/files/helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi_tests/ecn/files/helper.py b/tests/snappi_tests/ecn/files/helper.py index cf3446b08bb..43161ce01a3 100644 --- a/tests/snappi_tests/ecn/files/helper.py +++ b/tests/snappi_tests/ecn/files/helper.py @@ -470,7 +470,7 @@ def toggle_dut_port_state(api): cs.choice = cs.PORT cs.port.choice = cs.port.LINK # Apply the state to all ports - cs.link.port_names = port_names + cs.port.link.port_names = port_names # Set all ports down (shut) cs.port.link.state = cs.port.link.DOWN api.set_control_state(cs) From 90972d920fbdc50139baca00a8dad79912aff9f0 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 21 May 2025 00:46:09 -0700 Subject: [PATCH 16/17] Update helper.py fixed port_name field. --- tests/snappi_tests/pfc/files/helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi_tests/pfc/files/helper.py b/tests/snappi_tests/pfc/files/helper.py index 7fee5274b9a..9dac19efd20 100644 --- a/tests/snappi_tests/pfc/files/helper.py +++ b/tests/snappi_tests/pfc/files/helper.py @@ -417,7 +417,7 @@ def run_tx_drop_counter( cs.choice = cs.PORT cs.port.choice = cs.port.LINK # Apply the state to port - cs.link.port_names = [port_names] + cs.port.link.port_names = [port_names] # Set port down (shut) cs.port.link.state = cs.port.link.DOWN api.set_control_state(cs) From e2015db8af3f128639084310db265799656af6a6 Mon Sep 17 00:00:00 2001 From: kamalsahu0001 <57159499+kamalsahu0001@users.noreply.github.com> Date: Wed, 21 May 2025 00:47:20 -0700 Subject: [PATCH 17/17] Update ecnhelper.py fixed port_name field. --- tests/snappi_tests/ecn/files/ecnhelper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi_tests/ecn/files/ecnhelper.py b/tests/snappi_tests/ecn/files/ecnhelper.py index 6e9f24fae21..4326b89638d 100644 --- a/tests/snappi_tests/ecn/files/ecnhelper.py +++ b/tests/snappi_tests/ecn/files/ecnhelper.py @@ -202,7 +202,7 @@ def run_ecn_test_cisco8000(api, cs.choice = cs.PORT cs.port.choice = cs.port.LINK # Apply the state to all ports - cs.link.port_names = port_names + cs.port.link.port_names = port_names # Set all ports down (shut) cs.port.link.state = cs.port.link.DOWN api.set_control_state(cs)