9.2.2.1.2.1.3. Red

Dedicamos un epígrafe completo a la red, porque, amén de muy importante, es uno de los dispositivos que da más juego en su configuración.

Al principio, al proponer los alias para simplificar las órdenes, definimos una interfaz de red así:

-netdev user,id=nic -device virtio-net,netdev=nic

donde vemos que intervienen dos opciones complementarias: -device, que como ya venimos viendo con otro tipo de dispositivos define el dispositivo físico que se virtualiza; y -netdev, que indica cómo se utilizará y que es dónde se encuentra fundamentalmente el meollo.

En cuanto a la definición del dispositivo (-device) es importante apreciar algunos aspectos:

  • El dispositivo escogido es un virtio-net, que tiene mejor rendimiento que emular completamente una tarjeta de red[1]. Esto exige, no obstante, que el driver esté incluido en el sistema huésped. Es el caso de Linux, pero de los Windows (al menos los Windows 10). En el apartado de red para Virtualbox hay nota con un enlace desde el que se puede descargar el controlador.

  • Sin embargo, el predeterminado es e1000 que emula una tarjeta 82450EM de Intel, porque es más probable que el sistema anfitrión la soporte sin necesidad de instalar ningún hardware.

  • netdev= permite referir el identificador incluido con id= en la opción -netdev asociada.

  • Si disponemos varias tarjetas o arrancamos varias máquinas virtuales que comparten red, es importante que especifiquemos su dirección MAC, porque QEmu siempre asigna la misma: 52:54:00:12:34:56. Para ello, basta añadir la dirección al argumento de la opción: -device virtio-net,netdev=nic,mac=54:52:00:12:34:57.

Advertencia

Todas las configuraciones se hacen usando virtio-net, pero para que realmente sea ventajosa para el rendimiento su elección, es necesario también que se habilite el uso del módulo vhost_net. Podemos pues seguir sin preocuparnos de esto último, pero es conveniente, una vez que se controle bien cómo configurar la red, que se remate habilitándolo.

Con esto es suficiente para declarar el dispositivo virtual. -netdev es otra historia que requiere un cuento bastante más largo.

9.2.2.1.2.1.3.1. Red de usuario

Es la configuración de la interfaz que Virtualbox llama NAT y por defecto crea QEmu, si no la deshabiltamos con la opción -nodefaults. Su definición es la mostrada arriba:

-netdev user,id=nic

donde id refiere el identificador al que se hará en el -device asociado. Esta es la configuración mínima que supone que la máquina virtual se encuentre en una red definida de la siguiente forma:

  • La dirección de red es 10.0.2.0/24.

  • QEmu se encarga de traducir las peticiones al exterior como si se tratara de un router que hace enmascaramiento. La puerta de enlace que verá el huésped será la segunda IP disponible (en este caso, 10.0.2.2); y el servidor DNS, la tercera (en este caso, 10.0.2.3).

  • El sistema de la máquina virtual recibirá por DHCP otra IP de la red y tendrá conectividad con el exterior.

  • Una segunda máquina virtual se colocará en una red idéntica, pero no será la misma red, por lo que no existirá conectividad entre ambos huéspedes.

  • Funciona perfectamente el tráfico UDP y TCP, pero por un problema de privilegos no el ICMP, por lo que no podemos usar éste para comprobar conectividad.

  • Ningún puerto del sistema huésped estará expuesto.

Aunque no suele ser necesario, existen distintos parámetros para alterar las características de esta red que pueden consultarse en el manual de qemu-system-x86_64. Lo que sí es interesante es solucionar los dos últimos inconvenientes.

ICMP

Para ello lo más recomendable es crear un grupo en el anfitrión al que agreguemos todos los usuarios que utilicen QEmu (lo cual será útil más adelante para otras tareas), y que permitamos a tal grupo generar tráfico ICMP:

# addgroup --system qemusers
# adduser usuario qemusers
# getent group qemusers
qemusers:x:115:usuario
# echo "115 115" > /proc/sys/net/ipv4/ping_group_range

Este permiso es temporal y se perderá al apagar la máquina. Si queremos hacerlo permanente, en un sistema Debian podemos añadir una línea a /etc/sysctl.conf:

# echo "net.ipv4.ping_group_range = 115 155" >> /etc/sysctl.conf

y para no tener que reiniciar, podemos sólo por esta vez cargar su configuración:

# sysctl -p
Exposición de puertos

Tiene mucha utilidad si el huésped ofrece un servicio al que queremos acceder desde el anfitrión (p.e. el servicio SSH). Para ello, hay un parámetro (hostfwd) que permite redirigir un puerto del anfitrión a uno del cliente. Por ejemplo:

-netdev user,id=nic,hostfwd=tcp:127.0.0.1:10022-:22

permite acceder al servidor SSH del cliente a través del puerto 10022 del anfitrión. Para exponer más puertos, no hay más que escribir repetidamente el parámetro.

9.2.2.1.2.1.3.2. Red de máquinas virtuales

El propósito de este subapartado es solventar otra de las limitaciones de la red de usuario: la falta de conectividad entre los sistemas huéspedes.

