Ci sono due passi fondamentali per ottimizzare la larghezza di banda upstream. Per primo dobbiamo trovare un modo per prevenire che il modem ADSL metta in coda pacchetti fino a che non abbiamo il controllo su come esso la tratti. Per fare questo dovremo limitare la quantità di dati che il router invia su eth0 per rimanere leggermente sotto rispetto alla larghezza di banda totale dell'upstream del modem ADSL. Questo risulterà nell'avere il router che mette in coda pacchetti che arrivano dalla Rete Locale più velocemente di quanto esso possa inviarne.
Il secondo passo consiste nell'inserire una priorità di disciplina di coda sul router. Studieremo una coda che può essere configurata per dare priorità al traffico interattivo come il telnet o i giochi in modalità multi-player.
Il passo finale è di configurare il firewall per assegnare la priorità ai pacchetti utilizzando il campo fwmark.
Sebbene la connessione tra il router e il modem è a 10Mbit/s, il modem è capace di inviare dati solo a 128kbit/s. Ogni dato che ecceda questa quota verrà messo in coda sul modem. In questo modo, un pacchetto ping inviato dal router può andare al modem immediatamente, ma può impiegare qualche secondo per essere inviato effettivamente a Internet se la coda del modem ha qualche pacchetto al suo interno. Sfortunatamente molti modem ADSL non hanno nessun meccanismo per specificare come i pacchetti sono levati dalla coda o quanto sia larga questa, così il nostro primo obbiettivo è spostare il luogo dove i pacchetti in uscita sono messi in coda da qualche parte dove possiamo avere maggior controllo su di essa.
Possiamo realizzare questo utilizzando la coda HTB per limitare il tasso al quale inviamo i pacchetti al modem ADSL. Anche se la nostra larghezza di banda upstream può essere 128kbit/s dovremo limitare il valore al quale inviamo i pacchetti per fare in modo che sia leggermente inferiore a questo. Se vogliamo abbassare la latenza dobbiamo essere SICURI che neanche un singolo pacchetto sia messo in coda sul modem. Tramite prove ho scoperto che limitare il traffico uscente a circa 90kbit/s mi da quasi il 95% della larghezza di banda che posso ottenere senza il controllo di tasso HTB. Con HTB abilitato a questo valore, preveniamo la messa in coda dei pacchetti da parte del modem ADSL.
A questo punto non abbiamo ancora realizzato nessun cambiamento nella performance. Abbiamo semplicemente spostato la coda FIFO dal modem ADSL al router. In effetti, con Linux configurato con una coda di default di 100 pacchetti abbiamo probabilmente peggiorato il nostro problema! Ma non per molto...
Ad ogni classe adiacente in una coda HTB può essere assegnata una priorità. Mettendo differenti tipi di traffico in differenti classi e assegnando a queste classi differenti priorità, possiamo controllare l'ordine con il quale i pacchetti sono levati dalla coda e inviati. HTB rende ciò possibile, evitando contemporaneamente il prosciugamento delle altre classi, poiché c'è la possibilità di specificare un valore minimo garantito per ogni classe. In aggiunta, HTB ci permette di dire ad una particolare classe che può utilizzare qualsiasi larghezza di banda non utilizzata da altre classi fino ad una certa soglia.
Una volta che abbiamo le nostre classi pronte, dobbiamo creare dei filtri per distribuire il traffico nelle suddette. Ci sono diversi modi per farlo, ma il metodo descritto in questo documento utilizza i più noti comandi iptables/ipchains per marcare i pacchetti con un valore fwmark. I filtri mettono il traffico nelle classi della coda HTB basandosi sul loro fwmark. In questo modo, abbiamo la possibilità di creare delle matching rules con iptables per inviare certi tipi di traffico a determinate classi.
Il passo finale nella configurazione del vostro router per dare priorità al traffico interattivo è creare il firewall per definire come il traffico deve essere classificato. Questo viene ottenuto settando il campo fwmark del pacchetto.
Senza entrare in dettagli, di seguito c'è una descrizione semplificata di come i pacchetti uscenti possono essere classificati in 4 categorie con la 0x00 avente la priorità più alta:
Marcare TUTTI i pacchetti come 0x03. Questo li posiziona, per default, dentro la coda con priorità piu basssa.
Marcare i pacchetti ICMP come 0x00. Vogliamo pingare e mostrare la latenza per i pacchetti ad alta priorità.
Marcare tutti i pacchetti destinati alla porta 1024 o inferiore come 0x01. Questo da priorità ai servizi di sistema quali Telnet e SSH. Anche la porta di controllo FTP ricade in questo range comunque i dati di trasferimento FTP stanno su porte alte e rimangono nella banda 0x03.
Marcare tutti i pacchetti destinati alla porta 25 (SMTP) come 0x03. Se qualcuno invia e-mail con grandi allegati non vogliamo che affoghi il traffico interattivo.
Marcare tutti i pacchetti destinati a game server multiplayer come 0x02. Questo da ai giocatori bassa latenza ma evita loro di impantanare le applicazioni di sistema che la richiedono.
Marcare ogni pacchetto "piccolo" come 0x02. Pacchetti ACK uscenti generati da download entranti devono essere inviati prontamente per assicurare scaricamenti efficienti. Questo è possibile con l'utilizzo dell'iptables length module.
Ovviamente, tutto ciò può essere aggiustato secondo le vostre esigenze.
Ci sono altre due cose che potete fare per migliorare la vostra latenza. Primo, potete settare la Maximum Transmittable Unit (mtu) ad un valore più basso del default di 1500 bytes. Abbassando questo numero si abbasserà anche il tempo medio che dovrete aspettare per inviare un pacchetto prioritario se c'è già un pacchetto a bassa priorità full-sized che viene inviato. Abbassando questo numero decrescerà leggermente anche il vostro throughput perché ogni pacchetto contiene almeno 40 byte di valore di IP e TCP header information.
L'altra cosa che potete fare per migliorare la latenza anche sul vostro traffico a bassa priorità è di diminuire la lunghezza della coda dal valore di default di 100, la quale può impiegare anche 10 secondi per svuotarsi con una mtu di 1500 byte.
Usando l'Intermediate Queuing Device (IMQ), possiamo elaborare tutti i pacchetti entranti attraverso una coda nello stesso modo in cui lo facciamo con gli uscenti. La priorità dei pacchetti è piu semplice in questo caso. Potendo solo (provare a) controllare il traffico TCP in arrivo, potremmo mettere tutto il traffico non TCP nella classe 0x00, e tutto il traffico TCP nella classe 0x01. Potremmo anche mettere i pacchetti TCP "piccoli" nella 0x00 dato che questi sono per la maggior parte pacchetti ACK per dati in uscita che sono gia stati inviati. Creiamo una coda standard FIFO nella classe 0x00, e una coda Random Early Drop (RED) nella classe 0x01. La coda RED è migliore della FIFO (tail-drop) per controllare il TCP perché scarta i pacchetti prima di andare in overflow nel tentativo di rallentare trasferimenti che potrebbero andare fuori controllo. Possiamo limitare entrambe le classi ad un valore massimo inferiore all'effettivo valore in ingresso sul modem ADSL.
Vogliamo limitare il nostro traffico in ingresso per evitare di riempire la coda presso l'ISP,il quale può a volte bufferizzare fino a un valore di 5 secondi dei dati. Il problema è che attualmente l'unico modo per limitare il traffico TCP in ingresso è quello di scartare pacchetti perfettamente validi. Questi pacchetti hanno già preso una certa parte di banda sul modem ADSL solo per essere scartati dalla Linux Box nello sforzo di rallentare i futuri pacchetti. Essi saranno eventualmente ritrasmessi consumando ancora più banda. Quando limitiamo il traffico, limitiamo il rate dei pacchetti che saranno accettati nella nostra rete. Poiché l' attuale data rate in ingresso è leggermente superiore a causa dei pacchetti che scartiamo, dobbiamo limitare il downstream ad un valore molto più basso rispetto all'attuale valore del modem ADSL per assicurare una latenza bassa. In pratica devo limitare il mio downstream di 1.5 Mbit/s a 700kbit/sec per avere una latenza accettabile con 5 download concorrenti. Più sessioni TCP si hanno, più larghezza di banda si spreca con i pacchetti scartati, e più basso sarà il valore massimo da configurare.
Un miglior modo di controllare il traffico in arrivo potrebbe essere la manipolazione della larghezza della finestra del TCP, ma al momento di questa stesura non ci sono (libere) implementazioni di ciò per Linux (per quanto ne so...).