Fundamentos de SR-IOV en Debian 13: por qué falla y cómo depurar la primera vez

¿Te fue útil?

Activas SR-IOV porque quieres un rendimiento limpio y predecible y menor sobrecarga de CPU. Reinicias, haces echo de un número en
sriov_numvfs, y… nada. O peor: aparecen VFs, pero el host pierde enlace, los invitados no reciben paquetes, o los grupos de IOMMU
parecen un plato de espaguetis y VFIO se niega a colaborar.

El primer despliegue de SR-IOV rara vez se bloquea por “un bug”. Se bloquea por una cadena de supuestos: ajustes de firmware, parámetros del
kernel, elección de controladores PF/VF, topología PCIe y una “optimización” inocente que resulta ser una trampa.

SR-IOV en una página (sin cuentos)

SR-IOV (Single Root I/O Virtualization) permite a un dispositivo PCIe exponer múltiples funciones PCI ligeras. La función física (PF) es la
interfaz “propietaria”. Las funciones virtuales (VFs) son las “rebanadas” que entregas a invitados o contenedores (habitualmente vía VFIO passthrough) o gestionas en
el host para direccionamiento de tráfico.

La promesa: evitar parte del switching por software, reducir la sobrecarga por paquete y acercarse al rendimiento de línea con menos jitter. El coste:
ahora dependes del comportamiento del hardware, la política de firmware, la topología PCIe y expectativas estrictas de los controladores. No es “difícil”, pero es
diferente. La mentalidad de depuración se parece más a “resolver problemas de HBA de almacenamiento” que a “ajustar un bridge de Linux”.

En Debian 13, SR-IOV es en su mayor parte una historia de kernel+controlador+firmware. Debian no “hace” SR-IOV por ti; te da buenas herramientas para ver qué
está ocurriendo. Tu trabajo es dejar la plataforma honesta: IOMMU activado, ACS sensato, controlador PF estable y sin suposiciones mágicas.

Modelo mental central: tres planos

  • Plano de control: perillas en sysfs, devlink, ethtool, configuración PF, conmutadores de firmware.
  • Plano de datos: ruta real de paquetes/E/S dentro de la NIC; mapeo de colas, filtros VLAN/MAC, comprobaciones anti-spoof.
  • Plano de aislamiento: IOMMU/VT-d/AMD-Vi, grupos IOMMU, ACS, enlaces VFIO, enrutamiento de interrupciones.

La mayoría de los tickets “SR-IOV está roto” son problemas del plano de aislamiento disfrazados de problemas del plano de datos. El segundo más común son
valores por defecto del plano de control que no conocías.

Hechos interesantes y un poco de historia (para que dejes de culpar a lo equivocado)

  1. SR-IOV es una especificación de PCI-SIG de finales de los 2000, nacida por el dolor de las pilas de virtualización que cargaban 10GbE y
    tráfico de almacenamiento mediante emulación por software.
  2. “Virtual Function” no es una invención de Linux. Es un número de función PCIe con una estructura de capacidades estandarizada.
    Linux sólo lo expone vía sysfs y controladores.
  3. Los primeros despliegues de SR-IOV fueron tanto de almacenamiento como de red. HBAs y diseños tipo NVMe empujaron patrones similares de
    “asignación directa”.
  4. La adopción de IOMMU fue posterior a la de SR-IOV en muchos centros de datos. La gente habilitó VFs antes de activar el aislamiento DMA,
    que es cuando aprendes la diferencia entre “funciona” y “es seguro”.
  5. ACS (Access Control Services) es una característica de PCIe que controla el comportamiento peer-to-peer. Sin ACS adecuado, tus grupos IOMMU
    pueden ser demasiado grandes para pasar funciones individuales con seguridad.
  6. Los controladores de VF suelen exponer intencionalmente menos ajustes que los PF. Eso es por diseño: menos aristas afiladas para inquilinos y
    menos formas de trabar el dispositivo.
  7. Algunas NIC implementan un comportamiento “tipo switch” internamente. Las VFs no son solo colas; hay direccionamiento interno, filtrado
    y a veces algo de lógica embebida.
  8. SR-IOV no siempre es más rápido. Para paquetes pequeños, la sobrecarga de CPU puede bajar; para algunas cargas, la complejidad operacional compensa
    las ganancias y es mejor usar vhost-net/virtio y buen ajuste.

Cómo falla SR-IOV en la vida real

Los fallos de SR-IOV se agrupan. Si puedes categorizar lo que ves, puedes dejar de agitar las manos y empezar a medir.

Clase de fallo A: “No aparecen VFs”

Haces echo de 8 en /sys/class/net/<pf>/device/sriov_numvfs y devuelve
Invalid argument o silenciosamente se queda en cero. Causas comunes:

  • SR-IOV deshabilitado en BIOS/UEFI o firmware de la NIC (sí, ambos pueden importar).
  • Controlador PF incorrecto cargado (inbox vs proveedor; o un controlador de reserva sin soporte SR-IOV).
  • Límite de firmware: pediste más VFs de los que el dispositivo/puerto soporta.
  • El dispositivo está en un estado donde no se pueden crear VFs (p. ej., configurado en un modo que entra en conflicto con la creación de VF).

