KVM LibVirtD NIC Pass-through

Tengo un mini mierda de servidor con Centos 8 que le he instalado libvirtd para que sea un host de virtualización. En él he creado una máquina cuyo objetivo es analizar el tráfico de red.

La idea es que la máquina virtual pueda recibir el tráfico de un port mirror o span port.

El problema que he tenido es que creando interfaces 'bridge' para 'unir' la boca de red física del servidor con la máquina virtual, el rendimiento es muy pobre. Haciendo un tcp replay de un PCAP, la maquina virtual veia los paquetes, sí, pero perdía el 90% de ellos y según como le pica, a veces solo ve broadcasts/multicast y otras veces cualquier tipo de tráfico. En ambos casos, se pierden un montón de tramas y no sirve para nada.

La solución ha sido habilitar el PCI Passthrough para que la maquina virtual gestione directamente la interfaz física del servidor.

  • Parar la maquina virtual
  • Habilitar IOMMU en la BIOS (en mi caso no habia ninguna opción) así como la capacidad de virtualización
  • Pasarle un parametro al kernel para que habilite IOMMU
en /etc/default/grub:

GRUB_CMDLINE_LINUX="... iommu=pt intel_iommu=on pcie_acs_override=do
wnstream,multifunction"

grub2-mkconfig -o /etc/grub2.cfg (en mi caso uso BIOS, si usas UEFI creo que el destino es /etc/grub2-efi.cfg)

  • Reiniciar y verificar que el IOMMU furula
dmesg | grep IOMMU
[    0.000000] DMAR: IOMMU enabled
[    0.003040] DMAR-IR: IOAPIC id 2 under DRHD base  0xfed91000 IOMMU 1

for d in /sys/kernel/iommu_groups/*/devices/*; do n=${d#*/iommu_groups/*}; n=${n%%/*}; printf 'IOMMU Group %s ' "$n"; lspci -nns "${d##*/}"; done;

IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers [8086:1910] (rev 07)
IOMMU Group 10 00:1f.0 ISA bridge [0601]: Intel Corporation QM170 Chipset LPC/eSPI Controller [8086:a14d] (rev 31)
IOMMU Group 10 00:1f.2 Memory controller [0580]: Intel Corporation 100 Series/C230 Series Chipset Family Power Management Controller [8086:a121] (rev 31)

...

  • Buscar la tarjeta PCI que queremos pasar y indicar que use el driver vfio_pci
lspci -nn
03:00.0 Ethernet controller [0200]: Intel Corporation 82571EB/82571GB Gigabit Ethernet Controller D0/D1 (copper applications) [8086:105e] (rev 06)

03:00.1 Ethernet controller [0200]: Intel Corporation 82571EB/82571GB Gigabit Ethernet Controller D0/D1 (copper applications) [8086:105e] (rev 06)


Miramos que no hay problemas para cargar el modulo:
modprobe vfio_pci ids=8086:105e

si no problemo, creamos /etc/modprobe.d/vfio.conf para que lo cargue al arrancar:
options vfio_pci ids=8086:105e

  • reiniciamos y miramos si esta cargado ese modulo con lsmod | grep vfio
vfio_pci               57344  1
vfio_virqfd            16384  1 vfio_pci
vfio_iommu_type1       32768  1
vfio                   32768  5 vfio_iommu_type1,vfio_pci
irqbypass              16384  8 vfio_pci,kvm

  • Configurar la maquina virtual para que pille esa tarjeta pci (yo uso virt-manager):
    • Doble-click en la máquina y vas a la pestaña de configuración
    • añadir hardware
    • Dispositivo PCI anfitrion
    • Seleccionar la tarjeta pci que interesa, en mi caso: 03:00.0 Ethernet controller [0200]: Intel Corporation 82571EB/82571GB Gigabit Ethernet Controller D0/D1 (copper applications)
  • Arrancar máquina virtual, se observa que esa tarjeta desaparece del host anfitrion y aparece una nueva tarjeta de red en la máquina virtual

Si ahora hago un tcpreplay de un PCAP gordote a esa interfaz, la máquina virtual pierde solamente un 0,5% de los paquetes, lo cual ya es aceptable

Comentarios