1c6dab2a8SThomas Monjalon#! /usr/bin/env python 2c6dab2a8SThomas Monjalon# 3c6dab2a8SThomas Monjalon# BSD LICENSE 4c6dab2a8SThomas Monjalon# 5c6dab2a8SThomas Monjalon# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 6c6dab2a8SThomas Monjalon# All rights reserved. 7c6dab2a8SThomas Monjalon# 8c6dab2a8SThomas Monjalon# Redistribution and use in source and binary forms, with or without 9c6dab2a8SThomas Monjalon# modification, are permitted provided that the following conditions 10c6dab2a8SThomas Monjalon# are met: 11c6dab2a8SThomas Monjalon# 12c6dab2a8SThomas Monjalon# * Redistributions of source code must retain the above copyright 13c6dab2a8SThomas Monjalon# notice, this list of conditions and the following disclaimer. 14c6dab2a8SThomas Monjalon# * Redistributions in binary form must reproduce the above copyright 15c6dab2a8SThomas Monjalon# notice, this list of conditions and the following disclaimer in 16c6dab2a8SThomas Monjalon# the documentation and/or other materials provided with the 17c6dab2a8SThomas Monjalon# distribution. 18c6dab2a8SThomas Monjalon# * Neither the name of Intel Corporation nor the names of its 19c6dab2a8SThomas Monjalon# contributors may be used to endorse or promote products derived 20c6dab2a8SThomas Monjalon# from this software without specific prior written permission. 21c6dab2a8SThomas Monjalon# 22c6dab2a8SThomas Monjalon# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23c6dab2a8SThomas Monjalon# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24c6dab2a8SThomas Monjalon# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25c6dab2a8SThomas Monjalon# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26c6dab2a8SThomas Monjalon# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27c6dab2a8SThomas Monjalon# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28c6dab2a8SThomas Monjalon# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29c6dab2a8SThomas Monjalon# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30c6dab2a8SThomas Monjalon# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31c6dab2a8SThomas Monjalon# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32c6dab2a8SThomas Monjalon# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33c6dab2a8SThomas Monjalon# 34c6dab2a8SThomas Monjalon 35c6dab2a8SThomas Monjalonimport sys 36c6dab2a8SThomas Monjalonimport os 37c6dab2a8SThomas Monjalonimport getopt 38c6dab2a8SThomas Monjalonimport subprocess 39c6dab2a8SThomas Monjalonfrom os.path import exists, abspath, dirname, basename 40c6dab2a8SThomas Monjalon 41c6dab2a8SThomas Monjalon# The PCI base class for NETWORK devices 42c6dab2a8SThomas MonjalonNETWORK_BASE_CLASS = "02" 43c6dab2a8SThomas MonjalonCRYPTO_BASE_CLASS = "0b" 44c6dab2a8SThomas Monjalon 45c6dab2a8SThomas Monjalon# global dict ethernet devices present. Dictionary indexed by PCI address. 46c6dab2a8SThomas Monjalon# Each device within this is itself a dictionary of device properties 47c6dab2a8SThomas Monjalondevices = {} 48c6dab2a8SThomas Monjalon# list of supported DPDK drivers 49c6dab2a8SThomas Monjalondpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] 50c6dab2a8SThomas Monjalon 51c6dab2a8SThomas Monjalon# command-line arg flags 52c6dab2a8SThomas Monjalonb_flag = None 53c6dab2a8SThomas Monjalonstatus_flag = False 54c6dab2a8SThomas Monjalonforce_flag = False 55c6dab2a8SThomas Monjalonargs = [] 56c6dab2a8SThomas Monjalon 57c6dab2a8SThomas Monjalon 58c6dab2a8SThomas Monjalondef usage(): 59c6dab2a8SThomas Monjalon '''Print usage information for the program''' 60c6dab2a8SThomas Monjalon argv0 = basename(sys.argv[0]) 61c6dab2a8SThomas Monjalon print(""" 62c6dab2a8SThomas MonjalonUsage: 63c6dab2a8SThomas Monjalon------ 64c6dab2a8SThomas Monjalon 65c6dab2a8SThomas Monjalon %(argv0)s [options] DEVICE1 DEVICE2 .... 66c6dab2a8SThomas Monjalon 67c6dab2a8SThomas Monjalonwhere DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax 68c6dab2a8SThomas Monjalonor "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may 69c6dab2a8SThomas Monjalonalso be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. 70c6dab2a8SThomas Monjalon 71c6dab2a8SThomas MonjalonOptions: 72c6dab2a8SThomas Monjalon --help, --usage: 73c6dab2a8SThomas Monjalon Display usage information and quit 74c6dab2a8SThomas Monjalon 75c6dab2a8SThomas Monjalon -s, --status: 76c6dab2a8SThomas Monjalon Print the current status of all known network and crypto devices. 77c6dab2a8SThomas Monjalon For each device, it displays the PCI domain, bus, slot and function, 78c6dab2a8SThomas Monjalon along with a text description of the device. Depending upon whether the 79c6dab2a8SThomas Monjalon device is being used by a kernel driver, the igb_uio driver, or no 80c6dab2a8SThomas Monjalon driver, other relevant information will be displayed: 81c6dab2a8SThomas Monjalon * the Linux interface name e.g. if=eth0 82c6dab2a8SThomas Monjalon * the driver being used e.g. drv=igb_uio 83c6dab2a8SThomas Monjalon * any suitable drivers not currently using that device 84c6dab2a8SThomas Monjalon e.g. unused=igb_uio 85c6dab2a8SThomas Monjalon NOTE: if this flag is passed along with a bind/unbind option, the 86c6dab2a8SThomas Monjalon status display will always occur after the other operations have taken 87c6dab2a8SThomas Monjalon place. 88c6dab2a8SThomas Monjalon 89c6dab2a8SThomas Monjalon -b driver, --bind=driver: 90c6dab2a8SThomas Monjalon Select the driver to use or \"none\" to unbind the device 91c6dab2a8SThomas Monjalon 92c6dab2a8SThomas Monjalon -u, --unbind: 93c6dab2a8SThomas Monjalon Unbind a device (Equivalent to \"-b none\") 94c6dab2a8SThomas Monjalon 95c6dab2a8SThomas Monjalon --force: 96c6dab2a8SThomas Monjalon By default, network devices which are used by Linux - as indicated by 97c6dab2a8SThomas Monjalon having routes in the routing table - cannot be modified. Using the 98c6dab2a8SThomas Monjalon --force flag overrides this behavior, allowing active links to be 99c6dab2a8SThomas Monjalon forcibly unbound. 100c6dab2a8SThomas Monjalon WARNING: This can lead to loss of network connection and should be used 101c6dab2a8SThomas Monjalon with caution. 102c6dab2a8SThomas Monjalon 103c6dab2a8SThomas MonjalonExamples: 104c6dab2a8SThomas Monjalon--------- 105c6dab2a8SThomas Monjalon 106c6dab2a8SThomas MonjalonTo display current device status: 107c6dab2a8SThomas Monjalon %(argv0)s --status 108c6dab2a8SThomas Monjalon 109c6dab2a8SThomas MonjalonTo bind eth1 from the current driver and move to use igb_uio 110c6dab2a8SThomas Monjalon %(argv0)s --bind=igb_uio eth1 111c6dab2a8SThomas Monjalon 112c6dab2a8SThomas MonjalonTo unbind 0000:01:00.0 from using any driver 113c6dab2a8SThomas Monjalon %(argv0)s -u 0000:01:00.0 114c6dab2a8SThomas Monjalon 115c6dab2a8SThomas MonjalonTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver 116c6dab2a8SThomas Monjalon %(argv0)s -b ixgbe 02:00.0 02:00.1 117c6dab2a8SThomas Monjalon 118c6dab2a8SThomas Monjalon """ % locals()) # replace items from local variables 119c6dab2a8SThomas Monjalon 120c6dab2a8SThomas Monjalon 121c6dab2a8SThomas Monjalon# This is roughly compatible with check_output function in subprocess module 122c6dab2a8SThomas Monjalon# which is only available in python 2.7. 123c6dab2a8SThomas Monjalondef check_output(args, stderr=None): 124c6dab2a8SThomas Monjalon '''Run a command and capture its output''' 125c6dab2a8SThomas Monjalon return subprocess.Popen(args, stdout=subprocess.PIPE, 126c6dab2a8SThomas Monjalon stderr=stderr).communicate()[0] 127c6dab2a8SThomas Monjalon 128c6dab2a8SThomas Monjalon 129c6dab2a8SThomas Monjalondef find_module(mod): 130c6dab2a8SThomas Monjalon '''find the .ko file for kernel module named mod. 131c6dab2a8SThomas Monjalon Searches the $RTE_SDK/$RTE_TARGET directory, the kernel 132c6dab2a8SThomas Monjalon modules directory and finally under the parent directory of 133c6dab2a8SThomas Monjalon the script ''' 134c6dab2a8SThomas Monjalon # check $RTE_SDK/$RTE_TARGET directory 135c6dab2a8SThomas Monjalon if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ: 136c6dab2a8SThomas Monjalon path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'], 137c6dab2a8SThomas Monjalon os.environ['RTE_TARGET'], mod) 138c6dab2a8SThomas Monjalon if exists(path): 139c6dab2a8SThomas Monjalon return path 140c6dab2a8SThomas Monjalon 141c6dab2a8SThomas Monjalon # check using depmod 142c6dab2a8SThomas Monjalon try: 143c6dab2a8SThomas Monjalon depmod_out = check_output(["modinfo", "-n", mod], 144c6dab2a8SThomas Monjalon stderr=subprocess.STDOUT).lower() 145c6dab2a8SThomas Monjalon if "error" not in depmod_out: 146c6dab2a8SThomas Monjalon path = depmod_out.strip() 147c6dab2a8SThomas Monjalon if exists(path): 148c6dab2a8SThomas Monjalon return path 149c6dab2a8SThomas Monjalon except: # if modinfo can't find module, it fails, so continue 150c6dab2a8SThomas Monjalon pass 151c6dab2a8SThomas Monjalon 152c6dab2a8SThomas Monjalon # check for a copy based off current path 153c6dab2a8SThomas Monjalon tools_dir = dirname(abspath(sys.argv[0])) 154c6dab2a8SThomas Monjalon if tools_dir.endswith("tools"): 155c6dab2a8SThomas Monjalon base_dir = dirname(tools_dir) 156c6dab2a8SThomas Monjalon find_out = check_output(["find", base_dir, "-name", mod + ".ko"]) 157c6dab2a8SThomas Monjalon if len(find_out) > 0: # something matched 158c6dab2a8SThomas Monjalon path = find_out.splitlines()[0] 159c6dab2a8SThomas Monjalon if exists(path): 160c6dab2a8SThomas Monjalon return path 161c6dab2a8SThomas Monjalon 162c6dab2a8SThomas Monjalon 163c6dab2a8SThomas Monjalondef check_modules(): 164c6dab2a8SThomas Monjalon '''Checks that igb_uio is loaded''' 165c6dab2a8SThomas Monjalon global dpdk_drivers 166c6dab2a8SThomas Monjalon 167c6dab2a8SThomas Monjalon # list of supported modules 168c6dab2a8SThomas Monjalon mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] 169c6dab2a8SThomas Monjalon 170c6dab2a8SThomas Monjalon # first check if module is loaded 171c6dab2a8SThomas Monjalon try: 172c6dab2a8SThomas Monjalon # Get list of sysfs modules (both built-in and dynamically loaded) 173c6dab2a8SThomas Monjalon sysfs_path = '/sys/module/' 174c6dab2a8SThomas Monjalon 175c6dab2a8SThomas Monjalon # Get the list of directories in sysfs_path 176c6dab2a8SThomas Monjalon sysfs_mods = [os.path.join(sysfs_path, o) for o 177c6dab2a8SThomas Monjalon in os.listdir(sysfs_path) 178c6dab2a8SThomas Monjalon if os.path.isdir(os.path.join(sysfs_path, o))] 179c6dab2a8SThomas Monjalon 180c6dab2a8SThomas Monjalon # Extract the last element of '/sys/module/abc' in the array 181c6dab2a8SThomas Monjalon sysfs_mods = [a.split('/')[-1] for a in sysfs_mods] 182c6dab2a8SThomas Monjalon 183c6dab2a8SThomas Monjalon # special case for vfio_pci (module is named vfio-pci, 184c6dab2a8SThomas Monjalon # but its .ko is named vfio_pci) 185c6dab2a8SThomas Monjalon sysfs_mods = map(lambda a: 186c6dab2a8SThomas Monjalon a if a != 'vfio_pci' else 'vfio-pci', sysfs_mods) 187c6dab2a8SThomas Monjalon 188c6dab2a8SThomas Monjalon for mod in mods: 189c6dab2a8SThomas Monjalon if mod["Name"] in sysfs_mods: 190c6dab2a8SThomas Monjalon mod["Found"] = True 191c6dab2a8SThomas Monjalon except: 192c6dab2a8SThomas Monjalon pass 193c6dab2a8SThomas Monjalon 194c6dab2a8SThomas Monjalon # check if we have at least one loaded module 195c6dab2a8SThomas Monjalon if True not in [mod["Found"] for mod in mods] and b_flag is not None: 196c6dab2a8SThomas Monjalon if b_flag in dpdk_drivers: 197c6dab2a8SThomas Monjalon print("Error - no supported modules(DPDK driver) are loaded") 198c6dab2a8SThomas Monjalon sys.exit(1) 199c6dab2a8SThomas Monjalon else: 200c6dab2a8SThomas Monjalon print("Warning - no supported modules(DPDK driver) are loaded") 201c6dab2a8SThomas Monjalon 202c6dab2a8SThomas Monjalon # change DPDK driver list to only contain drivers that are loaded 203c6dab2a8SThomas Monjalon dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] 204c6dab2a8SThomas Monjalon 205c6dab2a8SThomas Monjalon 206c6dab2a8SThomas Monjalondef has_driver(dev_id): 207c6dab2a8SThomas Monjalon '''return true if a device is assigned to a driver. False otherwise''' 208c6dab2a8SThomas Monjalon return "Driver_str" in devices[dev_id] 209c6dab2a8SThomas Monjalon 210c6dab2a8SThomas Monjalon 211*c3ce205dSGuduri Prathyushadef get_pci_device_details(dev_id, probe_lspci): 212c6dab2a8SThomas Monjalon '''This function gets additional details for a PCI device''' 213c6dab2a8SThomas Monjalon device = {} 214c6dab2a8SThomas Monjalon 215*c3ce205dSGuduri Prathyusha if probe_lspci: 216c6dab2a8SThomas Monjalon extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() 217c6dab2a8SThomas Monjalon 218c6dab2a8SThomas Monjalon # parse lspci details 219c6dab2a8SThomas Monjalon for line in extra_info: 220c6dab2a8SThomas Monjalon if len(line) == 0: 221c6dab2a8SThomas Monjalon continue 222c6dab2a8SThomas Monjalon name, value = line.decode().split("\t", 1) 223c6dab2a8SThomas Monjalon name = name.strip(":") + "_str" 224c6dab2a8SThomas Monjalon device[name] = value 225c6dab2a8SThomas Monjalon # check for a unix interface name 226c6dab2a8SThomas Monjalon device["Interface"] = "" 227c6dab2a8SThomas Monjalon for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id): 228c6dab2a8SThomas Monjalon if "net" in dirs: 229c6dab2a8SThomas Monjalon device["Interface"] = \ 230c6dab2a8SThomas Monjalon ",".join(os.listdir(os.path.join(base, "net"))) 231c6dab2a8SThomas Monjalon break 232c6dab2a8SThomas Monjalon # check if a port is used for ssh connection 233c6dab2a8SThomas Monjalon device["Ssh_if"] = False 234c6dab2a8SThomas Monjalon device["Active"] = "" 235c6dab2a8SThomas Monjalon 236c6dab2a8SThomas Monjalon return device 237c6dab2a8SThomas Monjalon 238ea9f00f7SGuduri Prathyushadef clear_data(): 239ea9f00f7SGuduri Prathyusha '''This function clears any old data''' 240ea9f00f7SGuduri Prathyusha devices = {} 241c6dab2a8SThomas Monjalon 242ea9f00f7SGuduri Prathyushadef get_device_details(devices_type): 243c6dab2a8SThomas Monjalon '''This function populates the "devices" dictionary. The keys used are 244c6dab2a8SThomas Monjalon the pci addresses (domain:bus:slot.func). The values are themselves 245c6dab2a8SThomas Monjalon dictionaries - one for each NIC.''' 246c6dab2a8SThomas Monjalon global devices 247c6dab2a8SThomas Monjalon global dpdk_drivers 248c6dab2a8SThomas Monjalon 249c6dab2a8SThomas Monjalon # first loop through and read details for all devices 250*c3ce205dSGuduri Prathyusha # request machine readable format, with numeric IDs and String 251c6dab2a8SThomas Monjalon dev = {} 252*c3ce205dSGuduri Prathyusha dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines() 253c6dab2a8SThomas Monjalon for dev_line in dev_lines: 254c6dab2a8SThomas Monjalon if len(dev_line) == 0: 255ea9f00f7SGuduri Prathyusha if dev["Class"][0:2] == devices_type: 256c6dab2a8SThomas Monjalon # convert device and vendor ids to numbers, then add to global 257c6dab2a8SThomas Monjalon dev["Vendor"] = int(dev["Vendor"], 16) 258c6dab2a8SThomas Monjalon dev["Device"] = int(dev["Device"], 16) 259*c3ce205dSGuduri Prathyusha if "Driver" in dev.keys(): 260*c3ce205dSGuduri Prathyusha dev["Driver_str"] = dev.pop("Driver") 261c6dab2a8SThomas Monjalon # use dict to make copy of dev 262c6dab2a8SThomas Monjalon devices[dev["Slot"]] = dict(dev) 263*c3ce205dSGuduri Prathyusha # Clear previous device's data 264*c3ce205dSGuduri Prathyusha dev = {} 265c6dab2a8SThomas Monjalon else: 266c6dab2a8SThomas Monjalon name, value = dev_line.decode().split("\t", 1) 267*c3ce205dSGuduri Prathyusha value_list = value.rsplit(' ', 1) 268*c3ce205dSGuduri Prathyusha if len(value_list) > 1: 269*c3ce205dSGuduri Prathyusha # String stored in <name>_str 270*c3ce205dSGuduri Prathyusha dev[name.rstrip(":") + '_str'] = value_list[0] 271*c3ce205dSGuduri Prathyusha # Numeric IDs 272*c3ce205dSGuduri Prathyusha dev[name.rstrip(":")] = value_list[len(value_list) - 1] \ 273*c3ce205dSGuduri Prathyusha .rstrip("]").lstrip("[") 274c6dab2a8SThomas Monjalon 275ea9f00f7SGuduri Prathyusha if devices_type == NETWORK_BASE_CLASS: 276c6dab2a8SThomas Monjalon # check what is the interface if any for an ssh connection if 277c6dab2a8SThomas Monjalon # any to this host, so we can mark it later. 278c6dab2a8SThomas Monjalon ssh_if = [] 279c6dab2a8SThomas Monjalon route = check_output(["ip", "-o", "route"]) 280c6dab2a8SThomas Monjalon # filter out all lines for 169.254 routes 281c6dab2a8SThomas Monjalon route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), 282c6dab2a8SThomas Monjalon route.decode().splitlines())) 283c6dab2a8SThomas Monjalon rt_info = route.split() 284c6dab2a8SThomas Monjalon for i in range(len(rt_info) - 1): 285c6dab2a8SThomas Monjalon if rt_info[i] == "dev": 286c6dab2a8SThomas Monjalon ssh_if.append(rt_info[i+1]) 287c6dab2a8SThomas Monjalon 288c6dab2a8SThomas Monjalon # based on the basic info, get extended text details 289c6dab2a8SThomas Monjalon for d in devices.keys(): 290ea9f00f7SGuduri Prathyusha if devices[d]["Class"][0:2] != devices_type: 291617d9052SYoni Gilad continue 292617d9052SYoni Gilad 293c6dab2a8SThomas Monjalon # get additional info and add it to existing data 294c6dab2a8SThomas Monjalon devices[d] = devices[d].copy() 295*c3ce205dSGuduri Prathyusha # No need to probe lspci 296*c3ce205dSGuduri Prathyusha devices[d].update(get_pci_device_details(d, False).items()) 297c6dab2a8SThomas Monjalon 298ea9f00f7SGuduri Prathyusha if devices_type == NETWORK_BASE_CLASS: 299ea9f00f7SGuduri Prathyusha for _if in ssh_if: 300ea9f00f7SGuduri Prathyusha if _if in devices[d]["Interface"].split(","): 301ea9f00f7SGuduri Prathyusha devices[d]["Ssh_if"] = True 302ea9f00f7SGuduri Prathyusha devices[d]["Active"] = "*Active*" 303ea9f00f7SGuduri Prathyusha break 304ea9f00f7SGuduri Prathyusha 305c6dab2a8SThomas Monjalon # add igb_uio to list of supporting modules if needed 306c6dab2a8SThomas Monjalon if "Module_str" in devices[d]: 307c6dab2a8SThomas Monjalon for driver in dpdk_drivers: 308c6dab2a8SThomas Monjalon if driver not in devices[d]["Module_str"]: 309c6dab2a8SThomas Monjalon devices[d]["Module_str"] = \ 310c6dab2a8SThomas Monjalon devices[d]["Module_str"] + ",%s" % driver 311c6dab2a8SThomas Monjalon else: 312c6dab2a8SThomas Monjalon devices[d]["Module_str"] = ",".join(dpdk_drivers) 313c6dab2a8SThomas Monjalon 314c6dab2a8SThomas Monjalon # make sure the driver and module strings do not have any duplicates 315c6dab2a8SThomas Monjalon if has_driver(d): 316c6dab2a8SThomas Monjalon modules = devices[d]["Module_str"].split(",") 317c6dab2a8SThomas Monjalon if devices[d]["Driver_str"] in modules: 318c6dab2a8SThomas Monjalon modules.remove(devices[d]["Driver_str"]) 319c6dab2a8SThomas Monjalon devices[d]["Module_str"] = ",".join(modules) 320c6dab2a8SThomas Monjalon 321c6dab2a8SThomas Monjalon 322c6dab2a8SThomas Monjalondef dev_id_from_dev_name(dev_name): 323c6dab2a8SThomas Monjalon '''Take a device "name" - a string passed in by user to identify a NIC 324c6dab2a8SThomas Monjalon device, and determine the device id - i.e. the domain:bus:slot.func - for 325c6dab2a8SThomas Monjalon it, which can then be used to index into the devices array''' 326c6dab2a8SThomas Monjalon 327c6dab2a8SThomas Monjalon # check if it's already a suitable index 328c6dab2a8SThomas Monjalon if dev_name in devices: 329c6dab2a8SThomas Monjalon return dev_name 330c6dab2a8SThomas Monjalon # check if it's an index just missing the domain part 331c6dab2a8SThomas Monjalon elif "0000:" + dev_name in devices: 332c6dab2a8SThomas Monjalon return "0000:" + dev_name 333c6dab2a8SThomas Monjalon else: 334c6dab2a8SThomas Monjalon # check if it's an interface name, e.g. eth1 335c6dab2a8SThomas Monjalon for d in devices.keys(): 336c6dab2a8SThomas Monjalon if dev_name in devices[d]["Interface"].split(","): 337c6dab2a8SThomas Monjalon return devices[d]["Slot"] 338c6dab2a8SThomas Monjalon # if nothing else matches - error 339c6dab2a8SThomas Monjalon print("Unknown device: %s. " 340c6dab2a8SThomas Monjalon "Please specify device in \"bus:slot.func\" format" % dev_name) 341c6dab2a8SThomas Monjalon sys.exit(1) 342c6dab2a8SThomas Monjalon 343c6dab2a8SThomas Monjalon 344c6dab2a8SThomas Monjalondef unbind_one(dev_id, force): 345c6dab2a8SThomas Monjalon '''Unbind the device identified by "dev_id" from its current driver''' 346c6dab2a8SThomas Monjalon dev = devices[dev_id] 347c6dab2a8SThomas Monjalon if not has_driver(dev_id): 348c6dab2a8SThomas Monjalon print("%s %s %s is not currently managed by any driver\n" % 349c6dab2a8SThomas Monjalon (dev["Slot"], dev["Device_str"], dev["Interface"])) 350c6dab2a8SThomas Monjalon return 351c6dab2a8SThomas Monjalon 352c6dab2a8SThomas Monjalon # prevent us disconnecting ourselves 353c6dab2a8SThomas Monjalon if dev["Ssh_if"] and not force: 354c6dab2a8SThomas Monjalon print("Routing table indicates that interface %s is active. " 355c6dab2a8SThomas Monjalon "Skipping unbind" % (dev_id)) 356c6dab2a8SThomas Monjalon return 357c6dab2a8SThomas Monjalon 358c6dab2a8SThomas Monjalon # write to /sys to unbind 359c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] 360c6dab2a8SThomas Monjalon try: 361c6dab2a8SThomas Monjalon f = open(filename, "a") 362c6dab2a8SThomas Monjalon except: 363c6dab2a8SThomas Monjalon print("Error: unbind failed for %s - Cannot open %s" 364c6dab2a8SThomas Monjalon % (dev_id, filename)) 365c6dab2a8SThomas Monjalon sys.exit(1) 366c6dab2a8SThomas Monjalon f.write(dev_id) 367c6dab2a8SThomas Monjalon f.close() 368c6dab2a8SThomas Monjalon 369c6dab2a8SThomas Monjalon 370c6dab2a8SThomas Monjalondef bind_one(dev_id, driver, force): 371c6dab2a8SThomas Monjalon '''Bind the device given by "dev_id" to the driver "driver". If the device 372c6dab2a8SThomas Monjalon is already bound to a different driver, it will be unbound first''' 373c6dab2a8SThomas Monjalon dev = devices[dev_id] 374c6dab2a8SThomas Monjalon saved_driver = None # used to rollback any unbind in case of failure 375c6dab2a8SThomas Monjalon 376c6dab2a8SThomas Monjalon # prevent disconnection of our ssh session 377c6dab2a8SThomas Monjalon if dev["Ssh_if"] and not force: 378c6dab2a8SThomas Monjalon print("Routing table indicates that interface %s is active. " 379c6dab2a8SThomas Monjalon "Not modifying" % (dev_id)) 380c6dab2a8SThomas Monjalon return 381c6dab2a8SThomas Monjalon 382c6dab2a8SThomas Monjalon # unbind any existing drivers we don't want 383c6dab2a8SThomas Monjalon if has_driver(dev_id): 384c6dab2a8SThomas Monjalon if dev["Driver_str"] == driver: 385c6dab2a8SThomas Monjalon print("%s already bound to driver %s, skipping\n" 386c6dab2a8SThomas Monjalon % (dev_id, driver)) 387c6dab2a8SThomas Monjalon return 388c6dab2a8SThomas Monjalon else: 389c6dab2a8SThomas Monjalon saved_driver = dev["Driver_str"] 390c6dab2a8SThomas Monjalon unbind_one(dev_id, force) 391c6dab2a8SThomas Monjalon dev["Driver_str"] = "" # clear driver string 392c6dab2a8SThomas Monjalon 393c6dab2a8SThomas Monjalon # if we are binding to one of DPDK drivers, add PCI id's to that driver 394c6dab2a8SThomas Monjalon if driver in dpdk_drivers: 395c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/new_id" % driver 396c6dab2a8SThomas Monjalon try: 397c6dab2a8SThomas Monjalon f = open(filename, "w") 398c6dab2a8SThomas Monjalon except: 399c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot open %s" 400c6dab2a8SThomas Monjalon % (dev_id, filename)) 401c6dab2a8SThomas Monjalon return 402c6dab2a8SThomas Monjalon try: 403c6dab2a8SThomas Monjalon f.write("%04x %04x" % (dev["Vendor"], dev["Device"])) 404c6dab2a8SThomas Monjalon f.close() 405c6dab2a8SThomas Monjalon except: 406c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot write new PCI ID to " 407c6dab2a8SThomas Monjalon "driver %s" % (dev_id, driver)) 408c6dab2a8SThomas Monjalon return 409c6dab2a8SThomas Monjalon 410c6dab2a8SThomas Monjalon # do the bind by writing to /sys 411c6dab2a8SThomas Monjalon filename = "/sys/bus/pci/drivers/%s/bind" % driver 412c6dab2a8SThomas Monjalon try: 413c6dab2a8SThomas Monjalon f = open(filename, "a") 414c6dab2a8SThomas Monjalon except: 415c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot open %s" 416c6dab2a8SThomas Monjalon % (dev_id, filename)) 417c6dab2a8SThomas Monjalon if saved_driver is not None: # restore any previous driver 418c6dab2a8SThomas Monjalon bind_one(dev_id, saved_driver, force) 419c6dab2a8SThomas Monjalon return 420c6dab2a8SThomas Monjalon try: 421c6dab2a8SThomas Monjalon f.write(dev_id) 422c6dab2a8SThomas Monjalon f.close() 423c6dab2a8SThomas Monjalon except: 424c6dab2a8SThomas Monjalon # for some reason, closing dev_id after adding a new PCI ID to new_id 425c6dab2a8SThomas Monjalon # results in IOError. however, if the device was successfully bound, 426c6dab2a8SThomas Monjalon # we don't care for any errors and can safely ignore IOError 427*c3ce205dSGuduri Prathyusha tmp = get_pci_device_details(dev_id, True) 428c6dab2a8SThomas Monjalon if "Driver_str" in tmp and tmp["Driver_str"] == driver: 429c6dab2a8SThomas Monjalon return 430c6dab2a8SThomas Monjalon print("Error: bind failed for %s - Cannot bind to driver %s" 431c6dab2a8SThomas Monjalon % (dev_id, driver)) 432c6dab2a8SThomas Monjalon if saved_driver is not None: # restore any previous driver 433c6dab2a8SThomas Monjalon bind_one(dev_id, saved_driver, force) 434c6dab2a8SThomas Monjalon return 435c6dab2a8SThomas Monjalon 436c6dab2a8SThomas Monjalon 437c6dab2a8SThomas Monjalondef unbind_all(dev_list, force=False): 438c6dab2a8SThomas Monjalon """Unbind method, takes a list of device locations""" 439c6dab2a8SThomas Monjalon dev_list = map(dev_id_from_dev_name, dev_list) 440c6dab2a8SThomas Monjalon for d in dev_list: 441c6dab2a8SThomas Monjalon unbind_one(d, force) 442c6dab2a8SThomas Monjalon 443c6dab2a8SThomas Monjalon 444c6dab2a8SThomas Monjalondef bind_all(dev_list, driver, force=False): 445c6dab2a8SThomas Monjalon """Bind method, takes a list of device locations""" 446c6dab2a8SThomas Monjalon global devices 447c6dab2a8SThomas Monjalon 448c6dab2a8SThomas Monjalon dev_list = map(dev_id_from_dev_name, dev_list) 449c6dab2a8SThomas Monjalon 450c6dab2a8SThomas Monjalon for d in dev_list: 451c6dab2a8SThomas Monjalon bind_one(d, driver, force) 452c6dab2a8SThomas Monjalon 453c6dab2a8SThomas Monjalon # when binding devices to a generic driver (i.e. one that doesn't have a 454c6dab2a8SThomas Monjalon # PCI ID table), some devices that are not bound to any other driver could 455c6dab2a8SThomas Monjalon # be bound even if no one has asked them to. hence, we check the list of 456c6dab2a8SThomas Monjalon # drivers again, and see if some of the previously-unbound devices were 457c6dab2a8SThomas Monjalon # erroneously bound. 458c6dab2a8SThomas Monjalon for d in devices.keys(): 459c6dab2a8SThomas Monjalon # skip devices that were already bound or that we know should be bound 460c6dab2a8SThomas Monjalon if "Driver_str" in devices[d] or d in dev_list: 461c6dab2a8SThomas Monjalon continue 462c6dab2a8SThomas Monjalon 463c6dab2a8SThomas Monjalon # update information about this device 464c6dab2a8SThomas Monjalon devices[d] = dict(devices[d].items() + 465*c3ce205dSGuduri Prathyusha get_pci_device_details(d, True).items()) 466c6dab2a8SThomas Monjalon 467c6dab2a8SThomas Monjalon # check if updated information indicates that the device was bound 468c6dab2a8SThomas Monjalon if "Driver_str" in devices[d]: 469c6dab2a8SThomas Monjalon unbind_one(d, force) 470c6dab2a8SThomas Monjalon 471c6dab2a8SThomas Monjalon 472c6dab2a8SThomas Monjalondef display_devices(title, dev_list, extra_params=None): 473c6dab2a8SThomas Monjalon '''Displays to the user the details of a list of devices given in 474c6dab2a8SThomas Monjalon "dev_list". The "extra_params" parameter, if given, should contain a string 475c6dab2a8SThomas Monjalon with %()s fields in it for replacement by the named fields in each 476c6dab2a8SThomas Monjalon device's dictionary.''' 477c6dab2a8SThomas Monjalon strings = [] # this holds the strings to print. We sort before printing 478c6dab2a8SThomas Monjalon print("\n%s" % title) 479c6dab2a8SThomas Monjalon print("="*len(title)) 480c6dab2a8SThomas Monjalon if len(dev_list) == 0: 481c6dab2a8SThomas Monjalon strings.append("<none>") 482c6dab2a8SThomas Monjalon else: 483c6dab2a8SThomas Monjalon for dev in dev_list: 484c6dab2a8SThomas Monjalon if extra_params is not None: 485*c3ce205dSGuduri Prathyusha strings.append("%s '%s %s' %s" % (dev["Slot"], 486c6dab2a8SThomas Monjalon dev["Device_str"], 487*c3ce205dSGuduri Prathyusha dev["Device"], 488c6dab2a8SThomas Monjalon extra_params % dev)) 489c6dab2a8SThomas Monjalon else: 490c6dab2a8SThomas Monjalon strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) 491c6dab2a8SThomas Monjalon # sort before printing, so that the entries appear in PCI order 492c6dab2a8SThomas Monjalon strings.sort() 493c6dab2a8SThomas Monjalon print("\n".join(strings)) # print one per line 494c6dab2a8SThomas Monjalon 495c7dd412bSGuduri Prathyushadef show_device_status(devices_type, device_name): 496c6dab2a8SThomas Monjalon global dpdk_drivers 497c6dab2a8SThomas Monjalon kernel_drv = [] 498c6dab2a8SThomas Monjalon dpdk_drv = [] 499c6dab2a8SThomas Monjalon no_drv = [] 500c6dab2a8SThomas Monjalon 501c6dab2a8SThomas Monjalon # split our list of network devices into the three categories above 502c6dab2a8SThomas Monjalon for d in devices.keys(): 503c7dd412bSGuduri Prathyusha if devices_type in devices[d]["Class"]: 504c6dab2a8SThomas Monjalon if not has_driver(d): 505c6dab2a8SThomas Monjalon no_drv.append(devices[d]) 506c6dab2a8SThomas Monjalon continue 507c6dab2a8SThomas Monjalon if devices[d]["Driver_str"] in dpdk_drivers: 508c6dab2a8SThomas Monjalon dpdk_drv.append(devices[d]) 509c6dab2a8SThomas Monjalon else: 510c6dab2a8SThomas Monjalon kernel_drv.append(devices[d]) 511c6dab2a8SThomas Monjalon 512c6dab2a8SThomas Monjalon # print each category separately, so we can clearly see what's used by DPDK 513*c3ce205dSGuduri Prathyusha display_devices("%s devices using DPDK-compatible driver" % device_name, 514*c3ce205dSGuduri Prathyusha dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s") 515c7dd412bSGuduri Prathyusha display_devices("%s devices using kernel driver" % device_name, kernel_drv, 516c6dab2a8SThomas Monjalon "if=%(Interface)s drv=%(Driver_str)s " 517c6dab2a8SThomas Monjalon "unused=%(Module_str)s %(Active)s") 518*c3ce205dSGuduri Prathyusha display_devices("Other %s devices" % device_name, no_drv, 519*c3ce205dSGuduri Prathyusha "unused=%(Module_str)s") 520c6dab2a8SThomas Monjalon 521c7dd412bSGuduri Prathyushadef show_status(): 522c7dd412bSGuduri Prathyusha '''Function called when the script is passed the "--status" option. 523c7dd412bSGuduri Prathyusha Displays to the user what devices are bound to the igb_uio driver, the 524c7dd412bSGuduri Prathyusha kernel driver or to no driver''' 525c6dab2a8SThomas Monjalon 526c7dd412bSGuduri Prathyusha show_device_status(network_devices, "Network") 527c7dd412bSGuduri Prathyusha show_device_status(crypto_devices, "Crypto") 528c6dab2a8SThomas Monjalon 529c6dab2a8SThomas Monjalondef parse_args(): 530c6dab2a8SThomas Monjalon '''Parses the command-line arguments given by the user and takes the 531c6dab2a8SThomas Monjalon appropriate action for each''' 532c6dab2a8SThomas Monjalon global b_flag 533c6dab2a8SThomas Monjalon global status_flag 534c6dab2a8SThomas Monjalon global force_flag 535c6dab2a8SThomas Monjalon global args 536c6dab2a8SThomas Monjalon if len(sys.argv) <= 1: 537c6dab2a8SThomas Monjalon usage() 538c6dab2a8SThomas Monjalon sys.exit(0) 539c6dab2a8SThomas Monjalon 540c6dab2a8SThomas Monjalon try: 541c6dab2a8SThomas Monjalon opts, args = getopt.getopt(sys.argv[1:], "b:us", 542c6dab2a8SThomas Monjalon ["help", "usage", "status", "force", 543c6dab2a8SThomas Monjalon "bind=", "unbind"]) 544c6dab2a8SThomas Monjalon except getopt.GetoptError as error: 545c6dab2a8SThomas Monjalon print(str(error)) 546c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 547c6dab2a8SThomas Monjalon sys.exit(1) 548c6dab2a8SThomas Monjalon 549c6dab2a8SThomas Monjalon for opt, arg in opts: 550c6dab2a8SThomas Monjalon if opt == "--help" or opt == "--usage": 551c6dab2a8SThomas Monjalon usage() 552c6dab2a8SThomas Monjalon sys.exit(0) 553c6dab2a8SThomas Monjalon if opt == "--status" or opt == "-s": 554c6dab2a8SThomas Monjalon status_flag = True 555c6dab2a8SThomas Monjalon if opt == "--force": 556c6dab2a8SThomas Monjalon force_flag = True 557c6dab2a8SThomas Monjalon if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": 558c6dab2a8SThomas Monjalon if b_flag is not None: 559c6dab2a8SThomas Monjalon print("Error - Only one bind or unbind may be specified\n") 560c6dab2a8SThomas Monjalon sys.exit(1) 561c6dab2a8SThomas Monjalon if opt == "-u" or opt == "--unbind": 562c6dab2a8SThomas Monjalon b_flag = "none" 563c6dab2a8SThomas Monjalon else: 564c6dab2a8SThomas Monjalon b_flag = arg 565c6dab2a8SThomas Monjalon 566c6dab2a8SThomas Monjalon 567c6dab2a8SThomas Monjalondef do_arg_actions(): 568c6dab2a8SThomas Monjalon '''do the actual action requested by the user''' 569c6dab2a8SThomas Monjalon global b_flag 570c6dab2a8SThomas Monjalon global status_flag 571c6dab2a8SThomas Monjalon global force_flag 572c6dab2a8SThomas Monjalon global args 573c6dab2a8SThomas Monjalon 574c6dab2a8SThomas Monjalon if b_flag is None and not status_flag: 575c6dab2a8SThomas Monjalon print("Error: No action specified for devices." 576c6dab2a8SThomas Monjalon "Please give a -b or -u option") 577c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 578c6dab2a8SThomas Monjalon sys.exit(1) 579c6dab2a8SThomas Monjalon 580c6dab2a8SThomas Monjalon if b_flag is not None and len(args) == 0: 581c6dab2a8SThomas Monjalon print("Error: No devices specified.") 582c6dab2a8SThomas Monjalon print("Run '%s --usage' for further information" % sys.argv[0]) 583c6dab2a8SThomas Monjalon sys.exit(1) 584c6dab2a8SThomas Monjalon 585c6dab2a8SThomas Monjalon if b_flag == "none" or b_flag == "None": 586c6dab2a8SThomas Monjalon unbind_all(args, force_flag) 587c6dab2a8SThomas Monjalon elif b_flag is not None: 588c6dab2a8SThomas Monjalon bind_all(args, b_flag, force_flag) 589c6dab2a8SThomas Monjalon if status_flag: 590c6dab2a8SThomas Monjalon if b_flag is not None: 591ea9f00f7SGuduri Prathyusha clear_data() 592ea9f00f7SGuduri Prathyusha get_device_details(NETWORK_BASE_CLASS) # refresh if we have changed anything 593ea9f00f7SGuduri Prathyusha get_device_details(CRYPTO_BASE_CLASS) # refresh if we have changed anything 594c6dab2a8SThomas Monjalon show_status() 595c6dab2a8SThomas Monjalon 596c6dab2a8SThomas Monjalon 597c6dab2a8SThomas Monjalondef main(): 598c6dab2a8SThomas Monjalon '''program main function''' 599c6dab2a8SThomas Monjalon parse_args() 600c6dab2a8SThomas Monjalon check_modules() 601ea9f00f7SGuduri Prathyusha clear_data() 602ea9f00f7SGuduri Prathyusha get_device_details(NETWORK_BASE_CLASS) 603ea9f00f7SGuduri Prathyusha get_device_details(CRYPTO_BASE_CLASS) 604c6dab2a8SThomas Monjalon do_arg_actions() 605c6dab2a8SThomas Monjalon 606c6dab2a8SThomas Monjalonif __name__ == "__main__": 607c6dab2a8SThomas Monjalon main() 608