From patchwork Thu Nov 15 15:47:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Burakov, Anatoly" X-Patchwork-Id: 48131 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5F41D5B1E; Thu, 15 Nov 2018 16:47:40 +0100 (CET) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by dpdk.org (Postfix) with ESMTP id 6ACD74CAD for ; Thu, 15 Nov 2018 16:47:26 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 15 Nov 2018 07:47:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,236,1539673200"; d="scan'208";a="91384362" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga006.jf.intel.com with ESMTP; 15 Nov 2018 07:47:22 -0800 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id wAFFlLTY024805; Thu, 15 Nov 2018 15:47:21 GMT Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id wAFFlLEW028128; Thu, 15 Nov 2018 15:47:21 GMT Received: (from aburakov@localhost) by sivswdev01.ir.intel.com with LOCAL id wAFFlLGt028124; Thu, 15 Nov 2018 15:47:21 GMT From: Anatoly Burakov To: dev@dpdk.org Cc: john.mcnamara@intel.com, bruce.richardson@intel.com, pablo.de.lara.guarch@intel.com, david.hunt@intel.com, mohammad.abdul.awal@intel.com, thomas@monjalon.net, ferruh.yigit@intel.com Date: Thu, 15 Nov 2018 15:47:17 +0000 Message-Id: <9af4b611a659983a8a155a7d1d10b078b74c1d3d.1542291869.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [RFC v2 5/9] usertools/lib: add device information library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This library is mostly copy-paste of devbind script, but with few additional bells and whistles, such as the ability to enumerate and create/destroy VF devices. Signed-off-by: Anatoly Burakov --- usertools/DPDKConfigLib/DevInfo.py | 424 +++++++++++++++++++++++++++++ usertools/DPDKConfigLib/DevUtil.py | 242 ++++++++++++++++ usertools/DPDKConfigLib/Util.py | 19 ++ 3 files changed, 685 insertions(+) create mode 100755 usertools/DPDKConfigLib/DevInfo.py create mode 100755 usertools/DPDKConfigLib/DevUtil.py diff --git a/usertools/DPDKConfigLib/DevInfo.py b/usertools/DPDKConfigLib/DevInfo.py new file mode 100755 index 000000000..52edae771 --- /dev/null +++ b/usertools/DPDKConfigLib/DevInfo.py @@ -0,0 +1,424 @@ +#!/usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation +# Copyright(c) 2017 Cavium, Inc. All rights reserved. + +import glob +from .Util import * + +__DEFAULT_DPDK_DRIVERS = ["igb_uio", "vfio-pci", "uio_pci_generic"] +__dpdk_drivers = None # list of detected dpdk drivers +__devices = None # map from PCI address to device objects + +# The PCI base class for all devices +__network_class = {'Class': '02', 'Vendor': None, 'Device': None, + 'SVendor': None, 'SDevice': None} +__encryption_class = {'Class': '10', 'Vendor': None, 'Device': None, + 'SVendor': None, 'SDevice': None} +__intel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None, + 'SVendor': None, 'SDevice': None} +__cavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d', + 'SVendor': None, 'SDevice': None} +__cavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053', + 'SVendor': None, 'SDevice': None} +__cavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049', + 'SVendor': None, 'SDevice': None} +__cavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051', + 'SVendor': None, 'SDevice': None} +__cavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037', + 'SVendor': None, 'SDevice': None} +__avp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110', + 'SVendor': None, 'SDevice': None} + +# internal data, not supposed to be exposed, but available to local classes +_network_devices = [__network_class, __cavium_pkx, __avp_vnic] +_crypto_devices = [__encryption_class, __intel_processor_class] +_eventdev_devices = [__cavium_sso, __cavium_tim] +_mempool_devices = [__cavium_fpa] +_compress_devices = [__cavium_zip] + +__DRIVER_PATH_FMT = "/sys/bus/pci/drivers/%s/" +__DEVICE_PATH_FMT = "/sys/bus/pci/devices/%s/" + + +def _get_pci_speed_info(pci_addr): + data = subprocess.check_output(["lspci", "-vvs", pci_addr]).splitlines() + + # scan until we find capability structure + raw_data = {} + cur_key = "" + r = re.compile(r"Express \(v\d\) Endpoint") # PCI-E cap + found_pci_express_cap = False + for line in data: + key, value = kv_split(line, ":") + if not found_pci_express_cap: + if key != "Capabilities": + continue + # this is a capability structure - check if it's a PCI-E cap + m = r.search(value) + if not m: + continue # not a PCI-E cap + found_pci_express_cap = True + continue # start scanning for info + elif key == "Capabilities": + break # we've reached end of our PCI-E cap structure + if value is not None: + # this is a new key + cur_key = key + else: + value = key # this is continuation of previous key + raw_data[cur_key] = " ".join([raw_data.get(cur_key, ""), value]) + + # now, get our data out of there + result = { + "speed_supported": 0, + "width_supported": 0, + "speed_active": 0, + "width_active": 0 + } + speed_re = re.compile(r"Speed (\d+(\.\d+)?)GT/s") + width_re = re.compile(r"Width x(\d+)") + + val = raw_data.get("LnkCap", "") + speed_m = speed_re.search(val) + width_m = width_re.search(val) + # return empty + if speed_m: + result["speed_supported"] = float(speed_m.group(1)) + if width_m: + result["width_supported"] = int(width_m.group(1)) + + val = raw_data.get("LnkSta", "") + speed_m = speed_re.search(val) + width_m = width_re.search(val) + if speed_m: + result["speed_active"] = float(speed_m.group(1)) + if width_m: + result["width_active"] = int(width_m.group(1)) + return result + + +def _device_type_match(dev_dict, devices_type): + for i in range(len(devices_type)): + param_count = len( + [x for x in devices_type[i].values() if x is not None]) + match_count = 0 + if dev_dict["Class"][0:2] == devices_type[i]["Class"]: + match_count = match_count + 1 + for key in devices_type[i].keys(): + if key != 'Class' and devices_type[i][key]: + value_list = devices_type[i][key].split(',') + for value in value_list: + if value.strip() == dev_dict[key]: + match_count = match_count + 1 + # count must be the number of non None parameters to match + if match_count == param_count: + return True + return False + + +def _get_numa_node(addr): + path = get_device_path(addr, "numa_node") + if not os.path.isfile(path): + return 0 + val = int(read_file(path)) + return val if val >= 0 else 0 + + +def _basename_from_symlink(path): + if not os.path.islink(path): + raise ValueError("Invalid link: %s" % path) + return os.path.basename(os.path.realpath(path)) + + +def _get_pf_addr(pci_addr): + return _basename_from_symlink(get_device_path(pci_addr, "physfn")) + + +def _get_vf_addrs(pci_addr): + vf_path = get_device_path(pci_addr, "virtfn*") + return [_basename_from_symlink(path) for path in glob.glob(vf_path)] + + +def _get_total_vfs(pci_addr): + path = get_device_path(pci_addr, "sriov_totalvfs") + if not os.path.isfile(path): + return 0 + return int(read_file(path)) + + +# not allowed to use Enum because it's Python3.4+, so... +class DeviceType: + '''Device type identifier''' + DEVTYPE_UNKNOWN = -1 + DEVTYPE_NETWORK = 0 + DEVTYPE_CRYPTO = 1 + DEVTYPE_EVENT = 2 + DEVTYPE_MEMPOOL = 3 + DEVTYPE_COMPRESS = 4 + + +class DevInfo(object): + # map from lspci output to DevInfo attributes + __attr_map = { + 'Class': 'class_id', + 'Vendor': 'vendor_id', + 'Device': 'device_id', + 'SVendor': 'subsystem_vendor_id', + 'SDevice': 'subsystem_device_id', + 'Class_str': 'class_name', + 'Vendor_str': 'vendor_name', + 'Device_str': 'device_name', + 'SVendor_str': 'subsystem_vendor_name', + 'SDevice_str': 'subsystem_device_name', + 'Driver': 'active_driver' + } + + def __init__(self, pci_addr): + self.pci_addr = pci_addr # Slot + + # initialize all attributes + self.reset() + + # we know our PCI address at this point, so read lspci + self.update() + + def reset(self): + self.devtype = DeviceType.DEVTYPE_UNKNOWN # start with unknown type + self.class_id = "" # Class + self.vendor_id = "" # Vendor + self.device_id = "" # Device + self.subsystem_vendor_id = "" # SVendor + self.subsystem_device_id = "" # SDevice + self.class_name = "" # Class_str + self.vendor_name = "" # Vendor_str + self.device_name = "" # Device_str + self.subsystem_vendor_name = "" # SVendor_str + self.subsystem_device_name = "" # SDevice_str + self.kernel_drivers = [] # list of drivers in Module + self.active_driver = "" # Driver + self.available_drivers = [] + self.numa_node = -1 + self.is_virtual_function = False + self.virtual_functions = [] # list of VF pci addresses + self.physical_function = "" # PF PCI address if this is a VF + self.numvfs = 0 + self.totalvfs = 0 + self.pci_width_supported = 0 + self.pci_width_active = 0 + self.pci_speed_supported = 0 + self.pci_speed_active = 0 + + def update(self): + # clear everything + self.reset() + + lspci_info = subprocess.check_output(["lspci", "-vmmnnks", + self.pci_addr]).splitlines() + lspci_dict = {} + r = re.compile(r"\[[\da-f]{4}\]$") + + # parse lspci details + for line in lspci_info: + if len(line) == 0: + continue + name, value = line.decode().split("\t", 1) + name = name.strip(":") + has_id = r.search(value) is not None + if has_id: + namestr = name + "_str" + strvalue = value[:-7] # cut off hex value for _str value + value = value[-5:-1] # store hex value + lspci_dict[namestr] = strvalue + lspci_dict[name] = value + + # update object using map of lspci values to object attributes + for key, value in lspci_dict.items(): + if key in self.__attr_map: + setattr(self, self.__attr_map[key], value) + + # match device type + if _device_type_match(lspci_dict, _network_devices): + self.devtype = DeviceType.DEVTYPE_NETWORK + elif _device_type_match(lspci_dict, _crypto_devices): + self.devtype = DeviceType.DEVTYPE_CRYPTO + elif _device_type_match(lspci_dict, _eventdev_devices): + self.devtype = DeviceType.DEVTYPE_EVENT + elif _device_type_match(lspci_dict, _mempool_devices): + self.devtype = DeviceType.DEVTYPE_MEMPOOL + elif _device_type_match(lspci_dict, _compress_devices): + self.devtype = DeviceType.DEVTYPE_COMPRESS + + # special case - Module may have several drivers + if 'Module' in lspci_dict: + module_str = lspci_dict['Module'].split(',') + self.kernel_drivers = [d.strip() for d in module_str] + + # read NUMA node + self.numa_node = _get_numa_node(self.pci_addr) + + # check if device is a PF or a VF + try: + pf_addr = _get_pf_addr(self.pci_addr) + self.is_virtual_function = True + self.physical_function = pf_addr + except ValueError: + self.virtual_functions = _get_vf_addrs(self.pci_addr) + self.numvfs = len(self.virtual_functions) + self.totalvfs = _get_total_vfs(self.pci_addr) + + if not self.is_virtual_function: + speed_info = _get_pci_speed_info(self.pci_addr) + else: + speed_info = _get_pci_speed_info(self.physical_function) + + self.pci_width_active = speed_info["width_active"] + self.pci_width_supported = speed_info["width_supported"] + self.pci_speed_active = speed_info["speed_active"] + self.pci_speed_supported = speed_info["speed_supported"] + + # update available drivers + all_drivers = self.kernel_drivers + get_loaded_dpdk_drivers() + self.available_drivers = [driver for driver in all_drivers + if driver != self.active_driver] + + +# extends PCI device info with a few things unique to network devices +class NetworkDevInfo(DevInfo): + def __init__(self, pci_addr): + super(NetworkDevInfo, self).__init__(pci_addr) + + def reset(self): + super(NetworkDevInfo, self).reset() + self.interfaces = [] + self.ssh_interface = "" + self.active_interface = False + + def update(self): + # do regular update from lspci first + super(NetworkDevInfo, self).update() + + # now, update network-device-specific stuff + dirs = glob.glob(get_device_path(self.pci_addr, "net/*")) + self.interfaces = [os.path.basename(d) for d in dirs] + + # check what is the interface if any for an ssh connection if + # any to this host, so we can mark it. + route = subprocess.check_output(["ip", "-o", "route"]) + # filter out all lines for 169.254 routes + route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), + route.decode().splitlines())) + rt_info = route.split() + for i in range(len(rt_info) - 1): + if rt_info[i] == "dev": + iface = rt_info[i + 1] + if iface in self.interfaces: + self.ssh_interface = iface + self.active_interface = True + break + + +def __update_device_list(): + global __devices + + __devices = {} + + non_network_devices = _crypto_devices + _mempool_devices +\ + _eventdev_devices + _compress_devices + + # first loop through and read details for all devices + # request machine readable format, with numeric IDs and String + dev_dict = {} + lspci_lines = subprocess.check_output(["lspci", "-Dvmmnk"]).splitlines() + for line in lspci_lines: + if line.strip() == "": + # we've completed reading this device, so parse it + pci_addr = dev_dict['Slot'] + if _device_type_match(dev_dict, _network_devices): + d = NetworkDevInfo(pci_addr) + __devices[pci_addr] = d + elif _device_type_match(dev_dict, non_network_devices): + d = DevInfo(pci_addr) + __devices[pci_addr] = d + else: + # unsupported device, ignore + pass + dev_dict = {} # clear the dictionary for next + continue + name, value = line.decode().split("\t", 1) + name = name.rstrip(":") + # Numeric IDs + dev_dict[name] = value + + +def __update_dpdk_driver_list(): + global __dpdk_drivers + + __dpdk_drivers = __DEFAULT_DPDK_DRIVERS[:] # make a copy + + # list of supported modules + mods = [{"Name": driver, "Found": False} for driver in __dpdk_drivers] + + # first check if module is loaded + try: + # Get list of sysfs modules (both built-in and dynamically loaded) + sysfs_path = '/sys/module/' + + # Get the list of directories in sysfs_path + sysfs_mods = [os.path.join(sysfs_path, o) for o + in os.listdir(sysfs_path) + if os.path.isdir(os.path.join(sysfs_path, o))] + + # Extract the last element of '/sys/module/abc' in the array + sysfs_mods = [a.split('/')[-1] for a in sysfs_mods] + + # special case for vfio_pci (module is named vfio-pci, + # but its .ko is named vfio_pci) + sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods] + + for mod in mods: + if mod["Name"] in sysfs_mods: + mod["Found"] = True + except: + pass + + # change DPDK driver list to only contain drivers that are loaded + __dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] + + +# get a file/directory inside sysfs dir for a given PCI address +def get_device_path(pci_addr, fname): + return os.path.join(__DEVICE_PATH_FMT % pci_addr, fname) + + +# get a file/directory inside sysfs dir for a given driver +def get_driver_path(driver, fname): + return os.path.join(__DRIVER_PATH_FMT % driver, fname) + + +def get_loaded_dpdk_drivers(force_refresh=False): + '''Get list of loaded DPDK drivers''' + global __dpdk_drivers + + if __dpdk_drivers is not None and not force_refresh: + return __dpdk_drivers + + __update_dpdk_driver_list() + + return __dpdk_drivers + + +def get_supported_dpdk_drivers(): + return __DEFAULT_DPDK_DRIVERS + + +def get_devices(force_refresh=False): + '''Get list of detected devices''' + global __devices + + if __devices is not None and not force_refresh: + return __devices + + __update_device_list() + + return __devices diff --git a/usertools/DPDKConfigLib/DevUtil.py b/usertools/DPDKConfigLib/DevUtil.py new file mode 100755 index 000000000..17ee657f7 --- /dev/null +++ b/usertools/DPDKConfigLib/DevUtil.py @@ -0,0 +1,242 @@ +#!/usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation +# Copyright(c) 2017 Cavium, Inc. All rights reserved. + +from .DevInfo import * +import errno + + +# check if we have support for driver_override by looking at sysfs and checking +# if any of the PCI device directories have driver_override file inside them +__have_override = len(glob.glob("/sys/bus/pci/devices/*/driver_override")) != 0 + + +# wrap custom exceptions, so that we can handle errors we expect, but still pass +# through any unexpected errors to the caller (which might indicate a bug) +class BindException(Exception): + def __init__(self, *args, **kwargs): + Exception.__init__(self, *args, **kwargs) + + +class UnbindException(Exception): + def __init__(self, *args, **kwargs): + Exception.__init__(self, *args, **kwargs) + + +# change num vfs for a given device +def __write_numvfs(dev, num_vfs): + path = get_device_path(dev.pci_addr, "sriov_numvfs") + append_file(path, num_vfs) + dev.update() + + +# unbind device from its driver +def __unbind_device(dev): + '''Unbind the device identified by "addr" from its current driver''' + addr = dev.pci_addr + + # For kernels >= 3.15 driver_override is used to bind a device to a driver. + # Before unbinding it, overwrite driver_override with empty string so that + # the device can be bound to any other driver. + if __have_override: + override_fname = get_device_path(dev.pci_addr, "driver_override") + try: + write_file(override_fname, "\00") + except IOError as e: + raise UnbindException("Couldn't overwrite 'driver_override' " + "for PCI device '%s': %s" % + (addr, e.strerror)) + + filename = get_driver_path(dev.active_driver, "unbind") + try: + append_file(filename, addr) + except IOError: + raise UnbindException("Couldn't unbind PCI device '%s'" % addr) + dev.update() + + +# bind device to a specified driver +def __bind_device_to_driver(dev, driver): + '''Bind the device given by "dev_id" to the driver "driver". If the device + is already bound to a different driver, it will be unbound first''' + addr = dev.pci_addr + + # For kernels >= 3.15 driver_override can be used to specify the driver + # for a device rather than relying on the driver to provide a positive + # match of the device. The existing process of looking up + # the vendor and device ID, adding them to the driver new_id, + # will erroneously bind other devices too which has the additional burden + # of unbinding those devices + if driver in get_loaded_dpdk_drivers(): + if __have_override: + override_fname = get_device_path(dev.pci_addr, "driver_override") + try: + write_file(override_fname, driver) + except IOError as e: + raise BindException("Couldn't write 'driver_override' for " + "PCI device '%s': %s" % (addr, e.strerror)) + # For kernels < 3.15 use new_id to add PCI id's to the driver + else: + newid_fname = get_driver_path(driver, "new_id") + try: + # Convert Device and Vendor Id to int to write to new_id + write_file(newid_fname, "%04x %04x" % (int(dev.vendor_id, 16), + int(dev.device_id, 16))) + except IOError as e: + # for some reason, closing new_id after adding a new PCI + # ID to new_id results in IOError (with errno set to + # ENODEV). however, if the device was successfully bound, we + # don't care for any errors and can safely ignore the + # error. + if e.errno != errno.ENODEV: + raise BindException("Couldn't write 'new_id' for PCI " + "device '%s': %s" % (addr, e.strerror)) + + print(get_driver_path(driver, "bind")) + bind_fname = get_driver_path(driver, "bind") + try: + append_file(bind_fname, addr) + except IOError as e: + dev.update() + print(driver) + print(dev.active_driver) + raise BindException("Couldn't bind PCI device '%s' to driver '%s': %s" % + (addr, driver, e.strerror)) + dev.update() + + +def set_num_vfs(dev, num_vfs): + if not isinstance(dev, DevInfo): + dev = get_devices()[dev] + if dev.is_virtual_function: + raise ValueError("Device '%s' is a virtual function" % dev.pci_addr) + if num_vfs > dev.totalvfs: + raise ValueError("Device '%s' has '%i' virtual functions," + "'%i' requested" % (dev.pci_addr, dev.totalvfs, + num_vfs)) + if dev.num_vfs == num_vfs: + return + __write_numvfs(dev, num_vfs) + dev.update() + + +def unbind(addrs, force_unbind=False): + '''Unbind device(s) from all drivers''' + # build a list if we were not provided a list + pci_dev_list = [] + try: + pci_dev_list.extend(addrs) + except AttributeError: + pci_dev_list.append(addrs) + + # ensure we are only working with DevInfo objects + filter_func = (lambda d: d.active_interface != "" and + (d.devtype != DeviceType.DEVTYPE_NETWORK or + not d.active_interface or not force_unbind)) + pci_dev_list = filter(filter_func, [a if isinstance(a, DevInfo) + else get_devices()[get_device_name(a)] + for a in pci_dev_list]) + for d in pci_dev_list: + __unbind_device(d) + + +# we are intentionally not providing a "simple" function to bind a single +# device due to complexities involved with using kernels < 3.15. instead, we're +# allowing to call this function with either one PCI address or a list of PCI +# addresses, or one DevInfo object, or a list of DevInfo objects, and will +# automatically do cleanup even if we fail to bind some devices +def bind(addrs, driver, force_unbind=False): + '''Bind device(s) to a specified driver''' + # build a list if we were not provided a list + pci_dev_list = [] + try: + pci_dev_list.extend(addrs) + except AttributeError: + pci_dev_list.append(addrs) + + # we want devices that aren't already bound to the driver we want, and are + # either not network devices, or aren't active network interfaces, unless we + # are in force-unbind mode + filter_func = (lambda d: d.active_driver != driver and + (d.devtype != DeviceType.DEVTYPE_NETWORK or + not d.active_interface or not force_unbind)) + # ensure we are working with DevInfo instances, and filter them out + pci_dev_list = list(filter(filter_func, + [a if isinstance(a, DevInfo) + else get_devices()[get_device_name(a)] + for a in pci_dev_list])) + if len(pci_dev_list) == 0: + # nothing to be done, bail out + return + ex = None + try: + for dev in pci_dev_list: + old_driver = dev.active_driver + if dev.active_driver != "": + __unbind_device(dev) + __bind_device_to_driver(dev, driver) + except UnbindException as e: + # no need to roll back anything, but still stop + ex = e + except BindException as e: + # roll back changes, stop and raise later + dev.update() + if old_driver != dev.active_driver: + try: + __bind_device_to_driver(dev, old_driver) + except BindException: + # ignore this one, nothing we can do about it + pass + ex = e + finally: + # we need to do this regardless of whether we succeeded or failed + + # For kernels < 3.15 when binding devices to a generic driver + # (i.e. one that doesn't have a PCI ID table) using new_id, some devices + # that are not bound to any other driver could be bound even if no one + # has asked them to. hence, we check the list of drivers again, and see + # if some of the previously-unbound devices were erroneously bound. + if not __have_override: + for dev in get_devices(): + # skip devices that were already (or supposed to be) bound + if dev in pci_dev_list or dev.active_driver != "": + continue + + # update information about this device + dev.update() + + # check if updated information indicates the device was bound + if dev.active_driver != "": + try: + __unbind_device(dev) + except UnbindException as e: + # if we already had an exception previously, don't throw + # this one, because we have a higher-priority one that + # we haven't thrown yet + if ex is not None: + break + raise e + # if we've failed somewhere during the bind process, raise that + if ex is not None: + raise ex + + +def get_device_name(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 + it, which can then be used to index into the devices array''' + + # check if it's already a suitable index + if name in get_devices(): + return name + # check if it's an index just missing the domain part + elif "0000:" + name in get_devices(): + return "0000:" + name + else: + # check if it's an interface name, e.g. eth1 + filter_func = (lambda i: i.devtype == DeviceType.DEVTYPE_NETWORK) + for dev in filter(filter_func, get_devices().values()): + if name in dev.interfaces: + return dev.pci_addr + return None diff --git a/usertools/DPDKConfigLib/Util.py b/usertools/DPDKConfigLib/Util.py index 42434e728..eb21cce15 100755 --- a/usertools/DPDKConfigLib/Util.py +++ b/usertools/DPDKConfigLib/Util.py @@ -2,6 +2,25 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation +# read entire file and return the result +def read_file(path): + with open(path, 'r') as f: + result = f.read().strip() + return result + + +# write value to file +def write_file(path, value): + with open(path, 'w') as f: + f.write(value) + + +# append value to file +def append_file(path, value): + with open(path, 'a') as f: + f.write(value) + + # split line into key-value pair, cleaning up the values in the process def kv_split(line, separator): # just in case