From deb1ce15e6dd0e64c981dbedbf764e5c426e6ec4 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 14 Nov 2016 10:58:56 +0200 Subject: fix STL push pcap: start from zero (or explicit delay) Signed-off-by: Yaroslav Brustinov --- .../trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib') 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 e63f9125..63e61b1d 100755 --- 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 @@ -1073,6 +1073,8 @@ class STLProfile(object): def __pkts_to_streams (pkts, ipg_usec, speedup, loop_count, vm, packet_hook, start_delay_usec = 0): streams = [] + if speedup == 0: + raise STLError('Speedup should not be 0') # 10 ms delay before starting the PCAP last_ts_usec = -(start_delay_usec) @@ -1084,7 +1086,10 @@ class STLProfile(object): for i, (cap, meta) in enumerate(pkts, start = 1): # IPG - if not provided, take from cap if ipg_usec == None: - ts_usec = (meta[0] * 1e6 + meta[1]) / float(speedup) + packet_time = meta[0] * 1e6 + meta[1] + if i == 1: + base_time = packet_time + ts_usec = (packet_time - base_time) / float(speedup) else: ts_usec = (ipg_usec * i) / float(speedup) -- cgit 1.2.3-korg From b65b65e73948d297d5bc1ed0798e8b2162ff8b63 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 14 Nov 2016 16:19:34 +0200 Subject: STL push dual port split fixes Signed-off-by: Yaroslav Brustinov --- .../trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 7 ++++--- .../trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib') 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 80a4c4dc..a390534b 100755 --- 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 @@ -2392,7 +2392,7 @@ class STLClient(object): slave = port ^ 0x1 if slave in ports: - raise STLError("dual mode: cannot provide adjacent ports ({0}, {1}) in a batch".format(master, slave)) + raise STLError("dual mode: please specify only one of adjacent ports ({0}, {1}) in a batch".format(master, slave)) if not slave in self.get_acquired_ports(): raise STLError("dual mode: adjacent port {0} must be owned during dual mode".format(slave)) @@ -2441,7 +2441,7 @@ class STLClient(object): self.logger.post_cmd(RC_ERR(e)) raise - all_ports = ports + [p ^ 0x1 for p in ports] + all_ports = ports + [p ^ 0x1 for p in ports if profile_b] self.remove_all_streams(ports = all_ports) @@ -2450,7 +2450,8 @@ class STLClient(object): slave = port ^ 0x1 self.add_streams(profile_a.get_streams(), master) - self.add_streams(profile_b.get_streams(), slave) + if profile_b: + self.add_streams(profile_b.get_streams(), slave) return self.start(ports = all_ports, duration = duration) 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 63e61b1d..aa797773 100755 --- 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 @@ -1046,6 +1046,17 @@ class STLProfile(object): else: pkts_a, pkts_b = PCAPReader(pcap_file).read_all(split_mode = split_mode) + # swap the packets if a is empty, or the ts of first packet in b is earlier + if not pkts_a: + pkts_a, pkts_b = pkts_b, pkts_a + elif (ipg_usec is None) and pkts_b: + meta = pkts_a[0][1] + start_time_a = meta[0] * 1e6 + meta[1] + meta = pkts_b[0][1] + start_time_b = meta[0] * 1e6 + meta[1] + if start_time_b < start_time_a: + pkts_a, pkts_b = pkts_b, pkts_a + profile_a = STLProfile.__pkts_to_streams(pkts_a, ipg_usec, speedup, -- cgit 1.2.3-korg From 552626cf9ccf43636b48675caf61a1169853943e Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 15 Nov 2016 15:45:03 +0200 Subject: https://trex-tgn.cisco.com/youtrack/issue/trex-271 Signed-off-by: imarom --- .../trex_control_plane/stl/console/trex_tui.py | 4 +- .../stl/trex_stl_lib/trex_stl_async_client.py | 61 ++++++++++++++++------ .../stl/trex_stl_lib/trex_stl_client.py | 6 ++- 3 files changed, 50 insertions(+), 21 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index d7db6d30..bf6ed164 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -645,14 +645,14 @@ class TrexTUI(): # regular state if self.state == self.STATE_ACTIVE: # if no connectivity - move to lost connecitivty - if not self.stateless_client.async_client.is_alive(): + if not self.stateless_client.async_client.is_active(): self.stateless_client._invalidate_stats(self.pm.ports) self.state = self.STATE_LOST_CONT # lost connectivity elif self.state == self.STATE_LOST_CONT: - # got it back + # if the async is alive (might be zomibe, but alive) try to reconnect if self.stateless_client.async_client.is_alive(): # move to state reconnect self.state = self.STATE_RECONNECT diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py index 2c95844b..11e87592 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py @@ -137,6 +137,10 @@ class CTRexAsyncStatsManager(): class CTRexAsyncClient(): + THREAD_STATE_ACTIVE = 1 + THREAD_STATE_ZOMBIE = 2 + THREAD_STATE_DEAD = 3 + def __init__ (self, server, port, stateless_client): self.port = port @@ -159,7 +163,10 @@ class CTRexAsyncClient(): self.connected = False self.zipped = ZippedMsg() - + + self.t_state = self.THREAD_STATE_DEAD + + # connects the async channel def connect (self): @@ -173,8 +180,8 @@ class CTRexAsyncClient(): self.socket = self.context.socket(zmq.SUB) - # before running the thread - mark as active - self.active = True + # before running the thread - mark as active + self.t_state = self.THREAD_STATE_ACTIVE self.t = threading.Thread(target = self._run) # kill this thread on exit and don't add it to the join list @@ -198,26 +205,26 @@ class CTRexAsyncClient(): return RC_OK() - - # disconnect def disconnect (self): if not self.connected: return # mark for join - self.active = False - - # signal that the context was destroyed (exit the thread loop) + self.t_state = self.THREAD_STATE_DEAD self.context.term() - - # join self.t.join() + # done self.connected = False + # set the thread as a zombie (in case of server death) + def set_as_zombie (self): + self.last_data_recv_ts = None + self.t_state = self.THREAD_STATE_ZOMBIE + # thread function def _run (self): @@ -231,12 +238,19 @@ class CTRexAsyncClient(): self.monitor.reset() - while self.active: + while self.t_state != self.THREAD_STATE_DEAD: try: with self.monitor: line = self.socket.recv() + # last data recv. + self.last_data_recv_ts = time.time() + + # if thread was marked as zomibe - it does nothing besides fetching messages + if self.t_state == self.THREAD_STATE_ZOMBIE: + continue + self.monitor.on_recv_msg(line) # try to decomrpess @@ -246,7 +260,6 @@ class CTRexAsyncClient(): line = line.decode() - self.last_data_recv_ts = time.time() # signal once if not got_data: @@ -259,13 +272,14 @@ class CTRexAsyncClient(): # signal once if got_data: self.event_handler.on_async_dead() + self.set_as_zombie() got_data = False continue except zmq.ContextTerminated: # outside thread signaled us to exit - assert(not self.active) + assert(self.t_state != self.THREAD_STATE_ACTIVE) break msg = json.loads(line) @@ -283,16 +297,29 @@ class CTRexAsyncClient(): # closing of socket must be from the same thread self.socket.close(linger = 0) - def is_thread_alive (self): - return self.t.is_alive() - - # did we get info for the last 3 seconds ? + + # return True if the subscriber got data in the last 3 seconds + # even if zombie - will return true if got data def is_alive (self): + + # maybe the thread has exited with exception + if not self.t.is_alive(): + return False + + # simply no data if self.last_data_recv_ts == None: return False + # timeout of data return ( (time.time() - self.last_data_recv_ts) < 3 ) + + # more granular than active - it means that thread state is active we get info + # zomibes will return false + def is_active (self): + return self.is_alive() and self.t_state == self.THREAD_STATE_ACTIVE + + def get_stats (self): return self.stats 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 a390534b..7351f207 100755 --- 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 @@ -175,8 +175,8 @@ class EventsHandler(object): def on_async_dead (self): if self.client.connected: msg = 'Lost connection to server' - self.__add_event_log('local', 'info', msg, True) self.client.connected = False + self.__add_event_log('local', 'info', msg, True) def on_async_alive (self): @@ -341,6 +341,8 @@ class EventsHandler(object): # server stopped elif (event_type == 100): ev = "Server has stopped" + # to avoid any new messages on async + self.client.async_client.set_as_zombie() self.__async_event_server_stopped() show_event = True @@ -2613,7 +2615,7 @@ class STLClient(object): while set(self.get_active_ports()).intersection(ports): # make sure ASYNC thread is still alive - otherwise we will be stuck forever - if not self.async_client.is_thread_alive(): + if not self.async_client.is_active(): raise STLError("subscriber thread is dead") time.sleep(0.01) -- cgit 1.2.3-korg From a21e1f0b55e724f099e8732471788f6e1de1e3ef Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Tue, 15 Nov 2016 20:04:48 +0200 Subject: STL push remote pcap: don't check that path exists at client side Signed-off-by: Yaroslav Brustinov --- .../stl/trex_stl_lib/trex_stl_client.py | 33 +++++++++++++--------- .../stl/trex_stl_lib/utils/parsing_opts.py | 9 ++++++ 2 files changed, 29 insertions(+), 13 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib') 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 7351f207..6b53e67e 100755 --- 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 @@ -3174,21 +3174,28 @@ class STLClient(object): @__console def push_line (self, line): '''Push a pcap file ''' + args = [self, + "push", + self.push_line.__doc__, + parsing_opts.REMOTE_FILE, + parsing_opts.PORT_LIST_WITH_ALL, + parsing_opts.COUNT, + parsing_opts.DURATION, + parsing_opts.IPG, + parsing_opts.SPEEDUP, + parsing_opts.FORCE, + parsing_opts.DUAL] + + parser = parsing_opts.gen_parser(*(args + [parsing_opts.FILE_PATH_NO_CHECK])) + opts = parser.parse_args(line.split(), verify_acquired = True) - parser = parsing_opts.gen_parser(self, - "push", - self.push_line.__doc__, - parsing_opts.FILE_PATH, - parsing_opts.REMOTE_FILE, - parsing_opts.PORT_LIST_WITH_ALL, - parsing_opts.COUNT, - parsing_opts.DURATION, - parsing_opts.IPG, - parsing_opts.SPEEDUP, - parsing_opts.FORCE, - parsing_opts.DUAL) + if not opts: + return opts + + if not opts.remote: + parser = parsing_opts.gen_parser(*(args + [parsing_opts.FILE_PATH])) + opts = parser.parse_args(line.split(), verify_acquired = True) - opts = parser.parse_args(line.split(), verify_acquired = True) if not opts: return opts 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 7eda8635..34cafd79 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 @@ -43,6 +43,7 @@ CORE_MASK = 26 DUAL = 27 FLOW_CTRL = 28 SUPPORTED = 29 +FILE_PATH_NO_CHECK = 30 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -362,6 +363,14 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'type': is_valid_file, 'help': "File path to load"}), + FILE_PATH_NO_CHECK: ArgumentPack(['-f'], + {'metavar': 'FILE', + 'dest': 'file', + 'nargs': 1, + 'required': True, + 'type': str, + 'help': "File path to load"}), + FILE_FROM_DB: ArgumentPack(['--db'], {'metavar': 'LOADED_STREAM_PACK', 'help': "A stream pack which already loaded into console cache."}), -- cgit 1.2.3-korg