Linux Traffic Control (tc): una guía práctica

12 min de lectura - 5 de junio de 2026

hero section cover
Tabla de contenidos
  • Control de tráfico en Linux (tc): una guía práctica
  • Cómo funciona tc
  • Configuración de tc en un servidor Linux
  • Modelado del tráfico saliente con HTB
  • Modelado del tráfico entrante con IFB
  • Priorización del tráfico con DSCP
  • Supervisión y resolución de problemas
Compartir

Controle el ancho de banda, priorice el tráfico y configure la entrada y salida en Linux con tc. Configuración de HTB, IFB, DSCP y fq_codel para servidores reales.

Control de tráfico en Linux (tc): una guía práctica

El comando tc te permite controlar directamente cómo gestiona tu servidor el tráfico de red. Puedes limitar el ancho de banda por servicio, mantener la capacidad de respuesta de sesiones interactivas como SSH cuando se producen picos de transferencias masivas y modelar los flujos de salida y de entrada desde una única herramienta. Esta guía abarca los conceptos básicos, una configuración funcional de HTB, el modelado de entrada con IFB, la priorización basada en DSCP y cómo depurarla cuando algo falla.


 

Cómo funciona tc

Cada tc configuración se compone de cuatro elementos:

  • qdisc (disciplina de colas). El programador asociado a una interfaz de red. Decide cómo se colocan y se retiran los paquetes de la cola.
  • Clase. Una subdivisión dentro de un qdisc con clases. Piensa en ello como un carril con su propio límite de velocidad.
  • Filtro. Inspecciona las cabeceras de los paquetes (IP, puertos, marcas) y asigna cada paquete a una clase.
  • Acción. Lo que ocurre con un paquete una vez que cumple los criterios: reenviar, descartar, redirigir.

Estos elementos forman un árbol. Los paquetes entran en el qdisc raíz, pasan por los filtros, se clasifican en clases mediante un major:minor identificador y terminan en cola en un qdisc de hoja para su transmisión.

Para cualquier cosa más compleja que la coincidencia basada en puertos, marca los paquetes con iptables o nftables en la tabla mangle y, a continuación, utiliza el fw filtro de tc para clasificar por marca. Se adapta mucho mejor que encadenar reglas sin procesar u32 para cada tipo de tráfico.

Salida frente a entrada

La dirección importa. El kernel puede almacenar en búfer y retrasar los paquetes salientes, lo que es lo que permite el shaping real. Los paquetes entrantes ya han cruzado el cable en el momento en que los ves, por lo que solo puedes controlarlos (descartarlos por encima de un umbral) a menos que los redirijas primero a un dispositivo IFB.

CaracterísticaSalidaEntrada
DirecciónSalidaEntrante
ModeladoNativoRequiere IFB
ControlCompatibleCompatible
Uso típicoQoS, reparto de ancho de banda, control de velocidadLimitación de velocidad, mitigación básica de DDoS

Los qdiscs que realmente utilizarás

  • HTB (Hierarchical Token Bucket). Con clases. Úsalo cuando quieras garantizar un ancho de banda mínimo por servicio con la posibilidad de tomar prestada la capacidad no utilizada de otras clases.
  • TBF (Token Bucket Filter). Sin clases. Úsalo cuando solo necesites limitar toda una interfaz a una única velocidad.
  • fq_codel (Fair Queuing Controlled Delay). Combina la equidad por flujo con la gestión activa de colas para eliminar el bufferbloat. Ha sido el qdisc predeterminado en la mayoría de las distribuciones de Linux desde systemd 217 y viene por defecto en RHEL 9. Adjúntalo siempre como un qdisc hoja bajo clases HTB; de lo contrario, un solo flujo codicioso puede acaparar toda una clase.

Configuración de tc en un servidor Linux

tc se incluye con el paquete iproute2. En Debian y Ubuntu, instálalo con apt-get install iproute2. En RHEL y derivados, yum install iproute. Necesitarás privilegios de root o sudo.

