diff options
Diffstat (limited to 'scripts/automation/trex_control_plane/stl')
17 files changed, 489 insertions, 325 deletions
diff --git a/scripts/automation/trex_control_plane/stl/console/stl_path.py b/scripts/automation/trex_control_plane/stl/console/stl_path.py new file mode 100644 index 00000000..f15c666e --- /dev/null +++ b/scripts/automation/trex_control_plane/stl/console/stl_path.py @@ -0,0 +1,7 @@ +import sys, os + +# FIXME to the write path for trex_stl_lib +sys.path.insert(0, "../") + +STL_PROFILES_PATH = os.path.join(os.pardir, 'profiles') + diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index 8c71065c..da4c4486 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -30,14 +30,20 @@ import os import sys import tty, termios +try: + import stl_path +except: + from . import stl_path from trex_stl_lib.api import * from trex_stl_lib.utils.text_opts import * from trex_stl_lib.utils.common import user_input, get_current_user from trex_stl_lib.utils import parsing_opts - -from . import trex_tui +try: + import trex_tui +except: + from . import trex_tui from functools import wraps diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py index 56fd3cfd..bc7990aa 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py @@ -12,11 +12,12 @@ import argparse # and attach it to both sides and inject # at a certain rate for some time # finally it checks that all packets arrived -def imix_test (server): +def imix_test (server, mult): # create client c = STLClient(server = server) + passed = True @@ -27,6 +28,7 @@ def imix_test (server): # take all the ports c.reset() + # map ports - identify the routes table = stl_map_ports(c) @@ -37,7 +39,8 @@ def imix_test (server): print("Mapped ports to sides {0} <--> {1}".format(dir_0, dir_1)) # load IMIX profile - profile = STLProfile.load_py('../../../../stl/imix.py') + profile_file = os.path.join(stl_path.STL_PROFILES_PATH, 'imix.py') + profile = STLProfile.load_py(profile_file) streams = profile.get_streams() # add both streams to ports @@ -47,9 +50,8 @@ def imix_test (server): # clear the stats before injecting c.clear_stats() - # choose rate and start traffic for 10 seconds on 5 mpps + # choose rate and start traffic for 10 seconds duration = 10 - mult = "30%" print("Injecting {0} <--> {1} on total rate of '{2}' for {3} seconds".format(dir_0, dir_1, mult, duration)) c.start(ports = (dir_0 + dir_1), mult = mult, duration = duration, total = True) @@ -96,10 +98,8 @@ def imix_test (server): if passed: print("\nTest has passed :-)\n") - sys.exit(0) else: print("\nTest has failed :-(\n") - sys.exit(-1) parser = argparse.ArgumentParser(description="Example for TRex Stateless, sending IMIX traffic") parser.add_argument('-s', '--server', @@ -107,8 +107,13 @@ parser.add_argument('-s', '--server', help='Remote trex address', default='127.0.0.1', type = str) +parser.add_argument('-m', '--mult', + dest='mult', + help='Multiplier of traffic, see Stateless help for more info', + default='30%', + type = str) args = parser.parse_args() # run the tests -imix_test(args.server) +imix_test(args.server, args.mult) diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_imix_bidir.py b/scripts/automation/trex_control_plane/stl/examples/stl_imix_bidir.py index 05a8777b..956b910a 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_imix_bidir.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_imix_bidir.py @@ -29,14 +29,15 @@ def imix_test (server): # take all the ports c.reset() - dir_0 = [0] - dir_1 = [1] + dir_0 = [0] + dir_1 = [1] print "Mapped ports to sides {0} <--> {1}".format(dir_0, dir_1) # load IMIX profile - profile1 = STLProfile.load_py('../../../../stl/imix.py', direction=0) - profile2 = STLProfile.load_py('../../../../stl/imix.py', direction=1) + profile_file = os.path.join(stl_path.STL_PROFILES_PATH, 'imix.py') + profile1 = STLProfile.load_py(profile_file, direction=0) + profile2 = STLProfile.load_py(profile_file, direction=1) stream1 = profile1.get_streams() stream2 = profile2.get_streams() @@ -96,10 +97,8 @@ def imix_test (server): if passed: print "\nTest has passed :-)\n" - sys.exit(0) else: print "\nTest has failed :-(\n" - sys.exit(-1) parser = argparse.ArgumentParser(description="Example for TRex Stateless, sending IMIX traffic") parser.add_argument('-s', '--server', diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_path.py b/scripts/automation/trex_control_plane/stl/examples/stl_path.py index 8f400d23..f190aab1 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_path.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_path.py @@ -1,4 +1,7 @@ -import sys +import sys, os -# FIXME to the write path for trex_stl_lib +# FIXME to the right path for trex_stl_lib sys.path.insert(0, "../") + +STL_PROFILES_PATH = os.path.join(os.pardir, os.pardir, os.pardir, os.pardir, 'stl') + diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_profile.py b/scripts/automation/trex_control_plane/stl/examples/stl_profile.py index 3ae5f855..16d5238e 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_profile.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_profile.py @@ -18,8 +18,7 @@ def simple (): # prepare our ports c.reset(ports = my_ports) - - profile_file = "../../../../stl/udp_1pkt_simple.py" + profile_file = os.path.join(stl_path.STL_PROFILES_PATH, 'hlt', 'udp_1pkt_simple.py') try: profile = STLProfile.load(profile_file) diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_simple_console_like.py b/scripts/automation/trex_control_plane/stl/examples/stl_simple_console_like.py index 03909e65..1d4ef250 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_simple_console_like.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_simple_console_like.py @@ -29,9 +29,10 @@ def simple (): print(c.get_port_info(my_ports)) c.ping() + profile_file = os.path.join(stl_path.STL_PROFILES_PATH, 'udp_1pkt_simple.py') print("start") - c.start_line (" -f ../../../../stl/udp_1pkt_simple.py -m 10mpps --port 0 1 ") + c.start_line (" -f %s -m 10mpps --port 0 1 " % profile_file) time.sleep(2); c.pause_line("--port 0 1"); time.sleep(2); diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 25e35423..bddc4ad0 100644..100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -40,15 +40,15 @@ class LoggerApi(object): # implemented by specific logger def write(self, msg, newline = True): - raise Exception("implement this") + raise Exception("Implement this") # implemented by specific logger def flush(self): - raise Exception("implement this") + raise Exception("Implement this") def set_verbose (self, level): if not level in range(self.VERBOSE_QUIET, self.VERBOSE_HIGH + 1): - raise ValueError("bad value provided for logger") + raise ValueError("Bad value provided for logger") self.level = level @@ -146,7 +146,7 @@ class AsyncEventHandler(object): def on_async_dead (self): if self.client.connected: - msg = 'lost connection to server' + msg = 'Lost connection to server' self.__add_event_log(msg, 'local', True) self.client.connected = False @@ -319,12 +319,12 @@ class AsyncEventHandler(object): ############################ ############################# class CCommLink(object): - """describes the connectivity of the stateless client method""" - def __init__(self, server="localhost", port=5050, virtual=False, prn_func = None): + """Describes the connectivity of the stateless client method""" + def __init__(self, server="localhost", port=5050, virtual=False, client = None): self.virtual = virtual self.server = server self.port = port - self.rpc_link = JsonRpcClient(self.server, self.port, prn_func) + self.rpc_link = JsonRpcClient(self.server, self.port, client) @property def is_connected(self): @@ -347,25 +347,25 @@ class CCommLink(object): if not self.virtual: return self.rpc_link.disconnect() - def transmit(self, method_name, params={}): + def transmit(self, method_name, params = None, api_class = 'core'): if self.virtual: self._prompt_virtual_tx_msg() - _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) + _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params, api_class) print(msg) return else: - return self.rpc_link.invoke_rpc_method(method_name, params) + return self.rpc_link.invoke_rpc_method(method_name, params, api_class) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print([msg - for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params) + for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params, command.api_class) for command in batch_list]]) else: batch = self.rpc_link.create_batch() for command in batch_list: - batch.add(command.method, command.params) + batch.add(command.method, command.params, command.api_class) # invoke the batch return batch.invoke() @@ -380,7 +380,7 @@ class CCommLink(object): ############################ ############################# class STLClient(object): - """TRex Stateless client object- gives operations per TRex/user""" + """TRex Stateless client object - gives operations per TRex/user""" def __init__(self, username = common.get_current_user(), @@ -391,7 +391,7 @@ class STLClient(object): logger = None, virtual = False): """ - Set the connection setting + Configure the connection settings :parameters: username : string @@ -449,7 +449,7 @@ class STLClient(object): self.comm_link = CCommLink(server, sync_port, virtual, - self.logger) + self) # async event handler manager self.event_handler = AsyncEventHandler(self) @@ -481,7 +481,11 @@ class STLClient(object): self.flow_stats) - + # API classes + self.api_vers = [ {'type': 'core', 'major': 1, 'minor':0 } + ] + self.api_h = {'core': None} + ############# private functions - used by the class itself ########### # some preprocessing for port argument @@ -496,11 +500,11 @@ class STLClient(object): port_id_list = [port_id_list] if not isinstance(port_id_list, list): - raise ValueError("bad port id list: {0}".format(port_id_list)) + raise ValueError("Bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()): - raise ValueError("bad port id {0}".format(port_id)) + raise ValueError("Bad port id {0}".format(port_id)) return port_id_list @@ -668,6 +672,7 @@ class STLClient(object): return rc + # connect to server def __connect(self): @@ -686,12 +691,22 @@ class STLClient(object): if not rc: return rc + + # API sync + rc = self._transmit("api_sync", params = {'api_vers': self.api_vers}, api_class = None) + if not rc: + return rc + + # decode + for api in rc.data()['api_vers']: + self.api_h[ api['type'] ] = api['api_h'] + + # version rc = self._transmit("get_version") if not rc: return rc - self.server_version = rc.data() self.global_stats.server_version = rc.data() @@ -727,7 +742,7 @@ class STLClient(object): # connect async channel - self.logger.pre_cmd("connecting to publisher server on {0}:{1}".format(self.connection_info['server'], self.connection_info['async_port'])) + self.logger.pre_cmd("Connecting to publisher server on {0}:{1}".format(self.connection_info['server'], self.connection_info['async_port'])) rc = self.async_client.connect() self.logger.post_cmd(rc) @@ -765,7 +780,7 @@ class STLClient(object): if clear_flow_stats: self.flow_stats.clear_stats() - self.logger.log_cmd("clearing stats on port(s) {0}:".format(port_id_list)) + self.logger.log_cmd("Clearing stats on port(s) {0}:".format(port_id_list)) return RC @@ -817,8 +832,8 @@ class STLClient(object): # transmit request on the RPC link - def _transmit(self, method_name, params={}): - return self.comm_link.transmit(method_name, params) + def _transmit(self, method_name, params = None, api_class = 'core'): + return self.comm_link.transmit(method_name, params, api_class) # transmit batch request on the RPC link def _transmit_batch(self, batch_list): @@ -852,8 +867,26 @@ class STLClient(object): return RC_OK() - - + # remove all RX filters in a safe manner + def _remove_rx_filters (self, ports, rx_delay_ms): + + # get the enabled RX ports + rx_ports = [port_id for port_id in ports if self.ports[port_id].has_rx_enabled()] + + if not rx_ports: + return RC_OK() + + # block while any RX configured port has not yet have it's delay expired + while any([not self.ports[port_id].has_rx_delay_expired(rx_delay_ms) for port_id in rx_ports]): + time.sleep(0.01) + + # remove RX filters + rc = RC() + for port_id in rx_ports: + rc.add(self.ports[port_id].remove_rx_filters()) + + return rc + ################################# # ------ private methods ------ # @@ -914,13 +947,13 @@ class STLClient(object): # return verbose level of the logger def get_verbose (self): """ - get the verbose mode + Get the verbose mode :parameters: none :return: - get the verbose mode as Bool + Get the verbose mode as Bool :raises: None @@ -934,10 +967,10 @@ class STLClient(object): is_all_ports_acquired :parameters: - none + None :return: - return True if all ports are acquired + Returns True if all ports are acquired :raises: None @@ -951,7 +984,7 @@ class STLClient(object): """ :parameters: - none + None :return: is_connected @@ -969,10 +1002,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -987,10 +1020,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -1004,10 +1037,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -1021,10 +1054,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -1038,10 +1071,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -1065,10 +1098,10 @@ class STLClient(object): """ :parameters: - none + None :return: - connection dict + Connection dict :raises: None @@ -1089,6 +1122,7 @@ class STLClient(object): for port_id, port_obj in self.ports.items() if port_obj.is_active()] + # get paused ports def get_paused_ports (self): return [port_id @@ -1189,9 +1223,9 @@ class STLClient(object): :parameters: stop_traffic : bool - tries to stop traffic before disconnecting + Attempts to stop traffic before disconnecting. release_ports : bool - tries to release all the acquired ports + Attempts to release all the acquired ports. """ @@ -1217,9 +1251,9 @@ class STLClient(object): :parameters: ports : list - ports to execute the command + Ports on which to execute the command force : bool - force acquire the ports + Force acquire the ports. :raises: + :exc:`STLError` @@ -1252,7 +1286,7 @@ class STLClient(object): :parameters: ports : list - ports to execute the command + Ports on which to execute the command :raises: + :exc:`STLError` @@ -1285,7 +1319,7 @@ class STLClient(object): self.logger.pre_cmd( "Pinging the server on '{0}' port '{1}': ".format(self.connection_info['server'], self.connection_info['sync_port'])) - rc = self._transmit("ping") + rc = self._transmit("ping", api_class = None) self.logger.post_cmd(rc) @@ -1295,7 +1329,7 @@ class STLClient(object): @__api_check(True) def get_active_pgids(self): """ - Get active group ids + Get active group IDs :parameters: None @@ -1319,11 +1353,11 @@ class STLClient(object): @__api_check(True) def reset(self, ports = None): """ - force acquire ports, stop the traffic, remove all streams and clear stats + Force acquire ports, stop the traffic, remove all streams and clear stats :parameters: ports : list - ports to execute the command + Ports on which to execute the command :raises: @@ -1336,7 +1370,7 @@ class STLClient(object): ports = self._validate_port_list(ports) self.acquire(ports, force = True) - self.stop(ports) + self.stop(ports, rx_delay_ms = 0) self.remove_all_streams(ports) self.clear_stats(ports) @@ -1348,7 +1382,7 @@ class STLClient(object): :parameters: ports : list - ports to execute the command + Ports on which to execute the command :raises: @@ -1371,16 +1405,16 @@ class STLClient(object): @__api_check(True) def add_streams (self, streams, ports = None): """ - add a list of streams to port(s) + Add a list of streams to port(s) :parameters: ports : list - ports to execute the command + Ports on which to execute the command streams: list - streams to attach (or profile) + Streams to attach (or profile) :returns: - list of stream IDs in order of the stream list + List of stream IDs in order of the stream list :raises: + :exc:`STLError` @@ -1416,13 +1450,13 @@ class STLClient(object): @__api_check(True) def remove_streams (self, stream_id_list, ports = None): """ - remove a list of streams from ports + Remove a list of streams from ports :parameters: ports : list - ports to execute the command + Ports on which to execute the command stream_id_list: list - stream id list to remove + Stream id list to remove :raises: @@ -1460,27 +1494,29 @@ class STLClient(object): duration = -1, total = False): """ - start traffic on port(s) + Start traffic on port(s) :parameters: ports : list - ports to execute command + Ports on which to execute the command mult : str - multiplier in a form of pps, bps, or line util in % - examples: "5kpps", "10gbps", "85%", "32mbps" + Multiplier in a form of pps, bps, or line util in % + Examples: "5kpps", "10gbps", "85%", "32mbps" force : bool - imply stopping the port of active and also - forces a profile that exceeds the L1 BW + If the ports are not in stopped mode or do not have sufficient bandwidth for the traffic, determines whether to stop the current traffic and force start. + True: Force start + False: Do not force start duration : int - limit the run for time in seconds - -1 means unlimited + Limit the run time (seconds) + -1 = unlimited total : bool - should the B/W be divided by the ports - or duplicated for each + Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port. + True: Divide bandwidth among the ports + False: Duplicate :raises: @@ -1535,13 +1571,20 @@ class STLClient(object): @__api_check(True) - def stop (self, ports = None): + def stop (self, ports = None, rx_delay_ms = 10): """ - stop port(s) + Stop port(s) :parameters: ports : list - ports to execute the command + Ports on which to execute the command + + rx_delay_ms : int + time to wait until RX filters are removed + this value should reflect the time it takes + packets which were transmitted to arrive + to the destination. + after this time the RX filters will be removed :raises: + :exc:`STLError` @@ -1561,27 +1604,35 @@ class STLClient(object): if not rc: raise STLError(rc) + # remove any RX filters + rc = self._remove_rx_filters(ports, rx_delay_ms = rx_delay_ms) + if not rc: + raise STLError(rc) + @__api_check(True) def update (self, ports = None, mult = "1", total = False, force = False): """ - update traffic on port(s) + Update traffic on port(s) :parameters: ports : list - ports to execute command + Ports on which to execute the command mult : str - multiplier in a form of pps, bps, or line util in % - and also with +/- - examples: "5kpps+", "10gbps-", "85%", "32mbps", "20%+" + Multiplier in a form of pps, bps, or line util in % + Can also specify +/- + Examples: "5kpps+", "10gbps-", "85%", "32mbps", "20%+" force : bool - forces a profile that exceeds the L1 BW + If the ports are not in stopped mode or do not have sufficient bandwidth for the traffic, determines whether to stop the current traffic and force start. + True: Force start + False: Do not force start total : bool - should the B/W be divided by the ports - or duplicated for each + Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port. + True: Divide bandwidth among the ports + False: Duplicate :raises: @@ -1619,11 +1670,11 @@ class STLClient(object): @__api_check(True) def pause (self, ports = None): """ - pause traffic on port(s). works only for ports that are active and all streams are in cont mode + Pause traffic on port(s). Works only for ports that are active, and only if all streams are in Continuous mode. :parameters: ports : list - ports to execute command + Ports on which to execute the command :raises: + :exc:`STLError` @@ -1644,11 +1695,11 @@ class STLClient(object): @__api_check(True) def resume (self, ports = None): """ - resume traffic on port(s) + Resume traffic on port(s) :parameters: ports : list - ports to execute command + Ports on which to execute the command :raises: + :exc:`STLError` @@ -1671,23 +1722,24 @@ class STLClient(object): @__api_check(True) def validate (self, ports = None, mult = "1", duration = "-1", total = False): """ - validate port(s) configuration + Validate port(s) configuration :parameters: ports : list - ports to execute command + Ports on which to execute the command mult : str - multiplier in a form of pps, bps, or line util in % - examples: "5kpps", "10gbps", "85%", "32mbps" + Multiplier in a form of pps, bps, or line util in % + Examples: "5kpps", "10gbps", "85%", "32mbps" duration : int - limit the run for time in seconds - -1 means unlimited + Limit the run time (seconds) + -1 = unlimited total : bool - should the B/W be divided by the ports - or duplicated for each + Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port. + True: Divide bandwidth among the ports + False: Duplicate :raises: + :exc:`STLError` @@ -1723,17 +1775,17 @@ class STLClient(object): @__api_check(False) def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True): """ - clear stats on port(s) + Clear stats on port(s) :parameters: ports : list - ports to execute command + Ports on which to execute the command clear_global : bool - clear the global stats + Clear the global stats clear_flow_stats : bool - clear the flow stats + Clear the flow stats :raises: + :exc:`STLError` @@ -1757,11 +1809,11 @@ class STLClient(object): @__api_check(True) def is_traffic_active (self, ports = None): """ - retrun if specify port(s) has traffic + Return if specified port(s) have traffic :parameters: ports : list - ports to execute command + Ports on which to execute the command :raises: @@ -1778,17 +1830,25 @@ class STLClient(object): @__api_check(True) - def wait_on_traffic (self, ports = None, timeout = 60): + def wait_on_traffic (self, ports = None, timeout = 60, rx_delay_ms = 10): """ - block until specify port(s) traffic has ended + Block until traffic on specified port(s) has ended :parameters: ports : list - ports to execute command + Ports on which to execute the command timeout : int timeout in seconds + rx_delay_ms : int + time to wait until RX filters are removed + this value should reflect the time it takes + packets which were transmitted to arrive + to the destination. + after this time the RX filters will be removed + + :raises: + :exc:`STLTimeoutError` - in case timeout has expired + :exe:'STLError' @@ -1807,14 +1867,19 @@ class STLClient(object): if time.time() > expr: raise STLTimeoutError(timeout) + # remove any RX filters + rc = self._remove_rx_filters(ports, rx_delay_ms = rx_delay_ms) + if not rc: + raise STLError(rc) + @__api_check(True) def set_port_attr (self, ports = None, promiscuous = None): """ - set port(s) attributes + Set port attributes :parameters: - promiscuous - set this to True or False + promiscuous - True or False :raises: None @@ -1825,7 +1890,7 @@ class STLClient(object): ports = self._validate_port_list(ports) # check arguments - validate_type('promiscuous', promiscuous, (bool, NoneType)) + validate_type('promiscuous', promiscuous, (bool, type(None))) # build attributes attr_dict = {} @@ -1845,7 +1910,7 @@ class STLClient(object): def clear_events (self): """ - clear all events + Clear all events :parameters: None @@ -1921,7 +1986,7 @@ class STLClient(object): @__console def start_line (self, line): - '''Start selected traffic in specified ports on TRex\n''' + '''Start selected traffic on specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser(self, "start", @@ -2008,7 +2073,7 @@ class STLClient(object): @__console def stop_line (self, line): - '''Stop active traffic in specified ports on TRex\n''' + '''Stop active traffic on specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.stop_line.__doc__, @@ -2061,7 +2126,7 @@ class STLClient(object): @__console def pause_line (self, line): - '''Pause active traffic in specified ports on TRex\n''' + '''Pause active traffic on specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.pause_line.__doc__, @@ -2086,7 +2151,7 @@ class STLClient(object): @__console def resume_line (self, line): - '''Resume active traffic in specified ports on TRex\n''' + '''Resume active traffic on specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.resume_line.__doc__, @@ -2130,7 +2195,7 @@ class STLClient(object): @__console def show_stats_line (self, line): - '''Fetch statistics from TRex server by port\n''' + '''Get statistics from TRex server by port\n''' # define a parser parser = parsing_opts.gen_parser(self, "stats", @@ -2161,7 +2226,7 @@ class STLClient(object): @__console def show_streams_line(self, line): - '''Fetch streams statistics from TRex server by port\n''' + '''Get stream statistics from TRex server by port\n''' # define a parser parser = parsing_opts.gen_parser(self, "streams", @@ -2190,7 +2255,7 @@ class STLClient(object): @__console def validate_line (self, line): - '''validates port(s) stream configuration\n''' + '''Validates port(s) stream configuration\n''' parser = parsing_opts.gen_parser(self, "validate", @@ -2208,7 +2273,7 @@ class STLClient(object): @__console def push_line (self, line): - '''Push a PCAP file ''' + '''Push a pcap file ''' parser = parsing_opts.gen_parser(self, "push", diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_ext.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_ext.py index d6d66ec3..ed0c393d 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_ext.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_ext.py @@ -9,7 +9,7 @@ TREX_STL_EXT_PATH = os.environ.get('TREX_STL_EXT_PATH') # take default if not TREX_STL_EXT_PATH or not os.path.exists(TREX_STL_EXT_PATH): CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) - TREX_STL_EXT_PATH = os.path.normpath(os.path.join(CURRENT_PATH, os.pardir, 'external_libs')) + TREX_STL_EXT_PATH = os.path.normpath(os.path.join(CURRENT_PATH, os.pardir, os.pardir, 'external_libs')) if not os.path.exists(TREX_STL_EXT_PATH): # ../../../../external_libs TREX_STL_EXT_PATH = os.path.normpath(os.path.join(CURRENT_PATH, os.pardir, os.pardir, os.pardir, os.pardir, 'external_libs')) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py index 166fd64e..bd5ba8e7 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py @@ -26,9 +26,9 @@ class BatchMessage(object): self.rpc_client = rpc_client self.batch_list = [] - def add (self, method_name, params={}): + def add (self, method_name, params = None, api_class = 'core'): - id, msg = self.rpc_client.create_jsonrpc_v2(method_name, params, encode = False) + id, msg = self.rpc_client.create_jsonrpc_v2(method_name, params, api_class, encode = False) self.batch_list.append(msg) def invoke(self, block = False): @@ -46,8 +46,9 @@ class JsonRpcClient(object): MSG_COMPRESS_THRESHOLD = 4096 MSG_COMPRESS_HEADER_MAGIC = 0xABE85CEA - def __init__ (self, default_server, default_port, logger): - self.logger = logger + def __init__ (self, default_server, default_port, client): + self.client = client + self.logger = client.logger self.connected = False # default values @@ -93,14 +94,18 @@ class JsonRpcClient(object): def create_batch (self): return BatchMessage(self) - def create_jsonrpc_v2 (self, method_name, params = {}, encode = True): + def create_jsonrpc_v2 (self, method_name, params = None, api_class = 'core', encode = True): msg = {} msg["jsonrpc"] = "2.0" msg["method"] = method_name + msg["id"] = next(self.id_gen) - msg["params"] = params + msg["params"] = params if params is not None else {} - msg["id"] = next(self.id_gen) + # if this RPC has an API class - add it's handler + if api_class: + msg["params"]["api_h"] = self.client.api_h[api_class] + if encode: return id, json.dumps(msg) @@ -108,11 +113,11 @@ class JsonRpcClient(object): return id, msg - def invoke_rpc_method (self, method_name, params = {}): + def invoke_rpc_method (self, method_name, params = None, api_class = 'core'): if not self.connected: return RC_ERR("Not connected to server") - id, msg = self.create_jsonrpc_v2(method_name, params) + id, msg = self.create_jsonrpc_v2(method_name, params, api_class) return self.send_msg(msg) @@ -273,7 +278,7 @@ class JsonRpcClient(object): self.connected = True - rc = self.invoke_rpc_method('ping') + rc = self.invoke_rpc_method('ping', api_class = None) if not rc: self.connected = False return rc diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py index a7064853..f8517a47 100644..100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py @@ -35,7 +35,7 @@ def safe_ord (c): elif type(c) is int: return c else: - raise TypeError("cannot convert: {0} of type: {1}".format(c, type(c))) + raise TypeError("Cannot convert: {0} of type: {1}".format(c, type(c))) def _buffer_to_num(str_buffer): validate_type('str_buffer', str_buffer, bytes) @@ -48,18 +48,18 @@ def _buffer_to_num(str_buffer): def ipv4_str_to_num (ipv4_buffer): validate_type('ipv4_buffer', ipv4_buffer, bytes) - assert len(ipv4_buffer)==4, 'size of ipv4_buffer is not 4' + assert len(ipv4_buffer)==4, 'Size of ipv4_buffer is not 4' return _buffer_to_num(ipv4_buffer) def mac_str_to_num (mac_buffer): validate_type('mac_buffer', mac_buffer, bytes) - assert len(mac_buffer)==6, 'size of mac_buffer is not 6' + assert len(mac_buffer)==6, 'Size of mac_buffer is not 6' return _buffer_to_num(mac_buffer) def is_valid_ipv4(ip_addr): """ - return buffer in network order + Return buffer in network order """ if type(ip_addr) == bytes and len(ip_addr) == 4: return ip_addr @@ -72,12 +72,12 @@ def is_valid_ipv4(ip_addr): except AttributeError: # no inet_pton here, sorry return socket.inet_aton(ip_addr) except socket.error: # not a valid address - raise CTRexPacketBuildException(-10,"not valid ipv4 format"); + raise CTRexPacketBuildException(-10,"Not valid ipv4 format"); def is_valid_ipv6(ipv6_addr): """ - return buffer in network order + Return buffer in network order """ if type(ipv6_addr) == bytes and len(ipv6_addr) == 16: return ipv6_addr @@ -107,12 +107,12 @@ class CTRexScFieldRangeBase(CTRexScriptsBase): self.field_name =field_name self.field_type =field_type if not self.field_type in CTRexScFieldRangeBase.FILED_TYPES : - raise CTRexPacketBuildException(-12, 'field type should be in %s' % FILED_TYPES); + raise CTRexPacketBuildException(-12, 'Field type should be in %s' % FILED_TYPES); class CTRexScFieldRangeValue(CTRexScFieldRangeBase): """ - range of field value + Range of field values """ def __init__(self, field_name, field_type, @@ -123,14 +123,14 @@ class CTRexScFieldRangeValue(CTRexScFieldRangeBase): self.min_value =min_value; self.max_value =max_value; if min_value > max_value: - raise CTRexPacketBuildException(-12, 'min is greater than max'); + raise CTRexPacketBuildException(-12, 'Invalid range: min is greater than max.'); if min_value == max_value: - raise CTRexPacketBuildException(-13, "min value is equal to max value, you can't use this type of range"); + raise CTRexPacketBuildException(-13, "Invalid range: min value is equal to max value."); class CTRexScIpv4SimpleRange(CTRexScFieldRangeBase): """ - range of ipv4 ip + Range of ipv4 ip """ def __init__(self, field_name, field_type, min_ip, max_ip): super(CTRexScIpv4SimpleRange, self).__init__(field_name,field_type) @@ -144,7 +144,7 @@ class CTRexScIpv4SimpleRange(CTRexScFieldRangeBase): class CTRexScIpv4TupleGen(CTRexScriptsBase): """ - range tuple + Range tuple """ FLAGS_ULIMIT_FLOWS =1 @@ -166,7 +166,7 @@ class CTRexScIpv4TupleGen(CTRexScriptsBase): class CTRexScTrimPacketSize(CTRexScriptsBase): """ - trim packet size. field type is CTRexScFieldRangeBase.FILED_TYPES = ["inc","dec","rand"] + Trim packet size. Field type is CTRexScFieldRangeBase.FILED_TYPES = ["inc","dec","rand"] """ def __init__(self,field_type="rand",min_pkt_size=None, max_pkt_size=None): super(CTRexScTrimPacketSize, self).__init__() @@ -183,11 +183,11 @@ class CTRexScTrimPacketSize(CTRexScriptsBase): class STLScVmRaw(CTRexScriptsBase): """ - raw instructions + Raw instructions """ def __init__(self,list_of_commands=None,split_by_field=None): """ - include a list of a basic instructions objects + Include a list of a basic instructions objects. :parameters: list_of_commands : list @@ -197,7 +197,7 @@ class STLScVmRaw(CTRexScriptsBase): by which field to split to threads - The following example will split the generated traffic by "ip_src" variable + The following example splits the generated traffic by "ip_src" variable. .. code-block:: python :caption: Split by @@ -241,7 +241,7 @@ class STLScVmRaw(CTRexScriptsBase): class CTRexVmInsBase(object): """ - instruction base + Instruction base """ def __init__(self, ins_type): self.type = ins_type @@ -334,7 +334,7 @@ class CTRexVmEngine(object): def __init__(self): """ - inlcude list of instruction + Inlcude list of instructions. """ super(CTRexVmEngine, self).__init__() self.ins=[] @@ -390,7 +390,7 @@ class CTRexScapyPktUtl(object): def get_pkt_layers(self): """ - return string 'IP:UDP:TCP' + Return string 'IP:UDP:TCP' """ l=self.get_list_iter (); l1=map(lambda p: p.name,l ); @@ -398,7 +398,7 @@ class CTRexScapyPktUtl(object): def _layer_offset(self, name, cnt = 0): """ - return offset of layer e.g 'IP',1 will return offfset of layer ip:1 + Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1 """ save_cnt=cnt for pkt in self.pkt_iter (): @@ -413,7 +413,7 @@ class CTRexScapyPktUtl(object): def layer_offset(self, name, cnt = 0): """ - return offset of layer e.g 'IP',1 will return offfset of layer ip:1 + Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1 """ save_cnt=cnt for pkt in self.pkt_iter (): @@ -427,7 +427,7 @@ class CTRexScapyPktUtl(object): def get_field_offet(self, layer, layer_cnt, field_name): """ - return offset of layer e.g 'IP',1 will return offfset of layer ip:1 + Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1 """ t=self._layer_offset(layer,layer_cnt); l_offset=t[1]; @@ -439,11 +439,11 @@ class CTRexScapyPktUtl(object): if f.name == field_name: return (l_offset+f.offset,f.get_size_bytes ()); - raise CTRexPacketBuildException(-11, "no layer %s-%d." % (name, save_cnt, field_name)); + raise CTRexPacketBuildException(-11, "No layer %s-%d." % (name, save_cnt, field_name)); def get_layer_offet_by_str(self, layer_des): """ - return layer offset by string + Return layer offset by string. :parameters: @@ -469,21 +469,21 @@ class CTRexScapyPktUtl(object): def get_field_offet_by_str(self, field_des): """ - return field_des (offset,size) layer:cnt.field - for example + Return field_des (offset,size) layer:cnt.field + Example: 802|1Q.vlan get 802.1Q->valn replace | with . IP.src IP:0.src (first IP.src like IP.src) - for example IP:1.src for internal IP + Example: IP:1.src for internal IP - return (offset, size) as tuple + Return (offset, size) as tuple. """ s=field_des.split("."); if len(s)!=2: - raise CTRexPacketBuildException(-11, ("field desription should be layer:cnt.field e.g IP.src or IP:1.src")); + raise CTRexPacketBuildException(-11, ("Field desription should be layer:cnt.field Example: IP.src or IP:1.src")); layer_ex = s[0].replace("|",".") @@ -514,7 +514,7 @@ class CTRexScapyPktUtl(object): class CTRexVmDescBase(object): """ - instruction base + Instruction base """ def __init__(self): pass; @@ -534,37 +534,37 @@ class CTRexVmDescBase(object): def get_var_ref (self): ''' - virtual function return a ref var name + Virtual function returns a ref var name. ''' return None def get_var_name(self): ''' - virtual function return the varible name if exists + Virtual function returns the varible name if it exists. ''' return None def compile(self,parent): ''' - virtual function to take parent than has function name_to_offset + Virtual function to take parent that has function name_to_offset. ''' pass; def valid_fv_size (size): if not (size in CTRexVmInsFlowVar.VALID_SIZES): - raise CTRexPacketBuildException(-11,("flow var has not valid size %d ") % size ); + raise CTRexPacketBuildException(-11,("Flow var has invalid size %d ") % size ); def valid_fv_ops (op): if not (op in CTRexVmInsFlowVar.OPERATIONS): - raise CTRexPacketBuildException(-11,("flow var does not have a valid op %s ") % op ); + raise CTRexPacketBuildException(-11,("Flow var has invalid op %s ") % op ); def convert_val (val): if is_integer(val): return val if type(val) == str: return ipv4_str_to_num (is_valid_ipv4(val)) - raise CTRexPacketBuildException(-11,("init val not valid %s ") % val ); + raise CTRexPacketBuildException(-11,("init val invalid %s ") % val ); def check_for_int (val): validate_type('val', val, int) @@ -574,31 +574,32 @@ class STLVmFlowVar(CTRexVmDescBase): def __init__(self, name, init_value=None, min_value=0, max_value=255, size=4, step=1,op="inc"): """ - Flow variable instruction. Allocate a variable on a stream context. The size of the variable could be determined - The operation can be inc, dec and random. In case of increment and decrement operation, it is possible to set the "step" size. - Initialization value, minimum and maximum value could be set too. + Flow variable instruction. Allocates a variable on a stream context. The size argument determines the variable size. + The operation can be inc, dec, and random. + For increment and decrement operations, can set the "step" size. + For all operations, can set initialization value, minimum and maximum value. :parameters: name : string - The name of the stream variable + Name of the stream variable init_value : int - The init value of the variable. in case of None it will be min_value + Init value of the variable. If not specified, it will be min_value min_value : int - The min value + Min value max_value : int - The max value + Max value size : int - the number of bytes of the variable. could be 1,2,4,8 for uint8_t, uint16_t, uint32_t, uint64_t + Number of bytes of the variable. Possible values: 1,2,4,8 for uint8_t, uint16_t, uint32_t, uint64_t step : int - step in case of "inc","dec" operation + Step in case of "inc" or "dec" operations op : string - could be "inc", "dec", "random" + Possible values: "inc", "dec", "random" .. code-block:: python :caption: Example1 @@ -657,7 +658,7 @@ class STLVmFlowVar(CTRexVmDescBase): class STLVmFixIpv4(CTRexVmDescBase): def __init__(self, offset): """ - Fix IPv4 header checksum. should be added if the packet header was changed and there is a need to fix he checksum + Fix IPv4 header checksum. Use this if the packet header has changed and it is necessary to change the checksum. :parameters: offset : uint16_t or string @@ -694,26 +695,28 @@ class STLVmWrFlowVar(CTRexVmDescBase): def __init__(self, fv_name, pkt_offset, offset_fixup=0, add_val=0, is_big=True): """ Write a stream variable into a packet field. - The write is done in size of the stream variable. - In case there is a need to change the write have a look into the command `STLVmWrMaskFlowVar`. - The Field name/offset can be given by name in this format ``header[:id].field``. + The write position is determined by the packet offset + offset fixup. The size of the write is determined by the stream variable. + Example: Offset 10, fixup 0, variable size 4. This function writes at 10, 11, 12, and 13. + + For inromation about chaning the write size, offset, or fixup, see the `STLVmWrMaskFlowVar` command. + The Field name/offset can be given by name in the following format: ``header[:id].field``. :parameters: fv_name : string - the stream variable to write to a packet offset + Stream variable to write to a packet offset. pkt_offset : string or in - the name of the field or offset in byte from packet start. + Name of the field or offset in bytes from packet start. offset_fixup : int - how many bytes to go forward. In case of a negative value go backward + Number of bytes to move forward. If negative, move backward. add_val : int - value to add to stream variable before writing it to packet field. can be used as a constant offset + Value to add to the stream variable before writing it to the packet field. Can be used as a constant offset. is_big : bool - how to write the variable to the the packet. is it big-edian or little edian + How to write the variable to the the packet. True=big-endian, False=little-endian .. code-block:: python :caption: Example3 @@ -759,7 +762,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase): """ Write a stream variable into a packet field with some operations. - Using this instruction the variable size and the field could be with different size. + Using this instruction, the variable size and the field can have different sizes. Pseudocode of this code:: @@ -805,7 +808,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase): is_big : bool how to write the variable to the the packet. is it big-edian or little edian - Example 1- casting from uint16_t (var) to uint8_t (pkt):: + Example 1 - Cast from uint16_t (var) to uint8_t (pkt):: base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) @@ -824,7 +827,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase): pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) - Example 2- change MSB of uint16_t variable:: + Example 2 - Change MSB of uint16_t variable:: vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", @@ -841,7 +844,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase): - Example 3- Every 2 packet change the MAC (shift right):: + Example 3 - Every 2 packets, change the MAC (shift right):: vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", min_value=1, @@ -893,12 +896,12 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase): class STLVmTrimPktSize(CTRexVmDescBase): """ - Trim packet size by stream variable size. This instruction will only change the total packet size and will not fix up the fields to match the new size. + Trim the packet size by the stream variable size. This instruction only changes the total packet size, and does not repair the fields to match the new size. :parameters: fv_name : string - the stream variable name. the value from this variable would be the new total packet size. + Stream variable name. The value of this variable is the new total packet size. For Example:: @@ -959,8 +962,8 @@ class STLVmTrimPktSize(CTRexVmDescBase): class STLVmTupleGen(CTRexVmDescBase): def __init__(self,name, ip_min="0.0.0.1", ip_max="0.0.0.10", port_min=1025, port_max=65535, limit_flows=100000, flags=0): """ - Generate a struct with two varibles. ``var_name.ip`` as uint32_t and ``var_name.port`` as uint16_t - The variable are dependent. When the ip variable is wrapped the port is getting increment. + Generate a struct with two variables: ``var_name.ip`` as uint32_t and ``var_name.port`` as uint16_t + The variables are dependent. When the ip variable value reaches its maximum, the port is incremented. For: @@ -1001,22 +1004,22 @@ class STLVmTupleGen(CTRexVmDescBase): :parameters: name : string - The name of the stream struct. + Name of the stream struct. ip_min : string or int - The min value of the ip value. It can be in IPv4 format + Min value of the ip value. Number or IPv4 format. ip_max : string or int - The max value of the ip value. It can be in IPv4 format + Max value of the ip value. Number or IPv4 format. port_min : int - min value for port variable + Min value of port variable. port_max : int - max value for port variable + Max value of port variable. limit_flows : int - The limit of number of flows + Limit of number of flows. flags : 0 @@ -1093,10 +1096,10 @@ class STLPktBuilder(CTrexPktBuilderInterface): def __init__(self, pkt = None, pkt_buffer = None, vm = None, path_relative_to_profile = False, build_raw = False, remove_fcs = True): """ - This class defines a way to build a template packet, and Field Engine using scapy package. - Using this class the user can also define how TRex will handle the packet by specifying the Field engine setting. - pkt could be Scapy pkt or pcap file name - When path_relative_to_profile is a True load pcap file from a path relative to the profile + This class defines a method for building a template packet and Field Engine using the Scapy package. + Using this class the user can also define how TRex will handle the packet by specifying the Field engine settings. + The pkt can be a Scapy pkt or pcap file name. + If using a pcap file, and path_relative_to_profile is True, then the function loads the pcap file from a path relative to the profile. .. code-block:: python @@ -1134,22 +1137,22 @@ class STLPktBuilder(CTrexPktBuilderInterface): :parameters: pkt : string, - Scapy or pcap file filename a scapy packet + Scapy object or pcap filename. pkt_buffer : bytes - a packet as buffer + Packet as buffer. vm : list or base on :class:`trex_stl_lib.trex_stl_packet_builder_scapy.STLScVmRaw` - a list of instructions to manipolate packet fields + List of instructions to manipulate packet fields. path_relative_to_profile : bool - in case pkt is pcap file, do we want to load it relative to profile file + If pkt is a pcap file, determines whether to load it relative to profile file. build_raw : bool - Do we want to build scapy in case buffer was given. good for cases we want offset to be taken from scapy + If a buffer is specified (by pkt_buffer), determines whether to build Scapy. Useful in cases where it is necessary to take the offset from Scapy. remove_fcs : bool - in case of buffer do we want to remove fcs + If a buffer is specified (by pkt_buffer), determines whether to remove FCS. @@ -1171,7 +1174,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): if pkt != None and pkt_buffer != None: - raise CTRexPacketBuildException(-15, "packet builder cannot be provided with both pkt and pkt_buffer") + raise CTRexPacketBuildException(-15, "Packet builder cannot be provided with both pkt and pkt_buffer.") # process packet if pkt != None: @@ -1183,7 +1186,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): # process VM if vm != None: if not isinstance(vm, (STLScVmRaw, list)): - raise CTRexPacketBuildException(-14, "bad value for variable vm") + raise CTRexPacketBuildException(-14, "Bad value for variable vm.") self.add_command(vm if isinstance(vm, STLScVmRaw) else STLScVmRaw(vm)) @@ -1219,7 +1222,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): def dump_pkt(self, encode = True): """ - Dumps the packet as a decimal array of bytes (each item x gets value between 0-255) + Dumps the packet as a decimal array of bytes (each item x gets value in range 0-255) :parameters: encode : bool @@ -1254,7 +1257,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): def pkt_layers_desc (self): """ - return layer description like this IP:TCP:Pyload + Return layer description in this format: IP:TCP:Pyload """ pkt_buf = self._get_pkt_as_str() @@ -1274,13 +1277,13 @@ class STLPktBuilder(CTrexPktBuilderInterface): def set_pcap_file (self, pcap_file): """ - load raw pcap file into a buffer. load only the first packet + Load raw pcap file into a buffer. Loads only the first packet. :parameters: pcap_file : file_name :raises: - + :exc:`AssertionError`, in case packet is empty. + + :exc:`AssertionError`, if packet is empty. """ f_path = self._get_pcap_file_path (pcap_file) @@ -1293,7 +1296,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): self.pkt_raw = pkt[0] break if not was_set : - raise CTRexPacketBuildException(-14, "no buffer inside the pcap file {0}".format(f_path)) + raise CTRexPacketBuildException(-14, "No buffer inside the pcap file {0}".format(f_path)) def to_pkt_dump(self): p = self.pkt @@ -1312,7 +1315,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): """ Scapy packet - For Example:: + Example:: pkt =Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/IP()/('x'*10) @@ -1401,7 +1404,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): if var_names : for var_name in var_names: if var_name in vars: - raise CTRexPacketBuildException(-11,("variable %s define twice ") % (var_name) ); + raise CTRexPacketBuildException(-11,("Variable %s defined twice ") % (var_name) ); else: vars[var_name]=1 @@ -1410,7 +1413,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): var_name = desc.get_var_ref() if var_name : if not var_name in vars: - raise CTRexPacketBuildException(-11,("variable %s does not exists ") % (var_name) ); + raise CTRexPacketBuildException(-11,("Variable %s does not exist ") % (var_name) ); desc.compile(self); for desc in obj.commands: @@ -1439,7 +1442,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): # regular scapy packet elif not self.pkt: # should not reach here - raise CTRexPacketBuildException(-11, 'empty packet') + raise CTRexPacketBuildException(-11, 'Empty packet') if self.remove_fcs and self.pkt.lastlayer().name == 'Padding': self.pkt.lastlayer().underlayer.remove_payload() @@ -1469,7 +1472,7 @@ class STLPktBuilder(CTrexPktBuilderInterface): if self.pkt_raw: return self.pkt_raw - raise CTRexPacketBuildException(-11, 'empty packet'); + raise CTRexPacketBuildException(-11, 'Empty packet'); def _add_tuple_gen(self,tuple_gen): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index 47124114..89ad2663 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -7,8 +7,8 @@ from .trex_stl_types import * from . import trex_stl_stats import base64 -import time import copy +from datetime import datetime, timedelta StreamOnPort = namedtuple('StreamOnPort', ['compiled_stream', 'metadata']) @@ -61,6 +61,8 @@ class Port(object): self.port_stats = trex_stl_stats.CPortStats(self) self.next_available_id = 1 + self.tx_stopped_ts = None + self.has_rx_streams = False def err(self, msg): @@ -79,8 +81,7 @@ class Port(object): "session_id": self.session_id, "force": force} - command = RpcCmdData("acquire", params) - rc = self.transmit(command.method, command.params) + rc = self.transmit("acquire", params) if rc.good(): self.handler = rc.data() return self.ok() @@ -92,8 +93,7 @@ class Port(object): params = {"port_id": self.port_id, "handler": self.handler} - command = RpcCmdData("release", params) - rc = self.transmit(command.method, command.params) + rc = self.transmit("release", params) self.handler = None if rc.good(): @@ -117,8 +117,7 @@ class Port(object): def sync(self): params = {"port_id": self.port_id} - command = RpcCmdData("get_port_status", params) - rc = self.transmit(command.method, command.params) + rc = self.transmit("get_port_status", params) if rc.bad(): return self.err(rc.err()) @@ -147,8 +146,7 @@ class Port(object): # sync the streams params = {"port_id": self.port_id} - command = RpcCmdData("get_all_streams", params) - rc = self.transmit(command.method, command.params) + rc = self.transmit("get_all_streams", params) if rc.bad(): return self.err(rc.err()) @@ -222,7 +220,7 @@ class Port(object): "stream_id": stream_id, "stream": stream_json} - cmd = RpcCmdData('add_stream', params) + cmd = RpcCmdData('add_stream', params, 'core') batch.append(cmd) @@ -239,6 +237,9 @@ class Port(object): 'rate' : streams_list[i].get_rate()} ret.add(RC_OK(data = stream_id)) + + self.has_rx_streams = self.has_rx_streams or streams_list[i].has_flow_stats() + else: ret.add(RC(*single_rc)) @@ -271,7 +272,7 @@ class Port(object): "port_id": self.port_id, "stream_id": stream_id} - cmd = RpcCmdData('remove_stream', params) + cmd = RpcCmdData('remove_stream', params, 'core') batch.append(cmd) @@ -283,6 +284,9 @@ class Port(object): self.state = self.STATE_STREAMS if (len(self.streams) > 0) else self.STATE_IDLE + # recheck if any RX stats streams present on the port + self.has_rx_streams = any([stream.has_flow_stats() for stream in self.streams]) + return self.ok() if rc else self.err(rc.err()) @@ -305,6 +309,7 @@ class Port(object): self.streams = {} self.state = self.STATE_IDLE + self.has_rx_streams = False return self.ok() @@ -351,7 +356,7 @@ class Port(object): # stop traffic # with force ignores the cached state and sends the command def stop (self, force = False): - + if not self.is_acquired(): return self.err("port is not owned") @@ -360,7 +365,6 @@ class Port(object): if (self.state == self.STATE_IDLE) or (self.state == self.state == self.STATE_STREAMS): return self.ok() - params = {"handler": self.handler, "port_id": self.port_id} @@ -370,8 +374,56 @@ class Port(object): self.state = self.STATE_STREAMS + # timestamp for last tx + self.tx_stopped_ts = datetime.now() + + return self.ok() + + + # return True if port has any stream configured with RX stats + def has_rx_enabled (self): + return self.has_rx_streams + + + # return true if rx_delay_ms has passed since the last port stop + def has_rx_delay_expired (self, rx_delay_ms): + assert(self.has_rx_enabled()) + + # if active - it's not safe to remove RX filters + if self.is_active(): + return False + + # either no timestamp present or time has already passed + return not self.tx_stopped_ts or (datetime.now() - self.tx_stopped_ts) > timedelta(milliseconds = rx_delay_ms) + + + + def remove_rx_filters (self): + assert(self.has_rx_enabled()) + + if not self.is_acquired(): + return self.err("port is not owned") + + if self.state == self.STATE_DOWN: + return self.err("Unable to remove RX filters - port is down") + + if self.state == self.STATE_TX: + return self.err("Unable to remove RX filters - port is transmitting") + + if self.state == self.STATE_IDLE: + return self.ok() + + + params = {"handler": self.handler, + "port_id": self.port_id} + + rc = self.transmit("remove_rx_filters", params) + if rc.bad(): + return self.err(rc.err()) + return self.ok() + def pause (self): if not self.is_acquired(): @@ -597,6 +649,8 @@ class Port(object): ################# events handler ###################### def async_event_port_job_done (self): + # until thread is locked - order is important + self.tx_stopped_ts = datetime.now() self.state = self.STATE_STREAMS # rest of the events are used for TUI / read only sessions diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py index 18678e3e..1d89a599 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py @@ -39,7 +39,7 @@ class BpSimException(Exception): # stateless simulation class STLSim(object): - def __init__ (self, bp_sim_path = None, handler = 0, port_id = 0): + def __init__ (self, bp_sim_path = None, handler = 0, port_id = 0, api_h = "dummy"): if not bp_sim_path: # auto find scripts @@ -54,6 +54,7 @@ class STLSim(object): # dummies self.handler = handler + self.api_h = api_h self.port_id = port_id @@ -62,6 +63,7 @@ class STLSim(object): "jsonrpc": "2.0", "method": "start_traffic", "params": {"handler": self.handler, + "api_h" : self.api_h, "force": force, "port_id": self.port_id, "mul": parsing_opts.decode_multiplier(mult), @@ -168,6 +170,7 @@ class STLSim(object): "jsonrpc": "2.0", "method": "add_stream", "params": {"handler": self.handler, + "api_h": self.api_h, "port_id": self.port_id, "stream_id": stream_id, "stream": stream_json} diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 18c49d4e..a4bb64db 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -3,9 +3,8 @@ from .utils import text_tables from .utils.text_opts import format_text, format_threshold, format_num -from .trex_stl_async_client import CTRexAsyncStats - from collections import namedtuple, OrderedDict, deque +import sys import copy import datetime import time @@ -520,6 +519,10 @@ class CTRexStats(object): value = abs(v) arrow = u'\u25b2' if v > 0 else u'\u25bc' + + if sys.version_info < (3,0): + arrow = arrow.encode('utf-8') + color = up_color if v > 0 else down_color # change in 1% is not meaningful @@ -529,22 +532,22 @@ class CTRexStats(object): elif value > 5: if show_value: - return format_text(u"{0}{0}{0} {1:.2f}%".format(arrow,v), color) + return format_text("{0}{0}{0} {1:.2f}%".format(arrow,v), color) else: - return format_text(u"{0}{0}{0}".format(arrow), color) + return format_text("{0}{0}{0}".format(arrow), color) elif value > 2: if show_value: - return format_text(u"{0}{0} {1:.2f}%".format(arrow,v), color) + return format_text("{0}{0} {1:.2f}%".format(arrow,v), color) else: - return format_text(u"{0}{0}".format(arrow), color) + return format_text("{0}{0}".format(arrow), color) else: if show_value: - return format_text(u"{0} {1:.2f}%".format(arrow,v), color) + return format_text("{0} {1:.2f}%".format(arrow,v), color) else: - return format_text(u"{0}".format(arrow), color) + return format_text("{0}".format(arrow), color) @@ -595,21 +598,21 @@ class CGlobalStats(CTRexStats): ("version", "{ver}, UUID: {uuid}".format(ver=self.server_version.get("version", "N/A"), uuid="N/A")), - ("cpu_util", u"{0}% {1}".format( format_threshold(self.get("m_cpu_util"), [85, 100], [0, 85]), + ("cpu_util", "{0}% {1}".format( format_threshold(self.get("m_cpu_util"), [85, 100], [0, 85]), self.get_trend_gui("m_cpu_util", use_raw = True))), (" ", ""), - ("total_tx_L2", u"{0} {1}".format( self.get("m_tx_bps", format=True, suffix="b/sec"), + ("total_tx_L2", "{0} {1}".format( self.get("m_tx_bps", format=True, suffix="b/sec"), self.get_trend_gui("m_tx_bps"))), - ("total_tx_L1", u"{0} {1}".format( self.get("m_tx_bps_L1", format=True, suffix="b/sec"), + ("total_tx_L1", "{0} {1}".format( self.get("m_tx_bps_L1", format=True, suffix="b/sec"), self.get_trend_gui("m_tx_bps_L1"))), - ("total_rx", u"{0} {1}".format( self.get("m_rx_bps", format=True, suffix="b/sec"), + ("total_rx", "{0} {1}".format( self.get("m_rx_bps", format=True, suffix="b/sec"), self.get_trend_gui("m_rx_bps"))), - ("total_pps", u"{0} {1}".format( self.get("m_tx_pps", format=True, suffix="pkt/sec"), + ("total_pps", "{0} {1}".format( self.get("m_tx_pps", format=True, suffix="pkt/sec"), self.get_trend_gui("m_tx_pps"))), (" ", ""), @@ -721,24 +724,24 @@ class CPortStats(CTRexStats): "----": " ", "-----": " ", - "Tx bps L1": u"{0} {1}".format(self.get_trend_gui("m_total_tx_bps_L1", show_value = False), + "Tx bps L1": "{0} {1}".format(self.get_trend_gui("m_total_tx_bps_L1", show_value = False), self.get("m_total_tx_bps_L1", format = True, suffix = "bps")), - "Tx bps L2": u"{0} {1}".format(self.get_trend_gui("m_total_tx_bps", show_value = False), + "Tx bps L2": "{0} {1}".format(self.get_trend_gui("m_total_tx_bps", show_value = False), self.get("m_total_tx_bps", format = True, suffix = "bps")), - "Line Util.": u"{0} {1}".format(self.get_trend_gui("m_percentage", show_value = False), + "Line Util.": "{0} {1}".format(self.get_trend_gui("m_percentage", show_value = False), format_text( self.get("m_percentage", format = True, suffix = "%") if self._port_obj else "", - 'bold')), + 'bold')) if self._port_obj else "", - "Rx bps": u"{0} {1}".format(self.get_trend_gui("m_total_rx_bps", show_value = False), + "Rx bps": "{0} {1}".format(self.get_trend_gui("m_total_rx_bps", show_value = False), self.get("m_total_rx_bps", format = True, suffix = "bps")), - "Tx pps": u"{0} {1}".format(self.get_trend_gui("m_total_tx_pps", show_value = False), + "Tx pps": "{0} {1}".format(self.get_trend_gui("m_total_tx_pps", show_value = False), self.get("m_total_tx_pps", format = True, suffix = "pps")), - "Rx pps": u"{0} {1}".format(self.get_trend_gui("m_total_rx_pps", show_value = False), + "Rx pps": "{0} {1}".format(self.get_trend_gui("m_total_rx_pps", show_value = False), self.get("m_total_rx_pps", format = True, suffix = "pps")), "opackets" : self.get_rel("opackets"), diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py index 4f8ce3e6..3ce876ad 100644..100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py @@ -21,22 +21,22 @@ class STLTXMode(object): def __init__ (self, pps = None, bps_L1 = None, bps_L2 = None, percentage = None): """ - Speed could be in packet per second (pps) or L2/L1 bps or port precent - only one of them is valid. + Speed can be given in packets per second (pps), L2/L1 bps, or port percent + Use only one unit. you can enter pps =10000 oe bps_L1=10 :parameters: pps : float - packet per second + Packets per second bps_L1 : float - bit per second L1 (with IPG) + Bits per second L1 (with IPG) bps_L2 : float - bit per second L2 (Ethernet-FCS) + Bits per second L2 (Ethernet-FCS) percentage : float - link interface precent 0-100 e.g. 10 is 10%% of the port link setup + Link interface percent (0-100). Example: 10 is 10% of the port link setup .. code-block:: python :caption: STLTXMode Example @@ -95,11 +95,11 @@ class STLTXMode(object): # continuous mode class STLTXCont(STLTXMode): - """ continuous mode """ + """ Continuous mode """ def __init__ (self, **kwargs): """ - continuous mode + Continuous mode see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate @@ -124,11 +124,11 @@ class STLTXSingleBurst(STLTXMode): def __init__ (self, total_pkts = 1, **kwargs): """ - single burst mode + Single burst mode :parameters: total_pkts : int - how many packets for this burst + Number of packets for this burst see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate @@ -154,7 +154,7 @@ class STLTXSingleBurst(STLTXMode): # multi burst mode class STLTXMultiBurst(STLTXMode): - """ Multi burst mode """ + """ Multi-burst mode """ def __init__ (self, pkts_per_burst = 1, @@ -162,18 +162,18 @@ class STLTXMultiBurst(STLTXMode): count = 1, **kwargs): """ - Multi burst mode + Multi-burst mode :parameters: pkts_per_burst: int - how many packets per burst + Number of packets per burst ibg : float - inter burst gap in usec 1000,000.0 is 1 sec + Inter-burst gap in usec 1,000,000.0 is 1 sec count : int - how many bursts + Number of bursts see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate @@ -230,7 +230,7 @@ class STLFlowStats(object): def to_json (self): - """ dump as json""" + """ Dump as json""" return dict(self.fields) @staticmethod @@ -238,7 +238,7 @@ class STLFlowStats(object): return {'enabled' : False} class STLStream(object): - """ One stream object, include mode, Field Engine mode packet template and Rx stats + """ One stream object. Includes mode, Field Engine mode packet template and Rx stats .. code-block:: python :caption: STLStream Example @@ -277,42 +277,42 @@ class STLStream(object): :parameters: name : string - The name of the stream. Needed if this stream is dependent on another stream and another stream need to refer to this stream by its name. + Name of the stream. Required if this stream is dependent on another stream, and another stream needs to refer to this stream by name. packet : STLPktBuilder see :class:`trex_stl_lib.trex_stl_packet_builder_scapy.STLPktBuilder` - The template packet and field engine program e.g. packet = STLPktBuilder(pkt = base_pkt/pad) + Template packet and field engine program. Example: packet = STLPktBuilder(pkt = base_pkt/pad) mode : :class:`trex_stl_lib.trex_stl_streams.STLTXCont` or :class:`trex_stl_lib.trex_stl_streams.STLTXSingleBurst` or :class:`trex_stl_lib.trex_stl_streams.STLTXMultiBurst` enabled : bool - if the stream is enabled. + Indicates whether the stream is enabled. self_start : bool - In case it is False another stream will activate it + If False, another stream activates it. isg : float - Inter stream gap in usec. time to wait until stream will send the first packet + Inter-stream gap in usec. Time to wait until the stream sends the first packet. flow_stats : :class:`trex_stl_lib.trex_stl_streams.STLFlowStats` - Per stream statistic object see STLFlowStats + Per stream statistic object. See: STLFlowStats next : string - The name of the stream to activate + Name of the stream to activate. stream_id : - for HLTAPI usage + For use by HLTAPI. action_count : uint16_t - In case there is a next stream how many loops until stopping. Default is zero, which mean unlimited + If there is a next stream, number of loops before stopping. Default: 0 (unlimited). random_seed: uint16_t - If given the seed for this stream will be this value. Good in case you need a deterministic random value + If given, the seed for this stream will be this value. Useful if you need a deterministic random value. mac_src_override_by_pkt : bool - Template packet will set src MAC + Template packet sets src MAC. mac_dst_override_mode=None : STLStreamDstMAC_xx - Template packet will set dst MAC + Template packet sets dst MAC. """ @@ -326,7 +326,7 @@ class STLStream(object): validate_type('random_seed',random_seed,int); if (type(mode) == STLTXCont) and (next != None): - raise STLError("continuous stream cannot have a next stream ID") + raise STLError("Continuous stream cannot have a next stream ID") # tag for the stream and next - can be anything self.name = name @@ -412,7 +412,7 @@ class STLStream(object): def to_json (self): """ - return json format + Return json format """ return dict(self.fields) @@ -430,6 +430,10 @@ class STLStream(object): return self.next + def has_flow_stats (self): + """ Return True if stream was configured with flow stats """ + return self.fields['flow_stats']['enabled'] + def get_pkt (self): """ Get packet as string """ return self.pkt @@ -444,7 +448,7 @@ class STLStream(object): def get_pkt_type (self): - """ Get packet description for example IP:UDP """ + """ Get packet description. Example: IP:UDP """ if self.packet_desc == None: self.packet_desc = STLPktBuilder.pkt_layers_desc_from_buffer(self.get_pkt()) @@ -472,7 +476,7 @@ class STLStream(object): return self.get_rate_from_field(self.fields['mode']['rate']) def to_pkt_dump (self): - """ print packet description from scapy """ + """ Print packet description from Scapy """ if self.name: print("Stream Name: ",self.name) scapy_b = self.scapy_pkt_builder; @@ -484,7 +488,7 @@ class STLStream(object): def to_yaml (self): - """ convert to YAML """ + """ Convert to YAML """ y = {} if self.name: @@ -506,7 +510,7 @@ class STLStream(object): # returns the Python code (text) to build this stream, inside the code it will be in variable "stream" def to_code (self): - """ convert to Python code as profile """ + """ Convert to Python code as profile """ packet = Ether(self.pkt) layer = packet while layer: # remove checksums @@ -621,7 +625,7 @@ class STLStream(object): return r'\x{0:02x}'.format(ord(match.group())) def dump_to_yaml (self, yaml_file = None): - """ print as yaml """ + """ Print as yaml """ yaml_dump = yaml.dump([self.to_yaml()], default_flow_style = False) # write to file if provided @@ -642,7 +646,7 @@ class YAMLLoader(object): packet_type = set(packet_dict).intersection(['binary', 'pcap']) if len(packet_type) != 1: - raise STLError("packet section must contain either 'binary' or 'pcap'") + raise STLError("Packet section must contain either 'binary' or 'pcap'") if 'binary' in packet_type: try: @@ -707,7 +711,7 @@ class YAMLLoader(object): pg_id = flow_stats_obj.get('stream_id') if pg_id == None: - raise STLError("enabled RX stats section must contain 'stream_id' field") + raise STLError("Enabled RX stats section must contain 'stream_id' field") return STLFlowStats(pg_id = pg_id) @@ -822,16 +826,21 @@ class STLProfile(object): def get_streams (self): - """ Get the list of stream""" + """ Get the list of streams""" return self.streams def __str__ (self): return '\n'.join([str(stream) for stream in self.streams]) + def is_pauseable (self): + return all([x.get_mode() == "Continuous" for x in self.get_streams()]) + + def has_flow_stats (self): + return any([x.has_flow_stats() for x in self.get_streams()]) @staticmethod def load_yaml (yaml_file): - """ load from YAML file a profile with number of streams""" + """ Load (from YAML file) a profile with a number of streams""" # check filename if not os.path.isfile(yaml_file): @@ -866,11 +875,11 @@ class STLProfile(object): @staticmethod def load_py (python_file, direction = 0, port_id = 0, **kwargs): - """ load from Python profile """ + """ Load from Python profile """ # check filename if not os.path.isfile(python_file): - raise STLError("file '{0}' does not exists".format(python_file)) + raise STLError("File '{0}' does not exist".format(python_file)) basedir = os.path.dirname(python_file) sys.path.append(basedir) @@ -883,7 +892,7 @@ class STLProfile(object): t = STLProfile.get_module_tunables(module) for arg in kwargs: if not arg in t: - raise STLError("profile {0} does not support tunable '{1}' - supported tunables are: '{2}'".format(python_file, arg, t)) + raise STLError("Profile {0} does not support tunable '{1}' - supported tunables are: '{2}'".format(python_file, arg, t)) streams = module.register().get_streams(direction = direction, port_id = port_id, @@ -910,26 +919,26 @@ class STLProfile(object): # loop_count = 0 means loop forever @staticmethod def load_pcap (pcap_file, ipg_usec = None, speedup = 1.0, loop_count = 1, vm = None): - """ Convert a pcap file with a number of packets to a list of connected streams + """ Convert a pcap file with a number of packets to a list of connected streams. packet1->packet2->packet3 etc :parameters: pcap_file : string - The name of the pcap file + Name of the pcap file ipg_usec : float - The inter packet gap in usec. in case of None IPG is taken from pcap file + Inter packet gap in usec. If IPG=0, IPG is taken from pcap file speedup : float - By which factor to get IPG smaller so we will send pcap file in speedup + When reading the pcap file, divide IPG by this "speedup" factor. Resulting IPG is sped up by this factor. loop_count : uint16_t - how many loops to repeat the pcap file + Number of loops to repeat the pcap file vm : list - A list of Field engine instructions + List of Field engine instructions :return: STLProfile @@ -987,12 +996,12 @@ class STLProfile(object): @staticmethod def load (filename, direction = 0, port_id = 0, **kwargs): - """ load a profile by its type supported type are + """ Load a profile by its type. Supported types are: * py * yaml * pcap file that converted to profile automaticly - :parameters: + :Parameters: filename : string as filename direction : profile's direction (if supported by the profile) port_id : which port ID this profile is being loaded to @@ -1024,7 +1033,7 @@ class STLProfile(object): return profile.meta def dump_as_pkt (self): - """ dump the profile as scapy packet. in case it is raw convert to scapy and dump it""" + """ Dump the profile as Scapy packet. If the packet is raw, convert it to Scapy before dumping it.""" cnt=0; for stream in self.streams: print("=======================") @@ -1034,7 +1043,7 @@ class STLProfile(object): stream.to_pkt_dump() def dump_to_yaml (self, yaml_file = None): - """ convert it to yaml """ + """ Convert the profile to yaml """ yaml_list = [stream.to_yaml() for stream in self.streams] yaml_str = yaml.dump(yaml_list, default_flow_style = False) @@ -1046,7 +1055,7 @@ class STLProfile(object): return yaml_str def dump_to_code (self, profile_file = None): - """ convert it to Python native profile. yeah this is cool """ + """ Convert the profile to Python native profile. """ profile_dump = '''# !!! Auto-generated code !!! from trex_stl_lib.api import * diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py index e5305c78..cd15b831 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py @@ -4,7 +4,7 @@ from .utils.text_opts import * from .trex_stl_exceptions import * import types -RpcCmdData = namedtuple('RpcCmdData', ['method', 'params']) +RpcCmdData = namedtuple('RpcCmdData', ['method', 'params', 'api_class']) TupleRC = namedtuple('RCT', ['rc', 'data', 'is_warn']) class RpcResponseStatus(namedtuple('RpcResponseStatus', ['success', 'id', 'msg'])): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_tables.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_tables.py index 8917cd28..4b7e9b3e 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_tables.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_tables.py @@ -1,3 +1,4 @@ +import sys from texttable import Texttable from .text_opts import format_text @@ -23,6 +24,7 @@ def generate_trex_stats_table(): def print_table_with_header(texttable_obj, header="", untouched_header=""): header = header.replace("_", " ").title() + untouched_header print(format_text(header, 'cyan', 'underline') + "\n") + print((texttable_obj.draw() + "\n")) if __name__ == "__main__": |