1#! /usr/bin/env python 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright(c) 2010-2014 Intel Corporation 4# 5 6from __future__ import print_function 7import sys 8import os 9import getopt 10import subprocess 11from os.path import exists, abspath, dirname, basename 12 13# The PCI base class for all devices 14network_class = {'Class': '02', 'Vendor': None, 'Device': None, 15 'SVendor': None, 'SDevice': None} 16acceleration_class = {'Class': '12', 'Vendor': None, 'Device': None, 17 'SVendor': None, 'SDevice': None} 18ifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30', 19 'SVendor': None, 'SDevice': None} 20encryption_class = {'Class': '10', 'Vendor': None, 'Device': None, 21 'SVendor': None, 'SDevice': None} 22intel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None, 23 'SVendor': None, 'SDevice': None} 24cavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d', 25 'SVendor': None, 'SDevice': None} 26cavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053', 27 'SVendor': None, 'SDevice': None} 28cavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049', 29 'SVendor': None, 'SDevice': None} 30cavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051', 31 'SVendor': None, 'SDevice': None} 32cavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037', 33 'SVendor': None, 'SDevice': None} 34avp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110', 35 'SVendor': None, 'SDevice': None} 36 37octeontx2_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f9,a0fa', 38 'SVendor': None, 'SDevice': None} 39octeontx2_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc', 40 'SVendor': None, 'SDevice': None} 41octeontx2_dma = {'Class': '08', 'Vendor': '177d', 'Device': 'a081', 42 'SVendor': None, 'SDevice': None} 43 44intel_ioat_bdw = {'Class': '08', 'Vendor': '8086', 'Device': '6f20,6f21,6f22,6f23,6f24,6f25,6f26,6f27,6f2e,6f2f', 45 'SVendor': None, 'SDevice': None} 46intel_ioat_skx = {'Class': '08', 'Vendor': '8086', 'Device': '2021', 47 'SVendor': None, 'SDevice': None} 48intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c', 49 'SVendor': None, 'SDevice': None} 50 51network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class] 52baseband_devices = [acceleration_class] 53crypto_devices = [encryption_class, intel_processor_class] 54eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso] 55mempool_devices = [cavium_fpa, octeontx2_npa] 56compress_devices = [cavium_zip] 57misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ntb_skx, octeontx2_dma] 58 59# global dict ethernet devices present. Dictionary indexed by PCI address. 60# Each device within this is itself a dictionary of device properties 61devices = {} 62# list of supported DPDK drivers 63dpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] 64# list of currently loaded kernel modules 65loaded_modules = None 66 67# command-line arg flags 68b_flag = None 69status_flag = False 70force_flag = False 71args = [] 72 73 74def usage(): 75 '''Print usage information for the program''' 76 argv0 = basename(sys.argv[0]) 77 print(""" 78Usage: 79------ 80 81 %(argv0)s [options] DEVICE1 DEVICE2 .... 82 83where DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax 84or "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may 85also be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. 86 87Options: 88 --help, --usage: 89 Display usage information and quit 90 91 -s, --status: 92 Print the current status of all known network, crypto, event 93 and mempool devices. 94 For each device, it displays the PCI domain, bus, slot and function, 95 along with a text description of the device. Depending upon whether the 96 device is being used by a kernel driver, the igb_uio driver, or no 97 driver, other relevant information will be displayed: 98 * the Linux interface name e.g. if=eth0 99 * the driver being used e.g. drv=igb_uio 100 * any suitable drivers not currently using that device 101 e.g. unused=igb_uio 102 NOTE: if this flag is passed along with a bind/unbind option, the 103 status display will always occur after the other operations have taken 104 place. 105 106 --status-dev: 107 Print the status of given device group. Supported device groups are: 108 "net", "baseband", "crypto", "event", "mempool" and "compress" 109 110 -b driver, --bind=driver: 111 Select the driver to use or \"none\" to unbind the device 112 113 -u, --unbind: 114 Unbind a device (Equivalent to \"-b none\") 115 116 --force: 117 By default, network devices which are used by Linux - as indicated by 118 having routes in the routing table - cannot be modified. Using the 119 --force flag overrides this behavior, allowing active links to be 120 forcibly unbound. 121 WARNING: This can lead to loss of network connection and should be used 122 with caution. 123 124Examples: 125--------- 126 127To display current device status: 128 %(argv0)s --status 129 130To display current network device status: 131 %(argv0)s --status-dev net 132 133To bind eth1 from the current driver and move to use igb_uio 134 %(argv0)s --bind=igb_uio eth1 135 136To unbind 0000:01:00.0 from using any driver 137 %(argv0)s -u 0000:01:00.0 138 139To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver 140 %(argv0)s -b ixgbe 02:00.0 02:00.1 141 142 """ % locals()) # replace items from local variables 143 144 145# This is roughly compatible with check_output function in subprocess module 146# which is only available in python 2.7. 147def check_output(args, stderr=None): 148 '''Run a command and capture its output''' 149 return subprocess.Popen(args, stdout=subprocess.PIPE, 150 stderr=stderr).communicate()[0] 151 152# check if a specific kernel module is loaded 153def module_is_loaded(module): 154 global loaded_modules 155 156 if loaded_modules: 157 return module in loaded_modules 158 159 # Get list of sysfs modules (both built-in and dynamically loaded) 160 sysfs_path = '/sys/module/' 161 162 # Get the list of directories in sysfs_path 163 sysfs_mods = [m for m in os.listdir(sysfs_path) 164 if os.path.isdir(os.path.join(sysfs_path, m))] 165 166 # special case for vfio_pci (module is named vfio-pci, 167 # but its .ko is named vfio_pci) 168 sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods] 169 170 loaded_modules = sysfs_mods 171 172 return module in sysfs_mods 173 174 175def check_modules(): 176 '''Checks that igb_uio is loaded''' 177 global dpdk_drivers 178 179 # list of supported modules 180 mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] 181 182 # first check if module is loaded 183 for mod in mods: 184 if module_is_loaded(mod["Name"]): 185 mod["Found"] = True 186 187 # check if we have at least one loaded module 188 if True not in [mod["Found"] for mod in mods] and b_flag is not None: 189 print("Warning: no supported DPDK kernel modules are loaded", file=sys.stderr) 190 191 # change DPDK driver list to only contain drivers that are loaded 192 dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] 193 194 195def has_driver(dev_id): 196 '''return true if a device is assigned to a driver. False otherwise''' 197 return "Driver_str" in devices[dev_id] 198 199 200def get_pci_device_details(dev_id, probe_lspci): 201 '''This function gets additional details for a PCI device''' 202 device = {} 203 204 if probe_lspci: 205 extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() 206 207 # parse lspci details 208 for line in extra_info: 209 if len(line) == 0: 210 continue 211 name, value = line.decode().split("\t", 1) 212 name = name.strip(":") + "_str" 213 device[name] = value 214 # check for a unix interface name 215 device["Interface"] = "" 216 for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id): 217 if "net" in dirs: 218 device["Interface"] = \ 219 ",".join(os.listdir(os.path.join(base, "net"))) 220 break 221 # check if a port is used for ssh connection 222 device["Ssh_if"] = False 223 device["Active"] = "" 224 225 return device 226 227def clear_data(): 228 '''This function clears any old data''' 229 global devices 230 devices = {} 231 232def get_device_details(devices_type): 233 '''This function populates the "devices" dictionary. The keys used are 234 the pci addresses (domain:bus:slot.func). The values are themselves 235 dictionaries - one for each NIC.''' 236 global devices 237 global dpdk_drivers 238 239 # first loop through and read details for all devices 240 # request machine readable format, with numeric IDs and String 241 dev = {} 242 dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines() 243 for dev_line in dev_lines: 244 if len(dev_line) == 0: 245 if device_type_match(dev, devices_type): 246 # Replace "Driver" with "Driver_str" to have consistency of 247 # of dictionary key names 248 if "Driver" in dev.keys(): 249 dev["Driver_str"] = dev.pop("Driver") 250 if "Module" in dev.keys(): 251 dev["Module_str"] = dev.pop("Module") 252 # use dict to make copy of dev 253 devices[dev["Slot"]] = dict(dev) 254 # Clear previous device's data 255 dev = {} 256 else: 257 name, value = dev_line.decode().split("\t", 1) 258 value_list = value.rsplit(' ', 1) 259 if len(value_list) > 1: 260 # String stored in <name>_str 261 dev[name.rstrip(":") + '_str'] = value_list[0] 262 # Numeric IDs 263 dev[name.rstrip(":")] = value_list[len(value_list) - 1] \ 264 .rstrip("]").lstrip("[") 265 266 if devices_type == network_devices: 267 # check what is the interface if any for an ssh connection if 268 # any to this host, so we can mark it later. 269 ssh_if = [] 270 route = check_output(["ip", "-o", "route"]) 271 # filter out all lines for 169.254 routes 272 route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), 273 route.decode().splitlines())) 274 rt_info = route.split() 275 for i in range(len(rt_info) - 1): 276 if rt_info[i] == "dev": 277 ssh_if.append(rt_info[i+1]) 278 279 # based on the basic info, get extended text details 280 for d in devices.keys(): 281 if not device_type_match(devices[d], devices_type): 282 continue 283 284 # get additional info and add it to existing data 285 devices[d] = devices[d].copy() 286 # No need to probe lspci 287 devices[d].update(get_pci_device_details(d, False).items()) 288 289 if devices_type == network_devices: 290 for _if in ssh_if: 291 if _if in devices[d]["Interface"].split(","): 292 devices[d]["Ssh_if"] = True 293 devices[d]["Active"] = "*Active*" 294 break 295 296 # add igb_uio to list of supporting modules if needed 297 if "Module_str" in devices[d]: 298 for driver in dpdk_drivers: 299 if driver not in devices[d]["Module_str"]: 300 devices[d]["Module_str"] = \ 301 devices[d]["Module_str"] + ",%s" % driver 302 else: 303 devices[d]["Module_str"] = ",".join(dpdk_drivers) 304 305 # make sure the driver and module strings do not have any duplicates 306 if has_driver(d): 307 modules = devices[d]["Module_str"].split(",") 308 if devices[d]["Driver_str"] in modules: 309 modules.remove(devices[d]["Driver_str"]) 310 devices[d]["Module_str"] = ",".join(modules) 311 312 313def device_type_match(dev, devices_type): 314 for i in range(len(devices_type)): 315 param_count = len( 316 [x for x in devices_type[i].values() if x is not None]) 317 match_count = 0 318 if dev["Class"][0:2] == devices_type[i]["Class"]: 319 match_count = match_count + 1 320 for key in devices_type[i].keys(): 321 if key != 'Class' and devices_type[i][key]: 322 value_list = devices_type[i][key].split(',') 323 for value in value_list: 324 if value.strip(' ') == dev[key]: 325 match_count = match_count + 1 326 # count must be the number of non None parameters to match 327 if match_count == param_count: 328 return True 329 return False 330 331def dev_id_from_dev_name(dev_name): 332 '''Take a device "name" - a string passed in by user to identify a NIC 333 device, and determine the device id - i.e. the domain:bus:slot.func - for 334 it, which can then be used to index into the devices array''' 335 336 # check if it's already a suitable index 337 if dev_name in devices: 338 return dev_name 339 # check if it's an index just missing the domain part 340 elif "0000:" + dev_name in devices: 341 return "0000:" + dev_name 342 else: 343 # check if it's an interface name, e.g. eth1 344 for d in devices.keys(): 345 if dev_name in devices[d]["Interface"].split(","): 346 return devices[d]["Slot"] 347 # if nothing else matches - error 348 raise ValueError("Unknown device: %s. " 349 "Please specify device in \"bus:slot.func\" format" % dev_name) 350 351 352def unbind_one(dev_id, force): 353 '''Unbind the device identified by "dev_id" from its current driver''' 354 dev = devices[dev_id] 355 if not has_driver(dev_id): 356 print("Notice: %s %s %s is not currently managed by any driver" % 357 (dev["Slot"], dev["Device_str"], dev["Interface"]), file=sys.stderr) 358 return 359 360 # prevent us disconnecting ourselves 361 if dev["Ssh_if"] and not force: 362 print("Warning: routing table indicates that interface %s is active. " 363 "Skipping unbind" % dev_id, file=sys.stderr) 364 return 365 366 # write to /sys to unbind 367 filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] 368 try: 369 f = open(filename, "a") 370 except: 371 sys.exit("Error: unbind failed for %s - Cannot open %s" % 372 (dev_id, filename)) 373 f.write(dev_id) 374 f.close() 375 376 377def bind_one(dev_id, driver, force): 378 '''Bind the device given by "dev_id" to the driver "driver". If the device 379 is already bound to a different driver, it will be unbound first''' 380 dev = devices[dev_id] 381 saved_driver = None # used to rollback any unbind in case of failure 382 383 # prevent disconnection of our ssh session 384 if dev["Ssh_if"] and not force: 385 print("Warning: routing table indicates that interface %s is active. " 386 "Not modifying" % dev_id, file=sys.stderr) 387 return 388 389 # unbind any existing drivers we don't want 390 if has_driver(dev_id): 391 if dev["Driver_str"] == driver: 392 print("Notice: %s already bound to driver %s, skipping" % 393 (dev_id, driver), file=sys.stderr) 394 return 395 else: 396 saved_driver = dev["Driver_str"] 397 unbind_one(dev_id, force) 398 dev["Driver_str"] = "" # clear driver string 399 400 # For kernels >= 3.15 driver_override can be used to specify the driver 401 # for a device rather than relying on the driver to provide a positive 402 # match of the device. The existing process of looking up 403 # the vendor and device ID, adding them to the driver new_id, 404 # will erroneously bind other devices too which has the additional burden 405 # of unbinding those devices 406 if driver in dpdk_drivers: 407 filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 408 if os.path.exists(filename): 409 try: 410 f = open(filename, "w") 411 except: 412 print("Error: bind failed for %s - Cannot open %s" 413 % (dev_id, filename), file=sys.stderr) 414 return 415 try: 416 f.write("%s" % driver) 417 f.close() 418 except: 419 print("Error: bind failed for %s - Cannot write driver %s to " 420 "PCI ID " % (dev_id, driver), file=sys.stderr) 421 return 422 # For kernels < 3.15 use new_id to add PCI id's to the driver 423 else: 424 filename = "/sys/bus/pci/drivers/%s/new_id" % driver 425 try: 426 f = open(filename, "w") 427 except: 428 print("Error: bind failed for %s - Cannot open %s" 429 % (dev_id, filename), file=sys.stderr) 430 return 431 try: 432 # Convert Device and Vendor Id to int to write to new_id 433 f.write("%04x %04x" % (int(dev["Vendor"],16), 434 int(dev["Device"], 16))) 435 f.close() 436 except: 437 print("Error: bind failed for %s - Cannot write new PCI ID to " 438 "driver %s" % (dev_id, driver), file=sys.stderr) 439 return 440 441 # do the bind by writing to /sys 442 filename = "/sys/bus/pci/drivers/%s/bind" % driver 443 try: 444 f = open(filename, "a") 445 except: 446 print("Error: bind failed for %s - Cannot open %s" 447 % (dev_id, filename), file=sys.stderr) 448 if saved_driver is not None: # restore any previous driver 449 bind_one(dev_id, saved_driver, force) 450 return 451 try: 452 f.write(dev_id) 453 f.close() 454 except: 455 # for some reason, closing dev_id after adding a new PCI ID to new_id 456 # results in IOError. however, if the device was successfully bound, 457 # we don't care for any errors and can safely ignore IOError 458 tmp = get_pci_device_details(dev_id, True) 459 if "Driver_str" in tmp and tmp["Driver_str"] == driver: 460 return 461 print("Error: bind failed for %s - Cannot bind to driver %s" 462 % (dev_id, driver), file=sys.stderr) 463 if saved_driver is not None: # restore any previous driver 464 bind_one(dev_id, saved_driver, force) 465 return 466 467 # For kernels > 3.15 driver_override is used to bind a device to a driver. 468 # Before unbinding it, overwrite driver_override with empty string so that 469 # the device can be bound to any other driver 470 filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 471 if os.path.exists(filename): 472 try: 473 f = open(filename, "w") 474 except: 475 sys.exit("Error: unbind failed for %s - Cannot open %s" 476 % (dev_id, filename)) 477 try: 478 f.write("\00") 479 f.close() 480 except: 481 sys.exit("Error: unbind failed for %s - Cannot open %s" 482 % (dev_id, filename)) 483 484 485def unbind_all(dev_list, force=False): 486 """Unbind method, takes a list of device locations""" 487 488 if dev_list[0] == "dpdk": 489 for d in devices.keys(): 490 if "Driver_str" in devices[d]: 491 if devices[d]["Driver_str"] in dpdk_drivers: 492 unbind_one(devices[d]["Slot"], force) 493 return 494 495 try: 496 dev_list = map(dev_id_from_dev_name, dev_list) 497 except ValueError as ex: 498 print(ex) 499 sys.exit(1) 500 501 for d in dev_list: 502 unbind_one(d, force) 503 504 505def bind_all(dev_list, driver, force=False): 506 """Bind method, takes a list of device locations""" 507 global devices 508 509 # a common user error is to forget to specify the driver the devices need to 510 # be bound to. check if the driver is a valid device, and if it is, show 511 # a meaningful error. 512 try: 513 dev_id_from_dev_name(driver) 514 # if we've made it this far, this means that the "driver" was a valid 515 # device string, so it's probably not a valid driver name. 516 sys.exit("Error: Driver '%s' does not look like a valid driver. " \ 517 "Did you forget to specify the driver to bind devices to?" % driver) 518 except ValueError: 519 # driver generated error - it's not a valid device ID, so all is well 520 pass 521 522 # check if we're attempting to bind to a driver that isn't loaded 523 if not module_is_loaded(driver): 524 sys.exit("Error: Driver '%s' is not loaded." % driver) 525 526 try: 527 dev_list = map(dev_id_from_dev_name, dev_list) 528 except ValueError as ex: 529 sys.exit(ex) 530 531 for d in dev_list: 532 bind_one(d, driver, force) 533 534 # For kernels < 3.15 when binding devices to a generic driver 535 # (i.e. one that doesn't have a PCI ID table) using new_id, some devices 536 # that are not bound to any other driver could be bound even if no one has 537 # asked them to. hence, we check the list of drivers again, and see if 538 # some of the previously-unbound devices were erroneously bound. 539 if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d): 540 for d in devices.keys(): 541 # skip devices that were already bound or that we know should be bound 542 if "Driver_str" in devices[d] or d in dev_list: 543 continue 544 545 # update information about this device 546 devices[d] = dict(devices[d].items() + 547 get_pci_device_details(d, True).items()) 548 549 # check if updated information indicates that the device was bound 550 if "Driver_str" in devices[d]: 551 unbind_one(d, force) 552 553 554def display_devices(title, dev_list, extra_params=None): 555 '''Displays to the user the details of a list of devices given in 556 "dev_list". The "extra_params" parameter, if given, should contain a string 557 with %()s fields in it for replacement by the named fields in each 558 device's dictionary.''' 559 strings = [] # this holds the strings to print. We sort before printing 560 print("\n%s" % title) 561 print("="*len(title)) 562 if len(dev_list) == 0: 563 strings.append("<none>") 564 else: 565 for dev in dev_list: 566 if extra_params is not None: 567 strings.append("%s '%s %s' %s" % (dev["Slot"], 568 dev["Device_str"], 569 dev["Device"], 570 extra_params % dev)) 571 else: 572 strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) 573 # sort before printing, so that the entries appear in PCI order 574 strings.sort() 575 print("\n".join(strings)) # print one per line 576 577def show_device_status(devices_type, device_name): 578 global dpdk_drivers 579 kernel_drv = [] 580 dpdk_drv = [] 581 no_drv = [] 582 583 # split our list of network devices into the three categories above 584 for d in devices.keys(): 585 if device_type_match(devices[d], devices_type): 586 if not has_driver(d): 587 no_drv.append(devices[d]) 588 continue 589 if devices[d]["Driver_str"] in dpdk_drivers: 590 dpdk_drv.append(devices[d]) 591 else: 592 kernel_drv.append(devices[d]) 593 594 n_devs = len(dpdk_drv) + len(kernel_drv) + len(no_drv) 595 596 # don't bother displaying anything if there are no devices 597 if n_devs == 0: 598 msg = "No '%s' devices detected" % device_name 599 print("") 600 print(msg) 601 print("".join('=' * len(msg))) 602 return 603 604 # print each category separately, so we can clearly see what's used by DPDK 605 if len(dpdk_drv) != 0: 606 display_devices("%s devices using DPDK-compatible driver" % device_name, 607 dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s") 608 if len(kernel_drv) != 0: 609 display_devices("%s devices using kernel driver" % device_name, kernel_drv, 610 "if=%(Interface)s drv=%(Driver_str)s " 611 "unused=%(Module_str)s %(Active)s") 612 if len(no_drv) != 0: 613 display_devices("Other %s devices" % device_name, no_drv, 614 "unused=%(Module_str)s") 615 616def show_status(): 617 '''Function called when the script is passed the "--status" option. 618 Displays to the user what devices are bound to the igb_uio driver, the 619 kernel driver or to no driver''' 620 621 if status_dev == "net" or status_dev == "all": 622 show_device_status(network_devices, "Network") 623 624 if status_dev == "baseband" or status_dev == "all": 625 show_device_status(baseband_devices, "Baseband") 626 627 if status_dev == "crypto" or status_dev == "all": 628 show_device_status(crypto_devices, "Crypto") 629 630 if status_dev == "event" or status_dev == "all": 631 show_device_status(eventdev_devices, "Eventdev") 632 633 if status_dev == "mempool" or status_dev == "all": 634 show_device_status(mempool_devices, "Mempool") 635 636 if status_dev == "compress" or status_dev == "all": 637 show_device_status(compress_devices , "Compress") 638 639 if status_dev == "misc" or status_dev == "all": 640 show_device_status(misc_devices, "Misc (rawdev)") 641 642def parse_args(): 643 '''Parses the command-line arguments given by the user and takes the 644 appropriate action for each''' 645 global b_flag 646 global status_flag 647 global status_dev 648 global force_flag 649 global args 650 if len(sys.argv) <= 1: 651 usage() 652 sys.exit(0) 653 654 try: 655 opts, args = getopt.getopt(sys.argv[1:], "b:us", 656 ["help", "usage", "status", "status-dev=", 657 "force", "bind=", "unbind", ]) 658 except getopt.GetoptError as error: 659 print(str(error)) 660 print("Run '%s --usage' for further information" % sys.argv[0]) 661 sys.exit(1) 662 663 for opt, arg in opts: 664 if opt == "--help" or opt == "--usage": 665 usage() 666 sys.exit(0) 667 if opt == "--status-dev": 668 status_flag = True 669 status_dev = arg 670 if opt == "--status" or opt == "-s": 671 status_flag = True 672 status_dev = "all" 673 if opt == "--force": 674 force_flag = True 675 if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": 676 if b_flag is not None: 677 sys.exit("Error: binding and unbinding are mutually exclusive") 678 if opt == "-u" or opt == "--unbind": 679 b_flag = "none" 680 else: 681 b_flag = arg 682 683 684def do_arg_actions(): 685 '''do the actual action requested by the user''' 686 global b_flag 687 global status_flag 688 global force_flag 689 global args 690 691 if b_flag is None and not status_flag: 692 print("Error: No action specified for devices. " 693 "Please give a -b or -u option", file=sys.stderr) 694 usage() 695 sys.exit(1) 696 697 if b_flag is not None and len(args) == 0: 698 print("Error: No devices specified.", file=sys.stderr) 699 usage() 700 sys.exit(1) 701 702 if b_flag == "none" or b_flag == "None": 703 unbind_all(args, force_flag) 704 elif b_flag is not None: 705 bind_all(args, b_flag, force_flag) 706 if status_flag: 707 if b_flag is not None: 708 clear_data() 709 # refresh if we have changed anything 710 get_device_details(network_devices) 711 get_device_details(baseband_devices) 712 get_device_details(crypto_devices) 713 get_device_details(eventdev_devices) 714 get_device_details(mempool_devices) 715 get_device_details(compress_devices) 716 get_device_details(misc_devices) 717 show_status() 718 719 720def main(): 721 '''program main function''' 722 # check if lspci is installed, suppress any output 723 with open(os.devnull, 'w') as devnull: 724 ret = subprocess.call(['which', 'lspci'], 725 stdout=devnull, stderr=devnull) 726 if ret != 0: 727 sys.exit("'lspci' not found - please install 'pciutils'") 728 parse_args() 729 check_modules() 730 clear_data() 731 get_device_details(network_devices) 732 get_device_details(baseband_devices) 733 get_device_details(crypto_devices) 734 get_device_details(eventdev_devices) 735 get_device_details(mempool_devices) 736 get_device_details(compress_devices) 737 get_device_details(misc_devices) 738 do_arg_actions() 739 740if __name__ == "__main__": 741 main() 742