Clase de fallo B: “Aparecen VFs, pero el passthrough falla”

Los dispositivos VF aparecen en lspci, pero tu hipervisor no puede asignarlos. O VFIO se enlaza, pero QEMU falla con problemas de grupo IOMMU.
Causas comunes:

  • IOMMU no habilitado a nivel de kernel.
  • ACS/grupos IOMMU demasiado grandes; la VF comparte grupo con la PF o con dispositivos no relacionados.
  • vfio-pci no se enlaza porque otro controlador agarró la VF primero.
  • Secure Boot o la política de bloqueo del kernel impide VFIO o la carga de módulos en ciertas configuraciones (depende del entorno).

Clase de fallo C: “Caídas de tráfico, ARP extraño, confusión de VLAN”

El invitado ve enlace arriba, puede hacer ping a su gateway una vez y luego muere. O las etiquetas VLAN desaparecen. O las respuestas ARP no regresan.
Causas comunes:

  • El PF está aplicando políticas anti-spoof/MAC/VLAN y la VF no está configurada en consecuencia.
  • La seguridad del puerto del switch rechaza múltiples MACs; las MACs de tus VFs no coinciden con la lista permitida.
  • Las características de offload interactúan con la ruta del switch virtual de formas sorprendentes (menos común, pero real).

Clase de fallo D: “El rendimiento es peor que virtio”

Este es el que hace que la dirección sospeche. Causas comunes:

  • Tormentas de interrupciones por mala afinidad IRQ o demasiadas colas.
  • Bifurcación de slot PCIe o reducción de velocidad de enlace (x8 se convierte en x4, Gen4 baja a Gen3).
  • Desajuste de NUMA: la VF está en un socket y las vCPU de la VM en otro.
  • Carga de paquetes pequeños con sobrecarga por VM en otra parte (firewall, conntrack, bloqueos de aplicación) dominando.

Broma 1: SR-IOV es como darle a tu VM su propio carril en la autopista—hasta que te das cuenta de que la rampa de acceso sigue siendo gestionada por un comité.

Playbook de diagnóstico rápido (primera/segunda/tercera comprobación)

Esta es la secuencia que uso cuando alguien dice “SR-IOV está roto” y quiero una respuesta útil en menos de 15 minutos. El objetivo es identificar
la primera capa rota, no arreglar todo de una vez.

1) Confirma que la plataforma puede hacer aislamiento (IOMMU + grupos)

  • Comprueba IOMMU habilitado en la línea de comando del kernel y en dmesg.
  • Revisa los grupos IOMMU: ¿puedes aislar una VF con claridad?
  • Si los grupos son incorrectos, para. No procedas a “tuning” o cambios en invitados.

2) Confirma que la NIC y el controlador PF realmente soportan SR-IOV

  • Comprueba sriov_totalvfs.
  • Revisa el controlador PF y versiones de firmware.
  • Crea primero un pequeño número de VFs (2), no 32.

3) Confirma el enlace de la VF y la ruta de adjunto al invitado

  • Asegúrate de que las VFs estén enlazadas a vfio-pci cuando las pases; de lo contrario quedarán enlazadas a un driver de red en el host y lucharás con udev.
  • Confirma que el invitado ve el dispositivo y carga el controlador VF correcto.

4) Solo entonces: sanidad del plano de datos

  • Reglas de seguridad de puerto del switch y trunking VLAN.
  • Filtros MAC/VLAN en el PF para cada VF.
  • Contadores de rendimiento y colocación de colas/IRQ.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas son ejecutables en Debian 13. Las salidas mostradas son representativas. Tus cadenas exactas variarán, pero la lógica de decisión se mantiene.

Tarea 1: Identificar la interfaz PF y la dirección PCI

cr0x@server:~$ ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp129s0f0       UP             3c:fd:fe:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
enp129s0f1       DOWN           3c:fd:fe:12:34:57 <BROADCAST,MULTICAST>

Qué significa: enp129s0f0 parece ser tu PF (uno de los puertos físicos).
Decisión: elige la PF desde la que crearás VFs; no intentes hacer ambos puertos a la vez.

cr0x@server:~$ ethtool -i enp129s0f0
driver: mlx5_core
version: 6.1.0
firmware-version: 22.39.2048 (MT_0000000012)
expansion-rom-version:
bus-info: 0000:81:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: yes

Qué significa: Tienes la dirección de bus 0000:81:00.0 y el controlador PF.
Decisión: registra la dirección PCI; la mayoría de operaciones SR-IOV y VFIO son más fáciles cuando piensas en IDs PCI.

