From 2dab6b6d09f9f1474d2ade6b465ebfa5ce3b3f5e Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sat, 22 Oct 2016 10:38:27 +0200 Subject: dpdk_setup_ports.py: fix add of help in case of "t-rex-64 --help" dpdk_setup_ports.py: fix warning of TRex is already running if different NICs are being used singleton_daemon.py: fix error socket in use immediately after check if in use trex-console: fix crash in case of "tui --help" trex-console: try-catch commands instead of crashing add async notification on port status/atttibutes change add port xstats support add description of interfaces main_dpdk.cpp: fix --client_cfg not working with Python API Signed-off-by: Yaroslav Brustinov --- .../trex_control_plane/stl/console/trex_console.py | 37 +++--- .../stl/trex_stl_lib/trex_stl_client.py | 45 +++++-- .../stl/trex_stl_lib/trex_stl_jsonrpc_client.py | 2 +- .../stl/trex_stl_lib/trex_stl_port.py | 59 +++++++-- .../stl/trex_stl_lib/trex_stl_stats.py | 144 +++++++++++++++------ .../stl/trex_stl_lib/utils/common.py | 15 ++- .../stl/trex_stl_lib/utils/constants.py | 26 ++++ .../stl/trex_stl_lib/utils/parsing_opts.py | 43 +++--- 8 files changed, 279 insertions(+), 92 deletions(-) create mode 100755 scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py (limited to 'scripts/automation/trex_control_plane/stl') 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 b11ddbe3..ec7e6eef 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 @@ -320,6 +320,13 @@ class EventsHandler(object): ev = "port {0} job failed".format(port_id) show_event = True + # port attr changed + elif (type == 8): + port_id = int(data['port_id']) + ev = "port {0} attributes changed".format(port_id) + show_event = True + self.__async_event_port_attr_changed(port_id, data['attr']) + # server stopped elif (type == 100): ev = "Server has stopped" @@ -372,6 +379,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): @@ -887,7 +897,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() @@ -904,6 +914,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 @@ -2501,6 +2514,9 @@ class STLClient(object): clear_latency_stats : bool Clear the latency stats + clear_xstats : bool + Clear the extended stats + :raises: + :exc:`STLError` @@ -2513,7 +2529,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) @@ -2605,7 +2621,7 @@ class STLClient(object): flow_ctrl - 0: disable all, 1: enable tx side, 2: enable rx side, 3: full enable :raises: - None + + :exe:'STLError' """ @@ -3205,23 +3221,34 @@ class STLClient(object): 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.on_off_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) + 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 not filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl]): + 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 - return self.set_port_attr(opts.ports, opts.prom, opts.link, opts.led, opts.flow_ctrl) + 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 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_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index f0e3b109..4a094c5d 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 @@ -250,9 +251,10 @@ class Port(object): self.next_available_id = int(rc.data()['max_stream_id']) + 1 # attributes - self.attr = rc.data()['attr'] + self.attr = ['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,48 @@ 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 '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 self.attr.get('promiscuous'): + if 'promiscuous' in self.attr: info['prom'] = "on" if self.attr['promiscuous']['enabled'] else "off" else: info['prom'] = "N/A" + if 'description' in info: + if len(info['description']) > 18: + info['description'] = info['description'][:18] + else: + 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 +709,7 @@ class Port(object): info = self.get_info() return {"driver": info['driver'], + "description": info.get('description', 'N/A'), "HW src mac": info['hw_macaddr'], "SW src mac": info['src_macaddr'], "SW dst mac": info['dst_macaddr'], @@ -679,9 +717,10 @@ 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']), + "status": '%s (link %s)' % (info['status'], info['link']), + "promiscuous" : info['prom'], + "flow ctrl" : info['fc'], } def clear_stats(self): @@ -726,6 +765,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 eaa5e8b0..783387ca 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 @@ -184,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 {} @@ -206,7 +215,7 @@ 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")), @@ -222,14 +231,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"), @@ -238,8 +246,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'), @@ -249,19 +255,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 @@ -505,6 +521,29 @@ 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)): + if len(key) > 28: + 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 @@ -558,6 +597,7 @@ class CTRexInfoGenerator(object): return_stats_data = {} per_field_stats = OrderedDict([("owner", []), + ('link', []), ("state", []), ("speed", []), ("CPU util.", []), @@ -585,8 +625,7 @@ class CTRexInfoGenerator(object): ("oerrors", []), ("ierrors", []), - ] - ) + ]) total_stats = CPortStats(None) @@ -626,9 +665,11 @@ class CTRexInfoGenerator(object): return_stats_data = {} per_field_status = OrderedDict([("driver", []), - ("maximum", []), + ("description", []), + ("link speed", []), ("status", []), ("promiscuous", []), + ("flow ctrl", []), ("--", []), ("HW src mac", []), ("SW src mac", []), @@ -1054,13 +1095,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 == "ACTIVE": + port_state = format_text('TRANSMITTING', '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'} @@ -1077,7 +1129,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 '' , @@ -1439,7 +1492,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: @@ -1452,33 +1505,44 @@ class CXStats(CTRexStats): def __init__(self, client): super(CXStats, self).__init__() self.client = client - self.history = deque(maxlen = 1) - self.names = {} + self.names = [] self.last_update_ts = -999 - def get_stats(self, port_id, use_1sec_cache = False): + 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.history or not use_1sec_cache: + 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 Exception(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 Exception(rc) + raise STLError(rc) self.names = rc.data().get('xstats_names', []) if len(values) != len(self.names): - raise Exception('Length of get_xstats_names: %s and get_port_xstats_values: %s' % (len(self.names), len(values))) - self.history.append(dict([(key, val) for key, val in zip(self.names, values)])) - else: - self.history.append({}) + 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 = {} - for key, val in self.history[-1].items(): - stats[key] = self.history[-1][key] - self.reference_stats.get(key, 0) + 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__": 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..0214d7d7 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,7 +27,7 @@ def user_input(): return raw_input() -def random_id_gen(length=8): +def random_id_gen_unsafe(length=8): """ A generator for creating a random chars id of specific length @@ -47,6 +47,19 @@ def random_id_gen(length=8): return_id += random.choice(id_chars) yield return_id + +class random_id_gen: + """ Thread safe version of random_id_gen_unsafe """ + 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): try: 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 148f7715..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 @@ -3,6 +3,7 @@ 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 @@ -11,18 +12,6 @@ import os ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options']) -on_off_dict = OrderedDict([ - ('on', True), - ('off', 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 -]) - # list of available parsing options MULTIPLIER = 1 @@ -53,6 +42,7 @@ PIN_CORES = 25 CORE_MASK = 26 DUAL = 27 FLOW_CTRL = 28 +SUPPORTED = 29 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -61,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 @@ -296,20 +288,25 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], PROMISCUOUS: ArgumentPack(['--prom'], {'help': "Set port promiscuous on/off", - 'choices': on_off_dict}), + 'choices': ON_OFF_DICT}), LINK_STATUS: ArgumentPack(['--link'], - {'help': 'Set link status on/off', - 'choices': on_off_dict}), + {'help': 'Set link status up/down', + 'choices': UP_DOWN_DICT}), LED_STATUS: ArgumentPack(['--led'], {'help': 'Set LED status on/off', - 'choices': on_off_dict}), + 'choices': ON_OFF_DICT}), FLOW_CTRL: ArgumentPack(['--fc'], {'help': 'Set Flow Control type', 'dest': 'flow_ctrl', - 'choices': flow_ctrl_dict}), + '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'", @@ -419,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', @@ -455,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,], {}), -- cgit 1.2.3-korg