Esempio n. 1
0
def get_streams(pps, duration, ip_tot_len, ip_src, ip_dst):
    udp_data_len = ip_tot_len - IPv4_HDR_LEN - UDP_HDR_LEN
    if udp_data_len < 16:
        raise RuntimeError("The minimal payload size is 16 bytes.")
    print(f"UDP payload size: {udp_data_len}")
    udp_payload = "Z" * udp_data_len
    pkt = STLPktBuilder(pkt=Ether() / IP(src=ip_src, dst=ip_dst) /
                        UDP(dport=8888, sport=9999, chksum=0) / udp_payload)
    streams = [
        STLStream(
            name="s0",
            packet=pkt,
            flow_stats=STLFlowLatencyStats(pg_id=0),
            mode=STLTXSingleBurst(pps=pps, total_pkts=int(duration * pps)),
        )
    ]
    return streams
    def configure_traffic_stream(self, traffic_flows, nr_of_flows, packet_size,
                                 **kwargs):

        flow_percentage = float(kwargs.pop("percentage", 1000000)) / 10000
        trex_dst_mac = kwargs.pop("traffic_dst_mac", '00:00:02:00:00:00')
        trex_src_mac = kwargs.pop("traffic_src_mac", '00:00:01:00:00:00')
        l2_macs = kwargs.pop("l2_macs", 1)

        #
        # The packet size passed here assumes it includes the checksum, however
        # the TRex packet size does not. Adjust the size to correct this.
        #
        packet_size -= 4

        if traffic_flows == TrafficFlowType.none or \
           self.__traffic_flows != TrafficFlowType.none:
            #
            # We need either a cleanup, or a cleanup before we configure
            # a new traffic flow type
            #
            self._delete_traffic_stream_config()

        if traffic_flows == TrafficFlowType.l2_mac or \
           traffic_flows == TrafficFlowType.l3_ipv4 or \
           traffic_flows == TrafficFlowType.nfv_mobile:

            #
            # Max flows due to IPv4 address limit, and addresses used for tests
            #
            if nr_of_flows > 0x00ffffff:
                raise ValueError(
                    "To many flows requested, max {} supported!".format(
                        0x00ffffff))

            L2 = Ether(src=trex_src_mac, dst=trex_dst_mac)
            L3 = IP(src="1.0.0.0", dst="2.0.0.0")
            L4 = UDP(chksum=0)

            if (len(L2 / L3 / L4) + 4) > packet_size:  # +4 for Ethernet CRC
                raise ValueError("Packet size ({} bytes) too small for"
                                 "requested packet ({} bytes)!".format(
                                     packet_size,
                                     len(L2 / L3 / L4) + 4))

            if traffic_flows == TrafficFlowType.l2_mac:
                src_base = self._mac_2_int(trex_src_mac) & 0xff000000
                dst_base = self._mac_2_int(trex_dst_mac) & 0xff000000
                vm = [
                    # Source MAC address
                    STLVmFlowVar(name="src",
                                 min_value=src_base,
                                 max_value=src_base + nr_of_flows - 1,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="src", pkt_offset=8),

                    # Destination MAC address
                    STLVmFlowVar(name="dst",
                                 min_value=dst_base,
                                 max_value=dst_base + nr_of_flows - 1,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="dst", pkt_offset=2)
                ]

            elif traffic_flows == TrafficFlowType.l3_ipv4:

                src_end = str(
                    netaddr.IPAddress(
                        int(netaddr.IPAddress('1.0.0.0')) + nr_of_flows - 1))
                dst_end = str(
                    netaddr.IPAddress(
                        int(netaddr.IPAddress('2.0.0.0')) + nr_of_flows - 1))

                vm = [
                    # Source IPv4 address
                    STLVmFlowVar(name="src",
                                 min_value="1.0.0.0",
                                 max_value=src_end,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),

                    # Destination IPv4 address
                    STLVmFlowVar(name="dst",
                                 min_value="2.0.0.0",
                                 max_value=dst_end,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"),

                    # Checksum
                    STLVmFixIpv4(offset="IP")
                ]
            elif traffic_flows == TrafficFlowType.nfv_mobile:

                src_end = str(
                    netaddr.IPAddress(
                        int(netaddr.IPAddress('1.0.0.0')) + nr_of_flows - 1))
                dst_end = str(
                    netaddr.IPAddress(
                        int(netaddr.IPAddress('2.0.0.0')) + nr_of_flows - 1))

                vm = [
                    # Source MAC address
                    STLVmFlowVar(name="srcm",
                                 min_value=0x01000001,
                                 max_value=0x01000001 + l2_macs - 1,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="srcm", pkt_offset=8),

                    # Destination MAC address
                    STLVmFlowVar(name="dstm",
                                 min_value=0x02000000,
                                 max_value=0x02000000 + l2_macs - 1,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="dstm", pkt_offset=2),

                    # Source IPv4 address
                    STLVmFlowVar(name="src",
                                 min_value="1.0.0.0",
                                 max_value=src_end,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),

                    # Destination IPv4 address
                    STLVmFlowVar(name="dst",
                                 min_value="2.0.0.0",
                                 max_value=dst_end,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"),

                    # Checksum
                    STLVmFixIpv4(offset="IP")
                ]

            else:
                raise ValueError(
                    "Unsupported traffic type for T-Rex tester!!!")

            if traffic_flows == TrafficFlowType.nfv_mobile:
                stream_percentage = flow_percentage / 2
            else:
                stream_percentage = flow_percentage

            headers = L2 / L3 / L4
            padding = max(0, (packet_size - len(headers))) * 'e'
            packet = headers / padding

            trex_packet = STLPktBuilder(pkt=packet, vm=vm)

            trex_stream = STLStream(
                packet=trex_packet,
                mode=STLTXCont(percentage=stream_percentage))

            self.__trex_client.add_streams(trex_stream,
                                           ports=[self.__trex_port])

            #
            # For nfv_mobile we still need to setup the alternating streams.
            #
            if traffic_flows == TrafficFlowType.nfv_mobile:
                alternate_flows = kwargs.pop("alternate_flows", 200000)
                stream_percentage = flow_percentage / 2

                self.__active_alternate_stream = 0
                #
                # Keep the flows the same as for the Xena version, so the
                # traffic scripts using this do not have to differentiate
                # between traffic generator types.
                #
                # The Xena uses streams and every stream can generate 64K
                # flows. To Find the flow start we need the number of base
                # flows rounded of the next 64K (stream) and use the next one.
                #
                # For the individual iterations of the flow set they also
                # need to start at a 64K boundary.
                #
                start_stream_id = self._div_round_up(nr_of_flows, 0x10000) + 1
                for alternate_flow_sets in range(0, 3):
                    flow_start = start_stream_id * 0x10000

                    src_start = str(
                        netaddr.IPAddress(
                            int(netaddr.IPAddress('1.0.0.0')) + flow_start))
                    src_end = str(
                        netaddr.IPAddress(
                            int(netaddr.IPAddress('1.0.0.0')) + flow_start +
                            alternate_flows - 1))
                    dst_start = str(
                        netaddr.IPAddress(
                            int(netaddr.IPAddress('2.0.0.0')) + flow_start))
                    dst_end = str(
                        netaddr.IPAddress(
                            int(netaddr.IPAddress('2.0.0.0')) + flow_start +
                            alternate_flows - 1))

                    vm = [
                        # Source MAC address
                        STLVmFlowVar(name="srcm",
                                     min_value=0x01000001,
                                     max_value=0x01000001 + l2_macs - 1,
                                     size=4,
                                     op="inc"),
                        STLVmWrFlowVar(fv_name="srcm", pkt_offset=8),

                        # Destination MAC address
                        STLVmFlowVar(name="dstm",
                                     min_value=0x02000000,
                                     max_value=0x02000000 + l2_macs - 1,
                                     size=4,
                                     op="inc"),
                        STLVmWrFlowVar(fv_name="dstm", pkt_offset=2),

                        # Source IPv4 address
                        STLVmFlowVar(name="src",
                                     min_value=src_start,
                                     max_value=src_end,
                                     size=4,
                                     op="inc"),
                        STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),

                        # Destination IPv4 address
                        STLVmFlowVar(name="dst",
                                     min_value=dst_start,
                                     max_value=dst_end,
                                     size=4,
                                     op="inc"),
                        STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"),

                        # Checksum
                        STLVmFixIpv4(offset="IP")
                    ]
                    trex_packet = STLPktBuilder(pkt=packet, vm=vm)

                    stream = STLStream(
                        packet=trex_packet,
                        mode=STLTXCont(percentage=stream_percentage),
                        start_paused=False
                        if alternate_flow_sets == 0 else True)

                    self.__alternate_stream_sets.append(
                        self.__trex_client.add_streams(
                            stream, ports=[self.__trex_port]))

                    start_stream_id += self._div_round_up(
                        alternate_flows, 0x10000)

            self.__traffic_flows = traffic_flows
            return True
        elif traffic_flows == TrafficFlowType.none:
            self.__traffic_flows = traffic_flows
            return True
        else:
            raise ValueError(
                "Unsupported traffic flow passed for T-Rex tester!")

        self.__traffic_flows = TrafficFlowType.none
        return False

if __name__ == "__main__":
    # Create a client for stateless tests.
    clt = STLClient()
    passed = True

    try:
        udp_payload = "A" * 50
        pkt = STLPktBuilder(
            pkt=Ether() / IP(src="192.168.17.1", dst="192.168.17.2") /
            UDP(dport=8888, sport=9999, chksum=0) / udp_payload)
        st = STLStream(
            name="udp_single_burst",
            packet=pkt,
            # Packet group id
            flow_stats=STLFlowLatencyStats(pg_id=PG_ID),
            mode=STLTXSingleBurst(total_pkts=TOTAL_PKTS, pps=PPS),
        )

        clt.connect()
        all_ports = clt.get_all_ports()
        print("All ports: {}".format(",".join(map(str, all_ports))))
        tx_port, rx_port = all_ports
        print(f"TX port: {tx_port}, RX port: {rx_port}")
        tx_port_attr = clt.get_port_attr(tx_port)
        rx_port_attr = clt.get_port_attr(rx_port)
        assert tx_port_attr["src_ipv4"] == "192.168.17.1"
        assert rx_port_attr["src_ipv4"] == "192.168.18.1"
        clt.reset(ports=all_ports)
        clt.add_streams([st], ports=[tx_port])
Esempio n. 4
0
    def generate_streams(self, port, chain_id, stream_cfg, l2frame, latency=True,
                         e2e=False):
        """Create a list of streams corresponding to a given chain and stream config.

        port: port where the streams originate (0 or 1)
        chain_id: the chain to which the streams are associated to
        stream_cfg: stream configuration
        l2frame: L2 frame size (including 4-byte FCS) or 'IMIX'
        latency: if True also create a latency stream
        e2e: True if performing "end to end" connectivity check
        """
        streams = []
        pg_id, lat_pg_id = self.get_pg_id(port, chain_id)
        if l2frame == 'IMIX':
            for ratio, l2_frame_size in zip(IMIX_RATIOS, IMIX_L2_SIZES):
                pkt = self._create_pkt(stream_cfg, l2_frame_size)
                if e2e:
                    streams.append(STLStream(packet=pkt,
                                             mode=STLTXCont(pps=ratio)))
                else:
                    if stream_cfg['vxlan'] is True:
                        streams.append(STLStream(packet=pkt,
                                                 flow_stats=STLFlowStats(pg_id=pg_id,
                                                                         vxlan=True),
                                                 mode=STLTXCont(pps=ratio)))
                    else:
                        streams.append(STLStream(packet=pkt,
                                                 flow_stats=STLFlowStats(pg_id=pg_id),
                                                 mode=STLTXCont(pps=ratio)))

            if latency:
                # for IMIX, the latency packets have the average IMIX packet size
                pkt = self._create_pkt(stream_cfg, IMIX_AVG_L2_FRAME_SIZE)

        else:
            l2frame_size = int(l2frame)
            pkt = self._create_pkt(stream_cfg, l2frame_size)
            if e2e:
                streams.append(STLStream(packet=pkt,
                                         mode=STLTXCont()))
            else:
                if stream_cfg['vxlan'] is True:
                    streams.append(STLStream(packet=pkt,
                                             flow_stats=STLFlowStats(pg_id=pg_id,
                                                                     vxlan=True),
                                             mode=STLTXCont()))
                else:
                    streams.append(STLStream(packet=pkt,
                                             flow_stats=STLFlowStats(pg_id=pg_id),
                                             mode=STLTXCont()))
            # for the latency stream, the minimum payload is 16 bytes even in case of vlan tagging
            # without vlan, the min l2 frame size is 64
            # with vlan it is 68
            # This only applies to the latency stream
            if latency and stream_cfg['vlan_tag'] and l2frame_size < 68:
                pkt = self._create_pkt(stream_cfg, 68)

        if latency:
            # TRex limitation: VXLAN skip is not supported for latency stream
            streams.append(STLStream(packet=pkt,
                                     flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id),
                                     mode=STLTXCont(pps=self.LATENCY_PPS)))
        return streams