Averigua primero el nombre correcto de la interfaz. Ponerle un nombre incorrecto a la interfaz es la razón más común por la que una configuración no hace nada sin avisar:

ip link show

Comprueba lo que ya hay en la interfaz, incluidos los contadores en tiempo real:

tc -s qdisc show dev eth0

Borra cualquier qdisc de raíz existente antes de aplicar una nueva configuración, para evitar RTNETLINK answers: File exists errores:

tc qdisc del dev eth0 root 2>/dev/null || true

Si estás actualizando una regla existente en lugar de empezar desde cero, utiliza replace en lugar de add para un intercambio atómico.

La descarga de hardware, como TSO y GSO, agrupa los paquetes de formas que interfieren con el shaping. Desactívalas en la interfaz con shaping:

sudo ethtool -K eth0 tso off gso off

Establece fq_codel como qdisc predeterminado para todo el sistema en las nuevas interfaces:

sysctl -w net.core.default_qdisc=fq_codel

Para servidores con mucha actividad, combínelo con el algoritmo de control de congestión BBR (kernel 4.9+). BBR mantiene un alto rendimiento sin que crezcan las colas:

sysctl -w net.ipv4.tcp_congestion_control=bbr

Un hábito de seguridad si estás configurando un equipo remoto a través de SSH: abre una segunda sesión y ten tc qdisc del dev eth0 root listo para pegar. Una regla de filtrado incorrecta puede bloquearte al instante.

Modelado del tráfico saliente con HTB

HTB te permite asignar a cada servicio un mínimo garantizado (rate) y un límite máximo (ceil). El ancho de banda no utilizado se destina a quien lo necesite, por orden de prioridad. A continuación se muestra una configuración funcional de tres niveles para un enlace ascendente de 1 Gbps.

Crea el qdisc HTB raíz. El default 30 envía cualquier paquete no clasificado a la clase 1:30 en lugar de permitir que eluda tus reglas:

tc qdisc add dev eth0 root handle 1: htb default 30

Limita el rendimiento total a 900 Mbps. Ajusta siempre el ancho de banda ligeramente por debajo de la capacidad real del enlace; de lo contrario, se formará una cola en un router o módem de upstream que no controlas:

tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit

Define los niveles de servicio. Los prio obtienen primero el ancho de banda no utilizado:

# High priority: web and API traffic
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1
 
# Medium priority: database replication
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 300mbit ceil 900mbit prio 2
 
# Low priority: bulk and backup traffic
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 100mbit ceil 900mbit prio 3

Añade fq_codel como qdisc de hoja en cada clase para que un solo flujo no pueda dominar su nivel:

tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

Ahora clasifica el tráfico. Para una simple coincidencia de puertos, u32 es lo más rápido:

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip dport 443 0xffff flowid 1:10

Para cualquier cosa con estado, marca en iptables y haz coincidir la marca con fw:

iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 2
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20

Modelado del tráfico entrante con IFB

No se puede modelar el tráfico entrante de forma nativa porque, para cuando llega un paquete, ya ha consumido su ancho de banda. La solución consiste en redirigir el tráfico entrante a una interfaz virtual de bloque funcional intermedio (IFB), donde el núcleo lo trata como tráfico saliente y permite aplicar qdiscs con clases.

Cargue el módulo y active la interfaz:

modprobe ifb numifbs=1
ip link set dev ifb0 up

Añada un qdisc de entrada a la interfaz física y redirija todo a ifb0:

tc qdisc add dev eth0 ingress handle ffff:
tc filter add dev eth0 parent ffff: protocol all u32 \
  match u32 0 0 action mirred egress redirect dev ifb0

A partir de aquí, ifb0 se comporta como cualquier otra interfaz. Aplícale tu árbol HTB exactamente igual que lo harías en el tráfico de salida:

tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1

Priorización del tráfico con DSCP

