diff options
-rwxr-xr-x | scripts/dpdk_nic_bind.py | 86 | ||||
-rwxr-xr-x | scripts/dpdk_setup_ports.py | 350 | ||||
-rwxr-xr-x | src/bp_sim.h | 4 | ||||
-rw-r--r-- | src/internal_api/trex_platform_api.h | 11 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 80 | ||||
-rw-r--r-- | src/main_dpdk.h | 11 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_general.cpp | 24 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.cpp | 16 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.h | 2 |
9 files changed, 457 insertions, 127 deletions
diff --git a/scripts/dpdk_nic_bind.py b/scripts/dpdk_nic_bind.py index 44241e73..a2c8e197 100755 --- a/scripts/dpdk_nic_bind.py +++ b/scripts/dpdk_nic_bind.py @@ -32,9 +32,12 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -import sys, os, getopt, subprocess +import sys, os, getopt, subprocess, shlex from os.path import exists, abspath, dirname, basename from distutils.util import strtobool +sys.path.append(os.path.join('external_libs', 'texttable-0.8.4')) +import texttable +import re # The PCI device class for ETHERNET devices ETHERNET_CLASS = "0200" @@ -48,6 +51,7 @@ dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic" ] # command-line arg flags b_flag = None status_flag = False +table_flag = False force_flag = False args = [] @@ -81,6 +85,9 @@ Options: NOTE: if this flag is passed along with a bind/unbind option, the status display will always occur after the other operations have taken place. + -t, --table: + Similar to --status, but gives more info: NUMA, MAC etc. + -b driver, --bind=driver: Select the driver to use or \"none\" to unbind the device @@ -275,6 +282,18 @@ def get_nic_details(): modules.remove(devices[d]["Driver_str"]) devices[d]["Module_str"] = ",".join(modules) + # get MAC from Linux if available + mac_file = '/sys/bus/pci/devices/%s/net/%s/address' % (devices[d]['Slot'], devices[d]['Interface']) + if os.path.exists(mac_file): + with open(mac_file) as f: + devices[d]['MAC'] = f.read().strip() + + # get NUMA from Linux if available + numa_node_file = '/sys/bus/pci/devices/%s/numa_node' % devices[d]['Slot'] + if os.path.exists(numa_node_file): + with open(numa_node_file) as f: + devices[d]['NUMA'] = int(f.read().strip()) + def dev_id_from_dev_name(dev_name): '''Take a device "name" - a string passed in by user to identify a NIC device, and determine the device id - i.e. the domain:bus:slot.func - for @@ -403,7 +422,7 @@ def bind_all(dev_list, driver, force=False): """Bind method, takes a list of device locations""" global devices - dev_list = map(dev_id_from_dev_name, dev_list) + dev_list = list(map(dev_id_from_dev_name, dev_list)) for d in dev_list: bind_one(d, driver, force) @@ -474,11 +493,61 @@ def show_status(): display_devices("Other network devices", no_drv,\ "unused=%(Module_str)s") +def get_macs_from_trex(pci_addr_list): + if not pci_addr_list: + return {} + pci_mac_dict = {} + run_command = 'sudo ./t-rex-64 --dump-interfaces %s' % ' '.join(pci_addr_list) + proc = subprocess.Popen(shlex.split(run_command), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, universal_newlines = True) + stdout, _ = proc.communicate() + if proc.returncode: + if 'PANIC in rte_eal_init' in stdout: + print("Could not run TRex to get MAC info about interfaces, check if it's already running.") + else: + print('Error upon running TRex to get MAC info:\n%s.' % stdout) + return {} + pci_mac_str = 'PCI: (\S+).+?MAC: (\S+)' + pci_mac_re = re.compile(pci_mac_str) + for line in stdout.splitlines(): + match = pci_mac_re.match(line) + if match: + pci = match.group(1) + mac = match.group(2) + if pci not in pci_addr_list: # sanity check, should not happen + print('Internal error while getting MACs of DPDK bound interfaces, unknown PCI: %s' % pci) + return {} + pci_mac_dict[pci] = mac + return pci_mac_dict + +def show_table(): + '''Function called when the script is passed the "--table" option. + Similar to show_status() function, but shows more info: NUMA etc.''' + global dpdk_drivers + dpdk_drv = [] + for d in devices.keys(): + if devices[d].get("Driver_str") in dpdk_drivers: + dpdk_drv.append(d) + + for pci, mac in get_macs_from_trex(dpdk_drv).items(): + if pci not in dpdk_drv: # sanity check, should not happen + print('Internal error while getting MACs of DPDK bound interfaces, unknown PCI: %s' % pci) + return + devices[pci]['MAC'] = mac + + table = texttable.Texttable(max_width=-1) + table.header(['ID', 'NUMA', 'PCI', 'MAC', 'Name', 'Driver', 'Linux interface', 'Active']) + for id, pci in enumerate(sorted(devices.keys())): + d = devices[pci] + table.add_row([id, d['NUMA'], d['Slot_str'], d.get('MAC', ''), d['Device_str'], d.get('Driver_str', ''), d['Interface'], d['Active']]) + print(table.draw()) + def parse_args(): '''Parses the command-line arguments given by the user and takes the appropriate action for each''' global b_flag global status_flag + global table_flag global force_flag global args if len(sys.argv) <= 1: @@ -486,8 +555,8 @@ def parse_args(): sys.exit(0) try: - opts, args = getopt.getopt(sys.argv[1:], "b:us", - ["help", "usage", "status", "force", + opts, args = getopt.getopt(sys.argv[1:], "b:ust", + ["help", "usage", "status", "table", "force", "bind=", "unbind"]) except getopt.GetoptError as error: print(str(error)) @@ -500,6 +569,8 @@ def parse_args(): sys.exit(0) if opt == "--status" or opt == "-s": status_flag = True + if opt == "--table" or opt == "-t": + table_flag = True if opt == "--force": force_flag = True if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": @@ -515,10 +586,11 @@ def do_arg_actions(): '''do the actual action requested by the user''' global b_flag global status_flag + global table_flag global force_flag global args - if b_flag is None and not status_flag: + if b_flag is None and not status_flag and not table_flag: print("Error: No action specified for devices. Please give a -b or -u option") print("Run '%s --usage' for further information" % sys.argv[0]) sys.exit(1) @@ -536,6 +608,10 @@ def do_arg_actions(): if b_flag is not None: get_nic_details() # refresh if we have changed anything show_status() + if table_flag: + if b_flag is not None: + get_nic_details() # refresh if we have changed anything + show_table() def main(): '''program main function''' diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 59a00c8e..3ab13a2d 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -5,17 +5,179 @@ import os python_ver = 'python%s' % sys.version_info[0] sys.path.append(os.path.join('external_libs', 'pyyaml-3.11', python_ver)) import yaml -import os.path -import os import dpdk_nic_bind import re -import argparse; - +import argparse +import copy +import shlex +import traceback +from collections import defaultdict, OrderedDict +from distutils.util import strtobool + +class ConfigCreator(object): + mandatory_interface_fields = ['Slot_str', 'src_mac', 'dest_mac', 'Device_str', 'NUMA'] + _2hex_re = '[\da-fA-F]{2}' + mac_re = re.compile('^({0}:){{5}}{0}$'.format(_2hex_re)) + + # cpu_topology - dict: physical processor -> physical core -> logical processing unit (thread) + # interfaces - array of dicts per interface, should include "mandatory_interface_fields" values + def __init__(self, cpu_topology, interfaces, include_lcores = [], exclude_lcores = [], only_first_thread = False, zmq_rpc_port = None, zmq_pub_port = None, prefix = None): + self.cpu_topology = copy.deepcopy(cpu_topology) + self.interfaces = copy.deepcopy(interfaces) + del cpu_topology + del interfaces + assert isinstance(self.cpu_topology, dict), 'Type of cpu_topology should be dict, got: %s' % type(self.cpu_topology) + assert len(self.cpu_topology.keys()) > 0, 'cpu_topology should contain at least one processor' + assert isinstance(self.interfaces, list), 'Type of interfaces should be list, got: %s' % type(list) + assert len(self.interfaces) % 2 == 0, 'Should be even number of interfaces, got: %s' % len(self.interfaces) + assert len(self.interfaces) >= 2, 'Should be at least two interfaces, got: %s' % len(self.interfaces) + assert isinstance(include_lcores, list), 'include_lcores should be list, got: %s' % type(include_lcores) + assert isinstance(exclude_lcores, list), 'exclude_lcores should be list, got: %s' % type(exclude_lcores) + assert len(self.interfaces) >= 2, 'Should be at least two interfaces, got: %s' % len(self.interfaces) + if only_first_thread: + for cores in self.cpu_topology.values(): + for core in cores.keys(): + cores[core] = cores[core][:1] + include_lcores = [int(x) for x in include_lcores] + exclude_lcores = [int(x) for x in exclude_lcores] + self.has_zero_lcore = False + for cores in self.cpu_topology.values(): + for core, lcores in cores.items(): + for lcore in copy.copy(lcores): + if include_lcores and lcore not in include_lcores: + cores[core].remove(lcore) + if exclude_lcores and lcore in exclude_lcores: + cores[core].remove(lcore) + if 0 in lcores: + self.has_zero_lcore = True + cores[core].remove(0) + Device_str = None + for interface in self.interfaces: + for mandatory_interface_field in ConfigCreator.mandatory_interface_fields: + if mandatory_interface_field not in interface: + raise DpdkSetup("Expected '%s' field in interface dictionary, got: %s" % (mandatory_interface_field, interface)) + if Device_str is None: + Device_str = interface['Device_str'] + elif Device_str != interface['Device_str']: + raise DpdkSetup('Interfaces should be of same type, got:\n\t* %s\n\t* %s' % (Device_str, interface['Device_str'])) + if '40Gb' in Device_str: + self.speed = 40 + else: + self.speed = 10 + lcores_per_numa = OrderedDict() + system_lcores = int(self.has_zero_lcore) + for numa, core in self.cpu_topology.items(): + for lcores in core.values(): + if numa not in lcores_per_numa: + lcores_per_numa[numa] = [] + lcores_per_numa[numa].extend(lcores) + system_lcores += len(lcores) + minimum_required_lcores = len(self.interfaces) / 2 + 2 + if system_lcores < minimum_required_lcores: + raise DpdkSetup('Your system should have at least %s cores for %s interfaces, and it has: %s.' % + (minimum_required_lcores, len(self.interfaces), system_lcores + (0 if self.has_zero_lcore else 1))) + #if not stateless_only: + interfaces_per_numa = defaultdict(int) + for i in range(0, len(self.interfaces), 2): + if self.interfaces[i]['NUMA'] != self.interfaces[i+1]['NUMA']: + raise DpdkSetup('NUMA of each pair of interfaces should be same, got NUMA %s for client interface %s, NUMA %s for server interface %s' % + (self.interfaces[i]['NUMA'], self.interfaces[i]['Slot_str'], self.interfaces[i+1]['NUMA'], self.interfaces[i+1]['Slot_str'])) + interfaces_per_numa[self.interfaces[i]['NUMA']] += 2 + self.lcores_per_numa = lcores_per_numa + self.interfaces_per_numa = interfaces_per_numa + self.prefix = prefix + self.zmq_pub_port = zmq_pub_port + self.zmq_rpc_port = zmq_rpc_port + + def _convert_mac(self, mac_string): + if not ConfigCreator.mac_re.match(mac_string): + raise DpdkSetup('MAC address should be in format of 12:34:56:78:9a:bc, got: %s' % mac_string) + return ', '.join([('0x%s' % elem).lower() for elem in mac_string.split(':')]) + + def create_config(self, filename = None, print_config = False): + config_str = '### Config file generated by dpdk_setup_ports.py ###\n\n' + config_str += '- port_limit: %s\n' % len(self.interfaces) + config_str += ' version: 2\n' + config_str += " interfaces: ['%s']\n" % "', '".join([interface['Slot_str'] for interface in self.interfaces]) + if self.speed > 10: + config_str += ' port_bandwidth_gb: %s\n' % self.speed + if self.prefix: + config_str += ' prefix: %s\n' % self.prefix + if self.zmq_pub_port: + config_str += ' zmq_pub_port: %s\n' % self.zmq_pub_port + if self.zmq_rpc_port: + config_str += ' zmq_rpc_port: %s\n' % self.zmq_rpc_port + config_str += ' port_info:\n' + for interface in self.interfaces: + config_str += ' '*6 + '- dest_mac: [%s]\n' % self._convert_mac(interface['dest_mac']) + config_str += ' '*8 + 'src_mac: [%s]\n' % self._convert_mac(interface['src_mac']) + config_str += '\n platform:\n' + if len(self.interfaces_per_numa.keys()) == 1 and -1 in self.interfaces_per_numa: # VM, use any cores, 1 core per dual_if + lcores_pool = sorted([lcore for lcores in self.lcores_per_numa.values() for lcore in lcores]) + config_str += ' '*6 + 'master_thread_id: %s\n' % (0 if self.has_zero_lcore else lcores_pool.pop()) + config_str += ' '*6 + 'latency_thread_id: %s\n' % lcores_pool.pop() + config_str += ' '*6 + 'dual_if:\n' + for i in range(0, len(self.interfaces), 2): + config_str += ' '*8 + '- socket: 0\n' + config_str += ' '*10 + 'threads: [%s]\n\n' % lcores_pool.pop() + else: + # we will take common minimum among all NUMAs, to satisfy all + lcores_per_dual_if = 99 + extra_lcores = 1 if self.has_zero_lcore else 2 + # worst case 3 iterations, to ensure master and "rx" have cores left + while (lcores_per_dual_if * sum(self.interfaces_per_numa.values()) / 2) + extra_lcores > sum([len(lcores) for lcores in self.lcores_per_numa.values()]): + lcores_per_dual_if -= 1 + for numa, cores in self.lcores_per_numa.items(): + if not self.interfaces_per_numa[numa]: + continue + lcores_per_dual_if = min(lcores_per_dual_if, int(2 * len(cores) / self.interfaces_per_numa[numa])) + lcores_pool = copy.deepcopy(self.lcores_per_numa) + # first, allocate lcores for dual_if section + dual_if_section = ' '*6 + 'dual_if:\n' + for i in range(0, len(self.interfaces), 2): + numa = self.interfaces[i]['NUMA'] + dual_if_section += ' '*8 + '- socket: %s\n' % numa + lcores_for_this_dual_if = [str(lcores_pool[numa].pop()) for _ in range(lcores_per_dual_if)] + if not lcores_for_this_dual_if: + raise DpdkSetup('Not enough cores at NUMA %s. This NUMA has %s processing units and %s interfaces.' % (numa, len(self.lcores_per_numa[numa]), self.interfaces_per_numa[numa])) + dual_if_section += ' '*10 + 'threads: [%s]\n\n' % ','.join(lcores_for_this_dual_if) + # take the cores left to master and rx + lcores_pool_left = [lcore for lcores in lcores_pool.values() for lcore in lcores] + config_str += ' '*6 + 'master_thread_id: %s\n' % (0 if self.has_zero_lcore else lcores_pool_left.pop()) + config_str += ' '*6 + 'latency_thread_id: %s\n' % lcores_pool_left.pop() + # add the dual_if section + config_str += dual_if_section + + # verify config is correct YAML format + try: + yaml.safe_load(config_str) + except Exception as e: + raise DpdkSetup('Could not create correct yaml config.\nGenerated YAML:\n%s\nEncountered error:\n%s' % (config_str, e)) + + if filename: + if os.path.exists(filename): + result = None + try: + result = strtobool(raw_input('File %s already exist, overwrite? (y/N)' % filename)) + except: + pass + finally: + if not result: + print('Skipping.') + return config_str + with open(filename, 'w') as f: + f.write(config_str) + print('Saved.') + if print_config: + print(config_str) + return config_str class map_driver(object): - args=None; - cfg_file='/etc/trex_cfg.yaml' + args=None; + cfg_file='/etc/trex_cfg.yaml' + parent_cfg = None + dump_interfaces = None class DpdkSetup(Exception): pass @@ -64,6 +226,7 @@ Other network devices raise DpdkSetup(s) def load_config_file (self): + #return fcfg=self.m_cfg_file @@ -130,10 +293,12 @@ Other network devices self.m_devices= dpdk_nic_bind.devices def do_run (self): - self.load_config_file () self.run_dpdk_lspci () - - if_list=self.m_cfg_dict[0]['interfaces'] + if map_driver.dump_interfaces is None or (map_driver.dump_interfaces is [] and map_driver.parent_cfg): + self.load_config_file() + if_list=self.m_cfg_dict[0]['interfaces'] + else: + if_list = map_driver.dump_interfaces for obj in if_list: key= self.pci_name_to_full_name (obj) @@ -149,22 +314,83 @@ Other network devices self.do_bind_one (key) - def do_create (self): - print(" not supported yet !") - + def do_create(self): + create_interfaces = map_driver.args.create_interfaces + if type(create_interfaces) is not list: + raise DpdkSetup('type of map_driver.args.create_interfaces should be list') + if not len(create_interfaces): + raise DpdkSetup('Please specify interfaces to use in the config') + if len(create_interfaces) % 2: + raise DpdkSetup('Please specify even number of interfaces') + # gather info about NICS from dpdk_nic_bind.py + if not self.m_devices: + self.run_dpdk_lspci() + wanted_interfaces = [] + for interface in copy.copy(create_interfaces): + for m_device in self.m_devices.values(): + if interface in (m_device['Interface'], m_device['Slot'], m_device['Slot_str']): + if m_device in wanted_interfaces: + raise DpdkSetup('Interface %s is specified twice' % interface) + m_device['Interface_argv'] = interface + wanted_interfaces.append(m_device) + create_interfaces.remove(interface) + break + # verify all interfaces identified + if len(create_interfaces): + raise DpdkSetup('Could not find information about those interfaces: %s' % create_interfaces) + + dpdk_bound = [] + for interface in wanted_interfaces: + if 'Driver_str' not in interface: + self.do_bind_one(interface['Slot']) + dpdk_bound.append(interface['Slot']) + elif interface['Driver_str'] == 'igb_uio': + dpdk_bound.append(interface['Slot']) + if dpdk_bound: + for pci, mac in dpdk_nic_bind.get_macs_from_trex(dpdk_bound).items(): + self.m_devices[pci]['MAC'] = mac + + dest_macs = map_driver.args.dest_macs + for i, interface in enumerate(wanted_interfaces): + interface['src_mac'] = interface['MAC'] + if isinstance(dest_macs, list) and len(dest_macs) > i: + interface['dest_mac'] = dest_macs[i] + dual_index = i + 1 - (i % 2) * 2 + if 'dest_mac' not in wanted_interfaces[dual_index]: + wanted_interfaces[dual_index]['dest_mac'] = interface['MAC'] # loopback + + cpu_topology_file = '/proc/cpuinfo' + # physical processor -> physical core -> logical processing units (threads) + cpu_topology = OrderedDict() + if not os.path.exists(cpu_topology_file): + raise DpdkSetup('File with CPU topology (%s) does not exist.' % cpu_topology_file) + with open(cpu_topology_file) as f: + for lcore in f.read().split('\n\n'): + if not lcore: + continue + lcore_dict = OrderedDict() + for line in lcore.split('\n'): + key, val = line.split(':', 1) + lcore_dict[key.strip()] = val.strip() + numa = int(lcore_dict['physical id']) + if numa not in cpu_topology: + cpu_topology[numa] = OrderedDict() + core = int(lcore_dict['core id']) + if core not in cpu_topology[numa]: + cpu_topology[numa][core] = [] + cpu_topology[numa][core].append(int(lcore_dict['processor'])) + + config = ConfigCreator(cpu_topology, wanted_interfaces, include_lcores = map_driver.args.create_include, exclude_lcores = map_driver.args.create_exclude, + only_first_thread = map_driver.args.no_ht, + prefix = map_driver.args.prefix, zmq_rpc_port = map_driver.args.zmq_rpc_port, zmq_pub_port = map_driver.args.zmq_pub_port) + config.create_config(filename = map_driver.args.o, print_config = map_driver.args.dump) def parse_parent_cfg (parent_cfg): - l=parent_cfg.split(" "); - cfg_file=''; - next=False; - for obj in l: - if next: - cfg_file=obj - next=False; - if obj == '--cfg': - next=True - - return (cfg_file) + parent_parser = argparse.ArgumentParser() + parent_parser.add_argument('--cfg', default='') + parent_parser.add_argument('--dump-interfaces', nargs='*', default=None) + args, unkown = parent_parser.parse_known_args(shlex.split(parent_cfg)) + return (args.cfg, args.dump_interfaces) def process_options (): parser = argparse.ArgumentParser(usage=""" @@ -173,13 +399,13 @@ Examples: --------- To unbind the interfaces using the trex configuration file - dpdk_set_ports.py -l + sudo ./dpdk_set_ports.py -l -To create a default file - dpdk_set_ports.py -c +To create a default config file + sudo ./dpdk_setup_ports.py -c 02:00.0 02:00.1 -o /etc/trex_cfg.yaml -To show status - dpdk_set_ports.py -s +To show interfaces status + sudo ./dpdk_set_ports.py -s """, description=" unbind dpdk interfaces ", @@ -194,26 +420,65 @@ To show status ) parser.add_argument("--parent", - help=""" parent configuration CLI, extract --cfg from it if given """, + help=argparse.SUPPRESS + ) + + parser.add_argument("-c", "--create", nargs='*', default=None, dest='create_interfaces', metavar='<interface>', + help="""Try to create a configuration file by specifying needed interfaces by PCI address or Linux names: eth1 etc.""", + ) + + parser.add_argument("--ci", "--cores-include", nargs='*', default=[], dest='create_include', metavar='<cores>', + help="""White list of cores to use. Make sure there is enough for each NUMA.""", + ) + + parser.add_argument("--ce", "--cores-exclude", nargs='*', default=[], dest='create_exclude', metavar='<cores>', + help="""Black list of cores to exclude. Make sure there will be enough for each NUMA.""", ) - parser.add_argument("-c", "--create", action='store_true', - help=""" try to create a configuration file. It is heuristic try to look into the file before """, + parser.add_argument("--dump", default=False, action='store_true', + help="""Dump created config to screen.""", + ) + + parser.add_argument("--no-ht", default=False, dest='no_ht', action='store_true', + help="""Use only one thread of each Core in created config yaml (No Hyper-Threading).""", + ) + + parser.add_argument("--dest-macs", nargs='*', default=[], action='store', + help="""Destination MACs to be used in created yaml file. Without them, will be assumed loopback (0<->1, 2<->3 etc.)""", + ) + + parser.add_argument("-o", default=None, action='store', metavar='PATH', + help="""Output the config to this file.""", + ) + + parser.add_argument("--prefix", default=None, action='store', + help="""Advanced option: prefix to be used in TRex config in case of parallel instances.""", + ) + + parser.add_argument("--zmq-pub-port", default=None, action='store', + help="""Advanced option: ZMQ Publisher port to be used in TRex config in case of parallel instances.""", + ) + + parser.add_argument("--zmq-rpc-port", default=None, action='store', + help="""Advanced option: ZMQ RPC port to be used in TRex config in case of parallel instances.""", ) parser.add_argument("-s", "--show", action='store_true', help=""" show the status """, ) + parser.add_argument("-t", "--table", action='store_true', + help=""" show table with NICs info """, + ) + parser.add_argument('--version', action='version', version="0.1" ) map_driver.args = parser.parse_args(); - if map_driver.args.parent : - cfg = parse_parent_cfg (map_driver.args.parent) - if cfg != '': - map_driver.cfg_file = cfg; + map_driver.parent_cfg, map_driver.dump_interfaces = parse_parent_cfg (map_driver.args.parent) + if map_driver.parent_cfg != '': + map_driver.cfg_file = map_driver.parent_cfg; if map_driver.args.cfg : map_driver.cfg_file = map_driver.args.cfg; @@ -225,15 +490,22 @@ def main (): res=os.system('%s dpdk_nic_bind.py --status' % sys.executable); return(res); + if map_driver.args.table: + res=os.system('%s dpdk_nic_bind.py -t' % sys.executable); + return(res); + obj =CIfMap(map_driver.cfg_file); - if map_driver.args.create: + if map_driver.args.create_interfaces is not None: obj.do_create(); else: obj.do_run(); except Exception as e: - print(e) - exit(-1) + #debug + #traceback.print_exc() + print(e) + exit(-1) -main(); +if __name__ == '__main__': + main() diff --git a/src/bp_sim.h b/src/bp_sim.h index e1852da4..b1033496 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -764,7 +764,8 @@ public: enum trex_run_mode_e { RUN_MODE_INVALID, RUN_MODE_BATCH, - RUN_MODE_INTERACTIVE + RUN_MODE_INTERACTIVE, + RUN_MODE_DUMP_INFO, }; enum trex_learn_mode_e { @@ -837,6 +838,7 @@ public: std::string out_file; std::string prefix; + std::vector<std::string> dump_interfaces; CMacAddrCfg m_mac_addr[TREX_MAX_PORTS]; diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h index 7a2a0c8a..a55e8cd7 100644 --- a/src/internal_api/trex_platform_api.h +++ b/src/internal_api/trex_platform_api.h @@ -111,13 +111,6 @@ public: IF_STAT_RX_BYTES_COUNT = 8, // Card support counting rx bytes }; - enum driver_speed_e { - SPEED_INVALID, - SPEED_1G, - SPEED_10G, - SPEED_40G, - }; - struct mac_cfg_st { uint8_t hw_macaddr[6]; uint8_t src_macaddr[6]; @@ -130,7 +123,7 @@ public: */ struct intf_info_st { std::string driver_name; - driver_speed_e speed; + uint32_t speed; mac_cfg_st mac_info; std::string pci_addr; int numa_node; @@ -228,7 +221,7 @@ public: virtual void get_interface_info(uint8_t interface_id, intf_info_st &info) const { info.driver_name = "TEST"; - info.speed = TrexPlatformApi::SPEED_10G; + info.speed = 10000; info.has_crc = true; info.numa_node = 0; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 0ef83c02..f0320921 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -121,8 +121,6 @@ struct port_cfg_t; class CTRexExtendedDriverBase { public: - virtual TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) = 0; - /* by default NIC driver adds CRC */ virtual bool has_crc_added() { return true; @@ -166,10 +164,6 @@ public: CTRexExtendedDriverBase1G(){ } - TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) { - return TrexPlatformApi::SPEED_1G; - } - static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase1G() ); } @@ -215,10 +209,6 @@ public: CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); } - TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) { - return TrexPlatformApi::SPEED_1G; - } - virtual bool has_crc_added() { return false; } @@ -267,10 +257,6 @@ public: CTRexExtendedDriverBase10G(){ } - TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) { - return TrexPlatformApi::SPEED_10G; - } - static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase10G() ); } @@ -311,7 +297,6 @@ public: m_if_per_card = 4; } - TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id); static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase40G() ); } @@ -514,6 +499,7 @@ enum { OPT_HELP, OPT_MODE_BATCH, OPT_MODE_INTERACTIVE, OPT_NODE_DUMP, + OPT_DUMP_INTERFACES, OPT_UT, OPT_FILE_OUT, OPT_REAL_TIME, @@ -581,6 +567,7 @@ static CSimpleOpt::SOption parser_options[] = { OPT_LIMT_NUM_OF_PORTS,"--limit-ports", SO_REQ_SEP }, { OPT_CORES , "-c", SO_REQ_SEP }, { OPT_NODE_DUMP , "-v", SO_REQ_SEP }, + { OPT_DUMP_INTERFACES , "--dump-interfaces", SO_MULTI }, { OPT_LATENCY , "-l", SO_REQ_SEP }, { OPT_DURATION , "-d", SO_REQ_SEP }, { OPT_PLATFORM_FACTOR , "-pm", SO_REQ_SEP }, @@ -776,6 +763,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t bool latency_was_set=false; (void)latency_was_set; + char ** rgpszArg = NULL; int a=0; int node_dump=0; @@ -897,6 +885,19 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t node_dump=1; po->preview.setFileWrite(false); break; + case OPT_DUMP_INTERFACES: + if (first_time) { + rgpszArg = args.MultiArg(1); + while (rgpszArg != NULL) { + po->dump_interfaces.push_back(rgpszArg[0]); + rgpszArg = args.MultiArg(1); + } + } + if (po->m_run_mode != CParserOption::RUN_MODE_INVALID) { + parse_err("Please specify single run mode"); + } + po->m_run_mode = CParserOption::RUN_MODE_DUMP_INFO; + break; case OPT_MBUF_FACTOR: sscanf(args.OptionArg(),"%f", &po->m_mbuf_factor); break; @@ -4891,9 +4892,17 @@ int update_dpdk_args(void){ global_dpdk_args_num = 7; /* add white list */ - for (int i=0; i<(int)global_platform_cfg_info.m_if_list.size(); i++) { - global_dpdk_args[global_dpdk_args_num++]=(char *)"-w"; - global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_if_list[i].c_str(); + if (lpop->m_run_mode == CParserOption::RUN_MODE_DUMP_INFO and lpop->dump_interfaces.size()) { + for (int i=0; i<(int)lpop->dump_interfaces.size(); i++) { + global_dpdk_args[global_dpdk_args_num++]=(char *)"-w"; + global_dpdk_args[global_dpdk_args_num++]=(char *)lpop->dump_interfaces[i].c_str(); + } + } + else { + for (int i=0; i<(int)global_platform_cfg_info.m_if_list.size(); i++) { + global_dpdk_args[global_dpdk_args_num++]=(char *)"-w"; + global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_if_list[i].c_str(); + } } @@ -4951,6 +4960,22 @@ int sim_load_list_of_cap_files(CParserOption * op){ return (0); } +void dump_interfaces_info() { + printf("Showing interfaces info.\n"); + uint8_t m_max_ports = rte_eth_dev_count(); + struct ether_addr mac_addr; + char mac_str[ETHER_ADDR_FMT_SIZE]; + struct rte_pci_addr pci_addr; + + for (uint8_t port_id=0; port_id<m_max_ports; port_id++) { + // PCI and MAC + pci_addr = rte_eth_devices[port_id].pci_dev->addr; + rte_eth_macaddr_get(port_id, &mac_addr); + ether_format_addr(mac_str, sizeof mac_str, &mac_addr); + printf("PCI: %04x:%02x:%02x.%d - MAC: %s\n", + pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function, mac_str); + } +} int main_test(int argc , char * argv[]){ @@ -5015,7 +5040,10 @@ int main_test(int argc , char * argv[]){ printf(" You might need to run ./trex-cfg once \n"); rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); } - + if (CGlobalInfo::m_options.m_run_mode == CParserOption::RUN_MODE_DUMP_INFO) { + dump_interfaces_info(); + exit(0); + } reorder_dpdk_ports(); time_init(); @@ -5593,17 +5621,6 @@ CFlowStatParser *CTRexExtendedDriverBase10G::get_flow_stat_parser() { return parser; } -//////////////////////////////////////////////////////////////////////////////// -TrexPlatformApi::driver_speed_e CTRexExtendedDriverBase40G::get_driver_speed(uint8_t port_id) { - CPhyEthIF *phy_if = &g_trex.m_ports[port_id]; - - if (phy_if->m_dev_info.speed_capa & ETH_LINK_SPEED_40G) { - return TrexPlatformApi::SPEED_40G; - } else { - return TrexPlatformApi::SPEED_10G; - } - } - void CTRexExtendedDriverBase40G::clear_extended_stats(CPhyEthIF * _if){ rte_eth_stats_reset(_if->get_port_id()); } @@ -6099,7 +6116,8 @@ TrexDpdkPlatformApi::get_interface_info(uint8_t interface_id, intf_info_st &info struct ether_addr rte_mac_addr; info.driver_name = CTRexExtendedDriverDb::Ins()->get_driver_name(); - info.speed = CTRexExtendedDriverDb::Ins()->get_drv()->get_driver_speed(interface_id); + g_trex.m_ports[interface_id].update_link_status_nowait(); + g_trex.m_ports[interface_id].get_link_speed(&info.speed); info.has_crc = CTRexExtendedDriverDb::Ins()->get_drv()->has_crc_added(); /* mac INFO */ diff --git a/src/main_dpdk.h b/src/main_dpdk.h index 91618071..935a27ea 100644 --- a/src/main_dpdk.h +++ b/src/main_dpdk.h @@ -90,6 +90,9 @@ class CPhyEthIF { bool is_link_up(){ return (m_link.link_status?true:false); } + void get_link_speed(uint32_t *link_speed){ + *link_speed = m_link.link_speed; + } void dump_link(FILE *fd); void disable_flow_control(); void set_promiscuous(bool enable); @@ -119,10 +122,8 @@ class CPhyEthIF { } void flush_dp_rx_queue(void); void flush_rx_queue(void); - int add_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto - , uint8_t ipv6_next_h, uint16_t id) const; - int del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto - , uint8_t ipv6_next_h, uint16_t id) const; + int add_rx_flow_stat_rule(uint8_t type, uint16_t proto, uint16_t id); + int del_rx_flow_stat_rule(uint8_t type, uint16_t proto, uint16_t id); inline uint16_t tx_burst(uint16_t queue_id, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) { return rte_eth_tx_burst(m_port_id, queue_id, tx_pkts, nb_pkts); } @@ -154,9 +155,9 @@ class CPhyEthIF { const std::vector<std::pair<uint8_t, uint8_t>> & get_core_list(); private: + struct rte_eth_link m_link; uint8_t m_port_id; uint8_t m_rx_queue; - struct rte_eth_link m_link; uint64_t m_sw_try_tx_pkt; uint64_t m_sw_tx_drop_pkt; CBwMeasure m_bw_tx; diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 21f64e2e..cd845fca 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -289,7 +289,7 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { section["ports"] = Json::arrayValue; for (int i = 0; i < main->get_port_count(); i++) { - TrexPlatformApi::driver_speed_e speed; + uint32_t speed; string driver; string hw_macaddr; string src_macaddr; @@ -325,27 +325,7 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { section["ports"][i]["rx"]["caps"].append("rx_bytes"); } section["ports"][i]["rx"]["counters"] = port->get_rx_count_num(); - - - switch (speed) { - case TrexPlatformApi::SPEED_1G: - section["ports"][i]["speed"] = 1; - break; - - case TrexPlatformApi::SPEED_10G: - section["ports"][i]["speed"] = 10; - break; - - case TrexPlatformApi::SPEED_40G: - section["ports"][i]["speed"] = 40; - break; - - default: - /* unknown value */ - section["ports"][i]["speed"] = 0; - break; - } - + section["ports"][i]["speed"] = (uint16_t) speed / 1000; } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 134d4c98..2a545c5f 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -573,7 +573,7 @@ TrexStatelessPort::get_max_stream_id() const { } void -TrexStatelessPort::get_properties(std::string &driver, TrexPlatformApi::driver_speed_e &speed) { +TrexStatelessPort::get_properties(std::string &driver, uint32_t &speed) { driver = m_api_info.driver_name; speed = m_api_info.speed; @@ -657,19 +657,7 @@ TrexStatelessPort::send_message_to_rx(TrexStatelessCpToRxMsgBase *msg) { uint64_t TrexStatelessPort::get_port_speed_bps() const { - switch (m_api_info.speed) { - case TrexPlatformApi::SPEED_1G: - return (1LLU * 1000 * 1000 * 1000); - - case TrexPlatformApi::SPEED_10G: - return (10LLU * 1000 * 1000 * 1000); - - case TrexPlatformApi::SPEED_40G: - return (40LLU * 1000 * 1000 * 1000); - - default: - return 0; - } + return (uint64_t) m_api_info.speed * 1000 * 1000; } static inline double diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 7d976e46..ba86a279 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -256,7 +256,7 @@ public: * @param driver * @param speed */ - void get_properties(std::string &driver, TrexPlatformApi::driver_speed_e &speed); + void get_properties(std::string &driver, uint32_t &speed); |