summaryrefslogtreecommitdiff
path: root/tools/devbind/devbind.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/devbind/devbind.py')
-rw-r--r--tools/devbind/devbind.py162
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()