El DSCP (Differentiated Services Code Point) etiqueta los paquetes con un valor de 6 bits en el byte TOS, por lo que tus tc filtros puedan clasificar por etiqueta en lugar de buscar puertos en el conjunto de reglas. Al hacer coincidir el DSCP en tc, desplaza el valor 2 bits a la izquierda. DSCP EF (46) se convierte en 0xb8. La máscara 0xfc aisla los 6 bits de DSCP de los 2 bits de ECN.

Una asignación predeterminada razonable para cargas de trabajo de servidor:

Tipo de tráficoDSCPTOS hexEjemplos
InteractivoEF0xb8SSH, DNS, VoIP
NegociosAF410x88HTTP, HTTPS, API
MasivoCS10x20Copias de seguridad, FTP, actualizaciones de paquetes
Mejor esfuerzoCS00x00Todo lo demás

Etiqueta los paquetes salientes en iptables antes de que lleguen a tus tc filtros:

iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp 46

A continuación, compara la etiqueta en tc y redirígelo a la clase HTB correcta:

# EF (SSH, VoIP) goes to the high-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip tos 0xb8 0xfc flowid 1:10
 
# AF41 (web traffic) goes to the medium class
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 \
  match ip tos 0x88 0xfc flowid 1:20
 
# CS1 (bulk) goes to the low-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 \
  match ip tos 0x20 0xfc flowid 1:30

Supervisión y resolución de problemas

Los tres comandos que utilizarás constantemente:

tc -s qdisc show dev eth0
tc -s class show dev eth0
tc -s filter show dev eth0

Observa el dropped y overlimits . Los paquetes perdidos indican que la cola está saturada; los valores por encima del límite significan que has alcanzado el techo de la clase y el kernel ha tenido que retrasar o descartar tráfico. Para una vista en tiempo real:

watch -n 1 'tc -s class show dev eth0'

Añade -d para los parámetros internos (target, interval, quantum) y -j para la salida JSON si estás canalizando los datos a una pila de métricas. Combínalo con ss -tin para ver estimaciones de RTT y retransmisiones en la capa TCP.

La mayoría de los fallos se pueden resumir en una breve lista:

SíntomaCausa probableSolución
RTNETLINK answers: File existsQdisc raíz ya configuradotc qdisc del dev eth0 root primero
Las reglas se aplican, pero el tráfico no está limitadoInterfaz incorrecta, o TSO/GSO aún activadoConfirmar con ip link show, desactivar descargas con ethtool -K
El filtro nunca coincideSintaxis incorrecta del puerto/IP o alineación de la máscaraAñade una acción de contador y comprueba el recuento de aciertos en tc -s filter show
Las reglas desaparecen tras el reinicioLa configuración reside solo en memoriaEnvuélvelo en un script y llámalo desde systemd o un distribuidor de NetworkManager
Alta latencia en el tráfico prioritarioNo hay qdisc de hoja, o el burst es demasiado bajoAdjuntar fq_codel a clases leaf, aumentar burst

Si alguna vez te quedas bloqueado por una configuración errónea, el restablecimiento es sencillo:

tc qdisc del dev eth0 root

tc no se puede generar ancho de banda que no se tiene, pero en un enlace ascendente bien aprovisionado marca la diferencia entre un rendimiento predecible y un servidor que se colapsa en el momento en que un cliente inicia una transferencia de gran tamaño. Si necesitas el ancho de banda bruto y la libertad de configurarlo como quieras, echa un vistazo a los servidores dedicados de FDC.

Blog

Destacados de la semana

Más artículos
Linux Traffic Control (tc): una guía práctica

Linux Traffic Control (tc): una guía práctica

Controle el ancho de banda, priorice el tráfico y configure la entrada y salida en Linux con tc. Configuración de HTB, IFB, DSCP y fq_codel para servidores reales.

12 min de lectura - 5 de junio de 2026

Por qué es importante tener un VPS potente y sin contador

7 min de lectura - 9 de mayo de 2025

Más artículos