diff options
Diffstat (limited to 'scripts/automation/trex_control_plane/stl')
7 files changed, 748 insertions, 573 deletions
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py b/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py new file mode 100644 index 00000000..a729a572 --- /dev/null +++ b/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py @@ -0,0 +1,99 @@ +import stl_path +from trex_stl_lib.api import * +import argparse + + +def create_vm (ip_start, ip_end): + vm =[ + + # dest + STLVmFlowVar(name="dst", min_value = ip_start, max_value = ip_end, size = 4, op = "inc"), + STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"), + + # checksum + STLVmFixIpv4(offset = "IP") + + ] + + return vm + + +def inject_pcap (pcap_file, port, loop_count, ipg_usec, use_vm): + + # create client + c = STLClient() + + try: + if use_vm: + vm = create_vm("10.0.0.1", "10.0.0.254") + else: + vm = None + + profile = STLProfile.load_pcap(pcap_file, ipg_usec = ipg_usec, loop_count = loop_count, vm = vm) + + print "Loaded pcap {0} with {1} packets...\n".format(pcap_file, len(profile)) + + # uncomment this for simulator run + #STLSim().run(profile.get_streams(), outfile = 'out.cap') + + c.connect() + c.reset(ports = [port]) + stream_ids = c.add_streams(profile.get_streams(), ports = [port]) + + c.clear_stats() + + c.start() + c.wait_on_traffic(ports = [port]) + + stats = c.get_stats() + opackets = stats[port]['opackets'] + print "{0} packets were Tx on port {1}\n".format(opackets, port) + + except STLError as e: + print e + + finally: + c.disconnect() + + +def setParserOptions(): + parser = argparse.ArgumentParser(prog="stl_pcap.py") + + parser.add_argument("-f", help = "pcap file to inject", + dest = "pcap", + required = True, + type = str) + + parser.add_argument("-p", help = "port to inject on", + dest = "port", + required = True, + type = int) + + parser.add_argument("-n", help = "How many times to inject pcap [default is 1, 0 means forever]", + dest = "loop_count", + default = 1, + type = int) + + parser.add_argument("-i", help = "IPG in usec", + dest = "ipg", + default = 10.0, + type = float) + + + parser.add_argument("-x", help = "Iterate over IP dest", + dest = "use_vm", + default = False, + action = "store_true") + + return parser + +def main (): + parser = setParserOptions() + options = parser.parse_args() + + inject_pcap(options.pcap, options.port, options.loop_count, options.ipg, options.use_vm) + +# inject pcap +if __name__ == '__main__': + main() + diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 46d33e3e..fe162096 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -1984,6 +1984,7 @@ class STLClient(object): self.push_line.__doc__, parsing_opts.FILE_PATH, parsing_opts.PORT_LIST_WITH_ALL, + parsing_opts.COUNT, parsing_opts.DURATION, parsing_opts.IPG, parsing_opts.SPEEDUP, @@ -2010,7 +2011,7 @@ class STLClient(object): profile = STLProfile.load_pcap(opts.file[0], opts.ipg_usec, opts.speedup, - loop = True if opts.duration != -1 else False) + opts.count) id_list = self.add_streams(profile.get_streams(), opts.ports) self.start(ports = opts.ports, duration = opts.duration, force = opts.force) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py index a05e6bd9..5311884d 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py @@ -48,24 +48,40 @@ traffic_config_kwargs = { 'frame_size': 64, 'frame_size_min': 64, 'frame_size_max': 64, - 'frame_size_step': 1, # has to be 1 - 'l2_encap': 'ethernet_ii', # ( ethernet_ii ) + 'frame_size_step': 1, + 'l2_encap': 'ethernet_ii', # ( ethernet_ii | ethernet_ii_vlan ) 'mac_src': '00:00:01:00:00:01', 'mac_dst': '00:00:00:00:00:00', 'mac_src2': '00:00:01:00:00:01', 'mac_dst2': '00:00:00:00:00:00', - #'vlan': 'enable', # TODO: verify what is it exactly + 'mac_src_mode': 'fixed', # ( fixed | increment | decrement | random ) + 'mac_src_step': 1, + 'mac_src_count': 1, + 'mac_dst_mode': 'fixed', # ( fixed | increment | decrement | random ) + 'mac_dst_step': 1, + 'mac_dst_count': 1, + 'mac_src2_mode': 'fixed', # ( fixed | increment | decrement | random ) + 'mac_src2_step': 1, + 'mac_src2_count': 1, + 'mac_dst2_mode': 'fixed', # ( fixed | increment | decrement | random ) + 'mac_dst2_step': 1, + 'mac_dst2_count': 1, + # vlan options below can have multiple values for nested Dot1Q headers 'vlan_user_priority': 1, + 'vlan_priority_mode': 'fixed', # ( fixed | increment | decrement | random ) + 'vlan_priority_count': 1, + 'vlan_priority_step': 1, 'vlan_id': 0, - 'vlan_id_mode': 'increment', # ( fixed | increment) + 'vlan_id_mode': 'fixed', # ( fixed | increment | decrement | random ) 'vlan_id_count': 1, - 'vlan_id_step': 1, # has to be 1 + 'vlan_id_step': 1, 'vlan_cfi': 1, + 'vlan_protocol_tag_id': None, #L3, general - 'l3_protocol': 'ipv4', # ( ipv4 ) + 'l3_protocol': 'ipv4', # ( ipv4 | ipv6 ) 'l3_length_min': 110, 'l3_length_max': 238, - 'l3_length_step': 1, # has to be 1 + 'l3_length_step': 1, #L3, IPv4 'ip_precedence': 0, 'ip_tos_field': 0, @@ -85,10 +101,10 @@ traffic_config_kwargs = { 'ip_src_addr': '0.0.0.0', 'ip_dst_addr': '192.0.0.1', 'ip_src_mode': 'fixed', # ( fixed | increment | decrement | random ) - 'ip_src_step': 1, # has to be 1 + 'ip_src_step': 1, # ip or number 'ip_src_count': 1, 'ip_dst_mode': 'fixed', # ( fixed | increment | decrement | random ) - 'ip_dst_step': 1, # has to be 1 + 'ip_dst_step': 1, # ip or number 'ip_dst_count': 1, #L3, IPv6 'ipv6_traffic_class': 0, @@ -99,11 +115,11 @@ traffic_config_kwargs = { 'ipv6_src_addr': 'fe80:0:0:0:0:0:0:12', 'ipv6_dst_addr': 'fe80:0:0:0:0:0:0:22', 'ipv6_src_mode': 'fixed', # ( fixed | increment | decrement | random ) - 'ipv6_src_step': 1, # has to be 1 - 'ipv6_src_count': 1, # we are changing only 32 lowest bits + 'ipv6_src_step': 1, # we are changing only 32 lowest bits; can be ipv6 or number + 'ipv6_src_count': 1, 'ipv6_dst_mode': 'fixed', # ( fixed | increment | decrement | random ) - 'ipv6_dst_step': 1, # has to be 1 - 'ipv6_dst_count': 1, # we are changing only 32 lowest bits + 'ipv6_dst_step': 1, # we are changing only 32 lowest bits; can be ipv6 or number + 'ipv6_dst_count': 1, #L4, TCP 'l4_protocol': 'tcp', # ( tcp | udp ) 'tcp_src_port': 1024, @@ -121,21 +137,20 @@ traffic_config_kwargs = { 'tcp_checksum': None, 'tcp_urgent_ptr': 0, 'tcp_src_port_mode': 'increment', # ( increment | decrement | random ) - 'tcp_src_port_step': 1, # has to be 1 + 'tcp_src_port_step': 1, 'tcp_src_port_count': 1, 'tcp_dst_port_mode': 'increment', # ( increment | decrement | random ) - 'tcp_dst_port_step': 1, # has to be 1 + 'tcp_dst_port_step': 1, 'tcp_dst_port_count': 1, # L4, UDP 'udp_src_port': 1024, 'udp_dst_port': 80, 'udp_length': None, - 'udp_checksum': None, 'udp_dst_port_mode': 'increment', # ( increment | decrement | random ) - 'udp_src_port_step': 1, # has to be 1 + 'udp_src_port_step': 1, 'udp_src_port_count': 1, 'udp_src_port_mode': 'increment', # ( increment | decrement | random ) - 'udp_dst_port_step': 1, # has to be 1 + 'udp_dst_port_step': 1, 'udp_dst_port_count': 1, } @@ -180,8 +195,6 @@ class HLT_OK(dict): def merge_kwargs(default_kwargs, user_kwargs): kwargs = copy.deepcopy(default_kwargs) - if 'user_kwargs' not in kwargs: - kwargs['user_kwargs'] = copy.deepcopy(user_kwargs) for key, value in user_kwargs.items(): if key in kwargs: kwargs[key] = value @@ -194,18 +207,21 @@ def merge_kwargs(default_kwargs, user_kwargs): # change MACs from HLT formats {a b c d e f} or a-b-c-d-e-f or a.b.c.d.e.f to Scapy format a:b:c:d:e:f def correct_macs(kwargs): list_of_mac_args = ['mac_src', 'mac_dst', 'mac_src2', 'mac_dst2'] - for mac_arg in list_of_mac_args: + list_of_mac_steps = ['mac_src_step', 'mac_dst_step', 'mac_src2_step', 'mac_dst2_step'] + for mac_arg in list_of_mac_args + list_of_mac_steps: if mac_arg in kwargs: + if type(kwargs[mac_arg]) in (int, long) and kwargs[mac_arg] in list_of_mac_steps: # step can be number + continue if type(kwargs[mac_arg]) is not str: raise STLError('Argument %s should be str' % mac_arg) - kwargs[mac_arg] = kwargs[mac_arg].replace('{', '').replace('}', '').strip().replace('-', ':').replace(' ', ':').replace('.', ':') - kwargs[mac_arg] = ':'.join(kwargs[mac_arg].split(':')) # remove duplicate ':' if any + kwargs[mac_arg] = kwargs[mac_arg].replace('{', '').replace('}', '').strip().replace('-', ' ').replace(':', ' ').replace('.', ' ') + kwargs[mac_arg] = ':'.join(kwargs[mac_arg].split()) try: mac2str(kwargs[mac_arg]) # verify we are ok except: raise STLError('Incorrect MAC %s=%s, please use 01:23:45:67:89:10 or 01-23-45-67-89-10 or 01.23.45.67.89.10 or {01 23 45 67 89 10}' % (mac_arg, kwargs[mac_arg])) def is_true(input): - if input in (True, 'True', 'true', 1, '1', 'enable', 'Enable', 'Yes', 'yes', 'y', 'Y'): + if input in (True, 'True', 'true', 1, '1', 'enable', 'Enable', 'Yes', 'yes', 'y', 'Y', 'enabled', 'Enabled'): return True return False @@ -254,7 +270,6 @@ class CStreamsPerPort(defaultdict): if not isinstance(ports_list, list): ports_list = [ports_list] for port in ports_list: - del stream_hlt_args['port_handle'] if stream_id in self[port]: self[port][stream_id].update(stream_hlt_args) else: @@ -279,7 +294,6 @@ class CTRexHltApi(object): def __init__(self, verbose = 0): self.trex_client = None - self.connected = False self.verbose = verbose self._streams_history = {} # streams per stream_id per port in format of HLT arguments for modify later @@ -303,13 +317,13 @@ class CTRexHltApi(object): # sync = RPC, async = ZMQ self.trex_client = STLClient(kwargs['username'], device, sync_port = 4501, async_port = 4500, verbose_level = self.verbose) except Exception as e: - self.trex_client = None - return HLT_ERR('Could not init stateless client %s: %s' % (device, e)) + return HLT_ERR('Could not init stateless client %s: %s' % (device, e if isinstance(e, STLError) else traceback.format_exc())) + try: self.trex_client.connect() except Exception as e: self.trex_client = None - return HLT_ERR('Could not connect to device %s: %s' % (device, e)) + return HLT_ERR('Could not connect to device %s: %s' % (device, e if isinstance(e, STLError) else traceback.format_exc())) # connection successfully created with server, try acquiring ports of TRex try: @@ -317,7 +331,7 @@ class CTRexHltApi(object): self.trex_client.acquire(ports = port_list, force = kwargs['break_locks']) except Exception as e: self.trex_client = None - return HLT_ERR('Could not acquire ports %s: %s' % (port_list, e)) + return HLT_ERR('Could not acquire ports %s: %s' % (port_list, e if isinstance(e, STLError) else traceback.format_exc())) # since only supporting single TRex at the moment, 1:1 map port_handle = self.trex_client.get_acquired_ports() @@ -330,10 +344,9 @@ class CTRexHltApi(object): self.trex_client.reset(ports = port_list) except Exception as e: self.trex_client = None - return HLT_ERR('Error in reset traffic: %s' % e) + return HLT_ERR('Error in reset traffic: %s' % e if isinstance(e, STLError) else traceback.format_exc()) self._streams_history = CStreamsPerPort(hlt_history = True) - self.connected = True return HLT_OK(port_handle = port_handle) def cleanup_session(self, **user_kwargs): @@ -347,7 +360,7 @@ class CTRexHltApi(object): else: port_list = self.parse_port_list(port_list) except Exception as e: - return HLT_ERR('Unable to determine which ports to release: %s' % e) + return HLT_ERR('Unable to determine which ports to release: %s' % e if isinstance(e, STLError) else traceback.format_exc()) try: self.trex_client.release(port_list) except Exception as e: @@ -357,12 +370,11 @@ class CTRexHltApi(object): except Exception as e: return HLT_ERR('Error disconnecting: %s' % e) self.trex_client = None - self.connected = False return HLT_OK() def interface_config(self, port_handle, mode='config'): - if not self.connected: - return HLT_ERR('connect first') + if not self.trex_client: + return HLT_ERR('Connect first') ALLOWED_MODES = ['config', 'modify', 'destroy'] if mode not in ALLOWED_MODES: return HLT_ERR('Mode must be one of the following values: %s' % ALLOWED_MODES) @@ -375,12 +387,12 @@ class CTRexHltApi(object): ########################### def traffic_config(self, **user_kwargs): - if not self.connected: - return HLT_ERR('connect first') + if not self.trex_client: + return HLT_ERR('Connect first') try: correct_macs(user_kwargs) except Exception as e: - return HLT_ERR(e) + return HLT_ERR(e if isinstance(e, STLError) else traceback.format_exc()) kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs) stream_id = kwargs['stream_id'] mode = kwargs['mode'] @@ -416,7 +428,7 @@ class CTRexHltApi(object): del self._streams_history[port] return HLT_OK() except Exception as e: - return HLT_ERR('Could not reset streams at ports %s: %s' % (port_handle, e)) + return HLT_ERR('Could not reset streams at ports %s: %s' % (port_handle, e if isinstance(e, STLError) else traceback.format_exc())) if mode == 'remove': if stream_id is None: @@ -428,12 +440,12 @@ class CTRexHltApi(object): if port in self._streams_history: del self._streams_history[port] except Exception as e: - return HLT_ERR('Could not remove all streams at ports %s: %s' % (port_handle, e)) + return HLT_ERR('Could not remove all streams at ports %s: %s' % (port_handle, e if isinstance(e, STLError) else traceback.format_exc())) else: try: self._remove_stream(stream_id, port_handle) except Exception as e: - return HLT_ERR('Could not remove streams with specified by %s, error: %s' % (stream_id, e)) + return HLT_ERR('Could not remove streams with specified by %s, error: %s' % (stream_id, e if isinstance(e, STLError) else traceback.format_exc())) return HLT_OK() #if mode == 'enable': @@ -468,7 +480,7 @@ class CTRexHltApi(object): try: self.trex_client.remove_streams(stream_id, port_handle) except Exception as e: - return HLT_ERR('Could not remove stream(s) %s from port(s) %s: %s' % (stream_id, port_handle, e)) + return HLT_ERR('Could not remove stream(s) %s from port(s) %s: %s' % (stream_id, port_handle, e if isinstance(e, STLError) else traceback.format_exc())) if mode == 'create' or mode == 'modify': # create a new stream with desired attributes, starting by creating packet @@ -504,70 +516,16 @@ class CTRexHltApi(object): raise STLError('Could not create bidirectional stream 2: %s' % res2['log']) streams_per_port.add_streams_from_res(res2) except Exception as e: - return HLT_ERR('Could not generate bidirectional traffic: %s' % e) + return HLT_ERR('Could not generate bidirectional traffic: %s' % e if isinstance(e, STLError) else traceback.format_exc()) if mode == 'create': return HLT_OK(stream_id = streams_per_port) else: return HLT_OK() - if kwargs['length_mode'] == 'imix': # several streams with given length - try: - user_kwargs['length_mode'] = 'fixed' - if kwargs['l3_imix1_size'] < 32 or kwargs['l3_imix2_size'] < 32 or kwargs['l3_imix3_size'] < 32 or kwargs['l3_imix4_size'] < 32: - return HLT_ERR('l3_imix*_size should be at least 32') - total_rate = kwargs['l3_imix1_ratio'] + kwargs['l3_imix2_ratio'] + kwargs['l3_imix3_ratio'] + kwargs['l3_imix4_ratio'] - if total_rate == 0: - return HLT_ERR('Used length_mode imix, but all the ratio are 0') - save_to_yaml = kwargs.get('save_to_yaml') - rate_pps = float(kwargs['rate_pps']) - if kwargs['l3_imix1_ratio'] > 0: - if save_to_yaml and type(save_to_yaml) is str: - user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix1.yaml') - user_kwargs['frame_size'] = kwargs['l3_imix1_size'] - user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix1_ratio'] / total_rate - res = self.traffic_config(**user_kwargs) - if res['status'] == 0: - return HLT_ERR('Could not create stream imix1: %s' % res['log']) - streams_per_port.add_streams_from_res(res) - - if kwargs['l3_imix2_ratio'] > 0: - if save_to_yaml and type(save_to_yaml) is str: - user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix2.yaml') - user_kwargs['frame_size'] = kwargs['l3_imix2_size'] - user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix2_ratio'] / total_rate - res = self.traffic_config(**user_kwargs) - if res['status'] == 0: - return HLT_ERR('Could not create stream imix2: %s' % res['log']) - streams_per_port.add_streams_from_res(res) - if kwargs['l3_imix3_ratio'] > 0: - if save_to_yaml and type(save_to_yaml) is str: - kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix3.yaml') - user_kwargs['frame_size'] = kwargs['l3_imix3_size'] - user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix3_ratio'] / total_rate - res = self.traffic_config(**user_kwargs) - if res['status'] == 0: - return HLT_ERR('Could not create stream imix3: %s' % res['log']) - streams_per_port.add_streams_from_res(res) - if kwargs['l3_imix4_ratio'] > 0: - if save_to_yaml and type(save_to_yaml) is str: - user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix4.yaml') - user_kwargs['frame_size'] = kwargs['l3_imix4_size'] - user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix4_ratio'] / total_rate - res = self.traffic_config(**user_kwargs) - if res['status'] == 0: - return HLT_ERR('Could not create stream imix4: %s' % res['log']) - streams_per_port.add_streams_from_res(res) - except Exception as e: - return HLT_ERR('Could not generate imix streams: %s' % e) - if mode == 'create': - return HLT_OK(stream_id = streams_per_port) - else: - return HLT_OK() try: stream_obj = STLHltStream(**user_kwargs) - print stream_obj except Exception as e: - return HLT_ERR('Could not create stream: %s' % e) + return HLT_ERR('Could not create stream: %s' % e if isinstance(e, STLError) else traceback.format_exc()) # try adding the stream per ports try: @@ -576,17 +534,17 @@ class CTRexHltApi(object): for port in port_handle: self._streams_history.save_stream_args(port_handle, stream_id_arr[0], user_kwargs) except Exception as e: - return HLT_ERR('Could not add stream to ports: %s' % e) + return HLT_ERR('Could not add stream to ports: %s' % e if isinstance(e, STLError) else traceback.format_exc()) if mode == 'create': - return HLT_OK(stream_id = dict((port, stream_id_arr) for port in port_handle)) + return HLT_OK(stream_id = dict((port, stream_id_arr[0]) for port in port_handle)) else: return HLT_OK() return HLT_ERR('Got to the end of traffic_config, mode not implemented or forgot "return" somewhere.') def traffic_control(self, **user_kwargs): - if not self.connected: - return HLT_ERR('connect first') + if not self.trex_client: + return HLT_ERR('Connect first') kwargs = merge_kwargs(traffic_control_kwargs, user_kwargs) action = kwargs['action'] port_handle = kwargs['port_handle'] @@ -597,19 +555,17 @@ class CTRexHltApi(object): port_handle = [port_handle] if action == 'run': - try: self.trex_client.start(ports = port_handle) except Exception as e: - return HLT_ERR('Could not start traffic: %s' % e) + return HLT_ERR('Could not start traffic: %s' % e if isinstance(e, STLError) else traceback.format_exc()) return HLT_OK(stopped = 0) elif action == 'stop': - try: self.trex_client.stop(ports = port_handle) except Exception as e: - return HLT_ERR('Could not start traffic: %s' % e) + return HLT_ERR('Could not start traffic: %s' % e if isinstance(e, STLError) else traceback.format_exc()) return HLT_OK(stopped = 1) else: return HLT_ERR("Action '{0}' is not supported yet on TRex".format(action)) @@ -618,8 +574,8 @@ class CTRexHltApi(object): return HLT_ERR("Probably action '%s' is not implemented" % action) def traffic_stats(self, **user_kwargs): - if not self.connected: - return HLT_ERR('connect first') + if not self.trex_client: + return HLT_ERR('Connect first') kwargs = merge_kwargs(traffic_stats_kwargs, user_kwargs) mode = kwargs['mode'] port_handle = kwargs['port_handle'] @@ -633,7 +589,7 @@ class CTRexHltApi(object): try: stats = self.trex_client.get_stats(port_handle) except Exception as e: - return HLT_ERR('Could not retrieve stats: %s' % e) + return HLT_ERR('Could not retrieve stats: %s' % e if isinstance(e, STLError) else traceback.format_exc()) for port_id, stat_dict in stats.iteritems(): if type(port_id) in (int, long): hlt_stats_dict[port_id] = { @@ -726,444 +682,519 @@ class CTRexHltApi(object): return '\n'. join([str(response) for response in responses]) return responses -class STLHltStream(STLStream): - def __init__(self, **user_kwargs): - kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs) - try: - packet = STLHltStream.generate_packet(**user_kwargs) - except Exception as e: - raise STLError('Could not generate packet: %s' % e) - - try: - transmit_mode = kwargs['transmit_mode'] - rate_pps = kwargs['rate_pps'] - pkts_per_burst = kwargs['pkts_per_burst'] - if transmit_mode == 'continuous': - transmit_mode_class = STLTXCont(pps = rate_pps) - elif transmit_mode == 'single_burst': - transmit_mode_class = STLTXSingleBurst(pps = rate_pps, total_pkts = pkts_per_burst) - elif transmit_mode == 'multi_burst': - transmit_mode_class = STLTXMultiBurst(pps = rate_pps, total_pkts = pkts_per_burst, - count = kwargs['burst_loop_count'], ibg = kwargs['inter_burst_gap']) - else: - raise STLError('transmit_mode %s not supported/implemented') - except Exception as e: - raise STLError('Could not create transmit_mode class %s: %s' % (transmit_mode, e)) - - try: - STLStream.__init__(self, - packet = packet, - #enabled = True, - #self_start = True, - mode = transmit_mode_class, - #rx_stats = rx_stats, - #next_stream_id = -1, - stream_id = kwargs.get('stream_id'), - name = kwargs.get('name'), - ) - except Exception as e: - raise STLError('Could not create stream: %s' % e) - - debug_filename = kwargs.get('save_to_yaml') - if type(debug_filename) is str: - print 'saving to %s' % debug_filename - self.dump_to_yaml(debug_filename) - - @staticmethod - def generate_packet(**user_kwargs): - kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs) - #return Eth()/IPv6()/TCP - vm_cmds = [] - fix_ipv4_checksum = False - - ### L2 ### - if kwargs['l2_encap'] in ('ethernet_ii', 'ethernet_ii_vlan'): - #fields_desc = [ MACField("dst","00:00:00:01:00:00"), - # MACField("src","00:00:00:02:00:00"), - # XShortEnumField("type", 0x9000, ETHER_TYPES) ] - l2_layer = Ether(src = kwargs['mac_src'], dst = kwargs['mac_dst']) - if kwargs['l2_encap'] == 'ethernet_ii_vlan': - #fields_desc = [ BitField("prio", 0, 3), - # BitField("id", 0, 1), - # BitField("vlan", 1, 12), - # XShortEnumField("type", 0x0000, ETHER_TYPES) ] - l2_layer /= Dot1Q(prio = kwargs['vlan_user_priority'], - vlan = kwargs['vlan_id'], - id = kwargs['vlan_cfi'], - ) - # vlan VM - if kwargs['vlan_id_mode'] != 'fixed': - if kwargs['vlan_id_step'] != 1: - raise STLError('vlan_id_step has to be 1 (TRex limitation)') - if kwargs['vlan_id_count'] < 1: - raise STLError('vlan_id_count has to be at least 1') - if kwargs['vlan_id_count'] > 1: - raise STLError('vlan_id VM not supported yet, waiting for bitmask from stateless') - if kwargs['vlan_id_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'vlan_id', size = 4, op = 'inc', - min_value = kwargs['vlan_id'], - max_value = kwargs['vlan_id'] + kwargs['vlan_id_count'] - 1)) - elif kwargs['vlan_id_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'vlan_id', size = 4, op = 'dec', - min_value = kwargs['vlan_id'] - kwargs['vlan_id_count'] + 1, - max_value = kwargs['vlan_id'])) - elif kwargs['vlan_id_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'vlan_id', size = 4, op = 'random', - min_value = kwargs['vlan_id'], - max_value = kwargs['vlan_id'] + kwargs['vlan_id_count'] - 1)) - else: - raise STLError('vlan_id_mode %s is not supported' % kwargs['vlan_id_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='vlan_id', pkt_offset = 'Eth.vlan_id')) - +def STLHltStream(**user_kwargs): + kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs) + if kwargs['length_mode'] == 'imix': # several streams with given length + streams_arr = [] + user_kwargs['length_mode'] = 'fixed' + if kwargs['l3_imix1_size'] < 32 or kwargs['l3_imix2_size'] < 32 or kwargs['l3_imix3_size'] < 32 or kwargs['l3_imix4_size'] < 32: + raise STLError('l3_imix*_size should be at least 32') + total_rate = kwargs['l3_imix1_ratio'] + kwargs['l3_imix2_ratio'] + kwargs['l3_imix3_ratio'] + kwargs['l3_imix4_ratio'] + if total_rate == 0: + raise STLError('Used length_mode imix, but all the ratios are 0') + save_to_yaml = kwargs.get('save_to_yaml') + rate_pps = float(kwargs['rate_pps']) + if kwargs['l3_imix1_ratio'] > 0: + if save_to_yaml and type(save_to_yaml) is str: + user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix1.yaml') + user_kwargs['frame_size'] = kwargs['l3_imix1_size'] + user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix1_ratio'] / total_rate + streams_arr.append(STLHltStream(**user_kwargs)) + if kwargs['l3_imix2_ratio'] > 0: + if save_to_yaml and type(save_to_yaml) is str: + user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix2.yaml') + user_kwargs['frame_size'] = kwargs['l3_imix2_size'] + user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix2_ratio'] / total_rate + streams_arr.append(STLHltStream(**user_kwargs)) + if kwargs['l3_imix3_ratio'] > 0: + if save_to_yaml and type(save_to_yaml) is str: + user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix3.yaml') + user_kwargs['frame_size'] = kwargs['l3_imix3_size'] + user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix3_ratio'] / total_rate + streams_arr.append(STLHltStream(**user_kwargs)) + if kwargs['l3_imix4_ratio'] > 0: + if save_to_yaml and type(save_to_yaml) is str: + user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix4.yaml') + user_kwargs['frame_size'] = kwargs['l3_imix4_size'] + user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix4_ratio'] / total_rate + streams_arr.append(STLHltStream(**user_kwargs)) + return streams_arr + + # packet generation + packet = generate_packet(**user_kwargs) + try: + transmit_mode = kwargs['transmit_mode'] + rate_pps = kwargs['rate_pps'] + pkts_per_burst = kwargs['pkts_per_burst'] + if transmit_mode == 'continuous': + transmit_mode_class = STLTXCont(pps = rate_pps) + elif transmit_mode == 'single_burst': + transmit_mode_class = STLTXSingleBurst(pps = rate_pps, total_pkts = pkts_per_burst) + elif transmit_mode == 'multi_burst': + transmit_mode_class = STLTXMultiBurst(pps = rate_pps, total_pkts = pkts_per_burst, + count = kwargs['burst_loop_count'], ibg = kwargs['inter_burst_gap']) else: - raise NotImplementedError("l2_encap does not support the desired encapsulation '%s'" % kwargs['l2_encap']) - base_pkt = l2_layer - - ### L3 ### - if kwargs['l3_protocol'] == 'ipv4': - #fields_desc = [ BitField("version" , 4 , 4), - # BitField("ihl", None, 4), - # XByteField("tos", 0), - # ShortField("len", None), - # ShortField("id", 1), - # FlagsField("flags", 0, 3, ["MF","DF","evil"]), - # BitField("frag", 0, 13), - # ByteField("ttl", 64), - # ByteEnumField("proto", 0, IP_PROTOS), - # XShortField("chksum", None), - # Emph(IPField("src", "16.0.0.1")), - # Emph(IPField("dst", "48.0.0.1")), - # PacketListField("options", [], IPOption, length_from=lambda p:p.ihl*4-20) ] - # TODO: define way to pick TOS arguments - l3_layer = IP(#tos = kwargs['ip_precedence'] << 5 + kwargs['ip_tos_field'] << 2 + kwargs['ip_mbz'], - #tos = kwargs['ip_precedence'] << 5 + kwargs['ip_delay'] << 4 + kwargs['ip_throughput'] << 3 + kwargs['ip_reliability'] << 2 + kwargs['ip_cost'] << 1 + kwargs['ip_reserved'] - tos = kwargs['ip_dscp'] << 2 + kwargs['ip_cu'], - len = kwargs['l3_length'], - id = kwargs['ip_id'], - frag = kwargs['ip_fragment_offset'], - ttl = kwargs['ip_ttl'], - chksum = kwargs['ip_checksum'], - src = kwargs['ip_src_addr'], - dst = kwargs['ip_dst_addr'], - ) - # IPv4 VM - if kwargs['ip_src_mode'] != 'fixed': - if kwargs['ip_src_step'] != 1: - raise STLError('ip_src_step has to be 1 (TRex limitation)') - if kwargs['ip_src_count'] < 1: - raise STLError('ip_src_count has to be at least 1') - if kwargs['ip_src_count'] > 1: - fix_ipv4_checksum = True - ip_src_addr_num = ipv4_str_to_num(is_valid_ipv4(kwargs['ip_src_addr'])) - if kwargs['ip_src_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'inc', - min_value = ip_src_addr_num, - max_value = ip_src_addr_num + kwargs['ip_src_count'] - 1)) - elif kwargs['ip_src_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'dec', - min_value = ip_src_addr_num - kwargs['ip_src_count'] + 1, - max_value = ip_src_addr_num)) - elif kwargs['ip_src_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'random', - min_value = ip_src_addr_num, - max_value = ip_src_addr_num + kwargs['ip_src_count'] - 1)) - else: - raise STLError('ip_src_mode %s is not supported' % kwargs['ip_src_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ip_src', pkt_offset = 'IP.src')) - - if kwargs['ip_dst_mode'] != 'fixed': - if kwargs['ip_dst_step'] != 1: - raise STLError('ip_dst_step has to be 1 (TRex limitation)') - if kwargs['ip_dst_count'] < 1: - raise STLError('ip_dst_count has to be at least 1') - if kwargs['ip_dst_count'] > 1: - fix_ipv4_checksum = True - ip_dst_addr_num = ipv4_str_to_num(is_valid_ipv4(kwargs['ip_dst_addr'])) - if kwargs['ip_dst_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'inc', - min_value = ip_dst_addr_num, - max_value = ip_dst_addr_num + kwargs['ip_dst_count'] - 1)) - elif kwargs['ip_dst_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'dec', - min_value = ip_dst_addr_num - kwargs['ip_dst_count'] + 1, - max_value = ip_dst_addr_num)) - elif kwargs['ip_dst_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'random', - min_value = ip_dst_addr_num, - max_value = ip_dst_addr_num + kwargs['ip_dst_count'] - 1)) - else: - raise STLError('ip_dst_mode %s is not supported' % kwargs['ip_dst_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ip_dst', pkt_offset = 'IP.dst')) - elif kwargs['l3_protocol'] == 'ipv6': - #fields_desc = [ BitField("version" , 6 , 4), - # BitField("tc", 0, 8), #TODO: IPv6, ByteField ? - # BitField("fl", 0, 20), - # ShortField("plen", None), - # ByteEnumField("nh", 59, ipv6nh), - # ByteField("hlim", 64), - # IP6Field("dst", "::2"), - # #SourceIP6Field("src", "dst"), # dst is for src @ selection - # IP6Field("src", "::1") ] - ipv6_kwargs = {'tc': kwargs['ipv6_traffic_class'], - 'fl': kwargs['ipv6_flow_label'], - 'plen': kwargs['ipv6_length'], - 'hlim': kwargs['ipv6_hop_limit'], - 'src': kwargs['ipv6_src_addr'], - 'dst': kwargs['ipv6_dst_addr']} - if kwargs['ipv6_next_header'] is not None: - ipv6_kwargs['nh'] = kwargs['ipv6_next_header'] - l3_layer = IPv6(**ipv6_kwargs) - # IPv6 VM - if kwargs['ipv6_src_mode'] != 'fixed': - if kwargs['ipv6_src_step'] != 1: - raise STLError('ipv6_src_step has to be 1 (TRex limitation)') - if kwargs['ipv6_src_count'] < 1: - raise STLError('ipv6_src_count has to be at least 1') - if kwargs['ipv6_src_count'] > 1: - ipv6_src_addr_num = ipv4_str_to_num(is_valid_ipv6(kwargs['ipv6_src_addr'])[-4:]) - if kwargs['ipv6_src_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'inc', - min_value = ipv6_src_addr_num, - max_value = ipv6_src_addr_num + kwargs['ipv6_src_count'] - 1)) - elif kwargs['ipv6_src_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'dec', - min_value = ipv6_src_addr_num - kwargs['ipv6_src_count'] + 1, - max_value = ipv6_src_addr_num)) - elif kwargs['ipv6_src_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'random', - min_value = ipv6_src_addr_num, - max_value = ipv6_src_addr_num + kwargs['ipv6_src_count'] - 1)) - else: - raise STLError('ipv6_src_mode %s is not supported' % kwargs['ipv6_src_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ipv6_src', pkt_offset = 'IPv6.src', offset_fixup = 12)) - - if kwargs['ipv6_dst_mode'] != 'fixed': - if kwargs['ipv6_dst_step'] != 1: - raise STLError('ipv6_dst_step has to be 1 (TRex limitation)') - if kwargs['ipv6_dst_count'] < 1: - raise STLError('ipv6_dst_count has to be at least 1') - if kwargs['ipv6_dst_count'] > 1: - ipv6_dst_addr_num = ipv4_str_to_num(is_valid_ipv6(kwargs['ipv6_dst_addr'])[-4:]) - if kwargs['ipv6_dst_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'inc', - min_value = ipv6_dst_addr_num, - max_value = ipv6_dst_addr_num + kwargs['ipv6_dst_count'] - 1)) - elif kwargs['ipv6_dst_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'dec', - min_value = ipv6_dst_addr_num - kwargs['ipv6_dst_count'] + 1, - max_value = ipv6_dst_addr_num)) - elif kwargs['ipv6_dst_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'random', - min_value = ipv6_dst_addr_num, - max_value = ipv6_dst_addr_num + kwargs['ipv6_dst_count'] - 1)) - else: - raise STLError('ipv6_dst_mode %s is not supported' % kwargs['ipv6_dst_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ipv6_dst', pkt_offset = 'IPv6.dst', offset_fixup = 12)) - - else: - raise NotImplementedError("l3_protocol '%s' is not supported by TRex yet." % kwargs['l3_protocol']) - base_pkt /= l3_layer - - ### L4 ### - if kwargs['l4_protocol'] == 'tcp': - #fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES), - # ShortEnumField("dport", 80, TCP_SERVICES), - # IntField("seq", 0), - # IntField("ack", 0), - # BitField("dataofs", None, 4), - # BitField("reserved", 0, 4), - # FlagsField("flags", 0x2, 8, "FSRPAUEC"), - # ShortField("window", 8192), - # XShortField("chksum", None), - # ShortField("urgptr", 0), - # TCPOptionsField("options", {}) ] - tcp_flags = ('F' if kwargs['tcp_fin_flag'] else '' + - 'S' if kwargs['tcp_syn_flag'] else '' + - 'R' if kwargs['tcp_rst_flag'] else '' + - 'P' if kwargs['tcp_psh_flag'] else '' + - 'A' if kwargs['tcp_ack_flag'] else '' + - 'U' if kwargs['tcp_urg_flag'] else '') - - l4_layer = TCP(sport = kwargs['tcp_src_port'], - dport = kwargs['tcp_dst_port'], - seq = kwargs['tcp_seq_num'], - ack = kwargs['tcp_ack_num'], - dataofs = kwargs['tcp_data_offset'], - flags = tcp_flags, - window = kwargs['tcp_window'], - chksum = kwargs['tcp_checksum'], - urgptr = kwargs['tcp_urgent_ptr'], + raise STLError('transmit_mode %s not supported/implemented') + except Exception as e: + raise STLError('Could not create transmit_mode class %s: %s' % (transmit_mode, e if isinstance(e, STLError) else traceback.format_exc())) + + # stream generation + try: + stream = STLStream(packet = packet, + #enabled = True, + #self_start = True, + mode = transmit_mode_class, + #rx_stats = rx_stats, + #next_stream_id = -1, + stream_id = kwargs.get('stream_id'), + name = kwargs.get('name'), ) - # TCP VM - if kwargs['tcp_src_port_count'] != 1: - if kwargs['tcp_src_port_step'] != 1: - raise STLError('tcp_src_port_step has to be 1 (TRex limitation)') - if kwargs['tcp_src_port_count'] < 1: - raise STLError('tcp_src_port_count has to be at least 1') - if kwargs['tcp_src_port_count'] > 1: - fix_ipv4_checksum = True - if kwargs['tcp_src_port_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'inc', - min_value = kwargs['tcp_src_port'], - max_value = kwargs['tcp_src_port'] + kwargs['tcp_src_port_count'] - 1)) - elif kwargs['tcp_src_port_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'dec', - min_value = kwargs['tcp_src_port'] - kwargs['tcp_src_port_count'] +1, - max_value = kwargs['tcp_src_port'])) - elif kwargs['tcp_src_port_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'random', - min_value = kwargs['tcp_src_port'], - max_value = kwargs['tcp_src_port'] + kwargs['tcp_src_port_count'] - 1)) - else: - raise STLError('tcp_src_port_mode %s is not supported' % kwargs['tcp_src_port_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='tcp_src', pkt_offset = 'TCP.sport')) - - if kwargs['tcp_dst_port_count'] != 1: - if kwargs['tcp_dst_port_step'] != 1: - raise STLError('tcp_dst_port_step has to be 1 (TRex limitation)') - if kwargs['tcp_dst_port_count'] < 1: - raise STLError('tcp_dst_port_count has to be at least 1') - if kwargs['tcp_dst_port_count'] > 1: - fix_ipv4_checksum = True - if kwargs['tcp_dst_port_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'inc', - min_value = kwargs['tcp_dst_port'], - max_value = kwargs['tcp_dst_port'] + kwargs['tcp_dst_port_count'] - 1)) - elif kwargs['tcp_dst_port_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'dec', - min_value = kwargs['tcp_dst_port'] - kwargs['tcp_dst_port_count'] +1, - max_value = kwargs['tcp_dst_port'])) - elif kwargs['tcp_dst_port_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'random', - min_value = kwargs['tcp_dst_port'], - max_value = kwargs['tcp_dst_port'] + kwargs['tcp_dst_port_count'] - 1)) - else: - raise STLError('tcp_dst_port_mode %s is not supported' % kwargs['tcp_dst_port_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='tcp_dst', pkt_offset = 'TCP.dport')) - - - elif kwargs['l4_protocol'] == 'udp': - #fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES), - # ShortEnumField("dport", 53, UDP_SERVICES), - # ShortField("len", None), - # XShortField("chksum", None), ] - l4_layer = UDP(sport = kwargs['udp_src_port'], - dport = kwargs['udp_dst_port'], - len = kwargs['udp_length'], - chksum = kwargs['udp_checksum']) - # UDP VM - if kwargs['udp_src_port_count'] != 1: - if kwargs['udp_src_port_step'] != 1: - raise STLError('udp_src_port_step has to be 1 (TRex limitation)') - if kwargs['udp_src_port_count'] < 1: - raise STLError('udp_src_port_count has to be at least 1') - if kwargs['udp_src_port_count'] > 1: - fix_ipv4_checksum = True - if kwargs['udp_src_port_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'inc', - min_value = kwargs['udp_src_port'], - max_value = kwargs['udp_src_port'] + kwargs['udp_src_port_count'] - 1)) - elif kwargs['udp_src_port_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'dec', - min_value = kwargs['udp_src_port'] - kwargs['udp_src_port_count'] +1, - max_value = kwargs['udp_src_port'])) - elif kwargs['udp_src_port_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'random', - min_value = kwargs['udp_src_port'], - max_value = kwargs['udp_src_port'] + kwargs['udp_src_port_count'] - 1)) - else: - raise STLError('udp_src_port_mode %s is not supported' % kwargs['udp_src_port_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='udp_src', pkt_offset = 'UDP.sport')) - - if kwargs['udp_dst_port_count'] != 1: - if kwargs['udp_dst_port_step'] != 1: - raise STLError('udp_dst_port_step has to be 1 (TRex limitation)') - if kwargs['udp_dst_port_count'] < 1: - raise STLError('udp_dst_port_count has to be at least 1') - if kwargs['udp_dst_port_count'] > 1: - fix_ipv4_checksum = True - if kwargs['udp_dst_port_mode'] == 'increment': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'inc', - min_value = kwargs['udp_dst_port'], - max_value = kwargs['udp_dst_port'] + kwargs['udp_dst_port_count'] - 1)) - elif kwargs['udp_dst_port_mode'] == 'decrement': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'dec', - min_value = kwargs['udp_dst_port'] - kwargs['udp_dst_port_count'] +1, - max_value = kwargs['udp_dst_port'])) - elif kwargs['udp_dst_port_mode'] == 'random': - vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'random', - min_value = kwargs['udp_dst_port'], - max_value = kwargs['udp_dst_port'] + kwargs['udp_dst_port_count'] - 1)) - else: - raise STLError('udp_dst_port_mode %s is not supported' % kwargs['udp_dst_port_mode']) - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='udp_dst', pkt_offset = 'UDP.dport')) - else: - raise NotImplementedError("l4_protocol '%s' is not supported by TRex yet." % kwargs['l3_protocol']) - base_pkt /= l4_layer - - trim_dict = {'increment': 'inc', 'decrement': 'dec', 'random': 'random'} - length_mode = kwargs['length_mode'] - if length_mode == 'auto': - payload_len = 0 - elif length_mode == 'fixed': - if 'frame_size' in user_kwargs: - payload_len = kwargs['frame_size'] - len(base_pkt) - elif 'l3_length' in user_kwargs: - payload_len = kwargs['l3_length'] - len(base_pkt) - len(l2_layer) - else: # default - payload_len = kwargs['frame_size'] - len(base_pkt) - elif length_mode == 'imix': - raise STLError("Should not use length_mode 'imix' directly in packet building, split it to each stream at higher levels.") - elif length_mode in trim_dict: - if kwargs['frame_size_step'] != 1 or kwargs['l3_length_step'] != 1: - raise STLError('frame_size_step and l3_length_step has to be 1 (TRex limitation)') - if 'frame_size_min' in user_kwargs or 'frame_size_max' in user_kwargs: # size is determined by L2, higher priority over L3 size - if kwargs['frame_size_min'] < 44 or kwargs['frame_size_max'] < 44: - raise STLError('frame_size_min and frame_size_max should be at least 44') - if kwargs['frame_size_min'] > kwargs['frame_size_max']: - raise STLError('frame_size_min is bigger than frame_size_max') - if kwargs['frame_size_min'] != kwargs['frame_size_max']: - fix_ipv4_checksum = True - vm_cmds.append(CTRexVmDescFlowVar(name = 'pkt_len', size = 2, op = trim_dict[length_mode], - min_value = kwargs['frame_size_min'], - max_value = kwargs['frame_size_max'])) - vm_cmds.append(CTRexVmDescTrimPktSize('pkt_len')) - payload_len = kwargs['frame_size_max'] - len(base_pkt) - else: # size is determined by L3 - if kwargs['l3_length_min'] < 40 or kwargs['l3_length_max'] < 40: - raise STLError('l3_length_min and l3_length_max should be at least 40') - if kwargs['l3_length_min'] > kwargs['l3_length_max']: - raise STLError('l3_length_min is bigger than l3_length_max') - if kwargs['l3_length_min'] != kwargs['l3_length_max']: - fix_ipv4_checksum = True - vm_cmds.append(CTRexVmDescFlowVar(name = 'pkt_len', size = 2, op = trim_dict[length_mode], - min_value = kwargs['l3_length_min'] + len(l2_layer), - max_value = kwargs['l3_length_max'] + len(l2_layer))) - payload_len = kwargs['l3_length_max'] + len(l2_layer) - len(base_pkt) + except Exception as e: + raise STLError('Could not create stream: %s' % e if isinstance(e, STLError) else traceback.format_exc()) + + debug_filename = kwargs.get('save_to_yaml') + if type(debug_filename) is str: + print 'saving to %s' % debug_filename + stream.dump_to_yaml(debug_filename) + return stream + +def generate_packet(**user_kwargs): + correct_macs(user_kwargs) + kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs) + + vm_cmds = [] + fix_ipv4_checksum = False + + ### L2 ### + if kwargs['l2_encap'] in ('ethernet_ii', 'ethernet_ii_vlan'): + #fields_desc = [ MACField("dst","00:00:00:01:00:00"), + # MACField("src","00:00:00:02:00:00"), + # XShortEnumField("type", 0x9000, ETHER_TYPES) ] + l2_layer = Ether(src = kwargs['mac_src'], dst = kwargs['mac_dst']) + + # TODO: add Eth VM once variable masking will be done + + if kwargs['l2_encap'] == 'ethernet_ii_vlan' or (kwargs['l2_encap'] == 'ethernet_ii' and vlan_in_args(user_kwargs)): + #fields_desc = [ BitField("prio", 0, 3), + # BitField("id", 0, 1), + # BitField("vlan", 1, 12), + # XShortEnumField("type", 0x0000, ETHER_TYPES) ] + for i, vlan_kwargs in enumerate(split_vlan_args(kwargs)): + dot1q_kwargs = {'prio': vlan_kwargs['vlan_user_priority'], + 'vlan': vlan_kwargs['vlan_id'], + 'id': vlan_kwargs['vlan_cfi']} + if vlan_kwargs['vlan_protocol_tag_id'] is not None: + dot1q_kwargs['type'] = vlan_kwargs['vlan_protocol_tag_id'] + l2_layer /= Dot1Q(**dot1q_kwargs) + # vlan VM + if vlan_kwargs['vlan_id_mode'] != 'fixed': + if vlan_kwargs['vlan_id_count'] < 1: + raise STLError('vlan_id_count has to be at least 1') + if kwargs['vlan_id_count'] > 1: + var_name = 'vlan_id%s' % i + raise STLError('vlan_id VM not supported yet, waiting for bitmask from stateless') + if kwargs['vlan_id_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = var_name, size = 4, op = 'inc', step = vlan_kwargs['vlan_id_step'], + min_value = kwargs['vlan_id'], + max_value = kwargs['vlan_id'] + kwargs['vlan_id_count'] - 1)) + elif kwargs['vlan_id_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = var_name, size = 4, op = 'dec', step = vlan_kwargs['vlan_id_step'], + min_value = kwargs['vlan_id'] - kwargs['vlan_id_count'] + 1, + max_value = kwargs['vlan_id'])) + elif kwargs['vlan_id_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = var_name, size = 4, op = 'random', + min_value = kwargs['vlan_id'], + max_value = kwargs['vlan_id'] + kwargs['vlan_id_count'] - 1)) + else: + raise STLError('vlan_id_mode %s is not supported' % kwargs['vlan_id_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name = var_name, pkt_offset = 'Dot1Q:%s.vlan' % i)) + else: + raise NotImplementedError("l2_encap does not support the desired encapsulation '%s'" % kwargs['l2_encap']) + base_pkt = l2_layer + + ### L3 ### + if kwargs['l3_protocol'] == 'ipv4': + #fields_desc = [ BitField("version" , 4 , 4), + # BitField("ihl", None, 4), + # XByteField("tos", 0), + # ShortField("len", None), + # ShortField("id", 1), + # FlagsField("flags", 0, 3, ["MF","DF","evil"]), + # BitField("frag", 0, 13), + # ByteField("ttl", 64), + # ByteEnumField("proto", 0, IP_PROTOS), + # XShortField("chksum", None), + # Emph(IPField("src", "16.0.0.1")), + # Emph(IPField("dst", "48.0.0.1")), + # PacketListField("options", [], IPOption, length_from=lambda p:p.ihl*4-20) ] + ip_tos = get_TOS(user_kwargs, kwargs) + if ip_tos < 0 or ip_tos > 255: + raise STLError('TOS %s is not in range 0-255' % ip_tos) + l3_layer = IP(tos = get_TOS(user_kwargs, kwargs), + len = kwargs['l3_length'], + id = kwargs['ip_id'], + frag = kwargs['ip_fragment_offset'], + ttl = kwargs['ip_ttl'], + chksum = kwargs['ip_checksum'], + src = kwargs['ip_src_addr'], + dst = kwargs['ip_dst_addr'], + ) + # IPv4 VM + if kwargs['ip_src_mode'] != 'fixed': + if kwargs['ip_src_count'] < 1: + raise STLError('ip_src_count has to be at least 1') + if kwargs['ip_src_count'] > 1: + fix_ipv4_checksum = True + ip_src_addr_num = ipv4_str_to_num(is_valid_ipv4(kwargs['ip_src_addr'])) + if kwargs['ip_src_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'inc', step = kwargs['ip_src_step'], + min_value = ip_src_addr_num, + max_value = ip_src_addr_num + kwargs['ip_src_count'] - 1)) + elif kwargs['ip_src_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'dec', step = kwargs['ip_src_step'], + min_value = ip_src_addr_num - kwargs['ip_src_count'] + 1, + max_value = ip_src_addr_num)) + elif kwargs['ip_src_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_src', size = 4, op = 'random', + min_value = ip_src_addr_num, + max_value = ip_src_addr_num + kwargs['ip_src_count'] - 1)) + else: + raise STLError('ip_src_mode %s is not supported' % kwargs['ip_src_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ip_src', pkt_offset = 'IP.src')) + + if kwargs['ip_dst_mode'] != 'fixed': + if kwargs['ip_dst_count'] < 1: + raise STLError('ip_dst_count has to be at least 1') + if kwargs['ip_dst_count'] > 1: + fix_ipv4_checksum = True + ip_dst_addr_num = ipv4_str_to_num(is_valid_ipv4(kwargs['ip_dst_addr'])) + if kwargs['ip_dst_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'inc', step = kwargs['ip_dst_step'], + min_value = ip_dst_addr_num, + max_value = ip_dst_addr_num + kwargs['ip_dst_count'] - 1)) + elif kwargs['ip_dst_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'dec', step = kwargs['ip_dst_step'], + min_value = ip_dst_addr_num - kwargs['ip_dst_count'] + 1, + max_value = ip_dst_addr_num)) + elif kwargs['ip_dst_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ip_dst', size = 4, op = 'random', + min_value = ip_dst_addr_num, + max_value = ip_dst_addr_num + kwargs['ip_dst_count'] - 1)) + else: + raise STLError('ip_dst_mode %s is not supported' % kwargs['ip_dst_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ip_dst', pkt_offset = 'IP.dst')) + elif kwargs['l3_protocol'] == 'ipv6': + #fields_desc = [ BitField("version" , 6 , 4), + # BitField("tc", 0, 8), #TODO: IPv6, ByteField ? + # BitField("fl", 0, 20), + # ShortField("plen", None), + # ByteEnumField("nh", 59, ipv6nh), + # ByteField("hlim", 64), + # IP6Field("dst", "::2"), + # #SourceIP6Field("src", "dst"), # dst is for src @ selection + # IP6Field("src", "::1") ] + ipv6_kwargs = {'tc': kwargs['ipv6_traffic_class'], + 'fl': kwargs['ipv6_flow_label'], + 'plen': kwargs['ipv6_length'], + 'hlim': kwargs['ipv6_hop_limit'], + 'src': kwargs['ipv6_src_addr'], + 'dst': kwargs['ipv6_dst_addr']} + if kwargs['ipv6_next_header'] is not None: + ipv6_kwargs['nh'] = kwargs['ipv6_next_header'] + l3_layer = IPv6(**ipv6_kwargs) + # IPv6 VM + if kwargs['ipv6_src_mode'] != 'fixed': + if kwargs['ipv6_src_count'] < 1: + raise STLError('ipv6_src_count has to be at least 1') + if kwargs['ipv6_src_count'] > 1: + ipv6_src_addr_num = ipv4_str_to_num(is_valid_ipv6(kwargs['ipv6_src_addr'])[-4:]) + ipv6_src_step = kwargs['ipv6_src_step'] + if type(kwargs['ipv6_src_step']) is str: # convert ipv6 step to number + ipv6_src_step = ipv4_str_to_num(is_valid_ipv6(ipv6_src_step)[-4:]) + if kwargs['ipv6_src_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'inc', step = ipv6_src_step, + min_value = ipv6_src_addr_num, + max_value = ipv6_src_addr_num + kwargs['ipv6_src_count'] - 1)) + elif kwargs['ipv6_src_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'dec', step = ipv6_src_step, + min_value = ipv6_src_addr_num - kwargs['ipv6_src_count'] + 1, + max_value = ipv6_src_addr_num)) + elif kwargs['ipv6_src_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_src', size = 4, op = 'random', + min_value = ipv6_src_addr_num, + max_value = ipv6_src_addr_num + kwargs['ipv6_src_count'] - 1)) + else: + raise STLError('ipv6_src_mode %s is not supported' % kwargs['ipv6_src_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ipv6_src', pkt_offset = 'IPv6.src', offset_fixup = 12)) + + if kwargs['ipv6_dst_mode'] != 'fixed': + if kwargs['ipv6_dst_count'] < 1: + raise STLError('ipv6_dst_count has to be at least 1') + if kwargs['ipv6_dst_count'] > 1: + ipv6_dst_addr_num = ipv4_str_to_num(is_valid_ipv6(kwargs['ipv6_dst_addr'])[-4:]) + ipv6_dst_step = kwargs['ipv6_dst_step'] + if type(kwargs['ipv6_dst_step']) is str: # convert ipv6 step to number + ipv6_dst_step = ipv4_str_to_num(is_valid_ipv6(ipv6_dst_step)[-4:]) + if kwargs['ipv6_dst_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'inc', step = ipv6_dst_step, + min_value = ipv6_dst_addr_num, + max_value = ipv6_dst_addr_num + kwargs['ipv6_dst_count'] - 1)) + elif kwargs['ipv6_dst_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'dec', step = ipv6_dst_step, + min_value = ipv6_dst_addr_num - kwargs['ipv6_dst_count'] + 1, + max_value = ipv6_dst_addr_num)) + elif kwargs['ipv6_dst_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'ipv6_dst', size = 4, op = 'random', + min_value = ipv6_dst_addr_num, + max_value = ipv6_dst_addr_num + kwargs['ipv6_dst_count'] - 1)) + else: + raise STLError('ipv6_dst_mode %s is not supported' % kwargs['ipv6_dst_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='ipv6_dst', pkt_offset = 'IPv6.dst', offset_fixup = 12)) + + else: + raise NotImplementedError("l3_protocol '%s' is not supported by TRex yet." % kwargs['l3_protocol']) + base_pkt /= l3_layer + + ### L4 ### + if kwargs['l4_protocol'] == 'tcp': + #fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES), + # ShortEnumField("dport", 80, TCP_SERVICES), + # IntField("seq", 0), + # IntField("ack", 0), + # BitField("dataofs", None, 4), + # BitField("reserved", 0, 4), + # FlagsField("flags", 0x2, 8, "FSRPAUEC"), + # ShortField("window", 8192), + # XShortField("chksum", None), + # ShortField("urgptr", 0), + # TCPOptionsField("options", {}) ] + tcp_flags = ('F' if kwargs['tcp_fin_flag'] else '' + + 'S' if kwargs['tcp_syn_flag'] else '' + + 'R' if kwargs['tcp_rst_flag'] else '' + + 'P' if kwargs['tcp_psh_flag'] else '' + + 'A' if kwargs['tcp_ack_flag'] else '' + + 'U' if kwargs['tcp_urg_flag'] else '') + + l4_layer = TCP(sport = kwargs['tcp_src_port'], + dport = kwargs['tcp_dst_port'], + seq = kwargs['tcp_seq_num'], + ack = kwargs['tcp_ack_num'], + dataofs = kwargs['tcp_data_offset'], + flags = tcp_flags, + window = kwargs['tcp_window'], + chksum = kwargs['tcp_checksum'], + urgptr = kwargs['tcp_urgent_ptr'], + ) + # TCP VM + if kwargs['tcp_src_port_count'] != 1: + if kwargs['tcp_src_port_count'] < 1: + raise STLError('tcp_src_port_count has to be at least 1') + if kwargs['tcp_src_port_count'] > 1: + fix_ipv4_checksum = True + if kwargs['tcp_src_port_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'inc', step = kwargs['tcp_src_port_step'], + min_value = kwargs['tcp_src_port'], + max_value = kwargs['tcp_src_port'] + kwargs['tcp_src_port_count'] - 1)) + elif kwargs['tcp_src_port_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'dec', step = kwargs['tcp_src_port_step'], + min_value = kwargs['tcp_src_port'] - kwargs['tcp_src_port_count'] +1, + max_value = kwargs['tcp_src_port'])) + elif kwargs['tcp_src_port_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_src', size = 2, op = 'random', + min_value = kwargs['tcp_src_port'], + max_value = kwargs['tcp_src_port'] + kwargs['tcp_src_port_count'] - 1)) + else: + raise STLError('tcp_src_port_mode %s is not supported' % kwargs['tcp_src_port_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='tcp_src', pkt_offset = 'TCP.sport')) + + if kwargs['tcp_dst_port_count'] != 1: + if kwargs['tcp_dst_port_count'] < 1: + raise STLError('tcp_dst_port_count has to be at least 1') + if kwargs['tcp_dst_port_count'] > 1: + fix_ipv4_checksum = True + if kwargs['tcp_dst_port_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'inc', step = kwargs['tcp_dst_port_step'], + min_value = kwargs['tcp_dst_port'], + max_value = kwargs['tcp_dst_port'] + kwargs['tcp_dst_port_count'] - 1)) + elif kwargs['tcp_dst_port_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'dec', step = kwargs['tcp_dst_port_step'], + min_value = kwargs['tcp_dst_port'] - kwargs['tcp_dst_port_count'] +1, + max_value = kwargs['tcp_dst_port'])) + elif kwargs['tcp_dst_port_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'tcp_dst', size = 2, op = 'random', + min_value = kwargs['tcp_dst_port'], + max_value = kwargs['tcp_dst_port'] + kwargs['tcp_dst_port_count'] - 1)) + else: + raise STLError('tcp_dst_port_mode %s is not supported' % kwargs['tcp_dst_port_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='tcp_dst', pkt_offset = 'TCP.dport')) + + elif kwargs['l4_protocol'] == 'udp': + #fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES), + # ShortEnumField("dport", 53, UDP_SERVICES), + # ShortField("len", None), + # XShortField("chksum", None), ] + l4_layer = UDP(sport = kwargs['udp_src_port'], + dport = kwargs['udp_dst_port'], + len = kwargs['udp_length'], chksum = None) + # UDP VM + if kwargs['udp_src_port_count'] != 1: + if kwargs['udp_src_port_count'] < 1: + raise STLError('udp_src_port_count has to be at least 1') + if kwargs['udp_src_port_count'] > 1: + fix_ipv4_checksum = True + if kwargs['udp_src_port_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'inc', step = kwargs['udp_src_port_step'], + min_value = kwargs['udp_src_port'], + max_value = kwargs['udp_src_port'] + kwargs['udp_src_port_count'] - 1)) + elif kwargs['udp_src_port_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'dec', step = kwargs['udp_src_port_step'], + min_value = kwargs['udp_src_port'] - kwargs['udp_src_port_count'] +1, + max_value = kwargs['udp_src_port'])) + elif kwargs['udp_src_port_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_src', size = 2, op = 'random', + min_value = kwargs['udp_src_port'], + max_value = kwargs['udp_src_port'] + kwargs['udp_src_port_count'] - 1)) + else: + raise STLError('udp_src_port_mode %s is not supported' % kwargs['udp_src_port_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='udp_src', pkt_offset = 'UDP.sport')) + + if kwargs['udp_dst_port_count'] != 1: + if kwargs['udp_dst_port_count'] < 1: + raise STLError('udp_dst_port_count has to be at least 1') + if kwargs['udp_dst_port_count'] > 1: + fix_ipv4_checksum = True + if kwargs['udp_dst_port_mode'] == 'increment': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'inc', step = kwargs['udp_dst_port_step'], + min_value = kwargs['udp_dst_port'], + max_value = kwargs['udp_dst_port'] + kwargs['udp_dst_port_count'] - 1)) + elif kwargs['udp_dst_port_mode'] == 'decrement': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'dec', step = kwargs['udp_dst_port_step'], + min_value = kwargs['udp_dst_port'] - kwargs['udp_dst_port_count'] +1, + max_value = kwargs['udp_dst_port'])) + elif kwargs['udp_dst_port_mode'] == 'random': + vm_cmds.append(CTRexVmDescFlowVar(name = 'udp_dst', size = 2, op = 'random', + min_value = kwargs['udp_dst_port'], + max_value = kwargs['udp_dst_port'] + kwargs['udp_dst_port_count'] - 1)) + else: + raise STLError('udp_dst_port_mode %s is not supported' % kwargs['udp_dst_port_mode']) + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name='udp_dst', pkt_offset = 'UDP.dport')) + else: + raise NotImplementedError("l4_protocol '%s' is not supported by TRex yet." % kwargs['l3_protocol']) + base_pkt /= l4_layer + + trim_dict = {'increment': 'inc', 'decrement': 'dec', 'random': 'random'} + length_mode = kwargs['length_mode'] + if length_mode == 'auto': + payload_len = 0 + elif length_mode == 'fixed': + if 'frame_size' in user_kwargs: + payload_len = kwargs['frame_size'] - len(base_pkt) + elif 'l3_length' in user_kwargs: + payload_len = kwargs['l3_length'] - len(base_pkt) - len(l2_layer) + else: # default + payload_len = kwargs['frame_size'] - len(base_pkt) + elif length_mode == 'imix': + raise STLError("length_mode 'imix' should be treated at stream creating level.") + elif length_mode in trim_dict: + if 'frame_size_min' in user_kwargs or 'frame_size_max' in user_kwargs: # size is determined by L2, higher priority over L3 size + if kwargs['frame_size_min'] < 44 or kwargs['frame_size_max'] < 44: + raise STLError('frame_size_min and frame_size_max should be at least 44') + if kwargs['frame_size_min'] > kwargs['frame_size_max']: + raise STLError('frame_size_min is bigger than frame_size_max') + if kwargs['frame_size_min'] != kwargs['frame_size_max']: + fix_ipv4_checksum = True + vm_cmds.append(CTRexVmDescFlowVar(name = 'pkt_len', size = 2, op = trim_dict[length_mode], step = kwargs['frame_size_step'], + min_value = kwargs['frame_size_min'], + max_value = kwargs['frame_size_max'])) vm_cmds.append(CTRexVmDescTrimPktSize('pkt_len')) + payload_len = kwargs['frame_size_max'] - len(base_pkt) + else: # size is determined by L3 + if kwargs['l3_length_min'] < 40 or kwargs['l3_length_max'] < 40: + raise STLError('l3_length_min and l3_length_max should be at least 40') + if kwargs['l3_length_min'] > kwargs['l3_length_max']: + raise STLError('l3_length_min is bigger than l3_length_max') + if kwargs['l3_length_min'] != kwargs['l3_length_max']: + fix_ipv4_checksum = True + vm_cmds.append(CTRexVmDescFlowVar(name = 'pkt_len', size = 2, op = trim_dict[length_mode], step = kwargs['l3_length_step'], + min_value = kwargs['l3_length_min'] + len(l2_layer), + max_value = kwargs['l3_length_max'] + len(l2_layer))) + payload_len = kwargs['l3_length_max'] + len(l2_layer) - len(base_pkt) + vm_cmds.append(CTRexVmDescTrimPktSize('pkt_len')) + + if l3_layer.name == 'IP' or l4_layer.name == 'UDP': # add here other things need to fix due to size change + if l3_layer.name == 'IP': + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name = 'pkt_len', pkt_offset = 'IP.len', add_val = -len(l2_layer))) + if l4_layer.name == 'UDP': + vm_cmds.append(CTRexVmDescWrFlowVar(fv_name = 'pkt_len', pkt_offset = 'UDP.len', add_val = -len(l2_layer) - len(l3_layer))) + else: + raise STLError('length_mode should be one of the following: %s' % ['auto', 'fixed'] + trim_dict.keys()) + + if payload_len < 0: + raise STLError('Packet length is bigger than defined by frame_size* or l3_length*. We got payload size %s' % payload_len) + base_pkt /= '!' * payload_len + + pkt = STLPktBuilder() + pkt.set_packet(base_pkt) + if fix_ipv4_checksum and l3_layer.name == 'IP' and kwargs['ip_checksum'] is None: + vm_cmds.append(CTRexVmDescFixIpv4(offset = 'IP')) + if vm_cmds: + pkt.add_command(CTRexScRaw(vm_cmds)) + + # debug (only the base packet, without VM) + debug_filename = kwargs.get('save_to_pcap') + if type(debug_filename) is str: + pkt.dump_pkt_to_pcap(debug_filename) + return pkt + +def get_TOS(user_kwargs, kwargs): + TOS0 = set(['ip_precedence', 'ip_tos_field', 'ip_mbz']) + TOS1 = set(['ip_precedence', 'ip_delay', 'ip_throughput', 'ip_reliability', 'ip_cost', 'ip_reserved']) + TOS2 = set(['ip_dscp', 'ip_cu']) + user_args = set(user_kwargs.keys()) + if user_args & (TOS1 - TOS0) and user_args & (TOS0 - TOS1): + raise STLError('You have mixed %s and %s TOS parameters' % (TOS0, TOS1)) + if user_args & (TOS2 - TOS0) and user_args & (TOS0 - TOS2): + raise STLError('You have mixed %s and %s TOS parameters' % (TOS0, TOS2)) + if user_args & (TOS2 - TOS1) and user_args & (TOS1 - TOS2): + raise STLError('You have mixed %s and %s TOS parameters' % (TOS1, TOS2)) + if user_args & (TOS0 - TOS1 - TOS2): + return (kwargs['ip_precedence'] << 5) + (kwargs['ip_tos_field'] << 2) + kwargs['ip_mbz'] + if user_args & (TOS1 - TOS2): + return (kwargs['ip_precedence'] << 5) + (kwargs['ip_delay'] << 4) + (kwargs['ip_throughput'] << 3) + (kwargs['ip_reliability'] << 2) + (kwargs['ip_cost'] << 1) + kwargs['ip_reserved'] + return (kwargs['ip_dscp'] << 2) + kwargs['ip_cu'] + +def vlan_in_args(user_kwargs): + for arg in user_kwargs: + if arg.startswith('vlan_'): + return True + return False + +def split_vlan_arg(vlan_arg): + if type(vlan_arg) is list: + return vlan_arg + if type(vlan_arg) in (int, long, type(None)): + return [vlan_arg] + if type(vlan_arg) is str: + return vlan_arg.replace('{', '').replace('}', '').strip().split() + raise STLError('vlan argument invalid (expecting list, int, long, str, None): %s' % vlan_arg) + +def split_vlan_args(kwargs): + vlan_args_dict = {} + for arg, value in kwargs.items(): + if arg.startswith('vlan_'): + vlan_args_dict[arg] = split_vlan_arg(value) + if arg == 'vlan_protocol_tag_id': # special case, can be string of hex + print vlan_args_dict[arg] + vlan_args_dict[arg] = [int(x, 16) for x in vlan_args_dict[arg] if type(x) is str] + print vlan_args_dict[arg] + dot1q_headers_count = max([len(x) for x in vlan_args_dict.values()]) + vlan_args_per_header = [{} for _ in range(dot1q_headers_count)] + for arg, value in vlan_args_dict.items(): + for i in range(dot1q_headers_count): + if len(value) > i: + vlan_args_per_header[i][arg] = value[i] + else: + vlan_args_per_header[i][arg] = traffic_config_kwargs[arg] + return vlan_args_per_header - if l3_layer.name == 'IP' or l4_layer.name == 'UDP': # add here other things need to fix due to size change - if l3_layer.name == 'IP': - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name = 'pkt_len', pkt_offset = 'IP.len', add_val = -len(l2_layer))) - if l4_layer.name == 'UDP': - vm_cmds.append(CTRexVmDescWrFlowVar(fv_name = 'pkt_len', pkt_offset = 'UDP.len', add_val = -len(l2_layer) - len(l3_layer))) - else: - raise STLError('length_mode should be one of the following: %s' % ['auto', 'fixed'] + trim_dict.keys()) - - if payload_len < 0: - raise STLError('Packet length is bigger than defined by frame_size* or l3_length*. We got payload size %s' % payload_len) - base_pkt /= '!' * payload_len - - pkt = STLPktBuilder() - pkt.set_packet(base_pkt) - if fix_ipv4_checksum and l3_layer.name == 'IP' and kwargs['ip_checksum'] is None: - vm_cmds.append(CTRexVmDescFixIpv4(offset = 'IP')) - if vm_cmds: - pkt.add_command(CTRexScRaw(vm_cmds)) - - # debug (only the base packet, without VM) - debug_filename = kwargs.get('save_to_pcap') - if type(debug_filename) is str: - pkt.dump_pkt_to_pcap(debug_filename) - return pkt diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py index 96d1854d..7b284cb5 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py @@ -150,8 +150,8 @@ class JsonRpcClient(object): else: response = self.send_raw_msg(msg) - if response == None: - return RC_ERR("*** [RPC] - Failed to decode response from server") + if not response: + return response # print after @@ -159,8 +159,10 @@ class JsonRpcClient(object): self.verbose_msg("Server Response:\n\n" + self.pretty_json(response) + "\n") # process response (batch and regular) - - response_json = json.loads(response) + try: + response_json = json.loads(response) + except (TypeError, ValueError): + return RC_ERR("*** [RPC] - Failed to decode response from server") if isinstance(response_json, list): return self.process_batch_response(response_json) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py index 95c32b2f..24a7301b 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py @@ -674,8 +674,7 @@ class CScapyTRexPktBuilder(CTrexPktBuilderInterface): self.vm_low_level = None self.metadata="" self.path_relative_to_profile = path_relative_to_profile - - was_set=False + if pkt != None and pkt_buffer != None: raise CTRexPacketBuildException(-15, "packet builder cannot be provided with both pkt and pkt_buffer") @@ -683,9 +682,8 @@ class CScapyTRexPktBuilder(CTrexPktBuilderInterface): # process packet if pkt != None: self.set_packet(pkt) - was_set=True - if pkt_buffer != None: + elif pkt_buffer != None: self.set_pkt_as_str(pkt_buffer) # process VM @@ -694,10 +692,10 @@ class CScapyTRexPktBuilder(CTrexPktBuilderInterface): raise CTRexPacketBuildException(-14, "bad value for variable vm") self.add_command(vm if isinstance(vm, CTRexScRaw) else CTRexScRaw(vm)) - was_set=True - if was_set: - self.compile () + # if we have packet and VM - compile now + if (self.pkt or self.pkt_raw) and (self.vm_scripts): + self.compile() def dump_vm_data_as_yaml(self): @@ -829,21 +827,20 @@ class CScapyTRexPktBuilder(CTrexPktBuilderInterface): return True def compile (self): - self.vm_low_level=CTRexVmEngine() if self.pkt == None and self.pkt_raw == None: raise CTRexPacketBuildException(-14, "Packet is empty") - if self.pkt: - self.pkt.build(); + self.vm_low_level = CTRexVmEngine() + + # before VM compile set this to false + self.is_pkt_built = False + + # compile the VM for sc in self.vm_scripts: if isinstance(sc, CTRexScRaw): self._compile_raw(sc) - #for obj in self.vm_scripts: - # # tuple gen script - # if isinstance(obj, CTRexScIpv4TupleGen) - # self._add_tuple_gen(tuple_gen) #################################################### # private @@ -905,13 +902,40 @@ class CScapyTRexPktBuilder(CTrexPktBuilderInterface): self.vm_low_level.split_by_var = obj.split_by_field + # lazy packet build only on demand + def __lazy_build_packet (self): + # alrady built ? bail out + if self.is_pkt_built: + return + + # for buffer, promote to a scapy packet + if self.pkt_raw: + self.pkt = Ether(self.pkt_raw) + self.pkt.build() + self.pkt_raw = None + + # regular scapy packet + elif self.pkt: + self.pkt.build() + + else: + # should not reach here + raise CTRexPacketBuildException(-11, 'empty packet') + + + self.is_pkt_built = True + def _pkt_layer_offset (self,layer_name): - assert self.pkt != None, 'empty packet' + + self.__lazy_build_packet() + p_utl=CTRexScapyPktUtl(self.pkt); return p_utl.get_layer_offet_by_str(layer_name) def _name_to_offset(self,field_name): - assert self.pkt != None, 'empty packet' + + self.__lazy_build_packet() + p_utl=CTRexScapyPktUtl(self.pkt); return p_utl.get_field_offet_by_str(field_name) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py index 130beabe..b72b5d35 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py @@ -2,7 +2,7 @@ from trex_stl_exceptions import * from trex_stl_packet_builder_interface import CTrexPktBuilderInterface -from trex_stl_packet_builder_scapy import CScapyTRexPktBuilder, Ether, IP, RawPcapReader +from trex_stl_packet_builder_scapy import CScapyTRexPktBuilder, Ether, IP, UDP, TCP, RawPcapReader from collections import OrderedDict, namedtuple from dpkt import pcap @@ -194,6 +194,7 @@ class STLStream(object): self.fields['packet'] = packet.dump_pkt() self.fields['vm'] = packet.get_vm_data() + self.pkt = base64.b64decode(self.fields['packet']['binary']) # this is heavy, calculate lazy self.packet_desc = None @@ -234,12 +235,15 @@ class STLStream(object): def get_pkt_type (self): if self.packet_desc == None: - self.packet_desc = CScapyTRexPktBuilder.pkt_layers_desc_from_buffer(base64.b64decode(self.fields['packet']['binary'])) + self.packet_desc = CScapyTRexPktBuilder.pkt_layers_desc_from_buffer(self.get_pkt()) return self.packet_desc + def get_pkt (self): + return self.pkt + def get_pkt_len (self, count_crc = True): - pkt_len = len(base64.b64decode(self.fields['packet']['binary'])) + pkt_len = len(base64.b64decode(self.get_pkt())) if count_crc: pkt_len += 4 @@ -454,8 +458,10 @@ class STLProfile(object): finally: sys.path.remove(basedir) + + # loop_count = 0 means loop forever @staticmethod - def load_pcap (pcap_file, ipg_usec = None, speedup = 1.0, loop = False): + def load_pcap (pcap_file, ipg_usec = None, speedup = 1.0, loop_count = 1, vm = None): # check filename if not os.path.isfile(pcap_file): raise STLError("file '{0}' does not exists".format(pcap_file)) @@ -474,16 +480,19 @@ class STLProfile(object): # handle last packet if i == len(pkts): - next = 1 if loop else None + next = 1 + action_count = loop_count else: next = i + 1 + action_count = 0 streams.append(STLStream(name = i, - packet = CScapyTRexPktBuilder(pkt_buffer = cap), + packet = CScapyTRexPktBuilder(pkt_buffer = cap, vm = vm), mode = STLTXSingleBurst(total_pkts = 1), self_start = True if (i == 1) else False, isg = (ts_usec - last_ts_usec), # seconds to usec + action_count = action_count, next = next)) last_ts_usec = ts_usec @@ -525,3 +534,5 @@ class STLProfile(object): return yaml_str + def __len__ (self): + return len(self.streams) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py index 84dd5090..92e9a1d6 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py @@ -26,6 +26,7 @@ TOTAL = 14 FULL_OUTPUT = 15 IPG = 16 SPEEDUP = 17 +COUNT = 18 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -216,6 +217,12 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': 1.0, 'type': float}), + COUNT: ArgumentPack(['-n', '--count'], + {'help': "How many times to perform action [default is 1, 0 means forever]", + 'dest': "count", + 'default': 1, + 'type': int}), + PORT_LIST: ArgumentPack(['--port'], {"nargs": '+', 'dest':'ports', |