
Some checks failed
Bump build.func Revision / bump-revision (push) Has been cancelled
Replaces direct USB and GPU passthrough configuration in build.func with a unified select_hw_passthrough function. Refactors passthrough.func to add interactive selection for VAAPI and NVIDIA devices, streamlines device detection, and updates userland installation functions for both VAAPI and NVIDIA. Cleans up and simplifies device mapping and group ID logic.
286 lines
8.1 KiB
Bash
286 lines
8.1 KiB
Bash
#!/usr/bin/env bash
|
||
# passthrough.func — host-side passthrough logic (VAAPI & NVIDIA) for LXC
|
||
# This file ONLY touches host config (/etc/pve/lxc/<CTID>.conf) and whiptail.
|
||
# Inside-CT package setup lives in *_inside_setup (called from build.func).
|
||
|
||
# --------------------------- Common helpers -----------------------------------
|
||
|
||
_whiptail_dims() {
|
||
local n="$1" L="$2"
|
||
local maxW=$((L + 8))
|
||
((maxW < 70)) && maxW=70
|
||
((maxW > 100)) && maxW=100
|
||
local H=$((10 + n * 2))
|
||
((H > 22)) && H=22
|
||
echo "$H $maxW"
|
||
}
|
||
|
||
select_hw_passthrough() {
|
||
local CTID="$1" CTTYPE="$2" APP="$3"
|
||
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
||
|
||
local choices=()
|
||
[[ -d /dev/dri ]] && choices+=("VAAPI" "Intel/AMD GPU via VAAPI" OFF)
|
||
compgen -G "/dev/nvidia*" >/dev/null && choices+=("NVIDIA" "NVIDIA GPU passthrough" OFF)
|
||
|
||
[[ ${#choices[@]} -eq 0 ]] && {
|
||
msg_info "No GPU devices detected"
|
||
return
|
||
}
|
||
|
||
local HEIGHT WIDTH
|
||
HEIGHT=12
|
||
WIDTH=70
|
||
local SELECTED
|
||
SELECTED=$(whiptail --title "GPU Passthrough" \
|
||
--checklist "Select GPU passthrough for CT $CTID:" $HEIGHT $WIDTH 2 \
|
||
"${choices[@]}" 3>&1 1>&2 2>&3) || return
|
||
|
||
# export flags for install.sh
|
||
for sel in $SELECTED; do
|
||
case "$sel" in
|
||
"\"VAAPI\"")
|
||
export ENABLE_VAAPI=1
|
||
vaapi_select_and_apply "$CTID" "$CTTYPE"
|
||
;;
|
||
"\"NVIDIA\"")
|
||
export ENABLE_NVIDIA=1
|
||
nvidia_passthrough_to_lxc "$CTID" "$CTTYPE"
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
# Apps that benefit from GPU passthrough (VAAPI + NVIDIA)
|
||
# Apps that benefit from GPU passthrough (VAAPI + NVIDIA)
|
||
_GPU_APPS=(
|
||
immich
|
||
Channels
|
||
Emby
|
||
ErsatzTV
|
||
Frigate
|
||
Jellyfin
|
||
Plex
|
||
Scrypted
|
||
Tdarr
|
||
Unmanic
|
||
Ollama
|
||
FileFlows
|
||
"Open WebUI"
|
||
Tunarr
|
||
Debian
|
||
)
|
||
|
||
# ------------------------------ USB -------------------------------------------
|
||
|
||
usb_handle_passthrough() {
|
||
local CTID="$1" CTTYPE="$2"
|
||
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
||
|
||
[[ "$CTTYPE" != "0" ]] && return 0 # USB passthrough only for privileged CTs
|
||
|
||
cat <<EOF >>"$LXC_CONFIG"
|
||
# USB passthrough
|
||
lxc.cgroup2.devices.allow: a
|
||
lxc.cap.drop:
|
||
lxc.cgroup2.devices.allow: c 188:* rwm
|
||
lxc.cgroup2.devices.allow: c 189:* rwm
|
||
lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir
|
||
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
|
||
lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file
|
||
lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file
|
||
lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file
|
||
EOF
|
||
}
|
||
|
||
# ------------------------------ VAAPI -----------------------------------------
|
||
|
||
_vaapi_gid() {
|
||
local g="$1" gid
|
||
gid="$(getent group "$g" | cut -d: -f3)"
|
||
case "$g" in
|
||
video) echo "${gid:-44}" ;;
|
||
render) echo "${gid:-104}" ;;
|
||
*) echo "${gid:-44}" ;;
|
||
esac
|
||
}
|
||
|
||
_vaapi_pairs() {
|
||
local seen=() by real id idx card pci pci_info name
|
||
shopt -s nullglob
|
||
for by in /dev/dri/by-path/*-render /dev/dri/renderD*; do
|
||
[[ -e "$by" ]] || continue
|
||
real="$(readlink -f "$by" || true)"
|
||
[[ -e "$real" ]] || continue
|
||
id="$(basename "$real")"
|
||
[[ " ${seen[*]} " == *" $id "* ]] && continue
|
||
seen+=("$id")
|
||
|
||
idx="${id#renderD}"
|
||
[[ "$idx" =~ ^[0-9]+$ ]] && idx=$((idx - 128)) || idx=0
|
||
card="/dev/dri/card${idx}"
|
||
[[ -e "$card" ]] || card=""
|
||
|
||
if [[ "$by" == *"/by-path/"* ]]; then
|
||
pci="$(basename "$by" | sed -E 's/^pci-([0-9a-fA-F:.]+)-render/\1/')"
|
||
pci_info="$(lspci -nn 2>/dev/null | grep -i "${pci#0000:}" || true)"
|
||
name="${pci_info#*: }"
|
||
[[ -z "$name" ]] && name="GPU ${pci}"
|
||
else
|
||
name="DRM $(basename "$real")"
|
||
fi
|
||
|
||
label="$(basename "$real")"
|
||
[[ -n "$card" ]] && label+=" + $(basename "$card")"
|
||
label+=" – ${name}"
|
||
printf "%s:%s\t%s\n" "$real" "$card" "$label"
|
||
done
|
||
shopt -u nullglob
|
||
}
|
||
|
||
vaapi_select_and_apply() {
|
||
local CTID="$1" CTTYPE="$2"
|
||
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
||
|
||
mapfile -t pairs < <(_vaapi_pairs)
|
||
((${#pairs[@]} == 0)) && {
|
||
msg_warn "No VAAPI devices detected – skipping."
|
||
return
|
||
}
|
||
|
||
local items=() maxlen=0
|
||
for p in "${pairs[@]}"; do
|
||
local devs="${p%%$'\t'*}" label="${p#*$'\t'}"
|
||
items+=("$devs" "$label" "OFF")
|
||
((${#label} > maxlen)) && maxlen=${#label}
|
||
done
|
||
read -r h w < <(_whiptail_dims $((${#items[@]} / 3)) "$maxlen")
|
||
|
||
local SELECTED
|
||
SELECTED="$(whiptail --title "VAAPI Device Selection" \
|
||
--checklist "Select VAAPI devices for CT $CTID:" "$h" "$w" 6 \
|
||
"${items[@]}" 3>&1 1>&2 2>&3)" || {
|
||
msg_warn "VAAPI selection cancelled."
|
||
return
|
||
}
|
||
[[ -z "$SELECTED" ]] && {
|
||
msg_warn "No VAAPI devices selected."
|
||
return
|
||
}
|
||
|
||
local DID_MOUNT_DRI=0 idx=0
|
||
for dev in $SELECTED; do
|
||
dev="${dev%\"}"
|
||
dev="${dev#\"}"
|
||
IFS=":" read -r path card <<<"$dev"
|
||
for d in "$path" "$card"; do
|
||
[[ -n "$d" && -e "$d" ]] || continue
|
||
if [[ "$CTTYPE" == "0" ]]; then
|
||
[[ $DID_MOUNT_DRI -eq 0 && -d /dev/dri ]] && {
|
||
echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
|
||
DID_MOUNT_DRI=1
|
||
}
|
||
if mm=$(stat -c '%t:%T' "$d" | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}'); then
|
||
echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG"
|
||
echo "lxc.mount.entry: $d $d none bind,optional,create=file" >>"$LXC_CONFIG"
|
||
fi
|
||
else
|
||
gid=$([[ "$d" =~ renderD ]] && _vaapi_gid render || _vaapi_gid video)
|
||
echo "dev${idx}: $d,gid=${gid}" >>"$LXC_CONFIG"
|
||
idx=$((idx + 1))
|
||
fi
|
||
done
|
||
done
|
||
[[ "$CTTYPE" == "0" ]] && cat <<'EOF' >>"$LXC_CONFIG"
|
||
# VAAPI fallback
|
||
lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir
|
||
lxc.cgroup2.devices.allow: c 226:* rwm
|
||
EOF
|
||
}
|
||
|
||
# ----------------------------- NVIDIA -----------------------------------------
|
||
|
||
nvidia_passthrough_to_lxc() {
|
||
local CTID="$1" CTTYPE="$2"
|
||
local LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
||
local found=0
|
||
|
||
for dev in /dev/nvidia*; do
|
||
[[ -e "$dev" ]] || continue
|
||
found=1
|
||
if mm="$(stat -c '%t:%T' "$dev" | awk -F: '{printf "%d:%d","0x"$1,"0x"$2}')"; then
|
||
echo "lxc.cgroup2.devices.allow: c $mm rwm" >>"$LXC_CONFIG"
|
||
echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
|
||
fi
|
||
done
|
||
((found == 0)) && {
|
||
msg_warn "No NVIDIA devices found."
|
||
return
|
||
}
|
||
|
||
[[ -d /dev/dri && "$CTTYPE" == "0" ]] && echo "lxc.mount.entry: /dev/dri /dev/dri none bind,optional,create=dir" >>"$LXC_CONFIG"
|
||
msg_ok "NVIDIA devices mapped to CT ${CTID}"
|
||
}
|
||
|
||
install_vaapi_userland_interactive() {
|
||
. /etc/os-release
|
||
if [[ "$VERSION_CODENAME" == "trixie" ]]; then
|
||
read -r -p "${TAB3}Do you need the intel-media-va-driver-non-free driver for HW encoding (Debian 13 only)? <y/N> " prompt
|
||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||
msg_info "Installing Intel Hardware Acceleration (non-free)"
|
||
cat <<'EOF' >/etc/apt/sources.list.d/non-free.sources
|
||
Types: deb deb-src
|
||
URIs: http://deb.debian.org/debian
|
||
Suites: trixie
|
||
Components: non-free non-free-firmware
|
||
|
||
Types: deb deb-src
|
||
URIs: http://deb.debian.org/debian-security
|
||
Suites: trixie-security
|
||
Components: non-free non-free-firmware
|
||
|
||
Types: deb deb-src
|
||
URIs: http://deb.debian.org/debian
|
||
Suites: trixie-updates
|
||
Components: non-free non-free-firmware
|
||
EOF
|
||
$STD apt-get update
|
||
$STD apt-get install -y \
|
||
intel-media-va-driver-non-free \
|
||
ocl-icd-libopencl1 \
|
||
mesa-opencl-icd \
|
||
mesa-va-drivers \
|
||
libvpl2 \
|
||
vainfo \
|
||
intel-gpu-tools
|
||
msg_ok "Installed Intel Hardware Acceleration (non-free)"
|
||
return
|
||
fi
|
||
fi
|
||
|
||
msg_info "Installing Intel Hardware Acceleration (open packages)"
|
||
$STD apt-get update
|
||
$STD apt-get install -y \
|
||
va-driver-all \
|
||
ocl-icd-libopencl1 \
|
||
mesa-opencl-icd \
|
||
mesa-va-drivers \
|
||
vainfo \
|
||
intel-gpu-tools
|
||
msg_ok "Installed Intel Hardware Acceleration (open packages)"
|
||
}
|
||
|
||
install_nvidia_userland_interactive() {
|
||
msg_info "Installing NVIDIA Userland"
|
||
$STD apt-get update
|
||
$STD apt-get install -y \
|
||
nvidia-driver \
|
||
nvidia-utils \
|
||
libnvidia-encode1 \
|
||
libcuda1 || {
|
||
msg_error "Failed to install NVIDIA packages"
|
||
return 1
|
||
}
|
||
msg_ok "Installed NVIDIA Userland"
|
||
}
|