Capítulo 5: Networking con TAP Devices

Por: Artiko
firecrackernetworkingtapnatbridgevirtio-net

Capítulo 5: Networking

Firecracker usa TUN/TAP networking: cada interfaz de red del guest está respaldada por un TAP device en el host. El guest tiene una interfaz VirtIO-Net que mapea 1:1 a un TAP device del host.

Arquitectura de red

graph LR
    A[Guest eth0<br/>VirtIO-Net] <-->|"tap0 (host)"| B[TAP device]
    B --> C{Modo de red}
    C -->|NAT| D[iptables MASQUERADE<br/>→ Internet]
    C -->|Bridge| E[br0<br/>→ LAN directa]
    C -->|Namespace| F[netns aislado<br/>→ otro proceso]

Prerrequisitos

# Verificar que TUN/TAP está disponible
ls /dev/net/tun

# Si no existe, cargar el módulo
sudo modprobe tun

# Instalar herramientas de red si no están presentes
sudo apt-get install -y iproute2 iptables  # Debian/Ubuntu
sudo dnf install -y iproute iptables       # Fedora

Modo 1: NAT (más común para desarrollo)

El guest sale a internet usando la IP del host como NAT. El guest no es accesible desde fuera.

TAP_DEV="tap0"
TAP_IP="172.16.0.1"        # IP del host en esta subred
GUEST_IP="172.16.0.2"      # IP que configuraremos en el guest
MASK_SHORT="/30"            # Subred /30: solo 2 hosts

# 1. Crear el TAP device
sudo ip tuntap add dev "${TAP_DEV}" mode tap
sudo ip addr add "${TAP_IP}${MASK_SHORT}" dev "${TAP_DEV}"
sudo ip link set dev "${TAP_DEV}" up

# 2. Habilitar IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

# 3. Configurar NAT (reemplaza eth0 con tu interfaz física real)
HOST_IFACE=$(ip route list default | awk '{print $5; exit}')
sudo iptables -t nat -A POSTROUTING -o "${HOST_IFACE}" -j MASQUERADE
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i "${TAP_DEV}" -o "${HOST_IFACE}" -j ACCEPT

Configurar la interfaz en Firecracker

API_SOCKET="/tmp/firecracker.socket"

curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "iface_id": "eth0",
    "guest_mac": "AA:FC:00:00:00:01",
    "host_dev_name": "tap0"
  }' \
  "http://localhost/network-interfaces/eth0"

Configurar red dentro del guest

Una vez dentro del guest:

# Configurar IP estática
ip addr add 172.16.0.2/30 dev eth0
ip link set eth0 up
ip route add default via 172.16.0.1

# Configurar DNS
echo "nameserver 8.8.8.8" > /etc/resolv.conf

# Verificar conectividad
ping -c 3 8.8.8.8

Modo 2: Bridge (acceso directo a LAN)

El guest aparece en la red local con su propia IP, accesible desde otros hosts de la LAN.

# Crear bridge
sudo ip link add name br0 type bridge
sudo ip link set br0 up

# Mover la interfaz física al bridge (perderás conectividad temporalmente)
# ¡Cuidado en servidores remotos!
HOST_IFACE="eth0"
sudo ip link set "${HOST_IFACE}" master br0
sudo dhclient br0   # O configurar IP estática en br0

# Crear TAP y conectarlo al bridge
sudo ip tuntap add dev tap0 mode tap
sudo ip link set tap0 master br0
sudo ip link set tap0 up

Rate limiting de red

Puedes limitar el ancho de banda de cada interfaz de red:

curl -s -X PUT \
  --unix-socket "${API_SOCKET}" \
  --header "Content-Type: application/json" \
  --data '{
    "iface_id": "eth0",
    "guest_mac": "AA:FC:00:00:00:01",
    "host_dev_name": "tap0",
    "rx_rate_limiter": {
      "bandwidth": {
        "size": 52428800,
        "refill_time": 1000
      }
    },
    "tx_rate_limiter": {
      "bandwidth": {
        "size": 52428800,
        "refill_time": 1000
      }
    }
  }' \
  "http://localhost/network-interfaces/eth0"

El ejemplo limita a 50 MiB/s en ambas direcciones (52428800 bytes / 1000 ms).

Múltiples microVMs con subnets independientes

Para ejecutar muchas VMs simultáneamente, cada una necesita su propio TAP device y subred. La convención de Firecracker usa subredes /30 en 172.16.0.0/16:

#!/bin/bash
# setup-vm-network.sh — configura red para la VM número N
VM_NUM="${1:?Proporciona número de VM}"

# Fórmula para calcular IPs únicas
THIRD_OCTET=$(( (VM_NUM * 4) / 256 ))
FOURTH_OCTET=$(( (VM_NUM * 4) % 256 ))

TAP_DEV="tap${VM_NUM}"
TAP_IP="172.16.${THIRD_OCTET}.${FOURTH_OCTET}"
GUEST_IP="172.16.${THIRD_OCTET}.$(( FOURTH_OCTET + 1 ))"

sudo ip tuntap add dev "${TAP_DEV}" mode tap
sudo ip addr add "${TAP_IP}/30" dev "${TAP_DEV}"
sudo ip link set dev "${TAP_DEV}" up

echo "TAP: ${TAP_DEV}, Host IP: ${TAP_IP}, Guest IP: ${GUEST_IP}"

Limpiar después de usar

# Eliminar TAP device
sudo ip link delete tap0

# Eliminar reglas iptables
sudo iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -D FORWARD -i tap0 -o eth0 -j ACCEPT

Referencia