summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py')
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py501
1 files changed, 370 insertions, 131 deletions
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 22895a75..4e3d3092 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
@@ -511,8 +511,7 @@ class STLClient(object):
self.connected = False
# API classes
- self.api_vers = [ {'type': 'core', 'major': 1, 'minor':2 }
- ]
+ self.api_vers = [ {'type': 'core', 'major': 1, 'minor': 3 } ]
self.api_h = {'core': None}
# logger
@@ -555,14 +554,17 @@ class STLClient(object):
self.latency_stats = trex_stl_stats.CLatencyStats(self.ports)
+ self.util_stats = trex_stl_stats.CUtilStats(self)
+
self.stats_generator = trex_stl_stats.CTRexInfoGenerator(self.global_stats,
self.ports,
self.flow_stats,
self.latency_stats,
+ self.util_stats,
self.async_client.monitor)
-
+
############# private functions - used by the class itself ###########
@@ -1254,18 +1256,187 @@ class STLClient(object):
# get stats
- def get_stats (self, ports = None, async_barrier = True):
+ def get_stats (self, ports = None, sync_now = True):
+ """
+ Return dictionary containing statistics information gathered from the server.
+
+ :parameters:
+
+ ports - List of ports to retreive stats on.
+ If None, assume the request is for all acquired ports.
+
+ sync_now - Boolean - If true, create a call to the server to get latest stats, and wait for result to arrive. Otherwise, return last stats saved in client cache.
+ Downside of putting True is a slight delay (few 10th msecs) in getting the result. For practical uses, value should be True.
+ :return:
+ Statistics dictionary of dictionaries with the following format:
+
+ =============================== ===============
+ key Meaning
+ =============================== ===============
+ :ref:`numbers (0,1,..<total>` Statistcs per port number
+ :ref:`total <total>` Sum of port statistics
+ :ref:`flow_stats <flow_stats>` Per flow statistics
+ :ref:`global <global>` Global statistics
+ :ref:`latency <latency>` Per flow statistics regarding flow latency
+ =============================== ===============
+
+ Below is description of each of the inner dictionaries.
+
+ .. _total:
+
+ **total** and per port statistics contain dictionary with following format.
+
+ Most of the bytes counters (unless specified otherwise) are in L2 layer, including the Ethernet FCS. e.g. minimum packet size is 64 bytes
+
+ =============================== ===============
+ key Meaning
+ =============================== ===============
+ ibytes Number of input bytes
+ ierrors Number of input errors
+ ipackets Number of input packets
+ obytes Number of output bytes
+ oerrors Number of output errors
+ opackets Number of output packets
+ rx_bps Receive bytes per second rate (L2 layer)
+ rx_pps Receive packet per second rate
+ tx_bps Transmit bytes per second rate (L2 layer)
+ tx_pps Transmit packet per second rate
+ =============================== ===============
+
+ .. _flow_stats:
+
+ **flow_stats** contains :ref:`global dictionary <flow_stats_global>`, and dictionaries per packet group id (pg id). See structures below.
+
+ **per pg_id flow stat** dictionaries have following structure:
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ rx_bps Received bytes per second rate
+ rx_bps_l1 Received bytes per second rate, including layer one
+ rx_bytes Total number of received bytes
+ rx_pkts Total number of received packets
+ rx_pps Received packets per second
+ tx_bps Transmit bytes per second rate
+ tx_bps_l1 Transmit bytes per second rate, including layer one
+ tx_bytes Total number of sent bytes
+ tx_pkts Total number of sent packets
+ tx_pps Transmit packets per second rate
+ ================= ===============
+
+ .. _flow_stats_global:
+
+ **global flow stats** dictionary has the following structure:
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ rx_err Number of flow statistics packets received that we could not associate to any pg_id. This can happen if latency on the used setup is large. See :ref:`wait_on_traffic <wait_on_traffic>` rx_delay_ms parameter for details.
+ tx_err Number of flow statistics packets transmitted that we could not associate to any pg_id. This is never expected. If you see this different than 0, please report.
+ ================= ===============
+
+ .. _global:
+
+ **global**
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ bw_per_core Estimated byte rate Trex can support per core. This is calculated by extrapolation of current rate and load on transmitting cores.
+ cpu_util Estimate of the average utilization percentage of the transimitting cores
+ queue_full Total number of packets transmitted while the NIC TX queue was full. The packets will be transmitted, eventually, but will create high CPU%due to polling the queue. This usually indicates that the rate we trying to transmit is too high for this port.
+ rx_cpu_util Estimate of the utilization percentage of the core handling RX traffic. Too high value of this CPU utilization could cause drop of latency streams.
+ rx_drop_bps Received bytes per second drop rate
+ rx_bps Received bytes per second rate
+ rx_pps Received packets per second rate
+ tx_bps Transmit bytes per second rate
+ tx_pps Transmit packets per second rate
+ ================= ===============
+
+ .. _latency:
+
+ **latency** contains :ref:`global dictionary <lat_stats_global>`, and dictionaries per packet group id (pg id). Each one with the following structure.
+
+ **per pg_id latency stat** dictionaries have following structure:
+
+ =========================== ===============
+ key Meaning
+ =========================== ===============
+ :ref:`err_cntrs<err-cntrs>` Counters describing errors that occured with this pg id
+ :ref:`latency<lat_inner>` Information regarding packet latency
+ =========================== ===============
+
+ Following are the inner dictionaries of latency
+
+ .. _err-cntrs:
+
+ **err-cntrs**
+
+ ================= ===============
+ key Meaning (see better explanation below the table)
+ ================= ===============
+ dropped How many packets were dropped (estimation)
+ dup How many packets were duplicated.
+ out_of_order How many packets we received out of order.
+ seq_too_high How many events of packet with sequence number too high we saw.
+ seq_too_low How many events of packet with sequence number too low we saw.
+ ================= ===============
+
+ For calculating packet error events, we add sequence number to each packet's payload. We decide what went wrong only according to sequence number
+ of last packet received and that of the previous packet. 'seq_too_low' and 'seq_too_high' count events we see. 'dup', 'out_of_order' and 'dropped'
+ are heuristics we apply to try and understand what happened. They will be accurate in common error scenarios.
+ We describe few scenarios below to help understand this.
+
+ Scenario 1: Received packet with seq num 10, and another one with seq num 10. We increment 'dup' and 'seq_too_low' by 1.
+
+ Scenario 2: Received pacekt with seq num 10 and then packet with seq num 15. We assume 4 packets were dropped, and increment 'dropped' by 4, and 'seq_too_high' by 1.
+ We expect next packet to arrive with sequence number 16.
+
+ Scenario 2 continue: Received packet with seq num 11. We increment 'seq_too_low' by 1. We increment 'out_of_order' by 1. We *decrement* 'dropped' by 1.
+ (We assume here that one of the packets we considered as dropped before, actually arrived out of order).
+
+
+ .. _lat_inner:
+
+ **latency**
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ average Average latency over the stream lifetime (usec).Low pass filter is applied to the last window average.It is computed each sampling period by following formula: <average> = <prev average>/2 + <last sampling period average>/2
+ histogram Dictionary describing logarithmic distribution histogram of packet latencies. Keys in the dictionary represent range of latencies (in usec). Values are the total number of packets received in this latency range. For example, an entry {100:13} would mean that we saw 13 packets with latency in the range between 100 and 200 usec.
+ jitter Jitter of latency samples, computed as described in :rfc:`3550#appendix-A.8`
+ last_max Maximum latency measured between last two data reads from server (0.5 sec window).
+ total_max Maximum latency measured over the stream lifetime (in usec).
+ total_min Minimum latency measured over the stream lifetime (in usec).
+ ================= ===============
+
+ .. _lat_stats_global:
+
+ **global latency stats** dictionary has the following structure:
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ old_flow Number of latency statistics packets received that we could not associate to any pg_id. This can happen if latency on the used setup is large. See :ref:`wait_on_traffic <wait_on_traffic>` rx_delay_ms parameter for details.
+ bad_hdr Number of latency packets received with bad latency data. This can happen becuase of garbage packets in the network, or if the DUT causes packet corruption.
+ ================= ===============
+
+ :raises:
+ None
+
+ """
# by default use all acquired ports
ports = ports if ports is not None else self.get_acquired_ports()
ports = self._validate_port_list(ports)
# check async barrier
- if not type(async_barrier) is bool:
- raise STLArgumentError('async_barrier', async_barrier)
+ if not type(sync_now) is bool:
+ raise STLArgumentError('sync_now', sync_now)
# if the user requested a barrier - use it
- if async_barrier:
+ if sync_now:
rc = self.async_client.barrier()
if not rc:
raise STLError(rc)
@@ -1279,7 +1450,7 @@ class STLClient(object):
:parameters:
ev_type_filter - 'info', 'warning' or a list of those
- default is no filter
+ default: no filter
:return:
logged events
@@ -1487,8 +1658,8 @@ class STLClient(object):
"""
- self.logger.pre_cmd( "Pinging the server on '{0}' port '{1}': ".format(self.connection_info['server'],
- self.connection_info['sync_port']))
+ 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", api_class = None)
self.logger.post_cmd(rc)
@@ -1497,6 +1668,30 @@ class STLClient(object):
raise STLError(rc)
@__api_check(True)
+ def server_shutdown (self, force = False):
+ """
+ Sends the server a request for total shutdown
+
+ :parameters:
+ force - shutdown server even if some ports are owned by another
+ user
+
+ :raises:
+ + :exc:`STLError`
+
+ """
+
+ self.logger.pre_cmd("Sending shutdown request for the server")
+
+ rc = self._transmit("shutdown", params = {'force': force, 'user': self.username})
+
+ self.logger.post_cmd(rc)
+
+ if not rc:
+ raise STLError(rc)
+
+
+ @__api_check(True)
def get_active_pgids(self):
"""
Get active group IDs
@@ -1519,6 +1714,23 @@ class STLClient(object):
if not rc:
raise STLError(rc)
+ @__api_check(True)
+ def get_util_stats(self):
+ """
+ Get utilization stats:
+ History of TRex CPU utilization per thread (list of lists)
+ MBUFs memory consumption per CPU socket.
+
+ :parameters:
+ None
+
+ :raises:
+ + :exc:`STLError`
+
+ """
+ self.logger.pre_cmd('Getting Utilization stats')
+ return self.util_stats.get_stats()
+
@__api_check(True)
def reset(self, ports = None):
@@ -1700,6 +1912,11 @@ class STLClient(object):
ports = self._validate_port_list(ports)
+ validate_type('mult', mult, basestring)
+ validate_type('force', force, bool)
+ validate_type('duration', duration, (int, float))
+ validate_type('total', total, bool)
+
# verify multiplier
mult_obj = parsing_opts.decode_multiplier(mult,
allow_update = False,
@@ -1707,17 +1924,6 @@ class STLClient(object):
if not mult_obj:
raise STLArgumentError('mult', mult)
- # some type checkings
-
- if not type(force) is bool:
- raise STLArgumentError('force', force)
-
- if not isinstance(duration, (int, float)):
- raise STLArgumentError('duration', duration)
-
- if not type(total) is bool:
- raise STLArgumentError('total', total)
-
# verify ports are stopped or force stop them
active_ports = list(set(self.get_active_ports()).intersection(ports))
@@ -1739,8 +1945,6 @@ class STLClient(object):
raise STLError(rc)
-
-
@__api_check(True)
def stop (self, ports = None, rx_delay_ms = 10):
"""
@@ -1762,11 +1966,12 @@ class STLClient(object):
"""
- ports = ports if ports is not None else self.get_active_ports()
- ports = self._validate_port_list(ports)
+ if ports is None:
+ ports = self.get_active_ports()
+ if not ports:
+ return
- if not ports:
- return
+ ports = self._validate_port_list(ports)
self.logger.pre_cmd("Stopping traffic on port(s) {0}:".format(ports))
rc = self.__stop(ports)
@@ -1815,6 +2020,9 @@ class STLClient(object):
ports = ports if ports is not None else self.get_active_ports()
ports = self._validate_port_list(ports)
+ validate_type('mult', mult, basestring)
+ validate_type('force', force, bool)
+ validate_type('total', total, bool)
# verify multiplier
mult_obj = parsing_opts.decode_multiplier(mult,
@@ -1823,10 +2031,6 @@ class STLClient(object):
if not mult_obj:
raise STLArgumentError('mult', mult)
- # verify total
- if not type(total) is bool:
- raise STLArgumentError('total', total)
-
# call low level functions
self.logger.pre_cmd("Updating traffic on port(s) {0}:".format(ports))
@@ -1927,7 +2131,7 @@ class STLClient(object):
ports = ports if ports is not None else self.get_acquired_ports()
ports = self._validate_port_list(ports)
- validate_type('pcap_filename', pcap_filename, str)
+ validate_type('pcap_filename', pcap_filename, basestring)
validate_type('ipg_usec', ipg_usec, (float, int, type(None)))
validate_type('speedup', speedup, (float, int))
validate_type('count', count, int)
@@ -1994,7 +2198,7 @@ class STLClient(object):
ports = ports if ports is not None else self.get_acquired_ports()
ports = self._validate_port_list(ports)
- validate_type('pcap_filename', pcap_filename, str)
+ validate_type('pcap_filename', pcap_filename, basestring)
validate_type('ipg_usec', ipg_usec, (float, int, type(None)))
validate_type('speedup', speedup, (float, int))
validate_type('count', count, int)
@@ -2050,6 +2254,10 @@ class STLClient(object):
ports = ports if ports is not None else self.get_acquired_ports()
ports = self._validate_port_list(ports)
+ validate_type('mult', mult, basestring)
+ validate_type('duration', duration, (int, float))
+ validate_type('total', total, bool)
+
# verify multiplier
mult_obj = parsing_opts.decode_multiplier(mult,
@@ -2058,11 +2266,6 @@ class STLClient(object):
if not mult_obj:
raise STLArgumentError('mult', mult)
-
- if not isinstance(duration, (int, float)):
- raise STLArgumentError('duration', duration)
-
-
self.logger.pre_cmd("Validating streams on port(s) {0}:".format(ports))
rc = self.__validate(ports)
self.logger.post_cmd(rc)
@@ -2136,6 +2339,8 @@ class STLClient(object):
@__api_check(True)
def wait_on_traffic (self, ports = None, timeout = 60, rx_delay_ms = 10):
"""
+ .. _wait_on_traffic:
+
Block until traffic on specified port(s) has ended
:parameters:
@@ -2146,12 +2351,11 @@ class STLClient(object):
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
+ Time to wait (in milliseconds) after last packet was sent, until RX filters used for
+ measuring flow statistics and latency 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
-
+ After this time, RX filters will be removed, and packets arriving for per flow statistics feature and latency flows will be counted as errors.
:raises:
+ :exc:`STLTimeoutError` - in case timeout has expired
@@ -2247,13 +2451,14 @@ class STLClient(object):
rc = f(*args)
except STLError as e:
client.logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold'))
- return
+ return RC_ERR(e.brief())
# if got true - print time
if rc:
delta = time.time() - time1
client.logger.log(format_time(delta) + "\n")
+ return rc
return wrap
@@ -2261,7 +2466,22 @@ class STLClient(object):
def ping_line (self, line):
'''pings the server'''
self.ping()
- return True
+ return RC_OK()
+
+ @__console
+ def shutdown_line (self, line):
+ '''shutdown the server'''
+ parser = parsing_opts.gen_parser(self,
+ "shutdown",
+ self.shutdown_line.__doc__,
+ parsing_opts.FORCE)
+
+ opts = parser.parse_args(line.split())
+ if not opts:
+ return opts
+
+ self.server_shutdown(force = opts.force)
+ return RC_OK()
@__console
def connect_line (self, line):
@@ -2273,14 +2493,13 @@ class STLClient(object):
parsing_opts.FORCE)
opts = parser.parse_args(line.split(), default_ports = self.get_all_ports())
- if opts is None:
- return
+ if not opts:
+ return opts
self.connect()
self.acquire(ports = opts.ports, force = opts.force)
- # true means print time
- return True
+ return RC_OK()
@__console
@@ -2295,19 +2514,19 @@ class STLClient(object):
parsing_opts.FORCE)
opts = parser.parse_args(line.split(), default_ports = self.get_all_ports())
- if opts is None:
- return
+ if not opts:
+ return opts
# filter out all the already owned ports
ports = list_difference(opts.ports, self.get_acquired_ports())
if not ports:
- self.logger.log("acquire - all port(s) {0} are already acquired".format(opts.ports))
- return
+ msg = "acquire - all of port(s) {0} are already acquired".format(opts.ports)
+ self.logger.log(format_text(msg, 'bold'))
+ return RC_ERR(msg)
self.acquire(ports = ports, force = opts.force)
- # true means print time
- return True
+ return RC_OK()
#
@@ -2321,23 +2540,24 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports())
- if opts is None:
- return
+ if not opts:
+ return opts
ports = list_intersect(opts.ports, self.get_acquired_ports())
if not ports:
if not opts.ports:
- self.logger.log("release - no acquired ports")
- return
+ msg = "release - no acquired ports"
+ self.logger.log(format_text(msg, 'bold'))
+ return RC_ERR(msg)
else:
- self.logger.log("release - none of port(s) {0} are acquired".format(opts.ports))
- return
+ msg = "release - none of port(s) {0} are acquired".format(opts.ports)
+ self.logger.log(format_text(msg, 'bold'))
+ return RC_ERR(msg)
self.release(ports = ports)
- # true means print time
- return True
+ return RC_OK()
@__console
@@ -2349,23 +2569,23 @@ class STLClient(object):
self.reacquire_line.__doc__)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
# find all the on-owned ports under your name
my_unowned_ports = list_difference([k for k, v in self.ports.items() if v.get_owner() == self.username], self.get_acquired_ports())
if not my_unowned_ports:
- self.logger.log("reacquire - no unowned ports under '{0}'".format(self.username))
- return
+ msg = "reacquire - no unowned ports under '{0}'".format(self.username)
+ self.logger.log(msg)
+ return RC_ERR(msg)
self.acquire(ports = my_unowned_ports, force = True)
- return True
+ return RC_OK()
@__console
def disconnect_line (self, line):
self.disconnect()
-
@__console
@@ -2378,13 +2598,12 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
self.reset(ports = opts.ports)
- # true means print time
- return True
+ return RC_OK()
@@ -2405,15 +2624,15 @@ class STLClient(object):
parsing_opts.DRY_RUN)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
active_ports = list_intersect(self.get_active_ports(), opts.ports)
if active_ports:
if not opts.force:
msg = "Port(s) {0} are active - please stop them or add '--force'\n".format(active_ports)
self.logger.log(format_text(msg, 'bold'))
- return
+ return RC_ERR(msg)
else:
self.stop(active_ports)
@@ -2431,8 +2650,10 @@ class STLClient(object):
else:
# must be exact
if len(opts.ports) != len(opts.tunables):
- self.logger.log('tunables section count must be 1 or exactly as the number of ports: got {0}'.format(len(opts.tunables)))
- return
+ msg = 'tunables section count must be 1 or exactly as the number of ports: got {0}'.format(len(opts.tunables))
+ self.logger.log(msg)
+ return RC_ERR(msg)
+
tunables = opts.tunables
@@ -2452,9 +2673,10 @@ class STLClient(object):
self.add_streams(profile.get_streams(), ports = port)
except STLError as e:
- self.logger.log(format_text("\nError while loading profile '{0}'\n".format(opts.file[0]), 'bold'))
+ msg = format_text("\nError while loading profile '{0}'\n".format(opts.file[0]), 'bold')
+ self.logger.log(msg)
self.logger.log(e.brief() + "\n")
- return
+ return RC_ERR(msg)
if opts.dry:
@@ -2466,8 +2688,7 @@ class STLClient(object):
opts.duration,
opts.total)
- # true means print time
- return True
+ return RC_OK()
@@ -2480,24 +2701,25 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split(), default_ports = self.get_active_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
# find the relevant ports
ports = list_intersect(opts.ports, self.get_active_ports())
if not ports:
if not opts.ports:
- self.logger.log('stop - no active ports')
+ msg = 'stop - no active ports'
else:
- self.logger.log('stop - no active traffic on ports {0}'.format(opts.ports))
- return
+ msg = 'stop - no active traffic on ports {0}'.format(opts.ports)
+
+ self.logger.log(msg)
+ return RC_ERR(msg)
# call API
self.stop(ports)
- # true means print time
- return True
+ return RC_OK()
@__console
@@ -2512,23 +2734,24 @@ class STLClient(object):
parsing_opts.FORCE)
opts = parser.parse_args(line.split(), default_ports = self.get_active_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
# find the relevant ports
ports = list_intersect(opts.ports, self.get_active_ports())
if not ports:
if not opts.ports:
- self.logger.log('update - no active ports')
+ msg = 'update - no active ports'
else:
- self.logger.log('update - no active traffic on ports {0}'.format(opts.ports))
- return
+ msg = 'update - no active traffic on ports {0}'.format(opts.ports)
+
+ self.logger.log(msg)
+ return RC_ERR(msg)
self.update(ports, opts.mult, opts.total, opts.force)
- # true means print time
- return True
+ return RC_OK()
@__console
@@ -2540,27 +2763,29 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split(), default_ports = self.get_transmitting_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
# check for already paused case
if opts.ports and is_sub_list(opts.ports, self.get_paused_ports()):
- self.logger.log('pause - all of port(s) {0} are already paused'.format(opts.ports))
- return
+ msg = 'pause - all of port(s) {0} are already paused'.format(opts.ports)
+ self.logger.log(msg)
+ return RC_ERR(msg)
# find the relevant ports
ports = list_intersect(opts.ports, self.get_transmitting_ports())
if not ports:
if not opts.ports:
- self.logger.log('pause - no transmitting ports')
+ msg = 'pause - no transmitting ports'
else:
- self.logger.log('pause - none of ports {0} are transmitting'.format(opts.ports))
- return
+ msg = 'pause - none of ports {0} are transmitting'.format(opts.ports)
+
+ self.logger.log(msg)
+ return RC_ERR(msg)
self.pause(ports)
- # true means print time
- return True
+ return RC_OK()
@__console
@@ -2572,23 +2797,25 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split(), default_ports = self.get_paused_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
# find the relevant ports
ports = list_intersect(opts.ports, self.get_paused_ports())
if not ports:
if not opts.ports:
- self.logger.log('resume - no paused ports')
+ msg = 'resume - no paused ports'
else:
- self.logger.log('resume - none of ports {0} are paused'.format(opts.ports))
- return
+ msg = 'resume - none of ports {0} are paused'.format(opts.ports)
+
+ self.logger.log(msg)
+ return RC_ERR(msg)
self.resume(ports)
# true means print time
- return True
+ return RC_OK()
@__console
@@ -2602,8 +2829,8 @@ class STLClient(object):
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
self.clear_stats(opts.ports)
@@ -2622,8 +2849,8 @@ class STLClient(object):
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
# determine stats mask
mask = self.__get_mask_keys(**self.__filter_namespace_args(opts, trex_stl_stats.ALL_STATS_OPTS))
@@ -2653,8 +2880,8 @@ class STLClient(object):
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
streams = self._get_streams(opts.ports, set(opts.streams))
if not streams:
@@ -2680,8 +2907,8 @@ class STLClient(object):
parsing_opts.PORT_LIST_WITH_ALL)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
self.validate(opts.ports)
@@ -2705,8 +2932,8 @@ class STLClient(object):
parsing_opts.FORCE)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
active_ports = list(set(self.get_active_ports()).intersection(opts.ports))
@@ -2714,7 +2941,7 @@ class STLClient(object):
if not opts.force:
msg = "Port(s) {0} are active - please stop them or add '--force'\n".format(active_ports)
self.logger.log(format_text(msg, 'bold'))
- return
+ return RC_ERR(msg)
else:
self.stop(active_ports)
@@ -2738,7 +2965,7 @@ class STLClient(object):
- return True
+ return RC_OK()
@@ -2753,8 +2980,8 @@ class STLClient(object):
parsing_opts.PROMISCUOUS_SWITCH)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
- if opts is None:
- return
+ if not opts:
+ return opts
# if no attributes - fall back to printing the status
if opts.prom is None:
@@ -2762,7 +2989,7 @@ class STLClient(object):
return
self.set_port_attr(opts.ports, opts.prom)
-
+ return RC_OK()
@__console
@@ -2775,8 +3002,8 @@ class STLClient(object):
parsing_opts.FILE_PATH)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
info = STLProfile.get_info(opts.file[0])
@@ -2793,7 +3020,7 @@ class STLClient(object):
if profile_type == 'python':
self.logger.log('Type: {:^12}'.format('Python Module'))
- self.logger.log('Tunables: {:^12}'.format(['{0} = {1}'.format(k ,v) for k, v in info['tunables'].items()]))
+ self.logger.log('Tunables: {:^12}'.format(str(['{0} = {1}'.format(k ,v) for k, v in info['tunables'].items()])))
elif profile_type == 'yaml':
self.logger.log('Type: {:^12}'.format('YAML'))
@@ -2832,8 +3059,8 @@ class STLClient(object):
*x)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
ev_type_filter = []
@@ -2854,3 +3081,15 @@ class STLClient(object):
if opts.clear:
self.clear_events()
+ def generate_prompt (self, prefix = 'trex'):
+ if not self.is_connected():
+ return "{0}(offline)>".format(prefix)
+
+ elif not self.get_acquired_ports():
+ return "{0}(read-only)>".format(prefix)
+
+ elif self.is_all_ports_acquired():
+ return "{0}>".format(prefix)
+
+ else:
+ return "{0} {1}>".format(prefix, self.get_acquired_ports())