diff options
Diffstat (limited to 'scripts/dpdk_setup_ports.py')
-rwxr-xr-x | scripts/dpdk_setup_ports.py | 184 |
1 files changed, 135 insertions, 49 deletions
diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 6eb7481d..8e5a23be 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -24,8 +24,7 @@ import platform # 32 : no errors - mlx share object should be loaded MLX_EXIT_CODE = 32 -out = subprocess.check_output(['lsmod']) -DPDK_DRIVER = 'vfio-pci' if out.find('vfio_pci') != -1 else 'igb_uio' +class VFIOBindErr(Exception): pass class ConfigCreator(object): mandatory_interface_fields = ['Slot_str', 'Device_str', 'NUMA'] @@ -248,6 +247,52 @@ class ConfigCreator(object): print('Saved to %s.' % filename) return config_str +# only load igb_uio if it's available +def load_igb_uio(): + if 'igb_uio' in dpdk_nic_bind.get_loaded_modules(): + return True + km = './ko/%s/igb_uio.ko' % dpdk_nic_bind.kernel_ver + if os.path.exists(km): + return os.system('insmod %s' % km) == 0 + +# try to compile igb_uio if it's missing +def compile_and_load_igb_uio(): + loaded_mods = dpdk_nic_bind.get_loaded_modules() + if 'igb_uio' in loaded_mods: + return + if 'uio' not in loaded_mods: + res = os.system('modprobe uio') + if res: + print('Failed inserting uio module, please check if it is installed') + sys.exit(-1) + km = './ko/%s/igb_uio.ko' % dpdk_nic_bind.kernel_ver + if not os.path.exists(km): + print("ERROR: We don't have precompiled igb_uio.ko module for your kernel version") + print('Will try compiling automatically.') + try: + subprocess.check_output('make', cwd = './ko/src', stderr = subprocess.STDOUT) + subprocess.check_output(['make', 'install'], cwd = './ko/src', stderr = subprocess.STDOUT) + print('\nSuccess.') + except Exception as e: + print('\nAutomatic compilation failed: (%s)' % e) + print('You can try compiling yourself, using the following commands:') + print(' $cd ko/src') + print(' $make') + print(' $make install') + print(' $cd -') + print('Then, try to run TRex again.') + print('Note: you might need additional Linux packages for that:') + print(' * yum based (Fedora, CentOS, RedHat):') + print(' sudo yum install kernel-devel-`uname -r`') + print(' sudo yum group install "Development tools"') + print(' * apt based (Ubuntu):') + print(' sudo apt install linux-headers-`uname -r`') + print(' sudo apt install build-essential') + sys.exit(-1) + res = os.system('insmod %s' % km) + if res: + print('Failed inserting igb_uio module') + sys.exit(-1) class map_driver(object): args=None; @@ -442,17 +487,33 @@ Other network devices raise DpdkSetup('Error: port_limit should not be higher than number of interfaces in config file: %s\n' % fcfg) - def do_bind_one (self,key,mellanox): - if mellanox: - drv="mlx5_core" - else: - drv=DPDK_DRIVER - - cmd='%s dpdk_nic_bind.py --bind=%s %s ' % (sys.executable, drv,key) + def do_bind_all(self, drv, pci, force = False): + assert type(pci) is list + cmd = '{ptn} dpdk_nic_bind.py --bind={drv} {pci} {frc}'.format( + ptn = sys.executable, + drv = drv, + pci = ' '.join(pci), + frc = '--force' if force else '') print(cmd) - res=os.system(cmd); - if res!=0: - raise DpdkSetup('') + return os.system(cmd) + + # pros: no need to compile .ko per Kernel version + # cons: need special config/hw (not always works) + def try_bind_to_vfio_pci(self, to_bind_list): + krnl_params_file = '/proc/cmdline' + if not os.path.exists(krnl_params_file): + raise VFIOBindErr('Could not find file with Kernel boot parameters: %s' % krnl_params_file) + with open(krnl_params_file) as f: + krnl_params = f.read() + if 'iommu=' in krnl_params: + if 'vfio_pci' not in dpdk_nic_bind.get_loaded_modules(): + ret = os.system('modprobe vfio_pci') + if ret: + raise VFIOBindErr('Could not load vfio_pci') + ret = self.do_bind_all('vfio-pci', to_bind_list) + if ret: + raise VFIOBindErr('Binding to vfio_pci failed') + raise VFIOBindErr('vfio-pci is not an option here') def pci_name_to_full_name (self,pci_name): @@ -507,18 +568,15 @@ Other network devices err=" %s does not have Vendor_str " %key; raise DpdkSetup(err) - if self.m_devices[key]['Vendor_str'].find("Mellanox")>-1 : - Mellanox_cnt=Mellanox_cnt+1 + if 'Mellanox' in self.m_devices[key]['Vendor_str']: + Mellanox_cnt += 1 if not map_driver.parent_args.dump_interfaces: - if ((Mellanox_cnt>0) and (Mellanox_cnt!= len(if_list))): + if (Mellanox_cnt > 0) and (Mellanox_cnt != len(if_list)): err=" All driver should be from one vendor. you have at least one driver from Mellanox but not all "; raise DpdkSetup(err) - - - if not map_driver.parent_args.dump_interfaces: - if Mellanox_cnt>0 : + if Mellanox_cnt > 0: self.set_only_mellanox_nics() if self.get_only_mellanox_nics(): @@ -537,24 +595,11 @@ Other network devices if only_check_all_mlx: - if Mellanox_cnt >0: + if Mellanox_cnt > 0: exit(MLX_EXIT_CODE); else: exit(0); - for key in if_list: - if key not in self.m_devices: - err=" %s does not exist " %key; - raise DpdkSetup(err) - - if 'Driver_str' in self.m_devices[key]: - if self.m_devices[key]['Driver_str'] not in (dpdk_nic_bind.dpdk_drivers+dpdk_nic_bind.dpdk_and_kernel) : - self.do_bind_one (key,(Mellanox_cnt>0)) - pass; - else: - self.do_bind_one (key,(Mellanox_cnt>0)) - pass; - if if_list and map_driver.args.parent and self.m_cfg_dict[0].get('enable_zmq_pub', True): publisher_port = self.m_cfg_dict[0].get('zmq_pub_port', 4500) pid = dpdk_nic_bind.get_tcp_port_usage(publisher_port) @@ -574,37 +619,78 @@ Other network devices print("Could not start scapy_daemon_server, which is needed by GUI to create packets.\nIf you don't need it, use --no-scapy-server flag.") sys.exit(-1) - if Mellanox_cnt: - return MLX_EXIT_CODE - else: - return 0 + to_bind_list = [] + for key in if_list: + if key not in self.m_devices: + err=" %s does not exist " %key; + raise DpdkSetup(err) + + if self.m_devices[key].get('Driver_str') not in (dpdk_nic_bind.dpdk_drivers + dpdk_nic_bind.dpdk_and_kernel): + to_bind_list.append(key) + + if to_bind_list: + if Mellanox_cnt > 0: + ret = self.do_bind_all('mlx5_core', to_bind_list) + if ret: + raise DpdkSetup('Unable to bind interfaces to driver mlx5_core.') + return MLX_EXIT_CODE + else: + # if igb_uio is ready, use it as safer choice, afterwards try vfio-pci + if load_igb_uio(): + print('Trying to bind to igb_uio ...') + ret = self.do_bind_all('igb_uio', to_bind_list) + if ret: + raise DpdkSetup('Unable to bind interfaces to driver igb_uio.') # module present, loaded, but unable to bind + return + + try: + print('Trying to bind to vfio-pci ...') + self.try_bind_to_vfio_pci(to_bind_list) + return + except VFIOBindErr as e: + pass + #print(e) + + print('Trying to compile and bind to igb_uio ...') + compile_and_load_igb_uio() + ret = self.do_bind_all('igb_uio', to_bind_list) + if ret: + raise DpdkSetup('Unable to bind interfaces to driver igb_uio.') def do_return_to_linux(self): if not self.m_devices: self.run_dpdk_lspci() dpdk_interfaces = [] + check_drivers = set() for device in self.m_devices.values(): if device.get('Driver_str') in dpdk_nic_bind.dpdk_drivers: dpdk_interfaces.append(device['Slot']) + check_drivers.add(device['Driver_str']) if not dpdk_interfaces: print('No DPDK bound interfaces.') return - if dpdk_nic_bind.get_igb_uio_usage(): + any_driver_used = False + for driver in check_drivers: + if dpdk_nic_bind.is_module_used(driver): + any_driver_used = True + if any_driver_used: pid = dpdk_nic_bind.get_pid_using_pci(dpdk_interfaces) if pid: cmdline = dpdk_nic_bind.read_pid_cmdline(pid) print('DPDK interfaces are in use. Unbinding them might cause following process to hang:\npid: %s, cmd: %s' % (pid, cmdline)) if not dpdk_nic_bind.confirm('Confirm (y/N):'): - return + sys.exit(-1) + + # DPDK => Linux drivers_table = { 'net_ixgbe': 'ixgbe', - 'net_ixgbe_vf': 'ixgbe_vf', - 'net_e1000_igb': 'e1000_igb', + 'net_ixgbe_vf': 'ixgbevf', + 'net_e1000_igb': 'igb', 'net_i40e': 'i40e', - 'net_i40e_vf': 'i40e_vf', - 'net_e1000_em': 'e1000_em', + 'net_i40e_vf': 'i40evf', + 'net_e1000_em': 'e1000', 'net_vmxnet3': 'vmxnet3', 'net_virtio': 'virtio-pci', 'net_enic': 'enic', @@ -617,10 +703,13 @@ Other network devices raise DpdkSetup('Internal error: PCI %s is not found among devices' % pci) dev = self.m_devices[pci] if info['TRex_Driver'] not in drivers_table: - print("Got unknown driver '%s', description: %s" % (info['TRex_Driver'], dev['Device_str'])) + raise DpdkSetup("Got unknown driver '%s', description: %s" % (info['TRex_Driver'], dev['Device_str'])) + linux_driver = drivers_table[info['TRex_Driver']] + if linux_driver not in dpdk_nic_bind.get_loaded_modules(): + print("No Linux driver installed, or wrong module name: %s" % linux_driver) else: print('Returning to Linux %s' % pci) - dpdk_nic_bind.bind_one(pci, drivers_table[info['TRex_Driver']], False) + dpdk_nic_bind.bind_one(pci, linux_driver, False) def _get_cpu_topology(self): cpu_topology_file = '/proc/cpuinfo' @@ -915,12 +1004,9 @@ To return to Linux the DPDK bound interfaces (for ifconfig etc.) To create TRex config file using interactive mode sudo ./dpdk_set_ports.py -i -To create a default config file (example1) +To create a default config file (example) sudo ./dpdk_setup_ports.py -c 02:00.0 02:00.1 -o /etc/trex_cfg.yaml -To create a default config file (example2) - sudo ./dpdk_setup_ports.py -c eth1 eth2 --dest-macs 11:11:11:11:11:11 22:22:22:22:22:22 --dump - To show interfaces status sudo ./dpdk_set_ports.py -s |