feat: igb nic, jumbo frames and tap offloads on the guest link

This commit is contained in:
2026-09-06 05:39:38 +02:00
parent 91fd1c45e1
commit f90745e68e
6 changed files with 45 additions and 27 deletions

View File

@@ -1,8 +0,0 @@
# vfio-native: the emulated e1000e NIC's TX checksum and segmentation offloads
# corrupt packets on the host side of a libvirt tap. SMB tolerates it; SSH fails
# with "Corrupted MAC on input" and any integrity-checked protocol breaks.
# Measured on a Zen 4 host with QEMU 11.1.1. Disabling the offloads on every
# libvirt tap as it appears fixes it; on a host<->guest link the throughput
# cost is not measurable. libvirt's <driver><host .../> attributes are ignored
# for e1000e, and a libvirt hook must not call virsh, hence udev.
ACTION=="add", SUBSYSTEM=="net", KERNEL=="vnet*", RUN+="/usr/bin/ethtool -K %k tx off gso off gro off tso off"

View File

@@ -0,0 +1,15 @@
#!/bin/bash
# libvirt qemu hook: turn GSO and GRO on for the guest's tap.
#
# QEMU leaves them off and sets the tap up after udev has run, so it has to
# happen here. Paired with MTU 9000 they are the difference between 2.5 and
# 14 Gbit/s into the guest; neither helps alone. Tap names come from the domain
# XML on stdin, so the hook never calls virsh, which would deadlock libvirtd.
[ "$2" = started ] || exit 0
for tap in $(grep -oE "<target dev='(vnet|tap|macvtap)[^']*'" | sed "s/.*dev='//; s/'$//"); do
ethtool -K "$tap" gso on gro on 2>/dev/null
done
exit 0

View File

@@ -661,7 +661,11 @@ if conformant and E["CONVERT"] == "1":
s = re.sub(r"\s*<input type='[^']*' bus='virtio'/>", "", s)
s = re.sub(r"<memballoon model='virtio'>.*?</memballoon>", "<memballoon model='none'/>", s, flags=re.S)
s = re.sub(r"<memballoon model='virtio'/>", "<memballoon model='none'/>", s)
s = re.sub(r"<model type='virtio'/>(\s*<driver [^/]*/>)?", "<model type='e1000e'/>", s)
# jumbo frames are the single biggest win on the host<->guest link: the emulated
# NIC is packet-rate bound, so 9000-byte frames cut the per-packet cost the guest
# pays on receive. Measured 2922 -> 14232 Mbit/s inbound on igb, byte-exact clean.
s = re.sub(r"<model type='virtio'/>(\s*<driver [^/]*/>)?",
"<model type='igb'/>\n <mtu size='9000'/>", s)
if prof == "full":
s = re.sub(r"<video>.*?</video>", "<video>\n <model type='none'/>\n </video>", s, flags=re.S)
@@ -827,10 +831,19 @@ if [ "$PROFILE" = full ]; then
fi
if [ ! -e /usr/lib/udev/rules.d/99-vfio-native-vnet-offload.rules ] && [ ! -e /etc/udev/rules.d/99-vfio-native-vnet-offload.rules ]; then
echo "NOTE: the e1000e offload udev rule is not installed. SSH into the guest will fail with"
echo "NOTE: the NIC offload udev rule is not installed. SSH into the guest will fail with"
echo " 'Corrupted MAC on input' until it is:"
echo " sudo install -Dm644 $SELF/scripts/99-vfio-native-vnet-offload.rules /etc/udev/rules.d/ && sudo udevadm control --reload-rules"
fi
NET=$("${C[@]}" dumpxml "$DOM" 2>/dev/null | sed -n "s/.*<source network='\([^']*\)'.*/\1/p" | head -1)
NETMTU=$([ -n "$NET" ] && "${C[@]}" net-dumpxml --inactive "$NET" 2>/dev/null | sed -n "s/.*<mtu size='\([0-9]*\)'.*/\1/p")
if [ -n "$NET" ] && [ "${NETMTU:-1500}" -lt 9000 ]; then
echo "NOTE: the guest interface asks for MTU 9000 but libvirt network '$NET' is at ${NETMTU:-1500}."
echo " Jumbo needs both ends; inbound throughput is ~5x with it. Add <mtu size='9000'/> to"
echo " the network and restart it: virsh net-edit $NET && virsh net-destroy $NET && virsh net-start $NET"
echo " Then in the guest: set the NIC's Jumbo Packet to 9014 and the interface MTU to 9000."
fi
gov=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || echo unknown)
[ "$gov" = performance ] || echo "host governor is '$gov' - run: sudo cpupower frequency-set -g performance"