def test_pfc_pause_lossy_traffic(api, duthost, lossy_configs, start_delay, traffic_duration): """ This test case checks the behaviour of the SONiC DUT when it receives a PFC pause frame on lossy priorities. +-----------+ [Keysight Chassis Tx Port] | | [Keysight Chassis Rx Port] --------------------------->| SONiC DUT |<--------------------------- Test Data Traffic + | | PFC pause frame on Background Dada Traffic +-----------+ "lossy" priorities. 1. Configure SONiC DUT with multipul lossless priorities. 2. On SONiC DUT enable PFC on several lossless priorities e.g priority 3 and 4. 3. On the Keysight chassis 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 lossy priorities. 5. Configure 'Background Data Traffic' it contains traffic items with all lossless priorities. 6. From Rx port send pause frames on all lossless priorities. Then start 'Test Data Traffic' and 'Background Data Traffic'. 7. Verify the following: (a) When Pause Storm are running, Keysight Rx port is receiving both 'Test Data Traffic' and 'Background Data traffic'. (b) When Pause Storm are stoped, then also Keysight Rx port is receiving both 'Test Data Traffic' and 'Background Data traffic'. """ duthost.shell('sudo pfcwd stop') for base_config in lossy_configs: # create the configuration api.set_config(base_config) # start all flows api.set_flow_transmit(FlowTransmit(state='start')) exp_dur = start_delay + traffic_duration logger.info("Traffic is running for %s seconds" % (exp_dur)) time.sleep(exp_dur) # stop all flows api.set_flow_transmit(FlowTransmit(state='stop')) # Get statistics test_stat = api.get_flow_results(FlowRequest()) for rows in test_stat['rows']: tx_frame_index = test_stat['columns'].index('frames_tx') rx_frame_index = test_stat['columns'].index('frames_rx') caption_index = test_stat['columns'].index('name') if ((rows[caption_index] == 'Test Data') or (rows[caption_index] == 'Background Data')): if rows[tx_frame_index] != rows[rx_frame_index]: pytest_assert( False, "Not all %s reached Rx End" % (rows[caption_index]))
def test_pfc_global_pause(api, duthost, global_pause, start_delay, pause_line_rate, traffic_line_rate, traffic_duration, port_bandwidth, frame_size): """ +-----------+ [Keysight Chassis Tx Port] | | [Keysight Chassis Rx Port] --------------------------->| SONiC DUT |<--------------------------- Test Data Traffic + | | PFC pause frame on Background Dada Traffic +-----------+ "lossy" priorities. """ duthost.shell('sudo pfcwd stop') for base_config in global_pause: # create the configuration api.set_config(base_config) # start all flows api.set_flow_transmit(FlowTransmit(state='start')) exp_dur = start_delay + traffic_duration logger.info("Traffic is running for %s seconds" % (traffic_duration)) time.sleep(exp_dur) api.set_flow_transmit(FlowTransmit(state='stop')) # Get statistics test_stat = api.get_flow_results(FlowRequest()) for rows in test_stat['rows']: tx_frame_index = test_stat['columns'].index('frames_tx') rx_frame_index = test_stat['columns'].index('frames_rx') caption_index = test_stat['columns'].index('name') if ((rows[caption_index] == 'Test Data') or (rows[caption_index] == 'Background Data')): tx_frames = float(rows[tx_frame_index]) rx_frames = float(rows[rx_frame_index]) if ((tx_frames != rx_frames) or (rx_frames == 0)): pytest_assert( False, "Not all %s reached Rx End" % (rows[caption_index])) rx_bytes = rx_frames * frame_size line_rate = traffic_line_rate / 100.0 exp_rx_bytes = (port_bandwidth * line_rate * traffic_duration) / 8 tolerance_ratio = rx_bytes / exp_rx_bytes if ((tolerance_ratio < TOLERANCE_THRESHOLD) or (tolerance_ratio > 1)): pytest_assert( False, "expected % of packets not received at the RX port")
def create_topology( session, ports, name='Topology 1', ip_type='ipv4', ip_start='10.0.0.1', ip_incr_step='0.0.0.1', gw_start='10.0.0.2', gw_incr_step='0.0.0.0'): """ This function creates a topology with ethernet and IP stack on IxNetwork Note: ipv6 stack option is left for future extension. Args: session (obj): Ixia session object. ports (list): List of IxNetwork port objects, returned by the function 'configure_ports' name (str): The name of the topology. ip_type (str): IP stack type - ipv4 or ipv6. ip_start (str): Starting interface IP address. ip_incr_step (str): IP address increment step in IP format like "0.0.0.1" gw_start (str): Starting gateway IP address. gw_incr_step (str): IP address increment step in IP format like "0.0.0.1" Return: IxNetwork topology obect. """ ixnetwork = session.Ixnetwork topology = ixnetwork.Topology.add(Name=name, Ports=ports) ixnetwork.info('Creating Topology Group {}'.format(name)) device_group = topology.DeviceGroup.add(Name=name+' DG', Multiplier='1') ethernet = device_group.Ethernet.add(Name='Ethernet') if (ip_type == 'ipv4') : ixnetwork.info('Configure IPv4') ipv4 = ethernet.Ipv4.add(Name='Ipv4') ipv4.Address.Increment(start_value=ip_start, step_value=ip_incr_step) ipv4.Address.Steps.Step = ip_incr_step ipv4.GatewayIp.Increment(start_value=gw_start, step_value=gw_incr_step) ipv4.GatewayIp.Steps.Step = gw_incr_step elif (ip_type == 'ipv6') : # ipv6 stack option is left for future extension. pass else : logger.info("Unsupported address-type") pytest_assert(0) return topology
def start_protocols(session): """This function starts all the protocols configured on the IxNetwork protocol stack (e.g., IP and Ethernet). Args: session (obj) : IxNetwork session object. Returns: None """ ixnetwork = session.Ixnetwork ixnetwork.StartAllProtocols(Arg1='sync') protocolSummary = session.StatViewAssistant('Protocols Summary') protocolSummary.CheckCondition('Sessions Not Started', protocolSummary.EQUAL, 0) protocolSummary.CheckCondition('Sessions Down', protocolSummary.EQUAL, 0) logger.info(protocolSummary)
def test_ecn_marking_at_ecress(api, duthost, ecn_marking_at_ecress, start_delay, pause_line_rate, traffic_line_rate, traffic_duration, port_bandwidth, frame_size, ecn_thresholds): duthost.shell('sudo pfcwd stop') duthost.shell('sudo sudo ecnconfig -p AZURE_LOSSLESS -gmax %s' % (ecn_thresholds)) duthost.shell('sudo sudo ecnconfig -p AZURE_LOSSLESS -gmin %s' % (ecn_thresholds)) for base_config in ecn_marking_at_ecress: rx_port = base_config.ports[1] rx_port.capture = Capture(choice=[], enable=True) # create the configuration api.set_config(base_config) # start capture api.set_port_capture(PortCapture(port_names=[rx_port.name])) # start all flows api.set_flow_transmit(FlowTransmit(state='start')) exp_dur = start_delay + traffic_duration logger.info("Traffic is running for %s seconds" % (traffic_duration)) time.sleep(exp_dur) # stop all flows api.set_flow_transmit(FlowTransmit(state='stop')) pcap_bytes = api.get_capture_results( CaptureRequest(port_name=rx_port.name)) # Get statistics test_stat = api.get_flow_results(FlowRequest()) for rows in test_stat['rows']: tx_frame_index = test_stat['columns'].index('frames_tx') rx_frame_index = test_stat['columns'].index('frames_rx') caption_index = test_stat['columns'].index('name') if ((rows[caption_index] == 'Test Data') or (rows[caption_index] == 'Background Data')): tx_frames = float(rows[tx_frame_index]) rx_frames = float(rows[rx_frame_index]) if ((tx_frames != rx_frames) or (rx_frames == 0)): pytest_assert( False, "Not all %s reached Rx End" % (rows[caption_index])) # write the pcap bytes to a local file with open('%s.pcap' % rx_port.name, 'wb') as fid: fid.write(pcap_bytes) from scapy.all import PcapReader reader = PcapReader('%s.pcap' % rx_port.name) for item in reader: logger.info(tem.time) logger.info(item.show())
def set_ecn_thresold(duthost, thresold): profile_name = 'AZURE_LOSSLESS' duthost.shell('sudo pfcwd stop') from tests.common.reboot import logger config_facts = duthost.config_facts(host=duthost.hostname, source="persistent")['ansible_facts'] logger.info('--------------------------------------------') logger.info(config_facts) logger.info('--------------------------------------------') return 1
def test_testbed(testbed, conn_graph_facts, duthost, fanout_graph_facts, ixia_api_server_session, fanouthosts): logger.info("Connection Graph Facts = %s " % (conn_graph_facts)) logger.info("Fanout Graph facts = %s" % (fanout_graph_facts)) logger.info("DUT hostname = %s" % (duthost.hostname)) mg_facts = duthost.minigraph_facts(host=duthost.hostname) gateway_ip = mg_facts['ansible_facts']['minigraph_vlan_interfaces'][0][ 'addr'] start_interface_ip = increment_ip_address(gateway_ip) ixiaFanoutHostList = IxiaFanoutManager(fanout_graph_facts) ixiaFanoutHostList.get_fanout_device_details(device_number=0) session = ixia_api_server_session logger.info("Configuring ports.") port_list = configure_ports(session=session, port_list=ixiaFanoutHostList.get_ports()) logger.info("Creating topology.") topology = create_topology(session=session, ports=port_list, name="Sender", ip_start=start_interface_ip, ip_incr_step='0.0.0.1', gw_start=gateway_ip, gw_incr_step='0.0.0.0') logger.info("Starting all protocols") start_protocols(session) # Create a traffic item logger.info("Configuring traffic.") traffic_item = create_ip_traffic_item(session=session, src_start_port=1, src_port_count=1, src_first_route_index=1, src_route_count=1, dst_start_port=2, dst_port_count=3, dst_first_route_index=1, dst_route_count=1) # Generate, apply and start traffic. start_traffic(session) logger.info("run traffic for 5 seconds") time.sleep(5) # Fetch statistics. stats = get_traffic_statistics(session=session, stat_view_name='Traffic Item Statistics') logger.info(stats) stop_traffic(session) stop_protocols(session)
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_testbed(conn_graph_facts, duthosts, rand_one_dut_hostname, fanout_graph_facts, ixia_api_server_session, fanouthosts): duthost = duthosts[rand_one_dut_hostname] logger.info("Connection Graph Facts = %s " % (conn_graph_facts)) logger.info("Fanout Graph facts = %s" % (fanout_graph_facts)) logger.info("DUT hostname = %s" % (duthost.hostname)) ixia_fanout = get_peer_ixia_chassis(conn_data=conn_graph_facts, dut_hostname=duthost.hostname) pytest_require(ixia_fanout is not None, skip_message="Cannot find the peer IXIA chassis") ixia_fanout_id = list(fanout_graph_facts.keys()).index(ixia_fanout) ixia_fanout_list = IxiaFanoutManager(fanout_graph_facts) ixia_fanout_list.get_fanout_device_details(device_number=ixia_fanout_id) logger.info("Configuring ports.") port_list = ixia_fanout_list.get_ports(peer_device=duthost.hostname) session = ixia_api_server_session vports = configure_ports(session=session, port_list=port_list) subnet = get_vlan_subnet(duthost) gw = subnet.split('/')[0] ip_list = get_addrs_in_subnet(subnet=subnet, number_of_ip=len(vports)) logger.info("Creating topology.") topo_receiver = create_topology(session=session, name="Receiver", port_list=[vports[0]], ip_list=[ip_list[0]], gw_list=[gw]) topo_sender = create_topology(session=session, name="Sender", port_list=vports[1:], ip_list=ip_list[1:], gw_list=[gw] * len(vports[1:])) logger.info("Starting all protocols") start_protocols(session) # Create a traffic item logger.info("Configuring traffic.") traffic_item = create_ipv4_traffic(session=session, name="Test Data Traffic", source=topo_sender, destination=topo_receiver) # Generate, apply and start traffic. start_traffic(session) logger.info("run traffic for 5 seconds") time.sleep(5) # Fetch per-flow statistics. stats = dump_flow_statistics(session=session) logger.info(stats) stop_traffic(session) stop_protocols(session)
def base_configs(testbed, conn_graph_facts, duthost, lossless_prio_dscp_map, one_hundred_gbe, start_delay, pause_line_rate, traffic_line_rate, frame_size, ecn_thresholds, serializer): for config in one_hundred_gbe: start_delay = start_delay * 1000000000.0 test_dscp_list = [str(prio) for prio in lossless_prio_dscp_map] tx = config.ports[0] rx = config.ports[1] vlan_subnet = get_vlan_subnet(duthost) pytest_assert(vlan_subnet is not None, "Fail to get Vlan subnet information") vlan_ip_addrs = get_addrs_in_subnet(vlan_subnet, 2) gw_addr = vlan_subnet.split('/')[0] interface_ip_addr = vlan_ip_addrs[0] tx_port_ip = vlan_ip_addrs[1] rx_port_ip = vlan_ip_addrs[0] tx_gateway_ip = gw_addr rx_gateway_ip = gw_addr test_flow_name = 'Test Data' test_line_rate = traffic_line_rate pause_line_rate = pause_line_rate pytest_assert(test_line_rate <= pause_line_rate, "test_line_rate + should be less than pause_line_rate") ###################################################################### # Create TX stack configuration ###################################################################### tx_ipv4 = Ipv4(name='Tx Ipv4', address=Pattern(tx_port_ip), prefix=Pattern('24'), gateway=Pattern(tx_gateway_ip), ethernet=Ethernet(name='Tx Ethernet')) tx.devices.append( Device(name='Tx Device', device_count=1, choice=tx_ipv4)) ###################################################################### # Create RX stack configuration ###################################################################### rx_ipv4 = Ipv4(name='Rx Ipv4', address=Pattern(rx_port_ip), prefix=Pattern('24'), gateway=Pattern(rx_gateway_ip), ethernet=Ethernet(name='Rx Ethernet')) rx.devices.append( Device(name='Rx Device', device_count=1, choice=rx_ipv4)) ###################################################################### # Traffic configuration Test data ###################################################################### data_endpoint = DeviceTxRx( tx_device_names=[tx.devices[0].name], rx_device_names=[rx.devices[0].name], ) pytest_assert(ecn_thresholds < 1024 * 1024, "keep the ECN thresholds less than 1MB") test_dscp = Priority( Dscp(phb=FieldPattern(choice=test_dscp_list), ecn=FieldPattern(Dscp.ECN_CAPABLE_TRANSPORT_1))) # ecn_thresholds in bytes number_of_packets = int(2 * (ecn_thresholds / frame_size)) logger.info("Total number of packets to send = 2 * %s = %s"\ %(ecn_thresholds / frame_size, number_of_packets)) test_flow = Flow(name=test_flow_name, tx_rx=TxRx(data_endpoint), packet=[ Header(choice=EthernetHeader()), Header(choice=Ipv4Header(priority=test_dscp)) ], size=Size(frame_size), rate=Rate('line', test_line_rate), duration=Duration( FixedPackets(packets=number_of_packets, delay=start_delay, delay_unit='nanoseconds'))) config.flows.append(test_flow) ####################################################################### # Traffic configuration Pause ####################################################################### pause_endpoint = PortTxRx(tx_port_name='Rx', rx_port_names=['Rx']) pause = Header( PfcPause( dst=FieldPattern(choice='01:80:C2:00:00:01'), src=FieldPattern(choice='00:00:fa:ce:fa:ce'), class_enable_vector=FieldPattern(choice='18'), pause_class_0=FieldPattern(choice='0'), pause_class_1=FieldPattern(choice='0'), pause_class_2=FieldPattern(choice='0'), pause_class_3=FieldPattern(choice='ffff'), pause_class_4=FieldPattern(choice='ffff'), pause_class_5=FieldPattern(choice='0'), pause_class_6=FieldPattern(choice='0'), pause_class_7=FieldPattern(choice='0'), )) pause_flow = Flow(name='Pause Storm', tx_rx=TxRx(pause_endpoint), packet=[pause], size=Size(64), rate=Rate('line', value=100), duration=Duration( FixedPackets(packets=0, delay=0, delay_unit='nanoseconds'))) config.flows.append(pause_flow) return one_hundred_gbe