Advertencia

Tenga presente que por defecto QEmu asigna la misma MAC a todas las máquinas virtuales, por lo que tendrá que especificar expresamente direcciones MAC distintas para cada una de ellas.

Tenemos, al menos, dos alternativas: socket e interfaz puente.

9.2.2.1.2.1.3.2.1. socket

Es la solución más sencilla que, además, no requiere permisos de administración, por lo que puede implementarla un usuario sin privilegios. Para configurar una interfaz basta con hacerlo del siguiente modo:

-netdev socket,id=nic,mcast=230.0.0.1:12345

en donde usamos la dirección de multicast 230.0.0.1 y el puerto 12345. Con que todas las máquinas que participen en esa red repitan esta configuración se encontrarán en la misma red. Por ejemplo, las siguientes dos máquinas se encontrarán dentro de la misma red interna:

$ qemu-system-vga -hda disco1.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:56 \
   -netdev socket,id=nic,mcast=230.0.0.1:12345
$ qemu-system-vga -hda disco2.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:57 \
   -netdev socket,id=nic,mcast=230.0.0.1:12345

En este caso se encontrarán aisladas y necesitaremos fijarles direcciones estáticas, puesto que no hay ningún servidor DHCP en esa red. Si quisiéramos comunicar esta red con el exterior bastaría con que una de ellas hiciera de router. Por ejemplo, la primera de ellas podríamos haberla levantado así:

$ qemu-system-vga -hda disco1.qcw -device virtio-net,netdev=nic0,mac=52:54:00:12:34:55 -netdev user,id=nic0  \
   -device virtio-net,netdev=nic,mac=52:54:00:12:34:56 -netdev socket,id=nic,mcast=230.0.0.1:12345

Si tuviéramos necesidad de crear un segundo grupo de máquinas virtuales, bastaría con modificar la dirección de multicast, para que este grupo estuviera en una red diferente al primero. Por ejemplo:

$ qemu-system-vga -hda disco1.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:58 \
   -netdev socket,id=nic,mcast=230.0.0.2:12345
$ qemu-system-vga -hda disco2.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:59 \
   -netdev socket,id=nic,mcast=230.0.0.2:12345

9.2.2.1.2.1.3.2.2. Puente

Esta alternativa sí requiere permisos de administrador, porque exige crear interfaces adicionales en el anfitrión. La idea es crear una interfaz puente que contendrá interfaces virtuales TAP cada una de las cuales se asocia a una máquina virtual. De este modo, todas las máquinas virtuales compartirán la red.

Antes de empezar debemos preparar el sistema. En primer lugar, delegaremos en Qemu la tarea de crear las interfaces TAP y este hace uso del programita /usr/lib/qemu/qemu-bridge-helper. Sin embargo, si utilizamos un usuario sin privilegios, éste no será capaz de crear las interfaces, así que primero lo ajustaremos para que tenga esa capacidad:

# setcap 'cap_net_admin=ep' /usr/lib/qemu/qemu-bridge-helper

Además, el programa limita las interfaces puente a las que puede añadir las interfaces TAP que crea, así que debemos decir a cuáles se permite incluyéndolas en el archivo /etc/qemu/bridge.conf:

# mkdir -p /etc/qemu
# echo "allow all" > /etc/qemu/bridge.conf

Preparado el sistema, ya podemos indicar qué se debe hacer cada vez que se quiere crear una red mediante esta estrategia. Lo primero es crear una interfaz puente:

# ip link add name vmnet0 type bridge
# ip link set vmnet0 up

y, creada, ya podemos arrancar un par de máquinas virtuales dentro de una misma red:

$ qemu-system-vga -hda disco1.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:56 -netdev bridge,id=nic,br=vmnet0
$ qemu-system-vga -hda disco2.qcw -device virtio-net,netdev=nic,mac=52:54:00:12:34:57 -netdev bridge,id=nic,br=vmnet0

QEmu, a través de qemu-bridge-helper, se encargará de crear sendas interfaces TAP e incluirlas dentro del puente vmnet0. Cuáles sean en concreto estas interfaces, nos es indiferente, aunque para escoger nombre para ellas el programita toma tapN donde N es el número más bajo que haga que el nombre esté libre. Así, en principio, será tap0, pero si esta interfaz ya existe en el anfitrión, creará tap1.

Como en el caso de socket, la red estará aislada y las interfaces virtuales del huésped no recibirá una dirección IP dinámica. No obstante, para conectarla con el exterior podemos utilizar uno de los huéspedes como router, de modo análogo a como ya se hizo cuando ilustramos la red con socket.

Nota

Obviamente, si quisiéramos crear un segundo grupo de máquinas en un red distinta, bastaría con crear una interfaz puente distinta (p.e. vmnet1) y asociar tales máquinas a ella.

Es posible que, cuando las máquinas estén en funcionamiento, queramos poder establecer conexión con ellas directamente desde el anfitrión. Para ello, no tenemos más que dar a la interfaz puente (vmnet0 en este caso) una IP de la red en la que hayamos situado a los sistemas huéspedes. Por ejemplo, si en los sistemas huéspedes fijamos direcciones de la red 192.168.255.0/24, bastará con:

