#!/bin/bash # Waits for a just-started guest's network to actually come up, then turns # kvm_amd cpuid_passthrough on. # # The readiness signal is the guest's own tap RX counter: it is fresh every boot, # it needs nothing enabled inside the guest (no SSH, no RDP, no agent), and it only # moves once the guest's NIC driver has really loaded - which is well past the CPU # enumeration that the switch must not change under. A DHCP lease left over from a # previous boot cannot trip it early. # # Launched as a transient systemd unit by the cpuid-passthrough hook, so it is free # to call virsh (the hook itself must not - that deadlocks libvirtd). DOMAIN=$1 BRAND=$2 PARAM=/sys/module/kvm_amd/parameters V="virsh -c qemu:///system" running() { [ "$($V domstate "$DOMAIN" 2>/dev/null)" = running ]; } tap="" i=0 for _ in $(seq 1 65); do # ~195 s cap, then flip anyway if still up i=$((i + 1)) running || { sleep 3; continue; } # not "running" yet at prepare time - wait [ -z "$tap" ] && tap=$($V domiflist "$DOMAIN" 2>/dev/null | awk '$1 ~ /^(vnet|tap|macvtap)/ {print $1; exit}') rx="/sys/class/net/$tap/statistics/rx_packets" # the iteration floor keeps a stray pre-OS packet (a UEFI netboot attempt) from # tripping the flip before the guest is even past its interrupt and timer setup if [ "$i" -ge 4 ] && [ -n "$tap" ] && [ -r "$rx" ] && [ "$(cat "$rx" 2>/dev/null || echo 0)" -ge 4 ]; then break fi sleep 3 done running || exit 0 # guest went away before it came up printf '%s' "$BRAND" > "$PARAM/brand_string" echo Y > "$PARAM/cpuid_passthrough" logger -t vfio-cpuid "$DOMAIN network up: cpuid_passthrough=Y"