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 module == 'vfio_pci': 157 module = 'vfio-pci' 158 159 if loaded_modules: 160 return module in loaded_modules 161 162 # Get list of sysfs modules (both built-in and dynamically loaded) 163 sysfs_path = '/sys/module/' 164 165 # Get the list of directories in sysfs_path 166 sysfs_mods = [m for m in os.listdir(sysfs_path) 167 if os.path.isdir(os.path.join(sysfs_path, m))] 168 169 # special case for vfio_pci (module is named vfio-pci, 170 # but its .ko is named vfio_pci) 171 sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods] 172 173 loaded_modules = sysfs_mods 174 175 return module in sysfs_mods 176 177 178def check_modules(): 179 '''Checks that igb_uio is loaded''' 180 global dpdk_drivers 181 182 # list of supported modules 183 mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] 184 185 # first check if module is loaded 186 for mod in mods: 187 if module_is_loaded(mod["Name"]): 188 mod["Found"] = True 189 190 # check if we have at least one loaded module 191 if True not in [mod["Found"] for mod in mods] and b_flag is not None: 192 print("Warning: no supported DPDK kernel modules are loaded", file=sys.stderr) 193 194 # change DPDK driver list to only contain drivers that are loaded 195 dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] 196 197 198def has_driver(dev_id): 199 '''return true if a device is assigned to a driver. False otherwise''' 200 return "Driver_str" in devices[dev_id] 201 202 203def get_pci_device_details(dev_id, probe_lspci): 204 '''This function gets additional details for a PCI device''' 205 device = {} 206 207 if probe_lspci: 208 extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() 209 210 # parse lspci details 211 for line in extra_info: 212 if len(line) == 0: 213 continue 214 name, value = line.decode().split("\t", 1) 215 name = name.strip(":") + "_str" 216 device[name] = value 217 # check for a unix interface name 218 device["Interface"] = "" 219 for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id): 220 if "net" in dirs: 221 device["Interface"] = \ 222 ",".join(os.listdir(os.path.join(base, "net"))) 223 break 224 # check if a port is used for ssh connection 225 device["Ssh_if"] = False 226 device["Active"] = "" 227 228 return device 229 230def clear_data(): 231 '''This function clears any old data''' 232 global devices 233 devices = {} 234 235def get_device_details(devices_type): 236 '''This function populates the "devices" dictionary. The keys used are 237 the pci addresses (domain:bus:slot.func). The values are themselves 238 dictionaries - one for each NIC.''' 239 global devices 240 global dpdk_drivers 241 242 # first loop through and read details for all devices 243 # request machine readable format, with numeric IDs and String 244 dev = {} 245 dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines() 246 for dev_line in dev_lines: 247 if len(dev_line) == 0: 248 if device_type_match(dev, devices_type): 249 # Replace "Driver" with "Driver_str" to have consistency of 250 # of dictionary key names 251 if "Driver" in dev.keys(): 252 dev["Driver_str"] = dev.pop("Driver") 253 if "Module" in dev.keys(): 254 dev["Module_str"] = dev.pop("Module") 255 # use dict to make copy of dev 256 devices[dev["Slot"]] = dict(dev) 257 # Clear previous device's data 258 dev = {} 259 else: 260 name, value = dev_line.decode().split("\t", 1) 261 value_list = value.rsplit(' ', 1) 262 if len(value_list) > 1: 263 # String stored in <name>_str 264 dev[name.rstrip(":") + '_str'] = value_list[0] 265 # Numeric IDs 266 dev[name.rstrip(":")] = value_list[len(value_list) - 1] \ 267 .rstrip("]").lstrip("[") 268 269 if devices_type == network_devices: 270 # check what is the interface if any for an ssh connection if 271 # any to this host, so we can mark it later. 272 ssh_if = [] 273 route = check_output(["ip", "-o", "route"]) 274 # filter out all lines for 169.254 routes 275 route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), 276 route.decode().splitlines())) 277 rt_info = route.split() 278 for i in range(len(rt_info) - 1): 279 if rt_info[i] == "dev": 280 ssh_if.append(rt_info[i+1]) 281 282 # based on the basic info, get extended text details 283 for d in devices.keys(): 284 if not device_type_match(devices[d], devices_type): 285 continue 286 287 # get additional info and add it to existing data 288 devices[d] = devices[d].copy() 289 # No need to probe lspci 290 devices[d].update(get_pci_device_details(d, False).items()) 291 292 if devices_type == network_devices: 293 for _if in ssh_if: 294 if _if in devices[d]["Interface"].split(","): 295 devices[d]["Ssh_if"] = True 296 devices[d]["Active"] = "*Active*" 297 break 298 299 # add igb_uio to list of supporting modules if needed 300 if "Module_str" in devices[d]: 301 for driver in dpdk_drivers: 302 if driver not in devices[d]["Module_str"]: 303 devices[d]["Module_str"] = \ 304 devices[d]["Module_str"] + ",%s" % driver 305 else: 306 devices[d]["Module_str"] = ",".join(dpdk_drivers) 307 308 # make sure the driver and module strings do not have any duplicates 309 if has_driver(d): 310 modules = devices[d]["Module_str"].split(",") 311 if devices[d]["Driver_str"] in modules: 312 modules.remove(devices[d]["Driver_str"]) 313 devices[d]["Module_str"] = ",".join(modules) 314 315 316def device_type_match(dev, devices_type): 317 for i in range(len(devices_type)): 318 param_count = len( 319 [x for x in devices_type[i].values() if x is not None]) 320 match_count = 0 321 if dev["Class"][0:2] == devices_type[i]["Class"]: 322 match_count = match_count + 1 323 for key in devices_type[i].keys(): 324 if key != 'Class' and devices_type[i][key]: 325 value_list = devices_type[i][key].split(',') 326 for value in value_list: 327 if value.strip(' ') == dev[key]: 328 match_count = match_count + 1 329 # count must be the number of non None parameters to match 330 if match_count == param_count: 331 return True 332 return False 333 334def dev_id_from_dev_name(dev_name): 335 '''Take a device "name" - a string passed in by user to identify a NIC 336 device, and determine the device id - i.e. the domain:bus:slot.func - for 337 it, which can then be used to index into the devices array''' 338 339 # check if it's already a suitable index 340 if dev_name in devices: 341 return dev_name 342 # check if it's an index just missing the domain part 343 elif "0000:" + dev_name in devices: 344 return "0000:" + dev_name 345 else: 346 # check if it's an interface name, e.g. eth1 347 for d in devices.keys(): 348 if dev_name in devices[d]["Interface"].split(","): 349 return devices[d]["Slot"] 350 # if nothing else matches - error 351 raise ValueError("Unknown device: %s. " 352 "Please specify device in \"bus:slot.func\" format" % dev_name) 353 354 355def unbind_one(dev_id, force): 356 '''Unbind the device identified by "dev_id" from its current driver''' 357 dev = devices[dev_id] 358 if not has_driver(dev_id): 359 print("Notice: %s %s %s is not currently managed by any driver" % 360 (dev["Slot"], dev["Device_str"], dev["Interface"]), file=sys.stderr) 361 return 362 363 # prevent us disconnecting ourselves 364 if dev["Ssh_if"] and not force: 365 print("Warning: routing table indicates that interface %s is active. " 366 "Skipping unbind" % dev_id, file=sys.stderr) 367 return 368 369 # write to /sys to unbind 370 filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] 371 try: 372 f = open(filename, "a") 373 except: 374 sys.exit("Error: unbind failed for %s - Cannot open %s" % 375 (dev_id, filename)) 376 f.write(dev_id) 377 f.close() 378 379 380def bind_one(dev_id, driver, force): 381 '''Bind the device given by "dev_id" to the driver "driver". If the device 382 is already bound to a different driver, it will be unbound first''' 383 dev = devices[dev_id] 384 saved_driver = None # used to rollback any unbind in case of failure 385 386 # prevent disconnection of our ssh session 387 if dev["Ssh_if"] and not force: 388 print("Warning: routing table indicates that interface %s is active. " 389 "Not modifying" % dev_id, file=sys.stderr) 390 return 391 392 # unbind any existing drivers we don't want 393 if has_driver(dev_id): 394 if dev["Driver_str"] == driver: 395 print("Notice: %s already bound to driver %s, skipping" % 396 (dev_id, driver), file=sys.stderr) 397 return 398 else: 399 saved_driver = dev["Driver_str"] 400 unbind_one(dev_id, force) 401 dev["Driver_str"] = "" # clear driver string 402 403 # For kernels >= 3.15 driver_override can be used to specify the driver 404 # for a device rather than relying on the driver to provide a positive 405 # match of the device. The existing process of looking up 406 # the vendor and device ID, adding them to the driver new_id, 407 # will erroneously bind other devices too which has the additional burden 408 # of unbinding those devices 409 if driver in dpdk_drivers: 410 filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 411 if os.path.exists(filename): 412 try: 413 f = open(filename, "w") 414 except: 415 print("Error: bind failed for %s - Cannot open %s" 416 % (dev_id, filename), file=sys.stderr) 417 return 418 try: 419 f.write("%s" % driver) 420 f.close() 421 except: 422 print("Error: bind failed for %s - Cannot write driver %s to " 423 "PCI ID " % (dev_id, driver), file=sys.stderr) 424 return 425 # For kernels < 3.15 use new_id to add PCI id's to the driver 426 else: 427 filename = "/sys/bus/pci/drivers/%s/new_id" % driver 428 try: 429 f = open(filename, "w") 430 except: 431 print("Error: bind failed for %s - Cannot open %s" 432 % (dev_id, filename), file=sys.stderr) 433 return 434 try: 435 # Convert Device and Vendor Id to int to write to new_id 436 f.write("%04x %04x" % (int(dev["Vendor"],16), 437 int(dev["Device"], 16))) 438 f.close() 439 except: 440 print("Error: bind failed for %s - Cannot write new PCI ID to " 441 "driver %s" % (dev_id, driver), file=sys.stderr) 442 return 443 444 # do the bind by writing to /sys 445 filename = "/sys/bus/pci/drivers/%s/bind" % driver 446 try: 447 f = open(filename, "a") 448 except: 449 print("Error: bind failed for %s - Cannot open %s" 450 % (dev_id, filename), file=sys.stderr) 451 if saved_driver is not None: # restore any previous driver 452 bind_one(dev_id, saved_driver, force) 453 return 454 try: 455 f.write(dev_id) 456 f.close() 457 except: 458 # for some reason, closing dev_id after adding a new PCI ID to new_id 459 # results in IOError. however, if the device was successfully bound, 460 # we don't care for any errors and can safely ignore IOError 461 tmp = get_pci_device_details(dev_id, True) 462 if "Driver_str" in tmp and tmp["Driver_str"] == driver: 463 return 464 print("Error: bind failed for %s - Cannot bind to driver %s" 465 % (dev_id, driver), file=sys.stderr) 466 if saved_driver is not None: # restore any previous driver 467 bind_one(dev_id, saved_driver, force) 468 return 469 470 # For kernels > 3.15 driver_override is used to bind a device to a driver. 471 # Before unbinding it, overwrite driver_override with empty string so that 472 # the device can be bound to any other driver 473 filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 474 if os.path.exists(filename): 475 try: 476 f = open(filename, "w") 477 except: 478 sys.exit("Error: unbind failed for %s - Cannot open %s" 479 % (dev_id, filename)) 480 try: 481 f.write("\00") 482 f.close() 483 except: 484 sys.exit("Error: unbind failed for %s - Cannot open %s" 485 % (dev_id, filename)) 486 487 488def unbind_all(dev_list, force=False): 489 """Unbind method, takes a list of device locations""" 490 491 if dev_list[0] == "dpdk": 492 for d in devices.keys(): 493 if "Driver_str" in devices[d]: 494 if devices[d]["Driver_str"] in dpdk_drivers: 495 unbind_one(devices[d]["Slot"], force) 496 return 497 498 try: 499 dev_list = map(dev_id_from_dev_name, dev_list) 500 except ValueError as ex: 501 print(ex) 502 sys.exit(1) 503 504 for d in dev_list: 505 unbind_one(d, force) 506 507 508def bind_all(dev_list, driver, force=False): 509 """Bind method, takes a list of device locations""" 510 global devices 511 512 # a common user error is to forget to specify the driver the devices need to 513 # be bound to. check if the driver is a valid device, and if it is, show 514 # a meaningful error. 515 try: 516 dev_id_from_dev_name(driver) 517 # if we've made it this far, this means that the "driver" was a valid 518 # device string, so it's probably not a valid driver name. 519 sys.exit("Error: Driver '%s' does not look like a valid driver. " \ 520 "Did you forget to specify the driver to bind devices to?" % driver) 521 except ValueError: 522 # driver generated error - it's not a valid device ID, so all is well 523 pass 524 525 # check if we're attempting to bind to a driver that isn't loaded 526 if not module_is_loaded(driver.replace('-','_')): 527 sys.exit("Error: Driver '%s' is not loaded." % driver) 528 529 try: 530 dev_list = map(dev_id_from_dev_name, dev_list) 531 except ValueError as ex: 532 sys.exit(ex) 533 534 for d in dev_list: 535 bind_one(d, driver, force) 536 537 # For kernels < 3.15 when binding devices to a generic driver 538 # (i.e. one that doesn't have a PCI ID table) using new_id, some devices 539 # that are not bound to any other driver could be bound even if no one has 540 # asked them to. hence, we check the list of drivers again, and see if 541 # some of the previously-unbound devices were erroneously bound. 542 if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d): 543 for d in devices.keys(): 544 # skip devices that were already bound or that we know should be bound 545 if "Driver_str" in devices[d] or d in dev_list: 546 continue 547 548 # update information about this device 549 devices[d] = dict(devices[d].items() + 550 get_pci_device_details(d, True).items()) 551 552 # check if updated information indicates that the device was bound 553 if "Driver_str" in devices[d]: 554 unbind_one(d, force) 555 556 557def display_devices(title, dev_list, extra_params=None): 558 '''Displays to the user the details of a list of devices given in 559 "dev_list". The "extra_params" parameter, if given, should contain a string 560 with %()s fields in it for replacement by the named fields in each 561 device's dictionary.''' 562 strings = [] # this holds the strings to print. We sort before printing 563 print("\n%s" % title) 564 print("="*len(title)) 565 if len(dev_list) == 0: 566 strings.append("<none>") 567 else: 568 for dev in dev_list: 569 if extra_params is not None: 570 strings.append("%s '%s %s' %s" % (dev["Slot"], 571 dev["Device_str"], 572 dev["Device"], 573 extra_params % dev)) 574 else: 575 strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) 576 # sort before printing, so that the entries appear in PCI order 577 strings.sort() 578 print("\n".join(strings)) # print one per line 579 580def show_device_status(devices_type, device_name): 581 global dpdk_drivers 582 kernel_drv = [] 583 dpdk_drv = [] 584 no_drv = [] 585 586 # split our list of network devices into the three categories above 587 for d in devices.keys(): 588 if device_type_match(devices[d], devices_type): 589 if not has_driver(d): 590 no_drv.append(devices[d]) 591 continue 592 if devices[d]["Driver_str"] in dpdk_drivers: 593 dpdk_drv.append(devices[d]) 594 else: 595 kernel_drv.append(devices[d]) 596 597 n_devs = len(dpdk_drv) + len(kernel_drv) + len(no_drv) 598 599 # don't bother displaying anything if there are no devices 600 if n_devs == 0: 601 msg = "No '%s' devices detected" % device_name 602 print("") 603 print(msg) 604 print("".join('=' * len(msg))) 605 return 606 607 # print each category separately, so we can clearly see what's used by DPDK 608 if len(dpdk_drv) != 0: 609 display_devices("%s devices using DPDK-compatible driver" % device_name, 610 dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s") 611 if len(kernel_drv) != 0: 612 display_devices("%s devices using kernel driver" % device_name, kernel_drv, 613 "if=%(Interface)s drv=%(Driver_str)s " 614 "unused=%(Module_str)s %(Active)s") 615 if len(no_drv) != 0: 616 display_devices("Other %s devices" % device_name, no_drv, 617 "unused=%(Module_str)s") 618 619def show_status(): 620 '''Function called when the script is passed the "--status" option. 621 Displays to the user what devices are bound to the igb_uio driver, the 622 kernel driver or to no driver''' 623 624 if status_dev == "net" or status_dev == "all": 625 show_device_status(network_devices, "Network") 626 627 if status_dev == "baseband" or status_dev == "all": 628 show_device_status(baseband_devices, "Baseband") 629 630 if status_dev == "crypto" or status_dev == "all": 631 show_device_status(crypto_devices, "Crypto") 632 633 if status_dev == "event" or status_dev == "all": 634 show_device_status(eventdev_devices, "Eventdev") 635 636 if status_dev == "mempool" or status_dev == "all": 637 show_device_status(mempool_devices, "Mempool") 638 639 if status_dev == "compress" or status_dev == "all": 640 show_device_status(compress_devices , "Compress") 641 642 if status_dev == "misc" or status_dev == "all": 643 show_device_status(misc_devices, "Misc (rawdev)") 644 645def parse_args(): 646 '''Parses the command-line arguments given by the user and takes the 647 appropriate action for each''' 648 global b_flag 649 global status_flag 650 global status_dev 651 global force_flag 652 global args 653 if len(sys.argv) <= 1: 654 usage() 655 sys.exit(0) 656 657 try: 658 opts, args = getopt.getopt(sys.argv[1:], "b:us", 659 ["help", "usage", "status", "status-dev=", 660 "force", "bind=", "unbind", ]) 661 except getopt.GetoptError as error: 662 print(str(error)) 663 print("Run '%s --usage' for further information" % sys.argv[0]) 664 sys.exit(1) 665 666 for opt, arg in opts: 667 if opt == "--help" or opt == "--usage": 668 usage() 669 sys.exit(0) 670 if opt == "--status-dev": 671 status_flag = True 672 status_dev = arg 673 if opt == "--status" or opt == "-s": 674 status_flag = True 675 status_dev = "all" 676 if opt == "--force": 677 force_flag = True 678 if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": 679 if b_flag is not None: 680 sys.exit("Error: binding and unbinding are mutually exclusive") 681 if opt == "-u" or opt == "--unbind": 682 b_flag = "none" 683 else: 684 b_flag = arg 685 686 687def do_arg_actions(): 688 '''do the actual action requested by the user''' 689 global b_flag 690 global status_flag 691 global force_flag 692 global args 693 694 if b_flag is None and not status_flag: 695 print("Error: No action specified for devices. " 696 "Please give a -b or -u option", file=sys.stderr) 697 usage() 698 sys.exit(1) 699 700 if b_flag is not None and len(args) == 0: 701 print("Error: No devices specified.", file=sys.stderr) 702 usage() 703 sys.exit(1) 704 705 if b_flag == "none" or b_flag == "None": 706 unbind_all(args, force_flag) 707 elif b_flag is not None: 708 bind_all(args, b_flag, force_flag) 709 if status_flag: 710 if b_flag is not None: 711 clear_data() 712 # refresh if we have changed anything 713 get_device_details(network_devices) 714 get_device_details(baseband_devices) 715 get_device_details(crypto_devices) 716 get_device_details(eventdev_devices) 717 get_device_details(mempool_devices) 718 get_device_details(compress_devices) 719 get_device_details(misc_devices) 720 show_status() 721 722 723def main(): 724 '''program main function''' 725 # check if lspci is installed, suppress any output 726 with open(os.devnull, 'w') as devnull: 727 ret = subprocess.call(['which', 'lspci'], 728 stdout=devnull, stderr=devnull) 729 if ret != 0: 730 sys.exit("'lspci' not found - please install 'pciutils'") 731 parse_args() 732 check_modules() 733 clear_data() 734 get_device_details(network_devices) 735 get_device_details(baseband_devices) 736 get_device_details(crypto_devices) 737 get_device_details(eventdev_devices) 738 get_device_details(mempool_devices) 739 get_device_details(compress_devices) 740 get_device_details(misc_devices) 741 do_arg_actions() 742 743if __name__ == "__main__": 744 main() 745