From 700fb98ceef65a96261d464b73570fba4902c5b2 Mon Sep 17 00:00:00 2001 From: Wei Bai Date: Thu, 11 Feb 2021 06:39:05 +0000 Subject: [PATCH] Add PFC watchdog impact on runtime traffic test case --- .../files/pfcwd_runtime_traffic_helper.py | 166 ++++++++++++++++++ .../ixia/pfcwd/test_pfcwd_runtime_traffic.py | 35 ++++ 2 files changed, 201 insertions(+) create mode 100644 tests/ixia/pfcwd/files/pfcwd_runtime_traffic_helper.py create mode 100644 tests/ixia/pfcwd/test_pfcwd_runtime_traffic.py diff --git a/tests/ixia/pfcwd/files/pfcwd_runtime_traffic_helper.py b/tests/ixia/pfcwd/files/pfcwd_runtime_traffic_helper.py new file mode 100644 index 00000000000..f2ca6302f83 --- /dev/null +++ b/tests/ixia/pfcwd/files/pfcwd_runtime_traffic_helper.py @@ -0,0 +1,166 @@ +import time +from math import ceil + +from tests.common.helpers.assertions import pytest_assert +from tests.common.ixia.ixia_fixtures import ixia_api_serv_ip, ixia_api_serv_port,\ + ixia_api_serv_user, ixia_api_serv_passwd, ixia_api +from tests.common.ixia.ixia_helpers import get_dut_port_id +from tests.common.ixia.common_helpers import start_pfcwd, stop_pfcwd + +from abstract_open_traffic_generator.flow import DeviceTxRx, TxRx, Flow, Header,\ + Size, Rate,Duration, FixedSeconds, FixedPackets, PortTxRx, PfcPause +from abstract_open_traffic_generator.flow_ipv4 import Priority, Dscp +from abstract_open_traffic_generator.flow import Pattern as FieldPattern +from abstract_open_traffic_generator.flow import Ipv4 as Ipv4Header +from abstract_open_traffic_generator.flow import Ethernet as EthernetHeader +from abstract_open_traffic_generator.control import State, ConfigState,\ + FlowTransmitState +from abstract_open_traffic_generator.result import FlowRequest + +DATA_FLOW_NAME = "Data Flow" +DATA_PKT_SIZE = 1024 +DATA_FLOW_DURATION_SEC = 15 +PFCWD_START_DELAY_SEC = 3 +IXIA_POLL_DELAY_SEC = 2 +TOLERANCE_THRESHOLD = 0.05 + +def run_pfcwd_runtime_traffic_test(api, + testbed_config, + conn_data, + fanout_data, + duthost, + dut_port, + prio_list, + prio_dscp_map): + + pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') + + stop_pfcwd(duthost) + + """ 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)) + + flows = __gen_traffic(testbed_config=testbed_config, + port_id=port_id, + data_flow_name=DATA_FLOW_NAME, + data_flow_dur_sec=DATA_FLOW_DURATION_SEC, + data_pkt_size=DATA_PKT_SIZE, + prio_list=prio_list, + prio_dscp_map=prio_dscp_map) + + """ Tgen config = testbed config + flow config """ + config = testbed_config + config.flows = flows + + all_flow_names = [flow.name for flow in flows] + + flow_stats = __run_traffic(api=api, + config=config, + duthost=duthost, + all_flow_names=all_flow_names, + pfcwd_start_delay_sec=PFCWD_START_DELAY_SEC, + exp_dur_sec=DATA_FLOW_DURATION_SEC) + + speed_str = config.layer1[0].speed + speed_gbps = int(speed_str.split('_')[1]) + + __verify_results(rows=flow_stats, + speed_gbps=speed_gbps, + data_flow_dur_sec=DATA_FLOW_DURATION_SEC, + data_pkt_size=DATA_PKT_SIZE, + tolerance=TOLERANCE_THRESHOLD) + +def __gen_traffic(testbed_config, + port_id, + data_flow_name, + data_flow_dur_sec, + data_pkt_size, + prio_list, + prio_dscp_map): + + rx_port_id = port_id + tx_port_id = (port_id + 1) % len(testbed_config.devices) + + data_endpoint = DeviceTxRx( + tx_device_names=[testbed_config.devices[tx_port_id].name], + rx_device_names=[testbed_config.devices[rx_port_id].name], + ) + + result = list() + data_flow_rate_percent = int(100 / len(prio_list)) + + """ For each priority """ + for prio in prio_list: + ip_prio = Priority(Dscp(phb=FieldPattern(choice=prio_dscp_map[prio]), + ecn=FieldPattern(choice=Dscp.ECN_CAPABLE_TRANSPORT_1))) + pfc_queue = FieldPattern([prio]) + + data_flow = Flow( + name='{} Prio {}'.format(data_flow_name, prio), + tx_rx=TxRx(data_endpoint), + packet=[ + Header(choice=EthernetHeader(pfc_queue=pfc_queue)), + Header(choice=Ipv4Header(priority=ip_prio)) + ], + size=Size(data_pkt_size), + rate=Rate('line', data_flow_rate_percent), + duration=Duration(FixedSeconds(seconds=data_flow_dur_sec)) + ) + + result.append(data_flow) + + return result + +def __run_traffic(api, config, duthost, all_flow_names, pfcwd_start_delay_sec, exp_dur_sec): + api.set_state(State(ConfigState(config=config, state='set'))) + api.set_state(State(FlowTransmitState(state='start'))) + + time.sleep(pfcwd_start_delay_sec) + start_pfcwd(duthost) + time.sleep(exp_dur_sec - pfcwd_start_delay_sec) + + attempts = 0 + max_attempts = 20 + + while attempts < max_attempts: + rows = api.get_flow_results(FlowRequest(flow_names=all_flow_names)) + """ If all the flows have stopped """ + transmit_states = [row['transmit'] for row in rows] + if len(rows) == len(all_flow_names) and\ + list(set(transmit_states)) == ['stopped']: + time.sleep(IXIA_POLL_DELAY_SEC) + break + else: + time.sleep(1) + attempts += 1 + + """ Dump per-flow statistics """ + rows = api.get_flow_results(FlowRequest(flow_names=all_flow_names)) + api.set_state(State(FlowTransmitState(state='stop'))) + + return rows + +def __verify_results(rows, speed_gbps, data_flow_dur_sec, data_pkt_size, tolerance): + data_flow_rate_percent = int(100 / len(rows)) + + for row in rows: + flow_name = row['name'] + tx_frames = row['frames_tx'] + rx_frames = row['frames_rx'] + + pytest_assert(tx_frames == rx_frames, "{} packets of {} are dropped".\ + format(tx_frames-rx_frames, flow_name)) + + exp_rx_pkts = data_flow_rate_percent / 100.0 * speed_gbps \ + * 1e9 * data_flow_dur_sec / 8.0 / data_pkt_size + + deviation = (rx_frames - exp_rx_pkts) / float(exp_rx_pkts) + pytest_assert(abs(deviation) < tolerance, + "{} should receive {} packets (actual {})".\ + format(flow_name, exp_rx_pkts, rx_frames)) diff --git a/tests/ixia/pfcwd/test_pfcwd_runtime_traffic.py b/tests/ixia/pfcwd/test_pfcwd_runtime_traffic.py new file mode 100644 index 00000000000..780526ca356 --- /dev/null +++ b/tests/ixia/pfcwd/test_pfcwd_runtime_traffic.py @@ -0,0 +1,35 @@ +import pytest + +from tests.common.helpers.assertions import pytest_require, pytest_assert +from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ + fanout_graph_facts +from tests.common.ixia.ixia_fixtures import ixia_api_serv_ip, ixia_api_serv_port,\ + ixia_api_serv_user, ixia_api_serv_passwd, ixia_api, ixia_testbed +from tests.common.ixia.qos_fixtures import prio_dscp_map, all_prio_list + +from files.pfcwd_runtime_traffic_helper import run_pfcwd_runtime_traffic_test + +def test_pfcwd_runtime_traffic(ixia_api, + ixia_testbed, + conn_graph_facts, + fanout_graph_facts, + duthosts, + rand_one_dut_hostname, + rand_one_dut_portname_oper_up, + all_prio_list, + prio_dscp_map): + + dut_hostname, dut_port = rand_one_dut_portname_oper_up.split('|') + pytest_require(rand_one_dut_hostname == dut_hostname, + "Port is not mapped to the expected DUT") + + duthost = duthosts[rand_one_dut_hostname] + + run_pfcwd_runtime_traffic_test(api=ixia_api, + testbed_config=ixia_testbed, + conn_data=conn_graph_facts, + fanout_data=fanout_graph_facts, + duthost=duthost, + dut_port=dut_port, + prio_list=all_prio_list, + prio_dscp_map=prio_dscp_map)