summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/dpdk_nic_bind.py86
-rwxr-xr-xscripts/dpdk_setup_ports.py350
-rwxr-xr-xsrc/bp_sim.h4
-rw-r--r--src/internal_api/trex_platform_api.h11
-rw-r--r--src/main_dpdk.cpp80
-rw-r--r--src/main_dpdk.h11
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp24
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp16
-rw-r--r--src/stateless/cp/trex_stateless_port.h2
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 &params, 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 &params, 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);