From 1f90e4ed08414c8aa423693c4ee8fa84e7675230 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 24 Sep 2015 17:51:04 +0300 Subject: some improvements to the console --- .../client_utils/jsonrpc_client.py | 50 ++++++++- .../trex_control_plane/console/trex_console.py | 112 ++++++++++++++++++++- 2 files changed, 153 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py index 8b091b5e..db52d633 100644 --- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py @@ -60,6 +60,7 @@ class JsonRpcClient(object): return rc + # pretty print for JSON def pretty_json (self, json_str, use_colors = True): pretty_str = json.dumps(json.loads(json_str), indent = 4, separators=(',', ': '), sort_keys = True) @@ -87,6 +88,7 @@ class JsonRpcClient(object): print "[verbose] " + msg + # batch messages def create_batch (self): return BatchMessage(self) @@ -114,6 +116,7 @@ class JsonRpcClient(object): return self.send_raw_msg(msg, block) + # low level send of string message def send_raw_msg (self, msg, block = False): self.verbose_msg("Sending Request To Server:\n\n" + self.pretty_json(msg) + "\n") @@ -268,9 +271,15 @@ class TrexStatelessClient(JsonRpcClient): return self.server_version def get_system_info (self): + if not self.system_info: + return {} + return self.system_info def get_supported_cmds(self): + if not self.supported_cmds: + return {} + return self.supported_cmds def get_port_count (self): @@ -279,10 +288,10 @@ class TrexStatelessClient(JsonRpcClient): return self.system_info["port_count"] - # refresh the client for transient data - def refresh (self): + # sync the client with all the server required data + def sync (self): - # get server versionrc, msg = self.get_supported_cmds() + # get server version rc, msg = self.invoke_rpc_method("get_version") if not rc: self.disconnect() @@ -313,7 +322,7 @@ class TrexStatelessClient(JsonRpcClient): if not rc: return rc, err - return self.refresh() + return self.sync() # take ownership over ports @@ -446,4 +455,35 @@ class TrexStatelessClient(JsonRpcClient): index += 2 - return snap \ No newline at end of file + return snap + + # add stream + def add_stream (self, port_id, stream_id, isg, next_stream_id, packet): + if not port_id in self.get_owned_ports(): + return False, "Port {0} is not owned... please take ownership before adding streams".format(port_id) + + handler = self.port_handlers[port_id] + + stream = {} + stream['enabled'] = True + stream['self_start'] = True + stream['isg'] = isg + stream['next_stream_id'] = next_stream_id + stream['packet'] = {} + stream['packet']['binary'] = packet + stream['packet']['meta'] = "" + stream['vm'] = [] + stream['rx_stats'] = {} + stream['rx_stats']['enabled'] = False + + stream['mode'] = {} + stream['mode']['type'] = 'continuous' + stream['mode']['pps'] = 10.0 + + params = {} + params['handler'] = handler + params['stream'] = stream + params['port_id'] = port_id + params['stream_id'] = stream_id + + return self.invoke_rpc_method('add_stream', params = params) diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 3aeab901..9bf92174 100644 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -8,11 +8,96 @@ import random import string import sys +import tty, termios import trex_root_path + from client_utils.jsonrpc_client import TrexStatelessClient import trex_status +# + +def readch (choices = []): + + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + while True: + ch = sys.stdin.read(1) + if (ord(ch) == 3) or (ord(ch) == 4): + return None + if ch in choices: + return ch + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + + return None + +class YesNoMenu(object): + def __init__ (self, caption): + self.caption = caption + + def show (self): + print "{0}".format(self.caption) + sys.stdout.write("[Y/y/N/n] : ") + ch = readch(choices = ['y', 'Y', 'n', 'N']) + if ch == None: + return None + + print "\n" + if ch == 'y' or ch == 'Y': + return True + else: + return False + +# multi level cmd menu +class CmdMenu(object): + def __init__ (self): + self.menus = [] + + + def add_menu (self, caption, options): + menu = {} + menu['caption'] = caption + menu['options'] = options + self.menus.append(menu) + + def show (self): + cur_level = 0 + print "\n" + + selected_path = [] + for menu in self.menus: + # show all the options + print "{0}\n".format(menu['caption']) + for i, option in enumerate(menu['options']): + print "{0}. {1}".format(i + 1, option) + + #print "\nPlease select an option: " + + choices = range(0, len(menu['options'])) + choices = [ chr(x + 48) for x in choices] + + print "" + ch = readch(choices) + print "" + + if ch == None: + return None + + selected_path.append(int(ch) - 1) + + return selected_path + + +class AddStreamMenu(CmdMenu): + def __init__ (self): + super(AddStreamMenu, self).__init__() + self.add_menu('Please select type of stream', ['a', 'b', 'c']) + self.add_menu('Please select ISG', ['d', 'e', 'f']) + +# main console object class TrexConsole(cmd.Cmd): """Trex Console""" @@ -108,6 +193,13 @@ class TrexConsole(cmd.Cmd): def do_acquire (self, line, force = False): '''Acquire ports\n''' + # make sure that the user wants to acquire all + if line == "": + ask = YesNoMenu('Do you want to acquire all ports ? ') + rc = ask.show() + if rc == False: + return + port_list = self.parse_ports_from_line(line) if not port_list: return @@ -313,12 +405,24 @@ class TrexConsole(cmd.Cmd): print "{:<30} {:<30}".format(cmd + " - ", help) - # do - #def do_snapshot (self, line): - #for key, value in self.rpc_client.snapshot()[1]['streams'].iteritems(): - #print str(key) + " " + str(value) + # adds a very simple stream + def do_add_simple_stream (self, line): + if line == "": + add_stream = AddStreamMenu() + add_stream.show() + return + params = line.split() + port_id = int(params[0]) + stream_id = int(params[1]) + + packet = [0xFF,0xFF,0xFF] + rc, msg = self.rpc_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) + if rc: + print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n" + else: + print "\n*** " + msg + "\n" # aliasing do_exit = do_EOF = do_q = do_quit -- cgit 1.2.3-korg From ca479ac9bb1e4d1a5953e9d121ab39a29f7b8b8e Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 1 Oct 2015 09:15:22 +0300 Subject: Updated control plain documentation with typos and T-Rex changed to TRex. --- .../trex_control_plane/client/trex_adv_client.py | 2 +- .../trex_control_plane/client/trex_client.py | 128 ++++++++++----------- .../client_utils/general_utils.py | 2 +- .../client_utils/trex_yaml_gen.py | 6 +- .../trex_control_plane/doc/about_trex.rst | 8 +- .../trex_control_plane/doc/api/index.rst | 6 +- .../trex_control_plane/doc/api/json_fields.rst | 12 +- .../automation/trex_control_plane/doc/authors.rst | 7 +- .../trex_control_plane/doc/client_utils.rst | 4 +- scripts/automation/trex_control_plane/doc/conf.py | 14 +-- .../automation/trex_control_plane/doc/index.rst | 16 +-- .../trex_control_plane/doc/installation.rst | 6 +- .../trex_control_plane/doc/usage_examples.rst | 14 +-- .../examples/client_interactive_example.py | 102 ++++++++-------- 14 files changed, 164 insertions(+), 163 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client/trex_adv_client.py b/scripts/automation/trex_control_plane/client/trex_adv_client.py index b3fe3dad..b135da59 100755 --- a/scripts/automation/trex_control_plane/client/trex_adv_client.py +++ b/scripts/automation/trex_control_plane/client/trex_adv_client.py @@ -8,7 +8,7 @@ class CTRexAdvClient(trex_client.CTRexClient): super(CTRexAdvClient, self).__init__(trex_host, max_history_size, trex_daemon_port, trex_zmq_port, verbose) pass - # T-REX KIWI advanced methods + # TREX KIWI advanced methods def start_quick_trex(self, pcap_file, d, delay, dual, ipv6, times, interfaces): try: return self.server.start_quick_trex(pcap_file = pcap_file, duration = d, dual = dual, delay = delay, ipv6 = ipv6, times = times, interfaces = interfaces) diff --git a/scripts/automation/trex_control_plane/client/trex_client.py b/scripts/automation/trex_control_plane/client/trex_client.py index 56775766..4c40f142 100755 --- a/scripts/automation/trex_control_plane/client/trex_client.py +++ b/scripts/automation/trex_control_plane/client/trex_client.py @@ -30,18 +30,18 @@ from distutils.util import strtobool class CTRexClient(object): """ - This class defines the client side of the RESTfull interaction with T-Rex + This class defines the client side of the RESTfull interaction with TRex """ def __init__(self, trex_host, max_history_size = 100, trex_daemon_port = 8090, trex_zmq_port = 4500, verbose = False): """ - Instantiate a T-Rex client object, and connecting it to listening daemon-server + Instantiate a TRex client object, and connecting it to listening daemon-server :parameters: trex_host : str - a string of the t-rex ip address or hostname. + a string of the TRex ip address or hostname. max_history_size : int - a number to set the maximum history size of a single T-Rex run. Each sampling adds a new item to history. + a number to set the maximum history size of a single TRex run. Each sampling adds a new item to history. default value : **100** trex_daemon_port : int @@ -90,7 +90,7 @@ class CTRexClient(object): def start_trex (self, f, d, block_to_success = True, timeout = 30, user = None, **trex_cmd_options): """ - Request to start a T-Rex run on server. + Request to start a TRex run on server. :parameters: f : str @@ -98,17 +98,17 @@ class CTRexClient(object): d : int the desired duration of the test. must be at least 30 seconds long. block_to_success : bool - determine if this method blocks until T-Rex changes state from 'Starting' to either 'Idle' or 'Running' + determine if this method blocks until TRex changes state from 'Starting' to either 'Idle' or 'Running' default value : **True** timeout : int - maximum time (in seconds) to wait in blocking state until T-Rex changes state from 'Starting' to either 'Idle' or 'Running' + maximum time (in seconds) to wait in blocking state until TRex changes state from 'Starting' to either 'Idle' or 'Running' default value: **30** user : str the identity of the the run issuer. trex_cmd_options : key, val - sets desired T-Rex options using key=val syntax, separated by comma. + sets desired TRex options using key=val syntax, separated by comma. for keys with no value, state key=True :return: @@ -117,8 +117,8 @@ class CTRexClient(object): :raises: + :exc:`ValueError`, in case 'd' parameter inserted with wrong value. + :exc:`trex_exceptions.TRexError`, in case one of the trex_cmd_options raised an exception at server. - + :exc:`trex_exceptions.TRexInUseError`, in case T-Rex is already taken. - + :exc:`trex_exceptions.TRexRequestDenied`, in case T-Rex is reserved for another user than the one trying start T-Rex. + + :exc:`trex_exceptions.TRexInUseError`, in case TRex is already taken. + + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex is reserved for another user than the one trying start TRex. + ProtocolError, in case of error in JSON-RPC protocol. """ @@ -146,25 +146,25 @@ class CTRexClient(object): if retval!=0: self.seq = retval # update seq num only on successful submission return True - else: # T-Rex is has been started by another user + else: # TRex is has been started by another user raise TRexInUseError('T-Rex is already being used by another user or process. Try again once T-Rex is back in IDLE state.') def stop_trex (self): """ - Request to stop a T-Rex run on server. + Request to stop a TRex run on server. - The request is only valid if the stop initiator is the same client as the T-Rex run initiator. + The request is only valid if the stop initiator is the same client as the TRex run initiator. :parameters: None :return: + **True** on successful termination - + **False** if request issued but T-Rex wasn't running. + + **False** if request issued but TRex wasn't running. :raises: - + :exc:`trex_exceptions.TRexRequestDenied`, in case T-Rex ir running but started by another user. - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex ir running but started by another user. + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + ProtocolError, in case of error in JSON-RPC protocol. """ @@ -179,16 +179,16 @@ class CTRexClient(object): def force_kill (self, confirm = True): """ - Force killing of running T-Rex process (if exists) on the server. + Force killing of running TRex process (if exists) on the server. .. tip:: This method is a safety method and **overrides any running or reserved resources**, and as such isn't designed to be used on a regular basis. Always consider using :func:`trex_client.CTRexClient.stop_trex` instead. - In the end of this method, T-Rex will return to IDLE state with no reservation. + In the end of this method, TRex will return to IDLE state with no reservation. :parameters: confirm : bool - Prompt a user confirmation before continue terminating T-Rex session + Prompt a user confirmation before continue terminating TRex session :return: + **True** on successful termination @@ -221,20 +221,20 @@ class CTRexClient(object): def wait_until_kickoff_finish(self, timeout = 40): """ - Block the client application until T-Rex changes state from 'Starting' to either 'Idle' or 'Running' + Block the client application until TRex changes state from 'Starting' to either 'Idle' or 'Running' - The request is only valid if the stop initiator is the same client as the T-Rex run initiator. + The request is only valid if the stop initiator is the same client as the TRex run initiator. :parameters: timeout : int - maximum time (in seconds) to wait in blocking state until T-Rex changes state from 'Starting' to either 'Idle' or 'Running' + maximum time (in seconds) to wait in blocking state until TRex changes state from 'Starting' to either 'Idle' or 'Running' :return: + **True** on successful termination - + **False** if request issued but T-Rex wasn't running. + + **False** if request issued but TRex wasn't running. :raises: - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + ProtocolError, in case of error in JSON-RPC protocol. .. note:: Exceptions are throws only when start_trex did not block in the first place, i.e. `block_to_success` parameter was set to `False` @@ -252,22 +252,22 @@ class CTRexClient(object): def is_running (self, dump_out = False): """ - Poll for T-Rex running status. + Poll for TRex running status. - If T-Rex is running, a history item will be added into result_obj and processed. + If TRex is running, a history item will be added into result_obj and processed. - .. tip:: This method is especially useful for iterating until T-Rex run is finished. + .. tip:: This method is especially useful for iterating until TRex run is finished. :parameters: dump_out : dict if passed, the pointer object is cleared and the latest dump stored in it. :return: - + **True** if T-Rex is running. - + **False** if T-Rex is not running. + + **True** if TRex is running. + + **False** if TRex is not running. :raises: - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + :exc:`TypeError`, in case JSON stream decoding error. + ProtocolError, in case of error in JSON-RPC protocol. @@ -292,7 +292,7 @@ class CTRexClient(object): def get_trex_files_path (self): """ - Fetches the local path in which files are stored when pushed to t-rex server from client. + Fetches the local path in which files are stored when pushed to TRex server from client. :parameters: None @@ -300,7 +300,7 @@ class CTRexClient(object): :return: string representation of the desired path - .. note:: The returned path represents a path on the T-Rex server **local machine** + .. note:: The returned path represents a path on the TRex server **local machine** :raises: ProtocolError, in case of error in JSON-RPC protocol. @@ -317,7 +317,7 @@ class CTRexClient(object): def get_running_status (self): """ - Fetches the current T-Rex status. + Fetches the current TRex status. If available, a verbose data will accompany the state itself. @@ -344,18 +344,18 @@ class CTRexClient(object): def get_running_info (self): """ - Performs single poll of T-Rex running data and process it into the result object (named `result_obj`). + Performs single poll of TRex running data and process it into the result object (named `result_obj`). - .. tip:: This method will throw an exception if T-Rex isn't running. Always consider using :func:`trex_client.CTRexClient.is_running` which handles a single poll operation in safer manner. + .. tip:: This method will throw an exception if TRex isn't running. Always consider using :func:`trex_client.CTRexClient.is_running` which handles a single poll operation in safer manner. :parameters: None :return: - dictionary containing the most updated data dump from T-Rex. + dictionary containing the most updated data dump from TRex. :raises: - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + :exc:`TypeError`, in case JSON stream decoding error. + ProtocolError, in case of error in JSON-RPC protocol. @@ -379,7 +379,7 @@ class CTRexClient(object): def sample_until_condition (self, condition_func, time_between_samples = 5): """ - Automatically sets ongoing sampling of T-Rex data, with sampling rate described by time_between_samples. + Automatically sets ongoing sampling of TRex data, with sampling rate described by time_between_samples. On each fetched dump, the condition_func is applied on the result objects, and if returns True, the sampling will stop. @@ -394,23 +394,23 @@ class CTRexClient(object): default value : **5** :return: - the first result object (see :class:`CTRexResult` for further details) of the T-Rex run on which the condition has been met. + the first result object (see :class:`CTRexResult` for further details) of the TRex run on which the condition has been met. :raises: + :exc:`UserWarning`, in case the condition_func method condition hasn't been met - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + :exc:`TypeError`, in case JSON stream decoding error. + ProtocolError, in case of error in JSON-RPC protocol. + :exc:`Exception`, in case the condition_func suffered from any kind of exception """ - # make sure T-Rex is running. raise exceptions here if any + # make sure TRex is running. raise exceptions here if any self.wait_until_kickoff_finish() try: while self.is_running(): results = self.get_result_obj() if condition_func(results): - # if condition satisfied, stop T-Rex and return result object + # if condition satisfied, stop TRex and return result object self.stop_trex() return results time.sleep(time_between_samples) @@ -423,7 +423,7 @@ class CTRexClient(object): def sample_to_run_finish (self, time_between_samples = 5): """ - Automatically sets automatically sampling of T-Rex data with sampling rate described by time_between_samples until T-Rex run finished. + Automatically sets automatically sampling of TRex data with sampling rate described by time_between_samples until TRex run finished. :parameters: time_between_samples : int @@ -436,7 +436,7 @@ class CTRexClient(object): :raises: + :exc:`UserWarning`, in case the condition_func method condition hasn't been met - + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed T-Rex run (unexpected termination). + + :exc:`trex_exceptions.TRexIncompleteRunError`, in case one of failed TRex run (unexpected termination). + :exc:`TypeError`, in case JSON stream decoding error. + ProtocolError, in case of error in JSON-RPC protocol. @@ -475,13 +475,13 @@ class CTRexClient(object): def is_reserved (self): """ - Checks if T-Rex is currently reserved to any user or not. + Checks if TRex is currently reserved to any user or not. :parameters: None :return: - + **True** if T-Rex is reserved. + + **True** if TRex is reserved. + **False** otherwise. :raises: @@ -499,13 +499,13 @@ class CTRexClient(object): def reserve_trex (self, user = None): """ - Reserves the usage of T-Rex to a certain user. + Reserves the usage of TRex to a certain user. - When T-Rex is reserved, it can't be reserved. + When TRex is reserved, it can't be reserved. :parameters: user : str - a username of the desired owner of T-Rex + a username of the desired owner of TRex default: current logged user @@ -513,8 +513,8 @@ class CTRexClient(object): **True** if reservation made successfully :raises: - + :exc:`trex_exceptions.TRexRequestDenied`, in case T-Rex is reserved for another user than the one trying to make the reservation. - + :exc:`trex_exceptions.TRexInUseError`, in case T-Rex is currently running. + + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex is reserved for another user than the one trying to make the reservation. + + :exc:`trex_exceptions.TRexInUseError`, in case TRex is currently running. + ProtocolError, in case of error in JSON-RPC protocol. """ @@ -530,14 +530,14 @@ class CTRexClient(object): def cancel_reservation (self, user = None): """ - Cancels a current reservation of T-Rex to a certain user. + Cancels a current reservation of TRex to a certain user. - When T-Rex is reserved, no other user can start new T-Rex runs. + When TRex is reserved, no other user can start new TRex runs. :parameters: user : str - a username of the desired owner of T-Rex + a username of the desired owner of TRex default: current logged user @@ -546,7 +546,7 @@ class CTRexClient(object): + **False** if there was no reservation at all. :raises: - + :exc:`trex_exceptions.TRexRequestDenied`, in case T-Rex is reserved for another user than the one trying to cancel the reservation. + + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex is reserved for another user than the one trying to cancel the reservation. + ProtocolError, in case of error in JSON-RPC protocol. """ @@ -671,7 +671,7 @@ class CTRexClient(object): def _handle_AppError_exception(self, err): """ - This private method triggres the T-Rex dedicated exception generation in case a general ProtocolError has been raised. + This private method triggres the TRex dedicated exception generation in case a general ProtocolError has been raised. """ # handle known exceptions based on known error codes. # if error code is not known, raise ProtocolError @@ -680,17 +680,17 @@ class CTRexClient(object): class CTRexResult(object): """ - A class containing all results received from T-Rex. + A class containing all results received from TRex. Ontop to containing the results, this class offers easier data access and extended results processing options """ def __init__(self, max_history_size): """ - Instatiate a T-Rex result object + Instatiate a TRex result object :parameters: max_history_size : int - a number to set the maximum history size of a single T-Rex run. Each sampling adds a new item to history. + a number to set the maximum history size of a single TRex run. Each sampling adds a new item to history. """ self._history = deque(maxlen = max_history_size) @@ -749,7 +749,7 @@ class CTRexResult(object): def get_avg_latency (self): """ - Fetches the average latency measured on each of the interfaces from the start of T-Rex run + Fetches the average latency measured on each of the interfaces from the start of TRex run :parameters: None @@ -779,7 +779,7 @@ class CTRexResult(object): def get_total_drops (self): """ - Fetches the total number of drops identified from the moment T-Rex run began. + Fetches the total number of drops identified from the moment TRex run began. :parameters: None @@ -805,7 +805,7 @@ class CTRexResult(object): def is_valid_hist (self): """ - Checks if result obejct contains valid data. + Checks if result object contains valid data. :parameters: None @@ -819,7 +819,7 @@ class CTRexResult(object): def set_valid_hist (self, valid_stat = True): """ - Sets result obejct validity status. + Sets result object validity status. :parameters: valid_stat : bool @@ -835,7 +835,7 @@ class CTRexResult(object): def is_done_warmup (self): """ - Checks if T-Rex latest results TX-rate indicates that T-Rex has reached its expected TX-rate. + Checks if TRex latest results TX-rate indicates that TRex has reached its expected TX-rate. :parameters: None diff --git a/scripts/automation/trex_control_plane/client_utils/general_utils.py b/scripts/automation/trex_control_plane/client_utils/general_utils.py index b5912628..5488b9dd 100755 --- a/scripts/automation/trex_control_plane/client_utils/general_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/general_utils.py @@ -37,7 +37,7 @@ def find_path_to_pardir (pardir, base_path = os.getcwd() ): """ Finds the absolute path for some parent dir `pardir`, starting from base_path - The request is only valid if the stop intitiator is the same client as the T-Rex run intitiator. + The request is only valid if the stop initiator is the same client as the TRex run initiator. :parameters: pardir : str diff --git a/scripts/automation/trex_control_plane/client_utils/trex_yaml_gen.py b/scripts/automation/trex_control_plane/client_utils/trex_yaml_gen.py index 755674ea..351b7b9c 100755 --- a/scripts/automation/trex_control_plane/client_utils/trex_yaml_gen.py +++ b/scripts/automation/trex_control_plane/client_utils/trex_yaml_gen.py @@ -7,7 +7,7 @@ import os class CTRexYaml(object): """ - This class functions as a YAML generator according to T-Rex YAML format. + This class functions as a YAML generator according to TRex YAML format. CTRexYaml is compatible with both Python 2 and Python 3. """ @@ -38,7 +38,7 @@ class CTRexYaml(object): :parameters: trex_files_path : str - a path (on T-Rex server side) for the pcap files using which T-Rex can access it. + a path (on TRex server side) for the pcap files using which TRex can access it. """ self.yaml_obj = list(CTRexYaml.YAML_TEMPLATE) @@ -193,7 +193,7 @@ class CTRexYaml(object): """ Returns a list of all files related to the YAML object, including the YAML filename itself. - .. tip:: This method is especially useful for listing all the files that should be pushed to T-Rex server as part of the same yaml selection. + .. tip:: This method is especially useful for listing all the files that should be pushed to TRex server as part of the same yaml selection. :parameters: None diff --git a/scripts/automation/trex_control_plane/doc/about_trex.rst b/scripts/automation/trex_control_plane/doc/about_trex.rst index 97cad97d..08858048 100755 --- a/scripts/automation/trex_control_plane/doc/about_trex.rst +++ b/scripts/automation/trex_control_plane/doc/about_trex.rst @@ -1,11 +1,11 @@ -=================== -About T-Rex project -=================== +================== +About TRex project +================== Full project's official site ---------------------------- -To learn all about T-Rex project, visit Cisco's internal `official site `_ +To learn all about TRex project, visit TRex `official site `_ Even more --------- diff --git a/scripts/automation/trex_control_plane/doc/api/index.rst b/scripts/automation/trex_control_plane/doc/api/index.rst index 8233a634..7c558a94 100755 --- a/scripts/automation/trex_control_plane/doc/api/index.rst +++ b/scripts/automation/trex_control_plane/doc/api/index.rst @@ -1,9 +1,9 @@ API Reference ============= -The T-Rex API reference section is currently a work in progress. +The TRex API reference section is currently a work in progress. -**T-Rex Modules** +**TRex Modules** .. toctree:: :maxdepth: 4 @@ -11,7 +11,7 @@ The T-Rex API reference section is currently a work in progress. client_code exceptions -**T-Rex JSON Template** +**TRex JSON Template** .. toctree:: :maxdepth: 4 diff --git a/scripts/automation/trex_control_plane/doc/api/json_fields.rst b/scripts/automation/trex_control_plane/doc/api/json_fields.rst index b1a2af7c..193aa01b 100755 --- a/scripts/automation/trex_control_plane/doc/api/json_fields.rst +++ b/scripts/automation/trex_control_plane/doc/api/json_fields.rst @@ -1,23 +1,23 @@ -T-Rex JSON Template -=================== +TRex JSON Template +================== -Whenever T-Rex is publishing live data, it uses JSON notation to describe the data-object. +Whenever TRex is publishing live data, it uses JSON notation to describe the data-object. -Each client may parse it diffrently, however this page will describe the values meaning when published by T-Rex server. +Each client may parse it diffrently, however this page will describe the values meaning when published by TRex server. Main Fields ----------- -Each T-Rex server-published JSON object contains data divided to main fields under which the actual data lays. +Each TRex server-published JSON object contains data divided to main fields under which the actual data lays. These main fields are: +-----------------------------+----------------------------------------------------+---------------------------+ | Main field | Contains | Comments | +=============================+====================================================+===========================+ -| :ref:`trex-global-field` | Must-have data on T-Rex run, | | +| :ref:`trex-global-field` | Must-have data on TRex run, | | | | mainly regarding Tx/Rx and packet drops | | +-----------------------------+----------------------------------------------------+---------------------------+ | :ref:`tx-gen-field` | Data indicate the quality of the transmit process. | | diff --git a/scripts/automation/trex_control_plane/doc/authors.rst b/scripts/automation/trex_control_plane/doc/authors.rst index 3b85f020..08ee5db5 100755 --- a/scripts/automation/trex_control_plane/doc/authors.rst +++ b/scripts/automation/trex_control_plane/doc/authors.rst @@ -2,11 +2,12 @@ Authors ======= -T-Rex is developed in Cisco Systems Inc. as the next generation traffic generator. +TRex is developed in Cisco Systems Inc. as the next generation traffic generator. -T-Rex core-team developers are: +TRex core-team developers are: - Hanoch Haim - Dave Johnson - Wenxian Li - - Dan Klein \ No newline at end of file + - Dan Klein + - Itay Marom \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/client_utils.rst b/scripts/automation/trex_control_plane/doc/client_utils.rst index 224dfe19..5f133eee 100755 --- a/scripts/automation/trex_control_plane/doc/client_utils.rst +++ b/scripts/automation/trex_control_plane/doc/client_utils.rst @@ -2,8 +2,8 @@ Client Utilities ================ -T-Rex YAML generator --------------------- +TRex YAML generator +------------------- .. automodule:: trex_yaml_gen :members: diff --git a/scripts/automation/trex_control_plane/doc/conf.py b/scripts/automation/trex_control_plane/doc/conf.py index fb9ea83c..46d0435d 100755 --- a/scripts/automation/trex_control_plane/doc/conf.py +++ b/scripts/automation/trex_control_plane/doc/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# T-Rex Control Plain documentation build configuration file, created by +# TRex Control Plain documentation build configuration file, created by # sphinx-quickstart on Tue Jun 2 07:48:10 2015. # # This file is execfile()d with the current directory set to its @@ -54,7 +54,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'T-Rex Control Plain' +project = u'TRex Control Plain' copyright = u'2015, Cisco Systems Inc.' author = u'Dan Klein for Cisco Systems Inc.' @@ -211,7 +211,7 @@ html_static_path = ['_static'] #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'T-RexControlPlaindoc' +htmlhelp_basename = 'TRexControlPlaindoc' # -- Options for LaTeX output --------------------------------------------- @@ -233,7 +233,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'T-RexControlPlain.tex', u'T-Rex Control Plain Documentation', + (master_doc, 'TRexControlPlain.tex', u'TRex Control Plain Documentation', u'Dan Klein for Cisco Systems Inc', 'manual'), ] @@ -263,7 +263,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 't-rexcontrolplain', u'T-Rex Control Plain Documentation', + (master_doc, 'TRexcontrolplain', u'TRex Control Plain Documentation', [author], 1) ] @@ -277,8 +277,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'T-RexControlPlain', u'T-Rex Control Plain Documentation', - author, 'T-RexControlPlain', 'One line description of project.', + (master_doc, 'TRexControlPlain', u'TRex Control Plain Documentation', + author, 'TRexControlPlain', 'One line description of project.', 'Miscellaneous'), ] diff --git a/scripts/automation/trex_control_plane/doc/index.rst b/scripts/automation/trex_control_plane/doc/index.rst index e7a619d8..dcaf9505 100755 --- a/scripts/automation/trex_control_plane/doc/index.rst +++ b/scripts/automation/trex_control_plane/doc/index.rst @@ -1,18 +1,18 @@ -.. T-Rex Control Plain documentation master file, created by +.. TRex Control Plain documentation master file, created by sphinx-quickstart on Tue Jun 2 07:48:10 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to T-Rex Control Plain's documentation! +Welcome to TRex Control Plain's documentation! =============================================== -T-Rex is a **realistic traffic generator** that enables you to do get learn more about your under developement devices. +TRex is a **realistic traffic generator** that enables you to do get learn more about your under developement devices. -This site covers the Python API of T-Rex control plane, and explains how to utilize it to your needs. +This site covers the Python API of TRex control plane, and explains how to utilize it to your needs. However, since the entire API is JSON-RPC [#f1]_ based, you may want to check out other implementations that could suit you. -To understand the entirely how the API works and how to set up the server side, check out the `API documentation `_ undee the documentation section of T-Rex website. +To understand the entirely how the API works and how to set up the server side, check out the `API documentation `_ undee the documentation section of TRex website. **Use the table of contents below or the menu to your left to navigate through the site** @@ -34,12 +34,12 @@ API Reference api/index -About T-Rex -=========== +About TRex +========== .. toctree:: :maxdepth: 2 - All about T-Rex + All about TRex license diff --git a/scripts/automation/trex_control_plane/doc/installation.rst b/scripts/automation/trex_control_plane/doc/installation.rst index dda32f56..29239d97 100755 --- a/scripts/automation/trex_control_plane/doc/installation.rst +++ b/scripts/automation/trex_control_plane/doc/installation.rst @@ -4,9 +4,9 @@ Installation Prerequisites ------------- -The T-Rex control plane is based on client-server model that interacts using JSON-RPC. +The TRex control plane is based on client-server model that interacts using JSON-RPC. -In order to use the client-side API documented a T-Rex server daemon must be up and listening on the same host and port that the client tries to connect with. +In order to use the client-side API documented a TRex server daemon must be up and listening on the same host and port that the client tries to connect with. Compatibility ------------- @@ -20,6 +20,6 @@ However, the server side was desined to and best fits with Python 2.7.6 and on ( Installation manual ------------------- -T-Rex Control Plane is a cross-platform, cross-operatin system APi to control and run T-Rex. +TRex Control Plane is a cross-platform, cross-operating system APi to control and run TRex. The full, most updated manual (which refers to all programming languages) can be found under the `Automation API documentation `_ . \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/usage_examples.rst b/scripts/automation/trex_control_plane/doc/usage_examples.rst index 7116f28c..ff5c026d 100755 --- a/scripts/automation/trex_control_plane/doc/usage_examples.rst +++ b/scripts/automation/trex_control_plane/doc/usage_examples.rst @@ -6,7 +6,7 @@ Usage Examples Full-featured interactive shell ------------------------------- -The `client_interactive_example.py` extends and uses the `Cmd `_ built in python class to create a Full-featured shell using which one can interact with T-Rex server and get instant results. +The `client_interactive_example.py` extends and uses the `Cmd `_ built in python class to create a Full-featured shell using which one can interact with TRex server and get instant results. The help menu of this application is: @@ -14,21 +14,21 @@ The help menu of this application is: usage: client_interactive_example [options] - Run T-Rex client API demos and scenarios. + Run TRex client API demos and scenarios. optional arguments: -h, --help show this help message and exit -v, --version show program's version number and exit -t HOST, --trex-host HOST - Specify the hostname or ip to connect with T-Rex + Specify the hostname or ip to connect with TRex server. -p PORT, --trex-port PORT - Select port on which the T-Rex server listens. Default + Select port on which the TRex server listens. Default port is 8090. -m SIZE, --maxhist SIZE Specify maximum history size saved at client side. Default size is 100. - --verbose Switch ON verbose option at T-Rex client. Default is: + --verbose Switch ON verbose option at TRex client. Default is: OFF. **Code Excerpt** @@ -51,8 +51,8 @@ The demo takes the user a full circle: 2. exporting the generated packets into .pcap file named `dns_traffic.pcap`. 3. Use the :class:`trex_yaml_gen.CTRexYaml` generator to include that pcap file in the yaml object. 4. Export the YAML object onto a YAML file named `dns_traffic.yaml` - 5. Push the generated files to T-Rex server. - 6. Run T-Rex based on the generated (and pushed) files. + 5. Push the generated files to TRex server. + 6. Run TRex based on the generated (and pushed) files. **Code Excerpt** [#f1]_ diff --git a/scripts/automation/trex_control_plane/examples/client_interactive_example.py b/scripts/automation/trex_control_plane/examples/client_interactive_example.py index 05028463..5a3ebf8a 100755 --- a/scripts/automation/trex_control_plane/examples/client_interactive_example.py +++ b/scripts/automation/trex_control_plane/examples/client_interactive_example.py @@ -15,7 +15,7 @@ import errno class InteractiveTRexClient(cmd.Cmd): - intro = termstyle.green("\nInteractive shell to play with Cisco's T-Rex API.\nType help to view available pre-defined scenarios\n(c) All rights reserved.\n") + intro = termstyle.green("\nInteractive shell to play with Cisco's TRex API.\nType help to view available pre-defined scenarios\n(c) All rights reserved.\n") prompt = '> ' def __init__(self, trex_host, max_history_size = 100, trex_port = 8090, verbose_mode = False ): @@ -33,89 +33,89 @@ class InteractiveTRexClient(cmd.Cmd): def do_push_files (self, filepaths): - """Pushes a custom file to be stored locally on T-Rex server.\nPush multiple files by spefiying their path separated by ' ' (space).""" + """Pushes a custom file to be stored locally on TRex server.\nPush multiple files by spefiying their path separated by ' ' (space).""" try: filepaths = filepaths.split(' ') - print termstyle.green("*** Starting pushing files ({trex_files}) to T-Rex. ***".format (trex_files = ', '.join(filepaths)) ) + print termstyle.green("*** Starting pushing files ({trex_files}) to TRex. ***".format (trex_files = ', '.join(filepaths)) ) ret_val = self.trex.push_files(filepaths) if ret_val: - print termstyle.green("*** End of T-Rex push_files method (success) ***") + print termstyle.green("*** End of TRex push_files method (success) ***") else: - print termstyle.magenta("*** End of T-Rex push_files method (failed) ***") + print termstyle.magenta("*** End of TRex push_files method (failed) ***") except IOError as inst: print termstyle.magenta(inst) def do_show_default_run_params(self,line): - """Outputs the default T-Rex running parameters""" + """Outputs the default TRex running parameters""" pprint(self.DEFAULT_RUN_PARAMS) - print termstyle.green("*** End of default T-Rex running parameters ***") + print termstyle.green("*** End of default TRex running parameters ***") def do_show_run_params(self,line): - """Outputs the currently configured T-Rex running parameters""" + """Outputs the currently configured TRex running parameters""" pprint(self.run_params) - print termstyle.green("*** End of T-Rex running parameters ***") + print termstyle.green("*** End of TRex running parameters ***") def do_update_run_params(self, json_str): - """Updates provided parameters on T-Rex running configuration. Provide using JSON string""" + """Updates provided parameters on TRex running configuration. Provide using JSON string""" if json_str: try: upd_params = self.decoder.decode(json_str) self.run_params.update(upd_params) - print termstyle.green("*** End of T-Rex parameters update ***") + print termstyle.green("*** End of TRex parameters update ***") except ValueError as inst: print termstyle.magenta("Provided illegal JSON string. Please try again.\n[", inst,"]") else: print termstyle.magenta("JSON configuration string is missing. Please try again.") def do_show_status (self, line): - """Prompts T-Rex current status""" + """Prompts TRex current status""" print self.trex.get_running_status() - print termstyle.green("*** End of T-Rex status prompt ***") + print termstyle.green("*** End of TRex status prompt ***") def do_show_trex_files_path (self, line): - """Prompts the local path in which files are stored when pushed to t-rex server from client""" + """Prompts the local path in which files are stored when pushed to TRex server from client""" print self.trex.get_trex_files_path() print termstyle.green("*** End of trex_files_path prompt ***") def do_show_reservation_status (self, line): - """Prompts if T-Rex is currently reserved or not""" + """Prompts if TRex is currently reserved or not""" if self.trex.is_reserved(): - print "T-Rex is reserved" + print "TRex is reserved" else: - print "T-Rex is NOT reserved" + print "TRex is NOT reserved" print termstyle.green("*** End of reservation status prompt ***") def do_reserve_trex (self, user): - """Reserves the usage of T-Rex to a certain user""" + """Reserves the usage of TRex to a certain user""" try: if not user: ret = self.trex.reserve_trex() else: ret = self.trex.reserve_trex(user.split(' ')[0]) - print termstyle.green("*** T-Rex reserved successfully ***") + print termstyle.green("*** TRex reserved successfully ***") except TRexException as inst: print termstyle.red(inst) def do_cancel_reservation (self, user): - """Cancels a current reservation of T-Rex to a certain user""" + """Cancels a current reservation of TRex to a certain user""" try: if not user: ret = self.trex.cancel_reservation() else: ret = self.trex.cancel_reservation(user.split(' ')[0]) - print termstyle.green("*** T-Rex reservation canceled successfully ***") + print termstyle.green("*** TRex reservation canceled successfully ***") except TRexException as inst: print termstyle.red(inst) def do_restore_run_default (self, line): - """Restores original T-Rex running configuration""" + """Restores original TRex running configuration""" self.run_params = dict(self.DEFAULT_RUN_PARAMS) print termstyle.green("*** End of restoring default run parameters ***") def do_run_until_finish (self, sample_rate): - """Starts T-Rex and sample server until run is done.""" - print termstyle.green("*** Starting T-Rex run_until_finish scenario ***") + """Starts TRex and sample server until run is done.""" + print termstyle.green("*** Starting TRex run_until_finish scenario ***") if not sample_rate: # use default sample rate if not passed sample_rate = 5 @@ -123,15 +123,15 @@ class InteractiveTRexClient(cmd.Cmd): sample_rate = int(sample_rate) ret = self.trex.start_trex(**self.run_params) self.trex.sample_to_run_finish(sample_rate) - print termstyle.green("*** End of T-Rex run ***") + print termstyle.green("*** End of TRex run ***") except ValueError as inst: print termstyle.magenta("Provided illegal sample rate value. Please try again.\n[", inst,"]") except TRexException as inst: print termstyle.red(inst) def do_run_and_poll (self, sample_rate): - """Starts T-Rex and sample server manually until run is done.""" - print termstyle.green("*** Starting T-Rex run and manually poll scenario ***") + """Starts TRex and sample server manually until run is done.""" + print termstyle.green("*** Starting TRex run and manually poll scenario ***") if not sample_rate: # use default sample rate if not passed sample_rate = 5 try: @@ -145,7 +145,7 @@ class InteractiveTRexClient(cmd.Cmd): # do WHATEVER here time.sleep(sample_rate) - print termstyle.green("*** End of T-Rex run ***") + print termstyle.green("*** End of TRex run ***") except ValueError as inst: print termstyle.magenta("Provided illegal sample rate value. Please try again.\n[", inst,"]") except TRexException as inst: @@ -153,8 +153,8 @@ class InteractiveTRexClient(cmd.Cmd): def do_run_until_condition (self, sample_rate): - """Starts T-Rex and sample server until condition is satisfied.""" - print termstyle.green("*** Starting T-Rex run until condition is satisfied scenario ***") + """Starts TRex and sample server until condition is satisfied.""" + print termstyle.green("*** Starting TRex run until condition is satisfied scenario ***") def condition (result_obj): return result_obj.get_current_tx_rate()['m_tx_pps'] > 200000 @@ -166,55 +166,55 @@ class InteractiveTRexClient(cmd.Cmd): ret = self.trex.start_trex(**self.run_params) ret_val = self.trex.sample_until_condition(condition, sample_rate) print ret_val - print termstyle.green("*** End of T-Rex run ***") + print termstyle.green("*** End of TRex run ***") except ValueError as inst: print termstyle.magenta("Provided illegal sample rate value. Please try again.\n[", inst,"]") except TRexException as inst: print termstyle.red(inst) def do_start_and_return (self, line): - """Start T-Rex run and once in 'Running' mode, return to cmd prompt""" - print termstyle.green("*** Starting T-Rex run, wait until in 'Running' state ***") + """Start TRex run and once in 'Running' mode, return to cmd prompt""" + print termstyle.green("*** Starting TRex run, wait until in 'Running' state ***") try: ret = self.trex.start_trex(**self.run_params) - print termstyle.green("*** End of scenario (T-Rex is probably still running!) ***") + print termstyle.green("*** End of scenario (TRex is probably still running!) ***") except TRexException as inst: print termstyle.red(inst) def do_poll_once (self, line): - """Performs a single poll of T-Rex current data dump (if T-Rex is running) and prompts and short version of latest result_obj""" - print termstyle.green("*** Trying T-Rex single poll ***") + """Performs a single poll of TRex current data dump (if TRex is running) and prompts and short version of latest result_obj""" + print termstyle.green("*** Trying TRex single poll ***") try: last_res = dict() if self.trex.is_running(dump_out = last_res): obj = self.trex.get_result_obj() print obj else: - print termstyle.magenta("T-Rex isn't currently running.") - print termstyle.green("*** End of scenario (T-Rex is posssibly still running!) ***") + print termstyle.magenta("TRex isn't currently running.") + print termstyle.green("*** End of scenario (TRex is posssibly still running!) ***") except TRexException as inst: print termstyle.red(inst) def do_stop_trex (self, line): - """Try to stop T-Rex run (if T-Rex is currently running)""" - print termstyle.green("*** Starting T-Rex termination ***") + """Try to stop TRex run (if TRex is currently running)""" + print termstyle.green("*** Starting TRex termination ***") try: ret = self.trex.stop_trex() - print termstyle.green("*** End of scenario (T-Rex is not running now) ***") + print termstyle.green("*** End of scenario (TRex is not running now) ***") except TRexException as inst: print termstyle.red(inst) def do_kill_indiscriminately (self, line): - """Force killing of running T-Rex process (if exists) on the server.""" - print termstyle.green("*** Starting T-Rex termination ***") + """Force killing of running TRex process (if exists) on the server.""" + print termstyle.green("*** Starting TRex termination ***") ret = self.trex.force_kill() if ret: - print termstyle.green("*** End of scenario (T-Rex is not running now) ***") + print termstyle.green("*** End of scenario (TRex is not running now) ***") elif ret is None: - print termstyle.magenta("*** End of scenario (T-Rex termination aborted) ***") + print termstyle.magenta("*** End of scenario (TRex termination aborted) ***") else: - print termstyle.red("*** End of scenario (T-Rex termination failed) ***") + print termstyle.red("*** End of scenario (TRex termination failed) ***") def do_exit(self, arg): """Quits the application""" @@ -223,20 +223,20 @@ class InteractiveTRexClient(cmd.Cmd): if __name__ == "__main__": - parser = ArgumentParser(description = termstyle.cyan('Run T-Rex client API demos and scenarios.'), + parser = ArgumentParser(description = termstyle.cyan('Run TRex client API demos and scenarios.'), usage = """client_interactive_example [options]""" ) parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0 \t (C) Cisco Systems Inc.\n') parser.add_argument("-t", "--trex-host", required = True, dest="trex_host", - action="store", help="Specify the hostname or ip to connect with T-Rex server.", + action="store", help="Specify the hostname or ip to connect with TRex server.", metavar="HOST" ) parser.add_argument("-p", "--trex-port", type=int, default = 8090, metavar="PORT", dest="trex_port", - help="Select port on which the T-Rex server listens. Default port is 8090.", action="store") + help="Select port on which the TRex server listens. Default port is 8090.", action="store") parser.add_argument("-m", "--maxhist", type=int, default = 100, metavar="SIZE", dest="hist_size", help="Specify maximum history size saved at client side. Default size is 100.", action="store") parser.add_argument("--verbose", dest="verbose", - action="store_true", help="Switch ON verbose option at T-Rex client. Default is: OFF.", + action="store_true", help="Switch ON verbose option at TRex client. Default is: OFF.", default = False ) args = parser.parse_args() @@ -248,7 +248,7 @@ if __name__ == "__main__": exit(-1) except socket.error, e: if e.errno == errno.ECONNREFUSED: - raise socket.error(errno.ECONNREFUSED, "Connection from T-Rex server was terminated. Please make sure the server is up.") + raise socket.error(errno.ECONNREFUSED, "Connection from TRex server was terminated. Please make sure the server is up.") -- cgit 1.2.3-korg From 4d53d6e2633caed782067965b1b4422b45dab4a2 Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 7 Oct 2015 14:57:48 +0200 Subject: added async publisher to the RPC server --- linux/ws_main.py | 1 + .../trex_control_plane/console/trex_status.py | 2 +- src/gtest/rpc_test.cpp | 5 +- src/rpc-server/commands/trex_rpc_cmd_general.cpp | 13 +- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 1 + src/rpc-server/trex_rpc_async_server.cpp | 36 +++- src/rpc-server/trex_rpc_async_server.h | 1 + src/rpc-server/trex_rpc_cmd.cpp | 1 + src/rpc-server/trex_rpc_server.cpp | 6 +- src/rpc-server/trex_rpc_server_api.h | 6 +- src/rpc-server/trex_rpc_server_mock.cpp | 6 +- src/stateless/trex_stateless.cpp | 122 ++++--------- src/stateless/trex_stateless_api.h | 203 +++++---------------- src/stateless/trex_stateless_port.cpp | 172 +++++++++++++++++ src/stateless/trex_stateless_port.h | 196 ++++++++++++++++++++ 15 files changed, 504 insertions(+), 267 deletions(-) create mode 100644 src/stateless/trex_stateless_port.cpp create mode 100644 src/stateless/trex_stateless_port.h (limited to 'scripts') diff --git a/linux/ws_main.py b/linux/ws_main.py index f1d064cb..193a0d18 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -145,6 +145,7 @@ stateless_src = SrcGroup(dir='src/stateless/', src_list=['trex_stream.cpp', 'trex_stream_vm.cpp', 'trex_stateless.cpp', + 'trex_stateless_port.cpp' ]) # RPC code rpc_server_src = SrcGroup(dir='src/rpc-server/', diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index b881f9f5..2c5a648f 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -170,7 +170,7 @@ class PortsStatsPanel(TrexStatusPanel): port_stats = self.status_obj.stats.get_port_stats(port_index) if port_stats: - self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,}".format( + self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15,.2f} {:^15,.2f} {:^15,} {:^15,.2f} {:^15,.2f} {:^15,}".format( "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]), port_stats["tx_pps"], port_stats["tx_bps"], diff --git a/src/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp index 38d34320..4084b664 100644 --- a/src/gtest/rpc_test.cpp +++ b/src/gtest/rpc_test.cpp @@ -42,9 +42,10 @@ protected: m_verbose = false; - TrexRpcServerConfig cfg = TrexRpcServerConfig(TrexRpcServerConfig::RPC_PROT_TCP, 5050); + TrexRpcServerConfig req_resp_cfg = TrexRpcServerConfig(TrexRpcServerConfig::RPC_PROT_TCP, 5050); + TrexRpcServerConfig async_cfg = TrexRpcServerConfig(TrexRpcServerConfig::RPC_PROT_TCP, 5051); - m_rpc = new TrexRpcServer(cfg); + m_rpc = new TrexRpcServer(req_resp_cfg, async_cfg); m_rpc->start(); m_context = zmq_ctx_new (); diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 7721526c..3a0a12f8 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -22,6 +22,7 @@ limitations under the License. #include "trex_rpc_cmds.h" #include #include +#include #include #include @@ -271,17 +272,7 @@ TrexRpcCmdGetPortStats::_run(const Json::Value ¶ms, Json::Value &result) { result["result"]["status"] = port->get_state_as_string(); - result["result"]["tx_bps"] = Json::Value::UInt64(port->get_stats().m_stats.tx_bps); - result["result"]["tx_pps"] = Json::Value::UInt64(port->get_stats().m_stats.tx_pps); - result["result"]["total_tx_pkts"] = Json::Value::UInt64(port->get_stats().m_stats.total_tx_pkts); - result["result"]["total_tx_bytes"] = Json::Value::UInt64(port->get_stats().m_stats.total_tx_bytes); - - result["result"]["rx_bps"] = Json::Value::UInt64(port->get_stats().m_stats.rx_bps); - result["result"]["rx_pps"] = Json::Value::UInt64(port->get_stats().m_stats.rx_pps); - result["result"]["total_rx_pkts"] = Json::Value::UInt64(port->get_stats().m_stats.total_rx_pkts); - result["result"]["total_rx_bytes"] = Json::Value::UInt64(port->get_stats().m_stats.total_rx_bytes); - - result["result"]["tx_rx_error"] = Json::Value::UInt64(port->get_stats().m_stats.tx_rx_errors); + port->encode_stats(result["result"]); return (TREX_RPC_CMD_OK); } diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 1450e1a9..97c2b791 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -22,6 +22,7 @@ limitations under the License. #include #include #include +#include #include diff --git a/src/rpc-server/trex_rpc_async_server.cpp b/src/rpc-server/trex_rpc_async_server.cpp index 76549cbd..40d16dfe 100644 --- a/src/rpc-server/trex_rpc_async_server.cpp +++ b/src/rpc-server/trex_rpc_async_server.cpp @@ -18,10 +18,19 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + +/* required for sleep_for c++ 2011 + https://bugs.launchpad.net/ubuntu/+source/gcc-4.4/+bug/608145 +*/ +#define _GLIBCXX_USE_NANOSLEEP + #include +#include #include #include #include +#include +#include /** * ZMQ based publisher server @@ -32,6 +41,10 @@ TrexRpcServerAsync::TrexRpcServerAsync(const TrexRpcServerConfig &cfg) : TrexRpc m_context = zmq_ctx_new(); } +/** + * publisher thread + * + */ void TrexRpcServerAsync::_rpc_thread_cb() { std::stringstream ss; @@ -57,21 +70,30 @@ TrexRpcServerAsync::_rpc_thread_cb() { /* while the server is running - publish results */ while (m_is_running) { - /* update all ports for their stats */ - uint8_t port_count = TrexStateless::get_instance().get_port_count(); - for (uint8_t i = 0; i < port_count; i++) { - TrexStateless::get_instance().get_port_by_id(i).update_stats(); - const TrexPortStats &stats = TrexStateless::get_instance().get_port_by_id(i).get_stats(); + Json::Value snapshot; + Json::FastWriter writer; + + /* trigger a full update for stats */ + TrexStateless::get_instance().update_stats(); + + /* encode them to JSON */ + TrexStateless::get_instance().encode_stats(snapshot); + + /* write to string and publish */ + std::string snapshot_str = writer.write(snapshot); + zmq_send(m_socket, snapshot_str.c_str(), snapshot_str.size(), 0); + //std::cout << "sending " << snapshot_str << "\n"; + /* relax for some time */ + std::this_thread::sleep_for (std::chrono::milliseconds(1000)); - } } } void TrexRpcServerAsync::_stop_rpc_thread() { m_is_running = false; - this->m_thread.join(); + this->m_thread->join(); zmq_term(m_context); } diff --git a/src/rpc-server/trex_rpc_async_server.h b/src/rpc-server/trex_rpc_async_server.h index d0a1ee90..13525c01 100644 --- a/src/rpc-server/trex_rpc_async_server.h +++ b/src/rpc-server/trex_rpc_async_server.h @@ -23,6 +23,7 @@ limitations under the License. #define __TREX_RPC_ASYNC_SERVER_H__ #include +#include /** * async RPC server diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp index 6c355e70..f7cb5259 100644 --- a/src/rpc-server/trex_rpc_cmd.cpp +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -21,6 +21,7 @@ limitations under the License. #include #include #include +#include trex_rpc_cmd_rc_e TrexRpcCommand::run(const Json::Value ¶ms, Json::Value &result) { diff --git a/src/rpc-server/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp index 6b8c200d..18265a0e 100644 --- a/src/rpc-server/trex_rpc_server.cpp +++ b/src/rpc-server/trex_rpc_server.cpp @@ -21,6 +21,7 @@ limitations under the License. #include #include +#include #include #include #include @@ -112,10 +113,13 @@ get_current_date_time() { const std::string TrexRpcServer::s_server_uptime = get_current_date_time(); -TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg) { +TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg, + const TrexRpcServerConfig &async_cfg) { /* add the request response server */ m_servers.push_back(new TrexRpcServerReqRes(req_resp_cfg)); + /* add async publisher */ + m_servers.push_back(new TrexRpcServerAsync(async_cfg)); } TrexRpcServer::~TrexRpcServer() { diff --git a/src/rpc-server/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h index 06bbe10c..5a7cad48 100644 --- a/src/rpc-server/trex_rpc_server_api.h +++ b/src/rpc-server/trex_rpc_server_api.h @@ -139,8 +139,10 @@ protected: class TrexRpcServer { public: - /* currently only request response server config is required */ - TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg); + /* creates the collection of servers using configurations */ + TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg, + const TrexRpcServerConfig &async_cfg); + ~TrexRpcServer(); /** diff --git a/src/rpc-server/trex_rpc_server_mock.cpp b/src/rpc-server/trex_rpc_server_mock.cpp index 835e28b8..16aa6774 100644 --- a/src/rpc-server/trex_rpc_server_mock.cpp +++ b/src/rpc-server/trex_rpc_server_mock.cpp @@ -59,8 +59,10 @@ int main(int argc, char *argv[]) { cout << "\n-= Starting RPC Server Mock =-\n\n"; cout << "Listening on tcp://localhost:5050 [ZMQ]\n\n"; - TrexRpcServerConfig rpc_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); - TrexRpcServer rpc(rpc_cfg); + TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); + TrexRpcServerConfig rpc_async_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5051); + + TrexRpcServer rpc(rpc_req_resp_cfg, rpc_async_cfg); /* init the RPC server */ rpc.start(); diff --git a/src/stateless/trex_stateless.cpp b/src/stateless/trex_stateless.cpp index 3ec419ea..0b7947a0 100644 --- a/src/stateless/trex_stateless.cpp +++ b/src/stateless/trex_stateless.cpp @@ -19,6 +19,7 @@ See the License for the specific language governing permissions and limitations under the License. */ #include +#include using namespace std; @@ -73,107 +74,64 @@ uint8_t TrexStateless::get_port_count() { return m_port_count; } +void +TrexStateless::update_stats() { -/*************************** - * trex stateless port stats - * - **************************/ -TrexPortStats::TrexPortStats() { - m_stats = {0}; -} - -/*************************** - * trex stateless port - * - **************************/ -TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { - m_port_state = PORT_STATE_UP_IDLE; - clear_owner(); -} - + /* update CPU util. */ + #ifdef TREX_RPC_MOCK_SERVER + m_stats.m_stats.m_cpu_util = 0; + #else + m_stats.m_stats.m_cpu_util = 0; + #endif -/** - * starts the traffic on the port - * - */ -TrexStatelessPort::rc_e -TrexStatelessPort::start_traffic(void) { + /* for every port update and accumulate */ + for (uint8_t i = 0; i < m_port_count; i++) { + m_ports[i]->update_stats(); - if (m_port_state != PORT_STATE_UP_IDLE) { - return (RC_ERR_BAD_STATE_FOR_OP); - } + const TrexPortStats & port_stats = m_ports[i]->get_stats(); - if (get_stream_table()->size() == 0) { - return (RC_ERR_NO_STREAMS); - } + m_stats.m_stats.m_tx_bps += port_stats.m_stats.m_tx_bps; + m_stats.m_stats.m_rx_bps += port_stats.m_stats.m_rx_bps; - m_port_state = PORT_STATE_TRANSMITTING; + m_stats.m_stats.m_tx_pps += port_stats.m_stats.m_tx_pps; + m_stats.m_stats.m_rx_pps += port_stats.m_stats.m_rx_pps; - /* real code goes here */ - return (RC_OK); -} + m_stats.m_stats.m_total_tx_pkts += port_stats.m_stats.m_total_tx_pkts; + m_stats.m_stats.m_total_rx_pkts += port_stats.m_stats.m_total_rx_pkts; -void -TrexStatelessPort::stop_traffic(void) { + m_stats.m_stats.m_total_tx_bytes += port_stats.m_stats.m_total_tx_bytes; + m_stats.m_stats.m_total_rx_bytes += port_stats.m_stats.m_total_rx_bytes; - /* real code goes here */ - if (m_port_state == PORT_STATE_TRANSMITTING) { - m_port_state = PORT_STATE_UP_IDLE; + m_stats.m_stats.m_tx_rx_errors += port_stats.m_stats.m_tx_rx_errors; } } -/** -* access the stream table -* -*/ -TrexStreamTable * TrexStatelessPort::get_stream_table() { - return &m_stream_table; -} - +void +TrexStateless::encode_stats(Json::Value &global) { -std::string -TrexStatelessPort::get_state_as_string() { + global["cpu_util"] = m_stats.m_stats.m_cpu_util; - switch (get_state()) { - case PORT_STATE_DOWN: - return "down"; + global["tx_bps"] = m_stats.m_stats.m_tx_bps; + global["rx_bps"] = m_stats.m_stats.m_rx_bps; - case PORT_STATE_UP_IDLE: - return "idle"; + global["tx_pps"] = m_stats.m_stats.m_tx_pps; + global["rx_pps"] = m_stats.m_stats.m_rx_pps; - case PORT_STATE_TRANSMITTING: - return "transmitting"; - } + global["total_tx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_pkts); + global["total_rx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_pkts); - return "unknown"; -} + global["total_tx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_bytes); + global["total_rx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_bytes); -void -TrexStatelessPort::get_properties(string &driver, string &speed) { + global["tx_rx_errors"] = Json::Value::UInt64(m_stats.m_stats.m_tx_rx_errors); - /* take this from DPDK */ - driver = "e1000"; - speed = "1 Gbps"; -} + for (uint8_t i = 0; i < m_port_count; i++) { + std::stringstream ss; + ss << "port " << i; + Json::Value &port_section = global[ss.str()]; -/** - * generate a random connection handler - * - */ -std::string -TrexStatelessPort::generate_handler() { - std::stringstream ss; - - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - /* generate 8 bytes of random handler */ - for (int i = 0; i < 8; ++i) { - ss << alphanum[rand() % (sizeof(alphanum) - 1)]; + m_ports[i]->encode_stats(port_section); } - - return (ss.str()); } + diff --git a/src/stateless/trex_stateless_api.h b/src/stateless/trex_stateless_api.h index fd88baf7..e2bf4e1c 100644 --- a/src/stateless/trex_stateless_api.h +++ b/src/stateless/trex_stateless_api.h @@ -41,167 +41,36 @@ public: } }; -/** - * TRex stateless port stats - * - * @author imarom (24-Sep-15) - */ -class TrexPortStats { - -public: - TrexPortStats(); - -public: - struct { - uint64_t tx_pps; - uint64_t tx_bps; - uint64_t total_tx_pkts; - uint64_t total_tx_bytes; - - uint64_t rx_pps; - uint64_t rx_bps; - uint64_t total_rx_pkts; - uint64_t total_rx_bytes; - - uint64_t tx_rx_errors; - } m_stats; -}; +class TrexStatelessPort; /** - * describes a stateless port + * unified stats * - * @author imarom (31-Aug-15) + * @author imarom (06-Oct-15) */ -class TrexStatelessPort { +class TrexStatelessStats { public: - - /** - * port state - */ - enum port_state_e { - PORT_STATE_DOWN, - PORT_STATE_UP_IDLE, - PORT_STATE_TRANSMITTING - }; - - /** - * describess different error codes for port operations - */ - enum rc_e { - RC_OK, - RC_ERR_BAD_STATE_FOR_OP, - RC_ERR_NO_STREAMS, - RC_ERR_FAILED_TO_COMPILE_STREAMS - }; - - TrexStatelessPort(uint8_t port_id); - - /** - * start traffic - * - */ - rc_e start_traffic(void); - - /** - * stop traffic - * - */ - void stop_traffic(void); - - /** - * access the stream table - * - */ - TrexStreamTable *get_stream_table(); - - /** - * get the port state - * - */ - port_state_e get_state() { - return m_port_state; + TrexStatelessStats() { + m_stats = {0}; } - /** - * port state as string - * - */ - std::string get_state_as_string(); - - /** - * fill up properties of the port - * - * @author imarom (16-Sep-15) - * - * @param driver - * @param speed - */ - void get_properties(std::string &driver, std::string &speed); - - /** - * query for ownership - * - */ - const std::string &get_owner() { - return m_owner; - } - - /** - * owner handler - * for the connection - * - */ - const std::string &get_owner_handler() { - return m_owner_handler; - } - - bool is_free_to_aquire() { - return (m_owner == "none"); - } - - /** - * take ownership of the server array - * this is static - * ownership is total - * - */ - void set_owner(const std::string &owner) { - m_owner = owner; - m_owner_handler = generate_handler(); - } - - void clear_owner() { - m_owner = "none"; - m_owner_handler = ""; - } - - bool verify_owner_handler(const std::string &handler) { - - return ( (m_owner != "none") && (m_owner_handler == handler) ); - - } - - /** - * update the values of the stats - * - * @author imarom (24-Sep-15) - */ - void update_stats(); - - const TrexPortStats & get_stats() { - return m_stats; - } - -private: - - std::string generate_handler(); - - TrexStreamTable m_stream_table; - uint8_t m_port_id; - port_state_e m_port_state; - std::string m_owner; - std::string m_owner_handler; - TrexPortStats m_stats; + struct { + double m_cpu_util; + + double m_tx_bps; + double m_rx_bps; + + double m_tx_pps; + double m_rx_pps; + + uint64_t m_total_tx_pkts; + uint64_t m_total_rx_pkts; + + uint64_t m_total_tx_bytes; + uint64_t m_total_rx_bytes; + + uint64_t m_tx_rx_errors; + } m_stats; }; /** @@ -232,8 +101,22 @@ public: return instance; } - TrexStatelessPort *get_port_by_id(uint8_t port_id); - uint8_t get_port_count(); + TrexStatelessPort * get_port_by_id(uint8_t port_id); + uint8_t get_port_count(); + + /** + * update all the stats (deep update) + * (include all the ports and global stats) + * + */ + void update_stats(); + + /** + * fetch all the stats + * + */ + void encode_stats(Json::Value &global); + protected: TrexStateless(); @@ -248,9 +131,11 @@ protected: TrexStateless(TrexStateless const&) = delete; void operator=(TrexStateless const&) = delete; - bool m_is_configured; - TrexStatelessPort **m_ports; - uint8_t m_port_count; + bool m_is_configured; + TrexStatelessPort **m_ports; + uint8_t m_port_count; + + TrexStatelessStats m_stats; }; #endif /* __TREX_STATELESS_API_H__ */ diff --git a/src/stateless/trex_stateless_port.cpp b/src/stateless/trex_stateless_port.cpp new file mode 100644 index 00000000..7322ef8a --- /dev/null +++ b/src/stateless/trex_stateless_port.cpp @@ -0,0 +1,172 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include +#include +#include + +using namespace std; + +/*************************** + * trex stateless port + * + **************************/ +TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { + m_port_state = PORT_STATE_UP_IDLE; + clear_owner(); +} + + +/** + * starts the traffic on the port + * + */ +TrexStatelessPort::rc_e +TrexStatelessPort::start_traffic(void) { + + if (m_port_state != PORT_STATE_UP_IDLE) { + return (RC_ERR_BAD_STATE_FOR_OP); + } + + if (get_stream_table()->size() == 0) { + return (RC_ERR_NO_STREAMS); + } + + m_port_state = PORT_STATE_TRANSMITTING; + + /* real code goes here */ + return (RC_OK); +} + +void +TrexStatelessPort::stop_traffic(void) { + + /* real code goes here */ + if (m_port_state == PORT_STATE_TRANSMITTING) { + m_port_state = PORT_STATE_UP_IDLE; + } +} + +/** +* access the stream table +* +*/ +TrexStreamTable * TrexStatelessPort::get_stream_table() { + return &m_stream_table; +} + + +std::string +TrexStatelessPort::get_state_as_string() { + + switch (get_state()) { + case PORT_STATE_DOWN: + return "down"; + + case PORT_STATE_UP_IDLE: + return "idle"; + + case PORT_STATE_TRANSMITTING: + return "transmitting"; + } + + return "unknown"; +} + +void +TrexStatelessPort::get_properties(string &driver, string &speed) { + + /* take this from DPDK */ + driver = "e1000"; + speed = "1 Gbps"; +} + + +/** + * generate a random connection handler + * + */ +std::string +TrexStatelessPort::generate_handler() { + std::stringstream ss; + + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + /* generate 8 bytes of random handler */ + for (int i = 0; i < 8; ++i) { + ss << alphanum[rand() % (sizeof(alphanum) - 1)]; + } + + return (ss.str()); +} + +/** + * update stats for the port + * + */ +void +TrexStatelessPort::update_stats() { + #ifdef TREX_RPC_MOCK_SERVER + /* do lies - its a mock */ + m_stats.m_stats.m_tx_bps = rand() % 10000; + m_stats.m_stats.m_rx_bps = rand() % 10000; + + m_stats.m_stats.m_tx_pps = m_stats.m_stats.m_tx_bps / (64 + rand() % 1000); + m_stats.m_stats.m_rx_pps = m_stats.m_stats.m_rx_bps / (64 + rand() % 1000); + + + m_stats.m_stats.m_total_tx_bytes += m_stats.m_stats.m_tx_bps; + m_stats.m_stats.m_total_rx_bytes += m_stats.m_stats.m_rx_bps; + + m_stats.m_stats.m_total_tx_pkts += m_stats.m_stats.m_tx_pps; + m_stats.m_stats.m_total_rx_pkts += m_stats.m_stats.m_rx_pps; + + #else + /* real update work */ + #endif +} + +const TrexPortStats & +TrexStatelessPort::get_stats() { + return m_stats; +} + +void +TrexStatelessPort::encode_stats(Json::Value &port) { + + port["tx_bps"] = m_stats.m_stats.m_tx_bps; + port["rx_bps"] = m_stats.m_stats.m_rx_bps; + + port["tx_pps"] = m_stats.m_stats.m_tx_pps; + port["rx_pps"] = m_stats.m_stats.m_rx_pps; + + port["total_tx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_pkts); + port["total_rx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_pkts); + + port["total_tx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_bytes); + port["total_rx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_bytes); + + port["tx_rx_errors"] = Json::Value::UInt64(m_stats.m_stats.m_tx_rx_errors); +} + + diff --git a/src/stateless/trex_stateless_port.h b/src/stateless/trex_stateless_port.h new file mode 100644 index 00000000..ea98ddae --- /dev/null +++ b/src/stateless/trex_stateless_port.h @@ -0,0 +1,196 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#ifndef __TREX_STATELESS_PORT_H__ +#define __TREX_STATELESS_PORT_H__ + +#include + +/** + * TRex stateless port stats + * + * @author imarom (24-Sep-15) + */ +class TrexPortStats { + +public: + TrexPortStats() { + m_stats = {0}; + } + +public: + struct { + + double m_tx_bps; + double m_rx_bps; + + double m_tx_pps; + double m_rx_pps; + + uint64_t m_total_tx_pkts; + uint64_t m_total_rx_pkts; + + uint64_t m_total_tx_bytes; + uint64_t m_total_rx_bytes; + + uint64_t m_tx_rx_errors; + } m_stats; +}; + +/** + * describes a stateless port + * + * @author imarom (31-Aug-15) + */ +class TrexStatelessPort { +public: + + /** + * port state + */ + enum port_state_e { + PORT_STATE_DOWN, + PORT_STATE_UP_IDLE, + PORT_STATE_TRANSMITTING + }; + + /** + * describess different error codes for port operations + */ + enum rc_e { + RC_OK, + RC_ERR_BAD_STATE_FOR_OP, + RC_ERR_NO_STREAMS, + RC_ERR_FAILED_TO_COMPILE_STREAMS + }; + + TrexStatelessPort(uint8_t port_id); + + /** + * start traffic + * + */ + rc_e start_traffic(void); + + /** + * stop traffic + * + */ + void stop_traffic(void); + + /** + * access the stream table + * + */ + TrexStreamTable *get_stream_table(); + + /** + * get the port state + * + */ + port_state_e get_state() { + return m_port_state; + } + + /** + * port state as string + * + */ + std::string get_state_as_string(); + + /** + * fill up properties of the port + * + * @author imarom (16-Sep-15) + * + * @param driver + * @param speed + */ + void get_properties(std::string &driver, std::string &speed); + + /** + * query for ownership + * + */ + const std::string &get_owner() { + return m_owner; + } + + /** + * owner handler + * for the connection + * + */ + const std::string &get_owner_handler() { + return m_owner_handler; + } + + bool is_free_to_aquire() { + return (m_owner == "none"); + } + + /** + * take ownership of the server array + * this is static + * ownership is total + * + */ + void set_owner(const std::string &owner) { + m_owner = owner; + m_owner_handler = generate_handler(); + } + + void clear_owner() { + m_owner = "none"; + m_owner_handler = ""; + } + + bool verify_owner_handler(const std::string &handler) { + + return ( (m_owner != "none") && (m_owner_handler == handler) ); + + } + + /** + * update the values of the stats + * + */ + void update_stats(); + + const TrexPortStats & get_stats(); + + /** + * encode stats as JSON + */ + void encode_stats(Json::Value &port); + +private: + + std::string generate_handler(); + + TrexStreamTable m_stream_table; + uint8_t m_port_id; + port_state_e m_port_state; + std::string m_owner; + std::string m_owner_handler; + TrexPortStats m_stats; +}; + +#endif /* __TREX_STATELESS_PORT_H__ */ -- cgit 1.2.3-korg From 63318b05c360872ccd6d6348a6818ca2929927c9 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Mon, 12 Oct 2015 08:59:01 +0300 Subject: fixed documentation conflicts --- .../automation/trex_control_plane/doc/about_trex.rst | 19 ------------------- .../automation/trex_control_plane/doc/api/index.rst | 19 +++++++++++++++++++ scripts/automation/trex_control_plane/doc/index.rst | 14 -------------- 3 files changed, 19 insertions(+), 33 deletions(-) delete mode 100755 scripts/automation/trex_control_plane/doc/about_trex.rst create mode 100755 scripts/automation/trex_control_plane/doc/api/index.rst (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/doc/about_trex.rst b/scripts/automation/trex_control_plane/doc/about_trex.rst deleted file mode 100755 index 669e2b28..00000000 --- a/scripts/automation/trex_control_plane/doc/about_trex.rst +++ /dev/null @@ -1,19 +0,0 @@ -================== -About TRex project -================== - -Full project's official site ----------------------------- - -To learn all about TRex project, visit TRex `official site `_ - -GitHub Repository ------------------ - -`TRex GitHub repository `_ - -TRex Google Group ------------------ - -Check out the project's `google group `_ to contact TRex DEV team and follow other user stories. - diff --git a/scripts/automation/trex_control_plane/doc/api/index.rst b/scripts/automation/trex_control_plane/doc/api/index.rst new file mode 100755 index 00000000..6db45160 --- /dev/null +++ b/scripts/automation/trex_control_plane/doc/api/index.rst @@ -0,0 +1,19 @@ + +API Reference +============= +The T-Rex API reference section is currently a work in progress. + +**T-Rex Modules** + +.. toctree:: + :maxdepth: 4 + + client_code + exceptions + +**T-Rex JSON Template** + +.. toctree:: + :maxdepth: 4 + + json_fields \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/index.rst b/scripts/automation/trex_control_plane/doc/index.rst index 10803cb0..62fd9975 100755 --- a/scripts/automation/trex_control_plane/doc/index.rst +++ b/scripts/automation/trex_control_plane/doc/index.rst @@ -18,13 +18,6 @@ To understand the entirely how the API works and how to set up the server side, **Use the table of contents below or the menu to your left to navigate through the site** -Getting Started -=============== -.. toctree:: - :maxdepth: 2 - - installation - API Reference ============= .. toctree:: @@ -46,13 +39,6 @@ Usage Examples usage_examples -About TRex -========== -.. toctree:: - :maxdepth: 2 - - All about TRex - Indices and tables ================== -- cgit 1.2.3-korg From 279046aec7d7e72a0cb42250ed8b69f1d290df55 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Mon, 12 Oct 2015 16:49:58 +0300 Subject: check for 64bit kernel --- scripts/trex-cfg | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'scripts') diff --git a/scripts/trex-cfg b/scripts/trex-cfg index 2aebf026..ca442d15 100755 --- a/scripts/trex-cfg +++ b/scripts/trex-cfg @@ -30,6 +30,15 @@ for file in /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepag fi done +MACHINE_TYPE=`uname -m` + +if [ ${MACHINE_TYPE} != 'x86_64' ]; then + echo "ERROR You have a 32bit Kernel try to install 64bit Kernel" + exit 1 +fi + + + if ! lsmod | grep -q igb_uio ; then echo "Load the drivers for the first time " modprobe uio -- cgit 1.2.3-korg From bd640666c052a1c770c9c1758c809f68d99af010 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Mon, 12 Oct 2015 09:11:44 +0300 Subject: solving conflicts --- .../trex_control_plane/client/trex_adv_client.py | 2 +- .../trex_control_plane/client/trex_client.py | 4 +- .../trex_control_plane/doc/api/index.rst | 7 +- .../trex_control_plane/doc/api/json_fields.rst | 464 ++++++++++----------- .../trex_control_plane/doc/client_utils.rst | 5 + .../automation/trex_control_plane/doc/index.rst | 14 + .../doc/packet_generator/examples.rst | 5 + .../doc/packet_generator/export_format.yaml | 47 +++ .../trex_control_plane/doc/requirements.rst | 0 .../examples/client_interactive_example.py | 2 +- scripts/trex-cfg | 9 - 11 files changed, 310 insertions(+), 249 deletions(-) create mode 100755 scripts/automation/trex_control_plane/doc/packet_generator/examples.rst create mode 100755 scripts/automation/trex_control_plane/doc/packet_generator/export_format.yaml delete mode 100755 scripts/automation/trex_control_plane/doc/requirements.rst (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client/trex_adv_client.py b/scripts/automation/trex_control_plane/client/trex_adv_client.py index b135da59..b3fe3dad 100755 --- a/scripts/automation/trex_control_plane/client/trex_adv_client.py +++ b/scripts/automation/trex_control_plane/client/trex_adv_client.py @@ -8,7 +8,7 @@ class CTRexAdvClient(trex_client.CTRexClient): super(CTRexAdvClient, self).__init__(trex_host, max_history_size, trex_daemon_port, trex_zmq_port, verbose) pass - # TREX KIWI advanced methods + # T-REX KIWI advanced methods def start_quick_trex(self, pcap_file, d, delay, dual, ipv6, times, interfaces): try: return self.server.start_quick_trex(pcap_file = pcap_file, duration = d, dual = dual, delay = delay, ipv6 = ipv6, times = times, interfaces = interfaces) diff --git a/scripts/automation/trex_control_plane/client/trex_client.py b/scripts/automation/trex_control_plane/client/trex_client.py index 607251fe..c3677132 100755 --- a/scripts/automation/trex_control_plane/client/trex_client.py +++ b/scripts/automation/trex_control_plane/client/trex_client.py @@ -805,7 +805,7 @@ class CTRexResult(object): def is_valid_hist (self): """ - Checks if result object contains valid data. + Checks if result obejct contains valid data. :parameters: None @@ -819,7 +819,7 @@ class CTRexResult(object): def set_valid_hist (self, valid_stat = True): """ - Sets result object validity status. + Sets result obejct validity status. :parameters: valid_stat : bool diff --git a/scripts/automation/trex_control_plane/doc/api/index.rst b/scripts/automation/trex_control_plane/doc/api/index.rst index 6db45160..cfdc6917 100755 --- a/scripts/automation/trex_control_plane/doc/api/index.rst +++ b/scripts/automation/trex_control_plane/doc/api/index.rst @@ -1,9 +1,8 @@ API Reference ============= -The T-Rex API reference section is currently a work in progress. -**T-Rex Modules** +**TRex Modules** .. toctree:: :maxdepth: 4 @@ -11,9 +10,9 @@ The T-Rex API reference section is currently a work in progress. client_code exceptions -**T-Rex JSON Template** +**TRex JSON Template** .. toctree:: :maxdepth: 4 - json_fields \ No newline at end of file + json_fields diff --git a/scripts/automation/trex_control_plane/doc/api/json_fields.rst b/scripts/automation/trex_control_plane/doc/api/json_fields.rst index c921fec4..9e32d23e 100755 --- a/scripts/automation/trex_control_plane/doc/api/json_fields.rst +++ b/scripts/automation/trex_control_plane/doc/api/json_fields.rst @@ -1,233 +1,233 @@ - -TRex JSON Template -================== - -Whenever TRex is publishing live data, it uses JSON notation to describe the data-object. - -Each client may parse it differently, however this page will describe the values meaning when published by TRex server. - - -Main Fields ------------ - -Each TRex server-published JSON object contains data divided to main fields under which the actual data lays. - -These main fields are: - -+-----------------------------+----------------------------------------------------+---------------------------+ -| Main field | Contains | Comments | -+=============================+====================================================+===========================+ -| :ref:`trex-global-field` | Must-have data on TRex run, | | -| | mainly regarding Tx/Rx and packet drops | | -+-----------------------------+----------------------------------------------------+---------------------------+ -| :ref:`tx-gen-field` | Data indicate the quality of the transmit process. | | -| | In case histogram is zero it means that all packets| | -| | were injected in the right time. | | -+-----------------------------+----------------------------------------------------+---------------------------+ -| :ref:`trex-latecny-field` | Latency reports, containing latency data on | - Generated when latency | -| | generated data and on response traffic | test is enabled (``l`` | -| | | param) | -| | | - *typo* on field key: | -+-----------------------------+----------------------------------------------------+ will be fixed on next | -| :ref:`trex-latecny-v2-field`| Extended latency information | release | -+-----------------------------+----------------------------------------------------+---------------------------+ - - -Each of these fields contains keys for field general data (such as its name) and its actual data, which is always stored under the **"data"** key. - -For example, in order to access some trex-global data, the access path would look like:: - - AllData -> trex-global -> data -> desired_info - - - - -Detailed explanation --------------------- - -.. _trex-global-field: - -trex-global field -~~~~~~~~~~~~~~~~~ - - -+--------------------------------+-------+-----------------------------------------------------------+ -| Sub-key | Type | Meaning | -+================================+=======+===========================================================+ -| m_cpu_util | float | CPU utilization (0-100) | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_platform_factor | float | multiplier factor | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_bps | float | total tx bit per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_rx_bps | float | total rx bit per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_pps | float | total tx packet per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_cps | float | total tx connection per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_expected_cps | float | expected tx connection per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_expected_pps | float | expected tx packet per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_tx_expected_bps | float | expected tx bit per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_rx_drop_bps | float | drop rate in bit per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_active_flows | float | active trex flows | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_open_flows | float | open trex flows from startup (monotonically incrementing) | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_tx_pkts | int | total tx in packets | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_rx_pkts | int | total rx in packets | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_tx_bytes | int | total tx in bytes | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_rx_bytes | int | total rx in bytes | -+--------------------------------+-------+-----------------------------------------------------------+ -| opackets-# | int | output packets (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| obytes-# | int | output bytes (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| ipackets-# | int | input packet (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| ibytes-# | int | input bytes (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| ierrors-# | int | input errors (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| oerrors-# | int | input errors (per interface) | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_tx_bps-# | float | total transmitted data in bit per second | -+--------------------------------+-------+-----------------------------------------------------------+ -| unknown | int | | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_nat_learn_error [#f1]_ | int | | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_nat_active [#f2]_ | int | | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_nat_no_fid [#f2]_ | int | | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_nat_time_out [#f2]_ | int | | -+--------------------------------+-------+-----------------------------------------------------------+ -| m_total_nat_open [#f2]_ | int | | -+--------------------------------+-------+-----------------------------------------------------------+ - - -.. _tx-gen-field: - -tx-gen field -~~~~~~~~~~~~ - -+-------------------+-------+-----------------------------------------------------------+ -| Sub-key | Type | Meaning | -+===================+=======+===========================================================+ -| realtime-hist | dict | histogram of transmission. See extended information about | -| | | histogram object under :ref:`histogram-object-fields`. | -| | | The attribute analyzed is time packet has been sent | -| | | before/after it was intended to be | -+-------------------+-------+-----------------------------------------------------------+ -| unknown | int | | -+-------------------+-------+-----------------------------------------------------------+ - -.. _trex-latecny-field: - -trex-latecny field -~~~~~~~~~~~~~~~~~~ - -+---------+-------+---------------------------------------------------------+ -| Sub-key | Type | Meaning | -+=========+=======+=========================================================+ -| avg-# | float | average latency in usec (per interface) | -+---------+-------+---------------------------------------------------------+ -| max-# | float | max latency in usec from the test start (per interface) | -+---------+-------+---------------------------------------------------------+ -| c-max-# | float | max in the last 1 sec window (per interface) | -+---------+-------+---------------------------------------------------------+ -| error-# | float | errors in latency packets (per interface) | -+---------+-------+---------------------------------------------------------+ -| unknown | int | | -+---------+-------+---------------------------------------------------------+ - -.. _trex-latecny-v2-field: - -trex-latecny-v2 field -~~~~~~~~~~~~~~~~~~~~~ - -+--------------------------------------+-------+--------------------------------------+ -| Sub-key | Type | Meaning | -+======================================+=======+======================================+ -| cpu_util | float | rx thread cpu % (this is not trex DP | -| | | threads cpu%%) | -+--------------------------------------+-------+--------------------------------------+ -| port-# | | Containing per interface | -| | dict | information. See extended | -| | | information under ``port-# -> | -| | | key_name -> sub_key`` | -+--------------------------------------+-------+--------------------------------------+ -| port-#->hist | dict | histogram of latency. See extended | -| | | information about histogram object | -| | | under :ref:`histogram-object-fields`.| -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats | | Containing per interface | -| | dict | information. See extended | -| | | information under ``port-# -> | -| | | key_name -> sub_key`` | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_tx_pkt_ok | int | total of try sent packets | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_pkt_ok | int | total of packets sent from hardware | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_no_magic | int | rx error with no magic | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_no_id | int | rx errors with no id | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_seq_error | int | error in seq number | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_length_error | int | | -+--------------------------------------+-------+--------------------------------------+ -| port-#->stats->m_rx_check | int | packets tested in rx | -+--------------------------------------+-------+--------------------------------------+ -| unknown | int | | -+--------------------------------------+-------+--------------------------------------+ - - - -.. _histogram-object-fields: - -Histogram object fields -~~~~~~~~~~~~~~~~~~~~~~~ - -The histogram object is being used in number of place throughout the JSON object. -The following section describes its fields in detail. - - -+-----------+-------+-----------------------------------------------------------------------------------+ -| Sub-key | Type | Meaning | -+===========+=======+===================================================================================+ -| min_usec | int | min attribute value in usec. pkt with latency less than this value is not counted | -+-----------+-------+-----------------------------------------------------------------------------------+ -| max_usec | int | max attribute value in usec | -+-----------+-------+-----------------------------------------------------------------------------------+ -| high_cnt | int | how many packets on which its attribute > min_usec | -+-----------+-------+-----------------------------------------------------------------------------------+ -| cnt | int | total packets from test startup | -+-----------+-------+-----------------------------------------------------------------------------------+ -| s_avg | float | average value from test startup | -+-----------+-------+-----------------------------------------------------------------------------------+ -| histogram | | histogram of relevant object by the following keys: | -| | array | - key: value in usec | -| | | - val: number of packets | -+-----------+-------+-----------------------------------------------------------------------------------+ - - -Access Examples ---------------- - - - -.. rubric:: Footnotes - -.. [#f1] Available only in NAT and NAT learning operation (``learn`` and ``learn-verify`` flags) - + +TRex JSON Template +================== + +Whenever TRex is publishing live data, it uses JSON notation to describe the data-object. + +Each client may parse it differently, however this page will describe the values meaning when published by TRex server. + + +Main Fields +----------- + +Each TRex server-published JSON object contains data divided to main fields under which the actual data lays. + +These main fields are: + ++-----------------------------+----------------------------------------------------+---------------------------+ +| Main field | Contains | Comments | ++=============================+====================================================+===========================+ +| :ref:`trex-global-field` | Must-have data on TRex run, | | +| | mainly regarding Tx/Rx and packet drops | | ++-----------------------------+----------------------------------------------------+---------------------------+ +| :ref:`tx-gen-field` | Data indicate the quality of the transmit process. | | +| | In case histogram is zero it means that all packets| | +| | were injected in the right time. | | ++-----------------------------+----------------------------------------------------+---------------------------+ +| :ref:`trex-latecny-field` | Latency reports, containing latency data on | - Generated when latency | +| | generated data and on response traffic | test is enabled (``l`` | +| | | param) | +| | | - *typo* on field key: | ++-----------------------------+----------------------------------------------------+ will be fixed on next | +| :ref:`trex-latecny-v2-field`| Extended latency information | release | ++-----------------------------+----------------------------------------------------+---------------------------+ + + +Each of these fields contains keys for field general data (such as its name) and its actual data, which is always stored under the **"data"** key. + +For example, in order to access some trex-global data, the access path would look like:: + + AllData -> trex-global -> data -> desired_info + + + + +Detailed explanation +-------------------- + +.. _trex-global-field: + +trex-global field +~~~~~~~~~~~~~~~~~ + + ++--------------------------------+-------+-----------------------------------------------------------+ +| Sub-key | Type | Meaning | ++================================+=======+===========================================================+ +| m_cpu_util | float | CPU utilization (0-100) | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_platform_factor | float | multiplier factor | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_bps | float | total tx bit per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_rx_bps | float | total rx bit per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_pps | float | total tx packet per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_cps | float | total tx connection per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_expected_cps | float | expected tx connection per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_expected_pps | float | expected tx packet per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_tx_expected_bps | float | expected tx bit per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_rx_drop_bps | float | drop rate in bit per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_active_flows | float | active trex flows | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_open_flows | float | open trex flows from startup (monotonically incrementing) | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_tx_pkts | int | total tx in packets | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_rx_pkts | int | total rx in packets | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_tx_bytes | int | total tx in bytes | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_rx_bytes | int | total rx in bytes | ++--------------------------------+-------+-----------------------------------------------------------+ +| opackets-# | int | output packets (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| obytes-# | int | output bytes (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| ipackets-# | int | input packet (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| ibytes-# | int | input bytes (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| ierrors-# | int | input errors (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| oerrors-# | int | input errors (per interface) | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_tx_bps-# | float | total transmitted data in bit per second | ++--------------------------------+-------+-----------------------------------------------------------+ +| unknown | int | | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_nat_learn_error [#f1]_ | int | | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_nat_active [#f2]_ | int | | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_nat_no_fid [#f2]_ | int | | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_nat_time_out [#f2]_ | int | | ++--------------------------------+-------+-----------------------------------------------------------+ +| m_total_nat_open [#f2]_ | int | | ++--------------------------------+-------+-----------------------------------------------------------+ + + +.. _tx-gen-field: + +tx-gen field +~~~~~~~~~~~~ + ++-------------------+-------+-----------------------------------------------------------+ +| Sub-key | Type | Meaning | ++===================+=======+===========================================================+ +| realtime-hist | dict | histogram of transmission. See extended information about | +| | | histogram object under :ref:`histogram-object-fields`. | +| | | The attribute analyzed is time packet has been sent | +| | | before/after it was intended to be | ++-------------------+-------+-----------------------------------------------------------+ +| unknown | int | | ++-------------------+-------+-----------------------------------------------------------+ + +.. _trex-latecny-field: + +trex-latecny field +~~~~~~~~~~~~~~~~~~ + ++---------+-------+---------------------------------------------------------+ +| Sub-key | Type | Meaning | ++=========+=======+=========================================================+ +| avg-# | float | average latency in usec (per interface) | ++---------+-------+---------------------------------------------------------+ +| max-# | float | max latency in usec from the test start (per interface) | ++---------+-------+---------------------------------------------------------+ +| c-max-# | float | max in the last 1 sec window (per interface) | ++---------+-------+---------------------------------------------------------+ +| error-# | float | errors in latency packets (per interface) | ++---------+-------+---------------------------------------------------------+ +| unknown | int | | ++---------+-------+---------------------------------------------------------+ + +.. _trex-latecny-v2-field: + +trex-latecny-v2 field +~~~~~~~~~~~~~~~~~~~~~ + ++--------------------------------------+-------+--------------------------------------+ +| Sub-key | Type | Meaning | ++======================================+=======+======================================+ +| cpu_util | float | rx thread cpu % (this is not trex DP | +| | | threads cpu%%) | ++--------------------------------------+-------+--------------------------------------+ +| port-# | | Containing per interface | +| | dict | information. See extended | +| | | information under ``port-# -> | +| | | key_name -> sub_key`` | ++--------------------------------------+-------+--------------------------------------+ +| port-#->hist | dict | histogram of latency. See extended | +| | | information about histogram object | +| | | under :ref:`histogram-object-fields`.| ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats | | Containing per interface | +| | dict | information. See extended | +| | | information under ``port-# -> | +| | | key_name -> sub_key`` | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_tx_pkt_ok | int | total of try sent packets | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_pkt_ok | int | total of packets sent from hardware | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_no_magic | int | rx error with no magic | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_no_id | int | rx errors with no id | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_seq_error | int | error in seq number | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_length_error | int | | ++--------------------------------------+-------+--------------------------------------+ +| port-#->stats->m_rx_check | int | packets tested in rx | ++--------------------------------------+-------+--------------------------------------+ +| unknown | int | | ++--------------------------------------+-------+--------------------------------------+ + + + +.. _histogram-object-fields: + +Histogram object fields +~~~~~~~~~~~~~~~~~~~~~~~ + +The histogram object is being used in number of place throughout the JSON object. +The following section describes its fields in detail. + + ++-----------+-------+-----------------------------------------------------------------------------------+ +| Sub-key | Type | Meaning | ++===========+=======+===================================================================================+ +| min_usec | int | min attribute value in usec. pkt with latency less than this value is not counted | ++-----------+-------+-----------------------------------------------------------------------------------+ +| max_usec | int | max attribute value in usec | ++-----------+-------+-----------------------------------------------------------------------------------+ +| high_cnt | int | how many packets on which its attribute > min_usec | ++-----------+-------+-----------------------------------------------------------------------------------+ +| cnt | int | total packets from test startup | ++-----------+-------+-----------------------------------------------------------------------------------+ +| s_avg | float | average value from test startup | ++-----------+-------+-----------------------------------------------------------------------------------+ +| histogram | | histogram of relevant object by the following keys: | +| | array | - key: value in usec | +| | | - val: number of packets | ++-----------+-------+-----------------------------------------------------------------------------------+ + + +Access Examples +--------------- + + + +.. rubric:: Footnotes + +.. [#f1] Available only in NAT and NAT learning operation (``learn`` and ``learn-verify`` flags) + .. [#f2] Available only in NAT operation (``learn`` flag) \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/client_utils.rst b/scripts/automation/trex_control_plane/doc/client_utils.rst index 122ae310..32728a57 100755 --- a/scripts/automation/trex_control_plane/doc/client_utils.rst +++ b/scripts/automation/trex_control_plane/doc/client_utils.rst @@ -2,6 +2,11 @@ Client Utilities ================ +.. toctree:: + :maxdepth: 2 + + packet_generator/index + TRex YAML generator ------------------- diff --git a/scripts/automation/trex_control_plane/doc/index.rst b/scripts/automation/trex_control_plane/doc/index.rst index 62fd9975..10803cb0 100755 --- a/scripts/automation/trex_control_plane/doc/index.rst +++ b/scripts/automation/trex_control_plane/doc/index.rst @@ -18,6 +18,13 @@ To understand the entirely how the API works and how to set up the server side, **Use the table of contents below or the menu to your left to navigate through the site** +Getting Started +=============== +.. toctree:: + :maxdepth: 2 + + installation + API Reference ============= .. toctree:: @@ -39,6 +46,13 @@ Usage Examples usage_examples +About TRex +========== +.. toctree:: + :maxdepth: 2 + + All about TRex + Indices and tables ================== diff --git a/scripts/automation/trex_control_plane/doc/packet_generator/examples.rst b/scripts/automation/trex_control_plane/doc/packet_generator/examples.rst new file mode 100755 index 00000000..bff1ef7f --- /dev/null +++ b/scripts/automation/trex_control_plane/doc/packet_generator/examples.rst @@ -0,0 +1,5 @@ + +Packet Builder Usage Examples +============================= + +Here I'll add usage examples, very similar to those I added to RPC document \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/packet_generator/export_format.yaml b/scripts/automation/trex_control_plane/doc/packet_generator/export_format.yaml new file mode 100755 index 00000000..9f8c8f7b --- /dev/null +++ b/scripts/automation/trex_control_plane/doc/packet_generator/export_format.yaml @@ -0,0 +1,47 @@ +#################################################### +#### TRex packet export format #### +#################################################### + +# PACKET REP - OPTION #1 +packet: + is_pcap : YES/NO # <1> + binary : [] # <2> + pcap : path/to/pcap/file.pcap # <3> + meta : any metadata wished to # <4> + +# PACKET REP - OPTION #2 +packet: + data : [] / path/to/pcap/file.pcap # <5> + meta : any metadata wished to # <4> + +vm: # <6> + - vm instruction #1 + - vm instruction #2 + ... + - vm instruction #N + + +################################### +#### Comments #### +################################### +# +# <1>: is_pcap is a boolean field that indicates if packet is transferred by pcap referencs +# ('YES') or binary representation ('NO'). +# +# <2>: binary field encodes the packet in binary representation. in a sequence (array) data. +# Each array item is an integer ranging 0-255. +# **LEAVE BLANK IF USING PCAP REFERENCE** +# +# <3>: path to the linked pcap file. Make sure to provide path with reading credentials. +# **LEAVE BLANK IF USING BINARY REP FOR THE PACKET** +# +# <4>: meta data is any JSON formatted data ment to be passed on. +# +# <5>: data field can be both binary representation or pcap file refernce, +# without the need for user's explicit typing. +# The application logic differs between the cases by the object type +# (array/string ending in '.pcap') +# Less configuration, little more confusing, LESS similar to RPC spec +# +# <6>: vm instructions passed in array representation (sequence). +# Each instruction is deifned according to the structures of the supported VM instructions. \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/doc/requirements.rst b/scripts/automation/trex_control_plane/doc/requirements.rst deleted file mode 100755 index e69de29b..00000000 diff --git a/scripts/automation/trex_control_plane/examples/client_interactive_example.py b/scripts/automation/trex_control_plane/examples/client_interactive_example.py index 5a3ebf8a..9ee28898 100755 --- a/scripts/automation/trex_control_plane/examples/client_interactive_example.py +++ b/scripts/automation/trex_control_plane/examples/client_interactive_example.py @@ -74,7 +74,7 @@ class InteractiveTRexClient(cmd.Cmd): print termstyle.green("*** End of TRex status prompt ***") def do_show_trex_files_path (self, line): - """Prompts the local path in which files are stored when pushed to TRex server from client""" + """Prompts the local path in which files are stored when pushed to t-rex server from client""" print self.trex.get_trex_files_path() print termstyle.green("*** End of trex_files_path prompt ***") diff --git a/scripts/trex-cfg b/scripts/trex-cfg index ca442d15..2aebf026 100755 --- a/scripts/trex-cfg +++ b/scripts/trex-cfg @@ -30,15 +30,6 @@ for file in /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepag fi done -MACHINE_TYPE=`uname -m` - -if [ ${MACHINE_TYPE} != 'x86_64' ]; then - echo "ERROR You have a 32bit Kernel try to install 64bit Kernel" - exit 1 -fi - - - if ! lsmod | grep -q igb_uio ; then echo "Load the drivers for the first time " modprobe uio -- cgit 1.2.3-korg From a9ead5815d40dfe42651f6ff2140c94535b6a703 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Mon, 12 Oct 2015 09:13:16 +0300 Subject: solving conflicts --- scripts/automation/trex_control_plane/doc/index.rst | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/doc/index.rst b/scripts/automation/trex_control_plane/doc/index.rst index 10803cb0..62fd9975 100755 --- a/scripts/automation/trex_control_plane/doc/index.rst +++ b/scripts/automation/trex_control_plane/doc/index.rst @@ -18,13 +18,6 @@ To understand the entirely how the API works and how to set up the server side, **Use the table of contents below or the menu to your left to navigate through the site** -Getting Started -=============== -.. toctree:: - :maxdepth: 2 - - installation - API Reference ============= .. toctree:: @@ -46,13 +39,6 @@ Usage Examples usage_examples -About TRex -========== -.. toctree:: - :maxdepth: 2 - - All about TRex - Indices and tables ================== -- cgit 1.2.3-korg From 7482f09b8a5e8945e8b735233ad8f1674e637aef Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Mon, 12 Oct 2015 09:53:23 +0300 Subject: cosmetics --- scripts/automation/trex_control_plane/client_utils/packet_builder.py | 4 ++-- scripts/automation/trex_control_plane/server/trex_server.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/packet_builder.py b/scripts/automation/trex_control_plane/client_utils/packet_builder.py index 1c643335..c687126b 100755 --- a/scripts/automation/trex_control_plane/client_utils/packet_builder.py +++ b/scripts/automation/trex_control_plane/client_utils/packet_builder.py @@ -1055,8 +1055,8 @@ class CTRexPktBuilder(object): def __init__(self, name, layer_type, ok_type, message=''): self._default_message = "The type of packet layer {layer_name} is of type {layer_type}, " \ "and not of the expected {allowed_type}.".format(layer_name=name, - layer_type=layer_type, - allowed_type=ok_type.__name__) + layer_type=layer_type, + allowed_type=ok_type.__name__) self.message = message or self._default_message super(CTRexPktBuilder.PacketLayerTypeError, self).__init__(-13, self.message) diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 1e5098fb..fd39b9c4 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -318,7 +318,7 @@ class CTRexServer(object): io = iom, export = export_path ) - logger.info("T-REX FULL COMMAND: {command}".format(command = cmd) ) + logger.info("TREX FULL COMMAND: {command}".format(command = cmd) ) return (cmd, export_path, long(d)) -- cgit 1.2.3-korg From b18e8dc6f2aba20767304334380a9b1561379541 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 13 Oct 2015 10:31:16 +0300 Subject: Another Typo fix T-Rex -> TRex --- scripts/automation/readme.txt | 4 ++-- scripts/automation/report_template.html | 2 +- .../trex_control_plane/client/trex_adv_client.py | 2 +- .../trex_control_plane/console/trex_console.py | 4 ++-- .../examples/client_interactive_example.py | 2 +- .../examples/interactive_stateless.py | 14 ++++++------- .../trex_control_plane/server/trex_server.py | 2 +- .../unit_tests/control_plane_general_test.py | 2 +- .../unit_tests/control_plane_unit_test.py | 2 +- .../unit_tests/functional_test.py | 24 +++++++++++----------- scripts/automation/trex_perf.py | 8 ++++---- 11 files changed, 33 insertions(+), 33 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/readme.txt b/scripts/automation/readme.txt index 2541a1a3..152eee16 100755 --- a/scripts/automation/readme.txt +++ b/scripts/automation/readme.txt @@ -1,7 +1,7 @@ README - trex_perf.py ===================== -This script uses the T-Rex RESTfull client-server conrtol plane achitecture and tries to find the maximum M (platform factor) for trex before hitting one of two stopping conditions: +This script uses the TRex RESTfull client-server conrtol plane achitecture and tries to find the maximum M (platform factor) for trex before hitting one of two stopping conditions: (*) Packet drops (*) High latency. Since high latency can change from one platform to another, and might suffer from kickoff peak (espicially at VM), it is the user responsibility to provide the latency condition. @@ -9,7 +9,7 @@ This script uses the T-Rex RESTfull client-server conrtol plane achitecture and please note that '-f' and '-c' options are mandatory. -Also, this is the user's responsibility to make sure a T-Rex is running, listening to relevant client request coming from this script. +Also, this is the user's responsibility to make sure a TRex is running, listening to relevant client request coming from this script. example for finding max M (between 10 to 100) with imix_fast_1g.yaml traffic profile: ./trex_perf.py -m 10 100 -c config/trex-hhaim.cfg all drop -f cap2/imix_fast_1g.yaml diff --git a/scripts/automation/report_template.html b/scripts/automation/report_template.html index 779d5429..ccd5388d 100755 --- a/scripts/automation/report_template.html +++ b/scripts/automation/report_template.html @@ -76,7 +76,7 @@ vertical-align:top;

