From 376178ee67a6700da8c6550916fdfbf19a59fda4 Mon Sep 17 00:00:00 2001 From: Amit Pawar <158334735+amitpawar12@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:57:33 -0500 Subject: [PATCH] [Snappi]: PFC - Mixed Speed testcases (#14122) Description of PR As part of the new testcases to be added for the PFC-ECN, this PR addresses the mixed-speed ingress and egress testcases. Approach What is the motivation for this PR? This script addresses the mixed speed testcases. The topology has single ingress and egress of 400Gbps and 100Gbps respectively. The congestion is caused due to three factors: Due to oversubscription of egress. Pause frames received on egress link of 100Gbps. Both - over-subscription of egress and pause frames received on egress. Idea is to test behavior of the DUT in these conditions. How did you do it? The port_map defines to choose single ingress of 400Gbps and egress of 100Gbps. Following test functions are used: test_mixed_speed_diff_dist_dist_over: Lossless and lossy traffic are sent at 88 and 12% of the line-rate (400Gbps) respectively, causing normal congestion on DUT due to oversubscription of the egress. Lossless priority 3 and 4 are used, whereas lossy priorities are 0,1 and 2. Expectation is that lossless priorities will cause DUT to send PAUSE frames to IXIA transmitter, will be rate-limited and hence no drops. Lossy priority traffic will see no drops at all. Egress throughput is expected to be around 100Gbps. Lossy ingress and egress throughput does not change. test_mixed_speed_uni_dist_dist_over: Lossless and lossy traffic are sent at 20% of the line-rate (400Gbps) respectively, causing normal congestion on DUT due to oversubscription of the egress. Lossless priority 3 and 4 are used, whereas lossy priorities are 0,1 and 2. Expectation is that lossless priorities will cause DUT to send PAUSE frames to IXIA transmitter, will be rate-limited and hence no drops. Lossy priority traffic will however see partial drop. Egress throughput is expected to be around 100Gbps with lossless and lossy traffic of equal (or close to equal) ratio. test_mixed_speed_pfcwd_enable: Lossless and lossy traffic are sent at 20% of the line-rate (400Gbps) respectively, causing normal congestion on DUT due to oversubscription of the egress. Lossless priority 3 and 4 are used, whereas lossy priorities are 0,1 and 2. Additionally, the IXIA receiver is sending PAUSE frames to DUT for lossless priority traffic. This causes additional congestion on the DUT. Expectation is that DUT sends PFC to the IXIA transmitter for lossless priorities in response to natural congestion on DUT due to oversubscription of egress. Lossless priority is rate-limited by IXIA in response to PFCs from DUT. Lossy priority is partially dropped on DUT. But since the DUT is receiving PFCs on egress, the rate-limited lossless traffic is eventually dropped on egress. The IXIA receiver receives ONLY 60Gbps of lossy traffic. test_mixed_speed_pfcwd_disable: Lossless and lossy traffic are sent at 20% of the line-rate (400Gbps) respectively, causing normal congestion on DUT due to oversubscription of the egress. Lossless priority 3 and 4 are used, whereas lossy priorities are 0,1 and 2. Additionally, the IXIA receiver is sending PAUSE frames to DUT for lossless priority traffic. This causes additional congestion on the DUT. Since PFCWD is disabled in this scenario, DUT forwards both lossless and lossy traffic to the IXIA receiver. DUT is sending PFCs in response to natural congestion as well as PFCs received on the egress. The egress line-rate is 100Gbps with lossy traffic being partially dropped. Lossy and lossless traffic are in equal (or close to equal) ratio. test_mixed_speed_no_congestion: Purpose of the testcase is to see if the DUT does not congestion in case the ingress 400Gbps is receiving 100Gbps of traffic, which it seamlessly moves to the egress without any drops or congestion. For all the above testcases, an additional check for the fabric counters is added. The tests will clear the fabric counters on line-cards and supervisor card (if part of the test). At the end of the test, counters are being checked again for CRC and uncorrectable FEC errors and asserts if the counts are non-zero. The checks are added as part of a different PR process and will need to be merged first. The underlying infra also needs to be added first before the testcases are added. How did you verify/test it? Tested on local platform. 16:05:25 traffic_generation.run_sys_traffic L1190 INFO | Writing statistics to file : /tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_diff_dist__multiple-dut-mixed-speed_1024B-2024-10-09-16-05.csv PASSED [ 20%] 16:13:48 traffic_generation.run_sys_traffic L1190 INFO | Writing statistics to file : /tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_uni_dist__multiple-dut-mixed-speed_1024B-2024-10-09-16-13.csv PASSED [ 40%] 16:22:13 traffic_generation.run_sys_traffic L1190 INFO | Writing statistics to file : /tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_pause_pfcwd_enable__multiple-dut-mixed-speed_1024B-2024-10-09-16-22.csv PASSED [ 60%] 16:30:33 traffic_generation.run_sys_traffic L1190 INFO | Writing statistics to file : /tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_pause_pfcwd_disable__multiple-dut-mixed-speed_1024B-2024-10-09-16-30.csv PASSED [ 80%] 16:38:56 traffic_generation.run_sys_traffic L1190 INFO | Writing statistics to file : /tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_no_cong__multiple-dut-mixed-speed_1024B-2024-10-09-16-38.csv PASSED [100%] Any platform specific information? The test is specifically meant for Broadcom-DNX multi-ASIC platforms ONLY. co-authorized by: jianquanye@microsoft.com --- tests/common/snappi_tests/common_helpers.py | 2 +- .../pfc/files/mixed_speed_multidut_helper.py | 383 ++++++++++++++++ .../snappi_tests/pfc/test_pfc_mixed_speed.py | 424 ++++++++++++++++++ .../pfcwd/test_pfcwd_mixed_speed.py | 291 ++++++++++++ tests/snappi_tests/variables.py | 15 +- 5 files changed, 1113 insertions(+), 2 deletions(-) create mode 100644 tests/snappi_tests/pfc/files/mixed_speed_multidut_helper.py create mode 100644 tests/snappi_tests/pfc/test_pfc_mixed_speed.py create mode 100644 tests/snappi_tests/pfcwd/test_pfcwd_mixed_speed.py diff --git a/tests/common/snappi_tests/common_helpers.py b/tests/common/snappi_tests/common_helpers.py index 55ce452b6df..f849e9882fb 100644 --- a/tests/common/snappi_tests/common_helpers.py +++ b/tests/common/snappi_tests/common_helpers.py @@ -1183,7 +1183,7 @@ def get_interface_stats(duthost, port): def get_queue_count_all_prio(duthost, port): """ - Get the egress queue count in packets and bytes for a given port and priority from SONiC CLI. + Get the egress queue count in packets and bytes for a given port and all priorities. This is the equivalent of the "show queue counters" command. Args: duthost (Ansible host instance): device under test diff --git a/tests/snappi_tests/pfc/files/mixed_speed_multidut_helper.py b/tests/snappi_tests/pfc/files/mixed_speed_multidut_helper.py new file mode 100644 index 00000000000..be69f49aea6 --- /dev/null +++ b/tests/snappi_tests/pfc/files/mixed_speed_multidut_helper.py @@ -0,0 +1,383 @@ +import logging +import time + +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.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,\ + start_pfcwd, enable_packet_aging, \ + 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 generate_pause_flows, 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, run_traffic_and_collect_stats, \ + multi_base_traffic_config, generate_test_flows, generate_background_flows +from tests.common.snappi_tests.snappi_test_params import SnappiTestParams +from tests.common.snappi_tests.read_pcap import validate_pfc_frame + +logger = logging.getLogger(__name__) + +dut_port_config = [] +PAUSE_FLOW_NAME = 'Pause Storm' +TEST_FLOW_NAME = 'Test Flow' +BG_FLOW_NAME = 'Background Flow' +TOLERANCE_THRESHOLD = 0.1 +CONTINUOUS_MODE = -5 +ANSIBLE_POLL_DELAY_SEC = 4 +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, + test_def, + snappi_extra_params=None): + """ + 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 + test_def['enable_pause'] (bool) : if test expects no pause flow traffic. + snappi_extra_params (SnappiSysTestParams obj): additional parameters for Snappi traffic + + Returns: + N/A + """ + + TEST_FLOW_AGGR_RATE_PERCENT = test_def['TEST_FLOW_AGGR_RATE_PERCENT'] + BG_FLOW_AGGR_RATE_PERCENT = test_def['BG_FLOW_AGGR_RATE_PERCENT'] + data_flow_pkt_size = test_def['data_flow_pkt_size'] + DATA_FLOW_DURATION_SEC = test_def['DATA_FLOW_DURATION_SEC'] + data_flow_delay_sec = test_def['data_flow_delay_sec'] + SNAPPI_POLL_DELAY_SEC = test_def['SNAPPI_POLL_DELAY_SEC'] + PAUSE_FLOW_DUR_BASE_SEC = data_flow_delay_sec + DATA_FLOW_DURATION_SEC + if test_def['imix']: + fname = test_def['test_type'] + '_' + test_def['line_card_choice'] + '_' + 'IMIX' + else: + fname = test_def['test_type'] + '_' + test_def['line_card_choice'] + '_' + str(data_flow_pkt_size) + 'B' + port_map = test_def['port_map'] + + 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'] + dut_list = [egress_duthost, ingress_duthost] + + if (test_traffic_pause): + logger.info("PFC receiving DUT is {}".format(egress_duthost.hostname)) + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + + if (test_def['enable_pfcwd']): + start_pfcwd(egress_duthost) + start_pfcwd(ingress_duthost) + else: + stop_pfcwd(egress_duthost) + stop_pfcwd(ingress_duthost) + + if (test_def['enable_credit_wd']): + enable_packet_aging(egress_duthost, rx_port['asic_value']) + enable_packet_aging(ingress_duthost, tx_port['asic_value']) + else: + disable_packet_aging(egress_duthost, rx_port['asic_value']) + disable_packet_aging(ingress_duthost, tx_port['asic_value']) + + # Port id of Rx port for traffic config + # rx_port_id and tx_port_id belong to IXIA chassis. + rx_port_id = 0 + + # Rate percent must be an integer + bg_flow_rate_percent = int(BG_FLOW_AGGR_RATE_PERCENT / len(bg_prio_list)) + test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / len(test_prio_list)) + # Generate base traffic config + for i in range(port_map[2]): + tx_port_id = i+1 + snappi_extra_params.base_flow_config_list.append(multi_base_traffic_config(testbed_config=testbed_config, + port_config_list=port_config_list, + rx_port_id=rx_port_id, + tx_port_id=tx_port_id)) + + speed_str = testbed_config.layer1[0].speed + speed_gbps = int(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_list["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_list["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_count": None, + "flow_pkt_size": data_flow_pkt_size, + "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 (test_traffic_pause): + 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 (test_traffic_pause): + if valid_pfc_frame_test: + 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 + + # Generate test flow config based on number of ingress ports + # Every ingress port will be used as index. Example - test flow stream 0 - for first ingress. + for m in range(port_map[2]): + 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, + flow_index=m) + + if (test_def['background_traffic']): + for m in range(port_map[2]): + 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, + flow_index=m) + + # Generate pause storm config + if (test_traffic_pause): + for m in range(port_map[0]): + generate_pause_flows(testbed_config=testbed_config, + pause_prio_list=pause_prio_list, + global_pause=global_pause, + snappi_extra_params=snappi_extra_params, + flow_index=m) + + 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 + for dut in dut_list: + dut.command("pfcstat -c \n") + time.sleep(1) + dut.command("sonic-clear queuecounters \n") + time.sleep(1) + dut.command("sonic-clear counters \n") + time.sleep(1) + + exp_dur_sec = DATA_FLOW_DURATION_SEC + data_flow_delay_sec + + """ Run traffic """ + tgen_flow_stats, switch_flow_stats, test_stats = \ + run_traffic_and_collect_stats(rx_duthost=ingress_duthost, + tx_duthost=egress_duthost, + api=api, + config=testbed_config, + data_flow_names=data_flow_names, + all_flow_names=all_flow_names, + exp_dur_sec=exp_dur_sec, + port_map=test_def['port_map'], + fname=fname, + stats_interval=test_def['stats_interval'], + imix=test_def['imix'], + snappi_extra_params=snappi_extra_params) + + test_check = test_def['test_check'] + if (not test_check['loss_expected']): + # Check for loss packets on IXIA and DUT. + pytest_assert(test_stats['tgen_loss_pkts'] == 0, 'Loss seen on TGEN') + pytest_assert(test_stats['dut_loss_pkts'] == 0, 'Loss seen on DUT') + + # Check for Tx and Rx packets on IXIA for lossless and lossy streams. + pytest_assert(test_stats['tgen_lossless_rx_pkts'] == test_stats['tgen_lossless_tx_pkts'], + 'Losses observed in lossless traffic streams') + pytest_assert(test_stats['tgen_lossy_rx_pkts'] == test_stats['tgen_lossy_tx_pkts'], + 'Losses observed in lossy traffic streams') + + # Check for Rx packets between IXIA and DUT for lossy and lossless streams. + pytest_assert(test_stats['tgen_lossless_rx_pkts'] == test_stats['dut_lossless_pkts'], + 'Losses observed in lossless traffic streams on DUT Tx and IXIA Rx') + pytest_assert(test_stats['tgen_lossy_rx_pkts'] == test_stats['dut_lossy_pkts'], + 'Losses observed in lossy traffic streams on DUT Tx and IXIA Rx') + else: + # Check for lossless and lossy stream percentage drop for a given tolerance limit. + lossless_drop = round((1 - float(test_stats['tgen_lossless_rx_pkts']) / test_stats['tgen_lossless_tx_pkts']), 2) + lossy_drop = round((1 - float(test_stats['tgen_lossy_rx_pkts']) / test_stats['tgen_lossy_tx_pkts']), 2) + logger.info('Lossless Drop %:{}, Lossy Drop %:{}'.format(lossless_drop*100, lossy_drop*100)) + if test_def['enable_pfcwd']: + pytest_assert((lossless_drop*100) <= test_check['lossless'], 'Lossless packet drop outside tolerance limit') + pytest_assert((lossy_drop*100) <= test_check['lossy'], 'Lossy packet drop outside tolerance limit') + + # Checking if the actual line rate on egress is within tolerable limit of egress line speed. + pytest_assert(((1 - test_stats['tgen_rx_rate'] / float(port_map[0]*port_map[1]))*100) <= test_check['speed_tol'], + 'Egress speed beyond tolerance range') + + # Checking for PFC counts on DUT + if (not test_check['pfc']): + pytest_assert(test_stats['lossless_tx_pfc'] == 0, 'Error:PFC transmitted by DUT for lossless priorities') + pytest_assert(test_stats['lossy_rx_tx_pfc'] == 0, 'Error:PFC transmitted by DUT for lossy priorities') + else: + if (test_traffic_pause): + pytest_assert(test_stats['lossless_rx_pfc'] > 0, 'Error:No Rx PFCs to DUT from IXIA') + if ((test_stats['lossless_rx_pfc'] != 0) and (not test_def['enable_pfcwd'])): + pytest_assert(test_stats['lossless_tx_pfc'] > 0, 'Error:No Tx PFCs from DUT after receiving PFCs') + pytest_assert(test_stats['lossless_tx_pfc'] > 0, 'Error: PFC not be transmitted from DUT on congestion') + pytest_assert(test_stats['lossy_rx_tx_pfc'] == 0, 'Error:Incorrect Rx/Tx PFCs on DUT for lossy priorities') + + # Reset pfc delay parameter + pfc = testbed_config.layer1[0].flow_control.ieee_802_1qbb + pfc.pfc_delay = 0 + + # Verify PFC pause frames + if (test_traffic_pause): + if valid_pfc_frame_test: + is_valid_pfc_frame = validate_pfc_frame(snappi_extra_params.packet_capture_file + ".pcapng") + pytest_assert(is_valid_pfc_frame, "PFC frames invalid") + return + + # Verify pause flows + if (test_traffic_pause): + for metric in tgen_flow_stats: + if PAUSE_FLOW_NAME in metric.name: + pause_flow_name = metric.name + verify_pause_flow(flow_metrics=tgen_flow_stats, + pause_flow_name=pause_flow_name) + + # Check for the flows ONLY if normal packet size (non-imix) is used. + if (test_def['background_traffic'] and test_def['verify_flows'] and not test_def['imix']): + 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 + if (test_def['verify_flows'] and not test_def['imix']): + 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) + + if (test_traffic_pause and test_def['verify_flows']): + 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 + # Only true if pfcwd is disabled, else packets will dropped. + 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 and test_def['verify_flows']): + # Verify in flight TX packets count relative to switch buffer size + verify_in_flight_buffer_pkts(duthost=ingress_duthost, + asic_value=rx_port['asic_value'], + flow_metrics=tgen_flow_stats, + snappi_extra_params=snappi_extra_params) + + # Verify zero pause frames are counted when the PFC class enable vector is not set + verify_unset_cev_pause_frame_count(duthost=egress_duthost, + snappi_extra_params=snappi_extra_params) diff --git a/tests/snappi_tests/pfc/test_pfc_mixed_speed.py b/tests/snappi_tests/pfc/test_pfc_mixed_speed.py new file mode 100644 index 00000000000..d67e01edab4 --- /dev/null +++ b/tests/snappi_tests/pfc/test_pfc_mixed_speed.py @@ -0,0 +1,424 @@ +import pytest +import random +from tests.common.helpers.assertions import pytest_require, pytest_assert # noqa: F401 +from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts_multidut # noqa: F401 +from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ + snappi_api, cleanup_config, get_snappi_ports_for_rdma, snappi_multi_base_config, \ + get_snappi_ports, get_snappi_ports_multi_dut, clear_fabric_counters, check_fabric_counters # noqa: F401 +from tests.common.snappi_tests.qos_fixtures import prio_dscp_map, lossless_prio_list, \ + lossy_prio_list, all_prio_list # noqa: F401 +from tests.snappi_tests.variables import MIXED_SPEED_PORT_INFO, MULTIDUT_TESTBED +from tests.snappi_tests.pfc.files.mixed_speed_multidut_helper import run_pfc_test +from tests.common.snappi_tests.snappi_test_params import SnappiTestParams + +import logging +logger = logging.getLogger(__name__) + +pytestmark = [pytest.mark.topology('multidut-tgen')] + +port_map = [[1, 100, 1, 400]] +# Testplan: docs/testplan/PFC_Snappi_Additional_Testcases.md +# This test-script covers testcase#03: DETECT CONGESTION WITH MISMATCHED INGRESS AND EGRESS + + +@pytest.mark.parametrize('port_map', port_map) +@pytest.mark.parametrize("multidut_port_info", MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED]) +def test_mixed_speed_diff_dist_over(snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts_multidut, # noqa: F811 + duthosts, + prio_dscp_map, # noqa: F811 + lossless_prio_list, # noqa: F811 + lossy_prio_list, # noqa: F811 + tbinfo, + get_snappi_ports, # noqa: F811 + port_map, + multidut_port_info): # noqa: F811 + + """ + Majority traffic is lossless priority traffic. + DUT responds to congestion on ingress side by sending PFCs to IXIA transmitter. + IXIA transmitter slows down lossless traffic. + No Lossy traffic is dropped. + Lossy traffic makes through without any drop. Lossless traffic is adjusted. + Total egress link speed is 100Gbps. + + Args: + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts_multidut (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + lossless_prio_list(list): list of lossless priorities + lossy_prio_list(list): list of lossy priorities. + tbinfo(key): element to identify testbed info name. + get_snappi_ports(pytest fixture): returns list of ports based on linecards selected. + port_map(list): list for port-speed combination. + multidut_port_info : Line card classification along with ports selected as Rx and Tx port. + Returns: + N/A + + """ + + # port_map is defined as port-speed combination. + # first two parameters are count of egress links and its speed. + # last two parameters are count of ingress links and its speed. + + # pkt_size of 1024B will be used unless imix flag is set. + # With imix flag set, the traffic_generation.py uses IMIX profile. + pkt_size = 1024 + + for testbed_subtype, rdma_ports in MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED].items(): + tx_port_count = port_map[0] + rx_port_count = port_map[2] + snappi_port_list = get_snappi_ports + pytest_assert(MULTIDUT_TESTBED == tbinfo['conf-name'], + "The testbed name from testbed file doesn't match with MULTIDUT_TESTBED in variables.py ") + pytest_assert(len(snappi_port_list) >= tx_port_count + rx_port_count, + "Need Minimum of 2 ports defined in ansible/files/*links.csv file") + + pytest_assert(len(rdma_ports['tx_ports']) >= tx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Tx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + + pytest_assert(len(rdma_ports['rx_ports']) >= rx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Rx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + logger.info('Running test for testbed subtype: {}'.format(testbed_subtype)) + + snappi_ports = get_snappi_ports_for_rdma(snappi_port_list, rdma_ports, + tx_port_count, rx_port_count, MULTIDUT_TESTBED) + + testbed_config, port_config_list, snappi_ports = snappi_multi_base_config(duthosts, + snappi_ports, + snappi_api) + + # Percentage drop expected for lossless and lossy traffic. + # speed_tol is speed tolerance between egress link speed and actual speed. + # loss_expected to check losses on DUT and TGEN. + test_check = {'lossless': 0, 'lossy': 0, 'speed_tol': 3, 'loss_expected': False, 'pfc': True} + test_def = {'TEST_FLOW_AGGR_RATE_PERCENT': 88, + 'BG_FLOW_AGGR_RATE_PERCENT': 12, + 'data_flow_pkt_size': pkt_size, + 'DATA_FLOW_DURATION_SEC': 300, + 'data_flow_delay_sec': 0, + 'SNAPPI_POLL_DELAY_SEC': 60, + 'test_type': '/tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_diff_dist_', + 'line_card_choice': testbed_subtype, + 'port_map': port_map, + 'enable_pfcwd': True, + 'enable_credit_wd': True, + 'stats_interval': 60, + 'background_traffic': True, + 'imix': False, + 'test_check': test_check, + 'verify_flows': False} + + test_prio_list = lossless_prio_list + pause_prio_list = test_prio_list + bg_prio_list = random.sample(lossy_prio_list, 3) + logger.info('Selected lossless :{} and lossy priorities:{} for the test'.format(test_prio_list, bg_prio_list)) + + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = snappi_ports[0]['duthost'] + snappi_extra_params.multi_dut_params.duthost2 = snappi_ports[-1]['duthost'] + + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + if (snappi_ports[0]['peer_device'] == snappi_ports[-1]['peer_device']): + dut_list = [snappi_ports[0]['duthost']] + else: + dut_list = [snappi_ports[0]['duthost'], snappi_ports[-1]['duthost']] + + for dut in duthosts: + clear_fabric_counters(dut) + + try: + run_pfc_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts_multidut, + global_pause=False, + pause_prio_list=pause_prio_list, + test_prio_list=test_prio_list, + bg_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + test_traffic_pause=False, + test_def=test_def, + snappi_extra_params=snappi_extra_params) + + # Check the fabric counter for the line-cards. + for dut in duthosts: + check_fabric_counters(dut) + + finally: + cleanup_config(dut_list, snappi_ports) + + +@pytest.mark.parametrize('port_map', port_map) +@pytest.mark.parametrize("multidut_port_info", MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED]) +def test_mixed_speed_uni_dist_over(snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts_multidut, # noqa: F811 + duthosts, + prio_dscp_map, # noqa: F811 + lossless_prio_list, # noqa: F811 + lossy_prio_list, # noqa: F811 + tbinfo, + get_snappi_ports, # noqa: F811 + port_map, + multidut_port_info): # noqa: F811 + + """ + Traffic is sent to IXIA receiver in equal amount. + DUT responds to congestion on ingress side by sending PFCs to IXIA transmitter. + IXIA transmitter slows down lossless traffic. + Lossy traffic is dropped. + Equal amount of lossless and lossy priority traffic is sent to IXIA receiver. + Total egress link speed is 100Gbps. + + Args: + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts_multidut (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + lossless_prio_list(list): list of lossless priorities + lossy_prio_list(list): list of lossy priorities. + tbinfo(key): element to identify testbed info name. + get_snappi_ports(pytest fixture): returns list of ports based on linecards selected. + port_map(list): list for port-speed combination. + multidut_port_info : Line card classification along with ports selected as Rx and Tx port. + Returns: + N/A + + """ + + # port_map is defined as port-speed combination. + # first two parameters are count of egress links and its speed. + # last two parameters are count of ingress links and its speed. + + # pkt_size of 1024B will be used unless imix flag is set. + # With imix flag set, the traffic_generation.py uses IMIX profile. + pkt_size = 1024 + + for testbed_subtype, rdma_ports in MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED].items(): + tx_port_count = port_map[0] + rx_port_count = port_map[2] + snappi_port_list = get_snappi_ports + pytest_assert(MULTIDUT_TESTBED == tbinfo['conf-name'], + "The testbed name from testbed file doesn't match with MULTIDUT_TESTBED in variables.py ") + pytest_assert(len(snappi_port_list) >= tx_port_count + rx_port_count, + "Need Minimum of 2 ports defined in ansible/files/*links.csv file") + + pytest_assert(len(rdma_ports['tx_ports']) >= tx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Tx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + + pytest_assert(len(rdma_ports['rx_ports']) >= rx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Rx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + logger.info('Running test for testbed subtype: {}'.format(testbed_subtype)) + + snappi_ports = get_snappi_ports_for_rdma(snappi_port_list, rdma_ports, + tx_port_count, rx_port_count, MULTIDUT_TESTBED) + + testbed_config, port_config_list, snappi_ports = snappi_multi_base_config(duthosts, + snappi_ports, + snappi_api) + # Percentage drop expected for lossless and lossy traffic. + # speed_tol is speed tolerance between egress link speed and actual speed. + # loss_expected to check losses on DUT and TGEN. + test_check = {'lossless': 0, 'lossy': 77, 'speed_tol': 3, 'loss_expected': True, 'pfc': True} + test_def = {'TEST_FLOW_AGGR_RATE_PERCENT': 40, + 'BG_FLOW_AGGR_RATE_PERCENT': 60, + 'data_flow_pkt_size': pkt_size, + 'DATA_FLOW_DURATION_SEC': 300, + 'data_flow_delay_sec': 0, + 'SNAPPI_POLL_DELAY_SEC': 60, + 'test_type': '/tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_uni_dist_', + 'line_card_choice': testbed_subtype, + 'port_map': port_map, + 'enable_pfcwd': True, + 'enable_credit_wd': True, + 'stats_interval': 60, + 'background_traffic': True, + 'imix': False, + 'test_check': test_check, + 'verify_flows': False} + + test_prio_list = lossless_prio_list + pause_prio_list = test_prio_list + bg_prio_list = random.sample(lossy_prio_list, 3) + logger.info('Selected lossless :{} and lossy priorities:{} for the test'.format(test_prio_list, bg_prio_list)) + + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = snappi_ports[0]['duthost'] + snappi_extra_params.multi_dut_params.duthost2 = snappi_ports[-1]['duthost'] + + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + if (snappi_ports[0]['peer_device'] == snappi_ports[-1]['peer_device']): + dut_list = [snappi_ports[0]['duthost']] + else: + dut_list = [snappi_ports[0]['duthost'], snappi_ports[-1]['duthost']] + + for dut in duthosts: + clear_fabric_counters(dut) + + try: + run_pfc_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts_multidut, + global_pause=False, + pause_prio_list=pause_prio_list, + test_prio_list=test_prio_list, + bg_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + test_traffic_pause=False, + test_def=test_def, + snappi_extra_params=snappi_extra_params) + + for dut in duthosts: + check_fabric_counters(dut) + + finally: + cleanup_config(dut_list, snappi_ports) + + +@pytest.mark.parametrize('port_map', port_map) +@pytest.mark.parametrize("multidut_port_info", MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED]) +def test_mixed_speed_no_congestion(snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts_multidut, # noqa: F811 + duthosts, + prio_dscp_map, # noqa: F811 + lossless_prio_list, # noqa: F811 + lossy_prio_list, # noqa: F811 + tbinfo, + get_snappi_ports, # noqa: F811 + port_map, + multidut_port_info): # noqa: F811 + + """ + Test to have mixed speed ingress and egress without oversubscribing the egress. + Since the total ingress traffic on 400Gbps is less than 100Gbps, + there should be no congestion experienced by DUT. + No packet drops experienced by the DUT. + + Args: + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts_multidut (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + lossless_prio_list(list): list of lossless priorities + lossy_prio_list(list): list of lossy priorities. + tbinfo(key): element to identify testbed info name. + get_snappi_ports(pytest fixture): returns list of ports based on linecards selected. + port_map(list): list for port-speed combination. + multidut_port_info : Line card classification along with ports selected as Rx and Tx port. + + + + """ + + # port_map is defined as port-speed combination. + # first two parameters are count of egress links and its speed. + # last two parameters are count of ingress links and its speed. + + # pkt_size of 1024B will be used unless imix flag is set. + # With imix flag set, the traffic_generation.py uses IMIX profile. + pkt_size = 1024 + + for testbed_subtype, rdma_ports in MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED].items(): + tx_port_count = port_map[0] + rx_port_count = port_map[2] + snappi_port_list = get_snappi_ports + pytest_assert(MULTIDUT_TESTBED == tbinfo['conf-name'], + "The testbed name from testbed file doesn't match with MULTIDUT_TESTBED in variables.py ") + pytest_assert(len(snappi_port_list) >= tx_port_count + rx_port_count, + "Need Minimum of 2 ports defined in ansible/files/*links.csv file") + + pytest_assert(len(rdma_ports['tx_ports']) >= tx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Tx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + + pytest_assert(len(rdma_ports['rx_ports']) >= rx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Rx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + logger.info('Running test for testbed subtype: {}'.format(testbed_subtype)) + + snappi_ports = get_snappi_ports_for_rdma(snappi_port_list, rdma_ports, + tx_port_count, rx_port_count, MULTIDUT_TESTBED) + + testbed_config, port_config_list, snappi_ports = snappi_multi_base_config(duthosts, + snappi_ports, + snappi_api) + + # Percentage drop expected for lossless and lossy traffic. + # speed_tol is speed tolerance between egress link speed and actual speed. + # loss_expected to check losses on DUT and TGEN. + test_check = {'lossless': 0, 'lossy': 0, 'speed_tol': 10, 'loss_expected': False, 'pfc': False} + test_def = {'TEST_FLOW_AGGR_RATE_PERCENT': 14, + 'BG_FLOW_AGGR_RATE_PERCENT': 9, + 'data_flow_pkt_size': pkt_size, + 'DATA_FLOW_DURATION_SEC': 300, + 'data_flow_delay_sec': 0, + 'SNAPPI_POLL_DELAY_SEC': 60, + 'test_type': '/tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_no_cong_', + 'line_card_choice': testbed_subtype, + 'port_map': port_map, + 'enable_pfcwd': True, + 'enable_credit_wd': True, + 'stats_interval': 60, + 'background_traffic': True, + 'imix': False, + 'test_check': test_check, + 'verify_flows': False} + + test_prio_list = lossless_prio_list + pause_prio_list = test_prio_list + bg_prio_list = random.sample(lossy_prio_list, 3) + logger.info('Selected lossless :{} and lossy priorities:{} for the test'.format(test_prio_list, bg_prio_list)) + + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = snappi_ports[0]['duthost'] + snappi_extra_params.multi_dut_params.duthost2 = snappi_ports[-1]['duthost'] + + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + if (snappi_ports[0]['peer_device'] == snappi_ports[-1]['peer_device']): + dut_list = [snappi_ports[0]['duthost']] + else: + dut_list = [snappi_ports[0]['duthost'], snappi_ports[-1]['duthost']] + + for dut in duthosts: + clear_fabric_counters(dut) + + try: + run_pfc_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts_multidut, + global_pause=False, + pause_prio_list=pause_prio_list, + test_prio_list=test_prio_list, + bg_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + test_traffic_pause=False, + test_def=test_def, + snappi_extra_params=snappi_extra_params) + + for dut in duthosts: + check_fabric_counters(dut) + + finally: + cleanup_config(dut_list, snappi_ports) diff --git a/tests/snappi_tests/pfcwd/test_pfcwd_mixed_speed.py b/tests/snappi_tests/pfcwd/test_pfcwd_mixed_speed.py new file mode 100644 index 00000000000..5e28a51c37f --- /dev/null +++ b/tests/snappi_tests/pfcwd/test_pfcwd_mixed_speed.py @@ -0,0 +1,291 @@ +import pytest +import random +from tests.common.helpers.assertions import pytest_require, pytest_assert # noqa: F401 +from tests.common.fixtures.conn_graph_facts import conn_graph_facts, fanout_graph_facts_multidut # noqa: F401 +from tests.common.snappi_tests.snappi_fixtures import snappi_api_serv_ip, snappi_api_serv_port, \ + snappi_api, cleanup_config, get_snappi_ports_for_rdma, snappi_multi_base_config, \ + get_snappi_ports, get_snappi_ports_multi_dut, clear_fabric_counters, check_fabric_counters # noqa: F401 +from tests.common.snappi_tests.qos_fixtures import prio_dscp_map, lossless_prio_list, \ + lossy_prio_list, all_prio_list # noqa: F401 +from tests.snappi_tests.variables import MIXED_SPEED_PORT_INFO, MULTIDUT_TESTBED +from tests.snappi_tests.pfc.files.mixed_speed_multidut_helper import run_pfc_test +from tests.common.snappi_tests.snappi_test_params import SnappiTestParams + +import logging +logger = logging.getLogger(__name__) + +pytestmark = [pytest.mark.topology('multidut-tgen')] + +port_map = [[1, 100, 1, 400]] +# Testplan: docs/testplan/PFC_Snappi_Additional_Testcases.md +# This test-script covers testcase#03: DETECT CONGESTION WITH MISMATCHED INGRESS AND EGRESS + + +@pytest.mark.parametrize('port_map', port_map) +@pytest.mark.parametrize("multidut_port_info", MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED]) +def test_mixed_speed_pfcwd_enable(snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts_multidut, # noqa: F811 + duthosts, + prio_dscp_map, # noqa: F811 + lossless_prio_list, # noqa: F811 + lossy_prio_list, # noqa: F811 + tbinfo, + get_snappi_ports, # noqa: F811 + port_map, + multidut_port_info): # noqa: F811 + + """ + Test to oversubscribe the 100Gbps egress link and have PFCWD enabled. + Sending PAUSE frames to egress link for the lossless traffic. + In response to congestion due to PFC storm, DUT drops lossless traffic on egress side. + On ingress side, DUT sends PFCs to slow down IXIA transmitter. + Lossy traffic should be dropped. + DUT allows equal amount of traffic (lossless and lossy priorities) to the egress. + Egress traffic is around 60Gbps of lossy traffic only. + + Args: + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts_multidut (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + lossless_prio_list(list): list of lossless priorities + lossy_prio_list(list): list of lossy priorities. + tbinfo(key): element to identify testbed info name. + get_snappi_ports(pytest fixture): returns list of ports based on linecards selected. + port_map(list): list for port-speed combination. + multidut_port_info : Line card classification along with ports selected as Rx and Tx port. + + Returns: + N/A + """ + + # port_map is defined as port-speed combination. + # first two parameters are count of egress links and its speed. + # last two parameters are count of ingress links and its speed. + + # pkt_size of 1024B will be used unless imix flag is set. + # With imix flag set, the traffic_generation.py uses IMIX profile. + pkt_size = 1024 + + for testbed_subtype, rdma_ports in MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED].items(): + tx_port_count = port_map[0] + rx_port_count = port_map[2] + snappi_port_list = get_snappi_ports + pytest_assert(MULTIDUT_TESTBED == tbinfo['conf-name'], + "The testbed name from testbed file doesn't match with MULTIDUT_TESTBED in variables.py ") + pytest_assert(len(snappi_port_list) >= tx_port_count + rx_port_count, + "Need Minimum of 2 ports defined in ansible/files/*links.csv file") + + pytest_assert(len(rdma_ports['tx_ports']) >= tx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Tx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + + pytest_assert(len(rdma_ports['rx_ports']) >= rx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Rx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + logger.info('Running test for testbed subtype: {}'.format(testbed_subtype)) + + snappi_ports = get_snappi_ports_for_rdma(snappi_port_list, rdma_ports, + tx_port_count, rx_port_count, MULTIDUT_TESTBED) + + testbed_config, port_config_list, snappi_ports = snappi_multi_base_config(duthosts, + snappi_ports, + snappi_api) + + # Percentage drop expected for lossless and lossy traffic. + # speed_tol is speed tolerance between egress link speed and actual speed. + # loss_expected to check losses on DUT and TGEN. + test_check = {'lossless': 100, 'lossy': 75, 'speed_tol': 40, 'loss_expected': True, 'pfc': True} + test_def = {'TEST_FLOW_AGGR_RATE_PERCENT': 40, + 'BG_FLOW_AGGR_RATE_PERCENT': 60, + 'data_flow_pkt_size': pkt_size, + 'DATA_FLOW_DURATION_SEC': 300, + 'data_flow_delay_sec': 0, + 'SNAPPI_POLL_DELAY_SEC': 60, + 'test_type': '/tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_pause_pfcwd_enable_', + 'line_card_choice': testbed_subtype, + 'port_map': port_map, + 'enable_pfcwd': True, + 'enable_credit_wd': True, + 'stats_interval': 60, + 'background_traffic': True, + 'imix': False, + 'test_check': test_check, + 'verify_flows': False} + + test_prio_list = lossless_prio_list + pause_prio_list = test_prio_list + bg_prio_list = random.sample(lossy_prio_list, 3) + logger.info('Selected lossless :{} and lossy priorities:{} for the test'.format(test_prio_list, bg_prio_list)) + + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = snappi_ports[0]['duthost'] + snappi_extra_params.multi_dut_params.duthost2 = snappi_ports[-1]['duthost'] + + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + if (snappi_ports[0]['peer_device'] == snappi_ports[-1]['peer_device']): + dut_list = [snappi_ports[0]['duthost']] + else: + dut_list = [snappi_ports[0]['duthost'], snappi_ports[-1]['duthost']] + + for dut in duthosts: + clear_fabric_counters(dut) + + try: + run_pfc_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts_multidut, + global_pause=False, + pause_prio_list=pause_prio_list, + test_prio_list=test_prio_list, + bg_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + test_traffic_pause=True, + test_def=test_def, + snappi_extra_params=snappi_extra_params) + + for dut in duthosts: + check_fabric_counters(dut) + + finally: + cleanup_config(dut_list, snappi_ports) + + +@pytest.mark.parametrize('port_map', port_map) +@pytest.mark.parametrize("multidut_port_info", MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED]) +def test_mixed_speed_pfcwd_disable(snappi_api, # noqa: F811 + conn_graph_facts, # noqa: F811 + fanout_graph_facts_multidut, # noqa: F811 + duthosts, + prio_dscp_map, # noqa: F811 + lossless_prio_list, # noqa: F811 + lossy_prio_list, # noqa: F811 + tbinfo, + get_snappi_ports, # noqa: F811 + port_map, + multidut_port_info): # noqa: F811 + + """ + Test to oversubscribe the 100Gbps egress link and have PFCWD disabled. + Sending PAUSE frames to egress link for the lossless traffic. + DUT should send PFCs for the lossless traffic and have zero loss for lossless traffic. + Lossy traffic should be dropped. + DUT allows equal amount of traffic (lossless and lossy priorities) to the egress. + Egress traffic is around 100Gbps. + + Args: + snappi_api (pytest fixture): SNAPPI session + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts_multidut (pytest fixture): fanout graph + duthosts (pytest fixture): list of DUTs + prio_dscp_map (pytest fixture): priority vs. DSCP map (key = priority). + lossless_prio_list(list): list of lossless priorities + lossy_prio_list(list): list of lossy priorities. + tbinfo(key): element to identify testbed info name. + get_snappi_ports(pytest fixture): returns list of ports based on linecards selected. + port_map(list): list for port-speed combination. + multidut_port_info : Line card classification along with ports selected as Rx and Tx port. + Returns: + N/A + """ + + # port_map is defined as port-speed combination. + # first two parameters are count of egress links and its speed. + # last two parameters are count of ingress links and its speed. + + # pkt_size of 1024B will be used unless imix flag is set. + # With imix flag set, the traffic_generation.py uses IMIX profile. + pkt_size = 1024 + + for testbed_subtype, rdma_ports in MIXED_SPEED_PORT_INFO[MULTIDUT_TESTBED].items(): + tx_port_count = port_map[0] + rx_port_count = port_map[2] + snappi_port_list = get_snappi_ports + pytest_assert(MULTIDUT_TESTBED == tbinfo['conf-name'], + "The testbed name from testbed file doesn't match with MULTIDUT_TESTBED in variables.py ") + pytest_assert(len(snappi_port_list) >= tx_port_count + rx_port_count, + "Need Minimum of 2 ports defined in ansible/files/*links.csv file") + + pytest_assert(len(rdma_ports['tx_ports']) >= tx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Tx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + + pytest_assert(len(rdma_ports['rx_ports']) >= rx_port_count, + 'MULTIDUT_PORT_INFO doesn\'t have the required Rx ports defined for \ + testbed {}, subtype {} in variables.py'. + format(MULTIDUT_TESTBED, testbed_subtype)) + logger.info('Running test for testbed subtype: {}'.format(testbed_subtype)) + + snappi_ports = get_snappi_ports_for_rdma(snappi_port_list, rdma_ports, + tx_port_count, rx_port_count, MULTIDUT_TESTBED) + + testbed_config, port_config_list, snappi_ports = snappi_multi_base_config(duthosts, + snappi_ports, + snappi_api) + + # Percentage drop expected for lossless and lossy traffic. + # speed_tol is speed tolerance between egress link speed and actual speed. + # loss_expected to check losses on DUT and TGEN. + test_check = {'lossless': 0, 'lossy': 75, 'speed_tol': 3, 'loss_expected': True, 'pfc': True} + test_def = {'TEST_FLOW_AGGR_RATE_PERCENT': 40, + 'BG_FLOW_AGGR_RATE_PERCENT': 60, + 'data_flow_pkt_size': pkt_size, + 'DATA_FLOW_DURATION_SEC': 300, + 'data_flow_delay_sec': 0, + 'SNAPPI_POLL_DELAY_SEC': 60, + 'test_type': '/tmp/Single_400Gbps_Ingress_Single_100Gbps_Egress_pause_pfcwd_disable_', + 'line_card_choice': testbed_subtype, + 'port_map': port_map, + 'enable_pfcwd': False, + 'enable_credit_wd': False, + 'stats_interval': 60, + 'background_traffic': True, + 'imix': False, + 'test_check': test_check, + 'verify_flows': False} + + test_prio_list = lossless_prio_list + pause_prio_list = test_prio_list + bg_prio_list = random.sample(lossy_prio_list, 3) + logger.info('Selected lossless :{} and lossy priorities:{} for the test'.format(test_prio_list, bg_prio_list)) + + snappi_extra_params = SnappiTestParams() + snappi_extra_params.multi_dut_params.duthost1 = snappi_ports[0]['duthost'] + snappi_extra_params.multi_dut_params.duthost2 = snappi_ports[-1]['duthost'] + + snappi_extra_params.multi_dut_params.multi_dut_ports = snappi_ports + if (snappi_ports[0]['peer_device'] == snappi_ports[-1]['peer_device']): + dut_list = [snappi_ports[0]['duthost']] + else: + dut_list = [snappi_ports[0]['duthost'], snappi_ports[-1]['duthost']] + + for dut in duthosts: + clear_fabric_counters(dut) + + try: + run_pfc_test(api=snappi_api, + testbed_config=testbed_config, + port_config_list=port_config_list, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts_multidut, + global_pause=False, + pause_prio_list=pause_prio_list, + test_prio_list=test_prio_list, + bg_prio_list=bg_prio_list, + prio_dscp_map=prio_dscp_map, + test_traffic_pause=True, + test_def=test_def, + snappi_extra_params=snappi_extra_params) + + for dut in duthosts: + check_fabric_counters(dut) + + finally: + cleanup_config(dut_list, snappi_ports) diff --git a/tests/snappi_tests/variables.py b/tests/snappi_tests/variables.py index c2cef586681..88e70456f88 100644 --- a/tests/snappi_tests/variables.py +++ b/tests/snappi_tests/variables.py @@ -31,7 +31,20 @@ } }) )} - +# rx port is 400Gbps port receiving traffic in mixed-speed mode. +# tx port is 100Gbps port sending traffic to IXIA. +MIXED_SPEED_PORT_INFO = {MULTIDUT_TESTBED: ( + ({ + 'multiple-dut-any-asic': { + 'rx_ports': [ + {'port_name': 'Ethernet0', 'hostname': "sonic-s6100-dut1"} + ], + 'tx_ports': [ + {'port_name': 'Ethernet0', 'hostname': "sonic-s6100-dut2"} + ] + } + }) +)} ''' In this file user can modify the line_card_choice and it chooses the corresponding hostname and asic values from the config_set hostnames can be modified according to the dut hostname mentioned