From e939511acbb16cda3dab34fe255160ae7ae19258 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sun, 21 Aug 2016 23:22:19 +0300 Subject: Check if interfaces are in use at binding/unbinding/starting TRex. --- scripts/dpdk_nic_bind.py | 87 ++++++++++++++++++++++++++++++++++++--------- scripts/dpdk_setup_ports.py | 53 +++++++++++++++++++++------ scripts/trex-cfg | 14 ++++++-- 3 files changed, 125 insertions(+), 29 deletions(-) diff --git a/scripts/dpdk_nic_bind.py b/scripts/dpdk_nic_bind.py index dcb84823..b1f38c09 100755 --- a/scripts/dpdk_nic_bind.py +++ b/scripts/dpdk_nic_bind.py @@ -317,6 +317,51 @@ def dev_id_from_dev_name(dev_name): "Please specify device in \"bus:slot.func\" format" % dev_name) sys.exit(1) +def get_igb_uio_usage(): + for driver in dpdk_drivers: + refcnt_file = '/sys/module/%s/refcnt' % driver + if not os.path.exists(refcnt_file): + continue + with open(refcnt_file) as f: + ref_cnt = int(f.read().strip()) + if ref_cnt: + return True + return False + +def get_pid_using_pci(pci_list): + if not isinstance(pci_list, list): + pci_list = [pci_list] + pci_list = map(dev_id_from_dev_name, pci_list) + for pid in os.listdir('/proc'): + try: + int(pid) + except ValueError: + continue + with open('/proc/%s/maps' % pid) as f: + f_cont = f.read() + for pci in pci_list: + if '/%s/' % pci in f_cont: + with open('/proc/%s/status' % pid) as f: + for line in f.readlines(): + key, val = line.split(':', 1) + if key.strip() == 'Tgid' and val.strip() == pid: + return int(pid) + +def read_pid_cmdline(pid): + cmdline_file = '/proc/%s/cmdline' % pid + if not os.path.exists(cmdline_file): + return None + with open(cmdline_file, 'rb') as f: + return f.read().replace(b'\0', b' ').decode() + +def confirm(msg, default = False): + try: + if not os.isatty(1): + return default + return strtobool(raw_input(msg)) + except: + return default + def unbind_one(dev_id, force): '''Unbind the device identified by "dev_id" from its current driver''' dev = devices[dev_id] @@ -325,17 +370,22 @@ def unbind_one(dev_id, force): (dev[b"Slot"], dev[b"Device_str"], dev[b"Interface"])) return - # prevent us disconnecting ourselves - if dev["Active"] and not force: - print("netstat indicates that interface %s is active." % dev_id) - result = None - try: - result = strtobool(raw_input("Confirm unbind (y/N)")) - finally: - if not result: + if not force and dev.get('Driver_str') in dpdk_drivers and get_igb_uio_usage(): + pid = get_pid_using_pci(dev_id) + if pid: + cmdline = read_pid_cmdline(pid) + print('Interface %s is in use by process:\n%s' % (dev_id, cmdline)) + if not confirm('Unbinding might hang the process. Confirm unbind (y/N)'): print('Not unbinding.') return + # prevent us disconnecting ourselves + if dev["Active"] and not force: + print('netstat indicates that interface %s is active.' % dev_id) + if not confirm('Confirm unbind (y/N)'): + print('Not unbinding.') + return + # write to /sys to unbind filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] try: @@ -355,13 +405,9 @@ def bind_one(dev_id, driver, force): # prevent disconnection of our ssh session if dev["Active"] and not force: print("netstat indicates that interface %s is active" % dev_id) - result = None - try: - result = strtobool(raw_input("Confirm bind (y/N)")) - finally: - if not result: - print('Not binding.') - return + if not confirm("Confirm bind (y/N)"): + print('Not binding.') + return # unbind any existing drivers we don't want if has_driver(dev_id): @@ -370,6 +416,15 @@ def bind_one(dev_id, driver, force): return else: saved_driver = dev["Driver_str"] + if not force and get_igb_uio_usage(): + pid = get_pid_using_pci(dev_id) + if pid: + cmdline = read_pid_cmdline(pid) + print('Interface %s is in use by process:\n%s' % (dev_id, cmdline)) + if not confirm('Binding to other driver might hang the process. Confirm unbind (y/N)'): + print('Not binding.') + return + unbind_one(dev_id, force) dev["Driver_str"] = "" # clear driver string @@ -507,7 +562,7 @@ def get_macs_from_trex(pci_addr_list): 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) + print('Error upon running TRex to get MAC info:\n%s' % stdout) sys.exit(1) pci_mac_str = 'PCI: (\S+).+?MAC: (\S+)' pci_mac_re = re.compile(pci_mac_str) diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 252779a7..b32163da 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -239,7 +239,6 @@ Other network devices raise DpdkSetup(s) def load_config_file (self): - #return fcfg=self.m_cfg_file @@ -302,30 +301,60 @@ Other network devices def run_dpdk_lspci (self): - dpdk_nic_bind.get_nic_details() - self.m_devices= dpdk_nic_bind.devices + dpdk_nic_bind.get_nic_details() + self.m_devices= dpdk_nic_bind.devices def do_run (self): self.run_dpdk_lspci () - if map_driver.dump_interfaces is None or (map_driver.dump_interfaces is [] and map_driver.parent_cfg): + if map_driver.dump_interfaces is None or (map_driver.dump_interfaces == [] and map_driver.parent_cfg): self.load_config_file() if_list=self.m_cfg_dict[0]['interfaces'] else: if_list = map_driver.dump_interfaces + if not if_list: + for dev in self.m_devices.values(): + if dev.get('Driver_str') in dpdk_nic_bind.dpdk_drivers: + if_list.append(dev['Slot']) - for obj in if_list: - key= self.pci_name_to_full_name (obj) + if_list = list(map(self.pci_name_to_full_name, if_list)) + 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'] !='igb_uio' : + if self.m_devices[key]['Driver_str'] not in dpdk_nic_bind.dpdk_drivers : self.do_bind_one (key) else: self.do_bind_one (key) + if if_list and map_driver.args.parent and dpdk_nic_bind.get_igb_uio_usage(): + pid = dpdk_nic_bind.get_pid_using_pci(if_list) + cmdline = dpdk_nic_bind.read_pid_cmdline(pid) + print('Some or all of given interfaces are in use by following process:\n%s' % cmdline) + if not dpdk_nic_bind.confirm('Ignore and proceed (y/N):'): + sys.exit(1) + + + def do_return_to_linux(self): + if not self.m_devices: + self.run_dpdk_lspci() + dpdk_interfaces = [] + for device in self.m_devices.values(): + if device.get('Driver_str') in dpdk_nic_bind.dpdk_drivers: + dpdk_interfaces.append(device['Slot']) + if not dpdk_interfaces: + print('No DPDK bound interfaces.') + return + if dpdk_nic_bind.get_igb_uio_usage(): + 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:\n%s' % cmdline) + if not dpdk_nic_bind.confirm('Confirm (y/N):'): + return + print('TODO: unbind %s' % dpdk_interfaces) def do_create(self): create_interfaces = map_driver.args.create_interfaces @@ -357,7 +386,7 @@ Other network devices if 'Driver_str' not in interface: self.do_bind_one(interface['Slot']) dpdk_bound.append(interface['Slot']) - elif interface['Driver_str'] == 'igb_uio': + elif interface['Driver_str'] in dpdk_nic_bind.dpdk_drivers: dpdk_bound.append(interface['Slot']) if dpdk_bound: for pci, mac in dpdk_nic_bind.get_macs_from_trex(dpdk_bound).items(): @@ -414,7 +443,7 @@ def process_options (): Examples: --------- -To unbind the interfaces using the trex configuration file +To return to Linux the DPDK bound interfaces (for ifconfig etc.) sudo ./dpdk_set_ports.py -l To create a default config file (example1) @@ -433,8 +462,8 @@ To see more detailed info on interfaces (table): description=" unbind dpdk interfaces ", epilog=" written by hhaim"); - parser.add_argument("-l", "--load", action='store_true', - help=""" unbind the interfaces using the configuration file given """, + parser.add_argument("-l", "--linux", action='store_true', + help=""" Return all DPDK interfaces to Linux driver """, ) parser.add_argument("--cfg", @@ -524,6 +553,8 @@ def main (): if map_driver.args.create_interfaces is not None: obj.do_create(); + elif map_driver.args.linux: + obj.do_return_to_linux(); else: obj.do_run(); except DpdkSetup as e: diff --git a/scripts/trex-cfg b/scripts/trex-cfg index 02421001..55eb18fb 100755 --- a/scripts/trex-cfg +++ b/scripts/trex-cfg @@ -65,5 +65,15 @@ fi # try to bind the ports from the configuration file (new DPDK) PARENT_ARGS="$0 $@" -(/usr/bin/python -V &> /dev/null && ./dpdk_setup_ports.py --parent "$PARENT_ARGS") || - (/usr/bin/python3 -V &> /dev/null && /usr/bin/python3 dpdk_setup_ports.py --parent "$PARENT_ARGS") || exit 1 + +if /usr/bin/python -V &> /dev/null; then + ./dpdk_setup_ports.py --parent "$PARENT_ARGS" +elif /usr/bin/python3 -V &> /dev/null; then + /usr/bin/python3 dpdk_setup_ports.py --parent "$PARENT_ARGS" +elif python -V &> /dev/null; then + python ./dpdk_setup_ports.py --parent "$PARENT_ARGS" +else + echo "Could not find python to run dpdk_setup_ports.py script" + exit 1 +fi + -- cgit 1.2.3-korg