diff options
Diffstat (limited to 'scripts/automation/trex_control_plane')
4 files changed, 138 insertions, 34 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 82aa932d..b11ddbe3 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 @@ -560,11 +560,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) @@ -1785,6 +1788,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): @@ -2462,7 +2484,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) @@ -2572,12 +2594,15 @@ 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 @@ -2589,11 +2614,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 +3201,28 @@ 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, + ) 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) + # 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]): 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() - + 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_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_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 5d9cdcaa..eaa5e8b0 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 @@ -147,12 +147,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): @@ -1003,6 +1004,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 +1017,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 @@ -1417,7 +1431,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() @@ -1433,6 +1447,40 @@ class CUtilStats(CTRexStats): return self.history[-1] +class CXStats(CTRexStats): + + def __init__(self, client): + super(CXStats, self).__init__() + self.client = client + self.history = deque(maxlen = 1) + self.names = {} + self.last_update_ts = -999 + + def get_stats(self, port_id, use_1sec_cache = False): + time_now = time.time() + if self.last_update_ts + 1 < time_now or not self.history 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) + 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) + 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({}) + + stats = {} + for key, val in self.history[-1].items(): + stats[key] = self.history[-1][key] - self.reference_stats.get(key, 0) + return stats + if __name__ == "__main__": pass 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..148f7715 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,5 +1,5 @@ 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 * @@ -11,6 +11,18 @@ 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 @@ -32,14 +44,15 @@ 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 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -282,10 +295,21 @@ 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 on/off', + 'choices': on_off_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}), TUNABLES: ArgumentPack(['-t'], {'help': "Sets tunables for a profile. Example: '-t fsize=100,pg_id=7'", @@ -295,12 +319,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', @@ -424,12 +442,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], @@ -462,6 +474,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) |