diff options
Diffstat (limited to 'tools/devbind/devbind.py')
| -rw-r--r-- | tools/devbind/devbind.py | 162 |
1 files changed, 109 insertions, 53 deletions
diff --git a/tools/devbind/devbind.py b/tools/devbind/devbind.py index 1243f0e..3fc3cc0 100644 --- a/tools/devbind/devbind.py +++ b/tools/devbind/devbind.py @@ -39,7 +39,10 @@ import getopt import subprocess import json import argparse +import platform from os.path import exists, abspath, dirname, basename +from glob import glob +from os.path import join as path_join # The PCI base class for NETWORK devices NETWORK_BASE_CLASS = "02" @@ -57,6 +60,8 @@ default_gcfg_location = '/usr/local/etc/mrglobal.conf' # This is roughly compatible with check_output function in subprocess module # which is only available in python 2.7. + + def check_output(args, stderr=None): '''Run a command and capture its output''' return subprocess.Popen(args, stdout=subprocess.PIPE, @@ -101,6 +106,7 @@ def check_modules(): # change DPDK driver list to only contain drivers that are loaded dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] + print dpdk_drivers def has_driver(devices, dev_id): @@ -222,7 +228,7 @@ def dev_id_from_dev_name(devices, dev_name, quite=False): if not quite: print("Unknown device: %s. " - "Please specify device in \"bus:slot.func\" format" % dev_name) + "Please specify device in \"bus:slot.func\" format" % dev_name) sys.exit(1) return None @@ -232,14 +238,14 @@ def unbind_one(devices, dev_id, force): '''Unbind the device identified by "dev_id" from its current driver''' dev = devices[dev_id] if not has_driver(devices, dev_id): - print("%s %s %s is not currently managed by any driver\n" % + print("Notice: %s %s %s is not currently managed by any driver" % (dev["Slot"], dev["Device_str"], dev["Interface"])) return # prevent us disconnecting ourselves if dev["Ssh_if"] and not force: - print("Routing table indicates that interface %s is active. " - "Skipping unbind" % (dev_id)) + print("Warning: routing table indicates that interface %s is active. " + "Skipping unbind" % dev_id) return # write to /sys to unbind @@ -247,13 +253,13 @@ def unbind_one(devices, dev_id, force): try: f = open(filename, "a") except: - print("Error: unbind failed for %s - Cannot open %s" - % (dev_id, filename)) - sys.exit(1) + sys.exit("Error: unbind failed for %s - Cannot open %s" % + (dev_id, filename)) f.write(dev_id) f.close() -def is_mlx_dev(dev,devices): + +def is_mlx_dev(dev, devices): dev_item = devices.get(dev) dev_driver = dev_item.get('Driver_str') if 'mlx5_core' == dev_driver: @@ -261,57 +267,77 @@ def is_mlx_dev(dev,devices): else: return False + def bind_one(devices, dev_id, driver, force): '''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''' - dev = devices[dev_id] saved_driver = None # used to rollback any unbind in case of failure - if driver == '' or driver == None: - return - # 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("Warning: routing table indicates that interface %s is active. " + "Not modifying" % dev_id) return # unbind any existing drivers we don't want if has_driver(devices, dev_id): if dev["Driver_str"] == driver: - print("%s already bound to driver %s, skipping\n" - % (dev_id, driver)) + print("Notice: %s already bound to driver %s, skipping" % + (dev_id, driver)) return - else: - saved_driver = dev["Driver_str"] - unbind_one(devices, 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 + saved_driver = dev["Driver_str"] + unbind_one(devices, dev_id, force) + dev["Driver_str"] = "" # clear driver string + + # 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 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 + filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id + if exists(filename): + try: + f = open(filename, "w") + except: + print("Error: bind failed for %s - Cannot open %s" % + (dev_id, filename)) + return + try: + f.write("%s" % driver) + f.close() + except: + print("Error: bind failed for %s - Cannot write driver %s " % + (dev_id, driver)) + return + # For kernels < 3.15 use new_id to add PCI id's to the driver + else: + 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: + # Convert Device and Vendor Id to int to write to new_id + f.write("%04x %04x" % (int(dev["Vendor"], 16), + int(dev["Device"], 16))) + 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: f = open(filename, "a") except: - print("Error: bind failed for %s - Cannot open %s" - % (dev_id, filename)) + print("Error: bind failed for %s - Cannot open %s" % + (dev_id, filename)) if saved_driver is not None: # restore any previous driver bind_one(devices, dev_id, saved_driver, force) return @@ -325,12 +351,29 @@ def bind_one(devices, dev_id, driver, force): 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)) + 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(devices, dev_id, saved_driver, force) return + # 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 + filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id + if exists(filename): + try: + f = open(filename, "w") + except: + sys.exit("Error: unbind failed for %s - Cannot open %s" % + (dev_id, filename)) + try: + f.write("\00") + f.close() + except: + sys.exit("Error: unbind failed for %s - Cannot write %s" % + (dev_id, filename)) + def unbind_all(devices, dev_list, force=False): """Unbind method, takes a list of device locations""" @@ -344,7 +387,7 @@ def bind_all(devices, dev_list, driver, force=False): dev_list = map(lambda x: dev_id_from_dev_name(devices, x), dev_list) for d in dev_list: - if is_mlx_dev(d,devices) == False: + if is_mlx_dev(d, devices) == False: bind_one(devices, d, driver, force) # when binding devices to a generic driver (i.e. one that doesn't have a @@ -365,6 +408,7 @@ def bind_all(devices, dev_list, driver, force=False): if "Driver_str" in devices[d]: unbind_one(devices, d, force) + def hwfile_encode(location): devices = get_nic_details() _dirname = os.path.dirname(location) @@ -375,39 +419,48 @@ def hwfile_encode(location): json.dump(devices, json_fp) return + def hwfile_decode(location): with open(location, 'r') as json_fp: devices = json.load(json_fp) return devices + def setup_argv_parser(): parser = argparse.ArgumentParser(description='Marsio ZeroCopy Tools -- Network Interface Card Tools', - version = 'Marsio ZeroCopy Tools Suite 4.1') - - parser.add_argument('--hwfile', help = 'Hardware file location', nargs=1, metavar = 'FILE') - parser.add_argument('--action', help = 'Action, bind modules or unbind modules, or dump hwfiles', - choices=['bind','unbind','dump']) - parser.add_argument('--gcfg', help = 'Global configure file location', nargs=1, metavar = 'FILE') - parser.add_argument('interfaces', metavar='INTERFACES', help = 'symbol of interfaces', nargs ='*') + version='Marsio ZeroCopy Tools Suite 4.1') + + parser.add_argument( + '--hwfile', help='Hardware file location', nargs=1, metavar='FILE') + parser.add_argument('--action', help='Action, bind modules or unbind modules, or dump hwfiles', + choices=['bind', 'unbind', 'dump']) + parser.add_argument( + '--gcfg', help='Global configure file location', nargs=1, metavar='FILE') + parser.add_argument('interfaces', metavar='INTERFACES', + help='symbol of interfaces', nargs='*') return parser.parse_args() + def global_configure_parser(g_file): import ConfigParser config = ConfigParser.ConfigParser() config.read(g_file) - return config.get('device','device', 0).split(',') + return config.get('device', 'device', 0).split(',') + def nics_bind(hwinfo, niclist): devices_info = get_nic_details() + print dpdk_drivers bind_all(devices_info, niclist, dpdk_drivers[0], True) return + def nics_unbind(hwinfo, niclist): devices_info = get_nic_details() dev_addr_list = map(lambda x: dev_id_from_dev_name(hwinfo, x), niclist) kmod_list = map(lambda x: hwinfo[x]["Driver_str"], dev_addr_list) - map(lambda x,y: bind_one(devices_info, x, y, True), dev_addr_list, kmod_list) + map(lambda x, y: bind_one(devices_info, x, y, True), dev_addr_list, kmod_list) return @@ -415,7 +468,8 @@ def main(): r_options = setup_argv_parser() hwfile_location = r_options.hwfile[0] if r_options.hwfile else default_hwfile_location gcfg_location = r_options.gcfg[0] if r_options.gcfg else default_gcfg_location - niclist = r_options.interfaces if r_options.interfaces else global_configure_parser(gcfg_location) + niclist = r_options.interfaces if r_options.interfaces else global_configure_parser( + gcfg_location) if r_options.action == 'dump': return hwfile_encode(hwfile_location) @@ -430,7 +484,8 @@ def main(): hwinfo = hwfile_decode(hwfile_location) check_modules() - niclist = [ d for d in niclist if dev_id_from_dev_name(hwinfo, d, quite=True)] + niclist = [d for d in niclist if dev_id_from_dev_name( + hwinfo, d, quite=True)] print niclist if r_options.action == 'bind': @@ -439,5 +494,6 @@ def main(): return nics_unbind(hwinfo, niclist) return + if __name__ == "__main__": - main()
\ No newline at end of file + main() |
