diff --git a/tests/common/ixia/ixia_helpers.py b/tests/common/ixia/ixia_helpers.py index 402aed5c202..161c8c0e03f 100644 --- a/tests/common/ixia/ixia_helpers.py +++ b/tests/common/ixia/ixia_helpers.py @@ -530,3 +530,328 @@ def create_ip_traffic_item ( # Enable tracking. traffic_item.Tracking.find().TrackBy = ['trackingenabled0'] return traffic_item + + +def create_ipv4_traffic(session, + name, + source, + destination, + pkt_size=64, + pkt_count=None, + duration=None, + rate_percent=100, + start_delay=0, + dscp_list=None, + lossless_prio_list=None, + ecn_capable=False): + """ + Create an IPv4 traffic item on IxNetwork. + + Args: + session (obj): IxNetwork session object. + name (str): Name of traffic item + source (obj list): Source endpoints - list of IxNetwork vport objects. + destination (obj list): Destination endpoints - list of IxNetwork + vport objects. + pkt_size (int): Packet size. + pkt_count (int): Packet count. + duration (int): Traffic duration in second (positive integer only!) + rate_percent (int): Percentage of line rate. + start_delay (int): Start delay in second. + dscp_list(int list): List of DSCPs. + lossless_prio_list (int list): List of lossless priorities. + ecn_capable (bool): If packets can get ECN marked. + + Returns: + The created traffic item or None in case of error. + """ + ixnetwork = session.Ixnetwork + + traffic_item = ixnetwork.Traffic.TrafficItem.add(Name=name, + BiDirectional=False, + TrafficType='ipv4') + + traffic_item.EndpointSet.add(Sources=source, Destinations=destination) + + traffic_config = traffic_item.ConfigElement.find()[0] + + # Todo: add sending rate support + traffic_config.FrameRate.update(Type='percentLineRate', Rate=rate_percent) + traffic_config.FrameRateDistribution.PortDistribution = 'splitRateEvenly' + traffic_config.FrameSize.FixedSize = pkt_size + + if pkt_count is not None and duration is not None: + logger.error('You can only specify either pkt_count or duration') + return None + + if pkt_count is not None: + traffic_config.TransmissionControl.update(Type='fixedFrameCount', + FrameCount=pkt_count) + elif duration is not None: + if type(duration) != int or duration <= 0: + logger.error('Invalid duration value {} (positive integer only)'. + format(duration)) + + return None + else: + traffic_config.TransmissionControl.update( + Type='fixedDuration', + Duration=duration) + else: + traffic_config.TransmissionControl.update(Type='continuous') + + if start_delay > 0: + traffic_config.TransmissionControl.update( + StartDelayUnits='nanoseconds', + StartDelay=start_delay*(10**6)) + + if dscp_list is not None and len(dscp_list) > 0: + phb_field = traffic_item.ConfigElement.find().Stack.find('IPv4').Field.\ + find(DisplayName='Default PHB') + + phb_field.ActiveFieldChoice = True + phb_field.ValueType = 'valueList' + phb_field.ValueList = dscp_list + + # Set ECN bits to 10 (ECN capable). + if ecn_capable: + phb_field = traffic_item.ConfigElement.find().Stack.find('IPv4').\ + Field.find(FieldTypeId='ipv4.header.priority.ds.phb.defaultPHB.unused') + + phb_field.ActiveFieldChoice = True + phb_field.ValueType = 'singleValue' + phb_field.SingleValue = 2 + + if lossless_prio_list is not None and len(lossless_prio_list) > 0: + eth_stack = traffic_item.ConfigElement.find()[0].Stack.find( + DisplayName='Ethernet II') + + pfc_queue = eth_stack.Field.find(DisplayName='PFC Queue') + pfc_queue.ValueType = 'valueList' + pfc_queue.ValueList = lossless_prio_list + + traffic_item.Tracking.find()[0].TrackBy = ['flowGroup0'] + + # Push ConfigElement settings down to HighLevelStream resources. + traffic_item.Generate() + + return traffic_item + + +def create_pause_traffic(session, name, source, pkt_per_sec, pkt_count=None, + duration=None, start_delay=0, global_pause=False, + pause_prio_list=[]): + """ + Create a pause traffic item. + + Args: + session (obj): IxNetwork session object. + name (str): Name of traffic item. + source (obj list): Source endpoints - list of IxNetwork vport objects. + pkt_per_sec (int): Packets per second. + pkt_count (int): Packet count. + duration (int): Traffic duration in second (positive integer only!). + start_delay (int): Start delay in second. + global_pause (bool): If the generated packets are global pause + (IEEE 802.3X PAUSE). + pause_prio_list: list of priorities to pause. Only valid when + global_pause is False. + + Returns: + The created traffic item or None if any errors happen. + """ + if pause_prio_list is not None: + for prio in pause_prio_list: + if prio < 0 or prio > 7: + logger.error('Invalid pause priorities {}'. + format(pause_prio_list)) + return None + + ixnetwork = session.Ixnetwork + traffic_item = ixnetwork.Traffic.TrafficItem.add(Name=name, + BiDirectional=False, + TrafficType='raw') + + # Since PFC packets will not be forwarded by the switch, so + # destinations are actually not used. + traffic_item.EndpointSet.add(Sources=source.Protocols.find(), + Destinations=source.Protocols.find()) + + traffic_config = traffic_item.ConfigElement.find()[0] + traffic_config.FrameRate.update(Type='framesPerSecond', Rate=pkt_per_sec) + traffic_config.FrameRateDistribution.PortDistribution = 'splitRateEvenly' + traffic_config.FrameSize.FixedSize = 64 + + if pkt_count is not None and duration is not None: + logger.error('You can only specify either pkt_count or duration') + return None + + if pkt_count is not None: + traffic_config.TransmissionControl.update( + Type='fixedFrameCount', + FrameCount=pkt_count) + + elif duration is not None: + if type(duration) != int or duration <= 0: + logger.error('Invalid duration value {} (positive integer only)'. + format(duration)) + + return None + else: + traffic_config.TransmissionControl.update( + Type='fixedDuration', + Duration=duration) + + else: + traffic_config.TransmissionControl.update(Type='continuous') + + if start_delay > 0: + traffic_config.TransmissionControl.update( + StartDelayUnits='nanoseconds', + StartDelay=start_delay*(10**6)) + + # Add PFC header + pfc_stack_obj = __create_pkt_hdr( + ixnetwork=ixnetwork, + traffic_item=traffic_item, + pkt_hdr_to_add='^PFC PAUSE \(802.1Qbb\)', + append_to_stack='Ethernet II') + + # Construct global pause and PFC packets. + if global_pause: + __set_global_pause_fields(pfc_stack_obj) + else: + __set_pfc_fields(pfc_stack_obj, pause_prio_list) + + # Remove Ethernet header. + traffic_item.ConfigElement.find()[0].Stack.\ + find(DisplayName="Ethernet II").Remove() + + traffic_item.Tracking.find()[0].TrackBy = ['flowGroup0'] + + # Push ConfigElement settings down to HighLevelStream resources. + traffic_item.Generate() + + return traffic_item + +# This section defines helper function used in the module. These functions +# should not be called from test script. +# 1. __set_global_pause_fields +# 2. __set_eth_fields +# 3. __set_pfc_fields +# 4. __create_pkt_hdr + +def __set_global_pause_fields(pfc_stack_obj): + code = pfc_stack_obj.find(DisplayName='Control opcode') + code.ValueType = 'singleValue' + code.SingleValue = '1' + + # This field is pause duration in global pause packet. + prio_enable_vector = pfc_stack_obj.find(DisplayName='priority_enable_vector') + + prio_enable_vector.ValueType = 'singleValue' + prio_enable_vector.SingleValue = 'ffff' + + # pad bytes + for i in range(8): + pause_duration = pfc_stack_obj.find(DisplayName='PFC Queue {}'.format(i)) + + pause_duration.ValueType = 'singleValue' + pause_duration.SingleValue = '0' + + +def __set_eth_fields(eth_stack_obj, src_mac, dst_mac): + if src_mac is not None: + src_mac_field = eth_stack_obj.find(DisplayName='Source MAC Address') + src_mac_field.ValueType = 'singleValue' + src_mac_field.SingleValue = src_mac + + if dst_mac is not None: + dst_mac_field = eth_stack_obj.find(DisplayName='Destination MAC Address') + + dst_mac_field.ValueType = 'singleValue' + dst_mac_field.SingleValue = dst_mac + + +def __set_ip_fields(ip_stack_obj, src_ip, dst_ip, dscp_list): + if src_ip is not None: + src_ip_field = ip_stack_obj.find(DisplayName='Source Address') + src_ip_field.ValueType = 'singleValue' + src_ip_field.SingleValue = src_ip + + if dst_ip is not None: + dst_ip_field = ip_stack_obj.find(DisplayName='Destination Address') + dst_ip_field.ValueType = 'singleValue' + dst_ip_field.SingleValue = dst_ip + + if dscp_list is not None and len(dscp_list) > 0: + phb_field = ip_stack_obj.find(DisplayName='Default PHB') + phb_field.ActiveFieldChoice = True + phb_field.ValueType = 'valueList' + phb_field.ValueList = dscp_list + + +def __set_pfc_fields(pfc_stack_obj, pause_prio_list): + code = pfc_stack_obj.find(DisplayName='Control opcode') + code.ValueType = 'singleValue' + code.SingleValue = '101' + + prio_enable_vector = pfc_stack_obj.find(DisplayName='priority_enable_vector') + prio_enable_vector.ValueType = 'singleValue' + + val = 0 + for prio in pause_prio_list: + val += (1 << prio) + prio_enable_vector.SingleValue = hex(val) + + for i in range(8): + pause_duration = pfc_stack_obj.find(DisplayName='PFC Queue {}'.format(i)) + pause_duration.ValueType = 'singleValue' + + if i in pause_prio_list: + pause_duration.SingleValue = 'ffff' + else: + pause_duration.SingleValue = '0' + + +def __create_pkt_hdr(ixnetwork, + traffic_item, + pkt_hdr_to_add, + append_to_stack): + #Add new packet header in traffic item + config_element = traffic_item.ConfigElement.find()[0] + + # Do the followings to add packet headers on the new traffic item + + # Uncomment this to show a list of all the available protocol templates + # to create (packet headers) + #for protocolHeader in ixNetwork.Traffic.ProtocolTemplate.find(): + # ixNetwork.info('Protocol header: -- {} --'. + # format(protocolHeader.DisplayName)) + + # 1> Get the protocol template from the ProtocolTemplate + # list. + pkt_hdr_proto_template = \ + ixnetwork.Traffic.ProtocolTemplate.find(DisplayName=pkt_hdr_to_add) + #ixNetwork.info('protocolTemplate: {}'.format(packetHeaderProtocolTemplate)) + + # 2> Append the object after the specified packet + # header stack. + append_to_stack_obj = config_element.Stack.find( + DisplayName=append_to_stack + ) + #ixNetwork.info('appendToStackObj: {}'.format(appendToStackObj)) + append_to_stack_obj.Append(Arg2=pkt_hdr_proto_template) + + # 3> Get the new packet header stack to use it for appending an + # IPv4 stack after it. Look for the packet header object and stack ID. + pkt_hdr_stack_obj = config_element.Stack.find(DisplayName=pkt_hdr_to_add) + + # 4> In order to modify the fields, get the field object + pkt_hdr_field_obj = pkt_hdr_stack_obj.Field.find() + #ixNetwork.info('packetHeaderFieldObj: {}'.format(packetHeaderFieldObj)) + + # 5> Save the above configuration to the base config file. + # ixNetwork.SaveConfig(Files('baseConfig.ixncfg', local_file=True)) + return pkt_hdr_field_obj + diff --git a/tests/pfc/files/__init__.py b/tests/pfc/files/__init__.py new file mode 100644 index 00000000000..65d14a7c199 --- /dev/null +++ b/tests/pfc/files/__init__.py @@ -0,0 +1 @@ +# Local library for PFC tests. diff --git a/tests/pfc/files/qos_fixtures.py b/tests/pfc/files/qos_fixtures.py new file mode 100644 index 00000000000..dc32f25433f --- /dev/null +++ b/tests/pfc/files/qos_fixtures.py @@ -0,0 +1,53 @@ +import pytest +""" +RDMA test cases may require variety of traffic related fixtures. This file +is repository of all different kinds of traffic related fixtures. This +file currently holds the following fixture(s): + 1. lossless_prio_dscp_map +""" +@pytest.fixture(scope = "module") +def lossless_prio_dscp_map(duthost): + """ + This fixture reads the QOS parameters from SONiC DUT, and creates + lossless priority Vs. DSCP priority port map (dictionary key = lossless + priority). + + Args: + duthost (pytest fixture) : duthost + + Returns: + Lossless priority vs. DSCP map (dictionary, key = lossless priority). + Example: {3: [3], 4: [4]} + """ + config_facts = duthost.config_facts(host=duthost.hostname, + source="persistent")['ansible_facts'] + + if "PORT_QOS_MAP" not in config_facts.keys(): + return None + + # Read the port QOS map. If pfc_enable flag is false then return None. + port_qos_map = config_facts["PORT_QOS_MAP"] + intf = port_qos_map.keys()[0] + if 'pfc_enable' not in port_qos_map[intf]: + return None + + # lossless_priorities == list of priorities values for which frame loss + # should not happen + lossless_priorities = \ + [int(x) for x in port_qos_map[intf]['pfc_enable'].split(',')] + + dscp_to_tc_map = config_facts["DSCP_TO_TC_MAP"] + + result = dict() + for prio in lossless_priorities: + result[prio] = list() + + profile = dscp_to_tc_map.keys()[0] + + for dscp in dscp_to_tc_map[profile]: + tc = dscp_to_tc_map[profile][dscp] + + if int(tc) in lossless_priorities: + result[int(tc)].append(int(dscp)) + + return result diff --git a/tests/pfc/test_pfc_pause_lossless.py b/tests/pfc/test_pfc_pause_lossless.py new file mode 100644 index 00000000000..214b2c2fbb1 --- /dev/null +++ b/tests/pfc/test_pfc_pause_lossless.py @@ -0,0 +1,355 @@ +import logging +import time +import pytest + +from tests.common.reboot import logger +from tests.common.fixtures.conn_graph_facts import conn_graph_facts + +from tests.common.helpers.assertions import pytest_assert + +from tests.common.ixia.ixia_fixtures import ixia_api_serv_ip, \ + ixia_api_serv_user, ixia_api_serv_passwd, ixia_dev, ixia_api_serv_port,\ + ixia_api_serv_session_id, ixia_api_server_session + +from tests.common.ixia.ixia_helpers import configure_ports,\ + create_topology, start_protocols, create_ipv4_traffic,\ + create_pause_traffic, start_traffic, stop_traffic,\ + get_traffic_statistics, IxiaFanoutManager, clean_configuration + +from tests.common.ixia.common_helpers import get_vlan_subnet, \ + get_addrs_in_subnet + +#from tests.rdma.files.qos_fixtures import lossless_prio_dscp_map +from files.qos_fixtures import lossless_prio_dscp_map + +pytestmark = [pytest.mark.disable_loganalyzer] + +# Data packet size in bytes. +DATA_PKT_SIZE = 1024 +START_DELAY = 1.5 +RATE_PERCENTAGE = 50 +TOLERANCE_THRESHOLD = .97 + +def run_pfc_exp(session, dut, tx_port, rx_port, port_bw, test_prio_list, + test_dscp_list, bg_dscp_list, exp_dur, start_delay=START_DELAY, + test_traffic_pause_expected=True, + send_pause_frame=True) : + """ + Run a PFC experiment. + 1. IXIA sends test traffic and background traffic from tx_port. + 2. IXIA sends PFC pause frames from rx_port to pause priorities. + 3. Background traffic should not be interruped - all background traffic + will be received at the rx_port. + 4. No test traffic will be received at the rx_port when pause priority + is equal to test traffic priority. + + Note: PFC pause frames should always be dropped, regardless of their + pause priorities. + + Args: + session (IxNetwork Session object): IxNetwork session. + dut (object): Ansible instance of SONiC device under test (DUT). + tx_port (object Ixia vport): IXIA port to transmit traffic. + rx_port (object Ixia vport): IXIA port to receive traffic. + port_bw (int): bandwidth (in Mbps) of tx_port and rx_port. + test_prio_list (list of integers): PFC priorities of test traffic and + PFC pause frames. + test_dscp_list (list of integers): DSCP values of test traffic. + bg_dscp_list (list of integers): DSCP values of background traffic. + exp_dur (integer): experiment duration in second. + start_delay (float): approximated initial delay to start the traffic. + test_traffic_pause_expected (bool): Do you expect test traffic to + be stopped? If yes, this should be true; false otherwise. + send_pause_frame (bool): True/False depending on whether you want to + send pause frame Rx port or not. + + Returns: + This function returns nothing. + """ + + # Disable DUT's PFC watchdog. + dut.shell('sudo pfcwd stop') + + vlan_subnet = get_vlan_subnet(dut) + pytest_assert(vlan_subnet is not None, + "Fail to get Vlan subnet information") + + gw_addr = vlan_subnet.split('/')[0] + # One for sender and the other one for receiver. + vlan_ip_addrs = get_addrs_in_subnet(vlan_subnet, 2) + + topo_receiver = create_topology(session=session, + name="Receiver", + ports=list(rx_port), + ip_start=vlan_ip_addrs[0], + ip_incr_step='0.0.0.1', + gw_start=gw_addr, + gw_incr_step='0.0.0.0') + + # Assumption: Line rate percentage of background data traffic + # is equal to Line rate percentage of test data traffic. + pytest_assert(2 * RATE_PERCENTAGE <= 100, + "Value of RATE_PERCENTAGE should not be more than 50!") + + topo_sender = create_topology(session=session, + name="Sender", + ports=list(tx_port), + ip_start=vlan_ip_addrs[1], + ip_incr_step='0.0.0.1', + gw_start=gw_addr, + gw_incr_step='0.0.0.0') + start_protocols(session) + + test_traffic = create_ipv4_traffic(session=session, + name='Test Data Traffic', + source=topo_sender, + destination=topo_receiver, + pkt_size=DATA_PKT_SIZE, + duration=exp_dur, + rate_percent=RATE_PERCENTAGE, + start_delay=start_delay, + dscp_list=test_dscp_list, + lossless_prio_list=test_prio_list) + + bg_priority_list = [b for b in range(8) if b not in test_prio_list] + background_traffic = create_ipv4_traffic(session=session, + name='Background Data Traffic', + source=topo_sender, + destination=topo_receiver, + pkt_size=DATA_PKT_SIZE, + duration=exp_dur, + rate_percent=RATE_PERCENTAGE, + start_delay=start_delay, + dscp_list=bg_dscp_list, + lossless_prio_list=bg_priority_list) + + # Pause time duration (in second) for each PFC pause frame. + pause_dur_per_pkt = 65535 * 64 * 8.0 / (port_bw * 1000000) + + # Do not specify duration here as we want it keep running. + if send_pause_frame: + pfc_traffic = create_pause_traffic(session=session, + name='PFC Pause Storm', + source=rx_port, + pkt_per_sec=1.1/pause_dur_per_pkt, + start_delay=0, + global_pause=False, + pause_prio_list=test_prio_list) + + start_traffic(session) + + # Wait for test and background traffic to finish. + time.sleep(exp_dur + start_delay + 1) + + # Capture traffic statistics. + flow_statistics = get_traffic_statistics(session) + logger.info(flow_statistics) + + exp_tx_bytes = (exp_dur * port_bw * 1000000 * (RATE_PERCENTAGE / 100.0)) / 8 + for row_number, flow_stat in enumerate(flow_statistics.Rows): + tx_frames = int(flow_stat['Tx Frames']) + rx_frames = int(flow_stat['Rx Frames']) + rx_bytes = int(flow_stat['Rx Bytes']) + + tolerance_ratio = rx_bytes / exp_tx_bytes + if 'Test' in flow_stat['Traffic Item']: + if test_traffic_pause_expected: + pytest_assert(tx_frames > 0 and rx_frames == 0, + "Test traffic should be fully paused") + else: + pytest_assert(tx_frames > 0 and tx_frames == rx_frames, + "Test traffic packets should not be dropped") + + if ((tolerance_ratio < TOLERANCE_THRESHOLD) or + (tolerance_ratio > 1)) : + logger.error("Expected Tx/Rx = %s actual Rx = %s" + %(exp_tx_bytes, rx_bytes)) + + logger.error("tolerance_ratio = %s" %(tolerance_ratio)) + + pytest_assert(False, + "expected % of packets not received at the RX port") + + elif 'PFC' in flow_stat['Traffic Item']: + pytest_assert(tx_frames > 0 and rx_frames == 0, + "PFC packets should be dropped") + else: + pytest_assert(tx_frames > 0 and tx_frames == rx_frames, + "Background traffic should not be impacted") + + if ((tolerance_ratio < TOLERANCE_THRESHOLD) or + (tolerance_ratio > 1)) : + logger.error("Expected Tx/Rx = %s actual Rx = %s" + %(exp_tx_bytes, rx_bytes)) + + logger.error("tolerance_ratio = %s" %(tolerance_ratio)) + + pytest_assert(False, + "expected % of packets not received at the RX port") + + stop_traffic(session) + + +def test_pfc_pause_single_lossless_priority(testbed, + conn_graph_facts, + lossless_prio_dscp_map, + duthost, + ixia_dev, + ixia_api_server_session, + fanout_graph_facts): + """ + RDMA PFC - Pauses on single lossless priority. + 1. On SONiC DUT enable PFC on any priorities Pi. (0 <= i <= 7). + 2. Disable the PFC watchdog on the SONiC DUT. + 3. On the Ixia Tx port create two flows - a) 'Test Data Traffic' and + b) 'Background Data traffic'. + 4. The flow 'Test Data Traffic' can assume one of the lossless priority + values Pi. + 5. The flow 'Background Data Traffic' can assume all the priority values + which are not in 'Test Data Traffic'. For example if the priority of + 'Test Data Traffic' is 3, the priorities of the 'Background Data + Traffic' should be 0, 1, 2, 4, 5, 6, 7. + 6. From Rx port send pause frames on priority Pi. Such that priority of + 'Test Data Traffic' at Tx end == Pause Priority at Rx end. That is, + send pause frames on priority Pi. + 7. Start 'Test Data Traffic' and 'Background Data Traffic'. + 8. Repeat step 6 and 7 for each lossless priorities. + 9. Expected result - + a. No 'Test Data Traffic' will flow. Since priority of + 'Test Data Traffic' equals to the priority of PFC pause frames. + b. 'Background Data Traffic' will always flow. + + Note: Test and background traffic should be started after PFC pause storm. + + """ + port_list = list() + fanout_devices = IxiaFanoutManager(fanout_graph_facts) + fanout_devices.get_fanout_device_details(device_number=0) + device_conn = conn_graph_facts['device_conn'] + + for intf in fanout_devices.get_ports(): + peer_port = intf['peer_port'] + intf['speed'] = int(device_conn[peer_port]['speed']) + port_list.append(intf) + + # The topology should have at least two interfaces. + pytest_assert(len(device_conn) >= 2, + "The topology should have at least two interfaces") + + # Test pausing each lossless priority individually. + session = ixia_api_server_session + for prio in lossless_prio_dscp_map: + for i in range(len(port_list)): + for send_pause_frame in [True, False]: + paused = send_pause_frame + vports = configure_ports(session, port_list) + + rx_id = i + tx_id = (i + 1) % len(port_list) + + rx_port = vports[rx_id] + tx_port = vports[tx_id] + rx_port_bw = port_list[rx_id]['speed'] + tx_port_bw = port_list[tx_id]['speed'] + + pytest_assert(rx_port_bw == tx_port_bw) + + # All the DSCP values mapped to this priority. + test_dscp_list = lossless_prio_dscp_map[prio] + # The other DSCP values. + bg_dscp_list = [x for x in range(64) if x not in test_dscp_list] + + exp_dur = 2 + + run_pfc_exp(session=session, + dut=duthost, + tx_port=tx_port, + rx_port=rx_port, + port_bw=tx_port_bw, + test_prio_list=[prio], + test_dscp_list=test_dscp_list, + bg_dscp_list=bg_dscp_list, + exp_dur=exp_dur, + test_traffic_pause_expected=paused, + send_pause_frame=send_pause_frame) + + clean_configuration(session=session) + + +def test_pfc_pause_multi_lossless_priorities(testbed, + conn_graph_facts, + lossless_prio_dscp_map, + duthost, + ixia_dev, + ixia_api_server_session, + fanout_graph_facts): + """ + RDMA PFC - Pauses on multiple lossless priorities. + 1. On SONiC DUT enable PFC on several priorities e.g priority 3 and 4. + 2. Disable the PFC watchdog on the SONiC DUT. + 3. On the Ixia Tx port create two flows - a) 'Test Data Traffic' and + b) 'Background Data traffic'. + 4. Configure 'Test Data Traffic' such that it contains traffic items + with all lossless priorities. + 5. Configure 'Background Data Traffic' it contains traffic items with + all lossy priorities. + 6. From Rx port send pause frames on all lossless priorities. Then + start 'Test Data Traffic' and 'Background Data Traffic'. + 7. When pause frames are started 'Test Data Traffic' will stop; + and when pause frames are stopped 'Test Data Traffic' will start. + 8. 'Background Data Traffic' will always flow. + 9. Repeat the steps 4 to 8 on all ports. + + """ + port_list = list() + fanout_devices = IxiaFanoutManager(fanout_graph_facts) + fanout_devices.get_fanout_device_details(device_number=0) + device_conn = conn_graph_facts['device_conn'] + + for intf in fanout_devices.get_ports(): + peer_port = intf['peer_port'] + intf['speed'] = int(device_conn[peer_port]['speed']) + port_list.append(intf) + + # The topology should have at least two interfaces. + pytest_assert(len(device_conn) >= 2, + "The topology should have at least two interfaces") + + session = ixia_api_server_session + for i in range(len(port_list)): + for send_pause_frame in [True, False]: + paused = send_pause_frame + vports = configure_ports(session, port_list) + + rx_id = i + tx_id = (i + 1) % len(port_list) + + rx_port = vports[rx_id] + tx_port = vports[tx_id] + rx_port_bw = port_list[rx_id]['speed'] + tx_port_bw = port_list[tx_id]['speed'] + pytest_assert(rx_port_bw == tx_port_bw) + + test_dscp_list = [] + test_priority_list = [prio for prio in lossless_prio_dscp_map] + for prio in lossless_prio_dscp_map: + test_dscp_list += lossless_prio_dscp_map[prio] + + bg_dscp_list = [x for x in range(64) if x not in test_dscp_list] + exp_dur = 2 + + + run_pfc_exp(session=session, + dut=duthost, + tx_port=tx_port, + rx_port=rx_port, + port_bw=tx_port_bw, + test_prio_list=test_priority_list, + test_dscp_list=test_dscp_list, + bg_dscp_list=bg_dscp_list, + exp_dur=exp_dur, + test_traffic_pause_expected=paused, + send_pause_frame=send_pause_frame) + + clean_configuration(session=session) +