summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/automation/trex_control_plane/stl')
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py37
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py127
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py2
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py2
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py60
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py187
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py113
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py19
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py26
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py61
10 files changed, 434 insertions, 200 deletions
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 5d23d8da..b23b5f1f 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -230,14 +230,17 @@ class TRexConsole(TRexGeneralCmd):
self.save_console_history()
lines = line.split(';')
-
- for line in lines:
- stop = self.onecmd(line)
- stop = self.postcmd(stop, line)
- if stop:
- return "quit"
-
- return ""
+ try:
+ for line in lines:
+ stop = self.onecmd(line)
+ stop = self.postcmd(stop, line)
+ if stop:
+ return "quit"
+
+ return ""
+ except STLError as e:
+ print(e)
+ return ''
def postcmd(self, stop, line):
@@ -364,7 +367,7 @@ class TRexConsole(TRexGeneralCmd):
'help': "an history item index",
'default': 0})
- parser = parsing_opts.gen_parser(self,
+ parser = parsing_opts.gen_parser(self.stateless_client,
"history",
self.do_history.__doc__,
item)
@@ -551,16 +554,16 @@ class TRexConsole(TRexGeneralCmd):
@verify_connected
def do_tui (self, line):
'''Shows a graphical console\n'''
- parser = parsing_opts.gen_parser(self,
+ parser = parsing_opts.gen_parser(self.stateless_client,
"tui",
self.do_tui.__doc__,
parsing_opts.XTERM,
parsing_opts.LOCKED)
opts = parser.parse_args(line.split())
- if opts is None:
- return
+ if not opts:
+ return opts
if opts.xterm:
if not os.path.exists('/usr/bin/xterm'):
print(format_text("XTERM does not exists on this machine", 'bold'))
@@ -784,14 +787,18 @@ def show_intro (logger, c):
# find out which NICs the server has
port_types = {}
for port in x['ports']:
- key = (port['speed'], port['driver'])
- if not key in port_types:
+ if 'supp_speeds' in port:
+ speed = max(port['supp_speeds']) // 1000
+ else:
+ speed = port['speed']
+ key = (speed, port.get('description', port['driver']))
+ if key not in port_types:
port_types[key] = 0
port_types[key] += 1
port_line = ''
for k, v in port_types.items():
- port_line += "{0} x {1}Gbps @ {2}".format(v, k[0], k[1])
+ port_line += "{0} x {1}Gbps @ {2}\t".format(v, k[0], k[1])
logger.log(format_text("\nServer Info:\n", 'underline'))
logger.log("Server version: {:>}".format(format_text(ver, 'bold')))
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 82aa932d..80a4c4dc 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
@@ -222,18 +222,18 @@ class EventsHandler(object):
# dispatcher for server async events (port started, port stopped and etc.)
- def on_async_event (self, type, data):
+ def on_async_event (self, event_type, data):
# DP stopped
show_event = False
# port started
- if (type == 0):
+ if (event_type == 0):
port_id = int(data['port_id'])
ev = "Port {0} has started".format(port_id)
self.__async_event_port_started(port_id)
# port stopped
- elif (type == 1):
+ elif (event_type == 1):
port_id = int(data['port_id'])
ev = "Port {0} has stopped".format(port_id)
@@ -242,7 +242,7 @@ class EventsHandler(object):
# port paused
- elif (type == 2):
+ elif (event_type == 2):
port_id = int(data['port_id'])
ev = "Port {0} has paused".format(port_id)
@@ -250,7 +250,7 @@ class EventsHandler(object):
self.__async_event_port_paused(port_id)
# port resumed
- elif (type == 3):
+ elif (event_type == 3):
port_id = int(data['port_id'])
ev = "Port {0} has resumed".format(port_id)
@@ -258,7 +258,7 @@ class EventsHandler(object):
self.__async_event_port_resumed(port_id)
# port finished traffic
- elif (type == 4):
+ elif (event_type == 4):
port_id = int(data['port_id'])
ev = "Port {0} job done".format(port_id)
@@ -267,7 +267,7 @@ class EventsHandler(object):
show_event = True
# port was acquired - maybe stolen...
- elif (type == 5):
+ elif (event_type == 5):
session_id = data['session_id']
port_id = int(data['port_id'])
@@ -297,7 +297,7 @@ class EventsHandler(object):
# port was released
- elif (type == 6):
+ elif (event_type == 6):
port_id = int(data['port_id'])
who = data['who']
session_id = data['session_id']
@@ -315,13 +315,31 @@ class EventsHandler(object):
if session_id != self.client.session_id:
self.__async_event_port_released(port_id)
- elif (type == 7):
+ elif (event_type == 7):
port_id = int(data['port_id'])
ev = "port {0} job failed".format(port_id)
show_event = True
+ # port attr changed
+ elif (event_type == 8):
+ port_id = int(data['port_id'])
+ if data['attr'] == self.client.ports[port_id].attr:
+ return # false alarm
+ old_info = self.client.ports[port_id].get_info()
+ self.__async_event_port_attr_changed(port_id, data['attr'])
+ new_info = self.client.ports[port_id].get_info()
+ ev = "port {0} attributes changed".format(port_id)
+ for key, old_val in old_info.items():
+ new_val = new_info[key]
+ if old_val != new_val:
+ ev += '\n {key}: {old} -> {new}'.format(
+ key = key,
+ old = old_val.lower() if type(old_val) is str else old_val,
+ new = new_val.lower() if type(new_val) is str else new_val)
+ show_event = True
+
# server stopped
- elif (type == 100):
+ elif (event_type == 100):
ev = "Server has stopped"
self.__async_event_server_stopped()
show_event = True
@@ -372,6 +390,9 @@ class EventsHandler(object):
def __async_event_server_stopped (self):
self.client.connected = False
+ def __async_event_port_attr_changed (self, port_id, attr):
+ if port_id in self.client.ports:
+ self.client.ports[port_id].async_event_port_attr_changed(attr)
# add event to log
def __add_event_log (self, origin, ev_type, msg, show = False):
@@ -560,11 +581,14 @@ class STLClient(object):
self.util_stats = trex_stl_stats.CUtilStats(self)
+ self.xstats = trex_stl_stats.CXStats(self)
+
self.stats_generator = trex_stl_stats.CTRexInfoGenerator(self.global_stats,
self.ports,
self.flow_stats,
self.latency_stats,
self.util_stats,
+ self.xstats,
self.async_client.monitor)
@@ -884,7 +908,7 @@ class STLClient(object):
# clear stats
- def __clear_stats(self, port_id_list, clear_global, clear_flow_stats, clear_latency_stats):
+ def __clear_stats(self, port_id_list, clear_global, clear_flow_stats, clear_latency_stats, clear_xstats):
# we must be sync with the server
self.async_client.barrier()
@@ -901,6 +925,9 @@ class STLClient(object):
if clear_latency_stats:
self.latency_stats.clear_stats()
+ if clear_xstats:
+ self.xstats.clear_stats()
+
self.logger.log_cmd("Clearing stats on port(s) {0}:".format(port_id_list))
return RC
@@ -1785,6 +1812,25 @@ class STLClient(object):
self.logger.pre_cmd('Getting Utilization stats')
return self.util_stats.get_stats()
+ @__api_check(True)
+ def get_xstats(self, port_id):
+ print(port_id)
+ """
+ Get extended stats of port: all the counters as dict.
+
+ :parameters:
+ port_id: int
+
+ :returns:
+ Dict with names of counters as keys and values of uint64. Actual keys may vary per NIC.
+
+ :raises:
+ + :exc:`STLError`
+
+ """
+ self.logger.pre_cmd('Getting xstats')
+ return self.xstats.get_stats(port_id)
+
@__api_check(True)
def reset(self, ports = None):
@@ -2004,6 +2050,11 @@ class STLClient(object):
validate_type('total', total, bool)
validate_type('core_mask', core_mask, (int, list))
+ # verify link status
+ ports_link_down = [port_id for port_id in ports if self.ports[port_id].attr.get('link',{}).get('up') == False]
+ if not force and ports_link_down:
+ raise STLError("Port(s) %s - link DOWN - check the connection or specify 'force'" % ports_link_down)
+
#########################
# decode core mask argument
decoded_mask = self.__decode_core_mask(ports, core_mask)
@@ -2462,7 +2513,7 @@ class STLClient(object):
@__api_check(False)
- def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True, clear_latency_stats = True):
+ def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True, clear_latency_stats = True, clear_xstats = True):
"""
Clear stats on port(s)
@@ -2479,6 +2530,9 @@ class STLClient(object):
clear_latency_stats : bool
Clear the latency stats
+ clear_xstats : bool
+ Clear the extended stats
+
:raises:
+ :exc:`STLError`
@@ -2491,7 +2545,7 @@ class STLClient(object):
if not type(clear_global) is bool:
raise STLArgumentError('clear_global', clear_global)
- rc = self.__clear_stats(ports, clear_global, clear_flow_stats, clear_latency_stats)
+ rc = self.__clear_stats(ports, clear_global, clear_flow_stats, clear_latency_stats, clear_xstats)
if not rc:
raise STLError(rc)
@@ -2572,15 +2626,18 @@ class STLClient(object):
@__api_check(True)
- def set_port_attr (self, ports = None, promiscuous = None):
+ def set_port_attr (self, ports = None, promiscuous = None, link_up = None, led_on = None, flow_ctrl = None):
"""
Set port attributes
:parameters:
promiscuous - True or False
+ link_up - True or False
+ led_on - True or False
+ flow_ctrl - 0: disable all, 1: enable tx side, 2: enable rx side, 3: full enable
:raises:
- None
+ + :exe:'STLError'
"""
@@ -2589,11 +2646,20 @@ class STLClient(object):
# check arguments
validate_type('promiscuous', promiscuous, (bool, type(None)))
+ validate_type('link_up', link_up, (bool, type(None)))
+ validate_type('led_on', led_on, (bool, type(None)))
+ validate_type('flow_ctrl', flow_ctrl, (int, type(None)))
# build attributes
attr_dict = {}
if promiscuous is not None:
- attr_dict['promiscuous'] = {'enabled': bool(promiscuous)}
+ attr_dict['promiscuous'] = {'enabled': promiscuous}
+ if link_up is not None:
+ attr_dict['link_status'] = {'up': link_up}
+ if led_on is not None:
+ attr_dict['led_status'] = {'on': led_on}
+ if flow_ctrl is not None:
+ attr_dict['flow_ctrl_mode'] = {'mode': flow_ctrl}
# no attributes to set
if not attr_dict:
@@ -3167,20 +3233,39 @@ class STLClient(object):
"port_attr",
self.set_port_attr_line.__doc__,
parsing_opts.PORT_LIST_WITH_ALL,
- parsing_opts.PROMISCUOUS_SWITCH)
+ parsing_opts.PROMISCUOUS,
+ parsing_opts.LINK_STATUS,
+ parsing_opts.LED_STATUS,
+ parsing_opts.FLOW_CTRL,
+ parsing_opts.SUPPORTED,
+ )
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
if not opts:
return opts
+ opts.prom = parsing_opts.ON_OFF_DICT.get(opts.prom)
+ opts.link = parsing_opts.UP_DOWN_DICT.get(opts.link)
+ opts.led = parsing_opts.ON_OFF_DICT.get(opts.led)
+ opts.flow_ctrl = parsing_opts.FLOW_CTRL_DICT.get(opts.flow_ctrl)
+
# if no attributes - fall back to printing the status
- if opts.prom is None:
+ if not filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp]):
self.show_stats_line("--ps --port {0}".format(' '.join(str(port) for port in opts.ports)))
return
- self.set_port_attr(opts.ports, opts.prom)
- return RC_OK()
-
+ if opts.supp:
+ info = self.ports[0].get_info() # assume for now all ports are same
+ print('')
+ print('Supported attributes for current NICs:')
+ print(' Promiscuous: yes')
+ print(' Link status: %s' % info['link_change_supported'])
+ print(' LED status: %s' % info['led_change_supported'])
+ print(' Flow control: %s' % info['fc_supported'])
+ print('')
+ else:
+ return self.set_port_attr(opts.ports, opts.prom, opts.link, opts.led, opts.flow_ctrl)
+
@__console
def show_profile_line (self, line):
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 609ea076..1461fcec 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
@@ -182,7 +182,7 @@ class JsonRpcClient(object):
tries += 1
if tries > 5:
self.disconnect()
- return RC_ERR("*** [RPC] - Failed to get server response at {0}".format(self.transport))
+ return RC_ERR("*** [RPC] - Failed to get server response from {0}".format(self.transport))
return response
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 aa002d59..dc06f9fb 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
@@ -738,8 +738,8 @@ class STLVmFlowVarRepetableRandom(CTRexVmDescBase):
.. code-block:: python
- :caption: Example1
+ # Example1
# input , 1 byte or random with limit of 5
STLVmFlowVarRepetableRandom("var1",size=1,limit=5)
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 f0e3b109..cec3761f 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
@@ -5,6 +5,7 @@ from .trex_stl_packet_builder_scapy import STLPktBuilder
from .trex_stl_streams import STLStream
from .trex_stl_types import *
from . import trex_stl_stats
+from .utils.constants import FLOW_CTRL_DICT_REVERSED
import base64
import copy
@@ -42,9 +43,9 @@ class Port(object):
STATES_MAP = {STATE_DOWN: "DOWN",
STATE_IDLE: "IDLE",
STATE_STREAMS: "IDLE",
- STATE_TX: "ACTIVE",
+ STATE_TX: "TRANSMITTING",
STATE_PAUSE: "PAUSE",
- STATE_PCAP_TX : "ACTIVE"}
+ STATE_PCAP_TX : "TRANSMITTING"}
def __init__ (self, port_id, user, comm_link, session_id, info):
@@ -251,8 +252,9 @@ class Port(object):
# attributes
self.attr = rc.data()['attr']
+ if 'speed' in rc.data():
+ self.info['speed'] = rc.data()['speed'] // 1000
-
return self.ok()
@@ -577,7 +579,7 @@ class Port(object):
return self.err(rc.err())
- self.attr.update(attr_dict)
+ #self.attr.update(attr_dict)
return self.ok()
@@ -650,13 +652,46 @@ class Port(object):
def get_info (self):
info = dict(self.info)
- info['status'] = self.get_port_state_name()
+ info['status'] = self.get_port_state_name()
- if self.attr.get('promiscuous'):
+ if 'link' in self.attr:
+ info['link'] = 'UP' if self.attr['link']['up'] else 'DOWN'
+ else:
+ info['link'] = 'N/A'
+
+ if 'fc' in self.attr:
+ info['fc'] = FLOW_CTRL_DICT_REVERSED.get(self.attr['fc']['mode'], 'N/A')
+ else:
+ info['fc'] = 'N/A'
+
+ if 'promiscuous' in self.attr:
info['prom'] = "on" if self.attr['promiscuous']['enabled'] else "off"
else:
info['prom'] = "N/A"
+ if 'description' not in info:
+ info['description'] = "N/A"
+
+ if 'is_fc_supported' in info:
+ info['fc_supported'] = 'yes' if info['is_fc_supported'] else 'no'
+ else:
+ info['fc_supported'] = 'N/A'
+
+ if 'is_led_supported' in info:
+ info['led_change_supported'] = 'yes' if info['is_led_supported'] else 'no'
+ else:
+ info['led_change_supported'] = 'N/A'
+
+ if 'is_link_supported' in info:
+ info['link_change_supported'] = 'yes' if info['is_link_supported'] else 'no'
+ else:
+ info['link_change_supported'] = 'N/A'
+
+ if 'is_virtual' in info:
+ info['is_virtual'] = 'yes' if info['is_virtual'] else 'no'
+ else:
+ info['is_virtual'] = 'N/A'
+
return info
@@ -672,6 +707,7 @@ class Port(object):
info = self.get_info()
return {"driver": info['driver'],
+ "description": info.get('description', 'N/A')[:18],
"HW src mac": info['hw_macaddr'],
"SW src mac": info['src_macaddr'],
"SW dst mac": info['dst_macaddr'],
@@ -679,9 +715,11 @@ class Port(object):
"NUMA Node": info['numa'],
"--": "",
"---": "",
- "maximum": "{speed} Gb/s".format(speed=info['speed']),
- "status": info['status'],
- "promiscuous" : info['prom']
+ "link speed": "{speed} Gb/s".format(speed=info['speed']),
+ "port status": info['status'],
+ "link status": info['link'],
+ "promiscuous" : info['prom'],
+ "flow ctrl" : info['fc'],
}
def clear_stats(self):
@@ -726,6 +764,10 @@ class Port(object):
self.state = self.STATE_STREAMS
self.last_factor_type = None
+ def async_event_port_attr_changed (self, attr):
+ self.info['speed'] = attr['speed'] // 1000
+ self.attr = attr
+
# rest of the events are used for TUI / read only sessions
def async_event_port_stopped (self):
if not self.is_acquired():
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 5d9cdcaa..9f601484 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,6 +3,7 @@
from .utils import text_tables
from .utils.text_opts import format_text, format_threshold, format_num
from .trex_stl_types import StatNotAvailable, is_integer
+from .trex_stl_exceptions import STLError
from collections import namedtuple, OrderedDict, deque
import sys
@@ -23,8 +24,10 @@ LATENCY_STATS = 'ls'
LATENCY_HISTOGRAM = 'lh'
CPU_STATS = 'c'
MBUF_STATS = 'm'
+EXTENDED_STATS = 'x'
+EXTENDED_INC_ZERO_STATS = 'xz'
-ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM, CPU_STATS, MBUF_STATS]
+ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM, CPU_STATS, MBUF_STATS, EXTENDED_STATS, EXTENDED_INC_ZERO_STATS]
COMPACT = [GLOBAL_STATS, PORT_STATS]
GRAPH_PORT_COMPACT = [GLOBAL_STATS, PORT_GRAPH]
SS_COMPAT = [GLOBAL_STATS, STREAMS_STATS] # stream stats
@@ -147,12 +150,13 @@ class CTRexInfoGenerator(object):
STLClient and the ports.
"""
- def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, util_stats_ref, async_monitor):
+ def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, util_stats_ref, xstats_ref, async_monitor):
self._global_stats = global_stats_ref
self._ports_dict = ports_dict_ref
self._rx_stats_ref = rx_stats_ref
self._latency_stats_ref = latency_stats_ref
self._util_stats_ref = util_stats_ref
+ self._xstats_ref = xstats_ref
self._async_monitor = async_monitor
def generate_single_statistic(self, port_id_list, statistic_type):
@@ -183,6 +187,12 @@ class CTRexInfoGenerator(object):
elif statistic_type == MBUF_STATS:
return self._generate_mbuf_util_stats()
+ elif statistic_type == EXTENDED_STATS:
+ return self._generate_xstats(port_id_list, include_zero_lines = False)
+
+ elif statistic_type == EXTENDED_INC_ZERO_STATS:
+ return self._generate_xstats(port_id_list, include_zero_lines = True)
+
else:
# ignore by returning empty object
return {}
@@ -205,10 +215,9 @@ class CTRexInfoGenerator(object):
def _generate_global_stats(self):
global_stats = self._global_stats
- stats_data = OrderedDict([("connection", "{host}, Port {port}".format(host=global_stats.connection_info.get("server"),
+ stats_data_left = OrderedDict([("connection", "{host}, Port {port}".format(host=global_stats.connection_info.get("server"),
port=global_stats.connection_info.get("sync_port"))),
- ("version", "{ver}, UUID: {uuid}".format(ver=global_stats.server_version.get("version", "N/A"),
- uuid="N/A")),
+ ("version", "{ver}".format(ver=global_stats.server_version.get("version", "N/A"))),
("cpu_util.", "{0}% @ {2} cores ({3} per port) {1}".format( format_threshold(round_float(global_stats.get("m_cpu_util")), [85, 100], [0, 85]),
global_stats.get_trend_gui("m_cpu_util", use_raw = True),
@@ -221,14 +230,13 @@ class CTRexInfoGenerator(object):
("async_util.", "{0}% / {1}".format( format_threshold(round_float(self._async_monitor.get_cpu_util()), [85, 100], [0, 85]),
format_num(self._async_monitor.get_bps() / 8.0, suffix = "B/sec"))),
-
-
- (" ", ""),
+ ])
+ stats_data_right = OrderedDict([
("total_tx_L2", "{0} {1}".format( global_stats.get("m_tx_bps", format=True, suffix="b/sec"),
global_stats.get_trend_gui("m_tx_bps"))),
- ("total_tx_L1", "{0} {1}".format( global_stats.get("m_tx_bps_L1", format=True, suffix="b/sec"),
+ ("total_tx_L1", "{0} {1}".format( global_stats.get("m_tx_bps_L1", format=True, suffix="b/sec"),
global_stats.get_trend_gui("m_tx_bps_L1"))),
("total_rx", "{0} {1}".format( global_stats.get("m_rx_bps", format=True, suffix="b/sec"),
@@ -237,8 +245,6 @@ class CTRexInfoGenerator(object):
("total_pps", "{0} {1}".format( global_stats.get("m_tx_pps", format=True, suffix="pkt/sec"),
global_stats.get_trend_gui("m_tx_pps"))),
- #(" ", ""),
-
("drop_rate", "{0}".format( format_num(global_stats.get("m_rx_drop_bps"),
suffix = 'b/sec',
opts = 'green' if (global_stats.get("m_rx_drop_bps")== 0) else 'red'),
@@ -248,19 +254,29 @@ class CTRexInfoGenerator(object):
suffix = 'pkts',
compact = False,
opts = 'green' if (global_stats.get_rel("m_total_queue_full")== 0) else 'red'))),
-
- ]
- )
+ ])
# build table representation
stats_table = text_tables.TRexTextInfo()
stats_table.set_cols_align(["l", "l"])
+ stats_table.set_deco(0)
+ stats_table.set_cols_width([50, 45])
+ max_lines = max(len(stats_data_left), len(stats_data_right))
+ for line_num in range(max_lines):
+ row = []
+ if line_num < len(stats_data_left):
+ key = list(stats_data_left.keys())[line_num]
+ row.append('{:<12} : {}'.format(key, stats_data_left[key]))
+ else:
+ row.append('')
+ if line_num < len(stats_data_right):
+ key = list(stats_data_right.keys())[line_num]
+ row.append('{:<12} : {}'.format(key, stats_data_right[key]))
+ else:
+ row.append('')
+ stats_table.add_row(row)
- stats_table.add_rows([[k.replace("_", " ").title(), v]
- for k, v in stats_data.items()],
- header=False)
-
- return {"global_statistics": ExportableStats(stats_data, stats_table)}
+ return {"global_statistics": ExportableStats(None, stats_table)}
def _generate_streams_stats (self):
flow_stats = self._rx_stats_ref
@@ -325,7 +341,7 @@ class CTRexInfoGenerator(object):
def _generate_latency_stats(self):
lat_stats = self._latency_stats_ref
- latency_window_size = 10
+ latency_window_size = 14
# for TUI - maximum 5
pg_ids = list(filter(is_intable, lat_stats.latest_stats.keys()))[:5]
@@ -439,7 +455,7 @@ class CTRexInfoGenerator(object):
stats_table.set_cols_width([10, 3, 6] + [3] * (show_len - 1))
stats_table.set_cols_dtype(['t'] * (show_len + 2))
- for i in range(min(14, len(cpu_stats))):
+ for i in range(min(18, len(cpu_stats))):
history = cpu_stats[i]["history"]
ports = cpu_stats[i]["ports"]
avg = int(round(sum(history[:avg_len]) / avg_len))
@@ -504,6 +520,28 @@ class CTRexInfoGenerator(object):
stats_table.add_row(['No Data.'])
return {'mbuf_util': ExportableStats(None, stats_table)}
+ def _generate_xstats(self, port_id_list, include_zero_lines = False):
+ relevant_ports = [port.port_id for port in self.__get_relevant_ports(port_id_list)]
+ # get the data on relevant ports
+ xstats_data = OrderedDict()
+ for port_id in relevant_ports:
+ for key, val in self._xstats_ref.get_stats(port_id).items():
+ if key not in xstats_data:
+ xstats_data[key] = []
+ xstats_data[key].append(val)
+
+ # put into table
+ stats_table = text_tables.TRexTextTable()
+ stats_table.header(['Name:'] + ['Port %s:' % port_id for port_id in relevant_ports])
+ stats_table.set_cols_align(['l'] + ['r'] * len(relevant_ports))
+ stats_table.set_cols_width([30] + [15] * len(relevant_ports))
+ stats_table.set_cols_dtype(['t'] * (len(relevant_ports) + 1))
+ for key, arr in xstats_data.items():
+ if include_zero_lines or list(filter(None, arr)):
+ key = key[:28]
+ stats_table.add_row([key] + arr)
+ return {'xstats:': ExportableStats(None, stats_table)}
+
@staticmethod
def _get_rational_block_char(value, range_start, interval):
# in Konsole, utf-8 is sometimes printed with artifacts, return ascii for now
@@ -557,6 +595,7 @@ class CTRexInfoGenerator(object):
return_stats_data = {}
per_field_stats = OrderedDict([("owner", []),
+ ('link', []),
("state", []),
("speed", []),
("CPU util.", []),
@@ -584,8 +623,7 @@ class CTRexInfoGenerator(object):
("oerrors", []),
("ierrors", []),
- ]
- )
+ ])
total_stats = CPortStats(None)
@@ -625,9 +663,12 @@ class CTRexInfoGenerator(object):
return_stats_data = {}
per_field_status = OrderedDict([("driver", []),
- ("maximum", []),
- ("status", []),
+ ("description", []),
+ ("link status", []),
+ ("link speed", []),
+ ("port status", []),
("promiscuous", []),
+ ("flow ctrl", []),
("--", []),
("HW src mac", []),
("SW src mac", []),
@@ -1003,6 +1044,7 @@ class CPortStats(CTRexStats):
def _update(self, snapshot):
+ speed = self._port_obj.get_speed_bps()
# L1 bps
tx_bps = snapshot.get("m_total_tx_bps")
@@ -1015,22 +1057,34 @@ class CPortStats(CTRexStats):
bps_rx_L1 = calc_bps_L1(rx_bps, rx_pps)
snapshot['m_total_tx_bps_L1'] = bps_tx_L1
- snapshot['m_tx_util'] = (bps_tx_L1 / self._port_obj.get_speed_bps()) * 100.0
+ if speed:
+ snapshot['m_tx_util'] = (bps_tx_L1 / speed) * 100.0
+ else:
+ snapshot['m_tx_util'] = 0
snapshot['m_total_rx_bps_L1'] = bps_rx_L1
- snapshot['m_rx_util'] = (bps_rx_L1 / self._port_obj.get_speed_bps()) * 100.0
+ if speed:
+ snapshot['m_rx_util'] = (bps_rx_L1 / speed) * 100.0
+ else:
+ snapshot['m_rx_util'] = 0
# TX line util not smoothed
diff_tx_pkts = snapshot.get('opackets', 0) - self.latest_stats.get('opackets', 0)
diff_tx_bytes = snapshot.get('obytes', 0) - self.latest_stats.get('obytes', 0)
tx_bps_L1 = calc_bps_L1(8.0 * diff_tx_bytes / ts_diff, float(diff_tx_pkts) / ts_diff)
- snapshot['tx_percentage'] = 100.0 * tx_bps_L1 / self._port_obj.get_speed_bps()
+ if speed:
+ snapshot['tx_percentage'] = 100.0 * tx_bps_L1 / speed
+ else:
+ snapshot['tx_percentage'] = 0
# RX line util not smoothed
diff_rx_pkts = snapshot.get('ipackets', 0) - self.latest_stats.get('ipackets', 0)
diff_rx_bytes = snapshot.get('ibytes', 0) - self.latest_stats.get('ibytes', 0)
rx_bps_L1 = calc_bps_L1(8.0 * diff_rx_bytes / ts_diff, float(diff_rx_pkts) / ts_diff)
- snapshot['rx_percentage'] = 100.0 * rx_bps_L1 / self._port_obj.get_speed_bps()
+ if speed:
+ snapshot['rx_percentage'] = 100.0 * rx_bps_L1 / speed
+ else:
+ snapshot['rx_percentage'] = 0
# simple...
self.latest_stats = snapshot
@@ -1040,13 +1094,24 @@ class CPortStats(CTRexStats):
def generate_stats(self):
- state = self._port_obj.get_port_state_name() if self._port_obj else ""
- if state == "ACTIVE":
- state = format_text(state, 'green', 'bold')
- elif state == "PAUSE":
- state = format_text(state, 'magenta', 'bold')
+ port_state = self._port_obj.get_port_state_name() if self._port_obj else ""
+ if port_state == "TRANSMITTING":
+ port_state = format_text(port_state, 'green', 'bold')
+ elif port_state == "PAUSE":
+ port_state = format_text(port_state, 'magenta', 'bold')
+ else:
+ port_state = format_text(port_state, 'bold')
+
+ if self._port_obj:
+ if 'link' in self._port_obj.attr:
+ if self._port_obj.attr.get('link', {}).get('up') == False:
+ link_state = format_text('DOWN', 'red', 'bold')
+ else:
+ link_state = 'UP'
+ else:
+ link_state = 'N/A'
else:
- state = format_text(state, 'bold')
+ link_state = ''
# default rate format modifiers
rate_format = {'bpsl1': None, 'bps': None, 'pps': None, 'percentage': 'bold'}
@@ -1063,7 +1128,8 @@ class CPortStats(CTRexStats):
return {"owner": owner,
- "state": "{0}".format(state),
+ "state": "{0}".format(port_state),
+ 'link': link_state,
"speed": self._port_obj.get_formatted_speed() if self._port_obj else '',
"CPU util.": "{0} {1}%".format(self.get_trend_gui("m_cpu_util", use_raw = True),
format_threshold(round_float(self.get("m_cpu_util")), [85, 100], [0, 85])) if self._port_obj else '' ,
@@ -1417,7 +1483,7 @@ class CUtilStats(CTRexStats):
self.client = client
self.history = deque(maxlen = 1)
self.mbuf_types_list = None
- self.last_update_ts = 0
+ self.last_update_ts = -999
def get_stats(self, use_1sec_cache = False):
time_now = time.time()
@@ -1425,7 +1491,7 @@ class CUtilStats(CTRexStats):
if self.client.is_connected():
rc = self.client._transmit('get_utilization')
if not rc:
- raise Exception(rc)
+ raise STLError(rc)
self.last_update_ts = time_now
self.history.append(rc.data())
else:
@@ -1433,6 +1499,51 @@ class CUtilStats(CTRexStats):
return self.history[-1]
+class CXStats(CTRexStats):
+
+ def __init__(self, client):
+ super(CXStats, self).__init__()
+ self.client = client
+ self.names = []
+ self.last_update_ts = -999
+
+ def clear_stats(self, port_id = None):
+ if port_id == None:
+ ports = self.client.get_all_ports()
+ elif type(port_id) is list:
+ ports = port_id
+ else:
+ ports = [port_id]
+
+ for port_id in ports:
+ self.reference_stats[port_id] = self.get_stats(port_id, relative = False)
+
+ def get_stats(self, port_id, use_1sec_cache = False, relative = True):
+ time_now = time.time()
+ if self.last_update_ts + 1 < time_now or not self.latest_stats or not use_1sec_cache:
+ if self.client.is_connected():
+ rc = self.client._transmit('get_port_xstats_values', params = {'port_id': port_id})
+ if not rc:
+ raise STLError(rc)
+ self.last_update_ts = time_now
+ values = rc.data().get('xstats_values', [])
+ if len(values) != len(self.names): # need to update names ("keys")
+ rc = self.client._transmit('get_port_xstats_names', params = {'port_id': port_id})
+ if not rc:
+ raise STLError(rc)
+ self.names = rc.data().get('xstats_names', [])
+ if len(values) != len(self.names):
+ raise STLError('Length of get_xstats_names: %s and get_port_xstats_values: %s' % (len(self.names), len(values)))
+ self.latest_stats[port_id] = OrderedDict([(key, val) for key, val in zip(self.names, values)])
+
+ stats = OrderedDict()
+ for key, val in self.latest_stats[port_id].items():
+ if relative:
+ stats[key] = self.get_rel([port_id, key])
+ else:
+ stats[key] = self.get([port_id, key])
+ return stats
+
if __name__ == "__main__":
pass
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py
index 3993ad5e..fe4fc893 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py
@@ -85,27 +85,29 @@ class GA_EXCEPTION_ObjClass(GA_ObjClass):
#..................................................................class GA_TESTING_ObjClass................................................................
class GA_TESTING_ObjClass(GA_ObjClass):
- def __init__(self,cid,uuid,trackerID,TRexMode,test_name,setup_name,appName,appVer,commitID,bandwidthPerCore,goldenBPC):
+ def __init__(self,cid,trackerID,TRexMode,TestName,SetupName,appName,ActionNumber,appVer,TestType,Mppspc,GoldenMin,GoldenMax):
GA_ObjClass.__init__(self,cid,trackerID,appName,appVer)
- self.uid = uuid
+ self.ActionNumber = ActionNumber
self.TRexMode = TRexMode
- self.test_name = test_name
- self.setup_name = setup_name
- self.commitID = commitID
- self.bandwidthPerCore = bandwidthPerCore
- self.goldenBPC = goldenBPC
+ self.TestName = TestName
+ self.SetupName = SetupName
+ self.TestType = TestType
+ self.Mppspc = Mppspc
+ self.GoldenMin = GoldenMin
+ self.GoldenMax = GoldenMax
self.payload = self.generate_payload()
self.size = sys.getsizeof(self.payload)
def generate_payload(self):
- self.payload+='&ec='+str(self.TRexMode)
- self.payload+='&ea=RegressionReport'
- self.payload+='&cd5='+str(self.uid)
- self.payload+='&cd1='+str(self.test_name)
- self.payload+='&cd2='+str(self.setup_name)
- self.payload+='&cd3='+str(self.commitID)
- self.payload+='&cm1='+str(self.bandwidthPerCore)
- self.payload+='&cm2='+str(self.goldenBPC)
+ self.payload+='&ec=TRexTests'
+ self.payload+='&ea='+str(self.ActionNumber)
+ self.payload+='&cd2='+str(self.TRexMode)
+ self.payload+='&cd1='+str(self.TestName)
+ self.payload+='&cd3='+str(self.SetupName)
+ self.payload+='&cd4='+str(self.TestType)
+ self.payload+='&cm1='+str(self.Mppspc)
+ self.payload+='&cm2='+str(self.GoldenMin)
+ self.payload+='&cm3='+str(self.GoldenMax)
return self.payload
#.....................................................................class ga_Thread.................................................................
"""
@@ -265,7 +267,6 @@ class GAmanager:
attributes:
GoogleID - the tracker ID that Google uses in order to track the activity of a property. for regression use: 'UA-75220362-4'
AnalyticsUserID - text value - used by Google to differ between 2 users sending data. (will not be presented on reports). use only as a way to differ between different users
-UUID - text - will be presented on analysis. put here UUID
TRexMode - text - will be presented on analysis. put here TRexMode
appName - text - will be presented on analysis. put here appName as string describing app name
appVer - text - will be presented on analysis. put here the appVer
@@ -274,83 +275,21 @@ Timeout - integer (seconds) - the timeout in seconds between automated reports w
UserPermission - boolean (1/0) - required in order to send packets, should be 1.
BlockingMode - boolean (1/0) - required when each tracked event is critical and program should halt until the event is reported
SetupName - text - will be presented on analysis. put here setup name as string.
-CommitID - text - will be presented on analysis. put here CommitID
"""
class GAmanager_Regression(GAmanager):
- def __init__(self,GoogleID,AnalyticsUserID,UUID,TRexMode,appName,appVer,
- QueueSize,Timeout,UserPermission,BlockingMode,SetupName,CommitID):
- GAmanager.__init__(self,GoogleID,AnalyticsUserID,appName,appVer,
- QueueSize,Timeout,UserPermission,BlockingMode)
- self.UUID = UUID
- self.TRexMode = TRexMode
- self.SetupName = SetupName
- self.CommitID = CommitID
-
- def gaAddTestQuery(self,TestName,BandwidthPerCore,GoldenBPC):
- self.gaAddObject(GA_TESTING_ObjClass(self.UserID,self.UUID,self.GoogleID,
- self.TRexMode,TestName,self.SetupName,
- self.appName,self.appVer,self.CommitID,
- BandwidthPerCore,GoldenBPC))
-
-
-
-
-#***************************************------TEST--------------**************************************
-
-
-#if __name__ == '__main__':
-
-#g= GAmanager_Regression(GoogleID='UA-75220362-4',AnalyticsUserID=3845,UUID='trex18UUID_GA_TEST',TRexMode='stateFull_GA_TEST',
-# appName='TRex_GA_TEST',appVer='1.1_GA_TEST',QueueSize=20,Timeout=11,UserPermission=1,BlockingMode=0,SetupName='setup1_GA_TEST',CommitID='commitID1_GA_TEST')
-#for j in range(1,3,1):
-#for i in range(100,118,1):
-# g.gaAddTestQuery('test_name_GA_TEST',i+0.5,150)
-# sleep(11)
-# print "finished batch"
-#g.emptyAndReportQ()
-
-#g.printSelf()
-#g.emptyAndReportQ()
-
-#g = GAmanager(GoogleID='UA-75220362-4',UserID=1,QueueSize=100,Timeout=5,UserPermission=1,BlockingMode=0,appName='TRex',appVer='1.11.232') #timeout in seconds
-#for i in range(0,35,1):
-# g.gaAddAction(Event='test',action='start',label='1',value=i)
-#g.gaAddException('MEMFAULT',1)
-#g.emptyAndReportQ()
-#g.printSelf()
-#print g.payload
-#print g.size
-
-
-
-
-#g.activate()
-#g.gaAddAction(Event='test',action='start',label='1',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-#g.gaAddAction(Event='test',action='start',label='2',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-#g.gaAddAction(Event='test',action='start',label='3',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-
-#testdata = "v=1&t=event&tid=UA-75220362-4&cid=2&ec=test&ea=testing&el=testpacket&ev=2"
-#r = requests.post(url_debug,data=testdata)
-#print r
-
-#thread1 = ga_Thread(1,g)
-#thread1.start()
-#thread1.join()
-#for i in range(1,10,1):
-# sys.stdout.write('yesh %d'% (i))
-# sys.stdout.flush()
+ def __init__(self, GoogleID, AnalyticsUserID, appName, appVer,
+ QueueSize, Timeout, UserPermission, BlockingMode):
+ GAmanager.__init__(self, GoogleID, AnalyticsUserID, appName, appVer,
+ QueueSize, Timeout, UserPermission, BlockingMode)
+ self.GoogleID = GoogleID
+ self.AnalyticsUserID = AnalyticsUserID
+
+ def gaAddTestQuery(self, TestName, TRexMode, SetupName, ActionNumber, TestType, Mppspc, GoldenMin, GoldenMax):
+ self.gaAddObject(GA_TESTING_ObjClass(self.AnalyticsUserID, self.GoogleID, TRexMode, TestName, SetupName, self.appName, ActionNumber, self.appVer, TestType, Mppspc, GoldenMin, GoldenMax))
-
-
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py
index 638684c3..72ee8972 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py
@@ -27,9 +27,9 @@ def user_input():
return raw_input()
-def random_id_gen(length=8):
+class random_id_gen:
"""
- A generator for creating a random chars id of specific length
+ Emulated generator for creating a random chars id of specific length
:parameters:
length : int
@@ -40,12 +40,15 @@ def random_id_gen(length=8):
:return:
a random id with each next() request.
"""
- id_chars = string.ascii_lowercase + string.digits
- while True:
- return_id = ''
- for i in range(length):
- return_id += random.choice(id_chars)
- yield return_id
+ def __init__(self, length=8):
+ self.id_chars = string.ascii_lowercase + string.digits
+ self.length = length
+
+ def next(self):
+ return ''.join(random.choice(self.id_chars) for _ in range(self.length))
+
+ __next__ = next
+
# try to get number from input, return None in case of fail
def get_number(input):
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py
new file mode 100755
index 00000000..a4942094
--- /dev/null
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py
@@ -0,0 +1,26 @@
+from collections import OrderedDict
+
+ON_OFF_DICT = OrderedDict([
+ ('on', True),
+ ('off', False),
+])
+
+UP_DOWN_DICT = OrderedDict([
+ ('up', True),
+ ('down', False),
+])
+
+FLOW_CTRL_DICT = OrderedDict([
+ ('none', 0), # Disable flow control
+ ('tx', 1), # Enable flowctrl on TX side (RX pause frames)
+ ('rx', 2), # Enable flowctrl on RX side (TX pause frames)
+ ('full', 3), # Enable flow control on both sides
+])
+
+
+
+# generate reverse dicts
+
+for var_name in list(vars().keys()):
+ if var_name.endswith('_DICT'):
+ exec('{0}_REVERSED = OrderedDict([(val, key) for key, val in {0}.items()])'.format(var_name))
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
index 8ae86981..7eda8635 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
@@ -1,8 +1,9 @@
import argparse
-from collections import namedtuple
+from collections import namedtuple, OrderedDict
from .common import list_intersect, list_difference
from .text_opts import format_text
from ..trex_stl_types import *
+from .constants import ON_OFF_DICT, UP_DOWN_DICT, FLOW_CTRL_DICT
import sys
import re
@@ -32,14 +33,16 @@ IPG = 16
SPEEDUP = 17
COUNT = 18
PROMISCUOUS = 19
-NO_PROMISCUOUS = 20
-PROMISCUOUS_SWITCH = 21
+LINK_STATUS = 20
+LED_STATUS = 21
TUNABLES = 22
REMOTE_FILE = 23
LOCKED = 24
PIN_CORES = 25
CORE_MASK = 26
DUAL = 27
+FLOW_CTRL = 28
+SUPPORTED = 29
GLOBAL_STATS = 50
PORT_STATS = 51
@@ -48,6 +51,8 @@ STREAMS_STATS = 53
STATS_MASK = 54
CPU_STATS = 55
MBUF_STATS = 56
+EXTENDED_STATS = 57
+EXTENDED_INC_ZERO_STATS = 58
STREAMS_MASK = 60
CORE_MASK_GROUP = 61
@@ -282,10 +287,26 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'type': int}),
PROMISCUOUS: ArgumentPack(['--prom'],
- {'help': "Sets port promiscuous on",
- 'dest': "prom",
- 'default': None,
- 'action': "store_true"}),
+ {'help': "Set port promiscuous on/off",
+ 'choices': ON_OFF_DICT}),
+
+ LINK_STATUS: ArgumentPack(['--link'],
+ {'help': 'Set link status up/down',
+ 'choices': UP_DOWN_DICT}),
+
+ LED_STATUS: ArgumentPack(['--led'],
+ {'help': 'Set LED status on/off',
+ 'choices': ON_OFF_DICT}),
+
+ FLOW_CTRL: ArgumentPack(['--fc'],
+ {'help': 'Set Flow Control type',
+ 'dest': 'flow_ctrl',
+ 'choices': FLOW_CTRL_DICT}),
+
+ SUPPORTED: ArgumentPack(['--supp'],
+ {'help': 'Show which attributes are supported by current NICs',
+ 'default': None,
+ 'action': 'store_true'}),
TUNABLES: ArgumentPack(['-t'],
{'help': "Sets tunables for a profile. Example: '-t fsize=100,pg_id=7'",
@@ -295,12 +316,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'action': 'merge',
'type': decode_tunables}),
- NO_PROMISCUOUS: ArgumentPack(['--no-prom', '--no_prom'],
- {'help': "Sets port promiscuous off",
- 'dest': "prom",
- 'default': None,
- 'action': "store_false"}),
-
PORT_LIST: ArgumentPack(['--port', '-p'],
{"nargs": '+',
'dest':'ports',
@@ -401,6 +416,14 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
{'action': 'store_true',
'help': "Fetch only MBUF utilization stats"}),
+ EXTENDED_STATS: ArgumentPack(['-x'],
+ {'action': 'store_true',
+ 'help': "Fetch xstats of port, excluding lines with zero values"}),
+
+ EXTENDED_INC_ZERO_STATS: ArgumentPack(['--xz'],
+ {'action': 'store_true',
+ 'help': "Fetch xstats of port, including lines with zero values"}),
+
STREAMS_MASK: ArgumentPack(['--streams'],
{"nargs": '+',
'dest':'streams',
@@ -424,12 +447,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'default': None,
'help': "Core mask - only cores responding to the bit mask will be active"}),
-
- # promiscuous
- PROMISCUOUS_SWITCH: ArgumentGroup(MUTEX, [PROMISCUOUS,
- NO_PROMISCUOUS],
- {'required': False}),
-
# advanced options
PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST,
ALL_PORTS],
@@ -443,7 +460,9 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
PORT_STATUS,
STREAMS_STATS,
CPU_STATS,
- MBUF_STATS],
+ MBUF_STATS,
+ EXTENDED_STATS,
+ EXTENDED_INC_ZERO_STATS,],
{}),
@@ -462,6 +481,8 @@ class _MergeAction(argparse._AppendAction):
items.extend(values)
elif type(items) is dict and type(values) is dict: # tunables are dict
items.update(values)
+ else:
+ raise Exception("Argparser 'merge' option should be used on dict or list.")
setattr(namespace, self.dest, items)