def get_streams(
    pps: float, burst_num: int, model: str, src_num, tot_pkts_burst, l3_data, test: bool
) -> list:
    """
    Utilize the single burst stream profile in STL to build the model-based traffic.
    The ONLY focus here is the inter-arrival times of bursts.
    """

    if src_num > 1:
        raise RuntimeError("Currently not implemented!")
    pps = pps * 10 ** 6
    pprint.pp(pps)
    if pps < LATENCY_FLOW_PPS:
        raise RuntimeError(
            f"The minimal PPS {LATENCY_FLOW_PPS} is required for accuracy."
        )

    # Limit the search symbol table to current module.
    func_params = globals().get(f"create_stream_params_{model}", None)
    if not func_params:
        raise RuntimeError(f"Unknown model: {model}!")
    stream_params, flow_duration = func_params(pps, burst_num, src_num, tot_pkts_burst)
    if test:
        print("* Stream parameters: ")
        pprint.pp(stream_params)
        print(f"* Flow duration: {flow_duration} seconds.")

    streams = list()
    for index, param in enumerate(stream_params):
        self_start = False
        next_name = f"s{index+1}"

        if index == 0:
            self_start = True
        elif index == len(stream_params) - 1:
            next_name = None

        udp_payload_len = param["ip_tot_len"] - IPv4_HDR_LEN - UDP_HDR_LEN
        if udp_payload_len < 16:
            raise RuntimeError("The minimal payload size is 16 bytes.")
        udp_payload = "Z" * udp_payload_len
        # UDP checksum is disabled.
        pkt = STLPktBuilder(
            pkt=Ether()
            / IP(src=l3_data["ip_src"], dst=l3_data["ip_dst"])
            / UDP(dport=8888, sport=9999, chksum=0)
            / udp_payload
        )
        streams.append(
            STLStream(
                name=f"s{index}",
                isg=param["isg"] * 10 ** 6,  # TRex interprets them as µs
                packet=pkt,
                flow_stats=STLFlowLatencyStats(pg_id=index),
                mode=STLTXSingleBurst(
                    pps=param["pps"], total_pkts=param["tot_pkts_burst"]
                ),
                next=next_name,
                self_start=self_start,
            )
        )

    return (streams, flow_duration)
