In Linux la limitazione di banda non è un singolo comando magico. Se vuoi un risultato affidabile devi prima decidere dove applicare il limite: sull’interfaccia, su un singolo processo, su un gruppo di container, oppure solo in uscita verso una certa destinazione. La scelta cambia sia il comportamento sia il rischio operativo. Un limite messo nel punto sbagliato è facile da aggirare, difficile da misurare e spesso rompe più traffico del previsto.
La regola pratica è semplice: se ti serve un controllo di rete serio, usa traffic shaping con tc. Se ti serve una misura rapida e poco precisa, puoi appoggiarti a strumenti per singolo processo o a filtri del firewall, ma sappi che stai lavorando con un compromesso. Se l’obiettivo è proteggere un link saturo o dare priorità a traffico critico, il shaping sul kernel è la strada corretta.
Prima decisione: cosa stai limitando davvero
Prima di toccare la configurazione, chiarisci lo stato atteso e quello osservato. Atteso: il traffico di un host, di una VLAN o di un processo non deve superare una certa soglia. Osservato: oggi quella soglia viene superata, oppure vuoi prevenire che lo sia in futuro. Questa distinzione evita interventi inutili. Limitare tutto il traffico a livello di interfaccia per risolvere un problema che riguarda un solo job di backup è una soluzione grossolana, ma spesso è la prima che si prova quando manca visibilità.
In ordine di affidabilità, i metodi più usati sono questi:
- tc con qdisc e classi: controllo preciso, adatto a produzione.
- cgroup e network namespace: utile se il carico è confinato in container o servizi systemd.
- firewall con rate limit: comodo per casi semplici, ma non è shaping vero.
- tool applicativi o proxy: validi solo se controlli l’app e il flusso è molto specifico.
Se non sai ancora quale layer toccare, misura prima. Verifica il traffico reale con iftop, nload, ip -s link o metriche di monitoring. Senza un baseline rischi di impostare un limite arbitrario e poi inseguire falsi positivi.
Il metodo giusto per la maggior parte dei casi: tc
tc lavora sullo stack di rete del kernel e permette di definire code, classi e filtri. Per limitare la banda in uscita su un’interfaccia, il caso più comune è usare HTB o tbf. HTB è più flessibile, perché consente gerarchie e priorità; TBF è più lineare e utile quando vuoi un cap secco e basta.
Se l’obiettivo è dare a un server un tetto massimo di 100 Mbit/s sull’interfaccia eth0, una configurazione base con TBF può bastare:
sudo tc qdisc add dev eth0 root tbf rate 100mbit burst 32kbit latency 400ms
Qui rate è il limite effettivo, burst assorbe i picchi brevi e latency definisce il tempo massimo di attesa in coda. Il valore di burst non va scelto a caso: se è troppo basso, il traffico diventa nervoso e perdi throughput; se è troppo alto, il limite si ammorbidisce più del previsto. In pratica, il tuning dipende dalla velocità della linea e dal pattern del traffico.
Per verificare il risultato, guarda la coda e i contatori:
tc -s qdisc show dev eth0
Nel blocco di output cerca aumento di packets, presenza di overlimits e una crescita coerente con il limite impostato. Se il traffico continua a salire senza segni di shaping, probabilmente il qdisc non è agganciato all’interfaccia giusta oppure un’altra regola lo sta sovrascrivendo.
HTB quando ti serve più di un semplice tetto massimo
HTB è il punto di equilibrio migliore quando vuoi dividere banda tra servizi diversi. Per esempio: backup notturni limitati a 20 Mbit/s, traffico web con priorità più alta e replica database con banda garantita ma controllata. In questi casi un solo limite globale non basta, perché il problema vero non è solo la quantità totale, ma la distribuzione.
Una configurazione minimale può essere costruita così:
sudo tc qdisc add dev eth0 root handle 1: htb default 30
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 80mbit ceil 100mbit
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20mbit ceil 20mbit
In questo schema la classe 1:20 è il collo di bottiglia per il traffico che le assegni. Il default 30 significa che il traffico non classificato finisce in una classe predefinita, che devi definire se vuoi evitare buchi di comportamento. Senza una classificazione chiara, tc non indovina il traffico: lo lascia andare dove hai deciso tu, o dove hai dimenticato di decidere.
Per agganciare i pacchetti a una classe, puoi usare u32, fw mark o filtri basati su indirizzi e porte. Se hai già un firewall che marca i pacchetti, usare fw è spesso la strada meno fragile. Esempio:
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 handle 20 fw flowid 1:20
Qui il pacchetto con mark 20 viene instradato nella classe 1:20. Questo approccio è pulito perché separa il tagging dal shaping. Il firewall decide chi è il traffico, tc decide quanto può passare.
Limitare per processo o per servizio systemd
Se il traffico da contenere appartiene a un servizio ben definito, puoi lavorare con systemd e cgroup. Questo è particolarmente utile per backup agent, exporter, job batch o demoni che generano traffico in modo prevedibile. Il vantaggio è operativo: non devi inseguire PID dinamici a mano e puoi mantenere il controllo in una unità di servizio.
Una configurazione moderna può usare le proprietà di bandwidth disponibili in systemd, ma la compatibilità dipende dalla versione. Quando non vuoi affidarti a una feature specifica, puoi combinare il servizio con una rete namespace o con un wrapper che avvia il processo sotto condizioni controllate. In ambienti recenti, vale la pena verificare cosa supporta la tua release con:
systemctl --version
systemctl show nome-servizio.service | grep -E 'CPU|IO|Tasks|ManagedOOM|IPAccounting'
IPAccounting=yes non limita la banda, ma ti aiuta a misurare il traffico del servizio. È un buon punto di partenza perché spesso il vero problema è capire chi consuma banda prima ancora di limitarlo. Se il servizio è in un container, il controllo può essere più semplice a livello di orchestratore o namespace, ma il principio resta lo stesso: misura, poi limita.
Firewall: utile per rate limit, non per shaping serio
Molti confondono il rate limit del firewall con la limitazione di banda. Sono cose diverse. Un firewall può limitare il numero di connessioni o pacchetti, ma questo non equivale a controllare i megabit al secondo. È utile per difesa e contenimento, meno per garantire una quota di throughput.
Con nftables puoi fare limitazioni per connessione o per pacchetto, ad esempio per ridurre il rumore di un endpoint esposto. Un esempio di tipo difensivo è questo:
nft add rule inet filter input tcp dport 22 limit rate 10/second accept
Questo però non limita la banda SSH a 10 connessioni al secondo in senso stretto, e soprattutto non è un sostituto del shaping. Se il tuo obiettivo è evitare che un backup si mangi il link, il firewall da solo non basta. Se invece vuoi ridurre l’impatto di un servizio esposto o contenere un comportamento anomalo, allora ha senso.
Un caso pratico: backup che saturano la WAN
Scenario classico: alle 02:00 parte un backup remoto e la WAN si satura, con effetti collaterali su VPN, monitoring e mail. Il sintomo non è sempre un down totale; spesso è un degrado intermittente, con latenza alta e timeout sparsi. Qui il primo obiettivo non è rifare il backup, ma contenere il danno.
- Identifica l’interfaccia e il flusso con
ss,iftopo log del job. - Applica un cap temporaneo con
tcsulla porta o sul mark del traffico backup. - Verifica che il throughput si stabilizzi e che i servizi critici tornino reattivi.
- Solo dopo, valuta se spostare la finestra, comprimere meglio o cambiare protocollo.
Un errore comune è limitare il traffico sul server sbagliato. Se il backup usa un canale cifrato verso un endpoint remoto, il collo di bottiglia può stare sia in uscita sia in ingresso, e il limite va applicato sul punto in cui il traffico passa davvero. Se non sei sicuro, conferma con ip route get e con una traccia sintetica del flusso.
ip route get 203.0.113.10
ss -tpn | grep ':443'
Il primo comando ti dice quale interfaccia e quale gateway vengono usati. Il secondo ti mostra i socket attivi verso la destinazione, utile per associare un processo al traffico. Se il job gira in un container, aggiungi il namespace o il cgroup al quadro, altrimenti rischi di mettere il limite nel posto sbagliato.
Persistenza: evitare che il limite sparisca al reboot
Le regole tc non sono persistenti di default. Dopo un reboot spariscono, quindi in produzione devi prevedere un ripristino automatico. Il metodo più pulito è un’unità systemd dedicata o uno script richiamato al boot che applichi la configurazione in modo idempotente.
Un approccio semplice è creare uno script in /usr/local/sbin/traffic-shaping.sh e richiamarlo con un service. La logica deve prima rimuovere eventuali qdisc esistenti e poi applicare quelli nuovi, ma senza fare pulizie aggressive su interfacce non coinvolte. Prima di automatizzare, testa a mano e salva l’output di:
tc qdisc show dev eth0
journalctl -u nome-servizio-shaping.service -b
Se usi Ansible, Puppet o un pannello, il vantaggio è la ripetibilità. Il rischio è solo uno: rendere meno visibile il cambiamento. Per questo ogni modifica deve avere un diff chiaro e un rollback altrettanto chiaro. La forma più banale di rollback è rimuovere il qdisc con tc qdisc del dev eth0 root, ma va fatto solo se hai verificato che non stai togliendo anche un controllo utile ad altri flussi.
Misurare se il limite funziona davvero
Il limite non è valido perché il comando è stato accettato. È valido quando il traffico osservato si allinea alla soglia attesa e gli effetti collaterali restano entro tolleranza. La metrica più utile dipende dal caso: throughput medio, picco, p95 di latenza, perdita pacchetti o error rate applicativo.
Per un cap di banda, controlla almeno tre cose:
- il traffico reale su interfaccia con
ip -s linko tool equivalenti; - i contatori di
tc -s qdisc show; - la latenza dei servizi critici prima e dopo il limite.
Se il throughput si stabilizza ma la latenza peggiora troppo, il limite è troppo stretto o il buffer è mal tarato. Se invece la banda resta alta e i contatori non mostrano shaping, il filtro non sta intercettando il traffico giusto. In entrambi i casi il problema non è “Linux non funziona”, ma il punto di applicazione scelto male.
Errori tipici che fanno perdere tempo
Il primo errore è confondere limitazione di connessioni con limitazione di banda. Il secondo è applicare il limite su un’interfaccia sbagliata, per esempio sulla NIC fisica quando il traffico passa in realtà da un bridge o da una VLAN. Il terzo è non considerare il traffico in ingresso, che non si limita con la stessa semplicità dell’uscita e spesso richiede soluzioni diverse, come ingress policing o shaping lato peer.
Un altro errore frequente è impostare un limite senza escludere traffico critico. Se la stessa interfaccia trasporta SSH, monitoraggio e backup, un cap globale può rendere più difficile proprio la gestione dell’incidente che stai cercando di evitare. In questi casi conviene separare per classe, per mark o per policy di routing, non affidarsi a un singolo numero secco.
Infine, non dare per scontato che il traffico sia sempre IPv4. Se in rete c’è IPv6, devi verificare che le regole coprano anche quel flusso, altrimenti limiti metà del problema e l’altra metà continua a saturare il link.
Quando conviene non toccare Linux ma il punto di uscita
Se il traffico passa da un router, da un firewall o da un appliance di edge, a volte è meglio applicare il limite lì invece che sull’host. Questo vale soprattutto quando vuoi controllare più server con una sola policy, oppure quando il server non ha visibilità completa sul percorso di rete. In un ambiente con VLAN, tunnel e bilanciatori, il punto di shaping più efficace può essere a monte del sistema operativo.
Il criterio pratico è questo: limita nel punto più vicino possibile alla sorgente del problema, ma non oltre. Se il problema è un singolo demone, il cgroup è più preciso. Se il problema è un server intero, tc sull’interfaccia è spesso la scelta giusta. Se il problema è la somma di più host, sposta il controllo a livello di rete.
Conservare il controllo senza fare danni
La regola operativa migliore è applicare prima un limite provvisorio, osservare per un intervallo sufficiente e solo dopo consolidare. Ogni modifica che tocca banda, code o priorità può avere un blast radius più ampio di quanto sembri: non colpisce solo il traffico target, ma anche DNS, SSH, monitoring e aggiornamenti automatici. Per questo il rollback deve essere immediato e noto prima del change.
Se vuoi una procedura robusta, tieni sempre a portata questi tre elementi: il comando per verificare lo stato, il comando per rimuovere il limite e il criterio per dire che il test è fallito. Nel caso di tc, questo significa salvare l’output iniziale, applicare il qdisc, leggere i contatori e rimuovere tutto se la latenza o l’accessibilità peggiorano oltre soglia.
In sintesi, limitare la banda in Linux è facile solo in apparenza. Il risultato buono arriva quando scegli il layer giusto, misuri prima di cambiare e accetti che non esiste una sola tecnica valida per tutti i casi. Il kernel offre gli strumenti; l’operatore deve scegliere quello coerente con il traffico reale, non con l’idea astratta di “mettere un limite”.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.