Cómo ejecutar un dnsmasq dentro de QEMU, proporcionando servicio de arranque de red a otras máquinas virtuales

Cómo ejecutar un dnsmasq dentro de QEMU, proporcionando servicio de arranque de red a otras máquinas virtuales

EDITAR: WIP: La razón principal de las fallas que se explican a continuación se debe a que no abrí las interfaces TAP del host en el momento adecuado; si permito que QEMU maneje la creación de los dispositivos tap, todo funciona como se esperaba. Investigaré la falla con más detalle y brindaré una explicación más clara del problema cuando la tenga. ¡Gracias @anx por los consejos!

Objetivo: ejecutar una dnsmasqmáquina virtual QEMU dentro de un host, que dé servicio a los arranques de red desde otra máquina virtual QEMU que se ejecuta en el host.

Me gustaría que la máquina virtual dnsmasq actúe como una puerta de enlace, con una NIC como interfaz WAN ascendente, con un servidor DHCP ascendente y la otra interfaz como una interfaz LAN privada, a la que se "conectarán" otras máquinas virtuales y arrancarán en red desde dnsmasq escuchando en esta interfaz LAN privada.

Primero, para permitir que las máquinas virtuales se comuniquen entre sí, creo mi propio puente en el host,

ip link add name vivianbr0 type bridge
ip link set vivianbr0 up

Para que las máquinas virtuales se comuniquen entre sí a través del puente de host, necesitaré dos dispositivos tap, uno para la interfaz LAN privada en la máquina virtual de puerta de enlace y otro para la interfaz de red única de las máquinas virtuales privadas.

ip tuntap add mode tap tap0 user cturner
ip tuntap add mode tap tap1 user cturner
ip link set tap0 up
ip link set tap1 up
ip link set tap0 master vivianbr0
ip link set tap1 master vivianbr0

Para la máquina virtual de puerta de enlace, estoy usando una ISO de Arch Linux con fines de prueba, la máquina virtual se inicia con dos NIC, por lo tanto,

 qemu-system-x86_64 \
    -drive file=arch-disk.qcow2,if=none,id=nvm \
    -device nvme,serial=deadbeef,drive=nvm \
    -cdrom archlinux-2021.09.01-x86_64.iso \
    -boot d \
    -device virtio-net-pci,romfile=,netdev=net0,mac="DE:AD:BE:EF:00:11" \
    -device virtio-net-pci,romfile=,netdev=net1,mac="DE:AD:BE:EF:00:12" \
    `# Simulate the plugged in "upstream" cable with user-mode networking` \
    -netdev user,id=net0,hostfwd=tcp::60022-:22,hostfwd=tcp::8080-:80,hostfwd=tcp::8081-:8000,hostfwd=tcp::2375-:2375 \
    `# And now the unplugged one with, with TAP networks` \
    -netdev tap,id=net1,ifname=tap0,script=no,downscript=no \
-net bridge,br=vivianbr0 \
    -m 4G \
    -enable-kvm

Una vez que esta máquina ha arrancado, veo lo siguiente en la configuración del puente,

brctl show vivianbr0 

bridge name     bridge id               STP enabled     interfaces
vivianbr0               8000.46954a1ad851       no              tap0
                            tap1
                            tap2

Supongo tap2que fue creado por QEMU...

Dentro de esta VM, hay dos interfaces. ens4con MAC DE:AD:BE:EF:00:11 y ens5con MAC DE:AD:BE:EF:00:12. Dentro de esta VM, empiezo dnsmasq,

ip addr add 10.42.0.1/24 dev ens5
dnsmasq -d --dhcp-range=10.42.0.10,10.42.0.100 --dhcp-script=/bin/echo --enable-tftp=ens5 --interface=ens5

Esto comienza sin error.

Ahora intento arrancar en red otra VM, iniciada en el host de esta manera,

qemu-system-x86_64 \
-machine pc-q35-6.0,accel=kvm \
-m 1024 -smp 2,sockets=2,cores=1,threads=1 \
-netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
-device virtio-net-pci,netdev=net0,bootindex=1,mac=DE:AD:BE:EF:00:13 \
-net bridge,br=vivianbr0 \
-enable-kvm \
-vga virtio