Esempio n. 6
0
def create_streams_with_second_flow(stream_params: dict,
                                    second_stream_params: dict, ip_src: str,
                                    ip_dst: str) -> list:
    """Create a list of STLStream objects with the second flow."""

    spoofed_eth_srcs = ["0c:42:a1:51:41:d8", "ab:ab:ab:ab:ab:02"]
    udp_payload_size = IP_TOT_LEN - IPv4_HDR_LEN - UDP_HDR_LEN
    if udp_payload_size < 16:
        raise RuntimeError("The minimal payload size is 16 bytes.")
    print(f"UDP payload size: {udp_payload_size}")
    udp_payload = ["Z" * udp_payload_size, "Z" * (udp_payload_size - 1)]
    # UDP checksum is disabled.

    pkts = list()
    pkts.append(
        STLPktBuilder(pkt=Ether(src=spoofed_eth_srcs[0]) /
                      IP(src=ip_src, dst=ip_dst) /
                      UDP(dport=8888, sport=9999, chksum=0) / udp_payload[0]))
    pkts.append(
        STLPktBuilder(pkt=Ether(src=spoofed_eth_srcs[0]) /
                      IP(src=ip_src, dst=ip_dst) /
                      UDP(dport=8888, sport=9999, chksum=0) / udp_payload[1]))

    streams = list()
    pg_id = 0
    for prefix, params in enumerate([stream_params, second_stream_params]):
        print("Prefix: ", prefix)
        for index, stp in enumerate(params):
            next_st_name = None
            next_st_w_name = None
            self_start = False
            if index != len(params) - 1:
                next_st_name = f"s{prefix+1}{index+1}"
                next_st_w_name = f"sw{prefix+1}{index+1}"
            if index == 0:
                self_start = True

            # Add extra workload stream.
            workload_stream_pps = stp["pps"] - LATENCY_FLOW_PPS
            streams.append(
                STLStream(
                    name=f"sw{prefix+1}{index}",
                    isg=stp["isg"],
                    packet=pkts[prefix],
                    mode=STLTXSingleBurst(
                        pps=workload_stream_pps,
                        total_pkts=int(workload_stream_pps * stp["on_time"]),
                    ),
                    next=next_st_w_name,
                    self_start=self_start,
                ))

            # Add latency monitoring flow with a fixed PPS.
            streams.append(
                STLStream(
                    name=f"s{prefix+1}{index}",
                    isg=stp["isg"],
                    packet=pkts[prefix],
                    flow_stats=STLFlowLatencyStats(pg_id=pg_id),  # index),
                    mode=STLTXSingleBurst(
                        pps=LATENCY_FLOW_PPS,
                        total_pkts=int(LATENCY_FLOW_PPS * stp["on_time"]),
                    ),
                    next=next_st_name,
                    self_start=self_start,
                ))
            pg_id += 1

    return streams