Tarea 2: Confirma que existe la capacidad SR-IOV y ve el límite de VFs

cr0x@server:~$ cat /sys/class/net/enp129s0f0/device/sriov_totalvfs
64

Qué significa: La combinación hardware/controlador puede exponer hasta 64 VFs en este PF.
Decisión: empieza con 2 o 4. Si saltas directamente a 64 y falla, no sabrás si el problema es “SR-IOV roto” o “pediste demasiado”.

Tarea 3: Intentar crear VFs (y manejar los dos modos de fallo comunes)

cr0x@server:~$ cat /sys/class/net/enp129s0f0/device/sriov_numvfs
0
cr0x@server:~$ echo 4 | sudo tee /sys/class/net/enp129s0f0/device/sriov_numvfs
4
cr0x@server:~$ cat /sys/class/net/enp129s0f0/device/sriov_numvfs
4

Qué significa: Las VFs se crearon correctamente.
Decisión: pasa a enumerar las VFs en PCI y mapearlas a índices VF.

Si falla, verás algo así:

cr0x@server:~$ echo 4 | sudo tee /sys/class/net/enp129s0f0/device/sriov_numvfs
tee: /sys/class/net/enp129s0f0/device/sriov_numvfs: Invalid argument
4

Qué significa: El kernel rechazó la creación de VF. Normalmente es política del controlador/firmware/plataforma, no un error de tipado.
Decisión: inspecciona inmediatamente dmesg por la razón real (siguiente tarea).

Tarea 4: Lee dmesg para el error específico del dispositivo, no el ruido genérico

cr0x@server:~$ sudo dmesg -T | tail -n 30
[Mon Dec 30 09:11:12 2025] mlx5_core 0000:81:00.0: SR-IOV: failed to enable VFs, error: -22
[Mon Dec 30 09:11:12 2025] mlx5_core 0000:81:00.0: hint: SR-IOV disabled in firmware or not enough resources

Qué significa: El controlador te está diciendo que no puede asignar recursos o el firmware lo bloquea.
Decisión: revisa ajustes de firmware, modo PF y asegúrate de que no estás en una configuración restringida de la NIC.

Tarea 5: Verifica que IOMMU esté habilitado (esto bloquea VFIO y la asignación segura)

cr0x@server:~$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.12.0-amd64 root=UUID=8c3d... ro quiet intel_iommu=on iommu=pt

Qué significa: Los parámetros del kernel solicitan Intel IOMMU y modo pass-through para dispositivos del host.
Decisión: si no ves intel_iommu=on (o amd_iommu=on), añádelo y reinicia antes de hacer trabajo con VFIO.

cr0x@server:~$ sudo dmesg -T | egrep -i 'DMAR|IOMMU|AMD-Vi' | head -n 20
[Mon Dec 30 09:02:01 2025] DMAR: IOMMU enabled
[Mon Dec 30 09:02:01 2025] DMAR: Host address width 46
[Mon Dec 30 09:02:01 2025] DMAR: DRHD base: 0x000000fed90000 flags: 0x0
[Mon Dec 30 09:02:01 2025] DMAR: Interrupt remapping enabled

Qué significa: IOMMU y el reenvío de interrupciones están activos.
Decisión: procede a revisar los grupos; si falta el reenvío de interrupciones, espera comportamientos extraños de MSI/MSI-X bajo carga.

Tarea 6: Inspecciona grupos IOMMU (la pregunta “¿puedo aislar una VF?”)

