import sys
import os
import json
import glob
import logging
import time
import argparse
import subprocess
network_class = {
"Class": "02",
"Vendor": None,
"Device": None,
"SVendor": None,
"SDevice": None,
}
acceleration_class = {
"Class": "12",
"Vendor": None,
"Device": None,
"SVendor": None,
"SDevice": None,
}
ifpga_class = {
"Class": "12",
"Vendor": "8086",
"Device": "0b30",
"SVendor": None,
"SDevice": None,
}
encryption_class = {
"Class": "10",
"Vendor": None,
"Device": None,
"SVendor": None,
"SDevice": None,
}
intel_processor_class = {
"Class": "0b",
"Vendor": "8086",
"Device": None,
"SVendor": None,
"SDevice": None,
}
cavium_sso = {
"Class": "08",
"Vendor": "177d",
"Device": "a04b,a04d",
"SVendor": None,
"SDevice": None,
}
cavium_fpa = {
"Class": "08",
"Vendor": "177d",
"Device": "a053",
"SVendor": None,
"SDevice": None,
}
cavium_pkx = {
"Class": "08",
"Vendor": "177d",
"Device": "a0dd,a049",
"SVendor": None,
"SDevice": None,
}
cavium_tim = {
"Class": "08",
"Vendor": "177d",
"Device": "a051",
"SVendor": None,
"SDevice": None,
}
cavium_zip = {
"Class": "12",
"Vendor": "177d",
"Device": "a037",
"SVendor": None,
"SDevice": None,
}
avp_vnic = {
"Class": "05",
"Vendor": "1af4",
"Device": "1110",
"SVendor": None,
"SDevice": None,
}
octeontx2_sso = {
"Class": "08",
"Vendor": "177d",
"Device": "a0f9,a0fa",
"SVendor": None,
"SDevice": None,
}
octeontx2_npa = {
"Class": "08",
"Vendor": "177d",
"Device": "a0fb,a0fc",
"SVendor": None,
"SDevice": None,
}
octeontx2_dma = {
"Class": "08",
"Vendor": "177d",
"Device": "a081",
"SVendor": None,
"SDevice": None,
}
intel_ioat_bdw = {
"Class": "08",
"Vendor": "8086",
"Device": "6f20,6f21,6f22,6f23,6f24,6f25,6f26,6f27,6f2e,6f2f",
"SVendor": None,
"SDevice": None,
}
intel_ioat_skx = {
"Class": "08",
"Vendor": "8086",
"Device": "2021",
"SVendor": None,
"SDevice": None,
}
intel_ntb_skx = {
"Class": "06",
"Vendor": "8086",
"Device": "201c",
"SVendor": None,
"SDevice": None,
}
network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
baseband_devices = [acceleration_class]
crypto_devices = [encryption_class, intel_processor_class]
eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
mempool_devices = [cavium_fpa, octeontx2_npa]
compress_devices = [cavium_zip]
misc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ntb_skx, octeontx2_dma]
logger = logging.getLogger()
_DEVICES = {}
_DPDK_DRIVERS = ["igb_uio", "vfio-pci", "uio_pci_generic"]
_SETTINGS_FILE = "setup_dpdk_settings.dat"
_IP_TOOLS = None
def usage():
return """
This tool helps setting up DPDK on your machine. It's based on the `dpdk-devbind`
tool that is shipped with DPDK: <https://doc.dpdk.org/guides/tools/devbind.html>
but extends its capabilities. It takes care of everything that is needed to run
a DPDK application:
- Allocate hugepages used by DPDK for packet buffer allocation
- Insert DPDK kernel modules
- [Optional] Install the DPDK KNI module
(https://doc.dpdk.org/guides/prog_guide/kernel_nic_interface.html)
- Bind devices from their "standard" drivers to DPDK-controlled drivers
In addition this tool allows checking the status of the devices currently
bound/unbound to DPDK (similar to `dpdk-devbind --status`).
Last, it allows unsetting all DPDK configuration and restore the system to its
previous state.
The tool has 3 available options:
setup
-----
Setup DPDK on your machine. This option expects as input several parameters such
as the amount of hugepages to allocate, a list of (one or more) network interfaces
to allocate for DPDK, the DPDK driver to use and more.
After setup is complete the previous configuration is saved in the file
`{settings_file}` which can later be used to restore the settings by the
"restore" command.
status
------
Show the status of all network devices and for each device is shows whether it's
used by DPDK driver or by a kernel driver (similar to `dpdk-devbind --status`).
restore
-------
Restore the system to its previous state. This command assumes that the file
`{settings_file}` exists and contains the information that was written by the
"setup" command of the system configuration before DPDK setup.
Please note that a machine restart will usually reset these configurations
anyway (unless otherwise configured by the user). However this command is useful
for restoring the system without a restart.
Examples:
=========
[Setup] allocate 512 hugepages and bind interfaces `eth0` and `eth1` to DPDK:
sudo python setup_dpdk.py setup -g 512 -i eth0 eth1
[Setup] allocate 64 hugepages, bind `eth0` to DPDK and use the `uio_pci_generic`
driver (the default if not specified is `igb_uio`):
sudo python setup_dpdk.py setup -g 64 -i eth0 -m uio_pci_generic
[Setup] allocate 1024 hugepages, bind `enp0s3` to DPDK and load the DPDK KNI
driver (not loaded by default):
sudo python setup_dpdk.py setup -g 1024 -i enp0s3 -k
[Status]
sudo python setup_dpdk.py status
[Restore]
sudo python setup_dpdk.py restore\n\n
""".format(
settings_file=_SETTINGS_FILE
)
def check_output(args, stderr=None):
logger.debug("running command: '%s'", " ".join(args))
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=stderr).communicate()[
0
]
def has_driver(dev_id):
return "Driver_str" in _DEVICES[dev_id]
def get_pci_device_details(dev_id, probe_lspci):
device = {}
if probe_lspci:
extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines()
for line in extra_info:
if len(line) == 0:
continue
name, value = line.decode().split("\t", 1)
name = name.strip(":") + "_str"
device[name] = value
device["Interface"] = ""
for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id):
if "net" in dirs:
device["Interface"] = ",".join(os.listdir(os.path.join(base, "net")))
break
device["Ssh_if"] = False
device["Active"] = ""
return device
def clear_data():
global _DEVICES _DEVICES = {}
def get_device_details(devices_type):
global _DEVICES
dev = {}
dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines()
for dev_line in dev_lines:
if len(dev_line) == 0:
if device_type_match(dev, devices_type):
if "Driver" in dev.keys():
dev["Driver_str"] = dev.pop("Driver")
if "Module" in dev.keys():
dev["Module_str"] = dev.pop("Module")
_DEVICES[dev["Slot"]] = dict(dev)
dev = {}
else:
name, value = dev_line.decode().split("\t", 1)
value_list = value.rsplit(" ", 1)
if len(value_list) > 1:
dev[name.rstrip(":") + "_str"] = value_list[0]
dev[name.rstrip(":")] = (
value_list[len(value_list) - 1].rstrip("]").lstrip("[")
)
if devices_type == network_devices:
ssh_if = []
route = check_output(["ip", "-o", "route"])
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])
for dev in _DEVICES:
if not device_type_match(_DEVICES[dev], devices_type):
continue
_DEVICES[dev] = _DEVICES[dev].copy()
_DEVICES[dev].update(get_pci_device_details(dev, False).items())
if devices_type == network_devices:
for _if in ssh_if:
if _if in _DEVICES[dev]["Interface"].split(","):
_DEVICES[dev]["Ssh_if"] = True
_DEVICES[dev]["Active"] = "*Active*"
break
if "Module_str" in _DEVICES[dev]:
for driver in _DPDK_DRIVERS:
if driver not in _DEVICES[dev]["Module_str"]:
_DEVICES[dev]["Module_str"] = (
_DEVICES[dev]["Module_str"] + ",%s" % driver
)
else:
_DEVICES[dev]["Module_str"] = ",".join(_DPDK_DRIVERS)
if has_driver(dev):
modules = _DEVICES[dev]["Module_str"].split(",")
if _DEVICES[dev]["Driver_str"] in modules:
modules.remove(_DEVICES[dev]["Driver_str"])
_DEVICES[dev]["Module_str"] = ",".join(modules)
def device_type_match(dev, devices_type):
for _, device_type in enumerate(devices_type):
param_count = len([x for x in device_type.values() if x is not None])
match_count = 0
if dev["Class"][0:2] == device_type["Class"]:
match_count = match_count + 1
for key in device_type:
if key != "Class" and device_type[key]:
value_list = device_type[key].split(",")
for value in value_list:
if value.strip(" ") == dev[key]:
match_count = match_count + 1
if match_count == param_count:
return True
return False
def dev_id_from_dev_name(dev_name):
if dev_name in _DEVICES:
return dev_name
if "0000:" + dev_name in _DEVICES:
return "0000:" + dev_name
for dev in _DEVICES:
if dev_name in _DEVICES[dev]["Interface"].split(","):
return _DEVICES[dev]["Slot"]
raise ValueError(
"Unknown device: %s. "
'Please specify device in "bus:slot.func" format' % dev_name
)
def unbind_one(dev_id, quiet, force):
def handle_error(error_msg):
if not quiet:
logger.error(error_msg)
dev = _DEVICES[dev_id]
if not has_driver(dev_id):
handle_error(
"notice: %s %s %s is not currently managed by any driver"
% (dev["Slot"], dev["Device_str"], dev["Interface"])
)
return
if dev["Ssh_if"] and not force:
handle_error(
"routing table indicates that interface %s is active. "
"Skipping unbind" % dev_id
)
return
filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
try:
file_d = open(filename, "a")
except: handle_error(
"Error: unbind failed for %s - Cannot open %s" % (dev_id, filename)
)
file_d.write(dev_id)
logger.debug("unbind_one: write '%s' to '%s'", dev_id, filename)
file_d.close()
def bind_one(dev_id, driver, quiet, force):
def handle_error(error_msg):
if not quiet:
logger.error(error_msg)
dev = _DEVICES[dev_id]
saved_driver = None
if dev["Ssh_if"] and not force:
handle_error(
"Warning: routing table indicates that interface %s is active. Not modifying"
% dev_id
)
return None
if has_driver(dev_id):
if dev["Driver_str"] == driver:
handle_error(
"Notice: %s already bound to driver %s, skipping" % (dev_id, driver)
)
return None
saved_driver = dev["Driver_str"]
unbind_one(dev_id, quiet, force)
dev.pop("Driver_str")
filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
if os.path.exists(filename):
try:
file_d = open(filename, "w")
except: handle_error(
"Error: bind failed for %s - Cannot open %s" % (dev_id, filename)
)
return None
try:
file_d.write("%s" % driver)
logger.debug("bind_one: write '%s' to '%s'", driver, filename)
file_d.close()
except: handle_error(
"Error: bind failed for %s - Cannot write driver %s to "
"PCI ID " % (dev_id, driver)
)
return None
else:
filename = "/sys/bus/pci/drivers/%s/new_id" % driver
try:
file_d = open(filename, "w")
except: handle_error(
"Error: bind failed for %s - Cannot open %s" % (dev_id, filename)
)
return None
try:
file_d.write("%04x %04x" % (int(dev["Vendor"], 16), int(dev["Device"], 16)))
file_d.close()
except: handle_error(
"Error: bind failed for %s - Cannot write new PCI ID to "
"driver %s" % (dev_id, driver)
)
return None
filename = "/sys/bus/pci/drivers/%s/bind" % driver
try:
file_d = open(filename, "a")
except: logger.error("Error: bind failed for %s - Cannot open %s", dev_id, filename)
if saved_driver is not None: bind_one(dev_id, saved_driver, quiet, force)
return None
try:
file_d.write(dev_id)
logger.debug("bind_one: write '%s' to '%s'", dev_id, filename)
file_d.close()
except: tmp = get_pci_device_details(dev_id, True)
if "Driver_str" in tmp and tmp["Driver_str"] == driver:
return saved_driver
logger.error(
"Error: bind failed for %s - Cannot bind to driver %s", dev_id, driver
)
if saved_driver is not None: bind_one(dev_id, saved_driver, quiet, force)
return None
filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
if os.path.exists(filename):
try:
file_d = open(filename, "w")
except: handle_error(
"Error: unbind failed for %s - Cannot open %s" % (dev_id, filename)
)
return None
try:
file_d.write("\00")
logger.debug("bind_one: write '\00' to '%s'", filename)
file_d.close()
except: handle_error(
"Error: unbind failed for %s - Cannot open %s" % (dev_id, filename)
)
return None
return saved_driver
def display_devices(title, dev_list, extra_params=None):
strings = [] 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' %s"
% (
dev["Slot"],
dev["Device_str"],
dev["Device"],
extra_params % dev,
)
)
else:
strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
strings.sort()
print("\n".join(strings))
def show_device_status(devices_type, device_name):
kernel_drv = []
dpdk_drv = []
no_drv = []
for dev in _DEVICES:
if device_type_match(_DEVICES[dev], devices_type):
if not has_driver(dev):
no_drv.append(_DEVICES[dev])
continue
if _DEVICES[dev]["Driver_str"] in _DPDK_DRIVERS:
dpdk_drv.append(_DEVICES[dev])
else:
kernel_drv.append(_DEVICES[dev])
n_devs = len(dpdk_drv) + len(kernel_drv) + len(no_drv)
if n_devs == 0:
msg = "No '%s' devices detected" % device_name
print("")
print(msg)
print("".join("=" * len(msg)))
return
if len(dpdk_drv) != 0:
display_devices(
"%s devices using DPDK-compatible driver" % device_name,
dpdk_drv,
"drv=%(Driver_str)s unused=%(Module_str)s",
)
if len(kernel_drv) != 0:
display_devices(
"%s devices using kernel driver" % device_name,
kernel_drv,
"if=%(Interface)s drv=%(Driver_str)s " "unused=%(Module_str)s %(Active)s",
)
if len(no_drv) != 0:
display_devices(
"Other %s devices" % device_name, no_drv, "unused=%(Module_str)s"
)
def show_status(status_dev):
if status_dev in ("net", "all"):
show_device_status(network_devices, "Network")
if status_dev in ("baseband", "all"):
show_device_status(baseband_devices, "Baseband")
if status_dev in ("crypto", "all"):
show_device_status(crypto_devices, "Crypto")
if status_dev in ("event", "all"):
show_device_status(eventdev_devices, "Eventdev")
if status_dev in ("mempool", "all"):
show_device_status(mempool_devices, "Mempool")
if status_dev in ("compress", "all"):
show_device_status(compress_devices, "Compress")
if status_dev in ("misc", "all"):
show_device_status(misc_devices, "Misc (rawdev)")
def load_device_data():
clear_data()
get_device_details(network_devices)
get_device_details(baseband_devices)
get_device_details(crypto_devices)
get_device_details(eventdev_devices)
get_device_details(mempool_devices)
get_device_details(compress_devices)
get_device_details(misc_devices)
def is_mount(mount_path):
with open("/proc/mounts", "r") as mounts:
for line in mounts:
if mount_path in line.split():
return True
return False
def find_and_set_rte_sdk(args, settings):
if args.rte_sdk:
settings.rte_sdk = args.rte_sdk
return
if os.environ.get("RTE_SDK"):
settings.rte_sdk = os.environ.get("RTE_SDK")
return
if hasattr(settings, "rte_sdk") and settings.rte_sdk:
return
raise RuntimeError(
"Cannot find RTE_SDK. Searched in the settings file, OS env variables and command-line arguments"
)
def verify_rte_sdk(args, settings):
find_and_set_rte_sdk(args, settings)
if not os.path.exists(settings.rte_sdk):
raise FileExistsError("RTE_SDK path: '%s' does not exist" % settings.rte_sdk)
def check_huge_pages():
with open("/proc/meminfo", "r") as meminfo:
for line in meminfo:
if line.startswith("HugePages_Total"):
return line.split()[1]
return 0
def setup_huge_pages(amount):
if check_huge_pages() == amount:
return
nr_hugepages_path = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"
with open(nr_hugepages_path, "w") as nr_huge:
nr_huge.write(str(amount))
mount_dir = "/mnt/huge"
if not is_mount(mount_dir):
check_output(["mount", "-t", "hugetlbfs", "nodev", mount_dir])
logger.info("set up hugepages to %s", amount)
def restore_huge_pages():
if check_huge_pages() == 0:
return
nr_hugepages_path = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"
with open(nr_hugepages_path, "w") as nr_huge:
nr_huge.write("0")
mount_dir = "/mnt/huge"
if is_mount(mount_dir):
check_output(["umount", mount_dir])
logger.info("removed hugepages")
def is_module_loaded(module):
for line in check_output(["lsmod"]).decode("utf-8").splitlines():
if module in line.split():
return True
return False
def load_dpdk_module(module, settings):
if is_module_loaded(module):
logger.info("module '%s' already loaded", module)
return
if module in ["uio_pci_generic", "vfio-pci"]:
output = check_output(["modprobe", module], stderr=subprocess.STDOUT)
if output:
raise RuntimeError(
"Something went wrong with adding '%s' kernel module: %s"
% (module, output.decode("utf-8"))
)
settings.dpdk_module = module
logger.info("loaded kernel module '%s'", module)
elif module == "igb_uio":
if not hasattr(settings, "rte_sdk") or not settings.rte_sdk:
raise RuntimeError("Cannot find RTE_SDK value in '%s'" % _SETTINGS_FILE)
output = check_output(["modprobe", "uio"], stderr=subprocess.STDOUT)
if output:
raise RuntimeError(
"Something went wrong with adding 'uio' kernel module: %s"
% output.decode("utf-8")
)
logger.info("loaded kernel module 'uio'")
output = check_output(
["insmod", "%s/build/kmod/igb_uio.ko" % settings.rte_sdk],
stderr=subprocess.STDOUT,
)
if output:
output = check_output(
["modprobe", "igb_uio"],
stderr=subprocess.STDOUT,
)
if output:
raise RuntimeError(
"Something went wrong with adding 'igb_uio' kernel module: %s"
% output.decode("utf-8")
)
settings.dpdk_module = module
logger.info("loaded DPDK kernel module 'igb_uio'")
else:
raise RuntimeError("Module '%s' is not supported" % module)
settings.dpdk_module = module
def remove_dpdk_module(module, settings):
if not module:
settings.dpdk_module = None
return
if not is_module_loaded(module):
logger.warning("DPDK module not loaded")
settings.dpdk_module = None
return
if module in ["uio_pci_generic", "vfio-pci"]:
output = check_output(["modprobe", "-r", module], stderr=subprocess.STDOUT)
if output:
raise RuntimeError(
"Something went wrong with removing '%s' kernel module: %s"
% (module, output.decode("utf-8"))
)
logger.info("removed kernel module '%s'", module)
elif module == "igb_uio":
output = check_output(["rmmod", "igb_uio"], stderr=subprocess.STDOUT)
if output:
raise RuntimeError(
"Something went wrong with removing 'igb_uio' kernel module: %s"
% output.decode("utf-8")
)
logger.info("removed 'igb_uio' kernel module")
settings.dpdk_module = None
def insert_kni_module(args, settings):
kni_module = "rte_kni"
if is_module_loaded(kni_module):
logger.info("KNI module already loaded")
return
if not hasattr(settings, "rte_sdk") or not settings.rte_sdk:
raise RuntimeError("Cannot find RTE_SDK value in '%s'" % _SETTINGS_FILE)
kni_module_path = glob.glob(
f"{settings.rte_sdk}/**/{kni_module}.ko", recursive=True
)
if not kni_module_path:
raise RuntimeError(f"Cannot find KNI kernel module {kni_module}")
kmod_params = args.kni_params
output = check_output(
["insmod", kni_module_path[0], kmod_params],
stderr=subprocess.STDOUT,
)
if output:
raise RuntimeError(
"Something went wrong with adding KNI kernel module: %s"
% output.decode("utf-8")
)
settings.kni_module = kni_module
logger.info("loaded KNI module")
def remove_kni_module(settings):
kni_module = "rte_kni"
if not is_module_loaded(kni_module):
logger.warning("KNI module not loaded")
settings.kni_module = None
return
output = check_output(["rmmod", kni_module], stderr=subprocess.STDOUT)
if output:
raise RuntimeError(
"Something went wrong with removing KNI module: %s" % output.decode("utf-8")
)
logger.info("removed KNI kernel module")
settings.kni_module = None
def get_interface_command(interface, up_or_down):
if _IP_TOOLS == "ip":
return ["ip", "link", "set", "dev", interface, up_or_down]
return ["ifconfig", interface, up_or_down]
def set_interfaces_down(interfaces, settings):
for interface in interfaces:
output = check_output(
get_interface_command(interface, "down"), stderr=subprocess.STDOUT
)
if output:
if ( msg in output.decode("utf-8")
for msg in ["No such device", "Cannot find device"]
):
raise RuntimeError("Cannot find interface '%s'" % interface)
raise RuntimeError(
"Cannot shut down interface %s: %s"
% (interface, output.decode("utf-8"))
)
logger.info("set interface '%s' down", interface)
settings.interfaces = json.dumps(interfaces)
def set_interfaces_up(interfaces, settings):
for interface in interfaces:
output = check_output(
get_interface_command(interface, "up"), stderr=subprocess.STDOUT
)
if output:
if "No such device" in output.decode("utf-8"):
raise RuntimeError("cannot find interface '%s'" % interface)
logger.error(
"error restoring interface '%s': %s", interface, output.decode("utf-8")
)
else:
logger.info("restored interface '%s'", interface)
settings.interfaces = None
def is_bound_to_driver(dev_id, driver):
dev = _DEVICES[dev_id]
return has_driver(dev_id) and dev["Driver_str"] == driver
def bind_interfaces(dpdk_module, interfaces, interface_infos, settings):
load_device_data()
for interface in interfaces:
try:
dev_id = dev_id_from_dev_name(interface)
except ValueError:
raise RuntimeError( "cannot find interface '%s'", interface
)
if is_bound_to_driver(dev_id, dpdk_module):
logger.info(
"interface '%s' is already bound to DPDK driver '%s'",
interface,
dpdk_module,
)
interface_infos.append(
{"dev_id": dev_id, "saved_driver": _DEVICES[dev_id]["Module_str"]}
)
continue
saved_driver = bind_one(dev_id, dpdk_module, quiet=False, force=False)
if saved_driver:
interface_infos.append(
{
"dev_id": dev_id,
"saved_driver": saved_driver,
}
)
logger.info(
"bound interface '%s' ['%s'] to '%s'", interface, dev_id, dpdk_module
)
else:
raise RuntimeError("Error binding interface '%s'" % interface)
settings.interface_infos = json.dumps(interface_infos)
def unbind_interfaces(interface_infos, settings):
load_device_data()
for interface_info in interface_infos:
bind_one(
interface_info["dev_id"],
interface_info["saved_driver"],
quiet=True,
force=False,
)
logger.info(
"bound device '%s' back to '%s'",
interface_info["dev_id"],
interface_info["saved_driver"],
)
settings.interface_infos = None
def do_restore(dpdk_module, interfaces, interface_infos, settings, kni_module=None):
try:
restore_huge_pages()
unbind_interfaces(interface_infos, settings)
time.sleep(1)
set_interfaces_up(interfaces, settings)
remove_dpdk_module(dpdk_module, settings)
if kni_module:
remove_kni_module(settings)
except PermissionError:
logger.error("insufficient privileges. Please run this utility as 'sudo'")
raise
except Exception as exc:
logger.error("error restoring system: %s", exc)
raise exc
def handle_restore(_args, settings):
dpdk_module = getattr(settings, "dpdk_module", None)
kni_module = getattr(settings, "kni_module", None)
interfaces = json.loads(getattr(settings, "interfaces", "[]"))
interface_infos = json.loads(getattr(settings, "interface_infos", "[]"))
do_restore(
dpdk_module, interfaces, interface_infos, settings, kni_module=kni_module
)
logger.info("RESTORE COMPLETE")
def handle_setup(args, settings):
interface_infos = []
try:
verify_rte_sdk(args, settings)
except Exception as exc:
logger.error(exc)
raise
try:
setup_huge_pages(args.huge_pages)
load_dpdk_module(args.dpdk_module, settings)
if args.load_kni:
insert_kni_module(args, settings)
set_interfaces_down(args.interface, settings)
bind_interfaces(args.dpdk_module, args.interface, interface_infos, settings)
logger.info("SETUP COMPLETE")
except PermissionError:
logger.error("insufficient privileges. Please run this utility as 'sudo'")
raise
except Exception as exc:
logger.error(exc)
logger.error("restoring settings:")
do_restore(
args.dpdk_module,
args.interface,
interface_infos,
settings,
kni_module=args.load_kni,
)
raise exc
def handle_status(_args, _settings):
show_status("all")
def parse_args():
parser = argparse.ArgumentParser(
description=usage(), formatter_class=argparse.RawTextHelpFormatter
)
subparsers = parser.add_subparsers(title="Available options", dest="cmd")
subparsers.required = True
parser_setup = subparsers.add_parser("setup", help="setup DPDK on your machine")
parser_setup.set_defaults(func=handle_setup)
parser_setup.add_argument(
"-g",
"--huge-pages",
metavar="AMOUNT",
type=int,
required=True,
help="amount of huge pages to allocate (huge pages are needed for DPDK's memory allocations)", )
parser_setup.add_argument(
"-i",
"--interface",
metavar="NIC_NAME",
type=str,
nargs="+",
required=True,
help="the name of a network interface (e.g eth1) that will be unbound from Linux and move to DPDK control", )
parser_setup.add_argument(
"-m",
"--dpdk-module",
choices=["igb_uio", "uio_pci_generic", "vfio-pci"],
default="igb_uio",
help="the DPDK module to install. If not specified the default is 'igb_uio'",
)
parser_setup.add_argument(
"-k",
"--load-kni",
action="store_true",
help="install the KNI kernel module (not loaded by default)",
)
parser_setup.add_argument(
"-p",
"--kni-params",
type=str,
default="carrier=on",
help="optional parameters for installing the KNI kernel module",
)
parser_setup.add_argument(
"-v",
"--verbose",
action="store_true",
help="print more verbose output",
)
parser_setup.add_argument(
"-r",
"--rte-sdk",
type=str,
help="DPDK home directory",
)
parser_status = subparsers.add_parser(
"status", help="display current Ethernet device settings"
)
parser_status.set_defaults(func=handle_status)
parser_status.add_argument(
"-v",
"--verbose",
action="store_true",
help="print more verbose output",
)
parser_restore = subparsers.add_parser(
"restore", help="tear down DPDK and restore the system to its original state"
)
parser_restore.set_defaults(func=handle_restore)
parser_restore.add_argument(
"-v",
"--verbose",
action="store_true",
help="print more verbose output",
)
return parser.parse_args()
def init_logger(args):
if args.verbose:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
log_format = "[%(levelname)s] %(message)s"
formatter = logging.Formatter(log_format)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
class Settings:
@classmethod
def load(cls, settings_file_path):
settings = cls()
if os.path.exists(settings_file_path):
logger.debug("loading from settings file '%s':", settings_file_path)
with open(settings_file_path, "r") as settings_file:
for line in settings_file.readlines():
line = line.rstrip()
if line:
logger.debug(" %s", line)
[key, value] = line.split("=")
setattr(settings, key.lower(), value)
return settings
def save(self, settings_file_path):
with open(settings_file_path, "w") as settings_file:
logger.debug("saving to settings file '%s':", settings_file_path)
for attr, value in self.__dict__.items():
if value:
line = "%s=%s" % (attr.upper(), value)
logger.debug(" %s", line)
settings_file.write("{line}\n".format(line=line))
def main():
global _IP_TOOLS
with open(os.devnull, "w") as devnull:
if subprocess.call(["which", "lspci"], stdout=devnull, stderr=devnull) != 0:
sys.exit("'lspci' not found - please install 'pciutils'")
ip_installed = (
subprocess.call(["which", "ip"], stdout=devnull, stderr=devnull) == 0
)
ifconfig_installed = (
subprocess.call(["which", "ifconfig"], stdout=devnull, stderr=devnull) == 0
)
if ip_installed:
_IP_TOOLS = "ip"
elif ifconfig_installed:
_IP_TOOLS = "ifconfig"
else:
sys.exit(
"both 'ip' and 'ifconfig' are not found - please install one of them"
)
load_device_data()
args = parse_args()
init_logger(args)
settings_file_full_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
_SETTINGS_FILE,
)
settings = Settings.load(settings_file_full_path)
try:
args.func(args, settings)
settings.save(settings_file_full_path)
except: pass
if __name__ == "__main__":
main()