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