iproute2 es el conjunto de herramientas estándar para configurar la red en Linux: ip para interfaces, direcciones, rutas y namespaces, tc para el control de tráfico y ss para los sockets. Sustituye a ifconfig, route y netstat, que llevan años obsoletos. En este tutorial usarás iproute2 en Ubuntu 24.04 para inspeccionar la red, configurar enrutamiento por políticas, montar una red de namespaces con salida a Internet y limitar su ancho de banda, y al final verás cómo hacer persistentes los cambios con netplan.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Acceso a la consola del servidor (por ejemplo, la consola VNC del panel de CubePath) por si un cambio en la interfaz principal corta la conexión SSH.

Paso 1: Instalar las utilidades de prueba

iproute2 viene instalado en Ubuntu. Instala iperf3 para medir ancho de banda y tcpdump para ver el tráfico:

sudo apt update
sudo apt install iperf3 tcpdump

Si el instalador pregunta si quieres arrancar iperf3 como servicio, responde que no; lo lanzarás a mano.

Comprueba la versión de iproute2:

ip -V
ip utility, iproute2-6.1.0, libbpf 1.3.0

Paso 2: Inspeccionar interfaces, direcciones y rutas

La opción -br (breve) da una vista compacta del estado de las interfaces y sus direcciones:

ip -br link
ip -br addr
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0             UP             bc:24:11:5a:3e:10 <BROADCAST,MULTICAST,UP,LOWER_UP>
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             203.0.113.10/24 2001:db8:10::10/64 fe80::be24:11ff:fe5a:3e10/64

En esta guía la interfaz pública es eth0. En tu servidor puede llamarse de otra forma (por ejemplo ens18); sustitúyela donde aparezca.

Consulta la tabla de rutas principal:

ip route show
default via 203.0.113.1 dev eth0 proto static
203.0.113.0/24 dev eth0 proto kernel scope link src 203.0.113.10

El comando más útil para depurar enrutamiento es ip route get, que pregunta al kernel qué ruta, interfaz y dirección de origen usaría para llegar a un destino:

ip route get 1.1.1.1
1.1.1.1 via 203.0.113.1 dev eth0 src 203.0.113.10 uid 1000
    cache

Para ver estadísticas de tráfico y errores de una interfaz:

ip -s link show dev eth0

Y para ver la tabla de vecinos (ARP en IPv4, NDP en IPv6):

ip neigh show

Paso 3: Practicar con una interfaz dummy

Una interfaz dummy es una interfaz virtual que no está conectada a nada. Es perfecta para practicar sin riesgo:

sudo ip link add dummy0 type dummy
sudo ip link set dummy0 up

Añade dos direcciones IPv4 y una IPv6. Una interfaz puede tener tantas direcciones como necesites:

sudo ip addr add 192.168.50.1/24 dev dummy0
sudo ip addr add 192.168.51.1/24 dev dummy0
sudo ip -6 addr add fd00:50::1/64 dev dummy0
ip -br addr show dev dummy0
dummy0           UNKNOWN        192.168.50.1/24 192.168.51.1/24 fd00:50::1/64 fe80::a8c1:abff:fe12:3456/64

Añade una ruta estática hacia una red que se alcanza a través de un router de la red de dummy0, cambia el MTU y comprueba el resultado:

sudo ip route add 10.99.0.0/16 via 192.168.50.254 dev dummy0
sudo ip link set dummy0 mtu 1400
ip route get 10.99.1.1
10.99.1.1 via 192.168.50.254 dev dummy0 src 192.168.50.1 uid 1000
    cache

Para modificar una ruta existente sin borrarla antes usa ip route replace, y para eliminar una dirección ip addr del:

sudo ip route replace 10.99.0.0/16 via 192.168.51.254 dev dummy0
sudo ip addr del 192.168.51.1/24 dev dummy0

Comprueba el estado con ip -br addr show dev dummy0 e ip route show dev dummy0. Borra la interfaz cuando termines; sus direcciones y rutas se van con ella:

sudo ip link delete dummy0

Paso 4: Configurar enrutamiento por políticas

Normalmente el kernel elige la ruta solo por el destino. Con el enrutamiento por políticas puedes usar varias tablas de rutas y elegir la tabla según el origen, la interfaz de entrada o una marca del firewall. El caso típico es un servidor con dos IP de redes distintas que debe responder por la puerta de enlace correspondiente a cada una.

Las reglas se evalúan por orden de prioridad (número menor primero). Mira las que hay por defecto:

ip rule show
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

Dale un nombre a una tabla nueva, la 100. Los nombres se definen en archivos dentro de /etc/iproute2/rt_tables.d/:

sudo mkdir -p /etc/iproute2/rt_tables.d
echo "100 secundaria" | sudo tee /etc/iproute2/rt_tables.d/secundaria.conf

Para practicar, crea de nuevo una interfaz dummy con una dirección de "segunda red" y añade una ruta por defecto en la tabla secundaria que salga por ella:

