1c6dab2a8SThomas Monjalon#! /usr/bin/env python 29d7c01f8SBruce Richardson# SPDX-License-Identifier: BSD-3-Clause 39d7c01f8SBruce Richardson# Copyright(c) 2010-2014 Intel Corporation 4c6dab2a8SThomas Monjalon# 5c6dab2a8SThomas Monjalon 6c6dab2a8SThomas Monjalonimport sys 7c6dab2a8SThomas Monjalonimport os 8c6dab2a8SThomas Monjalonimport getopt 9c6dab2a8SThomas Monjalonimport subprocess 10c6dab2a8SThomas Monjalonfrom os.path import exists, abspath, dirname, basename 11c6dab2a8SThomas Monjalon 128ad08a28SGuduri Prathyusha# The PCI base class for all devices 138ad08a28SGuduri Prathyushanetwork_class = {'Class': '02', 'Vendor': None, 'Device': None, 148ad08a28SGuduri Prathyusha 'SVendor': None, 'SDevice': None} 158ad08a28SGuduri Prathyushaencryption_class = {'Class': '10', 'Vendor': None, 'Device': None, 168ad08a28SGuduri Prathyusha 'SVendor': None, 'SDevice': None} 178ad08a28SGuduri Prathyushaintel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None, 188ad08a28SGuduri Prathyusha 'SVendor': None, 'SDevice': None} 1932a02dbfSGuduri Prathyushacavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d', 2032a02dbfSGuduri Prathyusha 'SVendor': None, 'SDevice': None} 2180a1858dSGuduri Prathyushacavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053', 2280a1858dSGuduri Prathyusha 'SVendor': None, 'SDevice': None} 23156c42eaSJerin Jacobcavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049', 24156c42eaSJerin Jacob 'SVendor': None, 'SDevice': None} 25*f4bc0010SPavan Nikhileshcavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051', 26*f4bc0010SPavan Nikhilesh 'SVendor': None, 'SDevice': None} 2720526313SXiaohua Zhangavp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110', 2820526313SXiaohua Zhang 'SVendor': None, 'SDevice': None} 298ad08a28SGuduri Prathyusha 3020526313SXiaohua Zhangnetwork_devices = [network_class, cavium_pkx, avp_vnic] 318ad08a28SGuduri Prathyushacrypto_devices = [encryption_class, intel_processor_class] 32*f4bc0010SPavan Nikhilesheventdev_devices = [cavium_sso, cavium_tim] 3380a1858dSGuduri Prathyushamempool_devices = [cavium_fpa] 34c6dab2a8SThomas Monjalon 35c6dab2a8SThomas Monjalon# global dict ethernet devices present. Dictionary indexed by PCI address. 36c6dab2a8SThomas Monjalon# Each device within this is itself a dictionary of device properties 37c6dab2a8SThomas Monjalondevices = {} 38c6dab2a8SThomas Monjalon# list of supported DPDK drivers 39c6dab2a8SThomas Monjalondpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] 40c6dab2a8SThomas Monjalon 41c6dab2a8SThomas Monjalon# command-line arg flags 42c6dab2a8SThomas Monjalonb_flag = None 43c6dab2a8SThomas Monjalonstatus_flag = False 44c6dab2a8SThomas Monjalonforce_flag = False 45c6dab2a8SThomas Monjalonargs = [] 46c6dab2a8SThomas Monjalon 47c6dab2a8SThomas Monjalon 48c6dab2a8SThomas Monjalondef usage(): 49c6dab2a8SThomas Monjalon '''Print usage information for the program''' 50c6dab2a8SThomas Monjalon argv0 = basename(sys.argv[0]) 51c6dab2a8SThomas Monjalon print(""" 52c6dab2a8SThomas MonjalonUsage: 53c6dab2a8SThomas Monjalon------ 54c6dab2a8SThomas Monjalon 55c6dab2a8SThomas Monjalon %(argv0)s [options] DEVICE1 DEVICE2 .... 56c6dab2a8SThomas Monjalon 57c6dab2a8SThomas Monjalonwhere DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax 58c6dab2a8SThomas Monjalonor "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may 59c6dab2a8SThomas Monjalonalso be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. 60c6dab2a8SThomas Monjalon 61c6dab2a8SThomas MonjalonOptions: 62c6dab2a8SThomas Monjalon --help, --usage: 63c6dab2a8SThomas Monjalon Display usage information and quit 64c6dab2a8SThomas Monjalon 65c6dab2a8SThomas Monjalon -s, --status: 66b153c00bSFerruh Yigit Print the current status of all known network, crypto, event 67b153c00bSFerruh Yigit and mempool devices. 68c6dab2a8SThomas Monjalon For each device, it displays the PCI domain, bus, slot and function, 69c6dab2a8SThomas Monjalon along with a text description of the device. Depending upon whether the 70c6dab2a8SThomas Monjalon device is being used by a kernel driver, the igb_uio driver, or no 71c6dab2a8SThomas Monjalon driver, other relevant information will be displayed: 72c6dab2a8SThomas Monjalon * the Linux interface name e.g. if=eth0 73c6dab2a8SThomas Monjalon * the driver being used e.g. drv=igb_uio 74c6dab2a8SThomas Monjalon * any suitable drivers not currently using that device 75c6dab2a8SThomas Monjalon e.g. unused=igb_uio 76c6dab2a8SThomas Monjalon NOTE: if this flag is passed along with a bind/unbind option, the 77c6dab2a8SThomas Monjalon status display will always occur after the other operations have taken 78c6dab2a8SThomas Monjalon place. 79c6dab2a8SThomas Monjalon 80b153c00bSFerruh Yigit --status-dev: 81b153c00bSFerruh Yigit Print the status of given device group. Supported device groups are: 82b153c00bSFerruh Yigit "net", "crypto", "event" and "mempool" 83b153c00bSFerruh Yigit 84c6dab2a8SThomas Monjalon -b driver, --bind=driver: 85c6dab2a8SThomas Monjalon Select the driver to use or \"none\" to unbind the device 86c6dab2a8SThomas Monjalon 87c6dab2a8SThomas Monjalon -u, --unbind: 88c6dab2a8SThomas Monjalon Unbind a device (Equivalent to \"-b none\") 89c6dab2a8SThomas Monjalon 90c6dab2a8SThomas Monjalon --force: 91c6dab2a8SThomas Monjalon By default, network devices which are used by Linux - as indicated by 92c6dab2a8SThomas Monjalon having routes in the routing table - cannot be modified. Using the 93c6dab2a8SThomas Monjalon --force flag overrides this behavior, allowing active links to be 94c6dab2a8SThomas Monjalon forcibly unbound. 95c6dab2a8SThomas Monjalon WARNING: This can lead to loss of network connection and should be used 96c6dab2a8SThomas Monjalon with caution. 97c6dab2a8SThomas Monjalon 98c6dab2a8SThomas MonjalonExamples: 99c6dab2a8SThomas Monjalon--------- 100c6dab2a8SThomas Monjalon 101c6dab2a8SThomas MonjalonTo display current device status: 102c6dab2a8SThomas Monjalon %(argv0)s --status 103c6dab2a8SThomas Monjalon 104b153c00bSFerruh YigitTo display current network device status: 105b153c00bSFerruh Yigit %(argv0)s --status-dev net 106b153c00bSFerruh Yigit 107c6dab2a8SThomas MonjalonTo bind eth1 from the current driver and move to use igb_uio 108c6dab2a8SThomas Monjalon %(argv0)s --bind=igb_uio eth1 109c6dab2a8SThomas Monjalon 110c6dab2a8SThomas MonjalonTo unbind 0000:01:00.0 from using any driver 111c6dab2a8SThomas Monjalon %(argv0)s -u 0000:01:00.0 112c6dab2a8SThomas Monjalon 113c6dab2a8SThomas MonjalonTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver 114c6dab2a8SThomas Monjalon %(argv0)s -b ixgbe 02:00.0 02:00.1 115c6dab2a8SThomas Monjalon 116c6dab2a8SThomas Monjalon """ % locals()) # replace items from local variables 117c6dab2a8SThomas Monjalon 118c6dab2a8SThomas Monjalon 119c6dab2a8SThomas Monjalon# This is roughly compatible with check_output function in subprocess module 120c6dab2a8SThomas Monjalon# which is only available in python 2.7. 121c6dab2a8SThomas Monjalondef check_output(args, stderr=None): 122c6dab2a8SThomas Monjalon '''Run a command and capture its output''' 123c6dab2a8SThomas Monjalon return subprocess.Popen(args, stdout=subprocess.PIPE, 124c6dab2a8SThomas Monjalon stderr=stderr).communicate()[0] 125c6dab2a8SThomas Monjalon 126c6dab2a8SThomas Monjalon 127c6dab2a8SThomas Monjalondef check_modules(): 128c6dab2a8SThomas Monjalon '''Checks that igb_uio is loaded''' 129c6dab2a8SThomas Monjalon global dpdk_drivers 130c6dab2a8SThomas Monjalon 131c6dab2a8SThomas Monjalon # list of supported modules 132c6dab2a8SThomas Monjalon mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] 133c6dab2a8SThomas Monjalon 134c6dab2a8SThomas Monjalon # first check if module is loaded 135c6dab2a8SThomas Monjalon try: 136c6dab2a8SThomas Monjalon # Get list of sysfs modules (both built-in and dynamically loaded) 137c6dab2a8SThomas Monjalon sysfs_path = '/sys/module/' 138c6dab2a8SThomas Monjalon 139c6dab2a8SThomas Monjalon # Get the list of directories in sysfs_path 140c6dab2a8SThomas Monjalon sysfs_mods = [os.path.join(sysfs_path, o) for o 141c6dab2a8SThomas Monjalon in os.listdir(sysfs_path) 142c6dab2a8SThomas Monjalon if os.path.isdir(os.path.join(sysfs_path, o))] 143c6dab2a8SThomas Monjalon 144c6dab2a8SThomas Monjalon # Extract the last element of '/sys/module/abc' in the array 145c6dab2a8SThomas Monjalon sysfs_mods = [a.split('/')[-1] for a in sysfs_mods] 146c6dab2a8SThomas Monjalon 147c6dab2a8SThomas Monjalon # special case for vfio_pci (module is named vfio-pci, 148c6dab2a8SThomas Monjalon # but its .ko is named vfio_pci) 1498fab26f8SOmri Mor sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods] 150c6dab2a8SThomas Monjalon 151c6dab2a8SThomas Monjalon for mod in mods: 152c6dab2a8SThomas Monjalon if mod["Name"] in sysfs_mods: 153c6dab2a8SThomas Monjalon mod["Found"] = True 154c6dab2a8SThomas Monjalon except: 155c6dab2a8SThomas Monjalon pass 156c6dab2a8SThomas Monjalon 157c6dab2a8SThomas Monjalon # check if we have at least one loaded module 158c6dab2a8SThomas Monjalon if True not in [mod["Found"] for mod in mods] and b_flag is not None: 159c6dab2a8SThomas Monjalon if b_flag in dpdk_drivers: 160c6dab2a8SThomas Monjalon print("Error - no supported modules(DPDK driver) are loaded") 161c6dab2a8SThomas Monjalon sys.exit(1) 162c6dab2a8SThomas Monjalon else: 163c6dab2a8SThomas Monjalon print("Warning - no supported modules(DPDK driver) are loaded") 164c6dab2a8SThomas Monjalon 165c6dab2a8SThomas Monjalon # change DPDK driver list to only contain drivers that are loaded 166c6dab2a8SThomas Monjalon dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] 167c6dab2a8SThomas Monjalon 168c6dab2a8SThomas Monjalon 169c6dab2a8SThomas Monjalondef has_driver(dev_id): 170c6dab2a8SThomas Monjalon '''return true if a device is assigned to a driver. False otherwise''' 171c6dab2a8SThomas Monjalon return "Driver_str" in devices[dev_id] 172c6dab2a8SThomas Monjalon 173c6dab2a8SThomas Monjalon 174c3ce205dSGuduri Prathyushadef get_pci_device_details(dev_id, probe_lspci): 175c6dab2a8SThomas Monjalon '''This function gets additional details for a PCI device''' 176c6dab2a8SThomas Monjalon device = {} 177c6dab2a8SThomas Monjalon 178c3ce205dSGuduri Prathyusha if probe_lspci: 179c6dab2a8SThomas Monjalon extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() 180c6dab2a8SThomas Monjalon 181c6dab2a8SThomas Monjalon # parse lspci details 182c6dab2a8SThomas Monjalon for line in extra_info: 183c6dab2a8SThomas Monjalon if len(line) == 0: 184c6dab2a8SThomas Monjalon continue 185c6dab2a8SThomas Monjalon name, value = line.decode().split("\t", 1) 186c6dab2a8SThomas Monjalon name = name.strip(":") + "_str" 187c6dab2a8SThomas Monjalon device[name] = value 188c6dab2a8SThomas Monjalon # check for a unix interface name 189c6dab2a8SThomas Monjalon device["Interface"] = "" 190c6dab2a8SThomas Monjalon for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id): 191c6dab2a8SThomas Monjalon if "net" in dirs: 192c6dab2a8SThomas Monjalon device["Interface"] = \ 193c6dab2a8SThomas Monjalon ",".join(os.listdir(os.path.join(base, "net"))) 194c6dab2a8SThomas Monjalon break 195c6dab2a8SThomas Monjalon # check if a port is used for ssh connection 196c6dab2a8SThomas Monjalon device["Ssh_if"] = False 197c6dab2a8SThomas Monjalon device["Active"] = "" 198c6dab2a8SThomas Monjalon 199c6dab2a8SThomas Monjalon return device 200c6dab2a8SThomas Monjalon 201ea9f00f7SGuduri Prathyushadef clear_data(): 202ea9f00f7SGuduri Prathyusha '''This function clears any old data''' 203ea9f00f7SGuduri Prathyusha devices = {} 204c6dab2a8SThomas Monjalon 205ea9f00f7SGuduri Prathyushadef get_device_details(devices_type): 206c6dab2a8SThomas Monjalon '''This function populates the "devices" dictionary. The keys used are 207c6dab2a8SThomas Monjalon the pci addresses (domain:bus:slot.func). The values are themselves 208c6dab2a8SThomas Monjalon dictionaries - one for each NIC.''' 209c6dab2a8SThomas Monjalon global devices 210c6dab2a8SThomas Monjalon global dpdk_drivers 211c6dab2a8SThomas Monjalon 212c6dab2a8SThomas Monjalon # first loop through and read details for all devices 213c3ce205dSGuduri Prathyusha # request machine readable format, with numeric IDs and String 214c6dab2a8SThomas Monjalon dev = {} 215c3ce205dSGuduri Prathyusha dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines() 216c6dab2a8SThomas Monjalon for dev_line in dev_lines: 217c6dab2a8SThomas Monjalon if len(dev_line) == 0: 2188ad08a28SGuduri Prathyusha if device_type_match(dev, devices_type): 2198ad08a28SGuduri Prathyusha # Replace "Driver" with "Driver_str" to have consistency of 2208ad08a28SGuduri Prathyusha # of dictionary key names 221c3ce205dSGuduri Prathyusha if "Driver" in dev.keys(): 222c3ce205dSGuduri Prathyusha dev["Driver_str"] = dev.pop("Driver") 223c76a10ecSAnatoly Burakov if "Module" in dev.keys(): 224c76a10ecSAnatoly Burakov dev["Module_str"] = dev.pop("Module") 225c6dab2a8SThomas Monjalon # use dict to make copy of dev 226c6dab2a8SThomas Monjalon devices[dev["Slot"]] = dict(dev) 227c3ce205dSGuduri Prathyusha # Clear previous device's data 228c3ce205dSGuduri Prathyusha dev = {} 229c6dab2a8SThomas Monjalon else: 230c6dab2a8SThomas Monjalon name, value = dev_line.decode().split("\t", 1) 231c3ce205dSGuduri Prathyusha value_list = value.rsplit(' ', 1) 232c3ce205dSGuduri Prathyusha if len(value_list) > 1: 233c3ce205dSGuduri Prathyusha # String stored in <name>_str 234c3ce205dSGuduri Prathyusha dev[name.rstrip(":") + '_str'] = value_list[0] 235c3ce205dSGuduri Prathyusha # Numeric IDs 236c3ce205dSGuduri Prathyusha dev[name.rstrip(":")] = value_list[len(value_list) - 1] \ 237c3ce205dSGuduri Prathyusha .rstrip("]").lstrip("[") 238c6dab2a8SThomas Monjalon 2398ad08a28SGuduri Prathyusha if devices_type == network_devices: 240c6dab2a8SThomas Monjalon # check what is the interface if any for an ssh connection if 241c6dab2a8SThomas Monjalon # any to this host, so we can mark it later. 242c6dab2a8SThomas Monjalon ssh_if = [] 243c6dab2a8SThomas Monjalon route = check_output(["ip", "-o", "route"]) 244c6dab2a8SThomas Monjalon # filter out all lines for 169.254 routes 245c6dab2a8SThomas Monjalon route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), 246c6dab2a8SThomas Monjalon route.decode().splitlines())) 247c6dab2a8SThomas Monjalon rt_info = route.split() 248c6dab2a8SThomas Monjalon for i in range(len(rt_info) - 1): 249c6dab2a8SThomas Monjalon if rt_info[i] == "dev": 250c6dab2a8SThomas Monjalon ssh_if.append(rt_info[i+1]) 251c6dab2a8SThomas Monjalon 252c6dab2a8SThomas Monjalon # based on the basic info, get extended text details 253c6dab2a8SThomas Monjalon for d in devices.keys(): 2548ad08a28SGuduri Prathyusha if not device_type_match(devices[d], devices_type): 255617d9052SYoni Gilad continue 256617d9052SYoni Gilad 257c6dab2a8SThomas Monjalon # get additional info and add it to existing data 258c6dab2a8SThomas Monjalon devices[d] = devices[d].copy() 259c3ce205dSGuduri Prathyusha # No need to probe lspci 260c3ce205dSGuduri Prathyusha devices[d].update(get_pci_device_details(d, False).items()) 261c6dab2a8SThomas Monjalon 2628ad08a28SGuduri Prathyusha if devices_type == network_devices: 263ea9f00f7SGuduri Prathyusha for _if in ssh_if: 264ea9f00f7SGuduri Prathyusha if _if in devices[d]["Interface"].split(","): 265ea9f00f7SGuduri Prathyusha devices[d]["Ssh_if"] = True 266ea9f00f7SGuduri Prathyusha devices[d]["Active"] = "*Active*" 267ea9f00f7SGuduri Prathyusha break 268ea9f00f7SGuduri Prathyusha 269c6dab2a8SThomas Monjalon # add igb_uio to list of supporting modules if needed 270c6dab2a8SThomas Monjalon if "Module_str" in devices[d]: 271c6dab2a8SThomas Monjalon for driver in dpdk_drivers: 272c6dab2a8SThomas Monjalon if driver not in devices[d]["Module_str"]: 273c6dab2a8SThomas Monjalon devices[d]["Module_str"] = \ 274c6dab2a8SThomas Monjalon devices[d]["Module_str"] + ",%s" % driver 275c6dab2a8SThomas Monjalon else: 276c6dab2a8SThomas Monjalon devices[d]["Module_str"] = ",".join(dpdk_drivers) 277c6dab2a8SThomas Monjalon 278c6dab2a8SThomas Monjalon # make sure the driver and module strings do not have any duplicates 279c6dab2a8SThomas Monjalon if has_driver(d): 280c6dab2a8SThomas Monjalon modules = devices[d]["Module_str"].split(",") 281c6dab2a8SThomas Monjalon if devices[d]["Driver_str"] in modules: 282c6dab2a8SThomas Monjalon modules.remove(devices[d]["Driver_str"]) 283c6dab2a8SThomas Monjalon devices[d]["Module_str"] = ",".join(modules) 284c6dab2a8SThomas Monjalon 285c6dab2a8SThomas Monjalon 2868ad08a28SGuduri Prathyushadef device_type_match(dev, devices_type): 2878ad08a28SGuduri Prathyusha for i in range(len(devices_type)): 2888ad08a28SGuduri Prathyusha param_count = len( 2898ad08a28SGuduri Prathyusha [x for x in devices_type[i].values() if x is not None]) 2908ad08a28SGuduri Prathyusha match_count = 0 2918ad08a28SGuduri Prathyusha if dev["Class"][0:2] == devices_type[i]["Class"]: 2928ad08a28SGuduri Prathyusha match_count = match_count + 1 2938ad08a28SGuduri Prathyusha for key in devices_type[i].keys(): 2948ad08a28SGuduri Prathyusha if key != 'Class' and devices_type[i][key]: 2958ad08a28SGuduri Prathyusha value_list = devices_type[i][key].split(',') 2968ad08a28SGuduri Prathyusha for value in value_list: 2978ad08a28SGuduri Prathyusha if value.strip(' ') == dev[key]: 2988ad08a28SGuduri Prathyusha match_count = match_count + 1 2998ad08a28SGuduri Prathyusha # count must be the number of non None parameters to match 3008ad08a28SGuduri Prathyusha if match_count == param_count: 3018ad08a28SGuduri Prathyusha return True 3028ad08a28SGuduri Prathyusha return False 3038ad08a28SGuduri Prathyusha 304c6dab2a8SThomas Monjalondef dev_id_from_dev_name(dev_name): 305c6dab2a8SThomas Monjalon '''Take a device "name" - a string passed in by user to identify a NIC 306c6dab2a8SThomas Monjalon device, and determine the device id - i.e. the domain:bus:slot.func - for 307c6dab2a8SThomas Monjalon it, which can then be used to index into the devices array''' 308c6dab2a8SThomas Monjalon 309c6dab2a8SThomas Monjalon # check if it's already a suitable index 310c6dab2a8SThomas Monjalon if dev_name in devices: 311c6dab2a8SThomas Monjalon return dev_name 312c6dab2a8SThomas Monjalon # check if it's an index just missing the domain part 313c6dab2a8SThomas Monjalon elif "0000:" + dev_name in devices: 314c6dab2a8SThomas Monjalon return "0000:" + dev_name 315c6dab2a8SThomas Monjalon else: 316c6dab2a8SThomas Monjalon # check if it's an interface name, e.g. eth1 317c6dab2a8SThomas Monjalon for d in devices.keys(): 318c6dab2a8SThomas Monjalon if dev_name in devices[d]["Interface"].split(","): 319c6dab2a8SThomas Monjalon return devices[d]["Slot"] 320c6dab2a8SThomas Monjalon # if nothing else matches - error 321c6dab2a8SThomas Monjalon print("Unknown device: %s. " 322c6dab2a8SThomas Monjalon "Please specify device in \"bus:slot.func\" format" % dev_name) 323c6dab2a8SThomas Monjalon sys.exit(1) 324c6dab2a8SThomas Monjalon 325c6dab2a8SThomas Monjalon 326c6dab2a8SThomas Monjalondef unbind_one(dev_id, force): 327c6dab2a8SThomas Monjalon '''Unbind the device identified by "dev_id" from its current driver''' 328c6dab2a8SThomas Monjalon dev = devices[dev_id] 329c6dab2a8SThomas Monjalon if not has_driver(dev_id): 330c6dab2a8SThomas Monjalon print("%s %s %s is not currently managed by any driver\n" % 331c6dab2a8SThomas Monjalon (dev["Slot"], dev["Device_str"], dev["Interface"])) 332c6dab2a8SThomas Monjalon return 333c6dab2a8SThomas Monjalon 334c6dab2a8SThomas Monjalon # prevent us disconnecting ourselves 335c6dab2a8SThomas Monjalon if dev["Ssh_if"] and not force: 336c6dab2a8SThomas Monjalon print("Routing table indicates that interface %s is active. " 337c6dab2a8SThomas Monjalon "Skipping unbind" % (dev_id)) 338c6dab2a8SThomas Monjalon return 339c6dab2a8SThomas Monjalon 340c6dab2a8SThomas Monjalon # write to /sys to unbind 341c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] 342c6dab2a8SThomas Monjalon try: 343c6dab2a8SThomas Monjalon f = open(filename, "a") 344c6dab2a8SThomas Monjalon except: 345c6dab2a8SThomas Monjalon print("Error: unbind failed for %s - Cannot open %s" 346c6dab2a8SThomas Monjalon % (dev_id, filename)) 347c6dab2a8SThomas Monjalon sys.exit(1) 348c6dab2a8SThomas Monjalon f.write(dev_id) 349c6dab2a8SThomas Monjalon f.close() 350c6dab2a8SThomas Monjalon 351c6dab2a8SThomas Monjalon 352c6dab2a8SThomas Monjalondef bind_one(dev_id, driver, force): 353c6dab2a8SThomas Monjalon '''Bind the device given by "dev_id" to the driver "driver". If the device 354c6dab2a8SThomas Monjalon is already bound to a different driver, it will be unbound first''' 355c6dab2a8SThomas Monjalon dev = devices[dev_id] 356c6dab2a8SThomas Monjalon saved_driver = None # used to rollback any unbind in case of failure 357c6dab2a8SThomas Monjalon 358c6dab2a8SThomas Monjalon # prevent disconnection of our ssh session 359c6dab2a8SThomas Monjalon if dev["Ssh_if"] and not force: 360c6dab2a8SThomas Monjalon print("Routing table indicates that interface %s is active. " 361c6dab2a8SThomas Monjalon "Not modifying" % (dev_id)) 362c6dab2a8SThomas Monjalon return 363c6dab2a8SThomas Monjalon 364c6dab2a8SThomas Monjalon # unbind any existing drivers we don't want 365c6dab2a8SThomas Monjalon if has_driver(dev_id): 366c6dab2a8SThomas Monjalon if dev["Driver_str"] == driver: 367c6dab2a8SThomas Monjalon print("%s already bound to driver %s, skipping\n" 368c6dab2a8SThomas Monjalon % (dev_id, driver)) 369c6dab2a8SThomas Monjalon return 370c6dab2a8SThomas Monjalon else: 371c6dab2a8SThomas Monjalon saved_driver = dev["Driver_str"] 372c6dab2a8SThomas Monjalon unbind_one(dev_id, force) 373c6dab2a8SThomas Monjalon dev["Driver_str"] = "" # clear driver string 374c6dab2a8SThomas Monjalon 3752fc35029SGuduri Prathyusha # For kernels >= 3.15 driver_override can be used to specify the driver 3762fc35029SGuduri Prathyusha # for a device rather than relying on the driver to provide a positive 3772fc35029SGuduri Prathyusha # match of the device. The existing process of looking up 3782fc35029SGuduri Prathyusha # the vendor and device ID, adding them to the driver new_id, 3792fc35029SGuduri Prathyusha # will erroneously bind other devices too which has the additional burden 3802fc35029SGuduri Prathyusha # of unbinding those devices 381c6dab2a8SThomas Monjalon if driver in dpdk_drivers: 3822fc35029SGuduri Prathyusha filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 3832fc35029SGuduri Prathyusha if os.path.exists(filename): 3842fc35029SGuduri Prathyusha try: 3852fc35029SGuduri Prathyusha f = open(filename, "w") 3862fc35029SGuduri Prathyusha except: 3872fc35029SGuduri Prathyusha print("Error: bind failed for %s - Cannot open %s" 3882fc35029SGuduri Prathyusha % (dev_id, filename)) 3892fc35029SGuduri Prathyusha return 3902fc35029SGuduri Prathyusha try: 3912fc35029SGuduri Prathyusha f.write("%s" % driver) 3922fc35029SGuduri Prathyusha f.close() 3932fc35029SGuduri Prathyusha except: 3942fc35029SGuduri Prathyusha print("Error: bind failed for %s - Cannot write driver %s to " 3952fc35029SGuduri Prathyusha "PCI ID " % (dev_id, driver)) 3962fc35029SGuduri Prathyusha return 3972fc35029SGuduri Prathyusha # For kernels < 3.15 use new_id to add PCI id's to the driver 3982fc35029SGuduri Prathyusha else: 399c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/new_id" % driver 400c6dab2a8SThomas Monjalon try: 401c6dab2a8SThomas Monjalon f = open(filename, "w") 402c6dab2a8SThomas Monjalon except: 403c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot open %s" 404c6dab2a8SThomas Monjalon % (dev_id, filename)) 405c6dab2a8SThomas Monjalon return 406c6dab2a8SThomas Monjalon try: 4078ad08a28SGuduri Prathyusha # Convert Device and Vendor Id to int to write to new_id 4088ad08a28SGuduri Prathyusha f.write("%04x %04x" % (int(dev["Vendor"],16), 4098ad08a28SGuduri Prathyusha int(dev["Device"], 16))) 410c6dab2a8SThomas Monjalon f.close() 411c6dab2a8SThomas Monjalon except: 412c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot write new PCI ID to " 413c6dab2a8SThomas Monjalon "driver %s" % (dev_id, driver)) 414c6dab2a8SThomas Monjalon return 415c6dab2a8SThomas Monjalon 416c6dab2a8SThomas Monjalon # do the bind by writing to /sys 417c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/bind" % driver 418c6dab2a8SThomas Monjalon try: 419c6dab2a8SThomas Monjalon f = open(filename, "a") 420c6dab2a8SThomas Monjalon except: 421c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot open %s" 422c6dab2a8SThomas Monjalon % (dev_id, filename)) 423c6dab2a8SThomas Monjalon if saved_driver is not None: # restore any previous driver 424c6dab2a8SThomas Monjalon bind_one(dev_id, saved_driver, force) 425c6dab2a8SThomas Monjalon return 426c6dab2a8SThomas Monjalon try: 427c6dab2a8SThomas Monjalon f.write(dev_id) 428c6dab2a8SThomas Monjalon f.close() 429c6dab2a8SThomas Monjalon except: 430c6dab2a8SThomas Monjalon # for some reason, closing dev_id after adding a new PCI ID to new_id 431c6dab2a8SThomas Monjalon # results in IOError. however, if the device was successfully bound, 432c6dab2a8SThomas Monjalon # we don't care for any errors and can safely ignore IOError 433c3ce205dSGuduri Prathyusha tmp = get_pci_device_details(dev_id, True) 434c6dab2a8SThomas Monjalon if "Driver_str" in tmp and tmp["Driver_str"] == driver: 435c6dab2a8SThomas Monjalon return 436c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot bind to driver %s" 437c6dab2a8SThomas Monjalon % (dev_id, driver)) 438c6dab2a8SThomas Monjalon if saved_driver is not None: # restore any previous driver 439c6dab2a8SThomas Monjalon bind_one(dev_id, saved_driver, force) 440c6dab2a8SThomas Monjalon return 441c6dab2a8SThomas Monjalon 442720b7a05SGuduri Prathyusha # For kernels > 3.15 driver_override is used to bind a device to a driver. 443720b7a05SGuduri Prathyusha # Before unbinding it, overwrite driver_override with empty string so that 444720b7a05SGuduri Prathyusha # the device can be bound to any other driver 445720b7a05SGuduri Prathyusha filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id 446720b7a05SGuduri Prathyusha if os.path.exists(filename): 447720b7a05SGuduri Prathyusha try: 448720b7a05SGuduri Prathyusha f = open(filename, "w") 449720b7a05SGuduri Prathyusha except: 450720b7a05SGuduri Prathyusha print("Error: unbind failed for %s - Cannot open %s" 451720b7a05SGuduri Prathyusha % (dev_id, filename)) 452720b7a05SGuduri Prathyusha sys.exit(1) 453720b7a05SGuduri Prathyusha try: 454720b7a05SGuduri Prathyusha f.write("\00") 455720b7a05SGuduri Prathyusha f.close() 456720b7a05SGuduri Prathyusha except: 457720b7a05SGuduri Prathyusha print("Error: unbind failed for %s - Cannot open %s" 458720b7a05SGuduri Prathyusha % (dev_id, filename)) 459720b7a05SGuduri Prathyusha sys.exit(1) 460720b7a05SGuduri Prathyusha 461c6dab2a8SThomas Monjalon 462c6dab2a8SThomas Monjalondef unbind_all(dev_list, force=False): 463c6dab2a8SThomas Monjalon """Unbind method, takes a list of device locations""" 464657c7133SFerruh Yigit 465657c7133SFerruh Yigit if dev_list[0] == "dpdk": 466657c7133SFerruh Yigit for d in devices.keys(): 467657c7133SFerruh Yigit if "Driver_str" in devices[d]: 468657c7133SFerruh Yigit if devices[d]["Driver_str"] in dpdk_drivers: 469657c7133SFerruh Yigit unbind_one(devices[d]["Slot"], force) 470657c7133SFerruh Yigit return 471657c7133SFerruh Yigit 472c6dab2a8SThomas Monjalon dev_list = map(dev_id_from_dev_name, dev_list) 473c6dab2a8SThomas Monjalon for d in dev_list: 474c6dab2a8SThomas Monjalon unbind_one(d, force) 475c6dab2a8SThomas Monjalon 476c6dab2a8SThomas Monjalon 477c6dab2a8SThomas Monjalondef bind_all(dev_list, driver, force=False): 478c6dab2a8SThomas Monjalon """Bind method, takes a list of device locations""" 479c6dab2a8SThomas Monjalon global devices 480c6dab2a8SThomas Monjalon 481c6dab2a8SThomas Monjalon dev_list = map(dev_id_from_dev_name, dev_list) 482c6dab2a8SThomas Monjalon 483c6dab2a8SThomas Monjalon for d in dev_list: 484c6dab2a8SThomas Monjalon bind_one(d, driver, force) 485c6dab2a8SThomas Monjalon 486e4839614SPavel Shirshov # For kernels < 3.15 when binding devices to a generic driver 4872fc35029SGuduri Prathyusha # (i.e. one that doesn't have a PCI ID table) using new_id, some devices 4882fc35029SGuduri Prathyusha # that are not bound to any other driver could be bound even if no one has 4892fc35029SGuduri Prathyusha # asked them to. hence, we check the list of drivers again, and see if 4902fc35029SGuduri Prathyusha # some of the previously-unbound devices were erroneously bound. 4912fc35029SGuduri Prathyusha if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d): 492c6dab2a8SThomas Monjalon for d in devices.keys(): 493c6dab2a8SThomas Monjalon # skip devices that were already bound or that we know should be bound 494c6dab2a8SThomas Monjalon if "Driver_str" in devices[d] or d in dev_list: 495c6dab2a8SThomas Monjalon continue 496c6dab2a8SThomas Monjalon 497c6dab2a8SThomas Monjalon # update information about this device 498c6dab2a8SThomas Monjalon devices[d] = dict(devices[d].items() + 499c3ce205dSGuduri Prathyusha get_pci_device_details(d, True).items()) 500c6dab2a8SThomas Monjalon 501c6dab2a8SThomas Monjalon # check if updated information indicates that the device was bound 502c6dab2a8SThomas Monjalon if "Driver_str" in devices[d]: 503c6dab2a8SThomas Monjalon unbind_one(d, force) 504c6dab2a8SThomas Monjalon 505c6dab2a8SThomas Monjalon 506c6dab2a8SThomas Monjalondef display_devices(title, dev_list, extra_params=None): 507c6dab2a8SThomas Monjalon '''Displays to the user the details of a list of devices given in 508c6dab2a8SThomas Monjalon "dev_list". The "extra_params" parameter, if given, should contain a string 509c6dab2a8SThomas Monjalon with %()s fields in it for replacement by the named fields in each 510c6dab2a8SThomas Monjalon device's dictionary.''' 511c6dab2a8SThomas Monjalon strings = [] # this holds the strings to print. We sort before printing 512c6dab2a8SThomas Monjalon print("\n%s" % title) 513c6dab2a8SThomas Monjalon print("="*len(title)) 514c6dab2a8SThomas Monjalon if len(dev_list) == 0: 515c6dab2a8SThomas Monjalon strings.append("<none>") 516c6dab2a8SThomas Monjalon else: 517c6dab2a8SThomas Monjalon for dev in dev_list: 518c6dab2a8SThomas Monjalon if extra_params is not None: 519c3ce205dSGuduri Prathyusha strings.append("%s '%s %s' %s" % (dev["Slot"], 520c6dab2a8SThomas Monjalon dev["Device_str"], 521c3ce205dSGuduri Prathyusha dev["Device"], 522c6dab2a8SThomas Monjalon extra_params % dev)) 523c6dab2a8SThomas Monjalon else: 524c6dab2a8SThomas Monjalon strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) 525c6dab2a8SThomas Monjalon # sort before printing, so that the entries appear in PCI order 526c6dab2a8SThomas Monjalon strings.sort() 527c6dab2a8SThomas Monjalon print("\n".join(strings)) # print one per line 528c6dab2a8SThomas Monjalon 529c7dd412bSGuduri Prathyushadef show_device_status(devices_type, device_name): 530c6dab2a8SThomas Monjalon global dpdk_drivers 531c6dab2a8SThomas Monjalon kernel_drv = [] 532c6dab2a8SThomas Monjalon dpdk_drv = [] 533c6dab2a8SThomas Monjalon no_drv = [] 534c6dab2a8SThomas Monjalon 535c6dab2a8SThomas Monjalon # split our list of network devices into the three categories above 536c6dab2a8SThomas Monjalon for d in devices.keys(): 5378ad08a28SGuduri Prathyusha if device_type_match(devices[d], devices_type): 538c6dab2a8SThomas Monjalon if not has_driver(d): 539c6dab2a8SThomas Monjalon no_drv.append(devices[d]) 540c6dab2a8SThomas Monjalon continue 541c6dab2a8SThomas Monjalon if devices[d]["Driver_str"] in dpdk_drivers: 542c6dab2a8SThomas Monjalon dpdk_drv.append(devices[d]) 543c6dab2a8SThomas Monjalon else: 544c6dab2a8SThomas Monjalon kernel_drv.append(devices[d]) 545c6dab2a8SThomas Monjalon 546c6dab2a8SThomas Monjalon # print each category separately, so we can clearly see what's used by DPDK 5478ad08a28SGuduri Prathyusha display_devices("%s devices using DPDK-compatible driver" % device_name, 5488ad08a28SGuduri Prathyusha dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s") 549c7dd412bSGuduri Prathyusha display_devices("%s devices using kernel driver" % device_name, kernel_drv, 550c6dab2a8SThomas Monjalon "if=%(Interface)s drv=%(Driver_str)s " 551c6dab2a8SThomas Monjalon "unused=%(Module_str)s %(Active)s") 5528ad08a28SGuduri Prathyusha display_devices("Other %s devices" % device_name, no_drv, 5538ad08a28SGuduri Prathyusha "unused=%(Module_str)s") 554c6dab2a8SThomas Monjalon 555c7dd412bSGuduri Prathyushadef show_status(): 556c7dd412bSGuduri Prathyusha '''Function called when the script is passed the "--status" option. 557c7dd412bSGuduri Prathyusha Displays to the user what devices are bound to the igb_uio driver, the 558c7dd412bSGuduri Prathyusha kernel driver or to no driver''' 559c6dab2a8SThomas Monjalon 560b153c00bSFerruh Yigit if status_dev == "net" or status_dev == "all": 561c7dd412bSGuduri Prathyusha show_device_status(network_devices, "Network") 562b153c00bSFerruh Yigit 563b153c00bSFerruh Yigit if status_dev == "crypto" or status_dev == "all": 564c7dd412bSGuduri Prathyusha show_device_status(crypto_devices, "Crypto") 565b153c00bSFerruh Yigit 566b153c00bSFerruh Yigit if status_dev == "event" or status_dev == "all": 56732a02dbfSGuduri Prathyusha show_device_status(eventdev_devices, "Eventdev") 568b153c00bSFerruh Yigit 569b153c00bSFerruh Yigit if status_dev == "mempool" or status_dev == "all": 57080a1858dSGuduri Prathyusha show_device_status(mempool_devices, "Mempool") 571c6dab2a8SThomas Monjalon 572c6dab2a8SThomas Monjalondef parse_args(): 573c6dab2a8SThomas Monjalon '''Parses the command-line arguments given by the user and takes the 574c6dab2a8SThomas Monjalon appropriate action for each''' 575c6dab2a8SThomas Monjalon global b_flag 576c6dab2a8SThomas Monjalon global status_flag 577b153c00bSFerruh Yigit global status_dev 578c6dab2a8SThomas Monjalon global force_flag 579c6dab2a8SThomas Monjalon global args 580c6dab2a8SThomas Monjalon if len(sys.argv) <= 1: 581c6dab2a8SThomas Monjalon usage() 582c6dab2a8SThomas Monjalon sys.exit(0) 583c6dab2a8SThomas Monjalon 584c6dab2a8SThomas Monjalon try: 585c6dab2a8SThomas Monjalon opts, args = getopt.getopt(sys.argv[1:], "b:us", 586b153c00bSFerruh Yigit ["help", "usage", "status", "status-dev=", 587b153c00bSFerruh Yigit "force", "bind=", "unbind", ]) 588c6dab2a8SThomas Monjalon except getopt.GetoptError as error: 589c6dab2a8SThomas Monjalon print(str(error)) 590c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 591c6dab2a8SThomas Monjalon sys.exit(1) 592c6dab2a8SThomas Monjalon 593c6dab2a8SThomas Monjalon for opt, arg in opts: 594c6dab2a8SThomas Monjalon if opt == "--help" or opt == "--usage": 595c6dab2a8SThomas Monjalon usage() 596c6dab2a8SThomas Monjalon sys.exit(0) 597b153c00bSFerruh Yigit if opt == "--status-dev": 598b153c00bSFerruh Yigit status_flag = True 599b153c00bSFerruh Yigit status_dev = arg 600c6dab2a8SThomas Monjalon if opt == "--status" or opt == "-s": 601c6dab2a8SThomas Monjalon status_flag = True 602b153c00bSFerruh Yigit status_dev = "all" 603c6dab2a8SThomas Monjalon if opt == "--force": 604c6dab2a8SThomas Monjalon force_flag = True 605c6dab2a8SThomas Monjalon if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": 606c6dab2a8SThomas Monjalon if b_flag is not None: 607c6dab2a8SThomas Monjalon print("Error - Only one bind or unbind may be specified\n") 608c6dab2a8SThomas Monjalon sys.exit(1) 609c6dab2a8SThomas Monjalon if opt == "-u" or opt == "--unbind": 610c6dab2a8SThomas Monjalon b_flag = "none" 611c6dab2a8SThomas Monjalon else: 612c6dab2a8SThomas Monjalon b_flag = arg 613c6dab2a8SThomas Monjalon 614c6dab2a8SThomas Monjalon 615c6dab2a8SThomas Monjalondef do_arg_actions(): 616c6dab2a8SThomas Monjalon '''do the actual action requested by the user''' 617c6dab2a8SThomas Monjalon global b_flag 618c6dab2a8SThomas Monjalon global status_flag 619c6dab2a8SThomas Monjalon global force_flag 620c6dab2a8SThomas Monjalon global args 621c6dab2a8SThomas Monjalon 622c6dab2a8SThomas Monjalon if b_flag is None and not status_flag: 623c6dab2a8SThomas Monjalon print("Error: No action specified for devices." 624c6dab2a8SThomas Monjalon "Please give a -b or -u option") 625c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 626c6dab2a8SThomas Monjalon sys.exit(1) 627c6dab2a8SThomas Monjalon 628c6dab2a8SThomas Monjalon if b_flag is not None and len(args) == 0: 629c6dab2a8SThomas Monjalon print("Error: No devices specified.") 630c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 631c6dab2a8SThomas Monjalon sys.exit(1) 632c6dab2a8SThomas Monjalon 633c6dab2a8SThomas Monjalon if b_flag == "none" or b_flag == "None": 634c6dab2a8SThomas Monjalon unbind_all(args, force_flag) 635c6dab2a8SThomas Monjalon elif b_flag is not None: 636c6dab2a8SThomas Monjalon bind_all(args, b_flag, force_flag) 637c6dab2a8SThomas Monjalon if status_flag: 638c6dab2a8SThomas Monjalon if b_flag is not None: 639ea9f00f7SGuduri Prathyusha clear_data() 6408ad08a28SGuduri Prathyusha # refresh if we have changed anything 6418ad08a28SGuduri Prathyusha get_device_details(network_devices) 6428ad08a28SGuduri Prathyusha get_device_details(crypto_devices) 64332a02dbfSGuduri Prathyusha get_device_details(eventdev_devices) 64480a1858dSGuduri Prathyusha get_device_details(mempool_devices) 645c6dab2a8SThomas Monjalon show_status() 646c6dab2a8SThomas Monjalon 647c6dab2a8SThomas Monjalon 648c6dab2a8SThomas Monjalondef main(): 649c6dab2a8SThomas Monjalon '''program main function''' 650c6dab2a8SThomas Monjalon parse_args() 651c6dab2a8SThomas Monjalon check_modules() 652ea9f00f7SGuduri Prathyusha clear_data() 6538ad08a28SGuduri Prathyusha get_device_details(network_devices) 6548ad08a28SGuduri Prathyusha get_device_details(crypto_devices) 65532a02dbfSGuduri Prathyusha get_device_details(eventdev_devices) 65680a1858dSGuduri Prathyusha get_device_details(mempool_devices) 657c6dab2a8SThomas Monjalon do_arg_actions() 658c6dab2a8SThomas Monjalon 659c6dab2a8SThomas Monjalonif __name__ == "__main__": 660c6dab2a8SThomas Monjalon main() 661