Add initial PCI pass-through support

This commit is contained in:
Albrecht Lohofener
2025-01-10 12:36:23 +01:00
parent 3df7423a19
commit 2bb5a119fb
7 changed files with 104 additions and 6 deletions
+4 -1
View File
@@ -65,6 +65,7 @@ RUN echo "Building for platform '$TARGETPLATFORM'" \
netcat-openbsd \
uuidgen \
usbutils \
pciutils \
openssh-client \
util-linux-misc \
iproute2 \
@@ -152,12 +153,14 @@ RUN echo "Building for platform '$TARGETPLATFORM'" \
&& until ssh root@localhost -p $SSH_PORT "${PACKAGE_UPDATE}"; do echo "Retrying ${PACKAGE_UPDATE} ..."; sleep 1; done\
# Download Luci, qemu guest agent and mDNS support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} qemu-ga luci luci-ssl umdns losetup ${PACKAGE_EXTRA}" \
# Download USB, PCI and PCIe support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} usbutils pciutils" \
# Download Wi-Fi access point support and Wi-Fi USB devices support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} hostapd wpa-supplicant kmod-mt7921u" \
# Download celluar network support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} modemmanager kmod-usb-net-qmi-wwan luci-proto-modemmanager qmi-utils" \
# Download basic GPS support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} kmod-usb-serial usbutils minicom gpsd" \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} kmod-usb-serial minicom gpsd" \
# Add Wireguard support \
&& ssh root@localhost -p $SSH_PORT "${PACKAGE_INSTALL} wireguard-tools luci-proto-wireguard" \
# Add Power off script support \
+12 -2
View File
@@ -28,12 +28,21 @@ services:
# Make LuCI OpenWrt web interface accessible via host LAN
FORWARD_LUCI: "true"
# USB passthrough
# USB pass-through
# Format <vendorID>:<productID> like 'lsusb' is given
# Currently only two USB devices are supported
#USB_1: "0bda:8153"
#USB_2: "0e8d:7961"
# PCI and PCIe pass-through
# Host system requirements
# - IOMMU CPU feature has to enabled in bios
# - Host kernel has to switch on intel_iommu=on or amd_iommu=on
# - Host kernel module 'vfio-pci' has to exists
# - Ubuntu 24.04 is working by default
# Format <bus:device.function> like 'lspci' is given
#PCI_1: "00:1f.6"
# Define number of VM CPUs
# If unset -> 1
#CPU_COUNT: 2
@@ -48,6 +57,7 @@ services:
#OPENWRT_AFTER_BOOT_CMD: "/usr/bin/fw_wan_open_http; /usr/bin/fw_wan_open_ssh" # Example to execute two commands
#OPENWRT_AFTER_BOOT_CMD: "cat /etc/banner" # Custom commands example
#OPENWRT_AFTER_BOOT_CMD: "a=$$((1+1)); echo The result of 1+1 is $${a}" # Shell script example
#OPENWRT_AFTER_BOOT_CMD: '[ -f /etc/first_boot_over ] || { touch /etc/first_boot_over; echo "Crazy first boot"; }' # Example to run a command only once
#DEBUG: "y"
@@ -61,7 +71,7 @@ services:
# Use script /usr/bin/fw_wan_open_ssh to open the port. Works only if WAN_IF=host
#- 8022:8022
stop_grace_period: 2m
restart: on-failure
#restart: on-failure
# The following settings are mandatory to run the container
devices:
+1
View File
@@ -18,6 +18,7 @@ This Docker container brings you OpenWrt, a software-based router solution, in a
- Attaches two physical Ethernet interfaces (LAN/WAN) exclusively into the docker container
- Create virtual LAN between OpenWrt and host system (LAN only)
- USB pass-through e.g. for modem or Wi-Fi dongles
- PCI pass-through e.g. for Wi-Fi dongles or PCIe Ethernet cards
- Automatic configuration migration when OpenWrt image is updated
- Run shell commands inside OpenWrt after boot-up
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -Eeuo pipefail
. /run/helpers.sh
cleanup() {
info "Container is stopping. Performing cleanup..."
# Add your cleanup commands here
if [ -n "$PCI_1" ]; then
echo "Attaching PCI device $PCI_1 back to the host"
echo 1 > /sys/bus/pci/devices/0000:$PCI_1/remove
echo 1 > /sys/bus/pci/rescan
fi
echo "Cleanup complete."
exit 0
}
# Catch signals and call cleanup function
trap cleanup SIGTERM SIGINT
# Wait forever to prevent that multirun will stop the complete container
# This script purpose is only to catch the signal SIGTERM and SIGINT and to execute some last commands
sleep infinity & wait
+1
View File
@@ -14,6 +14,7 @@ trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
: "${LAN_IF:=""}" # Physical LAN interface name
: "${USB_1:=""}" # USB 1 vendor and device ID
: "${USB_2:=""}" # USB 2 vendor and device ID
: "${PCI_1:=""}" # PCI 1 slot (first number in lspci)
: "${FORWARD_LUCI:=""}" # Make LuCI OpenWrt web interface accessible via host LAN
: "${OPENWRT_AFTER_BOOT_CMD:=""}" # User command or script to run after OpenWrt is booted
: "${IS_U_OS_APP:=""}" # By default this container is not a u-OS app
+8 -1
View File
@@ -45,13 +45,19 @@ echo "* Content of /var/vm/openwrt_metadata.conf *" > /var/www/system_info.txt
cat /var/vm/openwrt_metadata.conf >> /var/www/system_info.txt
echo $'\n' >> /var/www/system_info.txt
echo "* Enviroment variables *" >> /var/www/system_info.txt
echo "* Environment variables *" >> /var/www/system_info.txt
export >> /var/www/system_info.txt
echo $'\n' >> /var/www/system_info.txt
echo "* USB devices *" >> /var/www/system_info.txt
set +e # Enable that the next command can fail
lsusb >> /var/www/system_info.txt
echo $'\n' >> /var/www/system_info.txt
set -e # Revert set +a
echo "* PCI devices *" >> /var/www/system_info.txt
set +e # Enable that the next command can fail
lspci >> /var/www/system_info.txt
set -e # Revert set +a
# ******* nginx handling *******
@@ -85,6 +91,7 @@ fi
# Start processes
exec multirun \
"/run/cleanup_container.sh" \
"qemu-openwrt-web-backend" \
"nginx" \
"/run/run_openwrt.sh" \
+53 -2
View File
@@ -135,6 +135,44 @@ attach_veth_if () {
fi
}
# Prepare PCI device for qemu
attach_pci_device () {
local PCI_DEVICE=$1
local PCI_PATH="/sys/bus/pci/devices/$PCI_DEVICE"
info "Preparing PCI pass-through for device $PCI_DEVICE ..."
if [ ! -e "$PCI_PATH" ]; then
echo "Error: PCI device $PCI_DEVICE not found"
exit 1
fi
# Unbind from current driver
local DRIVER=$(basename "$(readlink "$PCI_PATH/driver")" 2>/dev/null)
if [ "$DRIVER" ]; then
echo "Unbinding $PCI_DEVICE from $DRIVER"
echo "$PCI_DEVICE" > "$PCI_PATH/driver/unbind"
fi
# Ensure vfio-pci module is loaded
if ! lsmod | grep -q '^vfio_pci ' ; then
echo "Loading vfio-pci kernel module"
nsenter --target 1 --uts --net --ipc --mount modprobe vfio-pci
fi
# Bind to vfio-pci
echo "vfio-pci" > "$PCI_PATH/driver_override"
echo "$PCI_DEVICE" > /sys/bus/pci/drivers/vfio-pci/bind
# Verify binding
if [ "$(basename "$(readlink "$PCI_PATH/driver" 2>/dev/null)")" != "vfio-pci" ]; then
echo "Failed to bind $PCI_DEVICE to vfio-pci"
exit 1
fi
echo "Successfully bound $PCI_DEVICE to vfio-pci"
}
# Handle dirfferent architectures
if [ $CPU_ARCH = "aarch64" ]; then
CPU_ARGS="-M virt -bios /usr/share/qemu/edk2-aarch64-code.fd -vga none -device ramfb"
@@ -212,6 +250,20 @@ fi
USB_ARGS="${USB_1_ARGS} ${USB_2_ARGS}"
# Attaching PCI devices
PCI_ARGS=""
PCI_1_ARGS=""
if [[ -z "$PCI_1" ]]; then
PCI_1_ARGS=""
else
PCI_SLOT="0000:$PCI_1"
attach_pci_device "$PCI_SLOT"
PCI_1_ARGS="-device vfio-pci,host=$PCI_SLOT"
fi
PCI_ARGS="${PCI_1_ARGS}"
info "Booting image using $VERS..."
# See qemu command if debug is enabled
@@ -230,9 +282,8 @@ exec qemu-system-"$CPU_ARCH" \
$LAN_ARGS \
$WAN_ARGS \
$USB_ARGS \
$PCI_ARGS \
-qmp unix:/run/qmp-sock,server=on,wait=off \
-chardev socket,path=/run/qga.sock,server=on,wait=off,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
# -kernel /var/vm/kernel.bin -append "root=fe00 console=tty0" \