* [PATCH] usertools/dpdk-devbind: add basic FreeBSD support
@ 2025-12-10 12:38 Bruce Richardson
0 siblings, 0 replies; only message in thread
From: Bruce Richardson @ 2025-12-10 12:38 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
Add support for using dpdk-devbind to query device bind status on
FreeBSD. For other ops, bind and unbind, which are unsupported,
report a proper errors message indicating the unsupported status
and pointing the user to the docs.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
usertools/dpdk-devbind.py | 96 ++++++++++++++++++++++++++++++++-------
1 file changed, 80 insertions(+), 16 deletions(-)
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 06ae25aa34..93f2383dff 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -15,6 +15,12 @@
from os.path import exists, basename
from os.path import join as path_join
+is_linux = sys.platform.startswith('linux')
+is_bsd = sys.platform.startswith('freebsd')
+freebsd_err_unsupported_string = """Error: This operation is unsupported on FreeBSD.
+See FreeBSD Getting Started Guide for details on binding and unbinding devices.
+"""
+
# The PCI base class for all devices
network_class = {'Class': '02', 'Vendor': None, 'Device': None,
'SVendor': None, 'SDevice': None}
@@ -106,7 +112,7 @@
# 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"]
+dpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] if is_linux else ["nic_uio"]
# list of currently loaded kernel modules
loaded_modules = None
@@ -124,6 +130,9 @@
def module_is_loaded(module):
global loaded_modules
+ if is_bsd:
+ return subprocess.run(["kldstat", "-qn", module]).returncode == 0
+
if module == 'vfio_pci':
module = 'vfio-pci'
@@ -214,12 +223,8 @@ def clear_data():
devices = {}
-def get_device_details(devices_type):
- '''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.'''
+def get_basic_devinfo_linux(devices_type):
global devices
- global dpdk_drivers
# first loop through and read details for all devices
# request machine readable format, with numeric IDs and String
@@ -248,7 +253,53 @@ def get_device_details(devices_type):
dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
.rstrip("]").lstrip("[")
- if devices_type == network_devices:
+
+def get_basic_devinfo_bsd(devices_type):
+ global devices
+
+ dev_lines = subprocess.check_output(["pciconf", "-l"]).decode("utf8").splitlines()
+ netifs = subprocess.check_output(["ifconfig", "-a"]).decode("utf8").splitlines()
+ for dev_line in dev_lines:
+ dev = {}
+ name_addr, fields = dev_line.split(maxsplit=1)
+ devname, addr = name_addr.split('@')
+ dev["Slot"] = addr
+ dev["Slot_str"] = addr
+ dev["Driver_str"] = devname[:-1]
+ if devices_type == network_devices:
+ iflines = [ln for ln in netifs if ln.startswith(f"{devname}:")]
+ if iflines:
+ dev["Interface"] = devname
+ fields = fields.split()
+ for field in fields:
+ name, value = field.split("=")
+ name = name.title()
+ if name.startswith("Sub"):
+ name = "S" + name[3:].title()
+ dev[name + "_str"] = value
+ dev[name] = value[2:] if value.startswith("0x") else value
+ # explicitly query the device name string
+ devdetails = subprocess.check_output(["pciconf", "-lv", addr]).decode("utf8")
+ for devline in devdetails.splitlines():
+ if devline.lstrip().startswith("device") and "=" in devline:
+ dev["Device_str"] = devline.split("=")[1].strip().strip("'")
+ if device_type_match(dev, devices_type):
+ devices[addr] = dict(dev)
+
+
+def get_device_details(devices_type):
+ '''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
+
+ if is_linux:
+ get_basic_devinfo_linux(devices_type)
+ else:
+ get_basic_devinfo_bsd(devices_type)
+
+ if is_linux and devices_type == network_devices:
# check what is the interface if any for an ssh connection if
# any to this host, so we can mark it later.
ssh_if = []
@@ -271,7 +322,7 @@ def get_device_details(devices_type):
# No need to probe lspci
devices[d].update(get_pci_device_details(d, False).items())
- if devices_type == network_devices:
+ if is_linux and devices_type == network_devices:
for _if in ssh_if:
if _if in devices[d]["Interface"].split(","):
devices[d]["Ssh_if"] = True
@@ -470,6 +521,9 @@ def bind_one(dev_id, driver, force):
def unbind_all(dev_list, force=False):
"""Unbind method, takes a list of device locations"""
+ if is_bsd:
+ sys.exit(freebsd_err_unsupported_string)
+
if dev_list[0] == "dpdk":
for d in devices.keys():
if "Driver_str" in devices[d]:
@@ -520,6 +574,9 @@ def bind_all(dev_list, driver, force=False):
"""Bind method, takes a list of device locations"""
global devices
+ if is_bsd:
+ sys.exit(freebsd_err_unsupported_string)
+
# a common user error is to forget to specify the driver the devices need to
# be bound to. check if the driver is a valid device, and if it is, show
# a meaningful error.
@@ -719,10 +776,7 @@ def parse_args():
global vfio_uid
global vfio_gid
- parser = argparse.ArgumentParser(
- description='Utility to bind and unbind devices from Linux kernel',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- epilog="""
+ epilog_linux = """
Examples:
---------
@@ -740,7 +794,16 @@ def parse_args():
To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
%(prog)s -b ixgbe 02:00.0 02:00.1
-""")
+"""
+ epilog_bsd = """
+NOTE: Only query options, -s/--status and --status-dev, are supported on FreeBSD.
+"""
+
+ epilog = epilog_linux if is_linux else epilog_bsd
+ parser = argparse.ArgumentParser(
+ description='Utility to bind and unbind devices from OS kernel',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog=epilog)
parser.add_argument(
'-s',
@@ -866,12 +929,13 @@ def do_arg_actions():
def main():
'''program main function'''
- # check if lspci is installed, suppress any output
+ # check if lspci/pciconf is installed, suppress any output
+ pcitool = 'lspci' if is_linux else 'pciconf'
with open(os.devnull, 'w') as devnull:
- ret = subprocess.call(['which', 'lspci'],
+ ret = subprocess.call(['which', pcitool],
stdout=devnull, stderr=devnull)
if ret != 0:
- sys.exit("'lspci' not found - please install 'pciutils'")
+ sys.exit(f"'{pcitool}' not found - please install relevant package, e.g. 'pciutils'")
parse_args()
check_modules()
clear_data()
--
2.51.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-12-10 12:39 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-10 12:38 [PATCH] usertools/dpdk-devbind: add basic FreeBSD support Bruce Richardson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).