sudo ip link add dummy1 type dummy
sudo ip link set dummy1 up
sudo ip addr add 192.168.60.10/24 dev dummy1
sudo ip route add default via 192.168.60.1 dev dummy1 table secundaria

Crea la regla: todo el tráfico cuyo origen sea 192.168.60.10 consulta la tabla secundaria:

sudo ip rule add from 192.168.60.10 lookup secundaria priority 1000

Verifica la decisión del kernel para el mismo destino con y sin esa dirección de origen:

ip route get 8.8.8.8
ip route get 8.8.8.8 from 192.168.60.10
8.8.8.8 via 203.0.113.1 dev eth0 src 203.0.113.10 uid 1000
    cache
8.8.8.8 from 192.168.60.10 via 192.168.60.1 dev dummy1 uid 1000
    cache

La misma consulta sale por eth0 o por dummy1 según el origen. Puedes ver el contenido de la tabla con ip route show table secundaria. Limpia el ejercicio:

sudo ip rule del from 192.168.60.10 lookup secundaria priority 1000
sudo ip link delete dummy1

Paso 5: Montar una red de namespaces con bridge y NAT

Los network namespaces son pilas de red independientes: tienen sus propias interfaces, rutas y firewall. Aquí crearás dos, ns1 y ns2, conectados a un bridge br-lab en el host, que hará de router hacia Internet con NAT. Es, a pequeña escala, lo que hace Docker con docker0.

Crea los namespaces y el bridge:

sudo ip netns add ns1
sudo ip netns add ns2
sudo ip link add br-lab type bridge
sudo ip addr add 10.10.0.1/24 dev br-lab
sudo ip link set br-lab up

Conecta cada namespace al bridge con un par veth. Un extremo se mueve al namespace y el otro se enchufa al bridge:

sudo ip link add veth-ns1 type veth peer name eth0 netns ns1
sudo ip link add veth-ns2 type veth peer name eth0 netns ns2
sudo ip link set veth-ns1 master br-lab up
sudo ip link set veth-ns2 master br-lab up

Configura la dirección, la interfaz loopback y la ruta por defecto dentro de cada namespace:

sudo ip -n ns1 addr add 10.10.0.11/24 dev eth0
sudo ip -n ns1 link set eth0 up
sudo ip -n ns1 link set lo up
sudo ip -n ns1 route add default via 10.10.0.1

sudo ip -n ns2 addr add 10.10.0.12/24 dev eth0
sudo ip -n ns2 link set eth0 up
sudo ip -n ns2 link set lo up
sudo ip -n ns2 route add default via 10.10.0.1

ip -n ns1 es la forma corta de ip netns exec ns1 ip. Comprueba que los namespaces se ven entre sí a través del bridge:

sudo ip netns exec ns1 ping -c 2 10.10.0.12
64 bytes from 10.10.0.12: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 10.10.0.12: icmp_seq=2 ttl=64 time=0.048 ms

Para que salgan a Internet, el host tiene que reenviar paquetes y traducir las direcciones privadas a su IP pública. Activa el reenvío IPv4:

sudo sysctl -w net.ipv4.ip_forward=1

Crea una tabla de nftables con una regla de masquerade para la red del laboratorio:

sudo nft add table ip lab
sudo nft add chain ip lab postrouting '{ type nat hook postrouting priority srcnat; }'
sudo nft add rule ip lab postrouting ip saddr 10.10.0.0/24 oifname "eth0" masquerade

Si UFW está activo, su política de reenvío por defecto es DROP y bloqueará este tráfico. Permite el reenvío desde el bridge hacia la interfaz pública:

sudo ufw route allow in on br-lab out on eth0

Comprueba la salida a Internet desde ns1:

sudo ip netns exec ns1 ping -c 2 1.1.1.1
64 bytes from 1.1.1.1: icmp_seq=1 ttl=57 time=1.92 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=57 time=1.85 ms

Mantén este laboratorio en marcha para el paso siguiente.

Paso 6: Controlar el tráfico con tc

tc gestiona las colas (qdisc) de cada interfaz. Primero mide el ancho de banda sin límites. Arranca un servidor iperf3 dentro de ns1 en segundo plano:

sudo ip netns exec ns1 iperf3 -s -D

Y mide desde el host, que alcanza ns1 a través del bridge:

iperf3 -c 10.10.0.11 -t 5
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-5.00   sec  24.1 GBytes  41.4 Gbits/sec    0             sender

Limitar el ancho de banda

El qdisc tbf (token bucket filter) limita la velocidad de salida de una interfaz. El tráfico que va del host hacia ns1 sale por veth-ns1, así que aplica ahí un límite de 20 Mbit/s:

sudo tc qdisc add dev veth-ns1 root tbf rate 20mbit burst 32kbit latency 400ms

Repite la medición:

iperf3 -c 10.10.0.11 -t 5
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-5.00   sec  12.2 MBytes  20.4 Mbits/sec    0             sender

Las estadísticas del qdisc muestran cuántos paquetes ha enviado, descartado o retrasado:

tc -s qdisc show dev veth-ns1

Simular latencia y pérdida

