From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id CB396231C for ; Mon, 19 May 2014 17:52:01 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 19 May 2014 08:47:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.98,868,1392192000"; d="scan'208";a="514129830" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 19 May 2014 08:52:07 -0700 Received: from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com [10.237.217.46]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id s4JFq6AO003670; Mon, 19 May 2014 16:52:06 +0100 Received: from sivswdev02.ir.intel.com (localhost [127.0.0.1]) by sivswdev02.ir.intel.com with ESMTP id s4JFq6VT025130; Mon, 19 May 2014 16:52:06 +0100 Received: (from aburakov@localhost) by sivswdev02.ir.intel.com with id s4JFq6jp025126; Mon, 19 May 2014 16:52:06 +0100 From: Anatoly Burakov To: dev@dpdk.org Date: Mon, 19 May 2014 16:51:48 +0100 Message-Id: <1400514709-24087-16-git-send-email-anatoly.burakov@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: References: Subject: [dpdk-dev] [PATCH v2 15/16] Added support for VFIO drivers in dpdk_nic_bind.py X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 May 2014 15:52:04 -0000 Since igb_uio no longer has a PCI ID list, the script will no longer distinguish between supported and unsupported NICs. There's a weird behaviour of sysfs when a new device ID is added to new_id. Subsequent writing to "bind" will result in IOError on closing the file. This error is harmless but it triggers the exception anyway, so in order to work around that, we check if the device was actually bound to the driver before raising an error. Signed-off-by: Anatoly Burakov --- tools/dpdk_nic_bind.py | 163 ++++++++++++++++++++++++++---------------------- 1 files changed, 89 insertions(+), 74 deletions(-) diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py index 824aa2b..06fb28a 100755 --- a/tools/dpdk_nic_bind.py +++ b/tools/dpdk_nic_bind.py @@ -42,8 +42,8 @@ ETHERNET_CLASS = "0200" # global dict ethernet devices present. Dictionary indexed by PCI address. # Each device within this is itself a dictionary of device properties devices = {} -# list of vendor:device pairs (again stored as dictionary) supported by igb_uio -module_dev_ids = [] +# list of supported DPDK drivers +dpdk_drivers = [ "igb_uio", "vfio-pci" ] def usage(): '''Print usage information for the program''' @@ -147,64 +147,70 @@ def find_module(mod): return path def check_modules(): - '''Checks that the needed modules (igb_uio) is loaded, and then - determine from the .ko file, what its supported device ids are''' - global module_dev_ids + '''Checks that the needed modules (igb_uio or vfio_pci) are loaded''' + global dpdk_drivers fd = file("/proc/modules") loaded_mods = fd.readlines() fd.close() - mod = "igb_uio" + + # list of supported modules + mods = [{"Name" : driver, "Found" : False} for driver in dpdk_drivers] # first check if module is loaded - found = False for line in loaded_mods: - if line.startswith(mod): - found = True - break - if not found: - print "Error - module %s not loaded" %mod - sys.exit(1) - - # now find the .ko and get list of supported vendor/dev-ids - modpath = find_module(mod) - if modpath is None: - print "Cannot find module file %s" % (mod + ".ko") + for mod in mods: + if line.startswith(mod["Name"]): + mod["Found"] = True + # special case for vfio_pci (module is named vfio-pci, + # but its .ko is named vfio_pci) + elif line.replace("_", "-").startswith(mod["Name"]): + mod["Found"] = True + + # check if we have at least one loaded module + if True not in [mod["Found"] for mod in mods]: + print "Error - no supported modules are loaded" sys.exit(1) - depmod_output = check_output(["depmod", "-n", modpath]).splitlines() - for line in depmod_output: - if not line.startswith("alias"): - continue - if not line.endswith(mod): - continue - lineparts = line.split() - if not(lineparts[1].startswith("pci:")): - continue; - else: - lineparts[1] = lineparts[1][4:] - vendor = lineparts[1][:9] - device = lineparts[1][9:18] - if vendor.startswith("v") and device.startswith("d"): - module_dev_ids.append({"Vendor": int(vendor[1:],16), - "Device": int(device[1:],16)}) - -def is_supported_device(dev_id): - '''return true if device is supported by igb_uio, false otherwise''' - for dev in module_dev_ids: - if (dev["Vendor"] == devices[dev_id]["Vendor"] and - dev["Device"] == devices[dev_id]["Device"]): - return True - return False + + # change DPDK driver list to only contain drivers that are loaded + dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] + def has_driver(dev_id): '''return true if a device is assigned to a driver. False otherwise''' return "Driver_str" in devices[dev_id] +def get_pci_device_details(dev_id): + '''This function gets additional details for a PCI device''' + device = {} + + extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() + + # parse lspci details + for line in extra_info: + if len(line) == 0: + continue + name, value = line.split("\t", 1) + name = name.strip(":") + "_str" + device[name] = value + # check for a unix interface name + sys_path = "/sys/bus/pci/devices/%s/net/" % dev_id + if exists(sys_path): + device["Interface"] = ",".join(os.listdir(sys_path)) + else: + device["Interface"] = "" + # check if a port is used for ssh connection + device["Ssh_if"] = False + device["Active"] = "" + + return device + def get_nic_details(): '''This function populates the "devices" dictionary. The keys used are the pci addresses (domain:bus:slot.func). The values are themselves dictionaries - one for each NIC.''' global devices + global dpdk_drivers # clear any old data devices = {} @@ -237,38 +243,23 @@ def get_nic_details(): # based on the basic info, get extended text details for d in devices.keys(): - extra_info = check_output(["lspci", "-vmmks", d]).splitlines() - # parse lspci details - for line in extra_info: - if len(line) == 0: - continue - name, value = line.split("\t", 1) - name = name.strip(":") + "_str" - devices[d][name] = value - # check for a unix interface name - sys_path = "/sys/bus/pci/devices/%s/net/" % d - if exists(sys_path): - devices[d]["Interface"] = ",".join(os.listdir(sys_path)) - else: - devices[d]["Interface"] = "" - # check if a port is used for ssh connection - devices[d]["Ssh_if"] = False - devices[d]["Active"] = "" + # get additional info and add it to existing data + devices[d] = dict(devices[d].items() + get_pci_device_details(d).items()) + for _if in ssh_if: if _if in devices[d]["Interface"].split(","): devices[d]["Ssh_if"] = True devices[d]["Active"] = "*Active*" break; - # add igb_uio to list of supporting modules if needed - if is_supported_device(d): - if "Module_str" in devices[d]: - if "igb_uio" not in devices[d]["Module_str"]: - devices[d]["Module_str"] = devices[d]["Module_str"] + ",igb_uio" - else: - devices[d]["Module_str"] = "igb_uio" - if "Module_str" not in devices[d]: - devices[d]["Module_str"] = "" + # add DPDK drivers to list of supporting modules if needed + if "Module_str" in devices[d]: + for driver in dpdk_drivers: + if driver not in devices[d]["Module_str"]: + devices[d]["Module_str"] = devices[d]["Module_str"] + ",%s" % driver + else: + devices[d]["Module_str"] = ",".join(dpdk_drivers) + # make sure the driver and module strings do not have any duplicates if has_driver(d): modules = devices[d]["Module_str"].split(",") @@ -298,7 +289,7 @@ def dev_id_from_dev_name(dev_name): sys.exit(1) def unbind_one(dev_id, force): - '''Unbind the device identified by "dev_id" from its current driver''' + '''Unbind the device identified by "dev_id" from its current driver''' dev = devices[dev_id] if not has_driver(dev_id): print "%s %s %s is not currently managed by any driver\n" % \ @@ -329,8 +320,8 @@ def bind_one(dev_id, driver, force): # prevent disconnection of our ssh session if dev["Ssh_if"] and not force: - print "Routing table indicates that interface %s is active" \ - ". Not modifying" % (dev_id) + print ("Routing table indicates that interface %s is active" + ". Not modifying" % (dev_id)) return # unbind any existing drivers we don't want @@ -343,6 +334,22 @@ def bind_one(dev_id, driver, force): unbind_one(dev_id, force) dev["Driver_str"] = "" # clear driver string + # if we are binding to one of DPDK drivers, add PCI id's to that driver + if driver in dpdk_drivers: + filename = "/sys/bus/pci/drivers/%s/new_id" % driver + try: + f = open(filename, "w") + except: + print "Error: bind failed for %s - Cannot open %s" % (dev_id, filename) + return + try: + f.write("%04x %04x" % (dev["Vendor"], dev["Device"])) + f.close() + except: + print "Error: bind failed for %s - Cannot write new PCI ID to " \ + "driver %s" % (dev_id, driver) + return + # do the bind by writing to /sys filename = "/sys/bus/pci/drivers/%s/bind" % driver try: @@ -356,6 +363,12 @@ def bind_one(dev_id, driver, force): f.write(dev_id) f.close() except: + # for some reason, closing dev_id after adding a new PCI ID to new_id + # results in IOError. however, if the device was successfully bound, + # we don't care for any errors and can safely ignore IOError + tmp = get_pci_device_details(dev_id) + if "Driver_str" in tmp and tmp["Driver_str"] == driver: + return print "Error: bind failed for %s - Cannot bind to driver %s" % (dev_id, driver) if saved_driver is not None: # restore any previous driver bind_one(dev_id, saved_driver, force) @@ -399,21 +412,23 @@ def show_status(): '''Function called when the script is passed the "--status" option. Displays to the user what devices are bound to the igb_uio driver, the kernel driver or to no driver''' + global dpdk_drivers kernel_drv = [] - uio_drv = [] + dpdk_drv = [] no_drv = [] + # split our list of devices into the three categories above for d in devices.keys(): if not has_driver(d): no_drv.append(devices[d]) continue - if devices[d]["Driver_str"] == "igb_uio": - uio_drv.append(devices[d]) + if devices[d]["Driver_str"] in dpdk_drivers: + dpdk_drv.append(devices[d]) else: kernel_drv.append(devices[d]) # print each category separately, so we can clearly see what's used by DPDK - display_devices("Network devices using IGB_UIO driver", uio_drv, \ + display_devices("Network devices using IGB_UIO driver", dpdk_drv, \ "drv=%(Driver_str)s unused=%(Module_str)s") display_devices("Network devices using kernel driver", kernel_drv, "if=%(Interface)s drv=%(Driver_str)s unused=%(Module_str)s %(Active)s") -- 1.7.0.7