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
f"The average latency: {avg} usecs, total max: {total_max} usecs, jitter: {jitter} usecs" ) print(hist) return True 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)
TOTAL_PKTS = args.total_pkts PPS = args.pps MONITOR_DUR = args.monitor_dur print(f"Total TX packets: {TOTAL_PKTS}, PPS: {PPS},Monitor duration: {MONITOR_DUR}") # Create a client for stateless tests. clt = STLClient() passed = True try: udp_payload = "A" * 1400 if args.eth_src_spoofing: pkt = STLPktBuilder( pkt=Ether(SPOOFED_ETH_SRC) / IP(src=args.ip_src, dst=args.ip_dst) / UDP(dport=8888, sport=9999, chksum=0) / udp_payload ) else: pkt = STLPktBuilder( pkt=Ether() / IP(src=args.ip_src, dst=args.ip_dst) / 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),
def _create_pkt(self, stream_cfg, l2frame_size): """Create a packet of given size. l2frame_size: size of the L2 frame in bytes (including the 32-bit FCS) """ # Trex will add the FCS field, so we need to remove 4 bytes from the l2 frame size frame_size = int(l2frame_size) - 4 vm_param = [] if stream_cfg['vxlan'] is True: self._bind_vxlan() encap_level = '1' pkt_base = Ether(src=stream_cfg['vtep_src_mac'], dst=stream_cfg['vtep_dst_mac']) if stream_cfg['vtep_vlan'] is not None: pkt_base /= Dot1Q(vlan=stream_cfg['vtep_vlan']) pkt_base /= IP(src=stream_cfg['vtep_src_ip'], dst=stream_cfg['vtep_dst_ip']) pkt_base /= UDP(sport=random.randint(1337, 32767), dport=4789) pkt_base /= VXLAN(vni=stream_cfg['net_vni']) pkt_base /= Ether(src=stream_cfg['mac_src'], dst=stream_cfg['mac_dst']) # need to randomize the outer header UDP src port based on flow vxlan_udp_src_fv = STLVmFlowVar( name="vxlan_udp_src", min_value=1337, max_value=32767, size=2, op="random") vm_param = [vxlan_udp_src_fv, STLVmWrFlowVar(fv_name="vxlan_udp_src", pkt_offset="UDP.sport")] else: encap_level = '0' pkt_base = Ether(src=stream_cfg['mac_src'], dst=stream_cfg['mac_dst']) if stream_cfg['vlan_tag'] is not None: pkt_base /= Dot1Q(vlan=stream_cfg['vlan_tag']) udp_args = {} if stream_cfg['udp_src_port']: udp_args['sport'] = int(stream_cfg['udp_src_port']) if stream_cfg['udp_dst_port']: udp_args['dport'] = int(stream_cfg['udp_dst_port']) pkt_base /= IP() / UDP(**udp_args) if stream_cfg['ip_addrs_step'] == 'random': src_fv = STLVmFlowVarRepeatableRandom( name="ip_src", min_value=stream_cfg['ip_src_addr'], max_value=stream_cfg['ip_src_addr_max'], size=4, seed=random.randint(0, 32767), limit=stream_cfg['ip_src_count']) dst_fv = STLVmFlowVarRepeatableRandom( name="ip_dst", min_value=stream_cfg['ip_dst_addr'], max_value=stream_cfg['ip_dst_addr_max'], size=4, seed=random.randint(0, 32767), limit=stream_cfg['ip_dst_count']) else: src_fv = STLVmFlowVar( name="ip_src", min_value=stream_cfg['ip_src_addr'], max_value=stream_cfg['ip_src_addr'], size=4, op="inc", step=stream_cfg['ip_addrs_step']) dst_fv = STLVmFlowVar( name="ip_dst", min_value=stream_cfg['ip_dst_addr'], max_value=stream_cfg['ip_dst_addr_max'], size=4, op="inc", step=stream_cfg['ip_addrs_step']) vm_param.extend([ src_fv, STLVmWrFlowVar(fv_name="ip_src", pkt_offset="IP:{}.src".format(encap_level)), dst_fv, STLVmWrFlowVar(fv_name="ip_dst", pkt_offset="IP:{}.dst".format(encap_level)) ]) for encap in range(int(encap_level), -1, -1): # Fixing the checksums for all encap levels vm_param.append(STLVmFixChecksumHw(l3_offset="IP:{}".format(encap), l4_offset="UDP:{}".format(encap), l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP)) pad = max(0, frame_size - len(pkt_base)) * 'x' return STLPktBuilder(pkt=pkt_base / pad, vm=STLScVmRaw(vm_param))
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)
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
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