From a5788f0e036baa9c28eab4abb705affc89abc498 Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 17 Feb 2016 09:58:32 -0500 Subject: stl_pcap.py example - how to transmit a pcap --- .../trex_control_plane/stl/examples/stl_pcap.py | 99 ++++++++++++++++++++++ .../stl/trex_stl_lib/trex_stl_client.py | 3 +- .../trex_stl_lib/trex_stl_packet_builder_scapy.py | 56 ++++++++---- .../stl/trex_stl_lib/trex_stl_streams.py | 23 +++-- .../stl/trex_stl_lib/utils/parsing_opts.py | 7 ++ 5 files changed, 165 insertions(+), 23 deletions(-) create mode 100644 scripts/automation/trex_control_plane/stl/examples/stl_pcap.py (limited to 'scripts') 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_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py index c788e277..e028d6d5 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 @@ -627,8 +627,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") @@ -636,9 +635,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 @@ -647,10 +645,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): @@ -782,21 +780,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 @@ -858,13 +855,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', -- cgit 1.2.3-korg