Beispiel #1
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
        """
        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:
                    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:
                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:
            streams.append(
                STLStream(packet=pkt,
                          flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id),
                          mode=STLTXCont(pps=self.LATENCY_PPS)))
        return streams
    def start(self, args: dict) -> None:

        pkt = Ether(dst=DEST_MAC) / IP() / TCP() / ("*" * 1500)
        # Create a traffic stream
        stream = STLStream(packet=STLPktBuilder(pkt=pkt, vm=[]),
                           mode=STLTXCont())
        self.client.add_streams(stream, ports=[0])

        logging.info(
            "Starting traffic, duration: %d sec",
            args.duration,
        )

        # Start sending traffic
        self.client.start(SENDER_PORT, mult="100%", duration=args.duration)

        logging.info("Waiting until all traffic stop")
        self.client.wait_on_traffic(ports=SENDER_PORT)

        # Get statistics for TX and RX ports
        stats = self.client.get_stats()
        rx_rate_mbps = stats[1]["rx_bps"] / (10**6)
        assert (SHAPING_RATE_MBPS * 0.95 < rx_rate_mbps < SHAPING_RATE_MBPS
                ), "The measured RX rate is not close to the port shaping rate"

        readable_stats_0 = get_readable_port_stats(stats[0])
        readable_stats_1 = get_readable_port_stats(stats[1])

        print("\n Statistics for TX port: \n")
        print(readable_stats_0)

        print("\n Statistics for RX port: \n")
        print(readable_stats_1)
 def create_streams(self):
     base_pkt = Ether() / IP(
         src=self.tunables["src_ip"], dst=self.tunables["dst_ip"]
     ) / UDP(chksum=0)
     pkt_size = self.tunables["pkt_size"] - 4  # HW will add 4 bytes ethernet FCS
     pad = self.tunables["pkt_data"] * max(0, pkt_size - len(base_pkt))
     pkt = base_pkt / pad
     return STLStream(
         packet=STLPktBuilder(pkt=pkt), mode=STLTXCont(pps=self.tunables["pps"])
     )
 def create_streams(self):
     base_pkt = (Ether() / IP(src=self.tunables["src_ip"],
                              dst=self.tunables["dst_ip"]) / UDP(chksum=0))
     pkt_size = self.tunables[
         "pkt_size"] - 4  # HW will add 4 bytes ethernet FCS
     pad = self.tunables["pkt_data"] * max(0, pkt_size - len(base_pkt))
     if len(pad) < 16:
         raise Exception(
             "At least 16 bytes payload is needed for latency measurements")
     pkt = base_pkt / pad
     stream = STLStream(packet=STLPktBuilder(pkt=pkt),
                        mode=STLTXCont(pps=self.tunables["pps"]))
     streams = [stream]
     flow_stats = self.tunables["flow_stats"]
     if flow_stats == "stats":
         latency_stream = STLStream(
             packet=STLPktBuilder(pkt=pkt),
             mode=STLTXCont(pps=self.tunables["flow_stats_pps"]),
             flow_stats=STLFlowStats(
                 pg_id=self.tunables["flow_stats_pg_id"]),
         )
     elif flow_stats == "latency":
         latency_stream = STLStream(
             packet=STLPktBuilder(pkt=pkt),
             mode=STLTXCont(pps=self.tunables["flow_stats_pps"]),
             flow_stats=STLFlowLatencyStats(
                 pg_id=self.tunables["flow_stats_pg_id"]),
         )
         streams.append(latency_stream)
     elif not flow_stats:
         pass
     else:
         error_msg = (
             f"Unknown flow stats type {flow_stats}. Available types: stats, latency"
         )
         raise Exception(error_msg)
     return streams
    def start(self, args) -> None:
        pkt = (
            Ether(src=SOURCE_MAC, dst=DEST_MAC)
            / IP(src=SOURCE_IP, dst=DEST_IP)
            / UDP()
            / ("*" * 1500)
        )

        stream = STLStream(packet=STLPktBuilder(pkt=pkt, vm=[]), mode=STLTXCont())

        logging.info("Setting up ports")
        self.client.add_streams(stream, ports=SENDER_PORTS)

        pkt_capture_limit = args.duration * 3
        logging.info(
            "Start capturing first %s RX packet from INT collector", pkt_capture_limit
        )
        self.client.set_service_mode(ports=INT_COLLECTPR_PORTS, enabled=True)
        capture = self.client.start_capture(
            rx_ports=INT_COLLECTPR_PORTS,
            limit=pkt_capture_limit,
            bpf_filter="udp and dst port 32766",
        )

        logging.info(
            "Starting traffic, duration: %ds, throughput: 100%%", args.duration
        )
        self.client.start(ports=SENDER_PORTS, mult="100%", duration=args.duration)
        logging.info("Waiting until all traffic stop")
        self.client.wait_on_traffic(ports=SENDER_PORTS)

        logging.info("Stop capturing packet from INT collector port")
        output = "/tmp/congestion-report-{}.pcap".format(
            datetime.now().strftime("%Y%m%d-%H%M%S")
        )
        self.client.stop_capture(capture["id"], output)
        analysis_report_pcap(output)
        list_port_status(self.client.get_stats())
Beispiel #6
0
    def start(self, args) -> None:
        pkt = self.get_sample_packet(args.pkt_type)
        if not pkt:
            return 1

        stream = STLStream(packet=STLPktBuilder(pkt=pkt, vm=[]),
                           mode=STLTXCont())

        logging.info("Setting up ports")
        self.client.add_streams(stream, ports=SENDER_PORTS)

        pkt_capture_limit = args.duration * 3
        logging.info("Start capturing first %s RX packet from INT collector",
                     pkt_capture_limit)
        self.client.set_service_mode(ports=INT_COLLECTPR_PORTS, enabled=True)
        capture = self.client.start_capture(
            rx_ports=INT_COLLECTPR_PORTS,
            limit=pkt_capture_limit,
            bpf_filter="udp and dst port 32766",
        )

        logging.info("Starting traffic, duration: %ds, throughput: %s",
                     args.duration, args.mult)
        self.client.start(ports=SENDER_PORTS,
                          mult=args.mult,
                          duration=args.duration)
        logging.info("Waiting until all traffic stop")
        self.client.wait_on_traffic(ports=SENDER_PORTS)

        logging.info("Stop capturing packet from INT collector port")
        output = "/tmp/int-single-flow-{}-{}.pcap".format(
            args.pkt_type,
            datetime.now().strftime("%Y%m%d-%H%M%S"))
        logging.info("Capture file {}".format(output))
        self.client.stop_capture(capture["id"], output)
        analysis_report_pcap(output)
        list_port_status(self.client.get_stats())
Beispiel #7
0
 def create_stream(self):
     return STLStream(packet=STLPktBuilder(
         pkt=Ether() / IP(src="16.0.0.1", dst="48.0.0.1") /
         UDP(dport=12, sport=1025) / (10 * 'x')),
                      mode=STLTXCont())
Beispiel #8
0
    def start(self, args: dict) -> None:

        # create packets
        pkt1 = Ether(dst=DEST_MAC) / IP(src="16.0.0.1", dst="48.0.0.1") / UDP(
            dport=12, sport=1025) / ("*" * 1500)
        pkt2 = Ether(dst=DEST_MAC) / IP(src="16.0.0.2", dst="48.0.0.2") / UDP(
            dport=12, sport=1025) / ("*" * 1500)
        pkt3 = Ether(dst=DEST_MAC) / IP(src="16.0.0.3", dst="48.0.0.3") / UDP(
            dport=12, sport=1025) / ("*" * 1500)

        #stream list
        streams = []

        # Create a traffic stream
        # assume s1 is a delay critical stream with QoS
        s1 = STLStream(packet=STLPktBuilder(pkt=pkt1),
                       mode=STLTXCont(percentage=1),
                       flow_stats=STLFlowLatencyStats(pg_id=1))
        # assume s2 is a delay critical stream without QoS
        s2 = STLStream(packet=STLPktBuilder(pkt=pkt2),
                       mode=STLTXCont(percentage=1),
                       flow_stats=STLFlowLatencyStats(pg_id=2))
        # assume s3 is a lower priority stream
        s3 = STLStream(packet=STLPktBuilder(pkt=pkt3),
                       mode=STLTXCont(percentage=98),
                       flow_stats=STLFlowLatencyStats(pg_id=3))

        # prepare ports
        self.client.reset(ports=[0, 1])

        # add sterams
        streams.append(s1)
        streams.append(s2)
        streams.append(s3)
        self.client.add_streams(streams, ports=[0])

        logging.info(
            "Starting traffic, duration: %d sec",
            args.duration,
        )

        # Start sending traffic
        self.client.start(SENDER_PORT, mult="100%", duration=args.duration)
        pgids = self.client.get_active_pgids()

        logging.info("Waiting until all traffic stop")
        self.client.wait_on_traffic(ports=SENDER_PORT)

        # stats for pg_id 1 and 2
        stats = self.client.get_pgid_stats(pgids['latency'])
        flow_stats_1 = stats['flow_stats'].get(1)
        flow_stats_2 = stats['flow_stats'].get(2)
        global_lat_stats = stats['latency']
        lat_stats_1 = global_lat_stats.get(1)
        lat_stats_2 = global_lat_stats.get(2)

        tx_pkts_1 = flow_stats_1['tx_pkts'].get(0, 0)
        rx_pkts_1 = flow_stats_1['rx_pkts'].get(1, 0)
        drops_1 = lat_stats_1['err_cntrs']['dropped']

        tx_pkts_2 = flow_stats_2['tx_pkts'].get(0, 0)
        rx_pkts_2 = flow_stats_2['rx_pkts'].get(1, 0)
        drops_2 = lat_stats_2['err_cntrs']['dropped']

        print(
            " \n TX and RX flow stats and packets dropped for s1 (i.e., delay critical): "
        )
        print("  tx packets: {0}".format(tx_pkts_1))
        print("  tx bytes : {0}".format(tx_pps_1))
        print("  rx packets : {0}".format(rx_pkts_1))
        print("  drops: {0}".format(drops_1))

        print(
            " \n TX and RX flow stats and packets dropped for s2 (i.e., delay critical): "
        )
        print("  tx packets: {0}".format(tx_pkts_2))
        print("  tx bytes : {0}".format(tx_pps_2))
        print("  rx packets : {0}".format(rx_pkts_2))
        print("  drops: {0}".format(drops_2))

        # latency info for s1
        lat_1 = lat_stats_1['latency']
        avg_1 = lat_1['average']
        tot_max_1 = lat_1['total_max']
        tot_min_1 = lat_1['total_min']

        # latency info for s2
        lat_2 = lat_stats_2['latency']
        avg_2 = lat_2['average']
        tot_max_2 = lat_2['total_max']
        tot_min_2 = lat_2['total_min']

        print('\n Latency info for s1 (ie., delay critical with QoS):')
        print("  Maximum latency(usec): {0}".format(tot_max_1))
        print("  Minimum latency(usec): {0}".format(tot_min_1))
        print("  Average latency(usec): {0}".format(avg_1))

        print('\n Latency info for s2 (ie., delay critical without QoS):')
        print("  Maximum latency(usec): {0}".format(tot_max_2))
        print("  Minimum latency(usec): {0}".format(tot_min_2))
        print("  Average latency(usec): {0}".format(avg_2))

        # max latency difference between delay critcal streams s1 and s2
        dc_max_lat_diff = tot_max_2 - tot_max_1

        assert ((LATENCY_LP_MAX_USEC - LATENCY_DC_MAX_USEC) <= dc_max_lat_diff), \
        "Priority scheduling test failed."

        # Get statistics for TX and RX ports
        stats = self.client.get_stats()
        readable_stats_0 = get_readable_port_stats(stats[0])
        readable_stats_1 = get_readable_port_stats(stats[1])

        logging.info("Priority scheduling test successfully executed.")
        print("\n Overall Statistics for TX port: \n")
        print(readable_stats_0)
        print("\n Overall Statistics for RX port: \n")
        print(readable_stats_1)
Beispiel #9
0
    def runTest(self):
        n3TEID = 0

        startIP = IPv4Address('16.0.0.1')
        endIP = startIP + UE_COUNT - 1

        accessIP = IPv4Address('10.128.13.29')
        enbIP = IPv4Address(
            '10.27.19.99'
        )  # arbitrary ip for non-existent eNodeB for gtpu encap

        # program UPF for downlink traffic by installing PDRs and FARs
        print("Installing PDRs and FARs...")
        for i in range(UE_COUNT):
            # install N6 DL PDR to match UE dst IP
            pdrDown = self.createPDR(
                srcIface=CORE,
                dstIP=int(startIP + i),
                srcIfaceMask=0xFF,
                dstIPMask=0xFFFFFFFF,
                precedence=255,
                fseID=n3TEID + i + 1,  # start from 1
                ctrID=0,
                farID=i,
                qerIDList=[N6, 1],
                needDecap=0,
            )
            self.addPDR(pdrDown)

            # install N6 DL FAR for encap
            farDown = self.createFAR(
                farID=i,
                fseID=n3TEID + i + 1,  # start from 1
                applyAction=ACTION_FORWARD,
                dstIntf=DST_ACCESS,
                tunnelType=0x1,
                tunnelIP4Src=int(accessIP),
                tunnelIP4Dst=int(enbIP),  # only one eNB to send to downlink
                tunnelTEID=0,
                tunnelPort=GTPU_PORT,
            )
            self.addFAR(farDown)

            # install N6 DL/UL application QER
            qer = self.createQER(
                gate=GATE_UNMETER,
                qerID=N6,
                fseID=n3TEID + i + 1,  # start from 1
                qfi=9,
                ulGbr=0,
                ulMbr=0,
                dlGbr=0,
                dlMbr=0,
                burstDurationMs=10,
            )
            self.addApplicationQER(qer)

        # set up trex to send traffic thru UPF
        print("Setting up TRex client...")
        vm = STLVM()
        vm.var(
            name="dst",
            min_value=str(startIP),
            max_value=str(endIP),
            size=4,
            op="random",
        )
        vm.write(fv_name="dst", pkt_offset="IP.dst")
        vm.fix_chksum()

        pkt = testutils.simple_udp_packet(
            pktlen=PKT_SIZE,
            eth_dst=UPF_DEST_MAC,
            with_udp_chksum=False,
        )
        stream = STLStream(
            packet=STLPktBuilder(pkt=pkt, vm=vm),
            mode=STLTXCont(pps=RATE),
        )
        self.trex_client.add_streams(stream, ports=[BESS_SENDER_PORT])

        print("Running traffic...")
        s_time = time.time()
        self.trex_client.start(ports=[BESS_SENDER_PORT],
                               mult="1",
                               duration=DURATION)

        # FIXME: pull QoS metrics at end instead of while traffic running
        time.sleep(DURATION - 5)
        if self.trex_client.is_traffic_active():
            stats = self.getSessionStats(q=[90, 99, 99.9], quiet=True)

            preQos = stats["preQos"]
            postDlQos = stats["postDlQos"]
            postUlQos = stats["postUlQos"]

        self.trex_client.wait_on_traffic(ports=[BESS_SENDER_PORT])
        print(f"Duration was {time.time() - s_time}")
        trex_stats = self.trex_client.get_stats()

        sent_packets = trex_stats['total']['opackets']
        recv_packets = trex_stats['total']['ipackets']

        # 0% packet loss
        self.assertEqual(
            sent_packets,
            recv_packets,
            f"Didn't receive all packets; sent {sent_packets}, received {recv_packets}",
        )

        for fseid in postDlQos:
            lat = fseid['latency']['percentileValuesNs']
            jitter = fseid['jitter']['percentileValuesNs']

            # 99th %ile latency < 100 us
            self.assertLessEqual(
                int(lat[1]) / 1000, 100,
                f"99th %ile latency was higher than 100 us! Was {int(lat[1]) / 1000} us"
            )

            # 99.9th %ile latency < 200 us
            self.assertLessEqual(
                int(lat[2]) / 1000, 200,
                f"99.9th %ile latency was higher than 200 us! Was {int(lat[2]) / 1000} us"
            )

            # 99th% jitter < 100 us
            self.assertLessEqual(
                int(jitter[1]) / 1000, 100,
                f"99th %ile jitter was higher than 100 us! Was {int(jitter[1]) / 1000} us"
            )

        return
Beispiel #10
0
    def runTest(self):
        n3TEID = 0

        startIP = IPv4Address('16.0.0.1')
        endIP = startIP + UE_COUNT - 1

        accessIP = IPv4Address('10.128.13.29')
        enbIP = IPv4Address(
            '10.27.19.99')  # arbitrary ip for nonexistent enodeB

        # program UPF for downlink traffic by installing PDRs and FARs
        print("Installing PDRs and FARs...")
        for i in range(UE_COUNT):
            # install N6 DL PDR to match UE dst IP
            pdrDown = self.createPDR(
                srcIface=CORE,
                dstIP=int(startIP + i),
                srcIfaceMask=0xFF,
                dstIPMask=0xFFFFFFFF,
                precedence=255,
                fseID=n3TEID + i + 1,  # start from 1
                ctrID=0,
                farID=i,
                qerIDList=[N6, 1],
                needDecap=0,
            )
            self.addPDR(pdrDown)

            # install N6 DL FAR for encap
            farDown = self.createFAR(
                farID=i,
                fseID=n3TEID + i + 1,  # start from 1
                applyAction=ACTION_FORWARD,
                dstIntf=DST_ACCESS,
                tunnelType=0x1,
                tunnelIP4Src=int(accessIP),
                tunnelIP4Dst=int(enbIP),  # only one eNB to send to downlink
                tunnelTEID=0,
                tunnelPort=GTPU_PORT,
            )
            self.addFAR(farDown)

            # install N6 DL/UL application QER
            qer = self.createQER(
                gate=GATE_UNMETER,
                qerID=N6,
                fseID=n3TEID + i + 1,  # start from 1
                qfi=9,
                ulGbr=0,
                ulMbr=0,
                dlGbr=0,
                dlMbr=0,
                burstDurationMs=10,
            )
            self.addApplicationQER(qer)

        # set up trex to send traffic thru UPF
        print("Setting up TRex client...")
        vm = STLVM()
        vm.var(
            name="dst",
            min_value=str(startIP),
            max_value=str(endIP),
            size=4,
            op="random",
        )
        vm.write(fv_name="dst", pkt_offset="IP.dst")
        vm.fix_chksum()

        pkt = testutils.simple_udp_packet(
            pktlen=PKT_SIZE,
            eth_dst=UPF_DEST_MAC,
            with_udp_chksum=False,
        )
        stream = STLStream(
            packet=STLPktBuilder(pkt=pkt, vm=vm),
            mode=STLTXCont(pps=RATE),
            flow_stats=STLFlowLatencyStats(pg_id=0),
        )
        self.trex_client.add_streams(stream, ports=[BESS_SENDER_PORT])

        print("Running traffic...")
        s_time = time.time()
        self.trex_client.start(
            ports=[BESS_SENDER_PORT],
            mult="1",
            duration=DURATION,
        )

        self.trex_client.wait_on_traffic(ports=[BESS_SENDER_PORT])
        print(f"Duration was {time.time() - s_time}")

        trex_stats = self.trex_client.get_stats()
        lat_stats = get_latency_stats(0, trex_stats)
        flow_stats = get_flow_stats(0, trex_stats)

        # Verify test results met baseline performance expectations

        # 0% packet loss
        self.assertEqual(
            flow_stats.tx_packets,
            flow_stats.rx_packets,
            f"Didn't receive all packets; sent {flow_stats.tx_packets}, received {flow_stats.rx_packets}",
        )

        # 99.9th %ile latency < 1000 us
        self.assertLessEqual(
            lat_stats.percentile_99_9,
            1000,
            f"99.9th %ile latency was higher than 1000 us! Was {lat_stats.percentile_99_9} us",
        )

        # jitter < 20 us
        self.assertLessEqual(
            lat_stats.jitter,
            20,
            f"Jitter was higher than 20 us! Was {lat_stats.jitter}",
        )

        return
    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(str(L2 / L3 / L4)) +
                    4) > packet_size:  # +4 for Ethernet CRC
                raise ValueError("Packet size ({} bytes) to 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
    def configure_traffic_stream(self, traffic_flows, nr_of_flows, packet_size,
                                 **kwargs):

        flow_percentage = kwargs.pop("percentage", 1000000) / 10000

        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:

            #
            # 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="00:00:01:00:00:01", dst="00:00:02:00:00:00")
            L3 = IP(src="1.0.0.0", dst="2.0.0.0")
            L4 = UDP(chksum=0)

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

            if traffic_flows == TrafficFlowType.l2_mac:
                vm = [
                    # Source MAC address
                    STLVmFlowVar(name="src",
                                 min_value=0x01000001,
                                 max_value=0x01000001 + nr_of_flows - 1,
                                 size=4,
                                 op="inc"),
                    STLVmWrFlowVar(fv_name="src", pkt_offset=8),

                    # Destination MAC address
                    STLVmFlowVar(name="dst",
                                 min_value=0x02000000,
                                 max_value=0x02000000 + 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")
                ]
            else:
                raise ValueError(
                    "Unsupported traffic type for T-Rex tester!!!")

            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=flow_percentage))

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

            return True

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

        return False