All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anatoly Burakov <anatoly.burakov@intel.com>
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
Subject: [RFC 5/9] usertools/lib: add device information library
Date: Mon, 25 Jun 2018 16:59:42 +0100	[thread overview]
Message-ID: <fbdd490a61ed7eb058dec9ec6d5b2f443041e176.1529940601.git.anatoly.burakov@intel.com> (raw)
In-Reply-To: <cover.1529940601.git.anatoly.burakov@intel.com>
In-Reply-To: <cover.1529940601.git.anatoly.burakov@intel.com>

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 <anatoly.burakov@intel.com>
---
 usertools/DPDKConfigLib/DevInfo.py | 414 +++++++++++++++++++++++++++++
 usertools/DPDKConfigLib/DevUtil.py | 242 +++++++++++++++++
 usertools/DPDKConfigLib/Util.py    |  19 ++
 3 files changed, 675 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..8297b3544
--- /dev/null
+++ b/usertools/DPDKConfigLib/DevInfo.py
@@ -0,0 +1,414 @@
+#!/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}
+
+# internal data, not supposed to be exposed, but available to local classes
+_network_devices = [__network_class, __cavium_pkx]
+_crypto_devices = [__encryption_class, __intel_processor_class]
+_eventdev_devices = [__cavium_sso]
+_mempool_devices = [__cavium_fpa]
+
+__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
+
+
+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
+
+        # 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
+
+    # 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
-- 
2.17.1

  parent reply	other threads:[~2018-06-25 15:59 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-25 15:59 [RFC 0/9] Modularize and enhance DPDK Python scripts Anatoly Burakov
2018-06-25 15:59 ` [RFC 1/9] usertools: add DPDK config lib python library Anatoly Burakov
2018-06-25 15:59 ` [RFC 2/9] usertools/lib: add platform info library Anatoly Burakov
2018-06-25 15:59 ` [RFC 3/9] usertools/cpu_layout: rewrite to use DPDKConfigLib Anatoly Burakov
2018-06-25 15:59 ` [RFC 4/9] usertools/lib: support FreeBSD for platform info Anatoly Burakov
2018-06-25 15:59 ` Anatoly Burakov [this message]
2018-06-25 15:59 ` [RFC 6/9] usertools/devbind: switch to using DPDKConfigLib Anatoly Burakov
2018-06-25 15:59 ` [RFC 7/9] usertools/lib: add hugepage information library Anatoly Burakov
2018-06-25 15:59 ` [RFC 8/9] usertools: add hugepage info script Anatoly Burakov
2018-06-25 15:59 ` [RFC 9/9] usertools/lib: add GRUB utility library for hugepage config Anatoly Burakov
2018-06-26  1:09   ` Kevin Wilson
2018-06-26  9:05     ` Burakov, Anatoly
2018-08-14 10:11 ` [RFC 0/9] Modularize and enhance DPDK Python scripts Burakov, Anatoly
2018-08-28  8:16   ` Burakov, Anatoly
2018-11-15 15:47 ` [RFC v2 " Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 1/9] usertools: add DPDK config lib python library Anatoly Burakov
2018-11-16  0:45   ` Stephen Hemminger
2018-11-16 11:49     ` Burakov, Anatoly
2018-11-16 14:09       ` Wiles, Keith
2018-11-16 14:13         ` Richardson, Bruce
2018-11-16 14:37           ` Burakov, Anatoly
2018-11-16 14:55             ` Thomas Monjalon
2018-11-16 15:41               ` Wiles, Keith
2018-11-16 15:43               ` Burakov, Anatoly
2018-11-16 15:58                 ` Thomas Monjalon
2018-11-16 16:10                   ` Bruce Richardson
2018-11-16 16:08                 ` Bruce Richardson
2018-11-16 15:38             ` Wiles, Keith
2018-11-15 15:47 ` [RFC v2 2/9] usertools/lib: add platform info library Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 3/9] usertools/cpu_layout: rewrite to use DPDKConfigLib Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 4/9] usertools/lib: support FreeBSD for platform info Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 5/9] usertools/lib: add device information library Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 6/9] usertools/devbind: switch to using DPDKConfigLib Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 7/9] usertools/lib: add hugepage information library Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 8/9] usertools: add hugepage info script Anatoly Burakov
2018-11-15 15:47 ` [RFC v2 9/9] usertools/lib: add GRUB utility library for hugepage config Anatoly Burakov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fbdd490a61ed7eb058dec9ec6d5b2f443041e176.1529940601.git.anatoly.burakov@intel.com \
    --to=anatoly.burakov@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=david.hunt@intel.com \
    --cc=dev@dpdk.org \
    --cc=john.mcnamara@intel.com \
    --cc=mohammad.abdul.awal@intel.com \
    --cc=pablo.de.lara.guarch@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.