-T-Rex Performance Report +TRex Performance Report

diff --git a/scripts/automation/trex_control_plane/client/trex_adv_client.py b/scripts/automation/trex_control_plane/client/trex_adv_client.py index b3fe3dad..bf7ccf58 100755 --- a/scripts/automation/trex_control_plane/client/trex_adv_client.py +++ b/scripts/automation/trex_control_plane/client/trex_adv_client.py @@ -8,7 +8,7 @@ class CTRexAdvClient(trex_client.CTRexClient): super(CTRexAdvClient, self).__init__(trex_host, max_history_size, trex_daemon_port, trex_zmq_port, verbose) pass - # T-REX KIWI advanced methods + # TRex KIWI advanced methods def start_quick_trex(self, pcap_file, d, delay, dual, ipv6, times, interfaces): try: return self.server.start_quick_trex(pcap_file = pcap_file, duration = d, dual = dual, delay = delay, ipv6 = ipv6, times = times, interfaces = interfaces) diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 3aeab901..9478db5a 100644 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -326,11 +326,11 @@ class TrexConsole(cmd.Cmd): def setParserOptions (): parser = argparse.ArgumentParser(prog="trex_console.py") - parser.add_argument("-s", "--server", help = "T-Rex Server [default is localhost]", + parser.add_argument("-s", "--server", help = "TRex Server [default is localhost]", default = "localhost", type = str) - parser.add_argument("-p", "--port", help = "T-Rex Server Port [default is 5050]\n", + parser.add_argument("-p", "--port", help = "TRex Server Port [default is 5050]\n", default = 5050, type = int) diff --git a/scripts/automation/trex_control_plane/examples/client_interactive_example.py b/scripts/automation/trex_control_plane/examples/client_interactive_example.py index 9ee28898..d21b2b15 100755 --- a/scripts/automation/trex_control_plane/examples/client_interactive_example.py +++ b/scripts/automation/trex_control_plane/examples/client_interactive_example.py @@ -74,7 +74,7 @@ class InteractiveTRexClient(cmd.Cmd): print termstyle.green("*** End of TRex status prompt ***") def do_show_trex_files_path (self, line): - """Prompts the local path in which files are stored when pushed to t-rex server from client""" + """Prompts the local path in which files are stored when pushed to trex server from client""" print self.trex.get_trex_files_path() print termstyle.green("*** End of trex_files_path prompt ***") diff --git a/scripts/automation/trex_control_plane/examples/interactive_stateless.py b/scripts/automation/trex_control_plane/examples/interactive_stateless.py index 7c25b4ef..e64b4755 100644 --- a/scripts/automation/trex_control_plane/examples/interactive_stateless.py +++ b/scripts/automation/trex_control_plane/examples/interactive_stateless.py @@ -76,18 +76,18 @@ class InteractiveStatelessTRex(cmd.Cmd): def do_push_files(self, filepaths): - """Pushes a custom file to be stored locally on T-Rex server.\ + """Pushes a custom file to be stored locally on TRex server.\ \nPush multiple files by specifying their path separated by ' ' (space).""" try: filepaths = filepaths.split(' ') - print termstyle.green("*** Starting pushing files ({trex_files}) to T-Rex. ***".format( + print termstyle.green("*** Starting pushing files ({trex_files}) to TRex. ***".format( trex_files=', '.join(filepaths)) ) ret_val = self.trex.push_files(filepaths) if ret_val: - print termstyle.green("*** End of T-Rex push_files method (success) ***") + print termstyle.green("*** End of TRex push_files method (success) ***") else: - print termstyle.magenta("*** End of T-Rex push_files method (failed) ***") + print termstyle.magenta("*** End of TRex push_files method (failed) ***") except IOError as inst: print termstyle.magenta(inst) @@ -99,10 +99,10 @@ if __name__ == "__main__": parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0 \t (C) Cisco Systems Inc.\n') parser.add_argument("-t", "--trex-host", required = True, dest="trex_host", - action="store", help="Specify the hostname or ip to connect with T-Rex server.", + action="store", help="Specify the hostname or ip to connect with TRex server.", metavar="HOST" ) parser.add_argument("-p", "--trex-port", type=int, default = 5050, metavar="PORT", dest="trex_port", - help="Select port on which the T-Rex server listens. Default port is 5050.", action="store") + help="Select port on which the TRex server listens. Default port is 5050.", action="store") # parser.add_argument("-m", "--maxhist", type=int, default = 100, metavar="SIZE", dest="hist_size", # help="Specify maximum history size saved at client side. Default size is 100.", action="store") parser.add_argument("--virtual", dest="virtual", @@ -124,5 +124,5 @@ if __name__ == "__main__": except socket.error, e: if e.errno == errno.ECONNREFUSED: raise socket.error(errno.ECONNREFUSED, - "Connection from T-Rex server was terminated. \ + "Connection from TRex server was terminated. \ Please make sure the server is up.") diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 1e5098fb..e667dbf2 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -318,7 +318,7 @@ class CTRexServer(object): io = iom, export = export_path ) - logger.info("T-REX FULL COMMAND: {command}".format(command = cmd) ) + logger.info("TRex FULL COMMAND: {command}".format(command = cmd) ) return (cmd, export_path, long(d)) diff --git a/scripts/automation/trex_control_plane/unit_tests/control_plane_general_test.py b/scripts/automation/trex_control_plane/unit_tests/control_plane_general_test.py index 95f259b8..32ad5243 100755 --- a/scripts/automation/trex_control_plane/unit_tests/control_plane_general_test.py +++ b/scripts/automation/trex_control_plane/unit_tests/control_plane_general_test.py @@ -9,7 +9,7 @@ Name: Description: - This script creates the functionality to test the performance of the T-Rex traffic generator control plane. + This script creates the functionality to test the performance of the TRex traffic generator control plane. The scenarios assumes a WORKING server is listening and processing the requests. :: diff --git a/scripts/automation/trex_control_plane/unit_tests/control_plane_unit_test.py b/scripts/automation/trex_control_plane/unit_tests/control_plane_unit_test.py index 37130ee4..1120256c 100755 --- a/scripts/automation/trex_control_plane/unit_tests/control_plane_unit_test.py +++ b/scripts/automation/trex_control_plane/unit_tests/control_plane_unit_test.py @@ -18,7 +18,7 @@ class TRexCPConfiguringPlugin(Plugin): super(TRexCPConfiguringPlugin, self).options(parser, env) parser.add_option('-t', '--trex-server', action='store', dest='trex_server', default='trex-dan', - help='Specify T-Rex server hostname. This server will be used to test control-plane functionality.') + help='Specify TRex server hostname. This server will be used to test control-plane functionality.') def configure(self, options, conf): if options.trex_server: diff --git a/scripts/automation/trex_control_plane/unit_tests/functional_test.py b/scripts/automation/trex_control_plane/unit_tests/functional_test.py index f742403d..30836985 100755 --- a/scripts/automation/trex_control_plane/unit_tests/functional_test.py +++ b/scripts/automation/trex_control_plane/unit_tests/functional_test.py @@ -37,7 +37,7 @@ class CTRexStartStop_Test(CControlPlaneGeneral_Test): def test_parameter_name_error(self): ret = self.trex.start_trex( c = 4, - wrong_key = 1.1, # <----- This key does not exists in T-Rex API + wrong_key = 1.1, # <----- This key does not exists in TRex API d = 70, f = 'avl/sfr_delay_10_1g.yaml', nc = True, @@ -50,7 +50,7 @@ class CTRexStartStop_Test(CControlPlaneGeneral_Test): run_status = self.trex.get_running_status() assert isinstance(run_status, dict) assert_equal (run_status['state'], TRexStatus.Idle ) - assert_equal (run_status['verbose'], "T-Rex run failed due to wrong input parameters, or due to reachability issues.") + assert_equal (run_status['verbose'], "TRex run failed due to wrong input parameters, or due to reachability issues.") assert_raises(TRexError, self.trex.get_running_info) def test_too_early_sample(self): @@ -83,33 +83,33 @@ class CTRexStartStop_Test(CControlPlaneGeneral_Test): assert self.trex.is_running() == False def test_start_more_than_once_same_user(self): - assert self.trex.is_running() == False # first, make sure T-Rex is not running - ret = self.trex.start_trex(**self.valid_start_params) # start 1st T-Rex run + assert self.trex.is_running() == False # first, make sure TRex is not running + ret = self.trex.start_trex(**self.valid_start_params) # start 1st TRex run assert ret == True # make sure 1st run submitted successfuly # time.sleep(1) - assert_raises(TRexInUseError, self.trex.start_trex, **self.valid_start_params) # try to start T-Rex again + assert_raises(TRexInUseError, self.trex.start_trex, **self.valid_start_params) # try to start TRex again ret = self.trex.stop_trex() assert ret==True # make sure stop succeeded assert self.trex.is_running() == False def test_start_more_than_once_different_users(self): - assert self.trex.is_running() == False # first, make sure T-Rex is not running - ret = self.trex.start_trex(**self.valid_start_params) # start 1st T-Rex run + assert self.trex.is_running() == False # first, make sure TRex is not running + ret = self.trex.start_trex(**self.valid_start_params) # start 1st TRex run assert ret == True # make sure 1st run submitted successfuly # time.sleep(1) tmp_trex = CTRexClient(self.trex_server_name) # initialize another client connecting same server - assert_raises(TRexInUseError, tmp_trex.start_trex, **self.valid_start_params) # try to start T-Rex again + assert_raises(TRexInUseError, tmp_trex.start_trex, **self.valid_start_params) # try to start TRex again ret = self.trex.stop_trex() assert ret==True # make sure stop succeeded assert self.trex.is_running() == False def test_simultaneous_sampling(self): - assert self.trex.is_running() == False # first, make sure T-Rex is not running + assert self.trex.is_running() == False # first, make sure TRex is not running tmp_trex = CTRexClient(self.trex_server_name) # initialize another client connecting same server - ret = self.trex.start_trex(**self.valid_start_params) # start T-Rex run + ret = self.trex.start_trex(**self.valid_start_params) # start TRex run assert ret == True # make sure 1st run submitted successfuly time.sleep(6) @@ -123,7 +123,7 @@ class CTRexStartStop_Test(CControlPlaneGeneral_Test): assert tmp_trex.get_result_obj().is_valid_hist() == True if self.trex.get_result_obj().is_done_warmup(): assert tmp_trex.get_result_obj().is_done_warmup() == True - # except TRexError as inst: # T-Rex might have stopped between is_running result and get_running_info() call + # except TRexError as inst: # TRex might have stopped between is_running result and get_running_info() call # # hence, ingore that case # break @@ -132,7 +132,7 @@ class CTRexStartStop_Test(CControlPlaneGeneral_Test): def test_fast_toggling(self): assert self.trex.is_running() == False for i in range(20): - ret = self.trex.start_trex(**self.valid_start_params) # start T-Rex run + ret = self.trex.start_trex(**self.valid_start_params) # start TRex run assert ret == True assert self.trex.is_running() == False # we expect the status to be 'Starting' ret = self.trex.stop_trex() diff --git a/scripts/automation/trex_perf.py b/scripts/automation/trex_perf.py index 5d11f549..314a2318 100755 --- a/scripts/automation/trex_perf.py +++ b/scripts/automation/trex_perf.py @@ -950,7 +950,7 @@ def generate_job_id (): return (str(int(random.getrandbits(32)))) def print_header (): - logger.log("--== T-Trex Performance Tool v1.0 (2014) ==--") + logger.log("--== TTrex Performance Tool v1.0 (2014) ==--") # print startup summary def log_startup_summary (job_summary): @@ -960,10 +960,10 @@ def log_startup_summary (job_summary): logger.log("\nWork Request Details:\n") logger.log("Setup Details:\n") - logger.log("T-Rex Config File: {0}".format(job_summary['config_file'])) + logger.log("TRex Config File: {0}".format(job_summary['config_file'])) logger.log("Machine Name: {0}".format(trex_config['trex_name'])) - logger.log("T-Rex Type: {0}".format(trex_config['trex_machine_type'])) - logger.log("T-Rex Dual Int. Tx: {0}".format(trex_config['trex_is_dual'])) + logger.log("TRex Type: {0}".format(trex_config['trex_machine_type'])) + logger.log("TRex Dual Int. Tx: {0}".format(trex_config['trex_is_dual'])) logger.log("Router Interface: {0}".format(trex_config['router_interface'])) logger.log("\nJob Details:\n") -- cgit 1.2.3-korg From 2dd1a4d85c559ddafe695b6d6d393ee086e1a3de Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Wed, 14 Oct 2015 06:38:37 +0300 Subject: merged jsonrpc client for mock compatibility --- .../client_utils/jsonrpc_client.py | 270 +++++++++++++++++++-- 1 file changed, 255 insertions(+), 15 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py index 163c6923..8c8987b6 100755 --- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py @@ -6,9 +6,6 @@ import json import general_utils import re from time import sleep -from collections import namedtuple - -CmdResponse = namedtuple('CmdResponse', ['success', 'data']) class bcolors: BLUE = '\033[94m' @@ -26,12 +23,12 @@ class BatchMessage(object): self.rpc_client = rpc_client self.batch_list = [] - def add (self, method_name, params={}): + def add (self, method_name, params = {}): id, msg = self.rpc_client.create_jsonrpc_v2(method_name, params, encode = False) self.batch_list.append(msg) - def invoke(self, block = False): + def invoke (self, block = False): if not self.rpc_client.connected: return False, "Not connected to server" @@ -39,9 +36,9 @@ class BatchMessage(object): rc, resp_list = self.rpc_client.send_raw_msg(msg, block = False) if len(self.batch_list) == 1: - return CmdResponse(True, [CmdResponse(rc, resp_list)]) + return True, [(rc, resp_list)] else: - return CmdResponse(rc, resp_list) + return rc, resp_list # JSON RPC v2.0 client @@ -130,7 +127,7 @@ class JsonRpcClient(object): self.socket.send(msg, flags = zmq.NOBLOCK) except zmq.error.ZMQError as e: self.disconnect() - return CmdResponse(False, "Failed To Get Send Message") + return False, "Failed To Get Send Message" got_response = False @@ -148,7 +145,7 @@ class JsonRpcClient(object): if not got_response: self.disconnect() - return CmdResponse(False, "Failed To Get Server Response") + return False, "Failed To Get Server Response" self.verbose_msg("Server Response:\n\n" + self.pretty_json(response) + "\n") @@ -162,19 +159,19 @@ class JsonRpcClient(object): for single_response in response_json: rc, msg = self.process_single_response(single_response) - rc_list.append( CmdResponse(rc, msg) ) + rc_list.append( (rc, msg) ) - return CmdResponse(True, rc_list) + return True, rc_list else: rc, msg = self.process_single_response(response_json) - return CmdResponse(rc, msg) + return rc, msg def process_single_response (self, response_json): if (response_json.get("jsonrpc") != "2.0"): - return False, "Malformed Response ({0})".format(str(response)) + return False, "Malfromed Response ({0})".format(str(response)) # error reported by server if ("error" in response_json): @@ -185,7 +182,7 @@ class JsonRpcClient(object): # if no error there should be a result if ("result" not in response_json): - return False, "Malformed Response ({0})".format(str(response)) + return False, "Malfromed Response ({0})".format(str(response)) return True, response_json["result"] @@ -194,7 +191,7 @@ class JsonRpcClient(object): def set_verbose(self, mode): self.verbose = mode - def disconnect(self): + def disconnect (self): if self.connected: self.socket.close(linger = 0) self.context.destroy(linger = 0) @@ -247,3 +244,246 @@ class JsonRpcClient(object): print "Shutting down RPC client\n" if hasattr(self, "context"): self.context.destroy(linger=0) + +# MOVE THIS TO DAN'S FILE +class TrexStatelessClient(JsonRpcClient): + + def __init__ (self, server, port, user): + + super(TrexStatelessClient, self).__init__(server, port) + + self.user = user + self.port_handlers = {} + + self.supported_cmds = [] + self.system_info = None + self.server_version = None + + + def whoami (self): + return self.user + + def ping_rpc_server(self): + + return self.invoke_rpc_method("ping", block = False) + + def get_rpc_server_version (self): + return self.server_version + + def get_system_info (self): + if not self.system_info: + return {} + + return self.system_info + + def get_supported_cmds(self): + if not self.supported_cmds: + return {} + + return self.supported_cmds + + def get_port_count (self): + if not self.system_info: + return 0 + + return self.system_info["port_count"] + + # sync the client with all the server required data + def sync (self): + + # get server version + rc, msg = self.invoke_rpc_method("get_version") + if not rc: + self.disconnect() + return rc, msg + + self.server_version = msg + + # get supported commands + rc, msg = self.invoke_rpc_method("get_supported_cmds") + if not rc: + self.disconnect() + return rc, msg + + self.supported_cmds = [str(x) for x in msg if x] + + # get system info + rc, msg = self.invoke_rpc_method("get_system_info") + if not rc: + self.disconnect() + return rc, msg + + self.system_info = msg + + return True, "" + + def connect (self): + rc, err = super(TrexStatelessClient, self).connect() + if not rc: + return rc, err + + return self.sync() + + + # take ownership over ports + def take_ownership (self, port_id_array, force = False): + if not self.connected: + return False, "Not connected to server" + + batch = self.create_batch() + + for port_id in port_id_array: + batch.add("acquire", params = {"port_id":port_id, "user":self.user, "force":force}) + + rc, resp_list = batch.invoke() + if not rc: + return rc, resp_list + + for i, rc in enumerate(resp_list): + if rc[0]: + self.port_handlers[port_id_array[i]] = rc[1] + + return True, resp_list + + + def release_ports (self, port_id_array): + batch = self.create_batch() + + for port_id in port_id_array: + + # let the server handle un-acquired errors + if self.port_handlers.get(port_id): + handler = self.port_handlers[port_id] + else: + handler = "" + + batch.add("release", params = {"port_id":port_id, "handler":handler}) + + + rc, resp_list = batch.invoke() + if not rc: + return rc, resp_list + + for i, rc in enumerate(resp_list): + if rc[0]: + self.port_handlers.pop(port_id_array[i]) + + return True, resp_list + + def get_owned_ports (self): + return self.port_handlers.keys() + + # fetch port stats + def get_port_stats (self, port_id_array): + if not self.connected: + return False, "Not connected to server" + + batch = self.create_batch() + + # empty list means all + if port_id_array == []: + port_id_array = list([x for x in xrange(0, self.system_info["port_count"])]) + + for port_id in port_id_array: + + # let the server handle un-acquired errors + if self.port_handlers.get(port_id): + handler = self.port_handlers[port_id] + else: + handler = "" + + batch.add("get_port_stats", params = {"port_id":port_id, "handler":handler}) + + + rc, resp_list = batch.invoke() + + return rc, resp_list + + # snapshot will take a snapshot of all your owned ports for streams and etc. + def snapshot(self): + + + if len(self.get_owned_ports()) == 0: + return {} + + snap = {} + + batch = self.create_batch() + + for port_id in self.get_owned_ports(): + + batch.add("get_port_stats", params = {"port_id": port_id, "handler": self.port_handlers[port_id]}) + batch.add("get_stream_list", params = {"port_id": port_id, "handler": self.port_handlers[port_id]}) + + rc, resp_list = batch.invoke() + if not rc: + return rc, resp_list + + # split the list to 2s + index = 0 + for port_id in self.get_owned_ports(): + if not resp_list[index] or not resp_list[index + 1]: + snap[port_id] = None + continue + + # fetch the first two + stats = resp_list[index][1] + stream_list = resp_list[index + 1][1] + + port = {} + port['status'] = stats['status'] + port['stream_list'] = [] + + # get all the streams + if len(stream_list) > 0: + batch = self.create_batch() + for stream_id in stream_list: + batch.add("get_stream", params = {"port_id": port_id, "stream_id": stream_id, "handler": self.port_handlers[port_id]}) + + rc, stream_resp_list = batch.invoke() + if not rc: + port = {} + + port['streams'] = {} + for i, resp in enumerate(stream_resp_list): + if resp[0]: + port['streams'][stream_list[i]] = resp[1] + + snap[port_id] = port + + # move to next one + index += 2 + + + return snap + + # add stream + def add_stream (self, port_id, stream_id, isg, next_stream_id, packet): + if not port_id in self.get_owned_ports(): + return False, "Port {0} is not owned... please take ownership before adding streams".format(port_id) + + handler = self.port_handlers[port_id] + + stream = {} + stream['enabled'] = True + stream['self_start'] = True + stream['isg'] = isg + stream['next_stream_id'] = next_stream_id + stream['packet'] = {} + stream['packet']['binary'] = packet + stream['packet']['meta'] = "" + stream['vm'] = [] + stream['rx_stats'] = {} + stream['rx_stats']['enabled'] = False + + stream['mode'] = {} + stream['mode']['type'] = 'continuous' + stream['mode']['pps'] = 10.0 + + params = {} + params['handler'] = handler + params['stream'] = stream + params['port_id'] = port_id + params['stream_id'] = stream_id + + return self.invoke_rpc_method('add_stream', params = params) -- cgit 1.2.3-korg From 0c5a4348a31e0e8d76dd1fcf378cb2c0a2867f59 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 15 Oct 2015 09:57:35 +0300 Subject: updated yaml utils and stream object --- .../client_utils/external_packages.py | 3 +- .../trex_control_plane/client_utils/yaml_utils.py | 118 +++++++++++++ .../trex_control_plane/common/external_packages.py | 28 +++ .../trex_control_plane/common/rpc_defaults.yaml | 107 ++++++++++++ .../trex_control_plane/common/trex_status.py | 8 + .../trex_control_plane/common/trex_streams.py | 190 +++++++++++++++++++++ 6 files changed, 453 insertions(+), 1 deletion(-) create mode 100644 scripts/automation/trex_control_plane/client_utils/yaml_utils.py create mode 100755 scripts/automation/trex_control_plane/common/external_packages.py create mode 100644 scripts/automation/trex_control_plane/common/rpc_defaults.yaml create mode 100644 scripts/automation/trex_control_plane/common/trex_status.py create mode 100644 scripts/automation/trex_control_plane/common/trex_streams.py (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/external_packages.py b/scripts/automation/trex_control_plane/client_utils/external_packages.py index 4b10609b..e2bb37a5 100755 --- a/scripts/automation/trex_control_plane/client_utils/external_packages.py +++ b/scripts/automation/trex_control_plane/client_utils/external_packages.py @@ -8,7 +8,8 @@ ROOT_PATH = os.path.abspath(os.path.join(CURRENT_PATH, os.pardir)) PATH_TO_PYTHON_LIB = os.path.abspath(os.path.join(ROOT_PATH, os.pardir, os.pardir, 'external_libs')) CLIENT_UTILS_MODULES = ['zmq', - 'dpkt-1.8.6' + 'dpkt-1.8.6', + 'PyYAML-3.01/lib' ] def import_client_utils_modules(): diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py new file mode 100644 index 00000000..f04449ac --- /dev/null +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -0,0 +1,118 @@ + +''' +Dan Klein +Cisco Systems, Inc. + +Copyright (c) 2015-2015 Cisco Systems, Inc. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + +import external_packages +import yaml + +def yaml_obj_validator(evaluated_obj, yaml_reference_file_path, root_obj, fill_defaults=True): + """ + validate SINGLE ROOT object with yaml reference file. + Fills up default values if hasn't been assigned by user and available. + + :param evaluated_obj: python object that should match the yaml reference file + :param yaml_reference_file_path: + :param fill_defaults: + :return: a python representation object of the YAML file if OK + """ + type_dict = {"double":float, + "int":int, + "array":list, + "string":str, + "boolean":bool} + + def validator_rec_helper(obj_to_eval, ref_obj, root_key): + ref_item = ref_obj.get(root_key) + if ref_item is not None: + if "type" in obj_to_eval: + ref_item = ref_item[obj_to_eval.get("type")] + if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal + result_obj = {} + # iterate over key-value pairs + for k, v in ref_item.items(): + if k in obj_to_eval: + # need to validate with ref obj + tmp_type = v.get('type') + if tmp_type == "object": + # go deeper into nesting hierarchy + result_obj[k] = validator_rec_helper(obj_to_eval.get(k), ref_obj, k) + elif isinstance(tmp_type, list): + # item can be one of multiple types + python_types = set() + for t in tmp_type: + if t in type_dict: + python_types.add(type_dict.get(t)) + else: + raise TypeError("Unknown resolving for type {0}".format(t)) + if type(obj_to_eval[k]) not in python_types: + raise TypeError("Type of object field '{0}' is not allowed".format(k)) + + else: + # this is a single type field + python_type = type_dict.get(tmp_type) + if not isinstance(obj_to_eval[k], python_type): + raise TypeError("Type of object field '{0}' is not allowed".format(k)) + else: + # WE'RE OK! + result_obj[k] = obj_to_eval[k] + else: + # this is an object field that wasn't specified by the user + if v.get('has_default'): + # WE'RE OK! + result_obj[k] = v.get('default') + else: + # This is a mandatory field! + raise ValueError("The {0} field is mandatory and must be specified explicitly".format(v)) + return result_obj + elif isinstance(ref_item, list): + return [] + else: + + + + else: + raise KeyError("The given key is not ") + + + + + pass + pass + elif isinstance(obj_to_eval, list): + # iterate as list sequence + pass + else: + # evaluate as single item + pass + pass + + try: + yaml_ref = yaml.load(file(yaml_reference_file_path, 'r')) + result = validator_rec_helper(evaluated_obj, yaml_ref, root_obj) + + except yaml.YAMLError as e: + raise + except Exception: + raise + +def yaml_loader(file_path): + pass + +def yaml_exporter(file_path): + pass + +if __name__ == "__main__": + pass diff --git a/scripts/automation/trex_control_plane/common/external_packages.py b/scripts/automation/trex_control_plane/common/external_packages.py new file mode 100755 index 00000000..62121d4f --- /dev/null +++ b/scripts/automation/trex_control_plane/common/external_packages.py @@ -0,0 +1,28 @@ +#!/router/bin/python + +import sys +import os + +CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) +ROOT_PATH = os.path.abspath(os.path.join(CURRENT_PATH, os.pardir)) # path to trex_control_plane directory +PATH_TO_PYTHON_LIB = os.path.abspath(os.path.join(ROOT_PATH, os.pardir, os.pardir, 'external_libs')) + +CLIENT_UTILS_MODULES = ['PyYAML-3.01/lib' + ] + +def import_common_modules(): + # must be in a higher priority + sys.path.insert(0, PATH_TO_PYTHON_LIB) + sys.path.append(ROOT_PATH) + import_module_list(CLIENT_UTILS_MODULES) + + +def import_module_list(modules_list): + assert(isinstance(modules_list, list)) + for p in modules_list: + full_path = os.path.join(PATH_TO_PYTHON_LIB, p) + fix_path = os.path.normcase(full_path) + sys.path.insert(1, full_path) + +import_common_modules() + diff --git a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml new file mode 100644 index 00000000..fbaca40e --- /dev/null +++ b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml @@ -0,0 +1,107 @@ +############################################################## +#### TRex RPC stream list default values #### +############################################################## + +# this document is based on TRex RPC server spec and its fields: +# http://trex-tgn.cisco.com/trex/doc/trex_rpc_server_spec.html + +### HOW TO READ THIS FILE +# 1. Each key represents an object type +# 2. Each value can be either a value field or another object +# 2.1. If a value field, read as: +# + type: type of field +# + has_default: if the value has any default +# + default: the default value (Only appears if has_default field is 'YES') +# 2.2. If an object type, jump to correspoding object key. +# 3. If an object has more than one instance type, another layer with the type shall be added. +# For example, 'mode' object has 3 types: 'continuous', 'single_burst', 'multi_burst' +# So, 3 mode objects will be defined, named: +# - mode['continuous'] +# - mode['single_burst'] +# - mode['multi_burst'] +# In this case, there's no default for the 'type' field on the object +# 4. Some values has 'multiplier' property attached. +# In such case, the loaded value will be multiplied by the multiplier +# For example, if the mode's 'pps' field value is 10, and its multiplier is 5, +# the loaded pps value will be 10*5=50 + + +stream: + enabled: + type: boolean + has_default: YES + default: True + self_start: + type: boolean + has_default: YES + default: True + isg: + type: double + has_default: YES + default: 0.0 + next_stream_id: + type: [int, string] # string to allow naming binding + has_default: YES + default: -1 # no next streams + packet: + type: object + mode: + type: object + vm: + type: array + has_default: YES + default: [] # no ranging instructions + rx_stats: + type: object + +packet: + binary: + type: [array,string] + has_default: NO + meta: + type: string + has_default: YES + default: "" + +mode: + continuous: + pps: + type: double + has_default: NO + multiplier: 1.0 + single_burst: + pps: + type: int + has_default: NO + total_pkts: + type: int + has_default: NO + multiplier: 1.0 + multi_burst: + pps: + type: int + has_default: NO + pkts_per_burst: + type: int + has_default: NO + ibg: + type: double + has_default: YES + default: 100.0 + count: + type: int + has_default: YES + default: 0 # loop forever + multiplier: 1.0 + +rx_stats: + enabled: + type: boolean + has_default: YES + default: False + seq_enabled: + type: boolean + has_default: NO + latency_enabled: + type: boolean + has_default: NO \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/common/trex_status.py b/scripts/automation/trex_control_plane/common/trex_status.py new file mode 100644 index 00000000..f132720c --- /dev/null +++ b/scripts/automation/trex_control_plane/common/trex_status.py @@ -0,0 +1,8 @@ +#!/router/bin/python + +# define the states in which a T-Rex can hold during its lifetime +# TRexStatus = Enum('TRexStatus', 'Idle Starting Running') + +IDLE = 1 +STARTING = 2 +RUNNING = 3 diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py new file mode 100644 index 00000000..3b0e7376 --- /dev/null +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -0,0 +1,190 @@ +#!/router/bin/python + +import external_packages +from client_utils.packet_builder import CTRexPktBuilder +from collections import OrderedDict + + +class CStreamList(object): + + def __init__(self): + self.streams_list = OrderedDict() + self._stream_id = 0 + # self._stream_by_name = {} + + def append_stream(self, name, stream_obj): + assert isinstance(stream_obj, CStream) + if name in self.streams_list: + raise NameError("A stream with this name already exists on this list.") + self.streams_list[name]=stream_obj + return + + def remove_stream(self, name): + return self.streams_list.pop(name) + + def export_to_yaml(self, file_path): + pass + + def load_yaml(self, file_path): + # clear all existing streams linked to this object + self.streams_list.clear() + # self._stream_id = 0 + # load from YAML file the streams one by one + try: + with open(file_path, 'r') as f: + loaded_streams = yaml.load(f) + + # assume at this point that YAML file is according to rules and correct + + + except yaml.YAMLError as e: + print "Error in YAML configuration file:", e + print "Aborting YAML loading, no changes made to stream list" + return + + + pass + + + + +class CStream(object): + """docstring for CStream""" + DEFAULTS = {"rx_stats": CRxStats, + "mode": CTxMode, + "isg": 5.0, + "next_stream": -1, + "self_start": True, + "enabled": True} + + def __init__(self, **kwargs): + super(CStream, self).__init__() + for k, v in kwargs.items(): + setattr(self, k, v) + # set default values to unset attributes, according to DEFAULTS dict + set_keys = set(kwargs.keys()) + keys_to_set = [x + for x in self.DEFAULTS + if x not in set_keys] + for key in keys_to_set: + default = self.DEFAULTS.get(key) + if type(default) == type: + setattr(self, key, default()) + else: + setattr(self, key, default) + + @property + def packet(self): + return self._packet + + @packet.setter + def packet(self, packet_obj): + assert isinstance(packet_obj, CTRexPktBuilder) + self._packet = packet_obj + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, bool_value): + self._enabled = bool(bool_value) + + @property + def self_start(self): + return self._self_start + + @self_start.setter + def self_start(self, bool_value): + self._self_start = bool(bool_value) + + @property + def next_stream(self): + return self._next_stream + + @next_stream.setter + def next_stream(self, value): + self._next_stream = int(value) + + def dump(self): + pass + return {"enabled": self.enabled, + "self_start": self.self_start, + "isg": self.isg, + "next_stream": self.next_stream, + "packet": self.packet.dump_pkt(), + "mode": self.mode.dump(), + "vm": self.packet.get_vm_data(), + "rx_stats": self.rx_stats.dump()} + +class CRxStats(object): + + def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): + self._rx_dict = {"enabled": enabled, + "seq_enabled": seq_enabled, + "latency_enabled": latency_enabled} + + @property + def enabled(self): + return self._rx_dict.get("enabled") + + @enabled.setter + def enabled(self, bool_value): + self._rx_dict['enabled'] = bool(bool_value) + + @property + def seq_enabled(self): + return self._rx_dict.get("seq_enabled") + + @seq_enabled.setter + def seq_enabled(self, bool_value): + self._rx_dict['seq_enabled'] = bool(bool_value) + + @property + def latency_enabled(self): + return self._rx_dict.get("latency_enabled") + + @latency_enabled.setter + def latency_enabled(self, bool_value): + self._rx_dict['latency_enabled'] = bool(bool_value) + + def dump(self): + return {k: v + for k, v in self._rx_dict.items() + if v + } + + +class CTxMode(object): + """docstring for CTxMode""" + def __init__(self, tx_mode, pps): + super(CTxMode, self).__init__() + if tx_mode not in ["continuous", "single_burst", "multi_burst"]: + raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode)) + self._tx_mode = tx_mode + self._fields = {'pps': float(pps)} + if tx_mode == "single_burst": + self._fields['total_pkts'] = 0 + elif tx_mode == "multi_burst": + self._fields['pkts_per_burst'] = 0 + self._fields['ibg'] = 0.0 + self._fields['count'] = 0 + else: + pass + + def set_tx_mode_attr(self, attr, val): + if attr in self._fields: + self._fields[attr] = type(self._fields.get(attr))(val) + else: + raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')". + format(attr, self._tx_mode)) + + def dump(self): + dump = {"type": self._tx_mode} + dump.update({k: v + for k, v in self._fields.items() + }) + return dump + +if __name__ == "__main__": + pass -- cgit 1.2.3-korg From 7ada106ae824c12c2f831312f2af82ecf13c77da Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 15 Oct 2015 14:05:35 +0300 Subject: change console permission --- scripts/automation/trex_control_plane/console/trex_console.py | 0 scripts/automation/trex_control_plane/console/trex_root_path.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/console/trex_console.py mode change 100644 => 100755 scripts/automation/trex_control_plane/console/trex_root_path.py (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py old mode 100644 new mode 100755 diff --git a/scripts/automation/trex_control_plane/console/trex_root_path.py b/scripts/automation/trex_control_plane/console/trex_root_path.py old mode 100644 new mode 100755 -- cgit 1.2.3-korg From 2c38ad7f49fbddfdc75c150cbb2abdd54e3ede52 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Fri, 16 Oct 2015 15:37:46 +0300 Subject: Updated YAMLutils and rpc_defaults with relevant progress --- .../trex_control_plane/client_utils/yaml_utils.py | 291 +++++++++++++++------ .../trex_control_plane/common/rpc_defaults.yaml | 28 +- 2 files changed, 231 insertions(+), 88 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/client_utils/yaml_utils.py mode change 100644 => 100755 scripts/automation/trex_control_plane/common/rpc_defaults.yaml (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py old mode 100644 new mode 100755 index f04449ac..3ec3c9c8 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -1,5 +1,5 @@ -''' +""" Dan Klein Cisco Systems, Inc. @@ -13,100 +13,239 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -''' +""" import external_packages import yaml -def yaml_obj_validator(evaluated_obj, yaml_reference_file_path, root_obj, fill_defaults=True): - """ - validate SINGLE ROOT object with yaml reference file. - Fills up default values if hasn't been assigned by user and available. - - :param evaluated_obj: python object that should match the yaml reference file - :param yaml_reference_file_path: - :param fill_defaults: - :return: a python representation object of the YAML file if OK - """ - type_dict = {"double":float, + +class CTRexYAMLLoader(object): + TYPE_DICT = {"double":float, "int":int, "array":list, "string":str, "boolean":bool} - def validator_rec_helper(obj_to_eval, ref_obj, root_key): - ref_item = ref_obj.get(root_key) + def __init__(self, yaml_ref_file_path): + self.yaml_path = yaml_ref_file_path + self.ref_obj = None + + def load_reference(self): + try: + self.ref_obj = yaml.load(file(self.yaml_path, 'r')) + except yaml.YAMLError as e: + raise + except Exception as e: + raise + + def check_term_param_type(self, val, val_field, ref_val, multiplier): + print val, val_field, ref_val + tmp_type = ref_val.get('type') + if isinstance(tmp_type, list): + # item can be one of multiple types + print "multiple choice!" + python_types = set() + for t in tmp_type: + if t in self.TYPE_DICT: + python_types.add(self.TYPE_DICT.get(t)) + else: + return False, TypeError("Unknown resolving for type {0}".format(t)) + print "python legit types: ", python_types + if type(val) not in python_types: + return False, TypeError("Type of object field '{0}' is not allowed".format(val_field)) + else: + # WE'RE OK! + return True, CTRexYAMLLoader._calc_final_value(val, multiplier, ref_val.get('multiply', False)) + else: + # this is a single type field + python_type = self.TYPE_DICT.get(tmp_type) + if not isinstance(val, python_type): + return False, TypeError("Type of object field '{0}' is not allowed".format(val_field)) + else: + # WE'RE OK! + return True, CTRexYAMLLoader._calc_final_value(val, multiplier, ref_val.get('multiply', False)) + + def get_reference_default(self, root_obj, sub_obj, key): + print root_obj, sub_obj, key + if sub_obj: + ref_field = self.ref_obj.get(root_obj).get(sub_obj).get(key) + else: + ref_field = self.ref_obj.get(root_obj).get(key) + if 'has_default' in ref_field: + if ref_field.get('has_default'): + # WE'RE OK! + return True, ref_field.get('default') + else: + # This is a mandatory field! + return False, ValueError("The {0} field is mandatory and must be specified explicitly".format(key)) + else: + return False, ValueError("The {0} field has no indication about default value".format(key)) + + def validate_yaml(self, evaluated_obj, root_obj, fill_defaults=True, multiplier=1): + if isinstance(evaluated_obj, dict) and evaluated_obj.keys() == [root_obj]: + evaluated_obj = evaluated_obj.get(root_obj) + if not self.ref_obj: + self.load_reference() + ref_item = self.ref_obj.get(root_obj) if ref_item is not None: - if "type" in obj_to_eval: - ref_item = ref_item[obj_to_eval.get("type")] - if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal - result_obj = {} - # iterate over key-value pairs - for k, v in ref_item.items(): - if k in obj_to_eval: - # need to validate with ref obj - tmp_type = v.get('type') - if tmp_type == "object": - # go deeper into nesting hierarchy - result_obj[k] = validator_rec_helper(obj_to_eval.get(k), ref_obj, k) - elif isinstance(tmp_type, list): - # item can be one of multiple types - python_types = set() - for t in tmp_type: - if t in type_dict: - python_types.add(type_dict.get(t)) + try: + typed_obj = [False, None] # first item stores validity (multiple object "shapes"), second stored type + if "type" in evaluated_obj: + ref_item = ref_item[evaluated_obj.get("type")] + print "lower resolution with typed object" + typed_obj = [True, evaluated_obj.get("type")] + if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal + result_obj = {} + if typed_obj[0]: + result_obj["type"] = typed_obj[1] + print "processing dictionary non-terminal value" + for k, v in ref_item.items(): + print "processing element '{0}' with value '{1}'".format(k,v) + if k in evaluated_obj: + # validate with ref obj + print "found in evaluated object!" + tmp_type = v.get('type') + print tmp_type + print evaluated_obj + if tmp_type == "object": + # go deeper into nesting hierarchy + print "This is an object type, recursion!" + result_obj[k] = self.validate_yaml(evaluated_obj.get(k), k, fill_defaults, multiplier) + else: + # validation on terminal type + print "Validating terminal type %s" % k + res_ok, data = self.check_term_param_type(evaluated_obj.get(k), k, v, multiplier) + print "Validating: ", res_ok + if res_ok: + # data field contains the value to save + result_obj[k] = data else: - raise TypeError("Unknown resolving for type {0}".format(t)) - if type(obj_to_eval[k]) not in python_types: - raise TypeError("Type of object field '{0}' is not allowed".format(k)) - - else: - # this is a single type field - python_type = type_dict.get(tmp_type) - if not isinstance(obj_to_eval[k], python_type): - raise TypeError("Type of object field '{0}' is not allowed".format(k)) + # data var contains the exception to throw + raise data + elif fill_defaults: + # complete missing values with default value, if exists + sub_obj = typed_obj[1] if typed_obj[0] else None + res_ok, data = self.get_reference_default(root_obj, sub_obj, k) + if res_ok: + # data field contains the value to save + result_obj[k] = data else: - # WE'RE OK! - result_obj[k] = obj_to_eval[k] - else: - # this is an object field that wasn't specified by the user - if v.get('has_default'): - # WE'RE OK! - result_obj[k] = v.get('default') - else: - # This is a mandatory field! - raise ValueError("The {0} field is mandatory and must be specified explicitly".format(v)) - return result_obj - elif isinstance(ref_item, list): - return [] - else: + # data var contains the exception to throw + raise data + return result_obj + elif isinstance(ref_item, list): + # currently not handling list objects + return NotImplementedError("List object are currently unsupported") + else: + raise TypeError("Unknown parse tree object type.") + except KeyError as e: + raise + else: + raise KeyError("The given root_key '{key}' does not exists on reference object".format(key=root_obj)) + @staticmethod + def _calc_final_value(val, multiplier, multiply): + if multiply: + return (val * multiplier) + else: + return val - else: - raise KeyError("The given key is not ") - pass - pass - elif isinstance(obj_to_eval, list): - # iterate as list sequence - pass - else: - # evaluate as single item - pass - pass - - try: - yaml_ref = yaml.load(file(yaml_reference_file_path, 'r')) - result = validator_rec_helper(evaluated_obj, yaml_ref, root_obj) - - except yaml.YAMLError as e: - raise - except Exception: - raise +# +# def yaml_obj_validator(evaluated_obj, yaml_reference_file_path, root_obj, fill_defaults=True): +# """ +# validate SINGLE ROOT object with yaml reference file. +# Fills up default values if hasn't been assigned by user and available. +# +# :param evaluated_obj: python object that should match the yaml reference file +# :param yaml_reference_file_path: +# :param fill_defaults: +# :return: a python representation object of the YAML file if OK +# """ +# type_dict = {"double":float, +# "int":int, +# "array":list, +# "string":str, +# "boolean":bool} +# +# def validator_rec_helper(obj_to_eval, ref_obj, root_key): +# ref_item = ref_obj.get(root_key) +# if ref_item is not None: +# if "type" in obj_to_eval: +# ref_item = ref_item[obj_to_eval.get("type")] +# if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal +# result_obj = {} +# # iterate over key-value pairs +# for k, v in ref_item.items(): +# if k in obj_to_eval: +# # need to validate with ref obj +# tmp_type = v.get('type') +# if tmp_type == "object": +# # go deeper into nesting hierarchy +# result_obj[k] = validator_rec_helper(obj_to_eval.get(k), ref_obj, k) +# elif isinstance(tmp_type, list): +# # item can be one of multiple types +# python_types = set() +# for t in tmp_type: +# if t in type_dict: +# python_types.add(type_dict.get(t)) +# else: +# raise TypeError("Unknown resolving for type {0}".format(t)) +# if type(obj_to_eval[k]) not in python_types: +# raise TypeError("Type of object field '{0}' is not allowed".format(k)) +# +# else: +# # this is a single type field +# python_type = type_dict.get(tmp_type) +# if not isinstance(obj_to_eval[k], python_type): +# raise TypeError("Type of object field '{0}' is not allowed".format(k)) +# else: +# # WE'RE OK! +# result_obj[k] = obj_to_eval[k] +# else: +# # this is an object field that wasn't specified by the user +# if v.get('has_default'): +# # WE'RE OK! +# result_obj[k] = v.get('default') +# else: +# # This is a mandatory field! +# raise ValueError("The {0} field is mandatory and must be specified explicitly".format(v)) +# return result_obj +# +# elif isinstance(ref_item, list): +# return [] +# else: +# +# +# +# else: +# raise KeyError("The given key is not ") +# +# +# +# +# pass +# pass +# elif isinstance(obj_to_eval, list): +# # iterate as list sequence +# pass +# else: +# # evaluate as single item +# pass +# pass +# +# try: +# yaml_ref = yaml.load(file(yaml_reference_file_path, 'r')) +# result = validator_rec_helper(evaluated_obj, yaml_ref, root_obj) +# +# except yaml.YAMLError as e: +# raise +# except Exception: +# raise def yaml_loader(file_path): pass diff --git a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml old mode 100644 new mode 100755 index fbaca40e..576710a3 --- a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml +++ b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml @@ -12,7 +12,7 @@ # + type: type of field # + has_default: if the value has any default # + default: the default value (Only appears if has_default field is 'YES') -# 2.2. If an object type, jump to correspoding object key. +# 2.2. If an object type, jump to corresponding object key. # 3. If an object has more than one instance type, another layer with the type shall be added. # For example, 'mode' object has 3 types: 'continuous', 'single_burst', 'multi_burst' # So, 3 mode objects will be defined, named: @@ -20,10 +20,12 @@ # - mode['single_burst'] # - mode['multi_burst'] # In this case, there's no default for the 'type' field on the object -# 4. Some values has 'multiplier' property attached. +# 4. Some values has 'multiply' property attached. # In such case, the loaded value will be multiplied by the multiplier # For example, if the mode's 'pps' field value is 10, and its multiplier is 5, # the loaded pps value will be 10*5=50 +# 5. Any object type must be listed by the user, even if all its field are defaults. +# The most basic option would be to declare the object with "[]", which stands for empty object in YAML syntax. stream: @@ -36,7 +38,7 @@ stream: has_default: YES default: True isg: - type: double + type: [int, double, string] has_default: YES default: 0.0 next_stream_id: @@ -66,33 +68,33 @@ packet: mode: continuous: pps: - type: double + type: [int, double] has_default: NO - multiplier: 1.0 + multiply: YES single_burst: pps: - type: int + type: [int, double] has_default: NO + multiply: YES total_pkts: type: int has_default: NO - multiplier: 1.0 multi_burst: pps: - type: int + type: [int, double] has_default: NO + multiply: YES pkts_per_burst: type: int has_default: NO ibg: - type: double + type: [int, double, string] has_default: YES default: 100.0 count: type: int has_default: YES default: 0 # loop forever - multiplier: 1.0 rx_stats: enabled: @@ -101,7 +103,9 @@ rx_stats: default: False seq_enabled: type: boolean - has_default: NO + has_default: YES + default: False latency_enabled: type: boolean - has_default: NO \ No newline at end of file + has_default: YES + default: False \ No newline at end of file -- cgit 1.2.3-korg From 4a8d34c7548e85e97426bc1d85c670003b1f5870 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 18 Oct 2015 10:24:53 +0300 Subject: more yaml utils, better streams handling --- .../trex_control_plane/client_utils/yaml_utils.py | 115 +---------- .../trex_control_plane/common/rpc_defaults.yaml | 2 +- .../trex_control_plane/common/trex_streams.py | 230 +++++++++++++-------- 3 files changed, 154 insertions(+), 193 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py index 3ec3c9c8..0d808880 100755 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -30,14 +30,6 @@ class CTRexYAMLLoader(object): self.yaml_path = yaml_ref_file_path self.ref_obj = None - def load_reference(self): - try: - self.ref_obj = yaml.load(file(self.yaml_path, 'r')) - except yaml.YAMLError as e: - raise - except Exception as e: - raise - def check_term_param_type(self, val, val_field, ref_val, multiplier): print val, val_field, ref_val tmp_type = ref_val.get('type') @@ -85,7 +77,7 @@ class CTRexYAMLLoader(object): if isinstance(evaluated_obj, dict) and evaluated_obj.keys() == [root_obj]: evaluated_obj = evaluated_obj.get(root_obj) if not self.ref_obj: - self.load_reference() + self.ref_obj = load_yaml_to_obj(self.yaml_path) # load reference object to class attribute. ref_item = self.ref_obj.get(root_obj) if ref_item is not None: try: @@ -151,104 +143,13 @@ class CTRexYAMLLoader(object): return val - - - - -# -# def yaml_obj_validator(evaluated_obj, yaml_reference_file_path, root_obj, fill_defaults=True): -# """ -# validate SINGLE ROOT object with yaml reference file. -# Fills up default values if hasn't been assigned by user and available. -# -# :param evaluated_obj: python object that should match the yaml reference file -# :param yaml_reference_file_path: -# :param fill_defaults: -# :return: a python representation object of the YAML file if OK -# """ -# type_dict = {"double":float, -# "int":int, -# "array":list, -# "string":str, -# "boolean":bool} -# -# def validator_rec_helper(obj_to_eval, ref_obj, root_key): -# ref_item = ref_obj.get(root_key) -# if ref_item is not None: -# if "type" in obj_to_eval: -# ref_item = ref_item[obj_to_eval.get("type")] -# if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal -# result_obj = {} -# # iterate over key-value pairs -# for k, v in ref_item.items(): -# if k in obj_to_eval: -# # need to validate with ref obj -# tmp_type = v.get('type') -# if tmp_type == "object": -# # go deeper into nesting hierarchy -# result_obj[k] = validator_rec_helper(obj_to_eval.get(k), ref_obj, k) -# elif isinstance(tmp_type, list): -# # item can be one of multiple types -# python_types = set() -# for t in tmp_type: -# if t in type_dict: -# python_types.add(type_dict.get(t)) -# else: -# raise TypeError("Unknown resolving for type {0}".format(t)) -# if type(obj_to_eval[k]) not in python_types: -# raise TypeError("Type of object field '{0}' is not allowed".format(k)) -# -# else: -# # this is a single type field -# python_type = type_dict.get(tmp_type) -# if not isinstance(obj_to_eval[k], python_type): -# raise TypeError("Type of object field '{0}' is not allowed".format(k)) -# else: -# # WE'RE OK! -# result_obj[k] = obj_to_eval[k] -# else: -# # this is an object field that wasn't specified by the user -# if v.get('has_default'): -# # WE'RE OK! -# result_obj[k] = v.get('default') -# else: -# # This is a mandatory field! -# raise ValueError("The {0} field is mandatory and must be specified explicitly".format(v)) -# return result_obj -# -# elif isinstance(ref_item, list): -# return [] -# else: -# -# -# -# else: -# raise KeyError("The given key is not ") -# -# -# -# -# pass -# pass -# elif isinstance(obj_to_eval, list): -# # iterate as list sequence -# pass -# else: -# # evaluate as single item -# pass -# pass -# -# try: -# yaml_ref = yaml.load(file(yaml_reference_file_path, 'r')) -# result = validator_rec_helper(evaluated_obj, yaml_ref, root_obj) -# -# except yaml.YAMLError as e: -# raise -# except Exception: -# raise - -def yaml_loader(file_path): - pass +def load_yaml_to_obj(file_path): + try: + return yaml.load(file(file_path, 'r')) + except yaml.YAMLError as e: + raise + except Exception as e: + raise def yaml_exporter(file_path): pass diff --git a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml index 576710a3..5816f980 100755 --- a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml +++ b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml @@ -41,7 +41,7 @@ stream: type: [int, double, string] has_default: YES default: 0.0 - next_stream_id: + next_stream: type: [int, string] # string to allow naming binding has_default: YES default: -1 # no next streams diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 3b0e7376..e6aa66f2 100644 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -3,12 +3,15 @@ import external_packages from client_utils.packet_builder import CTRexPktBuilder from collections import OrderedDict +from client_utils.yaml_utils import * +import dpkt class CStreamList(object): def __init__(self): self.streams_list = OrderedDict() + self.yaml_loader = CTRexYAMLLoader("rpc_exceptions.yaml") self._stream_id = 0 # self._stream_by_name = {} @@ -22,101 +25,50 @@ class CStreamList(object): def remove_stream(self, name): return self.streams_list.pop(name) + def rearrange_streams(self, streams_names_list, new_streams_dict={}): + tmp_list = OrderedDict() + for stream in streams_names_list: + if stream in self.streams_list: + tmp_list[stream] = self.streams_list.get(stream) + elif stream in new_streams_dict: + new_stream_obj = new_streams_dict.get(stream) + assert isinstance(new_stream_obj, CStream) + tmp_list[stream] = new_stream_obj + else: + raise NameError("Given stream named '{0}' cannot be found in existing stream list or and wasn't" + "provided with the new_stream_dict parameter.".format(stream)) + self.streams_list = tmp_list + def export_to_yaml(self, file_path): - pass + raise NotImplementedError("export_to_yaml method is not implemented, yet") - def load_yaml(self, file_path): + def load_yaml(self, file_path, multiplier_dict={}): # clear all existing streams linked to this object self.streams_list.clear() - # self._stream_id = 0 - # load from YAML file the streams one by one - try: - with open(file_path, 'r') as f: - loaded_streams = yaml.load(f) + streams_data = load_yaml_to_obj(file_path) + assert isinstance(streams_data, list) + raw_streams = {} + for stream in streams_data: + stream_name = stream.get("name") + raw_stream = stream.get("stream") + if not stream_name or not raw_stream: + raise ValueError("Provided stream is not according to convention." + "Each stream must be provided as two keys: 'name' and 'stream'. " + "Provided item was:\n {stream}".format(stream)) + new_stream_data = self.yaml_loader.validate_yaml(raw_stream, + "stream", + multiplier= multiplier_dict.get(stream_name, 1)) + new_stream_obj = CStream() + new_stream_obj.load_data(**new_stream_data) + self.append_stream(stream_name, new_stream_obj) - # assume at this point that YAML file is according to rules and correct - except yaml.YAMLError as e: - print "Error in YAML configuration file:", e - print "Aborting YAML loading, no changes made to stream list" - return + # start validating and reassembling clients input pass - - - -class CStream(object): - """docstring for CStream""" - DEFAULTS = {"rx_stats": CRxStats, - "mode": CTxMode, - "isg": 5.0, - "next_stream": -1, - "self_start": True, - "enabled": True} - - def __init__(self, **kwargs): - super(CStream, self).__init__() - for k, v in kwargs.items(): - setattr(self, k, v) - # set default values to unset attributes, according to DEFAULTS dict - set_keys = set(kwargs.keys()) - keys_to_set = [x - for x in self.DEFAULTS - if x not in set_keys] - for key in keys_to_set: - default = self.DEFAULTS.get(key) - if type(default) == type: - setattr(self, key, default()) - else: - setattr(self, key, default) - - @property - def packet(self): - return self._packet - - @packet.setter - def packet(self, packet_obj): - assert isinstance(packet_obj, CTRexPktBuilder) - self._packet = packet_obj - - @property - def enabled(self): - return self._enabled - - @enabled.setter - def enabled(self, bool_value): - self._enabled = bool(bool_value) - - @property - def self_start(self): - return self._self_start - - @self_start.setter - def self_start(self, bool_value): - self._self_start = bool(bool_value) - - @property - def next_stream(self): - return self._next_stream - - @next_stream.setter - def next_stream(self, value): - self._next_stream = int(value) - - def dump(self): - pass - return {"enabled": self.enabled, - "self_start": self.self_start, - "isg": self.isg, - "next_stream": self.next_stream, - "packet": self.packet.dump_pkt(), - "mode": self.mode.dump(), - "vm": self.packet.get_vm_data(), - "rx_stats": self.rx_stats.dump()} - class CRxStats(object): def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): @@ -154,7 +106,6 @@ class CRxStats(object): if v } - class CTxMode(object): """docstring for CTxMode""" def __init__(self, tx_mode, pps): @@ -186,5 +137,114 @@ class CTxMode(object): }) return dump +class CStream(object): + """docstring for CStream""" + DEFAULTS = {"rx_stats": CRxStats, + "mode": CTxMode, + "isg": 5.0, + "next_stream": -1, + "self_start": True, + "enabled": True} + + FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] + + def __init__(self): + super(CStream, self).__init__() + for field in CStream.FIELDS: + setattr(self, field, None) + + def load_data(self, **kwargs): + for k, v in kwargs.items(): + if k == "rx_stats": + if isinstance(v, dict): + setattr(self, k, CRxStats(**v)) + elif isinstance(v, CRxStats): + setattr(self, k, v) + elif k == "mode": + if isinstance(v, dict): + setattr(self, k, CTxMode(v)) + elif isinstance(v, CTxMode): + setattr(self, k, v) + else: + setattr(self, k, v) + + + + # def __init__(self, enabled, self_start, next_stream, isg, mode, rx_stats, packet, vm): + # super(CStream, self).__init__() + # for k, v in kwargs.items(): + # if k == "rx_stats": + # if isinstance(v, dict): + # setattr(self, k, CRxStats(v)) + # elif isinstance(v, CRxStats): + # setattr(self, k, v) + # elif k == "mode": + # if isinstance(v, dict): + # setattr(self, k, CTxMode(v)) + # elif isinstance(v, CTxMode): + # setattr(self, k, v) + # else: + # setattr(self, k, v) + # # set default values to unset attributes, according to DEFAULTS dict + # set_keys = set(kwargs.keys()) + # keys_to_set = [x + # for x in self.DEFAULTS + # if x not in set_keys] + # for key in keys_to_set: + # default = self.DEFAULTS.get(key) + # if type(default) == type: + # setattr(self, key, default()) + # else: + # setattr(self, key, default) + + # @property + # def packet(self): + # return self._packet + # + # @packet.setter + # def packet(self, packet_obj): + # assert isinstance(packet_obj, CTRexPktBuilder) + # self._packet = packet_obj + # + # @property + # def enabled(self): + # return self._enabled + # + # @enabled.setter + # def enabled(self, bool_value): + # self._enabled = bool(bool_value) + # + # @property + # def self_start(self): + # return self._self_start + # + # @self_start.setter + # def self_start(self, bool_value): + # self._self_start = bool(bool_value) + # + # @property + # def next_stream(self): + # return self._next_stream + # + # @next_stream.setter + # def next_stream(self, value): + # self._next_stream = int(value) + + def dump(self): + pass + return {"enabled": self.enabled, + "self_start": self.self_start, + "isg": self.isg, + "next_stream": self.next_stream, + "packet": self.packet.dump_pkt(), + "mode": self.mode.dump(), + "vm": self.packet.get_vm_data(), + "rx_stats": self.rx_stats.dump()} + + + + + + if __name__ == "__main__": pass -- cgit 1.2.3-korg From ba9973506c1de58c87ccaa59798fb4e6252a186e Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sun, 18 Oct 2015 14:43:49 +0300 Subject: fix trex-130 issue --- scripts/cfg/cfg_example1.yaml | 9 +++++- src/platform_cfg.cpp | 64 +++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 34 deletions(-) (limited to 'scripts') diff --git a/scripts/cfg/cfg_example1.yaml b/scripts/cfg/cfg_example1.yaml index bfd7fd88..224fb15e 100755 --- a/scripts/cfg/cfg_example1.yaml +++ b/scripts/cfg/cfg_example1.yaml @@ -6,8 +6,15 @@ enable_zmq_pub : true # enable publisher for stats data zmq_pub_port : 4507 telnet_port : 4508 # the telnet port in case it is enable ( with intercative mode ) + platform : + master_thread_id : 12 + latency_thread_id : 13 + dual_if : + - socket : 1 + threads : [8,9,10,11] + port_info : # set eh mac addr - - dest_mac : [0x1,0x0,0x0,0x1,0x0,0x00] # port 0 + - dest_mac : [1,0x0,0x0,0x1,0x0,0x00] # port 0 src_mac : [0x2,0x0,0x0,0x2,0x0,0x00] - dest_mac : [0x3,0x0,0x0,0x3,0x0,0x00] # port 1 src_mac : [0x4,0x0,0x0,0x4,0x0,0x00] diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index a226a9ac..db563cc9 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -262,12 +262,6 @@ void operator >> (const YAML::Node& node, CPlatformMemoryYamlInfo & plat_info) { void operator >> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { - try { - node["port_limit"] >> plat_info.m_port_limit; - plat_info.m_port_limit_exist=true; - } catch ( const std::exception& e ) { - plat_info.m_port_limit=0xffffffff; - } try { @@ -284,14 +278,6 @@ void operator >> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { } - try { - node["enable_zmq_pub"] >> plat_info.m_enable_zmq_pub; - node["zmq_pub_port"] >> plat_info.m_zmq_pub_port; - plat_info.m_enable_zmq_pub_exist = true; - } catch ( const std::exception& e ) { - plat_info.m_enable_zmq_pub_exist = false; - } - /* must have interfaces */ const YAML::Node& interfaces = node["interfaces"]; for(unsigned i=0;i> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { plat_info.m_if_list.push_back(fi); } - try { - node["prefix"] >> plat_info.m_prefix; - } catch ( const std::exception& e ) { + + if ( node.FindValue("port_limit") ){ + node["port_limit"] >> plat_info.m_port_limit; + plat_info.m_port_limit_exist=true; } - try { - node["limit_memory"] >> plat_info.m_limit_memory; - } catch ( const std::exception& e ) { + + + plat_info.m_enable_zmq_pub_exist = true; + + if ( node.FindValue("enable_zmq_pub") ){ + node["enable_zmq_pub"] >> plat_info.m_enable_zmq_pub; + plat_info.m_enable_zmq_pub_exist = true; } - try { - node["c"] >> plat_info.m_thread_per_dual_if; - } catch ( const std::exception& e ) { + + if ( node.FindValue("zmq_pub_port") ){ + node["zmq_pub_port"] >> plat_info.m_zmq_pub_port; + plat_info.m_enable_zmq_pub_exist = true; } + if ( node.FindValue("prefix") ){ + node["prefix"] >> plat_info.m_prefix; + } + if ( node.FindValue("limit_memory") ){ + node["limit_memory"] >> plat_info.m_limit_memory; + } - try { - node["telnet_port"] >> plat_info.m_telnet_port; - plat_info.m_telnet_exist=true; - } catch ( const std::exception& e ) { - plat_info.m_telnet_port=4501; + if ( node.FindValue("c") ){ + node["c"] >> plat_info.m_thread_per_dual_if; } - try { - node["port_bandwidth_gb"] >> plat_info.m_port_bandwidth_gb; - } catch ( const std::exception& e ) { + if ( node.FindValue("telnet_port") ){ + node["telnet_port"] >> plat_info.m_telnet_port; + plat_info.m_telnet_exist=true; + } + + if ( node.FindValue("port_bandwidth_gb") ){ + node["port_bandwidth_gb"] >> plat_info.m_port_bandwidth_gb; } if ( node.FindValue("memory") ){ @@ -337,7 +336,7 @@ void operator >> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { plat_info.m_platform.m_is_exists=true; } - try { + if ( node.FindValue("port_info") ) { const YAML::Node& mac_info = node["port_info"]; for(unsigned i=0;i> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { plat_info.m_mac_info.push_back(fi); } plat_info.m_mac_info_exist = true; - }catch ( const std::exception& e ) { } } -- cgit 1.2.3-korg From 80bd7895112cba0b3cbb6d56995def6ffbdccf33 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 18 Oct 2015 16:12:26 +0300 Subject: Progress in trex_streams and in yaml_utils. Next, start working on StreamList object --- .../client_utils/packet_builder.py | 6 +- .../trex_control_plane/client_utils/yaml_utils.py | 3 +- .../trex_control_plane/common/trex_streams.py | 274 +++++++++------------ 3 files changed, 129 insertions(+), 154 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/common/trex_streams.py (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/packet_builder.py b/scripts/automation/trex_control_plane/client_utils/packet_builder.py index c687126b..caa6eab3 100755 --- a/scripts/automation/trex_control_plane/client_utils/packet_builder.py +++ b/scripts/automation/trex_control_plane/client_utils/packet_builder.py @@ -33,6 +33,7 @@ class CTRexPktBuilder(object): self._max_pkt_size = max_pkt_size self.payload_gen = CTRexPktBuilder.CTRexPayloadGen(self._packet, self._max_pkt_size) self.vm = CTRexPktBuilder.CTRexVM() + self.metadata = "" def add_pkt_layer(self, layer_name, pkt_layer): """ @@ -441,8 +442,9 @@ class CTRexPktBuilder(object): if self._packet is None: raise CTRexPktBuilder.EmptyPacketError() pkt_in_hex = binascii.hexlify(str(self._packet)) - return [int(pkt_in_hex[i:i+2], 16) - for i in range(0, len(pkt_in_hex), 2)] + return {"binary": [int(pkt_in_hex[i:i+2], 16) + for i in range(0, len(pkt_in_hex), 2)], + "meta": self.metadata} # return [pkt_in_hex[i:i+2] for i in range(0, len(pkt_in_hex), 2)] def dump_pkt_to_pcap(self, file_path, ts=None): diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py index 0d808880..024b73c2 100755 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -77,7 +77,8 @@ class CTRexYAMLLoader(object): if isinstance(evaluated_obj, dict) and evaluated_obj.keys() == [root_obj]: evaluated_obj = evaluated_obj.get(root_obj) if not self.ref_obj: - self.ref_obj = load_yaml_to_obj(self.yaml_path) # load reference object to class attribute. + self.ref_obj = load_yaml_to_any_obj(self.yaml_path) + # self.load_reference() ref_item = self.ref_obj.get(root_obj) if ref_item is not None: try: diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py old mode 100644 new mode 100755 index e6aa66f2..e366001d --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -5,13 +5,14 @@ from client_utils.packet_builder import CTRexPktBuilder from collections import OrderedDict from client_utils.yaml_utils import * import dpkt +import struct class CStreamList(object): def __init__(self): - self.streams_list = OrderedDict() - self.yaml_loader = CTRexYAMLLoader("rpc_exceptions.yaml") + self.streams_list = {OrderedDict()} + self.yaml_loader = CTRexYAMLLoader("rpc_defaults.yaml") self._stream_id = 0 # self._stream_by_name = {} @@ -62,184 +63,155 @@ class CStreamList(object): new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) - - - # start validating and reassembling clients input - + def compile_streams(self): + stream_ids = {} pass -class CRxStats(object): - - def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): - self._rx_dict = {"enabled": enabled, - "seq_enabled": seq_enabled, - "latency_enabled": latency_enabled} - - @property - def enabled(self): - return self._rx_dict.get("enabled") - @enabled.setter - def enabled(self, bool_value): - self._rx_dict['enabled'] = bool(bool_value) +class CRxStats(object): - @property - def seq_enabled(self): - return self._rx_dict.get("seq_enabled") + FIELDS = ["seq_enabled", "latency_enabled"] + def __init__(self, enabled=False, **kwargs): + self.enabled = bool(enabled) + for field in CRxStats.FIELDS: + setattr(self, field, kwargs.get(field, False)) - @seq_enabled.setter - def seq_enabled(self, bool_value): - self._rx_dict['seq_enabled'] = bool(bool_value) + def dump(self): + if self.enabled: + dump = {"enabled": True} + dump.update({k: getattr(self, k) + for k in CRxStats.FIELDS + if getattr(self, k) + }) + return dump + else: + return {"enabled": False} - @property - def latency_enabled(self): - return self._rx_dict.get("latency_enabled") - @latency_enabled.setter - def latency_enabled(self, bool_value): - self._rx_dict['latency_enabled'] = bool(bool_value) - - def dump(self): - return {k: v - for k, v in self._rx_dict.items() - if v - } class CTxMode(object): """docstring for CTxMode""" - def __init__(self, tx_mode, pps): - super(CTxMode, self).__init__() - if tx_mode not in ["continuous", "single_burst", "multi_burst"]: - raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode)) - self._tx_mode = tx_mode - self._fields = {'pps': float(pps)} - if tx_mode == "single_burst": - self._fields['total_pkts'] = 0 - elif tx_mode == "multi_burst": - self._fields['pkts_per_burst'] = 0 - self._fields['ibg'] = 0.0 - self._fields['count'] = 0 - else: - pass + GENERAL_FIELDS = ["type", "pps"] + FIELDS = {"continuous": [], + "single_burst": ["total_pkts"], + "multi_burst": ["pkts_per_burst", "ibg", "count"]} + + def __init__(self, type, pps=0, **kwargs): + self._MODES = CTxMode.FIELDS.keys() + self.type = type + self.pps = pps + for field in CTxMode.FIELDS.get(self.type): + setattr(self, field, kwargs.get(field, 0)) - def set_tx_mode_attr(self, attr, val): - if attr in self._fields: - self._fields[attr] = type(self._fields.get(attr))(val) - else: - raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')". - format(attr, self._tx_mode)) + @property + def type(self): + return self._type + + @type.setter + def type(self, type): + if type not in self._MODES: + raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(type)) + self._type = type + self._reset_fields() def dump(self): - dump = {"type": self._tx_mode} - dump.update({k: v - for k, v in self._fields.items() + dump = ({k: getattr(self, k) + for k in CTxMode.GENERAL_FIELDS + }) + dump.update({k: getattr(self, k) + for k in CTxMode.FIELDS.get(self.type) }) return dump + def _reset_fields(self): + for field in CTxMode.FIELDS.get(self.type): + setattr(self, field, 0) + + class CStream(object): """docstring for CStream""" - DEFAULTS = {"rx_stats": CRxStats, - "mode": CTxMode, - "isg": 5.0, - "next_stream": -1, - "self_start": True, - "enabled": True} FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] def __init__(self): - super(CStream, self).__init__() + self.is_loaded = False for field in CStream.FIELDS: setattr(self, field, None) def load_data(self, **kwargs): - for k, v in kwargs.items(): - if k == "rx_stats": - if isinstance(v, dict): - setattr(self, k, CRxStats(**v)) - elif isinstance(v, CRxStats): - setattr(self, k, v) - elif k == "mode": - if isinstance(v, dict): - setattr(self, k, CTxMode(v)) - elif isinstance(v, CTxMode): - setattr(self, k, v) - else: - setattr(self, k, v) - - - - # def __init__(self, enabled, self_start, next_stream, isg, mode, rx_stats, packet, vm): - # super(CStream, self).__init__() - # for k, v in kwargs.items(): - # if k == "rx_stats": - # if isinstance(v, dict): - # setattr(self, k, CRxStats(v)) - # elif isinstance(v, CRxStats): - # setattr(self, k, v) - # elif k == "mode": - # if isinstance(v, dict): - # setattr(self, k, CTxMode(v)) - # elif isinstance(v, CTxMode): - # setattr(self, k, v) - # else: - # setattr(self, k, v) - # # set default values to unset attributes, according to DEFAULTS dict - # set_keys = set(kwargs.keys()) - # keys_to_set = [x - # for x in self.DEFAULTS - # if x not in set_keys] - # for key in keys_to_set: - # default = self.DEFAULTS.get(key) - # if type(default) == type: - # setattr(self, key, default()) - # else: - # setattr(self, key, default) - - # @property - # def packet(self): - # return self._packet - # - # @packet.setter - # def packet(self, packet_obj): - # assert isinstance(packet_obj, CTRexPktBuilder) - # self._packet = packet_obj - # - # @property - # def enabled(self): - # return self._enabled - # - # @enabled.setter - # def enabled(self, bool_value): - # self._enabled = bool(bool_value) - # - # @property - # def self_start(self): - # return self._self_start - # - # @self_start.setter - # def self_start(self, bool_value): - # self._self_start = bool(bool_value) - # - # @property - # def next_stream(self): - # return self._next_stream - # - # @next_stream.setter - # def next_stream(self, value): - # self._next_stream = int(value) + try: + for k in CStream.FIELDS: + if k == "rx_stats": + rx_stats_data = kwargs[k] + if isinstance(rx_stats_data, dict): + setattr(self, k, CRxStats(**rx_stats_data)) + elif isinstance(rx_stats_data, CRxStats): + setattr(self, k, rx_stats_data) + elif k == "mode": + tx_mode = kwargs[k] + if isinstance(tx_mode, dict): + setattr(self, k, CTxMode(**tx_mode)) + elif isinstance(tx_mode, CTxMode): + setattr(self, k, tx_mode) + elif k == "packet": + if isinstance(kwargs[k], CTRexPktBuilder): + if "vm" not in kwargs: + self.load_packet_obj(kwargs[k]) + else: + raise ValueError("When providing packet object with a CTRexPktBuilder, vm parameter " + "should not be supplied") + else: + binary = kwargs[k]["binary"] + if isinstance(binary, list): + setattr(self, k, kwargs[k]) + elif isinstance(binary, str) and binary.endswith(".pcap"): + self.load_packet_from_pcap(binary, kwargs[k]["meta"]) + else: + raise ValueError("Packet binary attribute has been loaded with unsupported value." + "Supported values are reference to pcap file with SINGLE packet, " + "or a list of unsigned-byte integers") + else: + setattr(self, k, kwargs[k]) + self.is_loaded = True + except KeyError as e: + cause = e.args[0] + raise KeyError("The attribute '{0}' is missing as a field of the CStream object.\n" + "Loaded data must contain all of the following fields: {1}".format(cause, CStream.FIELDS)) + + def load_packet_obj(self, packet_obj): + assert isinstance(packet_obj, CTRexPktBuilder) + self.packet = packet_obj.dump_pkt() + self.vm = packet_obj.get_vm_data() + + def load_packet_from_pcap(self, pcap_path, metadata=''): + with open(pcap_path, 'r') as f: + pcap = dpkt.pcap.Reader(f) + first_packet = True + for _, buf in pcap: + # this is an iterator, can't evaluate the number of files in advance + if first_packet: + self.packet = {"binary": [struct.unpack('B', buf[i:i+1])[0] # represent data as list of 0-255 ints + for i in range(0, len(buf))], + "meta": metadata} # meta data continues without a change. + first_packet = False + else: + raise ValueError("Provided pcap file contains more than single packet.") + # arrive here ONLY if pcap contained SINGLE packet + return + def dump(self): - pass - return {"enabled": self.enabled, - "self_start": self.self_start, - "isg": self.isg, - "next_stream": self.next_stream, - "packet": self.packet.dump_pkt(), - "mode": self.mode.dump(), - "vm": self.packet.get_vm_data(), - "rx_stats": self.rx_stats.dump()} + if self.is_loaded: + dump = {} + for key in CStream.FIELDS: + try: + dump[key] = getattr(self, key).dump() # use dump() method of compound object, such TxMode + except AttributeError: + dump[key] = getattr(self, key) + return dump + else: + raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.") -- cgit 1.2.3-korg From d09df99769f67819c64a7a025dbdcd39811c7b44 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 20 Oct 2015 03:17:08 +0300 Subject: Major progress in console, yaml utils, and trex_streams basically done, minor changes remianing BIG ISSUE LEFT: rewire console to work with trexstateless client module --- .../client_utils/jsonrpc_client.py | 81 ++++++++++++-------- .../client_utils/packet_builder.py | 2 +- .../trex_control_plane/client_utils/yaml_utils.py | 28 +++---- .../trex_control_plane/common/rpc_defaults.yaml | 8 +- .../trex_control_plane/common/trex_streams.py | 85 +++++++++++++-------- .../trex_control_plane/console/trex_console.py | 86 ++++++++++++++++++++++ scripts/stl/imix_1pkt.yaml | 11 +++ 7 files changed, 226 insertions(+), 75 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/console/trex_console.py create mode 100755 scripts/stl/imix_1pkt.yaml (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py index 8c8987b6..b2d83cff 100755 --- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py @@ -458,32 +458,55 @@ class TrexStatelessClient(JsonRpcClient): return snap # add stream - def add_stream (self, port_id, stream_id, isg, next_stream_id, packet): - if not port_id in self.get_owned_ports(): - return False, "Port {0} is not owned... please take ownership before adding streams".format(port_id) - - handler = self.port_handlers[port_id] - - stream = {} - stream['enabled'] = True - stream['self_start'] = True - stream['isg'] = isg - stream['next_stream_id'] = next_stream_id - stream['packet'] = {} - stream['packet']['binary'] = packet - stream['packet']['meta'] = "" - stream['vm'] = [] - stream['rx_stats'] = {} - stream['rx_stats']['enabled'] = False - - stream['mode'] = {} - stream['mode']['type'] = 'continuous' - stream['mode']['pps'] = 10.0 - - params = {} - params['handler'] = handler - params['stream'] = stream - params['port_id'] = port_id - params['stream_id'] = stream_id - - return self.invoke_rpc_method('add_stream', params = params) + # def add_stream (self, port_id, stream_id, isg, next_stream_id, packet, vm=[]): + # if not port_id in self.get_owned_ports(): + # return False, "Port {0} is not owned... please take ownership before adding streams".format(port_id) + # + # handler = self.port_handlers[port_id] + # + # stream = {} + # stream['enabled'] = True + # stream['self_start'] = True + # stream['isg'] = isg + # stream['next_stream_id'] = next_stream_id + # stream['packet'] = {} + # stream['packet']['binary'] = packet + # stream['packet']['meta'] = "" + # stream['vm'] = vm + # stream['rx_stats'] = {} + # stream['rx_stats']['enabled'] = False + # + # stream['mode'] = {} + # stream['mode']['type'] = 'continuous' + # stream['mode']['pps'] = 10.0 + # + # params = {} + # params['handler'] = handler + # params['stream'] = stream + # params['port_id'] = port_id + # params['stream_id'] = stream_id + # + # print params + # return self.invoke_rpc_method('add_stream', params = params) + + def add_stream(self, port_id_array, stream_pack_list): + batch = self.create_batch() + + for port_id in port_id_array: + for stream_pack in stream_pack_list: + params = {"port_id": port_id, + "handler": self.port_handlers[port_id], + "stream_id": stream_pack.stream_id, + "stream": stream_pack.stream} + batch.add("add_stream", params=params) + rc, resp_list = batch.invoke() + if not rc: + return rc, resp_list + + for i, rc in enumerate(resp_list): + if rc[0]: + self.port_handlers[port_id_array[i]] = rc[1] + + return True, resp_list + + # return self.invoke_rpc_method('add_stream', params = params) diff --git a/scripts/automation/trex_control_plane/client_utils/packet_builder.py b/scripts/automation/trex_control_plane/client_utils/packet_builder.py index caa6eab3..3aeb6a34 100755 --- a/scripts/automation/trex_control_plane/client_utils/packet_builder.py +++ b/scripts/automation/trex_control_plane/client_utils/packet_builder.py @@ -889,7 +889,7 @@ class CTRexPktBuilder(object): dictionary holds variable data of VM variable """ - return {"ins_name": "flow_var", # VM variable dump always refers to manipulate instruction. + return {"type": "flow_var", # VM variable dump always refers to manipulate instruction. "name": self.name, "size": self.size, "op": self.operation, diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py index 024b73c2..414744fc 100755 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -31,18 +31,18 @@ class CTRexYAMLLoader(object): self.ref_obj = None def check_term_param_type(self, val, val_field, ref_val, multiplier): - print val, val_field, ref_val + # print val, val_field, ref_val tmp_type = ref_val.get('type') if isinstance(tmp_type, list): # item can be one of multiple types - print "multiple choice!" + # print "multiple choice!" python_types = set() for t in tmp_type: if t in self.TYPE_DICT: python_types.add(self.TYPE_DICT.get(t)) else: return False, TypeError("Unknown resolving for type {0}".format(t)) - print "python legit types: ", python_types + # print "python legit types: ", python_types if type(val) not in python_types: return False, TypeError("Type of object field '{0}' is not allowed".format(val_field)) else: @@ -58,7 +58,7 @@ class CTRexYAMLLoader(object): return True, CTRexYAMLLoader._calc_final_value(val, multiplier, ref_val.get('multiply', False)) def get_reference_default(self, root_obj, sub_obj, key): - print root_obj, sub_obj, key + # print root_obj, sub_obj, key if sub_obj: ref_field = self.ref_obj.get(root_obj).get(sub_obj).get(key) else: @@ -77,7 +77,7 @@ class CTRexYAMLLoader(object): if isinstance(evaluated_obj, dict) and evaluated_obj.keys() == [root_obj]: evaluated_obj = evaluated_obj.get(root_obj) if not self.ref_obj: - self.ref_obj = load_yaml_to_any_obj(self.yaml_path) + self.ref_obj = load_yaml_to_obj(self.yaml_path) # self.load_reference() ref_item = self.ref_obj.get(root_obj) if ref_item is not None: @@ -85,30 +85,30 @@ class CTRexYAMLLoader(object): typed_obj = [False, None] # first item stores validity (multiple object "shapes"), second stored type if "type" in evaluated_obj: ref_item = ref_item[evaluated_obj.get("type")] - print "lower resolution with typed object" + # print "lower resolution with typed object" typed_obj = [True, evaluated_obj.get("type")] if isinstance(ref_item, dict) and "type" not in ref_item: # this is not a terminal result_obj = {} if typed_obj[0]: result_obj["type"] = typed_obj[1] - print "processing dictionary non-terminal value" + # print "processing dictionary non-terminal value" for k, v in ref_item.items(): - print "processing element '{0}' with value '{1}'".format(k,v) + # print "processing element '{0}' with value '{1}'".format(k,v) if k in evaluated_obj: # validate with ref obj - print "found in evaluated object!" + # print "found in evaluated object!" tmp_type = v.get('type') - print tmp_type - print evaluated_obj + # print tmp_type + # print evaluated_obj if tmp_type == "object": # go deeper into nesting hierarchy - print "This is an object type, recursion!" + # print "This is an object type, recursion!" result_obj[k] = self.validate_yaml(evaluated_obj.get(k), k, fill_defaults, multiplier) else: # validation on terminal type - print "Validating terminal type %s" % k + # print "Validating terminal type %s" % k res_ok, data = self.check_term_param_type(evaluated_obj.get(k), k, v, multiplier) - print "Validating: ", res_ok + # print "Validating: ", res_ok if res_ok: # data field contains the value to save result_obj[k] = data diff --git a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml index 5816f980..32631609 100755 --- a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml +++ b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml @@ -41,8 +41,8 @@ stream: type: [int, double, string] has_default: YES default: 0.0 - next_stream: - type: [int, string] # string to allow naming binding + next_stream_id: + type: string # string to allow naming binding has_default: YES default: -1 # no next streams packet: @@ -101,6 +101,10 @@ rx_stats: type: boolean has_default: YES default: False + stream_id: + type: string + has_default: YES + default: False # use related stream_id seq_enabled: type: boolean has_default: YES diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index e366001d..674a6bcc 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -2,19 +2,21 @@ import external_packages from client_utils.packet_builder import CTRexPktBuilder -from collections import OrderedDict +from collections import OrderedDict, namedtuple from client_utils.yaml_utils import * import dpkt import struct +import copy +import os +StreamPack = namedtuple('StreamPack', ['stream_id', 'stream']) class CStreamList(object): def __init__(self): - self.streams_list = {OrderedDict()} - self.yaml_loader = CTRexYAMLLoader("rpc_defaults.yaml") - self._stream_id = 0 - # self._stream_by_name = {} + self.streams_list = {} + self.yaml_loader = CTRexYAMLLoader(os.path.join(os.path.dirname(os.path.realpath(__file__)), + "rpc_defaults.yaml")) def append_stream(self, name, stream_obj): assert isinstance(stream_obj, CStream) @@ -24,21 +26,19 @@ class CStreamList(object): return def remove_stream(self, name): - return self.streams_list.pop(name) - - def rearrange_streams(self, streams_names_list, new_streams_dict={}): - tmp_list = OrderedDict() - for stream in streams_names_list: - if stream in self.streams_list: - tmp_list[stream] = self.streams_list.get(stream) - elif stream in new_streams_dict: - new_stream_obj = new_streams_dict.get(stream) - assert isinstance(new_stream_obj, CStream) - tmp_list[stream] = new_stream_obj - else: - raise NameError("Given stream named '{0}' cannot be found in existing stream list or and wasn't" - "provided with the new_stream_dict parameter.".format(stream)) - self.streams_list = tmp_list + popped = self.streams_list.pop(name) + if popped: + for stream_name, stream in self.streams_list.items(): + if stream.next_stream_id == name: + stream.next_stream_id = -1 + try: + rx_stats_stream = getattr(stream.rx_stats, "stream_id") + if rx_stats_stream == name: + # if a referenced stream of rx_stats object deleted, revert to rx stats of current stream + setattr(stream.rx_stats, "stream_id", stream_name) + except AttributeError as e: + continue # + return popped def export_to_yaml(self, file_path): raise NotImplementedError("export_to_yaml method is not implemented, yet") @@ -48,7 +48,6 @@ class CStreamList(object): self.streams_list.clear() streams_data = load_yaml_to_obj(file_path) assert isinstance(streams_data, list) - raw_streams = {} for stream in streams_data: stream_name = stream.get("name") raw_stream = stream.get("stream") @@ -62,16 +61,41 @@ class CStreamList(object): new_stream_obj = CStream() new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) + return streams_data def compile_streams(self): + # first, assign an id to each stream stream_ids = {} - - pass + for idx, stream_name in enumerate(self.streams_list): + stream_ids[stream_name] = idx + # next, iterate over the streams and transform them from working with names to ids. + # with that build a new dict with old stream_name as the key, and StreamPack as the stored value + compiled_streams = {} + for stream_name, stream in self.streams_list.items(): + tmp_stream = CStreamList._compile_single_stream(stream_name, stream, stream_ids) + compiled_streams[stream_name] = StreamPack(stream_ids.get(stream_name), + tmp_stream) + return compiled_streams + + @staticmethod + def _compile_single_stream(stream_name, stream, id_dict): + # copy the old stream to temporary one, no change to class attributes + tmp_stream = copy.copy(stream) + next_stream_id = id_dict.get(getattr(tmp_stream, "next_stream_id"), -1) + try: + rx_stats_stream_id = id_dict.get(getattr(tmp_stream.rx_stats, "stream_id"), + id_dict.get(stream_name)) + except AttributeError as e: + rx_stats_stream_id = id_dict.get(stream_name) + # assign resolved values to stream object + tmp_stream.next_stream_id = next_stream_id + tmp_stream.rx_stats.stream_id = rx_stats_stream_id + return tmp_stream class CRxStats(object): - FIELDS = ["seq_enabled", "latency_enabled"] + FIELDS = ["seq_enabled", "latency_enabled", "stream_id"] def __init__(self, enabled=False, **kwargs): self.enabled = bool(enabled) for field in CRxStats.FIELDS: @@ -82,7 +106,7 @@ class CRxStats(object): dump = {"enabled": True} dump.update({k: getattr(self, k) for k in CRxStats.FIELDS - if getattr(self, k) + if getattr(self, k) or k == "stream_id" }) return dump else: @@ -132,10 +156,12 @@ class CTxMode(object): class CStream(object): """docstring for CStream""" - FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] + FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] + # COMPILE_FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] def __init__(self): self.is_loaded = False + self._is_compiled = False for field in CStream.FIELDS: setattr(self, field, None) @@ -201,7 +227,8 @@ class CStream(object): return - def dump(self): + def dump(self, compilation=False): + # fields = CStream.COMPILE_FIELDS if compilation else CStream.FIELDS if self.is_loaded: dump = {} for key in CStream.FIELDS: @@ -213,8 +240,8 @@ class CStream(object): else: raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.") - - + def dump_compiled(self): + return self.dump(compilation=True) diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py old mode 100644 new mode 100755 index 9478db5a..945bb177 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -9,9 +9,13 @@ import string import sys import trex_root_path +from common.trex_streams import * from client_utils.jsonrpc_client import TrexStatelessClient import trex_status +from collections import namedtuple + +LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) class TrexConsole(cmd.Cmd): """Trex Console""" @@ -29,6 +33,8 @@ class TrexConsole(cmd.Cmd): self.verbose = False self.postcmd(False, "") + + self.user_streams = {} # a cool hack - i stole this function and added space @@ -312,6 +318,86 @@ class TrexConsole(cmd.Cmd): print "{:<30} {:<30}".format(cmd + " - ", help) + def do_load_stream_list(self, line): + '''Loads a YAML stream list serialization into user console \n''' + args = line.split() + if args >= 2: + name = args[0] + yaml_path = args[1] + stream_list = CStreamList() + loaded_obj = stream_list.load_yaml(yaml_path) + # print self.rpc_client.pretty_json(json.dumps(loaded_obj)) + if name in self.user_streams: + print "Picked name already exist. Please pick another name." + else: + try: + compiled_streams = stream_list.compile_streams() + self.user_streams[name] = LoadedStreamList(loaded_obj, + [StreamPack(v.stream_id, v.stream.dump_compiled()) + for k, v in compiled_streams.items()]) + + print "Stream '{0}' loaded successfully".format(name) + except Exception as e: + raise + return + else: + print "please provide load name and YAML path, separated by space." + + def do_show_stream_list(self, line): + '''Shows the loaded stream list named [name] \n''' + args = line.split() + if args: + list_name = args[0] + try: + stream = self.user_streams[list_name] + if len(args) >= 2 and args[1] == "full": + print self.rpc_client.pretty_json(json.dumps(stream.compiled)) + else: + print self.rpc_client.pretty_json(json.dumps(stream.loaded)) + except KeyError as e: + print "Unknown stream list name provided" + else: + print "\nAvailable stream lists:\n{0}".format(', '.join([x + for x in self.user_streams.keys()])) + + def complete_show_stream_list (self, text, line, begidx, endidx): + return [x + for x in self.user_streams.keys() + if x.startswith(text)] + + def do_attach(self, line): + args = line.split() + if len(args) >= 1: + try: + stream_list = self.user_streams[args[0]] + port_list = self.parse_ports_from_line(' '.join(args[1:])) + owned = set(self.rpc_client.get_owned_ports()) + if set(port_list).issubset(owned): + rc, resp_list = self.rpc_client.add_stream(port_list, stream_list.compiled) + if not rc: + print "\n*** " + resp_list + "\n" + return + else: + print "Not all desired ports are aquired.\n" \ + "Acquired ports are: {acq}\n" \ + "Requested ports: {req}\n" \ + "Missing ports: {miss}".format(acq=list(owned), + req=port_list, + miss=list(set(port_list).difference(owned))) + except KeyError as e: + cause = e.args[0] + print "Provided stream list name '{0}' doesn't exists.".format(cause) + else: + print "Please provide list name and ports to attach to, or leave empty to attach to all ports." + + + + + + + + + # do #def do_snapshot (self, line): diff --git a/scripts/stl/imix_1pkt.yaml b/scripts/stl/imix_1pkt.yaml new file mode 100755 index 00000000..128bd559 --- /dev/null +++ b/scripts/stl/imix_1pkt.yaml @@ -0,0 +1,11 @@ +### Single stream UDP packet, 64B ### +##################################### +- name: udp_64B + stream: + self_start: True + packet: + binary: cap2/udp_64B_1pkt.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] \ No newline at end of file -- cgit 1.2.3-korg From 5abe21ffb26a15c2a63e90b5628d704e8211b599 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 20 Oct 2015 09:12:33 +0300 Subject: + Added traffic options at stl directory + updated console to support multiplier on loading + fixed minor issues at yaml_utils and trex_streams objects + console not stable, YET --- .../trex_control_plane/client_utils/yaml_utils.py | 8 ++++-- .../trex_control_plane/common/trex_streams.py | 6 ++--- .../trex_control_plane/console/trex_console.py | 28 ++++++++++++++++++--- scripts/stl/imix_1pkt.yaml | 2 +- scripts/stl/imix_2pkt.yaml | 20 +++++++++++++++ scripts/stl/imix_3pkt.yaml | 29 ++++++++++++++++++++++ 6 files changed, 84 insertions(+), 9 deletions(-) create mode 100755 scripts/stl/imix_2pkt.yaml create mode 100755 scripts/stl/imix_3pkt.yaml (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py index 414744fc..60630a04 100755 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -108,7 +108,6 @@ class CTRexYAMLLoader(object): # validation on terminal type # print "Validating terminal type %s" % k res_ok, data = self.check_term_param_type(evaluated_obj.get(k), k, v, multiplier) - # print "Validating: ", res_ok if res_ok: # data field contains the value to save result_obj[k] = data @@ -138,8 +137,13 @@ class CTRexYAMLLoader(object): @staticmethod def _calc_final_value(val, multiplier, multiply): + def to_num(s): + try: + return int(s) + except ValueError: + return float(s) if multiply: - return (val * multiplier) + return val * to_num(multiplier) else: return val diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 1aeb46b0..783f2769 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -43,7 +43,7 @@ class CStreamList(object): def export_to_yaml(self, file_path): raise NotImplementedError("export_to_yaml method is not implemented, yet") - def load_yaml(self, file_path, multiplier_dict={}): + def load_yaml(self, file_path, multiplier=1): # clear all existing streams linked to this object self.streams_list.clear() streams_data = load_yaml_to_obj(file_path) @@ -57,11 +57,11 @@ class CStreamList(object): "Provided item was:\n {stream}".format(stream)) new_stream_data = self.yaml_loader.validate_yaml(raw_stream, "stream", - multiplier= multiplier_dict.get(stream_name, 1)) + multiplier= multiplier) new_stream_obj = CStream() new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) - return streams_data + return new_stream_data def compile_streams(self): # first, assign an id to each stream diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 688f80f3..27a5eeab 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -1,5 +1,22 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- + +""" +Dan Klein, Itay Marom +Cisco Systems, Inc. + +Copyright (c) 2015-2015 Cisco Systems, Inc. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + import cmd import json import ast @@ -416,8 +433,12 @@ class TrexConsole(cmd.Cmd): if args >= 2: name = args[0] yaml_path = args[1] + try: + multiplier = args[2] + except IndexError: + multiplier = 1 stream_list = CStreamList() - loaded_obj = stream_list.load_yaml(yaml_path) + loaded_obj = stream_list.load_yaml(yaml_path, multiplier) # print self.rpc_client.pretty_json(json.dumps(loaded_obj)) if name in self.user_streams: print "Picked name already exist. Please pick another name." @@ -433,7 +454,8 @@ class TrexConsole(cmd.Cmd): raise return else: - print "please provide load name and YAML path, separated by space." + print "please provide load name and YAML path, separated by space.\n" \ + "Optionally, you may provide a third argument to specify multiplier." def do_show_stream_list(self, line): '''Shows the loaded stream list named [name] \n''' diff --git a/scripts/stl/imix_1pkt.yaml b/scripts/stl/imix_1pkt.yaml index 128bd559..511f8695 100755 --- a/scripts/stl/imix_1pkt.yaml +++ b/scripts/stl/imix_1pkt.yaml @@ -4,7 +4,7 @@ stream: self_start: True packet: - binary: cap2/udp_64B_1pkt.pcap + binary: cap2/udp_64B.pcap mode: type: continuous pps: 100 diff --git a/scripts/stl/imix_2pkt.yaml b/scripts/stl/imix_2pkt.yaml new file mode 100755 index 00000000..17a7bdc1 --- /dev/null +++ b/scripts/stl/imix_2pkt.yaml @@ -0,0 +1,20 @@ +### Two-stream UDP packets, 64B and 594B ### +############################################ +- name: udp_64B + stream: + self_start: True + packet: + binary: cap2/udp_64B.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] +- name: udp_594B + stream: + self_start: True + packet: + binary: cap2/udp_594B.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] \ No newline at end of file diff --git a/scripts/stl/imix_3pkt.yaml b/scripts/stl/imix_3pkt.yaml new file mode 100755 index 00000000..d3923fb8 --- /dev/null +++ b/scripts/stl/imix_3pkt.yaml @@ -0,0 +1,29 @@ +### Three-stream UDP packets, 64B, 594B and 1518B ### +##################################################### +- name: udp_64B + stream: + self_start: True + packet: + binary: cap2/udp_64B.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] +- name: udp_594B + stream: + self_start: True + packet: + binary: cap2/udp_594B.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] +- name: udp_1518B + stream: + self_start: True + packet: + binary: cap2/udp_1518B.pcap + mode: + type: continuous + pps: 100 + rx_stats: [] \ No newline at end of file -- cgit 1.2.3-korg From 876c76572fdb2fb8f0e8db21bc420d284dc05950 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Wed, 21 Oct 2015 03:14:26 +0300 Subject: Added support for path autocomletion for console methods :) --- .../trex_control_plane/console/trex_console.py | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 27a5eeab..a9ac040b 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -23,7 +23,7 @@ import ast import argparse import random import string - +import os import sys import tty, termios import trex_root_path @@ -457,6 +457,26 @@ class TrexConsole(cmd.Cmd): print "please provide load name and YAML path, separated by space.\n" \ "Optionally, you may provide a third argument to specify multiplier." + @staticmethod + def tree_autocomplete(text): + dir = os.path.dirname(text) + if dir: + path = dir + else: + path = "." + start_string = os.path.basename(text) + return [x + for x in os.listdir(path) + if x.startswith(start_string)] + + + def complete_load_stream_list(self, text, line, begidx, endidx): + arg_num = len(line.split()) - 1 + if arg_num == 2: + return TrexConsole.tree_autocomplete(line.split()[-1]) + else: + return [text] + def do_show_stream_list(self, line): '''Shows the loaded stream list named [name] \n''' args = line.split() @@ -474,7 +494,7 @@ class TrexConsole(cmd.Cmd): print "\nAvailable stream lists:\n{0}".format(', '.join([x for x in self.user_streams.keys()])) - def complete_show_stream_list (self, text, line, begidx, endidx): + def complete_show_stream_list(self, text, line, begidx, endidx): return [x for x in self.user_streams.keys() if x.startswith(text)] -- cgit 1.2.3-korg