Esempio n. 7
0
def create_streams(stream_params: dict, ip_src: str, ip_dst: str) -> list:
    """Create a list of STLStream objects."""

    udp_payload_size = IP_TOT_LEN - IPv4_HDR_LEN - UDP_HDR_LEN
    if udp_payload_size < 16:
        raise RuntimeError("The minimal payload size is 16 bytes.")
    print(f"UDP payload size: {udp_payload_size}")
    udp_payload = "Z" * udp_payload_size
    # UDP checksum is disabled.
    pkt = STLPktBuilder(pkt=Ether() / IP(src=ip_src, dst=ip_dst) /
                        UDP(dport=8888, sport=9999, chksum=0) / udp_payload)

    streams = list()

    # Ref: https://trex-tgn.cisco.com/trex/doc/trex_stateless.html#_tutorial_per_stream_latency_jitter_packet_errors

    # Latency streams are handled fully by software and do not support at full
    # line rate like normal streams. Typically, it is sufficient to have a
    # low-rate latency stream alongside with the real workload stream.
    # In order to have a latency resolution of 1usec, it is not necessary to
    # send a latency stream at a speed higher than 1 MPPS. It is suggested not
    # make the total rate of latency streams higher than 5 MPPS.

    for index, stp in enumerate(stream_params):
        next_st_name = None
        next_st_w_name = None
        self_start = False
        if index != len(stream_params) - 1:
            next_st_name = f"s{index+1}"
            next_st_w_name = f"sw{index+1}"
        if index == 0:
            self_start = True

        # Add extra workload stream.
        workload_stream_pps = stp["pps"] - LATENCY_FLOW_PPS
        streams.append(
            STLStream(
                name=f"sw{index}",
                isg=stp["isg"],
                packet=pkt,
                mode=STLTXSingleBurst(
                    pps=workload_stream_pps,
                    total_pkts=int(workload_stream_pps * stp["on_time"]),
                ),
                next=next_st_w_name,
                self_start=self_start,
            ))

        # Add latency monitoring flow with a fixed PPS.
        streams.append(
            STLStream(
                name=f"s{index}",
                isg=stp["isg"],
                packet=pkt,
                flow_stats=STLFlowLatencyStats(pg_id=index),
                mode=STLTXSingleBurst(
                    pps=LATENCY_FLOW_PPS,
                    total_pkts=int(LATENCY_FLOW_PPS * stp["on_time"]),
                ),
                next=next_st_name,
                self_start=self_start,
            ))

    return streams
 def _load_traffic_profiles(self, test_config):
     """Load traffic profiles for all ports based on loaded configuration."""
     test_name = test_config["name"]
     logger.debug(f"{test_name}: loading traffic profiles")
     for tx_config in test_config["transmit"]:
         tx_server_name, tx_port_id = tx_config["from"].split(":")
         rx_server_name, rx_port_id = tx_config["to"].split(":")
         tx_port_ip = self.get_port_by_id(tx_server_name, tx_port_id)["ip"]
         rx_port_ip = self.get_port_by_id(rx_server_name, rx_port_id)["ip"]
         tunables = {
             **{
                 "src_ip": tx_port_ip,
                 "dst_ip": rx_port_ip
             },
             **tx_config.get("tunables", {}),
         }
         profile_file = tx_config.get("profile_file")
         if not profile_file:
             logger.info(
                 f"{test_name}: profile file for {tx_server_name} port {tx_port_id} is not defined. Using default profile"
             )
             profile_file = os.path.join(
                 os.path.dirname(os.path.abspath(__file__)),
                 "default_profile.py",
             )
         client = self.get_server_by_name(tx_server_name)["client"]
         profile = STLProfile.load(profile_file,
                                   port_id=tx_port_id,
                                   **tunables)
         stream_ids = client.add_streams(profile.get_streams(), tx_port_id)
         stream_ids = stream_ids if isinstance(stream_ids,
                                               list) else [stream_ids]
         logger.debug(
             f"Added {len(stream_ids)} streams to {tx_server_name} port {tx_port_id}"
         )
         # to measure stats we need to attach to the receiver
         # a stream with pg_id of transmitter's stats stream, because
         # (see: https://trex-tgn.cisco.com/trex/doc/trex_faq.html
         # section 1.5.15.: "latency streams are handled by rx software")
         flow_stats_type = tunables.get("flow_stats")
         if flow_stats_type:
             if flow_stats_type not in ("stats", "latency"):
                 raise Exception(
                     'Unknown stats type. Valid values: "stats", "latency"')
             pg_id = tunables.get("flow_stats_pg_id",
                                  tunables.get("flow_stats_pg_id"))
             if not pg_id:
                 raise Exception(
                     "Streams with flow stats must have defined pg_id")
             if rx_server_name == tx_server_name:
                 continue
             if flow_stats_type == "latency":
                 flow_stats = STLFlowLatencyStats(pg_id=pg_id)
             else:
                 flow_stats = STLFlowStats(pg_id=pg_id)
             flow_stats_stream = STLStream(flow_stats=flow_stats,
                                           start_paused=True)
             flow_stats_profile = STLProfile(flow_stats_stream)
             rx_server_client = self.get_server_by_name(
                 rx_server_name)["client"]
             stream_ids = rx_server_client.add_streams(
                 flow_stats_profile.get_streams(), rx_port_id)
             stream_ids = (stream_ids if isinstance(stream_ids, list) else
                           [stream_ids])
             logger.debug(
                 f"{test_name}: Added {len(stream_ids)} streams to {rx_server_name} port {rx_port_id}"
             )
     logger.debug(f"{test_name}: traffic profiles succesfully loaded")