Control de tráfico en Linux (tc): una guía práctica
12 min de lectura - 5 de junio de 2026

Controla el ancho de banda, prioriza el tráfico y modula el tráfico de entrada y salida en Linux con tc. Configuraciones funcionales de HTB, IFB, DSCP y fq_codel para servidores reales.
Control de tráfico en Linux (tc): una guía práctica
El tc te permite controlar directamente cómo gestiona tu servidor el tráfico de red. Puedes limitar el ancho de banda por servicio, garantizar que las sesiones interactivas como SSH sigan respondiendo cuando se produzcan picos de transferencias masivas y regular tanto el tráfico saliente como el entrante desde una única herramienta. Esta guía abarca los conceptos básicos, una configuración funcional de HTB, la regulación del tráfico entrante 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 (direcciones 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 o redirigir.
Estos elementos forman un árbol. Los paquetes entran por el qdisc raíz, pasan por los filtros, se clasifican en clases mediante un major:minor identificador y acaban en la cola de 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 clasificarlos según la 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 núcleo puede almacenar en búfer y retrasar los paquetes salientes, lo que es lo que permite una regulación real. Los paquetes entrantes ya han atravesado la red en el momento en que los ves, por lo que solo puedes controlarlos (descartarlos por superar un umbral) a menos que los redirijas primero a un dispositivo IFB.
| Característica | Salida | Entrada |
|---|---|---|
| Dirección | Salida | Entrante |
| Regulación | Nativo | Requiere IFB |
| Control | Compatible | Compatible |
| Uso típico | QoS, reparto de ancho de banda, control de ritmo | Limitació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. Asigna siempre este qdisc como qdisc «hoja» bajo clases HTB; de lo contrario, un solo flujo «glotón» 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 sus derivados, yum install iproute. Necesitarás privilegios de root o sudo.
Averigua primero el nombre correcto de la interfaz. Indicar un nombre incorrecto para la interfaz es la razón más habitual por la que una configuración no produce ningún efecto de forma silenciosa:
ip link showComprueba qué hay ya en la interfaz, incluidos los contadores en tiempo real:
tc -s qdisc show dev eth0Elimina 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 || trueSi estás actualizando una regla existente en lugar de empezar desde cero, utiliza replace en lugar de add para realizar un intercambio atómico.
La descarga de hardware, como TSO y GSO, agrupa los paquetes de forma que interfiere con el shaping. Desactívalas en la interfaz sometida a shaping:
sudo ethtool -K eth0 tso off gso offEstablece fq_codel como qdisc predeterminado para todo el sistema en las nuevas interfaces:
sysctl -w net.core.default_qdisc=fq_codelEn el caso de servidores con mucha actividad, combínalo 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=bbrUn 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 pegarlo. Una regla de filtrado errónea puede bloquearte el acceso al instante.
Regulación del tráfico saliente con HTB
HTB 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 30Limita 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 origen que no controlas:
tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbitDefine 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 3Añade fq_codel como qdisc de hoja en cada clase para que un único 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_codelAhora clasifica el tráfico. Para una coincidencia de puertos sencilla, 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:10Para cualquier cosa que requiera 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:20Regulación del tráfico entrante con IFB
No es posible modelar el tráfico de entrada de forma nativa, ya que, para cuando llega un paquete, ya ha consumido tu ancho de banda. La solución consiste en redirigir el tráfico de entrada a una interfaz virtual de Bloque Funcional Intermedio (IFB), donde el núcleo lo trata como tráfico de salida y te permite aplicar qdiscs basados en clases.
Carga el módulo y activa la interfaz:
modprobe ifb numifbs=1
ip link set dev ifb0 upAñade un qdisc de entrada a la interfaz física y redirige 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 ifb0A 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 1Priorizació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 tener que buscar puertos en todo el conjunto de reglas. Al comparar el DSCP en tc, desplaza el valor 2 bits hacia la izquierda. DSCP EF (46) pasa a ser 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áfico | DSCP | TOS hex | Ejemplos |
|---|---|---|---|
| Interactivo | EF | 0xb8 | SSH, DNS, VoIP |
| Empresarial | AF41 | 0x88 | HTTP, HTTPS, API |
| Masivo | CS1 | 0x20 | Copias de seguridad, FTP, actualizaciones de paquetes |
| Mejor esfuerzo | CS0 | 0x00 | Todo 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 46A continuación, compara la etiqueta en tc y redirígelo a la clase HTB adecuada:
# 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:30Supervisió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 eth0Observa el dropped y overlimits . Los paquetes perdidos indican que la cola está saturada; los valores por encima de los límites indican que se ha alcanzado el techo de una clase y que el núcleo 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 obtener la salida en 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 clasificar en una breve lista:
| Síntoma | Causa probable | Solución |
|---|---|---|
RTNETLINK answers: File exists | El qdisc raíz ya está configurado | tc qdisc del dev eth0 root primero |
| Las reglas se aplican, pero el tráfico no se limita | Interfaz incorrecta, o TSO/GSO sigue activado | Confirmar con ip link show, desactiva las descargas con ethtool -K |
| El filtro nunca coincide | Sintaxis incorrecta del puerto o la IP, o alineación de la máscara | Añade una acción de contramedida y comprueba el recuento de coincidencias en tc -s filter show |
| Las reglas desaparecen tras el reinicio | La configuración reside únicamente en memoria | Incorpóralo en un script y llámalo desde systemd o un distribuidor de NetworkManager |
| Alta latencia en el tráfico prioritario | No hay qdisc de hoja, o el burst es demasiado bajo | Adjuntar 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 roottc 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 cuanto un cliente inicia una transferencia de gran volumen. Si necesitas el ancho de banda bruto y la libertad para modelarlo como quieras, echa un vistazo a los servidores dedicados de FDC.

Tutorial de iperf3: Comprobar la velocidad de red en Linux y Windows
Instala iperf3, realiza pruebas de ancho de banda y ajusta los búferes TCP para obtener resultados precisos en Linux y Windows. Abarca pruebas UDP, bidireccionales y de 10 GbE o más.
10 min de lectura - 7 de mayo de 2026
Perfiles optimizados para la optimización de la carga de trabajo de los servidores Linux
16 min de lectura - 9 de junio de 2026