Come abbiamo visto le qdisc sono un elemento fondamentale e ne sono disponibili diverse con proprie caratteristiche e obiettivi. Alcune sono 'classful' ossia possono essere "suddivise" in sotto-classi (es. CBQ) altre invece 'classless'.
La differenza consiste nel fatto che le qdisc 'classful' sono utilizzate per generare le classi, mentre le qdisc 'classless' (RED, SFQ, ...) hanno la funzione di coda e quindi di gestione dei pacchetti che arrivano alla classe.
Per creare, modificare, cancellare una disciplina è necessario utilizzare il comando tc qdisc:
# tc qdisc help Usage: tc qdisc [ add | del | replace | change | get ] dev STRING [ handle QHANDLE ] [ root | ingress | parent CLASSID ] [ estimator INTERVAL TIME_CONSTANT ] [ [ QDISC_KIND ] [ help | OPTIONS ] ] tc qdisc show [ dev STRING ] [ingress] Where: QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. } OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help add|del|replace|change|get: è necessario sempre indicare l'operazione che si desidera effettuare: add (aggiungi), del (rimuovi), replace (sostituisci), change (cambia), get (ottiene l'ID interno utilizzato). dev: si deve specificare l'interfaccia/dispositivo su cui si desidera controllare il traffico (es. dev eth0). handle: è l'identificatore numerico utilizzato per distinguere le varie classi (es. 10:0). [root | ingress | parent]: root si utilizza quando si imposta una classe radice, ingress quando si desidera limitare il traffico in ingresso, parent per specificare la classe/nodo "padre". estimator: utilizzato per stabilire se i requesiti della coda sono soddisfatti. Usage: ... estimator INTERVAL TIME-CONST INTERVAL: intervallo tra i misuramenti TIME-CONST: costante media tempo Esempio: ... est 1sec 8sec
Le qdisc che possono essere utilizzare sono le seguenti:
CBQ (class-based queueing) è la 'queue discipline' più importante. E' basata su classi ossia è possibile creare diverse classi, che a loro volta possono essere suddivise in ulteriori classi, a cui assegnare caratteristiche differenti (bandwidth, priorità, coda, ...). Ciò permette, se si ha a disposizione ad esempio una banda pari a 10Mbit, di suddividerla in due classi, una con bandwidth di 3Mbit e una di 7Mbit. Potremmo così inviare il traffico più importante verso la banda più "larga" e quello meno importante sull'altra. I parametri richiesti da questa coda sono i seguenti:
# tc qdisc add cbq help Usage: ... cbq bandwidth BPS avpkt BYTES [ mpu BYTES ] [ cell BYTES ] [ ewma LOG ] bandwidth: bandwidth totale disponibile espressa in bytes o altra misura (es. 1Mbit, 10Mbit, 128kbps ...) avpkt: dimensione media dei pacchetti, nel caso di pacchetti ethernet corrisponde a 1000 byte mpu: dimensione minima che può avere un pacchetto, nel caso ethernet corrisponde a 64 byte cell: impostata in genere a 8 byte ewma: exponential weighted moving average NOTA: i parametri compresi tra [ parentesi quadre ] sono opzionali. Es.: tc qdisc add dev eth0 root handle 1: cbq bandwidth 10Mbit avpkt 1000
L'algoritmo FIFO (First In, First Out) è l'algoritmo di default e probabilmente il più semplice. I pacchetti che arrivano prima sono i primi ad essere serviti e quindi ad essere inviati. Se un pacchetto arriva mentre è in corso l'invio di alcuni pacchetti presenti nella coda, questo è accodato. Se la coda però è completamente occupata, la "policy" determinerà se questo pacchetto deve essere scartato oppure se un pacchetto presente nella coda deve essere rimosso per fargli posto.
+---------+ --- o --->| | |o|o|o|----> +---------+ coda FIFO # tc qdisc add pfifo help Usage: ... [p|b]fifo [ limit NUMBER ] limit: dimensione della coda. Se si sceglie pfifo questo valore deve essere espresso in numero di pacchetti. Se si sceglie bfifo può essere indicato in byte. Es.: tc qdisc add dev eth0 parent 1:10 pfifo
CSZ utilizza sia WFQ (Weighted Fair Queueing) sia priority. Priority è ideale per i servizi real-time, mentre WFQ supporta e gestisce guaranteed service e link sharing. Al momento CSZ è inutilizzabile e probabilmente sarà sostituito con h-pfq.
Questo algoritmo permette di suddividere i pacchetti in diverse code (bande) ciascuna con diversa priorità. In base a questa priorità viene selezionata la coda da cui prelevare il pacchetto da inviare in output. Se la coda con priorità maggiore ha dei pacchetti saranno quest'ultimi ad essere inviati, se è vuota saranno inviati (se presenti) i pacchetti della seconda coda in ordine di priorità.
+-----+ |o| | |------+ +-----+ | P1 | +-----+ | - o -+ |o|o| | +-----> | +-----+ | P2 | +-----+ +->|o| | | +-----+ P3 # tc qdisc add prio help Usage: ... prio bands NUMBER priomap P1 P2.. bands: numero di bande che si vogliono creare (default 3) priomap: priorità delle bande. Da aggiornare se si indicano più bande del valore di default, ossia 3. Questa è la priomap di default: 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1. Es.: tc qdisc add dev eth0 parent 1:10 prio
RED è utilizzata per controllare la congestione della rete ed è usata in particolare con le backbone. Questo algoritmo si basa sui protocolli TCP/IP, ed il suo scopo è quello di simulare una situazione di congestione della rete prima che essa avvenga realmente. Questa simulazione permette di tenere sotto controllo la latenza, la coda e di evitare diversi inconvenienti noti. Il TCP/IP infatti prevede inizialmente un invio contenuto di pacchetti che tende ad aumentare progressivamente fino al completo esaurimento della banda a disposizione con conseguenti pacchetti scartati, richieste di ritrasmissione, ...
# tc qdisc add red help Usage: ... red limit BYTES min BYTES max BYTES avpkt BYTES burst PACKETS probability PROBABILITY bandwidth KBPS limit: dimensione della coda in byte min: soglia minima della coda prima di cominciare a scartare i pacchetti Per una linea ISDN 64kbit/s si dovrebbe aggirare sui 1600 bytes, considerando una latenza di 200 ms. (min = bandwidth*latenza). E' importante scegliere un valore min che non sia troppo basso o eccessivo altrimenti si potrebbero ottenere rispettivamente un degrado del throughput o della latenza. max: soglia massima della coda che l'algoritmo deve rispettare. Dovrebbe essere il doppio del parametro min. avpkt: dimensione media dei pacchetti burst: numero massimo di pacchetti che possono essere inviati in un certo istante (burst). probability: probabilità che i pacchetti siano scartati in caso di raggiungimento del limite bandwidth: bandwidth a disposizione
SFQ (Stochastic Fairness Queueing) [RFC1254] prevede che i pacchetti siano distinti in base ai parametri delle loro intestazioni. Nel caso di pacchetti IP in base a indirizzo sorgente, destinazione. Questo permette di distinguere i flussi, le connessioni stabilite. SFQ prevede l'allocazione e l'utilizzo di una nuova coda FIFO per ogni flusso di pacchetti. I pacchetti poi saranno prelevati dalle code e inviati nella rete utilizzando una disciplina round-robin, che consiste nel prelevare in ordine un pacchetto da ogni coda (se presente) e nell'inviarlo in rete. Le code FIFO sono quindi trattate in modo equo, imparziale (Fairness). In caso di congestione è prevista la rimozione di pacchetti dalla coda FIFO che ne contiene il maggior numero. Per tenere traccia dei vari flussi è utilizzata una tabella hash che come noto è soggetta a collisioni, ciò può degradare l'imparzialità di trattamento, quindi è previsto un meccanismo di "perturbamento" periodico della hash function in modo da limitare le collisioni. I benefici che si traggono da questo tipo di implementazione sono un consumo minimo di risorse CPU e di memoria.
+-------------------+ | +-----+ .<.. | |o| | |--.---+ | | +-----+ . .| | | FIFO . ^| | | +-----+ . .| | - o -+ |o|o| | . .+----->> | | +-----+ . . | | | FIFO . . | | | +-----+ v . | +------> |o| | | . . | | +-----+ ..>. | | FIFO | +-------------------+ # tc qdisc add sfq help Usage: ... sfq [ perturb SECS ] [ quantum BYTES ] perturb: intervallo di tempo prima di effettuare un'operazione di "perturbamento" quantum: corrisponde in genere a MTU (caso ethernet si utilizza 1514b). Es.: tc qdisc add dev eth0 parent 1:10 sfq quantum 1514b perturb 15
...
...
TBF (Token Bucket Filter) è un algoritmo diverso dai precedenti in quanto l'invio dei pacchetti nella rete dipende da una seconda struttura (bucket) in cui sono memorizzati dei token. I token sono aggiunti nel bucket a cadenza regolare (es. 1 ogni secondo), e sono utilizzati per determinare se un pacchetto può essere inviato nella rete, se deve attendere oppure se deve essere scartato. Se un pacchetto arriva e il bucket non contiene almeno un token allora dovrà attenderne l'arrivo di uno (l'implementazione in Linux prevede che questi pacchetti siano scartati) prima di essere inviato nella rete, altrimenti può essere inviato immediatamente e un token è rimosso dal bucket. Se il bucket è completamente occupato i nuovi token sono scartati.
+---- O r token/secondo | V | | |O| |O| +-+ | V --- pacchetti ----- o ----->| | -------> rete --- # tc qdisc add tbf help Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ] [ peakrate KBPS ] [ latency TIME ] limit: numero massimo di byte che possono essere accodati burst: numero massimo di byte che possono essere inviati in un certo istante (burst). rate: velocità trasmissione dati (KBPS) mtu: maximum transfer unit peakrate: limite massimo di pacchetti che possono essere inviati. latency: latenza Es.: tc qdisc add dev eth0 parent 1:10 tbf rate 64Kbit buffer 5Kb/8 limit 10Kb
Generalized RED.
Usage: ... gred DP drop-probability limit BYTES min BYTES max BYTES avpkt BYTES burst PACKETS probability PROBABILITY bandwidth KBPS [prio value] OR ... gred setup DPs <num of DPs> default <default DP> [grio]
Questa qdisc permette di realizzare i "Differentiated Services" sfruttando differenti per-hop behaviour (PHB). I pacchetti sono distinti attraverso il campo DS presente nell'intestazione IP. Nel caso del protocollo IPv4 il campo DS corrisponde al campo TOS (Type Of Service) che è riutilizzato ed esteso. Tutti i pacchetti con lo stesso valore DS sono trattati come un singolo flusso.
Usage: dsmark indices INDICES [ default_index DEFAULT_INDEX ] [ set_tc_index ] Es.: tc qdisc add dev eth0 handle 1:0 root dsmark indices 64
Questa disciplina speciale è utilizzata per limitare il traffico in ingresso ad una interfaccia. Gli eventuali pacchetti che eccedono il limite sono scartati. Un utilizzo per questa qdisc pùò essere ad esempio quello di limitare attacchi TCP SYN flooding.
Usage: ... ingress Es.: tc qdisc add dev eth0 handle ffff: ingress
Per creare una qdisc root, supponendo di avere a disposizione una banda da 10Mbit, che permetta di utilizzare più classi dove indirizzare i pacchetti è possibile utilizzare la qdisc CBQ:
+------------ QDISC CBQ -----------+ | | | | | | Pacchetto --> | | | | | | | = ---> | | eth0 | | | | | | | | | | +----------------------------------+ # ----------------------------------------------------------------------------- # Crea e associa all'interfaccia eth0 una qdisc root cbq e identificala con 10: # bandwidth totale a disposizione 10Mbit avpkt 1000 byte. # ----------------------------------------------------------------------------- tc qdisc add dev eth0 root handle 10: cbq bandwidth 10Mbit avpkt 1000