El qdisc netem añade retardo, variación y pérdida de paquetes, muy útil para probar cómo se comporta una aplicación en una red mala. Sustituye el tbf por un retardo de 100 ms con 10 ms de variación y un 1 % de pérdida:

sudo tc qdisc replace dev veth-ns1 root netem delay 100ms 10ms loss 1%

Compruébalo con ping desde el host:

ping -c 5 10.10.0.11
64 bytes from 10.10.0.11: icmp_seq=1 ttl=64 time=104 ms
64 bytes from 10.10.0.11: icmp_seq=2 ttl=64 time=93.7 ms
...

Elimina el qdisc para volver al comportamiento por defecto (fq_codel en Ubuntu 24.04):

sudo tc qdisc del dev veth-ns1 root

Paso 7: Monitorizar cambios y sockets

ip monitor muestra en tiempo real los cambios de enlaces, direcciones y rutas. Déjalo en una sesión y, en otra, levanta o baja una interfaz del laboratorio:

ip monitor link address route
[LINK]4: veth-ns2@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue master br-lab state DOWN

ss muestra los sockets. Estas son las consultas más habituales:

sudo ss -tlnp
ss -s
ss -tn state established '( dport = :443 )'

La primera lista los puertos TCP en escucha con el proceso que los abre, la segunda un resumen por protocolo y la tercera las conexiones HTTPS salientes establecidas.

La mayoría de comandos de ip admiten -j para salida JSON, cómoda para scripts:

ip -j -br addr | python3 -m json.tool

Paso 8: Limpiar el laboratorio

Borra los namespaces (sus extremos veth desaparecen con ellos), el bridge, la tabla nftables y la regla de UFW, y desactiva el reenvío si no lo necesitas:

sudo pkill iperf3
sudo ip netns delete ns1
sudo ip netns delete ns2
sudo ip link delete br-lab
sudo nft delete table ip lab
sudo ufw route delete allow in on br-lab out on eth0
sudo sysctl -w net.ipv4.ip_forward=0

Si has instalado Docker u otro software que necesita reenvío, no desactives ip_forward.

Paso 9: Hacer persistente la configuración con netplan

En Ubuntu 24.04 la configuración de red permanente se define con netplan en /etc/netplan/. Todo lo que has hecho con ip addr, ip route e ip rule tiene equivalente en YAML. Por ejemplo, para añadir una segunda IP a eth0 con su propia tabla de rutas y su regla, crea un archivo nuevo:

sudo nano /etc/netplan/60-secundaria.yaml
network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 198.51.100.20/24
      routes:
        - to: default
          via: 198.51.100.1
          table: 100
      routing-policy:
        - from: 198.51.100.20
          table: 100
          priority: 1000

Las direcciones de este ejemplo son de documentación: usa las que te haya asignado tu proveedor. Netplan combina este archivo con el existente de eth0. Protege los permisos y prueba la configuración con netplan try, que la revierte automáticamente si no confirmas en 120 segundos (por ejemplo, porque has perdido el SSH):

sudo chmod 600 /etc/netplan/60-secundaria.yaml
sudo netplan try

Verifica el resultado:

ip rule show
ip route show table 100
0:      from all lookup local
1000:   from 198.51.100.20 lookup 100 proto static
32766:  from all lookup main
32767:  from all lookup default
default via 198.51.100.1 dev eth0 proto static

Solución de problemas

RTNETLINK answers: File exists: la dirección, ruta o interfaz ya existe. Usa ip route replace en lugar de add, o bórrala antes.

Error: Nexthop has invalid gateway: el gateway no está en ninguna red conectada directamente. Añade antes la dirección de esa red a la interfaz o indica onlink si sabes que el gateway es alcanzable en el enlace.

El namespace llega al bridge pero no a Internet: revisa en este orden sysctl net.ipv4.ip_forward (debe ser 1), sudo nft list table ip lab (regla de masquerade con la interfaz correcta), sudo ufw status verbose (regla de route allow) y sudo ip -n ns1 route (ruta por defecto hacia 10.10.0.1).

La regla de ip rule no tiene efecto: comprueba su prioridad con ip rule show y que la tabla tiene rutas con ip route show table <tabla>. Una regla que apunta a una tabla vacía hace que el kernel pase a la siguiente regla.

tc no limita nada: probablemente aplicaste el qdisc a la interfaz equivocada o al sentido contrario del tráfico. Recuerda que limita la salida; comprueba con tc -s qdisc show dev <interfaz> que los contadores Sent aumentan durante la prueba.

Conclusión

Has usado ip para inspeccionar la red, gestionar direcciones y rutas y configurar enrutamiento por políticas, has construido una red de namespaces con bridge y NAT, y has limitado y degradado el tráfico con tc. También sabes trasladar estos cambios a netplan para que sobrevivan a un reinicio. Como siguientes pasos puedes:

  • Usar tc con el qdisc htb para repartir el ancho de banda entre clases de tráfico.
  • Crear túneles WireGuard o VXLAN con ip link add para unir servidores de distintas ubicaciones.
  • Profundizar en los namespaces y cgroups que usan los contenedores.