diff options
11 files changed, 154 insertions, 166 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 76e6898c..a241fe1b 100644 --- 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 @@ -619,6 +619,7 @@ class STLClient(object): return rc + # connect to server def __connect(self): @@ -662,12 +663,14 @@ class STLClient(object): # create ports for port_id in xrange(self.system_info["port_count"]): - speed = self.system_info['ports'][port_id]['speed'] - driver = self.system_info['ports'][port_id]['driver'] + speed = self.system_info['ports'][port_id]['speed'] + driver = self.system_info['ports'][port_id]['driver'] + macaddr = self.system_info['ports'][port_id]['macaddr'] self.ports[port_id] = Port(port_id, speed, driver, + macaddr, self.username, self.comm_link, self.session_id) @@ -744,24 +747,24 @@ class STLClient(object): ############ functions used by other classes but not users ############## - def _verify_port_id_list (self, port_id_list): - # check arguments - if not isinstance(port_id_list, list): - return RC_ERR("ports should be an instance of 'list' not {0}".format(type(port_id_list))) - - # all ports are valid ports - if not port_id_list or not all([port_id in self.get_all_ports() for port_id in port_id_list]): - return RC_ERR("") - - return RC_OK() + def _validate_port_list (self, port_id_list): + # listfiy single int + if isinstance(port_id_list, int): + port_id_list = [port_id_list] - def _validate_port_list(self, port_id_list): + # should be a list if not isinstance(port_id_list, list): - return False + raise STLTypeError('port_id_list', type(port_id_list), list) - # check each item of the sequence - return (port_id_list and all([port_id in self.get_all_ports() for port_id in port_id_list])) + if not port_id_list: + raise STLError('No ports provided') + valid_ports = self.get_all_ports() + for port_id in port_id_list: + if not port_id in valid_ports: + raise STLError("Port ID '{0}' is not a valid port ID - valid values: {1}".format(port_id, valid_ports)) + + return port_id_list # transmit request on the RPC link @@ -931,16 +934,9 @@ class STLClient(object): # get stats def get_stats (self, ports = None, async_barrier = True): - # by default use all ports - if ports == None: - ports = self.get_acquired_ports() - else: - ports = self.__ports(ports) - - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + # 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: @@ -959,6 +955,16 @@ class STLClient(object): def get_events (self): return self.event_handler.get_events() + # get port(s) info as a list of dicts + @__api_check(True) + def get_port_info (self, ports = None): + + ports = ports if ports is not None else self.get_all_ports() + ports = self._validate_port_list(ports) + + return [self.ports[port_id].get_info() for port_id in ports] + + ############################ Commands ############################# ############################ ############################# ############################ ############################# @@ -1046,16 +1052,11 @@ class STLClient(object): """ @__api_check(True) def acquire (self, ports = None, force = False): - # by default use all ports - if ports == None: - ports = self.get_all_ports() - # verify ports - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + # by default use all ports + ports = ports if ports is not None else self.get_all_ports() + ports = self._validate_port_list(ports) - # verify valid port id list if force: self.logger.pre_cmd("Force acquiring ports {0}:".format(ports)) else: @@ -1084,14 +1085,9 @@ class STLClient(object): """ @__api_check(True) def release (self, ports = None): - # by default use all acquired ports - if ports == None: - ports = self.get_acquired_ports() - # verify ports - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) self.logger.pre_cmd("Releasing ports {0}:".format(ports)) rc = self.__release(ports) @@ -1139,14 +1135,8 @@ class STLClient(object): @__api_check(True) def reset(self, ports = None): - # by default use all ports - if ports == None: - ports = self.get_all_ports() - - # verify ports - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_all_ports() + ports = self._validate_port_list(ports) self.acquire(ports, force = True) self.stop(ports) @@ -1169,14 +1159,8 @@ class STLClient(object): @__api_check(True) def remove_all_streams (self, ports = None): - # by default use all ports - if ports == None: - ports = self.get_acquired_ports() - - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) self.logger.pre_cmd("Removing all streams from port(s) {0}:".format(ports)) rc = self.__remove_all_streams(ports) @@ -1204,14 +1188,9 @@ class STLClient(object): """ @__api_check(True) def add_streams (self, streams, ports = None): - # by default use all ports - if ports == None: - ports = self.get_acquired_ports() - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) # transform single stream if not isinstance(streams, list): @@ -1247,14 +1226,9 @@ class STLClient(object): """ @__api_check(True) def remove_streams (self, stream_id_list, ports = None): - # by default use all ports - if ports == None: - ports = self.get_acquired_ports() - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) # transform single stream if not isinstance(stream_id_list, list): @@ -1311,14 +1285,9 @@ class STLClient(object): total = False): - # by default use all ports - if ports == None: - ports = self.get_acquired_ports() + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, @@ -1376,16 +1345,11 @@ class STLClient(object): @__api_check(True) def stop (self, ports = None): - # by default the user means all the active ports - if ports == None: - ports = self.get_active_ports() - if not ports: - return + ports = ports if ports is not None else self.get_active_ports() + ports = self._validate_port_list(ports) - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + if not ports: + return self.logger.pre_cmd("Stopping traffic on port(s) {0}:".format(ports)) rc = self.__stop(ports) @@ -1423,14 +1387,9 @@ class STLClient(object): @__api_check(True) def update (self, ports = None, mult = "1", total = False, force = False): - # by default the user means all the active ports - if ports == None: - ports = self.get_active_ports() + ports = ports if ports is not None else self.get_active_ports() + ports = self._validate_port_list(ports) - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, @@ -1468,14 +1427,8 @@ class STLClient(object): @__api_check(True) def pause (self, ports = None): - # by default the user means all the TX ports - if ports == None: - ports = self.get_transmitting_ports() - - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_transmitting_ports() + ports = self._validate_port_list(ports) self.logger.pre_cmd("Pausing traffic on port(s) {0}:".format(ports)) rc = self.__pause(ports) @@ -1500,14 +1453,9 @@ class STLClient(object): @__api_check(True) def resume (self, ports = None): - # by default the user means all the paused ports - if ports == None: - ports = self.get_paused_ports() + ports = ports if ports is not None else self.get_paused_ports() + ports = self._validate_port_list(ports) - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) self.logger.pre_cmd("Resume traffic on port(s) {0}:".format(ports)) rc = self.__resume(ports) @@ -1542,13 +1490,10 @@ class STLClient(object): """ @__api_check(True) def validate (self, ports = None, mult = "1", duration = "-1", total = False): - if ports == None: - ports = self.get_acquired_ports() - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) + # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, @@ -1588,16 +1533,8 @@ class STLClient(object): @__api_check(False) def clear_stats (self, ports = None, clear_global = True): - # by default use all ports - if ports == None: - ports = self.get_all_ports() - else: - ports = self.__ports(ports) - - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_all_ports() + ports = self._validate_port_list(ports) # verify clear global if not type(clear_global) is bool: @@ -1630,14 +1567,9 @@ class STLClient(object): @__api_check(True) def wait_on_traffic (self, ports = None, timeout = 60): - # by default use all acquired ports - if ports == None: - ports = self.get_acquired_ports() + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) expr = time.time() + timeout @@ -1661,14 +1593,9 @@ class STLClient(object): """ @__api_check(True) def set_port_attr (self, ports = None, promiscuous = None): - # by default use all acquired ports - if ports == None: - ports = self.get_acquired_ports() - # verify valid port id list - rc = self._validate_port_list(ports) - if not rc: - raise STLArgumentError('ports', ports, valid_values = self.get_all_ports()) + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) # check arguments validate_type('promiscuous', promiscuous, (bool, NoneType)) @@ -2094,13 +2021,4 @@ class STLClient(object): print e.brief() return - # show - print "" - for port_id in opts.ports: - print format_text('Port {0}:\n'.format(port_id), 'bold', 'underline') - for k, v in self.get_port(port_id).get_attr().iteritems(): - print "{0}:".format(k) - for pk, pv in v.iteritems(): - print " {0}: {1}".format(pk, format_text(str(pv), 'bold')) - print "" - + 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 8d542b35..f2d4cd95 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 @@ -41,7 +41,7 @@ class Port(object): STATE_PAUSE: "PAUSE"} - def __init__ (self, port_id, speed, driver, user, comm_link, session_id): + def __init__ (self, port_id, speed, driver, macaddr, user, comm_link, session_id): self.port_id = port_id self.state = self.STATE_IDLE self.handler = None @@ -51,6 +51,7 @@ class Port(object): self.user = user self.driver = driver self.speed = speed + self.macaddr = macaddr self.streams = {} self.profile = None self.session_id = session_id @@ -473,9 +474,6 @@ class Port(object): return self.ok() - def get_attr (self): - return self.attr - def get_profile (self): return self.profile @@ -520,6 +518,21 @@ class Port(object): format_time(exp_time_factor_sec)) print "\n" + # generate port info + def get_info (self): + info = {} + info['speed'] = self.speed + info['driver'] = self.driver + info['status'] = self.get_port_state_name() + info['macaddr'] = self.macaddr + + if self.attr.get('promiscuous'): + info['prom'] = "on" if self.attr['promiscuous']['enabled'] else "off" + else: + info['prom'] = "N/A" + + return info + def get_port_state_name(self): return self.STATES_MAP.get(self.state, "Unknown") @@ -529,9 +542,14 @@ class Port(object): return self.port_stats.generate_stats() def generate_port_status(self): - return {"type": self.driver, - "maximum": "{speed} Gb/s".format(speed=self.speed), - "status": self.get_port_state_name() + + info = self.get_info() + + return {"type": info['driver'], + "macaddr": info['macaddr'], + "maximum": "{speed} Gb/s".format(speed=info['speed']), + "status": info['status'], + "promiscuous" : info['prom'] } def clear_stats(self): 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 ebc686f8..ec5435a3 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 @@ -180,9 +180,11 @@ class CTRexInfoGenerator(object): relevant_ports = self.__get_relevant_ports(port_id_list) return_stats_data = {} - per_field_status = OrderedDict([("type", []), + per_field_status = OrderedDict([("macaddr", []), + ("type", []), ("maximum", []), - ("status", []) + ("status", []), + ("promiscuous", []), ] ) @@ -198,7 +200,7 @@ class CTRexInfoGenerator(object): stats_table = text_tables.TRexTextTable() stats_table.set_cols_align(["l"] + ["c"]*len(relevant_ports)) - stats_table.set_cols_width([10] + [20] * len(relevant_ports)) + stats_table.set_cols_width([15] + [20] * len(relevant_ports)) stats_table.add_rows([[k] + v for k, v in per_field_status.iteritems()], diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py index fdd330a5..7964992b 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py @@ -533,10 +533,16 @@ class STLProfile(object): # loop_count = 0 means loop forever @staticmethod def load_pcap (pcap_file, ipg_usec = None, speedup = 1.0, loop_count = 1, vm = None): + # check filename if not os.path.isfile(pcap_file): raise STLError("file '{0}' does not exists".format(pcap_file)) + # make sure IPG is not less than 1 usec + if ipg_usec < 1: + raise STLError("ipg_usec cannot be less than 1 usec: '{0}'".format(ipg_usec)) + + streams = [] last_ts_usec = 0 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 0c70801f..649c192a 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 @@ -360,7 +360,7 @@ class CCmdArgParser(argparse.ArgumentParser): # so maybe we have ports configured elif getattr(opts, "ports", None): for port in opts.ports: - if not self.stateless_client._validate_port_list([port]): + if not self.stateless_client._validate_port_list(port): self.error("port id '{0}' is not a valid port id\n".format(port)) return opts diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 5cd42a8f..9472c0b3 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -32,7 +32,7 @@ The name of the configuration file should be /etc/trex_cfg.yaml " The minimum configuration file should include something like this - version : 2 # version 2 of the configuration file interfaces : ["03:00.0","03:00.1","13:00.1","13:00.0"] # list of the interfaces to bind run ./dpdk_nic_bind.py --status to see the list - port_limit : 2 # number of ports to use valid is 2,4,6,8 + port_limit : 2 # number of ports to use valid is 2,4,6,8,10,12 example of already bind devices @@ -76,12 +76,12 @@ Other network devices raise e stream.close(); + cfg_dict = self.m_cfg_dict[0] + if not cfg_dict.has_key('version') : + self.raise_error ("Configuration file %s is old, should include version field\n" % fcfg ) - if not self.m_cfg_dict[0].has_key('version') : - self.raise_error ("Configuration file %s is old, should include version field" % fcfg ) - - if int(self.m_cfg_dict[0]['version'])<2 : - self.raise_error ("Configuration file %s is old, should include version field with value greater than 2" % fcfg) + if int(cfg_dict['version'])<2 : + self.raise_error ("Configuration file %s is old, should include version field with value greater than 2\n" % fcfg) if not self.m_cfg_dict[0].has_key('interfaces') : self.raise_error ("Configuration file %s is old, should include interfaces field even number of elemets" % fcfg) @@ -92,6 +92,9 @@ Other network devices self.raise_error ("Configuration file %s should include interfaces field with maximum of number of elemets" % (fcfg,l)) if ((l % 2)==1): self.raise_error ("Configuration file %s should include even number of interfaces " % (fcfg,l)) + if 'port_limit' in cfg_dict and cfg_dict['port_limit'] > len(if_list): + self.raise_error ('Error: port_limit should not be higher than number of interfaces in config file: %s\n' % fcfg) + def do_bind_one (self,key): cmd='./dpdk_nic_bind.py --force --bind=igb_uio %s ' % ( key) diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h index 249adb2f..5d5f4389 100644 --- a/src/internal_api/trex_platform_api.h +++ b/src/internal_api/trex_platform_api.h @@ -25,6 +25,7 @@ limitations under the License. #include <stdint.h> #include <vector> #include <string> +#include <string.h> /** * Global stats @@ -129,6 +130,7 @@ public: virtual int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const = 0; virtual void set_promiscuous(uint8_t port_id, bool enabled) const = 0; virtual bool get_promiscuous(uint8_t port_id) const = 0; + virtual void get_macaddr(uint8_t port_id, uint8_t *macaddr) const = 0; virtual ~TrexPlatformApi() {} }; @@ -159,6 +161,7 @@ public: int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const; void set_promiscuous(uint8_t port_id, bool enabled) const; bool get_promiscuous(uint8_t port_id) const; + void get_macaddr(uint8_t port_id, uint8_t *macaddr) const; }; @@ -215,6 +218,10 @@ public: return false; } + void get_macaddr(uint8_t port_id, uint8_t *macaddr) const { + memset(macaddr, 0, 6); + } + private: int m_dp_core_count; }; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 8dad5f5a..79f3d628 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -5165,3 +5165,14 @@ bool TrexDpdkPlatformApi::get_promiscuous(uint8_t port_id) const { return g_trex.m_ports[port_id].get_promiscuous(); } +void TrexDpdkPlatformApi::get_macaddr(uint8_t port_id, uint8_t *macaddr) const { + struct ether_addr rte_mac_addr; + + g_trex.m_ports[port_id].macaddr_get(&rte_mac_addr); + + assert(ETHER_ADDR_LEN == 6); + for (int i = 0; i < 6; i++) { + macaddr[i] = rte_mac_addr.addr_bytes[i]; + } + +} diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 05565179..47569bde 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -177,6 +177,7 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { section["ports"][i]["index"] = i; section["ports"][i]["driver"] = driver; + section["ports"][i]["macaddr"] = port->get_macaddr(); section["ports"][i]["rx"]["caps"] = port->get_rx_caps(); section["ports"][i]["rx"]["counters"] = port->get_rx_count_num(); diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 43f32d22..01733117 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -679,7 +679,28 @@ TrexStatelessPort::get_promiscuous() { } +std::string +TrexStatelessPort::get_macaddr() { + uint8_t macaddr[6]; + std::string output; + get_stateless_obj()->get_platform_api()->get_macaddr(m_port_id, macaddr); + + for (int i = 0; i < 6; i++) { + char formatted[4]; + + if (i == 0) { + snprintf(formatted, sizeof(formatted), "%02x", macaddr[i]); + } else { + snprintf(formatted, sizeof(formatted), ":%02x", macaddr[i]); + } + + output += formatted; + } + + return output; + +} void TrexStatelessPort::add_stream(TrexStream *stream) { diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 1d3eebc3..0d626375 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -331,6 +331,7 @@ public: */ void set_promiscuous(bool enabled); bool get_promiscuous(); + std::string get_macaddr(); private: |