Exemple #1
0
def create_ipv4_traffic(session,
                        name,
                        source,
                        destination,
                        bidirectional=False,
                        fullmesh=False,
                        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.
        bidirectional (bool): if traffic item is bidirectional.
        fullmesh (bool): if traffic pattern is full mesh
        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

    if fullmesh:
        traffic_item = ixnetwork.Traffic.TrafficItem.add(
            Name=name, SrcDestMesh='fullMesh', TrafficType='ipv4')

        if source != destination:
            logger.error(
                'Source and destination must be same under full mesh traffic pattern'
            )
            return None
        else:
            traffic_item.EndpointSet.add(FullyMeshedEndpoints=destination)

    else:
        traffic_item = ixnetwork.Traffic.TrafficItem.add(
            Name=name, BiDirectional=bidirectional, TrafficType='ipv4')
        traffic_item.EndpointSet.add(Sources=source, Destinations=destination)

    traffic_config = traffic_item.ConfigElement.find()[0]
    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**9))

    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
Exemple #2
0
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**9))

    # 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
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)