Controllo del traffico (tc) di Linux: una guida pratica
12 min di lettura - 5 giugno 2026

Controllare la larghezza di banda, assegnare priorità al traffico e modellare l'ingresso e l'uscita su Linux con tc. Configurazione di HTB, IFB, DSCP e fq_codel per server reali.
Controllo del traffico Linux (tc): una guida pratica
Il comando tc ti offre il controllo diretto su come il tuo server gestisce il traffico di rete. È possibile limitare la larghezza di banda per servizio, mantenere reattive le sessioni interattive come SSH quando i trasferimenti in blocco raggiungono picchi elevati e modellare sia i flussi in uscita che quelli in entrata da un unico strumento. Questa guida tratta i concetti fondamentali, una configurazione HTB funzionante, l'ingress shaping con IFB, la prioritizzazione basata su DSCP e come eseguire il debug in caso di malfunzionamenti.
Come funziona tc
Ogni tc configurazione è costituita da quattro parti mobili:
- qdisc (queuing discipline). Lo scheduler collegato a un'interfaccia di rete. Decide come i pacchetti vengono inseriti e rimossi dalla coda.
- Classe. Una suddivisione all'interno di un qdisc classful. Pensatela come una corsia con un proprio limite di velocità.
- Filtro. Esamina le intestazioni dei pacchetti (IP, porte, marcatori) e assegna ogni pacchetto a una classe.
- Azione. Cosa succede a un pacchetto una volta che viene abbinato: inoltro, eliminazione, reindirizzamento.
Questi elementi formano un albero. I pacchetti entrano nel qdisc radice, incontrano i filtri, vengono ordinati in classi tramite un major:minor handle e finiscono in coda in un qdisc foglia per la trasmissione.
Per qualsiasi cosa più complessa della corrispondenza basata sulla porta, contrassegnare i pacchetti con iptables o nftables nella tabella mangle, quindi utilizzare il fw filtro in tc per classificare in base al contrassegno. È molto più scalabile rispetto al concatenare regole grezze u32 per ogni tipo di traffico.
Uscita vs entrata
La direzione è importante. Il kernel può bufferizzare e ritardare i pacchetti in uscita, ed è questo che consente un vero shaping. I pacchetti in entrata hanno già attraversato la linea quando li vedete, quindi potete solo controllarli (eliminarli se superano una soglia) a meno che non li reindirizziate prima verso un dispositivo IFB.
| Caratteristica | Uscita | Ingresso |
|---|---|---|
| Direzione | In uscita | In entrata |
| Modellazione | Nativo | Richiede IFB |
| Controllo | Supportato | Supportato |
| Uso tipico | QoS, condivisione della larghezza di banda, regolazione della velocità | Limitazione della velocità, mitigazione DDoS di base |
I qdisc che userete effettivamente
- HTB (Hierarchical Token Bucket). Con classi. Da utilizzare quando si desidera una larghezza di banda minima garantita per servizio con la possibilità di prendere in prestito capacità inutilizzata da altre classi.
- TBF (Token Bucket Filter). Senza classi. Da utilizzare quando è necessario limitare l'intera interfaccia a una singola velocità.
- fq_codel (Fair Queuing Controlled Delay). Combina l'equità per flusso con la gestione attiva delle code per eliminare il bufferbloat. È il qdisc predefinito nella maggior parte delle distribuzioni Linux a partire da systemd 217 ed è preinstallato su RHEL 9. Collegatelo sempre come qdisc foglia sotto le classi HTB, altrimenti un singolo flusso avido può monopolizzare un'intera classe.
Configurazione di tc su un server Linux
tc viene fornito con il pacchetto iproute2. Su Debian e Ubuntu, installarlo con apt-get install iproute2. Su RHEL e derivati, yum install iproute. È necessario avere i privilegi di root o sudo.
Ottenere prima il nome corretto dell'interfaccia. Un nome errato dell'interfaccia è il motivo più comune per cui una configurazione non produce alcun risultato:
ip link showControlla cosa c'è già sull'interfaccia, compresi i contatori in tempo reale:
tc -s qdisc show dev eth0Cancella qualsiasi qdisc di root esistente prima di applicare una nuova configurazione, per evitare RTNETLINK answers: File exists errori:
tc qdisc del dev eth0 root 2>/dev/null || trueSe stai aggiornando una regola esistente invece di partire da zero, usa replace invece di add per uno swap atomico.
L'offloading hardware come TSO e GSO raggruppa i pacchetti in modi che interferiscono con lo shaping. Disattivarli sull'interfaccia sottoposta a shaping:
sudo ethtool -K eth0 tso off gso offImposta fq_codel come qdisc predefinito a livello di sistema per le nuove interfacce:
sysctl -w net.core.default_qdisc=fq_codelPer i server molto trafficati, abbinalo all'algoritmo di controllo della congestione BBR (kernel 4.9+). BBR mantiene alto il throughput senza far crescere le code:
sysctl -w net.ipv4.tcp_congestion_control=bbrUn'abitudine di sicurezza se si sta configurando un dispositivo remoto tramite SSH: aprire una seconda sessione e avere tc qdisc del dev eth0 root pronto per l'incollaggio. Una regola di filtro errata può bloccarti all'istante.
Modellare il traffico in uscita con HTB
HTB consente di assegnare a ciascun servizio un minimo garantito (rate) e un limite massimo (ceil). La larghezza di banda inutilizzata viene destinata a chi ne ha bisogno, in ordine di priorità. Ecco una configurazione funzionante a tre livelli per un uplink da 1 Gbps.
Creare il qdisc HTB di base. Il default 30 invia qualsiasi pacchetto non classificato alla classe 1:30 anziché lasciarlo bypassare le tue regole:
tc qdisc add dev eth0 root handle 1: htb default 30Limita il throughput totale a 900 Mbps. Regola sempre la larghezza di banda leggermente al di sotto della capacità effettiva del collegamento, altrimenti si formerà una coda su un router o un modem a monte che non controlli:
tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbitDefinire i livelli di servizio. I valori prio ottengono per primi la larghezza di banda inutilizzata:
# 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 3Aggiungi fq_codel come qdisc foglia su ciascuna classe in modo che un singolo flusso non possa dominare il proprio livello:
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_codelOra classificare il traffico. Per una semplice corrispondenza delle porte, u32 è più veloce:
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
match ip dport 443 0xffff flowid 1:10Per qualsiasi cosa che sia stateful, contrassegnare in iptables e abbinare il contrassegno 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:20Modellare il traffico in entrata con IFB
Non è possibile modellare nativamente il traffico in entrata perché, nel momento in cui un pacchetto arriva, ha già utilizzato la larghezza di banda. La soluzione alternativa consiste nel reindirizzare il traffico in entrata verso un'interfaccia virtuale Intermediate Functional Block (IFB), dove il kernel lo tratta come traffico in uscita e consente di applicare qdisc di classe.
Caricare il modulo e attivare l'interfaccia:
modprobe ifb numifbs=1
ip link set dev ifb0 upAggiungere un qdisc in ingresso all'interfaccia fisica e reindirizzare tutto 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 ifb0Da questo punto in poi, ifb0 si comporta come qualsiasi altra interfaccia. Applica il tuo albero HTB esattamente come faresti in uscita:
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 1Priorità del traffico con DSCP
Il DSCP (Differentiated Services Code Point) contrassegna i pacchetti con un valore a 6 bit nel byte TOS, in modo che i tc filtri possano classificare in base al tag anziché cercare le porte in tutto il set di regole. Quando si abbina il DSCP in tc, sposta il valore a sinistra di 2 bit. DSCP EF (46) diventa 0xb8. La maschera 0xfc isola i 6 bit DSCP dai 2 bit ECN.
Una mappatura predefinita ragionevole per i carichi di lavoro dei server:
| Tipo di traffico | DSCP | TOS esadecimale | Esempi |
|---|---|---|---|
| Interattivo | EF | 0xb8 | SSH, DNS, VoIP |
| Business | AF41 | 0x88 | HTTP, HTTPS, API |
| Bulk | CS1 | 0x20 | Backup, FTP, aggiornamenti dei pacchetti |
| Best effort | CS0 | 0x00 | Tutto il resto |
Contrassegna i pacchetti in uscita in iptables prima che raggiungano i tuoi tc filtri:
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp 46Quindi abbinare il tag in tc e instradalo alla classe HTB corretta:
# 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:30Monitoraggio e risoluzione dei problemi
I tre comandi che userai costantemente:
tc -s qdisc show dev eth0
tc -s class show dev eth0
tc -s filter show dev eth0Guarda il dropped e overlimits . I pacchetti persi indicano che la coda è satura; i superamenti dei limiti indicano che hai raggiunto il limite massimo della classe e che il kernel ha dovuto ritardare o eliminare il traffico. Per una visualizzazione in tempo reale:
watch -n 1 'tc -s class show dev eth0'Aggiungi -d per i parametri interni (target, interval, quantum) e -j per l'output JSON se stai inviando i dati a uno stack di metriche. Abbinalo a ss -tin per vedere le stime RTT e le ritrasmissioni a livello di TCP.
La maggior parte degli errori rientra in un breve elenco:
| Sintomo | Probabile causa | Soluzione |
|---|---|---|
RTNETLINK answers: File exists | qdisc di root già configurato | tc qdisc del dev eth0 root prima |
| Le regole si applicano ma il traffico non è limitato | Interfaccia errata, oppure TSO/GSO ancora attivi | Verifica con ip link show, disabilitare gli offload con ethtool -K |
| Il filtro non trova mai corrispondenze | Sintassi porta/IP errata o allineamento della maschera | Aggiungere una contro-azione e controllare il conteggio degli accessi in tc -s filter show |
| Regole scomparse dopo il riavvio | La configurazione risiede solo in memoria | Inserire in uno script e richiamare da systemd o da un dispatcher di NetworkManager |
| Elevata latenza sul traffico prioritario | Nessun qdisc leaf, o burst troppo basso | Collegare fq_codel alle classi leaf, aumentare burst |
Se mai dovessi bloccarti a causa di una configurazione errata, il ripristino è semplice:
tc qdisc del dev eth0 roottc non puoi creare larghezza di banda che non hai, ma su un uplink ben dimensionato fa la differenza tra prestazioni prevedibili e un server che va in tilt nel momento in cui un utente avvia un trasferimento di grandi dimensioni. Se hai bisogno della larghezza di banda grezza e della libertà di modellarla come preferisci, dai un'occhiata ai server dedicati di FDC.

Controllo del traffico (tc) di Linux: una guida pratica
Controllare la larghezza di banda, assegnare priorità al traffico e modellare l'ingresso e l'uscita su Linux con tc. Configurazione di HTB, IFB, DSCP e fq_codel per server reali.
12 min di lettura - 5 giugno 2026
Perché è importante avere un VPS potente e senza contatore
7 min di lettura - 9 maggio 2025

Avete domande o avete bisogno di una soluzione personalizzata?
Opzioni flessibili
Portata globale
Distribuzione immediata
Opzioni flessibili
Portata globale
Distribuzione immediata