#!/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"
