aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorC.J. Collier <cjcollier@linuxfoundation.org>2016-06-14 07:54:47 -0700
committerC.J. Collier <cjcollier@linuxfoundation.org>2016-06-14 07:55:43 -0700
commit5129044dce1f85ce4950f31bcf90f3886466f06a (patch)
tree1c6269614c0c15ffef8451c58ae8f8b30a1bc804 /tools
parente04be89c2409570e0055b2cda60bd11395bb93b0 (diff)
Imported upstream release 16.04
* gbp import-orig ../dpdk-16.04.tar.xz Change-Id: Iac2196db782ba322f6974d8a752acc34ce5024c3 Signed-off-by: C.J. Collier <cjcollier@linuxfoundation.org>
Diffstat (limited to 'tools')
-rwxr-xr-xtools/cpu_layout.py95
-rwxr-xr-xtools/dpdk_nic_bind.py576
-rwxr-xr-xtools/setup.sh634
3 files changed, 1305 insertions, 0 deletions
diff --git a/tools/cpu_layout.py b/tools/cpu_layout.py
new file mode 100755
index 00000000..d38d0b5a
--- /dev/null
+++ b/tools/cpu_layout.py
@@ -0,0 +1,95 @@
+#! /usr/bin/python
+#
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import sys
+
+sockets = []
+cores = []
+core_map = {}
+
+fd=open("/proc/cpuinfo")
+lines = fd.readlines()
+fd.close()
+
+core_details = []
+core_lines = {}
+for line in lines:
+ if len(line.strip()) != 0:
+ name, value = line.split(":", 1)
+ core_lines[name.strip()] = value.strip()
+ else:
+ core_details.append(core_lines)
+ core_lines = {}
+
+for core in core_details:
+ for field in ["processor", "core id", "physical id"]:
+ if field not in core:
+ print "Error getting '%s' value from /proc/cpuinfo" % field
+ sys.exit(1)
+ core[field] = int(core[field])
+
+ if core["core id"] not in cores:
+ cores.append(core["core id"])
+ if core["physical id"] not in sockets:
+ sockets.append(core["physical id"])
+ key = (core["physical id"], core["core id"])
+ if key not in core_map:
+ core_map[key] = []
+ core_map[key].append(core["processor"])
+
+print "============================================================"
+print "Core and Socket Information (as reported by '/proc/cpuinfo')"
+print "============================================================\n"
+print "cores = ",cores
+print "sockets = ", sockets
+print ""
+
+max_processor_len = len(str(len(cores) * len(sockets) * 2 - 1))
+max_core_map_len = max_processor_len * 2 + len('[, ]') + len('Socket ')
+max_core_id_len = len(str(max(cores)))
+
+print " ".ljust(max_core_id_len + len('Core ')),
+for s in sockets:
+ print "Socket %s" % str(s).ljust(max_core_map_len - len('Socket ')),
+print ""
+print " ".ljust(max_core_id_len + len('Core ')),
+for s in sockets:
+ print "--------".ljust(max_core_map_len),
+print ""
+
+for c in cores:
+ print "Core %s" % str(c).ljust(max_core_id_len),
+ for s in sockets:
+ print str(core_map[(s,c)]).ljust(max_core_map_len),
+ print ""
diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py
new file mode 100755
index 00000000..28eace33
--- /dev/null
+++ b/tools/dpdk_nic_bind.py
@@ -0,0 +1,576 @@
+#! /usr/bin/python
+#
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import sys
+import os
+import getopt
+import subprocess
+from os.path import exists, abspath, dirname, basename
+
+# The PCI device class for ETHERNET devices
+ETHERNET_CLASS = "0200"
+
+# global dict ethernet devices present. Dictionary indexed by PCI address.
+# Each device within this is itself a dictionary of device properties
+devices = {}
+# list of supported DPDK drivers
+dpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"]
+
+# command-line arg flags
+b_flag = None
+status_flag = False
+force_flag = False
+args = []
+
+
+def usage():
+ '''Print usage information for the program'''
+ argv0 = basename(sys.argv[0])
+ print("""
+Usage:
+------
+
+ %(argv0)s [options] DEVICE1 DEVICE2 ....
+
+where DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax
+or "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may
+also be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc.
+
+Options:
+ --help, --usage:
+ Display usage information and quit
+
+ -s, --status:
+ Print the current status of all known network interfaces.
+ For each device, it displays the PCI domain, bus, slot and function,
+ along with a text description of the device. Depending upon whether the
+ device is being used by a kernel driver, the igb_uio driver, or no
+ driver, other relevant information will be displayed:
+ * the Linux interface name e.g. if=eth0
+ * the driver being used e.g. drv=igb_uio
+ * any suitable drivers not currently using that device
+ e.g. unused=igb_uio
+ NOTE: if this flag is passed along with a bind/unbind option, the
+ status display will always occur after the other operations have taken
+ place.
+
+ -b driver, --bind=driver:
+ Select the driver to use or \"none\" to unbind the device
+
+ -u, --unbind:
+ Unbind a device (Equivalent to \"-b none\")
+
+ --force:
+ By default, devices which are used by Linux - as indicated by having
+ routes in the routing table - cannot be modified. Using the --force
+ flag overrides this behavior, allowing active links to be forcibly
+ unbound.
+ WARNING: This can lead to loss of network connection and should be used
+ with caution.
+
+Examples:
+---------
+
+To display current device status:
+ %(argv0)s --status
+
+To bind eth1 from the current driver and move to use igb_uio
+ %(argv0)s --bind=igb_uio eth1
+
+To unbind 0000:01:00.0 from using any driver
+ %(argv0)s -u 0000:01:00.0
+
+To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
+ %(argv0)s -b ixgbe 02:00.0 02:00.1
+
+ """ % locals()) # replace items from local variables
+
+
+# This is roughly compatible with check_output function in subprocess module
+# which is only available in python 2.7.
+def check_output(args, stderr=None):
+ '''Run a command and capture its output'''
+ return subprocess.Popen(args, stdout=subprocess.PIPE,
+ stderr=stderr).communicate()[0]
+
+
+def find_module(mod):
+ '''find the .ko file for kernel module named mod.
+ Searches the $RTE_SDK/$RTE_TARGET directory, the kernel
+ modules directory and finally under the parent directory of
+ the script '''
+ # check $RTE_SDK/$RTE_TARGET directory
+ if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ:
+ path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'],
+ os.environ['RTE_TARGET'], mod)
+ if exists(path):
+ return path
+
+ # check using depmod
+ try:
+ depmod_out = check_output(["modinfo", "-n", mod],
+ stderr=subprocess.STDOUT).lower()
+ if "error" not in depmod_out:
+ path = depmod_out.strip()
+ if exists(path):
+ return path
+ except: # if modinfo can't find module, it fails, so continue
+ pass
+
+ # check for a copy based off current path
+ tools_dir = dirname(abspath(sys.argv[0]))
+ if (tools_dir.endswith("tools")):
+ base_dir = dirname(tools_dir)
+ find_out = check_output(["find", base_dir, "-name", mod + ".ko"])
+ if len(find_out) > 0: # something matched
+ path = find_out.splitlines()[0]
+ if exists(path):
+ return path
+
+
+def check_modules():
+ '''Checks that igb_uio is loaded'''
+ global dpdk_drivers
+
+ # list of supported modules
+ mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers]
+
+ # first check if module is loaded
+ try:
+ # Get list of sysfs modules (both built-in and dynamically loaded)
+ sysfs_path = '/sys/module/'
+
+ # Get the list of directories in sysfs_path
+ sysfs_mods = [os.path.join(sysfs_path, o) for o
+ in os.listdir(sysfs_path)
+ if os.path.isdir(os.path.join(sysfs_path, o))]
+
+ # Extract the last element of '/sys/module/abc' in the array
+ sysfs_mods = [a.split('/')[-1] for a in sysfs_mods]
+
+ # special case for vfio_pci (module is named vfio-pci,
+ # but its .ko is named vfio_pci)
+ sysfs_mods = map(lambda a:
+ a if a != 'vfio_pci' else 'vfio-pci', sysfs_mods)
+
+ for mod in mods:
+ if mod["Name"] in sysfs_mods:
+ mod["Found"] = True
+ except:
+ pass
+
+ # check if we have at least one loaded module
+ if True not in [mod["Found"] for mod in mods] and b_flag is not None:
+ if b_flag in dpdk_drivers:
+ print("Error - no supported modules(DPDK driver) are loaded")
+ sys.exit(1)
+ else:
+ print("Warning - no supported modules(DPDK driver) are loaded")
+
+ # change DPDK driver list to only contain drivers that are loaded
+ dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]]
+
+
+def has_driver(dev_id):
+ '''return true if a device is assigned to a driver. False otherwise'''
+ return "Driver_str" in devices[dev_id]
+
+
+def get_pci_device_details(dev_id):
+ '''This function gets additional details for a PCI device'''
+ device = {}
+
+ extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines()
+
+ # parse lspci details
+ for line in extra_info:
+ if len(line) == 0:
+ continue
+ name, value = line.decode().split("\t", 1)
+ name = name.strip(":") + "_str"
+ device[name] = value
+ # check for a unix interface name
+ sys_path = "/sys/bus/pci/devices/%s/net/" % dev_id
+ if exists(sys_path):
+ device["Interface"] = ",".join(os.listdir(sys_path))
+ else:
+ device["Interface"] = ""
+ # check if a port is used for ssh connection
+ device["Ssh_if"] = False
+ device["Active"] = ""
+
+ return device
+
+
+def get_nic_details():
+ '''This function populates the "devices" dictionary. The keys used are
+ the pci addresses (domain:bus:slot.func). The values are themselves
+ dictionaries - one for each NIC.'''
+ global devices
+ global dpdk_drivers
+
+ # clear any old data
+ devices = {}
+ # first loop through and read details for all devices
+ # request machine readable format, with numeric IDs
+ dev = {}
+ dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines()
+ for dev_line in dev_lines:
+ if (len(dev_line) == 0):
+ if dev["Class"] == ETHERNET_CLASS:
+ # convert device and vendor ids to numbers, then add to global
+ dev["Vendor"] = int(dev["Vendor"], 16)
+ dev["Device"] = int(dev["Device"], 16)
+ # use dict to make copy of dev
+ devices[dev["Slot"]] = dict(dev)
+ else:
+ name, value = dev_line.decode().split("\t", 1)
+ dev[name.rstrip(":")] = value
+
+ # check what is the interface if any for an ssh connection if
+ # any to this host, so we can mark it later.
+ ssh_if = []
+ route = check_output(["ip", "-o", "route"])
+ # filter out all lines for 169.254 routes
+ route = "\n".join(filter(lambda ln: not ln.startswith("169.254"),
+ route.decode().splitlines()))
+ rt_info = route.split()
+ for i in range(len(rt_info) - 1):
+ if rt_info[i] == "dev":
+ ssh_if.append(rt_info[i+1])
+
+ # based on the basic info, get extended text details
+ for d in devices.keys():
+ # get additional info and add it to existing data
+ devices[d] = devices[d].copy()
+ devices[d].update(get_pci_device_details(d).items())
+
+ for _if in ssh_if:
+ if _if in devices[d]["Interface"].split(","):
+ devices[d]["Ssh_if"] = True
+ devices[d]["Active"] = "*Active*"
+ break
+
+ # add igb_uio to list of supporting modules if needed
+ if "Module_str" in devices[d]:
+ for driver in dpdk_drivers:
+ if driver not in devices[d]["Module_str"]:
+ devices[d]["Module_str"] = \
+ devices[d]["Module_str"] + ",%s" % driver
+ else:
+ devices[d]["Module_str"] = ",".join(dpdk_drivers)
+
+ # make sure the driver and module strings do not have any duplicates
+ if has_driver(d):
+ modules = devices[d]["Module_str"].split(",")
+ if devices[d]["Driver_str"] in modules:
+ modules.remove(devices[d]["Driver_str"])
+ devices[d]["Module_str"] = ",".join(modules)
+
+
+def dev_id_from_dev_name(dev_name):
+ '''Take a device "name" - a string passed in by user to identify a NIC
+ device, and determine the device id - i.e. the domain:bus:slot.func - for
+ it, which can then be used to index into the devices array'''
+
+ # check if it's already a suitable index
+ if dev_name in devices:
+ return dev_name
+ # check if it's an index just missing the domain part
+ elif "0000:" + dev_name in devices:
+ return "0000:" + dev_name
+ else:
+ # check if it's an interface name, e.g. eth1
+ for d in devices.keys():
+ if dev_name in devices[d]["Interface"].split(","):
+ return devices[d]["Slot"]
+ # if nothing else matches - error
+ print("Unknown device: %s. "
+ "Please specify device in \"bus:slot.func\" format" % dev_name)
+ sys.exit(1)
+
+
+def unbind_one(dev_id, force):
+ '''Unbind the device identified by "dev_id" from its current driver'''
+ dev = devices[dev_id]
+ if not has_driver(dev_id):
+ print("%s %s %s is not currently managed by any driver\n" %
+ (dev["Slot"], dev["Device_str"], dev["Interface"]))
+ return
+
+ # prevent us disconnecting ourselves
+ if dev["Ssh_if"] and not force:
+ print("Routing table indicates that interface %s is active. "
+ "Skipping unbind" % (dev_id))
+ return
+
+ # write to /sys to unbind
+ filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
+ try:
+ f = open(filename, "a")
+ except:
+ print("Error: unbind failed for %s - Cannot open %s"
+ % (dev_id, filename))
+ sys.exit(1)
+ f.write(dev_id)
+ f.close()
+
+
+def bind_one(dev_id, driver, force):
+ '''Bind the device given by "dev_id" to the driver "driver". If the device
+ is already bound to a different driver, it will be unbound first'''
+ dev = devices[dev_id]
+ saved_driver = None # used to rollback any unbind in case of failure
+
+ # prevent disconnection of our ssh session
+ if dev["Ssh_if"] and not force:
+ print("Routing table indicates that interface %s is active. "
+ "Not modifying" % (dev_id))
+ return
+
+ # unbind any existing drivers we don't want
+ if has_driver(dev_id):
+ if dev["Driver_str"] == driver:
+ print("%s already bound to driver %s, skipping\n"
+ % (dev_id, driver))
+ return
+ else:
+ saved_driver = dev["Driver_str"]
+ unbind_one(dev_id, force)
+ dev["Driver_str"] = "" # clear driver string
+
+ # if we are binding to one of DPDK drivers, add PCI id's to that driver
+ if driver in dpdk_drivers:
+ filename = "/sys/bus/pci/drivers/%s/new_id" % driver
+ try:
+ f = open(filename, "w")
+ except:
+ print("Error: bind failed for %s - Cannot open %s"
+ % (dev_id, filename))
+ return
+ try:
+ f.write("%04x %04x" % (dev["Vendor"], dev["Device"]))
+ f.close()
+ except:
+ print("Error: bind failed for %s - Cannot write new PCI ID to "
+ "driver %s" % (dev_id, driver))
+ return
+
+ # do the bind by writing to /sys
+ filename = "/sys/bus/pci/drivers/%s/bind" % driver
+ try:
+ f = open(filename, "a")
+ except:
+ print("Error: bind failed for %s - Cannot open %s"
+ % (dev_id, filename))
+ if saved_driver is not None: # restore any previous driver
+ bind_one(dev_id, saved_driver, force)
+ return
+ try:
+ f.write(dev_id)
+ f.close()
+ except:
+ # for some reason, closing dev_id after adding a new PCI ID to new_id
+ # results in IOError. however, if the device was successfully bound,
+ # we don't care for any errors and can safely ignore IOError
+ tmp = get_pci_device_details(dev_id)
+ if "Driver_str" in tmp and tmp["Driver_str"] == driver:
+ return
+ print("Error: bind failed for %s - Cannot bind to driver %s"
+ % (dev_id, driver))
+ if saved_driver is not None: # restore any previous driver
+ bind_one(dev_id, saved_driver, force)
+ return
+
+
+def unbind_all(dev_list, force=False):
+ """Unbind method, takes a list of device locations"""
+ dev_list = map(dev_id_from_dev_name, dev_list)
+ for d in dev_list:
+ unbind_one(d, force)
+
+
+def bind_all(dev_list, driver, force=False):
+ """Bind method, takes a list of device locations"""
+ global devices
+
+ dev_list = map(dev_id_from_dev_name, dev_list)
+
+ for d in dev_list:
+ bind_one(d, driver, force)
+
+ # when binding devices to a generic driver (i.e. one that doesn't have a
+ # PCI ID table), some devices that are not bound to any other driver could
+ # be bound even if no one has asked them to. hence, we check the list of
+ # drivers again, and see if some of the previously-unbound devices were
+ # erroneously bound.
+ for d in devices.keys():
+ # skip devices that were already bound or that we know should be bound
+ if "Driver_str" in devices[d] or d in dev_list:
+ continue
+
+ # update information about this device
+ devices[d] = dict(devices[d].items() +
+ get_pci_device_details(d).items())
+
+ # check if updated information indicates that the device was bound
+ if "Driver_str" in devices[d]:
+ unbind_one(d, force)
+
+
+def display_devices(title, dev_list, extra_params=None):
+ '''Displays to the user the details of a list of devices given in
+ "dev_list". The "extra_params" parameter, if given, should contain a string
+ with %()s fields in it for replacement by the named fields in each
+ device's dictionary.'''
+ strings = [] # this holds the strings to print. We sort before printing
+ print("\n%s" % title)
+ print("="*len(title))
+ if len(dev_list) == 0:
+ strings.append("<none>")
+ else:
+ for dev in dev_list:
+ if extra_params is not None:
+ strings.append("%s '%s' %s" % (dev["Slot"],
+ dev["Device_str"], extra_params % dev))
+ else:
+ strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
+ # sort before printing, so that the entries appear in PCI order
+ strings.sort()
+ print("\n".join(strings)) # print one per line
+
+
+def show_status():
+ '''Function called when the script is passed the "--status" option.
+ Displays to the user what devices are bound to the igb_uio driver, the
+ kernel driver or to no driver'''
+ global dpdk_drivers
+ kernel_drv = []
+ dpdk_drv = []
+ no_drv = []
+
+ # split our list of devices into the three categories above
+ for d in devices.keys():
+ if not has_driver(d):
+ no_drv.append(devices[d])
+ continue
+ if devices[d]["Driver_str"] in dpdk_drivers:
+ dpdk_drv.append(devices[d])
+ else:
+ kernel_drv.append(devices[d])
+
+ # print each category separately, so we can clearly see what's used by DPDK
+ display_devices("Network devices using DPDK-compatible driver", dpdk_drv,
+ "drv=%(Driver_str)s unused=%(Module_str)s")
+ display_devices("Network devices using kernel driver", kernel_drv,
+ "if=%(Interface)s drv=%(Driver_str)s "
+ "unused=%(Module_str)s %(Active)s")
+ display_devices("Other network devices", no_drv, "unused=%(Module_str)s")
+
+
+def parse_args():
+ '''Parses the command-line arguments given by the user and takes the
+ appropriate action for each'''
+ global b_flag
+ global status_flag
+ global force_flag
+ global args
+ if len(sys.argv) <= 1:
+ usage()
+ sys.exit(0)
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "b:us",
+ ["help", "usage", "status", "force",
+ "bind=", "unbind"])
+ except getopt.GetoptError as error:
+ print(str(error))
+ print("Run '%s --usage' for further information" % sys.argv[0])
+ sys.exit(1)
+
+ for opt, arg in opts:
+ if opt == "--help" or opt == "--usage":
+ usage()
+ sys.exit(0)
+ if opt == "--status" or opt == "-s":
+ status_flag = True
+ if opt == "--force":
+ force_flag = True
+ if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind":
+ if b_flag is not None:
+ print("Error - Only one bind or unbind may be specified\n")
+ sys.exit(1)
+ if opt == "-u" or opt == "--unbind":
+ b_flag = "none"
+ else:
+ b_flag = arg
+
+
+def do_arg_actions():
+ '''do the actual action requested by the user'''
+ global b_flag
+ global status_flag
+ global force_flag
+ global args
+
+ if b_flag is None and not status_flag:
+ print("Error: No action specified for devices."
+ "Please give a -b or -u option")
+ print("Run '%s --usage' for further information" % sys.argv[0])
+ sys.exit(1)
+
+ if b_flag is not None and len(args) == 0:
+ print("Error: No devices specified.")
+ print("Run '%s --usage' for further information" % sys.argv[0])
+ sys.exit(1)
+
+ if b_flag == "none" or b_flag == "None":
+ unbind_all(args, force_flag)
+ elif b_flag is not None:
+ bind_all(args, b_flag, force_flag)
+ if status_flag:
+ if b_flag is not None:
+ get_nic_details() # refresh if we have changed anything
+ show_status()
+
+
+def main():
+ '''program main function'''
+ parse_args()
+ check_modules()
+ get_nic_details()
+ do_arg_actions()
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/setup.sh b/tools/setup.sh
new file mode 100755
index 00000000..6097ab7b
--- /dev/null
+++ b/tools/setup.sh
@@ -0,0 +1,634 @@
+#! /bin/bash
+
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Run with "source /path/to/setup.sh"
+#
+
+#
+# Change to DPDK directory ( <this-script's-dir>/.. ), and export it as RTE_SDK
+#
+cd $(dirname ${BASH_SOURCE[0]})/..
+export RTE_SDK=$PWD
+echo "------------------------------------------------------------------------------"
+echo " RTE_SDK exported as $RTE_SDK"
+echo "------------------------------------------------------------------------------"
+
+HUGEPGSZ=`cat /proc/meminfo | grep Hugepagesize | cut -d : -f 2 | tr -d ' '`
+
+#
+# Application EAL parameters for setting memory options (amount/channels/ranks).
+#
+EAL_PARAMS='-n 4'
+
+#
+# Sets QUIT variable so script will finish.
+#
+quit()
+{
+ QUIT=$1
+}
+
+# Shortcut for quit.
+q()
+{
+ quit
+}
+
+#
+# Sets up environmental variables for ICC.
+#
+setup_icc()
+{
+ DEFAULT_PATH=/opt/intel/bin/iccvars.sh
+ param=$1
+ shpath=`which iccvars.sh 2> /dev/null`
+ if [ $? -eq 0 ] ; then
+ echo "Loading iccvars.sh from $shpath for $param"
+ source $shpath $param
+ elif [ -f $DEFAULT_PATH ] ; then
+ echo "Loading iccvars.sh from $DEFAULT_PATH for $param"
+ source $DEFAULT_PATH $param
+ else
+ echo "## ERROR: cannot find 'iccvars.sh' script to set up ICC."
+ echo "## To fix, please add the directory that contains"
+ echo "## iccvars.sh to your 'PATH' environment variable."
+ quit
+ fi
+}
+
+#
+# Sets RTE_TARGET and does a "make install".
+#
+setup_target()
+{
+ option=$1
+ export RTE_TARGET=${TARGETS[option]}
+
+ compiler=${RTE_TARGET##*-}
+ if [ "$compiler" == "icc" ] ; then
+ platform=${RTE_TARGET%%-*}
+ if [ "$platform" == "x86_64" ] ; then
+ setup_icc intel64
+ else
+ setup_icc ia32
+ fi
+ fi
+ if [ "$QUIT" == "0" ] ; then
+ make install T=${RTE_TARGET}
+ fi
+ echo "------------------------------------------------------------------------------"
+ echo " RTE_TARGET exported as $RTE_TARGET"
+ echo "------------------------------------------------------------------------------"
+}
+
+#
+# Creates hugepage filesystem.
+#
+create_mnt_huge()
+{
+ echo "Creating /mnt/huge and mounting as hugetlbfs"
+ sudo mkdir -p /mnt/huge
+
+ grep -s '/mnt/huge' /proc/mounts > /dev/null
+ if [ $? -ne 0 ] ; then
+ sudo mount -t hugetlbfs nodev /mnt/huge
+ fi
+}
+
+#
+# Removes hugepage filesystem.
+#
+remove_mnt_huge()
+{
+ echo "Unmounting /mnt/huge and removing directory"
+ grep -s '/mnt/huge' /proc/mounts > /dev/null
+ if [ $? -eq 0 ] ; then
+ sudo umount /mnt/huge
+ fi
+
+ if [ -d /mnt/huge ] ; then
+ sudo rm -R /mnt/huge
+ fi
+}
+
+#
+# Unloads igb_uio.ko.
+#
+remove_igb_uio_module()
+{
+ echo "Unloading any existing DPDK UIO module"
+ /sbin/lsmod | grep -s igb_uio > /dev/null
+ if [ $? -eq 0 ] ; then
+ sudo /sbin/rmmod igb_uio
+ fi
+}
+
+#
+# Loads new igb_uio.ko (and uio module if needed).
+#
+load_igb_uio_module()
+{
+ if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko ];then
+ echo "## ERROR: Target does not have the DPDK UIO Kernel Module."
+ echo " To fix, please try to rebuild target."
+ return
+ fi
+
+ remove_igb_uio_module
+
+ /sbin/lsmod | grep -s uio > /dev/null
+ if [ $? -ne 0 ] ; then
+ modinfo uio > /dev/null
+ if [ $? -eq 0 ]; then
+ echo "Loading uio module"
+ sudo /sbin/modprobe uio
+ fi
+ fi
+
+ # UIO may be compiled into kernel, so it may not be an error if it can't
+ # be loaded.
+
+ echo "Loading DPDK UIO module"
+ sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko
+ if [ $? -ne 0 ] ; then
+ echo "## ERROR: Could not load kmod/igb_uio.ko."
+ quit
+ fi
+}
+
+#
+# Unloads VFIO modules.
+#
+remove_vfio_module()
+{
+ echo "Unloading any existing VFIO module"
+ /sbin/lsmod | grep -s vfio > /dev/null
+ if [ $? -eq 0 ] ; then
+ sudo /sbin/rmmod vfio-pci
+ sudo /sbin/rmmod vfio_iommu_type1
+ sudo /sbin/rmmod vfio
+ fi
+}
+
+#
+# Loads new vfio-pci (and vfio module if needed).
+#
+load_vfio_module()
+{
+ remove_vfio_module
+
+ VFIO_PATH="kernel/drivers/vfio/pci/vfio-pci.ko"
+
+ echo "Loading VFIO module"
+ /sbin/lsmod | grep -s vfio_pci > /dev/null
+ if [ $? -ne 0 ] ; then
+ if [ -f /lib/modules/$(uname -r)/$VFIO_PATH ] ; then
+ sudo /sbin/modprobe vfio-pci
+ fi
+ fi
+
+ # make sure regular users can read /dev/vfio
+ echo "chmod /dev/vfio"
+ sudo chmod a+x /dev/vfio
+ if [ $? -ne 0 ] ; then
+ echo "FAIL"
+ quit
+ fi
+ echo "OK"
+
+ # check if /dev/vfio/vfio exists - that way we
+ # know we either loaded the module, or it was
+ # compiled into the kernel
+ if [ ! -e /dev/vfio/vfio ] ; then
+ echo "## ERROR: VFIO not found!"
+ fi
+}
+
+#
+# Unloads the rte_kni.ko module.
+#
+remove_kni_module()
+{
+ echo "Unloading any existing DPDK KNI module"
+ /sbin/lsmod | grep -s rte_kni > /dev/null
+ if [ $? -eq 0 ] ; then
+ sudo /sbin/rmmod rte_kni
+ fi
+}
+
+#
+# Loads the rte_kni.ko module.
+#
+load_kni_module()
+{
+ # Check that the KNI module is already built.
+ if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko ];then
+ echo "## ERROR: Target does not have the DPDK KNI Module."
+ echo " To fix, please try to rebuild target."
+ return
+ fi
+
+ # Unload existing version if present.
+ remove_kni_module
+
+ # Now try load the KNI module.
+ echo "Loading DPDK KNI module"
+ sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko
+ if [ $? -ne 0 ] ; then
+ echo "## ERROR: Could not load kmod/rte_kni.ko."
+ quit
+ fi
+}
+
+#
+# Sets appropriate permissions on /dev/vfio/* files
+#
+set_vfio_permissions()
+{
+ # make sure regular users can read /dev/vfio
+ echo "chmod /dev/vfio"
+ sudo chmod a+x /dev/vfio
+ if [ $? -ne 0 ] ; then
+ echo "FAIL"
+ quit
+ fi
+ echo "OK"
+
+ # make sure regular user can access everything inside /dev/vfio
+ echo "chmod /dev/vfio/*"
+ sudo chmod 0666 /dev/vfio/*
+ if [ $? -ne 0 ] ; then
+ echo "FAIL"
+ quit
+ fi
+ echo "OK"
+
+ # since permissions are only to be set when running as
+ # regular user, we only check ulimit here
+ #
+ # warn if regular user is only allowed
+ # to memlock <64M of memory
+ MEMLOCK_AMNT=`ulimit -l`
+
+ if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then
+ MEMLOCK_MB=`expr $MEMLOCK_AMNT / 1024`
+ echo ""
+ echo "Current user memlock limit: ${MEMLOCK_MB} MB"
+ echo ""
+ echo "This is the maximum amount of memory you will be"
+ echo "able to use with DPDK and VFIO if run as current user."
+ echo -n "To change this, please adjust limits.conf memlock "
+ echo "limit for current user."
+
+ if [ $MEMLOCK_AMNT -lt 65536 ] ; then
+ echo ""
+ echo "## WARNING: memlock limit is less than 64MB"
+ echo -n "## DPDK with VFIO may not be able to initialize "
+ echo "if run as current user."
+ fi
+ fi
+}
+
+#
+# Removes all reserved hugepages.
+#
+clear_huge_pages()
+{
+ echo > .echo_tmp
+ for d in /sys/devices/system/node/node? ; do
+ echo "echo 0 > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp
+ done
+ echo "Removing currently reserved hugepages"
+ sudo sh .echo_tmp
+ rm -f .echo_tmp
+
+ remove_mnt_huge
+}
+
+#
+# Creates hugepages.
+#
+set_non_numa_pages()
+{
+ clear_huge_pages
+
+ echo ""
+ echo " Input the number of ${HUGEPGSZ} hugepages"
+ echo " Example: to have 128MB of hugepages available in a 2MB huge page system,"
+ echo " enter '64' to reserve 64 * 2MB pages"
+ echo -n "Number of pages: "
+ read Pages
+
+ echo "echo $Pages > /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" > .echo_tmp
+
+ echo "Reserving hugepages"
+ sudo sh .echo_tmp
+ rm -f .echo_tmp
+
+ create_mnt_huge
+}
+
+#
+# Creates hugepages on specific NUMA nodes.
+#
+set_numa_pages()
+{
+ clear_huge_pages
+
+ echo ""
+ echo " Input the number of ${HUGEPGSZ} hugepages for each node"
+ echo " Example: to have 128MB of hugepages available per node in a 2MB huge page system,"
+ echo " enter '64' to reserve 64 * 2MB pages on each node"
+
+ echo > .echo_tmp
+ for d in /sys/devices/system/node/node? ; do
+ node=$(basename $d)
+ echo -n "Number of pages for $node: "
+ read Pages
+ echo "echo $Pages > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp
+ done
+ echo "Reserving hugepages"
+ sudo sh .echo_tmp
+ rm -f .echo_tmp
+
+ create_mnt_huge
+}
+
+#
+# Run unit test application.
+#
+run_test_app()
+{
+ echo ""
+ echo " Enter hex bitmask of cores to execute test app on"
+ echo " Example: to execute app on cores 0 to 7, enter 0xff"
+ echo -n "bitmask: "
+ read Bitmask
+ echo "Launching app"
+ sudo ${RTE_TARGET}/app/test -c $Bitmask $EAL_PARAMS
+}
+
+#
+# Run unit testpmd application.
+#
+run_testpmd_app()
+{
+ echo ""
+ echo " Enter hex bitmask of cores to execute testpmd app on"
+ echo " Example: to execute app on cores 0 to 7, enter 0xff"
+ echo -n "bitmask: "
+ read Bitmask
+ echo "Launching app"
+ sudo ${RTE_TARGET}/app/testpmd -c $Bitmask $EAL_PARAMS -- -i
+}
+
+#
+# Print hugepage information.
+#
+grep_meminfo()
+{
+ grep -i huge /proc/meminfo
+}
+
+#
+# Calls dpdk_nic_bind.py --status to show the NIC and what they
+# are all bound to, in terms of drivers.
+#
+show_nics()
+{
+ if [ -d /sys/module/vfio_pci -o -d /sys/module/igb_uio ]; then
+ ${RTE_SDK}/tools/dpdk_nic_bind.py --status
+ else
+ echo "# Please load the 'igb_uio' or 'vfio-pci' kernel module before "
+ echo "# querying or adjusting NIC device bindings"
+ fi
+}
+
+#
+# Uses dpdk_nic_bind.py to move devices to work with vfio-pci
+#
+bind_nics_to_vfio()
+{
+ if [ -d /sys/module/vfio_pci ]; then
+ ${RTE_SDK}/tools/dpdk_nic_bind.py --status
+ echo ""
+ echo -n "Enter PCI address of device to bind to VFIO driver: "
+ read PCI_PATH
+ sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b vfio-pci $PCI_PATH &&
+ echo "OK"
+ else
+ echo "# Please load the 'vfio-pci' kernel module before querying or "
+ echo "# adjusting NIC device bindings"
+ fi
+}
+
+#
+# Uses dpdk_nic_bind.py to move devices to work with igb_uio
+#
+bind_nics_to_igb_uio()
+{
+ if [ -d /sys/module/igb_uio ]; then
+ ${RTE_SDK}/tools/dpdk_nic_bind.py --status
+ echo ""
+ echo -n "Enter PCI address of device to bind to IGB UIO driver: "
+ read PCI_PATH
+ sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b igb_uio $PCI_PATH && echo "OK"
+ else
+ echo "# Please load the 'igb_uio' kernel module before querying or "
+ echo "# adjusting NIC device bindings"
+ fi
+}
+
+#
+# Uses dpdk_nic_bind.py to move devices to work with kernel drivers again
+#
+unbind_nics()
+{
+ ${RTE_SDK}/tools/dpdk_nic_bind.py --status
+ echo ""
+ echo -n "Enter PCI address of device to unbind: "
+ read PCI_PATH
+ echo ""
+ echo -n "Enter name of kernel driver to bind the device to: "
+ read DRV
+ sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b $DRV $PCI_PATH && echo "OK"
+}
+
+#
+# Options for building a target. Note that this step MUST be first as it sets
+# up TARGETS[] starting from 1, and this is accessed in setup_target using the
+# user entered option.
+#
+step1_func()
+{
+ TITLE="Select the DPDK environment to build"
+ CONFIG_NUM=1
+ for cfg in config/defconfig_* ; do
+ cfg=${cfg/config\/defconfig_/}
+ TEXT[$CONFIG_NUM]="$cfg"
+ TARGETS[$CONFIG_NUM]=$cfg
+ FUNC[$CONFIG_NUM]="setup_target"
+ let "CONFIG_NUM+=1"
+ done
+}
+
+#
+# Options for setting up environment.
+#
+step2_func()
+{
+ TITLE="Setup linuxapp environment"
+
+ TEXT[1]="Insert IGB UIO module"
+ FUNC[1]="load_igb_uio_module"
+
+ TEXT[2]="Insert VFIO module"
+ FUNC[2]="load_vfio_module"
+
+ TEXT[3]="Insert KNI module"
+ FUNC[3]="load_kni_module"
+
+ TEXT[4]="Setup hugepage mappings for non-NUMA systems"
+ FUNC[4]="set_non_numa_pages"
+
+ TEXT[5]="Setup hugepage mappings for NUMA systems"
+ FUNC[5]="set_numa_pages"
+
+ TEXT[6]="Display current Ethernet device settings"
+ FUNC[6]="show_nics"
+
+ TEXT[7]="Bind Ethernet device to IGB UIO module"
+ FUNC[7]="bind_nics_to_igb_uio"
+
+ TEXT[8]="Bind Ethernet device to VFIO module"
+ FUNC[8]="bind_nics_to_vfio"
+
+ TEXT[9]="Setup VFIO permissions"
+ FUNC[9]="set_vfio_permissions"
+}
+
+#
+# Options for running applications.
+#
+step3_func()
+{
+ TITLE="Run test application for linuxapp environment"
+
+ TEXT[1]="Run test application (\$RTE_TARGET/app/test)"
+ FUNC[1]="run_test_app"
+
+ TEXT[2]="Run testpmd application in interactive mode (\$RTE_TARGET/app/testpmd)"
+ FUNC[2]="run_testpmd_app"
+}
+
+#
+# Other options
+#
+step4_func()
+{
+ TITLE="Other tools"
+
+ TEXT[1]="List hugepage info from /proc/meminfo"
+ FUNC[1]="grep_meminfo"
+
+}
+
+#
+# Options for cleaning up the system
+#
+step5_func()
+{
+ TITLE="Uninstall and system cleanup"
+
+ TEXT[1]="Unbind NICs from IGB UIO or VFIO driver"
+ FUNC[1]="unbind_nics"
+
+ TEXT[2]="Remove IGB UIO module"
+ FUNC[2]="remove_igb_uio_module"
+
+ TEXT[3]="Remove VFIO module"
+ FUNC[3]="remove_vfio_module"
+
+ TEXT[4]="Remove KNI module"
+ FUNC[4]="remove_kni_module"
+
+ TEXT[5]="Remove hugepage mappings"
+ FUNC[5]="clear_huge_pages"
+}
+
+STEPS[1]="step1_func"
+STEPS[2]="step2_func"
+STEPS[3]="step3_func"
+STEPS[4]="step4_func"
+STEPS[5]="step5_func"
+
+QUIT=0
+
+while [ "$QUIT" == "0" ]; do
+ OPTION_NUM=1
+
+ for s in $(seq ${#STEPS[@]}) ; do
+ ${STEPS[s]}
+
+ echo "----------------------------------------------------------"
+ echo " Step $s: ${TITLE}"
+ echo "----------------------------------------------------------"
+
+ for i in $(seq ${#TEXT[@]}) ; do
+ echo "[$OPTION_NUM] ${TEXT[i]}"
+ OPTIONS[$OPTION_NUM]=${FUNC[i]}
+ let "OPTION_NUM+=1"
+ done
+
+ # Clear TEXT and FUNC arrays before next step
+ unset TEXT
+ unset FUNC
+
+ echo ""
+ done
+
+ echo "[$OPTION_NUM] Exit Script"
+ OPTIONS[$OPTION_NUM]="quit"
+ echo ""
+ echo -n "Option: "
+ read our_entry
+ echo ""
+ ${OPTIONS[our_entry]} ${our_entry}
+
+ if [ "$QUIT" == "0" ] ; then
+ echo
+ echo -n "Press enter to continue ..."; read
+ fi
+
+done