# ip addr add 192.168.255.5/24 dev vmnet0

suponiendo que tal IP está libre. Al apagar las máquinas, las interfaces TAP creadas se borrarán automáticamente. Por tanto, lo único que restará, será eliminar el puente:

# ip link del vmnet0

Ver también

Exploraremos la posibilidad de automatizar la creación de las interfaces necesarias en el epígrafe en que proponemos un script de arranque.

9.2.2.1.2.1.3.3. Adaptador puente

El propósito bajo el epígrafe es lograr un huésped cuya interfaz de red se encuentre en la misma red que el anfitrión (o sea, la configuración que Virtualbox denomina adaptador puente). Esto se logra asociando a la interfaz real del anfitrión la interfaz virtual que utilice el huésped. Tenemos al menos dos alternativas:

  • Utilizar una interfaz TAP como ya hemos visto dentro de un puente en el que también esté incluida la interfaz física del anfitrión.

  • Echar mano de las interfaces macvlan.

9.2.2.1.2.1.3.3.1. Puente

Esta alternativa exige que ya tengamos preparado el anfitrión, y hayamos agregado la interfaz física a un puente. En Debian esto se traduciría en una configuración dentro de /etc/network/interfaces semejante a esta:

# Interfaz física.
allow-hotplug eth0
iface eth0 inet manual
   up  ip link set $IFACE up
   down ip link set $IFACE down

# Interfaz puente en que se incluye la anterior
auto br0
iface br0 inet dhcp
   bridge_ports eth0
   bridge_maxwait 2

donde suponemos que el anfitrión recibe una IP dinámicamente. Con esta situación, el puente ya está creado de antemano, con lo que para arrancar una máquina en la misma red que la del anfitrión no habrá más que hacer lo siguiente:

$ qemu-system-vga -hda disco.qcw -device virtio-net,netdev=nic -netdev bridge,id=nic,br=br0

supuesto, claro está, que hayamos preparado /usr/lib/qemu/qemu-brigde-helper, como se explicó en el epígrafe anterior, para que sea capaz de crear las interfaces TAP.

9.2.2.1.2.1.3.3.2. MACVLAN

La otra alternativa es más eficiente y, en principio, no exige configurar la interfaz física del anfitrión de un modo especial. Simplemente, antes de arrancar la máquina deberemos preparar una interfaz derivada del siguiente modo:

# ip link add link eth0 name macvtap0 address 52:54:00:12:34:56 type macvtap mode bridge
# ip link set macvtap0 up

La primera orden creará un dispositivo de caracteres /dev/tapN donde N es un número que puede consultarse en /sys/class/net/nombre_interfaz/ifindex. El problema es que el usuario deberá poder leer y escribir en él, si queremos que funcione este método. Para ello podemos cambiar los permisos cada vez que creamos una nueva interfaz:

# chgrp qemusers /dev/tap$(</sys/class/net/macvtap0/ifindex)
# chmod g+w /dev/tap$(</sys/class/net/macvtap0/ifindex)

o bien crear una regla para que cuando se cree un dispositivo de este tipo lo haga siempre con estos permisos:

# cat >> /etc/udev/rules.d/55-qemuperm.rules
KERNEL=="tap*", ACTION=="add", GROUP="qemusers", MODE="0660"

Nota

Hemos supuesto que hemos creado un grupo qemusers donde se encontrarán todos los usuarios que usen QEmu tal como sugerimos para resolver el ping en una red de usuario.

Preparado el sistema, podremos arrancar la máquina de este modo:

$ qemu-system-vga -hda disco.qcw -device virtio-net,netdev=nic,mac=$(</sys/class/net/macvtap0/address) \
     -netdev tap,id=nic,fd=3 3<>/dev/tap$(</sys/class/net/macvtap0/ifindex)

donde puede observarse que la MAC de la interfaz macvtap coincide con la MAC que se asigne a la interfaz virtualizada del anfitrión y, además, se usa el descriptor de archivo 3.

El problema de esta solución es que las interfaces derivadas carecen de conectividad con la interfaz física. Esto supone que los huéspedes (en caso de que haya varios) podrán comunicarse entre sí y comunicarse con el exterior, pero no con el propio anfitrión (y viceversa). La solución es que el anfitrión no use directamente la interfaz física, sino también una interfaz macvlan. En consecuencia, su configuración para Debian debería ser así:

# Interfaz física.
allow-hotplug eth0
iface eth0 inet manual
   up   ip link set dev $IFACE up
   down ip link set dev $IFACE down

# Interfaz derivada de la anterior
auto ethost
iface ethost inet dhcp
   pre-up    ip link add link eth0 name $IFACE type macvtap mode bridge
   post-down ip link del dev $IFACE

De este modo, el anfitrión se comunicará también a través de una interfaz macvtap (ethost) y, en consecuencia, no quedará aislado de los huéspedes.

Notas al pie