cr0x@server:~$ for g in /sys/kernel/iommu_groups/*; do \
  echo "Group $(basename "$g")"; \
  ls -l "$g/devices"; \
done | sed -n '1,60p'
Group 12
total 0
lrwxrwxrwx 1 root root 0 Dec 30 09:03 0000:81:00.0 -> ../../../../devices/pci0000:80/0000:80:01.0/0000:81:00.0
lrwxrwxrwx 1 root root 0 Dec 30 09:03 0000:81:00.1 -> ../../../../devices/pci0000:80/0000:80:01.0/0000:81:00.1
lrwxrwxrwx 1 root root 0 Dec 30 09:03 0000:81:00.2 -> ../../../../devices/pci0000:80/0000:80:01.0/0000:81:00.2

Qué significa: PF y VFs podrían estar en el mismo grupo (depende de tu listado de dispositivos). Eso puede ser un problema para
el passthrough: muchas configuraciones quieren que cada VF esté en su propio grupo.
Decisión: si la VF comparte grupo con la PF o con dispositivos no relacionados, puede que necesites opciones BIOS relacionadas con ACS, diferente
colocación en slots, o aceptar que tu plataforma no puede hacer una asignación por-VF “limpia”.

Tarea 7: Enumera las funciones PCI de las VFs recién creadas

cr0x@server:~$ lspci -nn | egrep -i 'Ethernet|Virtual Function|SR-IOV'
81:00.0 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6] [15b3:101b]
81:00.1 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
81:00.2 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
81:00.3 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
81:00.4 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]

Qué significa: Las VFs existen en 81:00.1 a 81:00.4.
Decisión: decide si el host usará estas VFs como netdevs (raro en diseños limpios) o si las enlazarás a VFIO para invitados.

Tarea 8: Mapear índice VF a dirección PCI (deja de adivinar qué VF entregaste)

cr0x@server:~$ ip link show enp129s0f0
5: enp129s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 3c:fd:fe:12:34:56 brd ff:ff:ff:ff:ff:ff
    vf 0     link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff, spoof checking on, link-state auto, trust off
    vf 1     link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff, spoof checking on, link-state auto, trust off
    vf 2     link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff, spoof checking on, link-state auto, trust off
    vf 3     link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff, spoof checking on, link-state auto, trust off

Qué significa: Existen índices VF, pero las MAC están sin establecer y trust está desactivado.
Decisión: establece MAC/VLAN/trust intencionalmente en el PF antes de asignar la VF a un invitado, o depurarás “inestabilidad de red” que en realidad es aplicación de políticas.

Tarea 9: Establecer política MAC y VLAN de VF (o desactivar la aplicación deliberadamente)

cr0x@server:~$ sudo ip link set enp129s0f0 vf 0 mac 52:54:00:aa:bb:01
cr0x@server:~$ sudo ip link set enp129s0f0 vf 0 vlan 120 qos 0
cr0x@server:~$ sudo ip link set enp129s0f0 vf 0 spoofchk on
cr0x@server:~$ sudo ip link set enp129s0f0 vf 0 trust off

Qué significa: VF0 solo puede usar la MAC especificada y VLAN 120; el spoofing está bloqueado; trust está desactivado.
Decisión: en entornos multi-inquilino, mantén el spoof checking activado. Si necesitas que el invitado actúe como router, puede que necesites
trust on (y entonces más te vale tener un modelo de seguridad upstream que tenga sentido).

Tarea 10: Enlazar una VF a vfio-pci (para passthrough) y verificar que se mantuvo

cr0x@server:~$ lspci -nnk -s 81:00.1
81:00.1 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
	Subsystem: Mellanox Technologies Device [15b3:0058]
	Kernel driver in use: mlx5_core
	Kernel modules: mlx5_core

Qué significa: La VF está actualmente enlazada a un driver de red del host. Eso está bien para uso en el host, pero no para passthrough VFIO.
Decisión: des-enlaza y enlaza a vfio-pci, y asegúrate de que persista mediante configuración de modprobe o reglas udev.

cr0x@server:~$ sudo modprobe vfio-pci
cr0x@server:~$ echo 0000:81:00.1 | sudo tee /sys/bus/pci/devices/0000:81:00.1/driver/unbind
0000:81:00.1
cr0x@server:~$ echo vfio-pci | sudo tee /sys/bus/pci/devices/0000:81:00.1/driver_override
vfio-pci
cr0x@server:~$ echo 0000:81:00.1 | sudo tee /sys/bus/pci/drivers/vfio-pci/bind
0000:81:00.1
cr0x@server:~$ lspci -nnk -s 81:00.1
81:00.1 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
	Subsystem: Mellanax Technologies Device [15b3:0058]
	Kernel driver in use: vfio-pci
	Kernel modules: mlx5_core

Qué significa: La VF ahora es propiedad de VFIO y está lista para passthrough.
Decisión: si el enlace falla con “Device or resource busy”, aún tienes usuarios (como NetworkManager o systemd-networkd) que la están agarrando; deténlos o pon la VF en la lista negra para esos controladores.

Tarea 11: Verifica velocidad/anchura del enlace PCIe (tu prueba definitiva de “SR-IOV es lento”)

cr0x@server:~$ sudo lspci -vv -s 81:00.0 | egrep -i 'LnkCap|LnkSta'
LnkCap:	Port #0, Speed 16GT/s, Width x16, ASPM L1, Exit Latency L1 <64us
LnkSta:	Speed 16GT/s (ok), Width x8 (downgraded)

Qué significa: La tarjeta soporta x16 pero está funcionando a x8. Eso puede estar bien, o puede limitarte bajo carga.
Decisión: si esperabas x16 y estás saturando, revisa cableado de slot, bifurcación BIOS, risers y si otro dispositivo se llevó carriles.

Tarea 12: Verifica localidad NUMA (porque DMA entre sockets es un impuesto silencioso)

cr0x@server:~$ cat /sys/bus/pci/devices/0000:81:00.0/numa_node
1
cr0x@server:~$ lscpu | egrep 'NUMA node1 CPU\(s\)|NUMA node0 CPU\(s\)'
NUMA node0 CPU(s):           0-31
NUMA node1 CPU(s):           32-63

Qué significa: Tu NIC está en el nodo NUMA 1.
Decisión: fija las vCPUs de la VM (y preferiblemente la memoria) al nodo 1 cuando uses VFs de esa NIC. Si no, medirás latencia y sin querer medirás tu interconexión.

Tarea 13: Confirma la distribución de interrupciones (la razón oculta de picos de CPU)

cr0x@server:~$ grep -E 'mlx5|vfio|enp129s0f0' /proc/interrupts | head -n 12
  156:    120345          0          0          0   IR-PCI-MSI 524288-edge      mlx5_comp0@pci:0000:81:00.0
  157:     98765          0          0          0   IR-PCI-MSI 524289-edge      mlx5_comp1@pci:0000:81:00.0
  158:    110002          0          0          0   IR-PCI-MSI 524290-edge      mlx5_comp2@pci:0000:81:00.0

Qué significa: Todas las interrupciones están yendo a la CPU0 (primera columna), lo cual es clásico “olvidamos la afinidad IRQ”.
Decisión: distribuye las IRQs entre CPUs locales al nodo NUMA de la NIC, o habilita irqbalance con restricciones sensatas.

Tarea 14: Confirma que el PF no bloquea la VF por política (spoof check, trust, link-state)

cr0x@server:~$ ip link show enp129s0f0 | sed -n '1,12p'
5: enp129s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 3c:fd:fe:12:34:56 brd ff:ff:ff:ff:ff:ff
    vf 0     link/ether 52:54:00:aa:bb:01 brd ff:ff:ff:ff:ff:ff, vlan 120, spoof checking on, link-state auto, trust off

Qué significa: La política está establecida y visible.
Decisión: si el invitado envía tramas etiquetadas en otra VLAN, serán descartadas. Eso no es un “bug de Linux”; eres tú aplicando algo que olvidaste configurar.

Tarea 15: Confirma que el invitado ve la VF y carga el controlador correcto (dentro de la VM)

cr0x@server:~$ lspci -nnk | egrep -A3 -i 'Ethernet|Virtual Function' | head -n 10
00:04.0 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6 Virtual Function] [15b3:101c]
	Subsystem: Mellanox Technologies Device [15b3:0058]
	Kernel driver in use: mlx5_core
	Kernel modules: mlx5_core

Qué significa: La VM ve el dispositivo y tiene un controlador.
Decisión: si la VM ve el dispositivo pero ningún controlador se enlaza, te falta soporte de controlador en el invitado o usas un kernel/initramfs antiguo.

Tarea 16: Revisa problemas con la capacidad de reset PCI (común con VFs)

cr0x@server:~$ sudo dmesg -T | egrep -i 'reset|FLR|vfio' | tail -n 20
[Mon Dec 30 09:20:44 2025] vfio-pci 0000:81:00.1: enabling device (0000 -> 0002)
[Mon Dec 30 09:20:44 2025] vfio-pci 0000:81:00.1: not capable of FLR, using PM reset

Qué significa: La VF puede que no soporte Function Level Reset (FLR). VFIO usará rutas de reset alternativas.
Decisión: si las VMs fallan al reiniciar o en reset en caliente, puede que necesites otra VF, un flujo de reset completo del PF, o reglas operativas
(“migrar en lugar de reiniciar bajo carga”).

Tres micro-historias del mundo corporativo (todas lo bastante reales para doler)

Micro-historia 1: El incidente causado por una suposición errónea

Un equipo desplegó SR-IOV para un conjunto de servicios sensibles a la latencia. Habían hecho el trabajo de laboratorio: números geniales, gráficos limpios, sonrisas satisfechas. En
producción, pasaron VFs a VMs y todo parecía normal. Enlace arriba, DHCP exitoso, checks de salud en verde. Luego, cinco minutos después,
instancias aleatorias quedaron “medio muertas”: podían enviar tráfico, pero las respuestas no volvían de forma fiable.

La primera suposición fue que era el switch. La segunda que era caché ARP. La tercera que debía ser una regresión del kernel. Cada quien tenía su fantasma favorito.

El problema real fue aburrido: el puerto upstream del switch tenía límite de MAC configurado en “una MAC por puerto”. SR-IOV introdujo múltiples MACs
detrás del mismo puerto físico. El switch no cerró completamente el puerto; descartó selectivamente tramas una vez excedido el límite, lo que
pareció un problema intermitente del host. Diferentes racks se comportaron distinto porque no todos los puertos tenían el mismo perfil de seguridad.

La solución fue doble: cambiar la seguridad del puerto del switch para permitir el número esperado de direcciones MAC (o usar un perfil de trunk diseñado para virtualización), e implementar
una comprobación previa que contara las VFs planificadas y las comparara con la política del switch. La lección real no fue “apaga la seguridad.” Fue “deja de asumir que la red trata
un puerto de servidor como una sola identidad.”

También aprendieron una lección social: cuando cambias la semántica de una interfaz, te haces responsable del radio de impacto. El equipo de red no rompió nada; el de cómputo cambió las reglas sin avisar.

Micro-historia 2: La optimización que salió mal

Otra organización decidió que SR-IOV arreglaría el consumo de CPU en hosts con muchos flujos pequeños. Crearon el número máximo de VFs por NIC,
porque “podríamos necesitarlas después”, y las pre-enlazaron a VFIO. También habilitaron todos los offloads que encontraron, porque “la NIC está hecha para esto”.

El resultado: los tiempos de arranque se alargaron, y hosts ocasionales no arrancaban limpiamente después de mantenimiento. Cuando arrancaban, su monitorización
mostraba picos de latencia extraños cada pocos minutos. La historia fácil fue “SR-IOV es inestable”, que se convirtió en punto político.

La causa raíz resultó ser una combinación de presión de recursos e interrupciones. Crear muchas VFs aumentó la contabilidad del dispositivo,
y el host quedó con un lío de IRQs que por defecto aterrizaban en un pequeño conjunto de CPUs. Los offloads no eran universalmente malos, pero algunos interactuaban mal con
su patrón de tráfico y los controladores de los invitados. Su postura de “optimizar todo” creó un sistema frágil ante reinicios, impredecible bajo carga y difícil de depurar.

El plan de reversión fue simple: crear solo el número de VFs necesarias por rol de host, distribuir las IRQs correctamente y habilitar solo los offloads probados en su entorno.
Su rendimiento se recuperó—y su fiabilidad mejoró más que su latencia p99.

Broma 2: Si creas 64 VFs “por si acaso”, has inventado una nueva clase de deuda técnica: deuda PCIe, pagadera a la hora del reinicio.

Micro-historia 3: La práctica aburrida pero correcta que salvó el día

Un tercer equipo ejecutaba cargas mixtas: algunas VMs necesitaban SR-IOV por rendimiento, otras iban bien con virtio. Estandarizaron una regla operativa: cada asignación de VF requería un mapeo registrado de PF name → VF index → PCI address → VM. Sin excepciones.

La gente se quejó. Pareció burocrático. Pareció trámites para ingenieros que “saben lo que hacen”. Entonces un host reinició tras una actualización del kernel y el orden de enumeración de udev cambió. Las direcciones PCI se mantuvieron estables, pero las definiciones de VM referenciaban índices VF equivocados en un clúster porque alguien había estado “haciendo clic” en la UI y confiando en nombres de etiqueta.

El equipo no tuvo un corte. Tuvieron un susto menor y un puñado de adjuntos mal enrutados detectados en pruebas preproducción, porque su hoja de mapeo (y luego un pequeño servicio de inventario interno) hizo obvia la discrepancia.

Su práctica aburrida también facilitó auditorías: puedes explicar “esta VF pertenece a este inquilino” cuando puedes señalar IDs deterministas, no sensaciones. La fiabilidad es a menudo disciplina clerical con sombrero de ingeniería.

Una idea parafraseada atribuida a W. Edwards Deming encaja con operaciones: “No puedes mejorar lo que no mides.” (idea parafraseada)

Errores comunes: síntoma → causa raíz → solución

1) “echo a sriov_numvfs devuelve Invalid argument”

  • Síntoma: Invalid argument al crear VFs.
  • Causa raíz: firmware/BIOS SR-IOV deshabilitado, controlador PF incorrecto, o pediste más que sriov_totalvfs.
  • Solución: confirma sriov_totalvfs > 0; revisa dmesg por pistas del controlador; habilita SR-IOV en BIOS/NIC; pide menos VFs primero.

2) “Las VFs existen pero VFIO passthrough falla con error de grupo IOMMU”

  • Síntoma: el hipervisor se queja de que el dispositivo no está en un grupo IOMMU aislado; QEMU se niega a asignarlo.
  • Causa raíz: ACS no proporciona aislamiento, o la plataforma agrupa PF+VF juntos.
  • Solución: mueve la NIC a un slot/puerto raíz diferente, habilita opciones BIOS relacionadas con ACS si están disponibles, o acepta que esta plataforma no puede pasar por-VF de forma segura.

3) “El invitado tiene enlace pero no puede pasar tráfico de forma fiable”

  • Síntoma: conectividad intermitente, problemas de resolución ARP, tráfico unidireccional.
  • Causa raíz: comprobación anti-spoof/trust/política VLAN de la VF no coincide con el comportamiento del invitado; límite MAC en el puerto upstream.
  • Solución: establece MAC/VLAN de la VF en el PF, ajusta spoof/trust intencionalmente y asegúrate de que el puerto del switch permita múltiples MACs.

4) “El rendimiento es peor después de SR-IOV”

  • Síntoma: mayor uso de CPU o menor throughput frente a virtio.
  • Causa raíz: IRQs fijadas a CPUs erróneas, desajuste NUMA, reducción de ancho de enlace, demasiadas colas/offloads.
  • Solución: revisa ancho/velocidad de enlace, coloca la VM en el mismo nodo NUMA, ajusta afinidad IRQ, reduce el número de VFs/colas, valida offloads con mediciones.

5) “La VF desaparece después del reinicio”

  • Síntoma: las VFs desaparecen o se reinician a 0 tras reiniciar el host.
  • Causa raíz: la creación de VFs SR-IOV no es persistente; no reaplicaste sriov_numvfs al arranque, o un servicio resetea el dispositivo.
  • Solución: implementa un mecanismo en el arranque (unidad systemd) para fijar sriov_numvfs después de que cargue el controlador PF; verifica el orden.

6) “No puedo descargar el controlador PF / dispositivo atascado”

  • Síntoma: no puedes cambiar el conteo de VFs; la descarga del controlador falla; el dispositivo está ocupado.
  • Causa raíz: las VFs aún existen y están en uso; VFs enlazadas a controladores; una VM mantiene una VF abierta vía VFIO.
  • Solución: establece sriov_numvfs a 0, desasocia las VFs de los invitados, des-enlaza las VFs de los controladores y luego reconfigura.

Listas de verificación / plan paso a paso

Lista de preflight del host (haz esto antes de tocar invitados)

  1. Confirma controlador PF y firmware: ethtool -i.
  2. Confirma capacidad SR-IOV: sriov_totalvfs > 0.
  3. Habilita IOMMU en la línea de comandos del kernel; reinicia; verifica en dmesg.
  4. Inspecciona grupos IOMMU; si el aislamiento es imposible, detente y rediseña.
  5. Verifica velocidad/anchura PCIe; arregla slot/bifurcación temprano.
  6. Crea un pequeño conteo de VFs (2–4) y asegúrate de que dmesg esté limpio.
  7. Decide política: MAC/VLAN/trust/spoof por VF.
  8. Decide enlace: driver de red host vs vfio-pci, no ambos.

Plan de creación de VFs y política (operaciones reproducibles)

  1. Pon el conteo de VFs a 0 (pizarra limpia).
  2. Crea el número deseado de VFs.
  3. Asigna MAC/VLAN/trust por VF de forma determinista (inventaríalo).
  4. Enlaza a vfio-pci si vas a pasarla a un invitado.
  5. Adjunta a la VM; confirma el controlador del invitado; realiza un ping simple + prueba iperf.

Lista de validación del invitado (prueba que no miente)

  1. Confirma dispositivo visible en el invitado con lspci -nnk.
  2. Confirma que aparece el nombre de interfaz en el invitado y que el enlace está arriba.
  3. Confirma que el MTU coincide con la red (no asumas jumbo frames end-to-end).
  4. Confirma que el comportamiento VLAN coincide con la política del PF.
  5. Realiza una captura de paquetes en el uplink del host si sospechas descartes por política (la verdad del plano de datos vence a la teoría).

Plan de persistencia (porque reiniciar es una característica)

La configuración SR-IOV suele resetearse al reiniciar. Trata la creación de VFs y la política de VF como cualquier otra configuración del sistema: declarativa y
aplicada por systemd en el orden correcto.

cr0x@server:~$ cat /etc/systemd/system/sriov-enp129s0f0.service
[Unit]
Description=Configure SR-IOV VFs on enp129s0f0
After=network-pre.target
After=sys-subsystem-net-devices-enp129s0f0.device
Wants=network-pre.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo 0 > /sys/class/net/enp129s0f0/device/sriov_numvfs; echo 4 > /sys/class/net/enp129s0f0/device/sriov_numvfs'
ExecStart=/sbin/ip link set enp129s0f0 vf 0 mac 52:54:00:aa:bb:01 vlan 120 spoofchk on trust off
ExecStart=/sbin/ip link set enp129s0f0 vf 1 mac 52:54:00:aa:bb:02 vlan 120 spoofchk on trust off
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl enable --now sriov-enp129s0f0.service
Created symlink /etc/systemd/system/multi-user.target.wants/sriov-enp129s0f0.service → /etc/systemd/system/sriov-enp129s0f0.service.

Qué significa: has hecho que la creación de VFs y la política sean reproducibles.
Decisión: mantén esta unidad simple. Evita incluir la lógica de enlace VFIO aquí a menos que estés seguro del orden de carga de módulos y del comportamiento de udev en tu entorno.

FAQ

1) ¿Necesito SR-IOV habilitado en BIOS, o solo en la NIC?

Potencialmente ambos. Algunas plataformas condicionan SR-IOV a opciones BIOS/UEFI (especialmente para “virtualización I/O”), y algunas NICs tienen conmutadores de firmware o perfiles de recursos que restringen la creación de VFs. Si sriov_totalvfs es 0, trátalo como “algo está deshabilitado” hasta que se demuestre lo contrario.

2) ¿Cuál es la diferencia entre iommu=pt y no usarlo?

iommu=pt (pass-through) normalmente significa que los propios dispositivos del host usan mappings de identidad para menor sobrecarga, manteniendo al mismo tiempo traducción/aislamiento para dispositivos VFIO. Es común en hosts de virtualización. Si estás depurando fallos DMA extraños, puedes probar sin ello, pero mide y entiende la compensación.

3) ¿Por qué son enormes mis grupos IOMMU?

Porque tu topología PCIe y las opciones ACS deciden qué puede aislarse. Algunas plataformas más orientadas al consumidor y algunos diseños de servidor detrás de ciertos switches agrupan funciones. Si la VF comparte grupo con la PF o con dispositivos no relacionados, tu plan de passthrough por-VF limpio puede ser imposible en ese hardware.

4) ¿Puedo usar VFs SR-IOV con bridges de Linux u Open vSwitch en lugar de passthrough?

Puedes, pero normalmente no es la razón por la que se despliega SR-IOV. Si mantienes VFs en el host y las bridgeas, a menudo reintroduces switching por software y complejidad de políticas. Decide lo que quieres: “asignación directa” o “switching gestionado por el host”. Mezclar objetivos es cómo se crea red misteriosa.

5) ¿Por qué el enlace VFIO a veces revierte después del reinicio?

Porque el controlador por defecto puede enlazarse primero durante la enumeración. Arréglalo con reglas de enlace persistentes: aplicar driver_override en el momento adecuado, o configuración de modprobe que asegure que vfio-pci reclame ciertos IDs vendor/device. Ten cuidado: reclamar por ID también puede agarrar dispositivos que no pretendías si tienes múltiples NIC idénticas.

6) ¿Debería poner trust on para las VFs?

Solo si sabes exactamente por qué. Trust puede permitir a la VF cambiar comportamiento MAC/VLAN y puede relajar el filtrado. Eso es útil para appliances, routers o redes anidadas, pero cambia tu modelo de amenazas. Postura por defecto: trust off, spoofchk on, y establece MAC/VLAN explícitamente.

7) ¿Son “gratis” los jumbo frames con SR-IOV?

No. Aún necesitas consistencia MTU end-to-end: interfaz invitado, VF, PF, puerto del switch y camino upstream. Fallos de jumbo frames suelen parecer pérdidas aleatorias, porque el tráfico de control pequeño funciona mientras los payloads grandes se pierden.

8) ¿Por qué varía el rendimiento entre hosts con la misma NIC?

Topología PCIe, colocación NUMA, valores BIOS y perfiles de firmware. Dos NIC idénticas en diferentes slots pueden comportarse de forma muy distinta. También, la colocación de IRQ y la frecuencia de CPU del host pueden sesgar resultados. Trata el rendimiento como propiedad de la plataforma, no solo de la NIC.

9) ¿Es SR-IOV un límite de seguridad?

Puede formar parte de uno, pero no lo trates como un muro mágico. Dependess del aislamiento IOMMU, firmware correcto, comportamiento correcto del controlador y controles operativos sensatos. Si tu modelo de amenazas es multi-tenancy fuerte, necesitas configuración disciplinada y auditoría. Si tu modelo es “mantener honestas a las personas honestas”, es más fácil.

10) ¿Cuándo no debería usar SR-IOV?

Cuando necesitas políticas L2/L3 flexibles en el host, cuando tu plataforma no puede aislar grupos IOMMU, cuando no puedes coordinar políticas de puerto del switch, o cuando necesitas migración en vivo sin interrupciones y tus herramientas no manejan SR-IOV limpiamente. Virtio con buen ajuste no es una vergüenza. A menudo es la respuesta correcta.

Siguientes pasos que puedes hacer esta semana

Si quieres que SR-IOV se comporte en Debian 13, deja de tratarlo como un único interruptor de características. Trátalo como un pequeño proyecto de integración de plataforma.

  1. Elige un host y un puerto NIC y valida IOMMU + aislamiento primero. Si los grupos son incorrectos, rediseña ahora.
  2. Crea 2 VFs, no 32. Enlaza una a VFIO y adjúntala a una VM de prueba. Prueba el controlador del invitado y la conectividad básica.
  3. Haz la política explícita: establece VF MAC/VLAN/spoof/trust intencionalmente y documenta el mapeo de VF → inquilino.
  4. Mide el rendimiento con conciencia de topología: confirma ancho/velocidad de enlace y colocación NUMA antes de culpar a controladores.
  5. Automatiza la persistencia con una simple unidad systemd oneshot que recree VFs y políticas tras el reinicio.

Una vez que SR-IOV sea estable, puedes empezar a preocuparte por las cosas divertidas: conteo de colas, offloads, DPDK y recortar microsegundos. Antes que nada, haz que sea aburrido. La red aburrida es la que no te despierta.

← Anterior
MySQL/MariaDB en Docker: los valores por defecto que arruinan el rendimiento
Siguiente →
Migración de stack Docker Compose: mover a un nuevo host sin mitos sobre el tiempo de inactividad

Deja un comentario