Pero no arranca. Superviso el vivianbr0uso tcpdumpy puedo ver las solicitudes de DHCP, pero no hay respuestas, nada llega al dnsmasq que se ejecuta dentro de la primera VM.

tcpdump -i vivianbr0 -nN
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vivianbr0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:21:39.585229 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:40.587741 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:40.700038 IP6 fe80::6ce2:2aff:fe94:ba48.5353 > ff02::fb.5353: 0 [7q] PTR (QM)? _nfs._tcp.local. PTR (QM)? _ftp._tcp.local. PTR (QM)? _webdav._tcp.local. PTR (QM)? _webdavs._tcp.local. PTR (QM)? _sftp-ssh._tcp.local. PTR (QM)? _smb._tcp.local. PTR (QM)? _afpovertcp._tcp.local. (118)
12:21:42.619968 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:21:46.684448 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:13, length 397
12:22:30.609555 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289
12:23:33.796148 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289
12:24:38.673364 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from de:ad:be:ef:00:12, length 289

Curiosamente, veo solicitudes BOOTP de de:ad:be:ef:00:13(la dirección MAC de las máquinas virtuales de arranque en red)y de de:ad:be:ef:00:12(la NIC privada de la máquina virtual de puerta de enlace), lo que indica que algo está mal configurado.

¿Cómo puedo hacer que esto funcione?

Respuesta1

Tus pasos para dos invitados están bien, acabo de replicar tu configuración.hasta el momento de las direcciones de arrendamiento. Podría entregar direcciones IP de una máquina virtual que ejecute dnsmasq a una máquina virtual que ejecute un cliente dhcp.

Compruebe estos:

  • no se pueden abrir dispositivos tap no conectados
    • visible desde el DOWNestado en ip a lla salida del host (debería decir UNKNOWNo UP)
      • si dejas que qemu cree el dispositivo tap, lo qemu-bridge-helperabrirá
      • si usa un script =, abra el dispositivo allí
      • de lo contrario, tendrá que hacerlo ip link set tapN upalgún tiempo después del inicio de la máquina virtual.
  • Las direcciones MAC deben ser únicas
    • visible en la etherdirección en ip a llos invitados
    • enumerar las Mac aprendidas (no host), por ejemplo, brctl showmacs br0deberían tenerdosentradas con un temporizador de envejecimiento distinto de cero
  • soltar paquetes a través de iptables
    • comprobar /proc/sys/net/bridge/bridge-nf-call*y si br_netfilterel módulo está cargado
    • agregue una regla de registro, para IPv4, algo así como iptables -A FORWARD -j LOG --log-prefix "forward dropped"antes de descartar o antes de una política DROP en la tabla FORWARD
    • ignorar /sys/class/net/br*/bridge/nf_call_*(no sé por qué estospoderestar apagado cuando el filtrado está activado)

Otros notables que encontré durante las pruebas:

  • Qemu agregó la vnet_hdropción en mis dispositivos tap. Eso parece razonable y podría haberse deshabilitado en la línea cmdline de qemu si así lo hubiera deseado.
  • A veces mi ruta (enlace de alcance) para el puente se perdía. Todavía tengo que determinar cómo podría suceder eso.

Acerca de su intento de simplificar la prueba vinculándolo al dispositivo de grifo.

dnsmasq se ejecutará dentro de una VM QEMU

Los dispositivos de grifo persistente AFAIK no se pueden utilizar hasta que estén realmente conectados. Por lo tanto, sólo puedes probar de manera significativa cualquiera de las configuraciones completas:

  • ¿Quieres ejecutar dnsmasq en el host?
    • luego conéctelo al dispositivo puente
  • ¿O quieres ejecutar dnsmasq dentro de una VM?
    • luego conéctelo a la interfaz de red respectivaadentroesa máquina virtual

--interfaz=toque0

Sugerencia: Úselo --bind-interfacespara indicarle a dnsmasq que pase de simplemente descartar el tráfico de otras interfaces a intentar vincularse, saliendo así detalladamente cuando se inicia con configuraciones inutilizables.

información relacionada