Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/48131/?format=api
http://patches.dpdk.org/api/patches/48131/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/patch/9af4b611a659983a8a155a7d1d10b078b74c1d3d.1542291869.git.anatoly.burakov@intel.com/", "project": { "id": 1, "url": "http://patches.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": "<9af4b611a659983a8a155a7d1d10b078b74c1d3d.1542291869.git.anatoly.burakov@intel.com>", "list_archive_url": "https://inbox.dpdk.org/dev/9af4b611a659983a8a155a7d1d10b078b74c1d3d.1542291869.git.anatoly.burakov@intel.com", "date": "2018-11-15T15:47:17", "name": "[RFC,v2,5/9] usertools/lib: add device information library", "commit_ref": null, "pull_url": null, "state": "rejected", "archived": true, "hash": "616fac7756273699d1ee9860b140ae3626def84a", "submitter": { "id": 4, "url": "http://patches.dpdk.org/api/people/4/?format=api", "name": "Anatoly Burakov", "email": "anatoly.burakov@intel.com" }, "delegate": { "id": 1, "url": "http://patches.dpdk.org/api/users/1/?format=api", "username": "tmonjalo", "first_name": "Thomas", "last_name": "Monjalon", "email": "thomas@monjalon.net" }, "mbox": "http://patches.dpdk.org/project/dpdk/patch/9af4b611a659983a8a155a7d1d10b078b74c1d3d.1542291869.git.anatoly.burakov@intel.com/mbox/", "series": [ { "id": 2442, "url": "http://patches.dpdk.org/api/series/2442/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=2442", "date": "2018-11-15T15:47:16", "name": "Modularize and enhance DPDK Python scripts", "version": 2, "mbox": "http://patches.dpdk.org/series/2442/mbox/" } ], "comments": "http://patches.dpdk.org/api/patches/48131/comments/", "check": "success", "checks": "http://patches.dpdk.org/api/patches/48131/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 5F41D5B1E;\n\tThu, 15 Nov 2018 16:47:40 +0100 (CET)", "from mga17.intel.com (mga17.intel.com [192.55.52.151])\n\tby dpdk.org (Postfix) with ESMTP id 6ACD74CAD\n\tfor <dev@dpdk.org>; Thu, 15 Nov 2018 16:47:26 +0100 (CET)", "from orsmga006.jf.intel.com ([10.7.209.51])\n\tby fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t15 Nov 2018 07:47:24 -0800", "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga006.jf.intel.com with ESMTP; 15 Nov 2018 07:47:22 -0800", "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\twAFFlLTY024805; Thu, 15 Nov 2018 15:47:21 GMT", "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id wAFFlLEW028128;\n\tThu, 15 Nov 2018 15:47:21 GMT", "(from aburakov@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id wAFFlLGt028124;\n\tThu, 15 Nov 2018 15:47:21 GMT" ], "X-Amp-Result": "SKIPPED(no attachment in message)", "X-Amp-File-Uploaded": "False", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos;i=\"5.56,236,1539673200\"; d=\"scan'208\";a=\"91384362\"", "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, thomas@monjalon.net,\n\tferruh.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": [ "<cover.1542291869.git.anatoly.burakov@intel.com>", "<cover.1542291869.git.anatoly.burakov@intel.com>" ], "References": [ "<cover.1542291869.git.anatoly.burakov@intel.com>", "<cover.1529940601.git.anatoly.burakov@intel.com>\n\t<cover.1542291869.git.anatoly.burakov@intel.com>" ], "Subject": "[dpdk-dev] [RFC v2 5/9] usertools/lib: add device information\n\tlibrary", "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 | 424 +++++++++++++++++++++++++++++\n usertools/DPDKConfigLib/DevUtil.py | 242 ++++++++++++++++\n usertools/DPDKConfigLib/Util.py | 19 ++\n 3 files changed, 685 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..52edae771\n--- /dev/null\n+++ b/usertools/DPDKConfigLib/DevInfo.py\n@@ -0,0 +1,424 @@\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+__cavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051',\n+ 'SVendor': None, 'SDevice': None}\n+__cavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037',\n+ 'SVendor': None, 'SDevice': None}\n+__avp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110',\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, __avp_vnic]\n+_crypto_devices = [__encryption_class, __intel_processor_class]\n+_eventdev_devices = [__cavium_sso, __cavium_tim]\n+_mempool_devices = [__cavium_fpa]\n+_compress_devices = [__cavium_zip]\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+ DEVTYPE_COMPRESS = 4\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+ elif _device_type_match(lspci_dict, _compress_devices):\n+ self.devtype = DeviceType.DEVTYPE_COMPRESS\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 + _compress_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", "v2", "5/9" ] }{ "id": 48131, "url": "