get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/41484/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

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