Controllo del traffico, shaping Masetti Marco v0.1, 01 Luglio 2000 Questo documento introduce e descrive come impostare Linux per effet­ tuare il controllo del traffico (traffic control - shaping). ______________________________________________________________________ Indice Generale 1. Introduzione 2. Liberatoria 3. QoS (Quality of Service) 3.1 Modelli 3.2 QoS e Linux 4. Shaper device 4.1 Introduzione 4.2 Esempio 5. TC (traffic control) 6. Kernel 6.1 Impostazioni 6.2 Descrizione 7. iproute2 7.1 Dove trovare il pacchetto 7.2 Compilare ed installare iproute2 7.3 Documentazione 7.4 tc 7.5 ip 8. Queue 8.1 Introduzione 8.2 qdisc 8.3 Creare una qdisc root 9. Classi 9.1 Introduzione 9.2 CBQ 9.3 Creare le classi 9.4 Associare una qdisc alle classi 9.5 DSMARK 10. Classificatori 10.1 Introduzione 10.2 Filtri 11. Varie 11.1 Dettagli sul traffico 11.2 Impostazioni 11.3 Unità 12. Esempi 12.1 Esempio 1 - CBQ e filtro route 12.2 Esempio 2 - CBQ e filtro u32 12.3 Esempio 3 - CBQ e filtro fw 12.4 Esempio 4 - CBQ e filtro fw 12.5 Esempio 5 - ingress 12.6 Esempio 6 - ingress e dsmark 13. Risorse 14. Marchi registrati ______________________________________________________________________ 1. Introduzione In molti casi gli internet service provider e chi è intenzionato a offrire dei servizi (ftp, mail, ...) hanno la necessità di poter controllare e gestire il traffico della rete. Il protocollo standard di internet (IP), che si occupa dell'istradamento dei pacchetti, non è stato progettato originariamente per soddisfare in modo completo queste esigenze. IP (Internet Protocol) si basa su best effort, ossia tutti i pacchetti sono trattati e considerati allo stesso modo. In genere quindi sono inoltrati nella rete dal router in base all'ordine di arrivo. Esiste anche la possibilità di garantire a dei pacchetti un trattamento più efficiente e prioritario utilizzando il campo TOS (Type Of Service) presente nell'intestazione dei pacchetti IP, però questa soluzione non è sufficiente e completa. Servizi come mail, www in effetti non hanno necessità di particolari trattamenti, ma altri invece come i servizi real-time, video- conferenze, ... che stanno assumendo sempre maggior importanza sono penalizzati da questo sistema che inevitabilmente ne degrada le prestazioni. Il QoS (Quality of Service) ha come obiettivo permettere un maggior controllo dei pacchetti e della rete. Il desiderio in genere è quindi di garantire agli utenti che lo richiedono un certo tipo di qualità della trasmissione dei dati, dedicando ad esempio ad un certo tipo di traffico una porzione della bandwidth disponibile oppure assegnando a determinati pacchetti una priorità maggiore. Alcuni potrebbero infatti richiedere un accesso ftp veloce, altri di accedere a video conferenze o a servizi real time a velocità soddisfacenti. Le aziende potrebbero avere la necessità di gestire la banda a disposizione, limitando ad esempio il traffico FTP e WWW a favore di un accesso rapido e immediato ai database. Questo documento ha come obiettivo introdurre e spiegare come ottenere il controllo del traffico utilizzando Linux. Al momento non è ancora completo (anzi...), se si riscontrano degli errori inviate un'email all'indirizzo marcomas@libero.it 2. Liberatoria L'autore non si assume alcuna responsabilità, esplicita o implicita, riguardante questo documento. Il documento deve essere visto come un'introduzione alle funzionalità di controllo del traffico offerte dal S.O. Linux. Non sono, e non pretendo di esserlo, un esperto dell'argomento. 3. QoS (Quality of Service) 3.1. Modelli La IETF (Internet Engineering Task Force) ha proposto in passato diversi modelli per soddisfare le richieste di QoS tra cui: · Integrated-services · Differentiated-services Integrated-services In questo modello è previsto che l'applicazione richieda uno specifico tipo di servizio prima di poter inviare i dati nella rete. Questo in genere avviene inviando al router dei segnali specifici. Il router appena ha a disposizione le risorse necessarie invia conferma all'applicazione che può finalmente inviare i dati. A questo scopo è utilizzato il protocollo Resource Reservation Protocol (RSVP). Questo modello purtroppo non si è affermato come standard a causa di noti problemi di scalabilità e di implementazione. Differentiated-services Con questo modello si è cercato di risolvere i problemi che affliggono l'Integrated-services, in particolare la necessità di dover richiedere attraverso dei segnali le risorse, e senza dover rivoluzionare il protocollo IP. A questo scopo è stato deciso di "riutilizzare" ed estendere il campo TOS (Type Of Service), presente nell'intestazione IP, per ottenere in modo semplice e scalabile il controllo del traffico. 3.2. QoS e Linux Linux a partire dal kernel versione 2.1.x incorpora codice dedicato al controllo del traffico realizzato da Alexey Kuznetsov kuznet@ms2.inr.ac.ru , autore anche del pacchetto iproute2 che comprende il programma tc utilizzato per la gestione e l'impostazione degli elementi del controllo del traffico. Con la versione 2.0.36 è disponibile inoltre anche lo shaper device che permette di controllare la velocità di trasferimento dei dati in uscita da un'interfaccia. Altri sistemi operativi noti che supportano QoS sono tra gli altri BSD e Sun Solaris. 4. Shaper device 4.1. Introduzione In passato Alan Cox aveva già introdotto un meccanismo piuttosto semplice per controllare e limitare il traffico in uscita. E' stato aggiunto e funziona correttamente a partire dai kernel versione 2.0.36 (stabile) e 2.1 (sviluppo). Esiste inoltre anche un pacchetto rshaper-1.07.tar.gz disponibile all'indirizzo ftp.systemy.it che dovrebbe permettere di controllare anche il traffico in ingresso. Per gestire lo shaping è necessario in questo caso compilare il driver come modulo (shaper.o) e utilizzare il programma shapecfg per la configurazione. Nota: la velocità di trasmissione minima che si può impostare è di 9600 baud, quella massima è di 256K. 4.2. Esempio Esempio #!/bin/bash # --------------------------------------------------------- # velocità di trasmissione 64Kbits (min. 9600, max. 256000) # --------------------------------------------------------- SPEED=64000 # --------------------------------------------------------- # Variabili riguardanti gli indirizzi della rete # --------------------------------------------------------- IPADDRESS=192.168.0.1 NETMASK=255.255.255.0 BROADCAST=192.168.0.255 RETE=... NETMASK_RETE=... echo "shaping ..." # --------------------------------------------------------- # inserire prima di tutto il modulo shaper.o # --------------------------------------------------------- insmod shaper # --------------------------------------------------------- # selezionare l'interfaccia utilizzata per lo shaping, in # questo caso eth0 # --------------------------------------------------------- shapecfg attach shaper0 eth0 # --------------------------------------------------------- # impostare la velocitò di invio dei dati # --------------------------------------------------------- shapecfg speed shaper0 $SPEED # --------------------------------------------------------- # impostare i parametri come una qualsiasi interfaccia # --------------------------------------------------------- ifconfig shaper0 $IPADDRESS netmask $NETMASK broadcast $BROADCAST up # --------------------------------------------------------- # impostare l'instradamento (rotte) affinché i pacchetti # diretti verso la rete $RETE utilizzino il device shaper0 # appena creato (qui si possono vagliare diverse soluzioni). # --------------------------------------------------------- route add -net $RETE netmask $NETMASK_RETE dev shaper0 Questo sistema è molto semplice e permette di gestire il traffico anche se in modo molto limitato. Sono comunque disponibili dei pacchetti che permettono di ampliarlo. 5. TC (traffic control) Rispetto allo shaping realizzato con il modulo shaper.o il nuovo codice presente nei kernel 2.1, 2.2, 2.3 e 2.4 prevede nuove possibilità e un maggior controllo. E' sempre possibile stabilire la velocità di trasmissione dei dati in uscita da una interfaccia, però è anche possibile finalmente stabilire delle priorità tra i pacchetti, suddividere i pacchetti in base alla destinazione, al tipo, ai bit TOS (Type Of Service) su diverse bande con larghezza e priorità diverse. Per implementare tutte queste nuove caratteristiche è stato necessario introdurre i seguenti elementi: · disciplina delle code · classi · filtri · policing disciplina della coda Le discipline delle code (qdisc) sono l'elemento fondamentale, ogni pacchetto proveniente da un'interfaccia viene accodato e in base alla qdisc prescelta sarà poi prelevato e inviato nella rete dall'interfaccia di output. Esistono diverse discipline delle code, quella di default è la FIFO (First IN, First OUT): il primo pacchetto arrivato e anche il primo ad uscire (best- effort). Questa disciplina è molto semplice, ne esistono comunque altre più complesse (RED, TBF, CBQ). Alcune come la CBQ consentono di creare delle classi ciascuna con proprie caratteristiche e funzionalità, altre come la SFQ sono in grado di offrire buone prestazioni in termini di consumo di memoria e CPU, ... classi Le classi permettono di definire delle "sotto-bande" e di stabilirne la bandwidth (es. 500KB), la priorità oltre ad altri parametri. Inoltre ogni classe può essere ulteriormente suddivisa in sotto-classi ognuna avente le proprie caratteristiche. Ad ogni classe in genere si associa infine una coda, che come già visto si occuperà di stabilire quali pacchetti inviare per prima, in quale ordine, quali eventualmente scartare. Se non si provvede a specificarla sarà utilizzata quella di default ossia FIFO. filtri I filtri detti anche classificatori sono utilizzati per "smistare" i pacchetti e indirizzarli verso le classi corrispondenti. Lo "smistamento" può avvenire per indirizzo sorgente o destinazione, in base ad uno dei campi del pacchetto (es. porta destinazione www, ftp-data, ...), in base a come il filtro dei pacchetti (firewall) lo ha marcato oppure in base alla tabella degli instradamenti. policing In situazioni di traffico eccessivo, congestione per evitare che certi limiti siano superati è necessario prendere delle decisioni, ad esempio scartare (DROP) alcuni pacchetti in modo selettivo o arbitrario, ciò per impedire il degrado delle prestazioni. Attraverso queste componenti è possibile quindi implementare il QoS. Ecco un esempio semplificato del percorso effettuato da un pacchetto nel caso si utilizzi una qdisc CBQ: .. .. .. +-------+ .. || >|TCP/UDP|> || || / +-------+ \ || || / \ +------+ || o -->ETH1 ---> Demultiplexing ---> FORWARDING --->| TC | ---> ETH0 --> o || +------+ || || ^^^^^^^^ || || / \ || +------------------------------------------/-------- -\-------+ / \ ------------------------------/ \-------------- / \ +----------------------------- TC -------------------------------+ |+-------------------------- QDISC ----------------------------+|| || || || +--------- CLASSE A -------+ || || ------------ | +--------------+ | || Pacchetto o ->|-->+--> | Filtro A | --> = -> |o|o| Coda | | | ---> = ---+ || || | ------------ | +--------------+ | | || || | +--------------------------+ | || || | +--> = ---> o || | +--------- CLASSE B -------+ | || || | ---------- | +--------------+ | | || || +--> | Filtro B | --> = -> |o| | Coda | | | ---> = ---+ || || ----------- | +--------------+ | || || +--------------------------+ || || || |+--------------------------------------------------------------+| +----------------------------------------------------------------+ In questo caso il pacchetto proveniente dalla rete entra attraverso l'interfaccia ETH1, quindi prosegue e viene sottoposto eventualmente a modifiche o controlli (es. filtraggio) quindi prima di essere inoltrato nella rete esterna attraverso l'interfaccia ETH0 è sottoposto al controllo del traffico. Il pacchetto in questa fase è passato ai filtri che stabiliscono a quale classe appartiene ed è quindi accodato nella coda corrispondente che deciderà infine quando, come e se inviarlo. Vediamo un esempio più realistico: +---------------------------- QDISC ---------------------------+ | | | +--------- CLASSE A -------+ | | ------------ | +----------------+ | | Pacchetto --> |-->+--> |Filtro WWW| --> = -> | TBF, rate=5Mbps|--> = ---+ | | | ------------ | +----------------+ | | | | | +--------------------------+ | | | | | | | | +--------- CLASSE B -------+ | | | | ------------ | +----------------+ | | | | +--> |Filtro MAIL| -->= -> | FIFO,rate=2Mbps|--> = ---+----= --> | | ------------- | +----------------+ | | | | | +--------------------------+ | | | | | | | | +--------- CLASSE C -------+ | | | | ------------ | +----------------+ | | | | +--> | Default | -->= -> | FIFO,rate=3Mbps|--> = ---+ | | ------------- | +----------------+ | | | +--------------------------+ | +--------------------------------------------------------------+ In questo caso sono state create tre classi ognuna con una propria bandwidth (5, 2 e 3 Mbps) e qdisc (TBF, FIFO), i pacchetti sono poi suddivisi all'arrivo dai filtri. I pacchetti destinati alla porta www sono quindi accodati nella coda corrispondente alla classe A, i pacchetti destinati alla porta smtp (mail) alla classe B e infine tutti gli altri pacchetti (telnet, ftp, dns, ...) sono collocati nella coda della classe C. In molti casi per rappresentare graficamente l'organizzazione delle classi si utilizza un grafo ad albero: ______ / \ | QDISC | \______/ / \ / \ / \ ______ ______ / \ / \ |CLASSE A| |CLASSE B| \______/ \______/ E' necessario sottolineare che è possibile controllare solo il traffico in uscita ossia inviato, spedito da un'interfaccia. Il traffico in arrivo ad esempio il download di un file via ftp, supponiamo da Internet, non è controllabile. La velocità di trasferimento dei dati in questo caso dipende dal tipo di connessione (ISDN, ADSL), dal server, ... Eventualmente è possibile comunque limitare il flusso dei pacchetti in arrivo in modo che siano rispettati certi limiti. Inoltre si può utilizzare il controllo del traffico anche su più interfacce, nell'esempio seguente si utilizza un computer (PC0) con tre interfacce ethernet, su cui si imposta il controllo del traffico sulle interfacce eth2 ed eth1 per quanto riguarda il traffico diretto rispettivamente alla LAN e alla rete dei server. eth2 con TC +----+ | |PC1 |----+ | eth0 +----+ | | / +----+ | \+----+/ |MAC2|----+----|PC0 |--O----------> INTERNET +----+ | +----+ | / | . / | +---+ eth1 +--|WWW| con TC | +---+ | +---+ +--|FTP| | +---+ . [RETE LAN] [RETE SERVER] Una volta stabilite le qdisc e i filtri è possibile impostare uno script che attraverso il programma tc realizzi ciò che si desidera. Per poter creare e gestire il traffico è necessario compilare il kernel selezionando le voci corrispondenti al QoS e installare il pacchetto iproute2 che contiene il programma tc (traffic controller) da utilizzare per le impostazioni. 6. Kernel 6.1. Impostazioni Il kernel contiene una voce (QoS and/or fair queueing) che consente di aggiungere il supporto al QoS e la selezione dei vari algoritmi disponibili. E' necessario aggiungere che il supporto QoS non è completo e ancora in sviluppo, per questo è necessario selezionare la voce Code maturity level options ---> [*] Prompt for development and/or incomplete code/drivers durante il menuconfig. Comunque vediamo le voci disponibile nel kernel, in questo caso si tratta della versione 2.3.99pre8. Code maturity level options ---> [*] Prompt for development and/or incomplete code/drivers [CONFIG_EXPERIMENTAL] Networking Options ---> ... [*] QoS and/or fair queueing ---> [*] QoS and/or fair queueing (EXPERIMENTAL) [CONFIG_NET_SCHED] CBQ packet scheduler [CONFIG_NET_SCH_CBQ] CSZ packet scheduler [CONFIG_NET_SCH_CSZ] The simplest PRIO pseudoscheduler [CONFIG_NET_SCH_PRIO] RED queue [CONFIG_NET_SCH_RED] SFQ queue [CONFIG_NET_SCH_SFQ] TEQL queue [CONFIG_NET_SCH_TEQL] TBF queue [CONFIG_NET_SCH_TBF] GRED queue Diffserv field marker Ingress Qdisc [*] QoS support [CONFIG_NET_QOS] [*] Rate estimator [CONFIG_NET_ESTIMATOR] [*] Packet classifier API [CONFIG_NET_CLS] TC index classifier Routing table based classifier [CONFIG_NET_CLS_ROUTE4] Firewall based classifier [CONFIG_NET_CLS_FW] U32 classifier [CONFIG_NET_CLS_U32] Special RSVP classifier [CONFIG_NET_CLS_RSVP] Special RSVP classifier for IPv6 [CONFIG_NET_CLS_RSVP6] [*] Traffic policing (needed for in/egress) 6.2. Descrizione Code maturity level options ---> [*] Prompt for development and/or incomplete code/drivers Il supporto QoS (Quality of Service) nella versione del kernel 2.4 è ancora al momento in via di sviluppo, quindi ci sono diverse cose che non sono implementate o che necessitano ancora di modifiche e test. Attivando questa opzione nel menu "Networking Options --->" compare la voce "QoS and/or fair queueing --->" che permette di selezionare i moduli del QoS. [*] Qos and/or fair queueing (EXPERIMENTAL) Quando il kernel deve inviare nella rete molti pacchetti deve decidere quali inviare per primi, quali dopo, quali scartare. Questo lavoro viene svolto dal "packet scheduler". Esistono diversi algoritmi che possono essere utilizzati a questo scopo (CBQ, CSZ, PRIO, FIFO ...). Se rispondi N, sarà utilizzato il "packet scheduler" di default ossia FIFO (First In, First Out). Se rispondi Y, potrai invece selezionare diversi algoritmi alternativi, che potranno poi essere assegnati ai differenti dispositivi di rete. Inoltre sarà possibile abilitare l'utilizzo, sul router Linux, del "differentiated service" (diffserv) e del "Resource Reservation Protocol" (RSVP). Se rispondi Y qui e anche alla voce "/proc file system" sarà possibile leggere varie informazioni sullo stato dei packet scheduler nel file /proc/net/psched. CBQ packet scheduler Se si risponde Y, allora si potrà utilizzare il packet scheduler CBQ (Class-Based Queueing) per i dispositivi di rete. Questo algoritmo classifica i pacchetti in una gerarchia di classi organizzate ad albero. CBQ è molto comune e permette di utilizzare qualsiasi algoritmo di gestione delle code che seguono. Modulo: sch_cbq.o CSZ packet scheduler Se si risponde Y, si potrà utilizzare il packet scheduler CSZ (Clark-Shenker-Zhang). Al momento è l'unico algoritmo che permette di ottenere "guaranteed services" per le applicazioni real-time. Nota: questo scheduler al momento non funziona ancora correttamente e probabilmente sarà sostituito con un altro algoritmo. Modulo: sch_csz.o The simplest PRIO pseudoscheduler Se si risponde Y, si potrà utilizzare un packet scheduler con coda a n-bande con priorità. Rispondi Y, se vuoi che l'algoritmo CBQ la utilizzi come disciplina per i nodi foglia. Modulo: sch_prio.o RED queue Se si risponde Y, si potrà utilizzare l'algoritmo di packet scheduling RED (Random Early Detection). Modulo: sch_red.o SFQ queue Se si risponde Y, si potrà utilizzare l'algoritmo di packet scheduling SFQ (Stochastic Fairness Queueing). Modulo: sch_sfq.o TEQL queue Se si risponde Y, si potrà utilizzare l'algoritmo di packet scheduling TLE (True Link Equalizer) sia per i dispositivi di rete sia come disciplina per l'algoritmo di scheduling CBQ. Questa disciplina delle code permette di combinare più dispositivi fisici in un dispositivo virtuale. Modulo: sch_teql.o TBF queue Se si risponde Y, si potrà utilizzare l'algoritmo di packet scheduling TBF (Token Bucket Filter) sia per i dispositivi di rete che come disciplina per l'algoritmo di scheduling CBQ. Modulo: sch_tbf.o GRED queue Generalized RED. Modulo: sch_gred.o Diffserv field marker Modulo: sch_dsmark.o Ingress Qdisc Modulo: sch_ingress.o [*] QoS support Se si risponde Y, si potranno sfruttare alcune caratteristiche aggiuntive di scheduling per il QoS. Ad esempio si potranno impostare dei limiti di rate-of-flow per i dispositivi di rete. [*] Rate estimator Per consentire allo scheduling QoS di operare correttamente, è necessario stimare il rate-of-flow del dispositivo di rete. [*] Packet classifier API L'algoritmo di scheduling CBQ richiede che i pacchetti, che devono essere spediti nella rete attraverso un dispositivo di rete, siano classificati in base ad alcuni criteri. Se si risponde Y, si potranno selezionare tra diversi classificatori/filtri di pacchetti. TC index classifier Segue elenco dei filtri o classificatori disponibili. Routing table based classifier E' necessario rispondere Y se si desidera classificare i pacchetti da inviare in base alle voci della tabella di routing. Modulo: cls_route.o Firewall based classifier E' necessario rispondere Y se si desidera classificare i pacchetti da inviare in base ai criteri impostati nel firewall. Modulo: cls_fw.o U32 classifier E' necessario rispondere Y se si desidera classificare i pacchetti da inviare in base all'indirizzo di destinazione o ad altri campi delle intestazioni (IP, TCP, UDP). Modulo: cls_u32.o Special RSVP classifier Il protocollo RSVP (Resource Reservation Protocol) permette a dei sistemi di richiedere per una connessione un minimo e massimo data flow rate; questo è importante per dati real-time (video, suono). E' necessario rispondere Y se si desidera classificare i pacchetti da inviare in base alle richieste RSVP. Modulo: cls_rsvp.o Special RSVP classifier for IPv6 Come sopra ma implementato per essere utilizzato con il protocollo IPv6. Modulo: cls_rsvp6.o Traffic policing (necessario per in/egress) Modulo: sch_police.o 7. iproute2 7.1. Dove trovare il pacchetto Il pacchetto iproute2 è disponibile all'indirizzo ftp.inr.ac.ru/ip- routing/iproute2-current.tar.gz (circa 139K). Oltre al tool tc, fondamentale per impostare i parametri e realizzare il controllo del traffico, contiene anche il programma ip per la configurazione della rete, che sostituisce e completa ifconfig, route, ... 7.2. Compilare ed installare iproute2 Per compilare il pacchetto è necessario scompattare l'archivio con il comando: # tar -zxvf iproute2...tar.gz Il pacchetto iproute2-2.2.4-now-ss000305.tar.gz contiene i seguenti file/directory: Config Makefile Patches/ README README.decnet README.iproute2+tc RELNOTES doc/ etc/ examples/ include-glibc/ include/ ip/ lib/ tc/ A questo punto si può accedere alla directory iproute2 ed eseguire il comando: # make 7.3. Documentazione Per la documentazione è necessario accedere alla directory doc e come al solito eseguire: # make E' necessario che i pacchetti relativi a laTEX siano installati. 7.4. tc Terminata la compilazione è possibile utilizzare per la configurazione del controllo del traffico il programma tc presente nella directory tc/. Il suo utilizzo è comune a tanti altri tool disponibili per Linux. Per ottenere un help in linea è sufficiente impartire il comando: # tc help Usage: tc [ OPTIONS ] OBJECT { COMMAND | help } where OBJECT := { qdisc | class | filter } OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] } OPTIONS: è possibile ottenere un insieme di informazioni statistiche riguardanti i pacchetti/byte gestiti, scartati, ... (-s[tatistics). Ottenere maggiori dettagli e informazioni (-d[etails]). Ottenere valori grezzi (-r[aw]). OBJECT: gli oggetti che possono essere impostati sono 3: qdisc (discipline delle code), class (classi), filter (filtri). 7.5. ip Uno strumento molto potente è anche ip che può essere utilizzato ad esempio in questo modo per configurare una rete: Impostare un'interfaccia: ------------------------- ifconfig/route ifconfig eth0 1.2.3.4 netmask 255.255.255.0 broadcast 1.2.3.255 route add -net 1.2.3.0 netmask 255.255.255.0 route add default gw 1.2.3.1 ip ip address add 1.2.3.4/24 broadcast 1.2.3.255 dev eth0 ip link set dev eth0 up (necessaria!) ip route add default via 1.2.3.1 Stato delle interfacce: ----------------------- ifconfig/route ifconfig ip ip address show Stato delle rotte: ----------------------- ifconfig/route route -n ip ip route show 8. Queue 8.1. Introduzione 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 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 8.2. qdisc Le qdisc che possono essere utilizzare sono le seguenti: · CBQ (Class-Based Queueing) · FIFO (packet (pFIFO) oppure byte (bFIFO)) · CSZ (Clark-Shenker-Zhang) · PRIO (Priority n-bande) · RED (Random Early Detect) · SFQ (Stochastic Fairness Queueing) · TEQL (Traffic Equalizer) · TBF (Token Bucket Filter) · GRED (generic random early detection) · Diffserv field marker · Ingress Qdisc CBQ 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 FIFO 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 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. PRIO 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 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 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 TEQL ... ... TBF 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 GRED 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 default [grio] Diffserv field marker 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 Ingress Qdisc 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 8.3. Creare una qdisc root 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 9. Classi 9.1. Introduzione La disciplina CBQ (Class-based queueing) permette di creare più classi, a loro volta ulteriormente suddividibili, ognuna con le proprie caratteristiche (rate, priorità, identificatore, ...). Inoltre è sempre associata una delle qdisc viste precedentemente (SFQ, FIFO, ...) che servono a stabilire come devono essere gestiti i pacchetti che arrivano. Se non si specifica una coda allora è utilizzata per default la FIFO. Le qdisc che supportano le classi (classful) sono: CBQ, DS_MARK, CSZ e p-FIFO. Le altre non le supportano e sono dette classless (RED, TBF, ...). Graficamente si possono rappresentare in questo modo: +------------------- QDISC CBQ -------------------+ |+--------------- CLASSE CBQ ROOT ---------------+| ______ || || / \ || +-CLASSE A 8Mbit prio 3 ---+ || | ROOT | || | +----------------+ | || \______/ Pacchetto -->== = -> | SFQ |--> = ---+ || /10:1\ || | +----------------+ | | || 8Mbit / \ 2Mbit || +--------------------------+ | || ______ ______ || +--> ==---> / \ / \ || +-CLASSE B 2Mbit prio 2 ---+ | || |CLASSE A| |CLASSE B| || | +--------------+ | | || \______/ \______/ || = -> | FIFO | ---> = ---+ || 10:100 10:200 || | +--------------+ | || || +--------------------------+ || |+-----------------------------------------------+| +-------------------------------------------------+ Per creare una classe è necessario utilizzare il comando tc class e quindi impostare correttamente i parametri: # tc class help Usage: tc class [ add | del | change | get ] dev STRING [ classid CLASSID ] [ root | parent CLASSID ] [ [ QDISC_KIND ] [ help | OPTIONS ] ] tc class show [ dev STRING ] [ root | parent CLASSID ] Where: QDISC_KIND := { prio | cbq | etc. } OPTIONS := ... try tc class add help dev: device, interfaccia classid: identificatore della classe. Es. 10:100 il primo numero (10) indica in genere la classe root contenitore, il secondo numero (100) è l'identificatore della classe. Attraverso questo identificatore possiamo indicare univocamente la classe e ad esempio utilizzarla per associarle una qdisc. root | parent: la struttura delle classi è ad albero, in genere si ha un nodo root (classe "contenitore") e diverse classi. Per ciascuna di queste classi è necessario specificare da quale classe/nodo derivano utilizzando il parametro parent. QDISC_KIND: qdisc da utilizzare. 9.2. CBQ Per creare una classe con qdisc CBQ è necessario specificare diversi parametri: # tc class add cbq help Usage: ... cbq bandwidth BPS rate BPS maxburst PKTS [ avpkt BYTES ] [ minburst PKTS ] [ bounded ] [ isolated ] [ allot BYTES ] [ mpu BYTES ] [ weight RATE ] [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ] [ estimator INTERVAL TIME_CONSTANT ] [ split CLASSID ] [ defmap MASK/CHANGE ] bandwidth: larghezza di banda totale a disposizione rate: bandwidth assegnata a questa classe maxburst: numero massimo di pacchetti che possono essere inviati nel burst avpkt: dimensione media di un pacchetto minburst: numero minimo di pacchetti bounded: da specificare se non si desidera che la classe possa utilizzare la banda a disposizione della classe "parent" da cui deriva. isolated: da specificare se non si desidera che la classe condivida la propria bandwidth con nessuna classe che non sia discendente. allot: MTU + intestazione MAC. Nel caso ethernet è da impostare a 1500+14=1514 byte mpu: numero minimo di bytes che possono essere inviati in un pacchetto weight: parametro da scegliere in modo che sia proporzionale al parametro 'rate' Es. 1/10 di rate prio: priorità da associare alla classe cell: impostata in genere a 8 byte ewma: vedi sopra estimator: vedi sopra split: utilizzato per accessi rapidi defmap: si utilizza per assegnare alla classe i pacchetti con i bit TOS (caso pacchetti in arrivo) o priorità (caso pacchetti generati localmente) specificati e che non sono classificabili in nessun'altra classe. 9.3. Creare le classi Ad esempio per creare le classi del grafo precedente, supponendo di aver già creato la qdisc root 10:, è necessario utilizzare i seguenti comandi: # ------------------------------------------------------------------------- # Creazione della prima classe ROOT. # bandwidth assegnata 10Mbit, priorità della classe 8. # allot nel caso ethernet è da impostare a 1514 (allot=MTU+MAC) # weight è da scegliere proporzionale a rate, in genere 1/10 di rate. # ------------------------------------------------------------------------- tc class add dev eth0 parent 10:0 classid 10:1 cbq bandwidth 10Mbit rate 10Mbit \ allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 avpkt 1000 # ---------------------------------------------------------------------------------------------- # Crea e associa una classe all'interfaccia eth0, la classe parent è root 10:1 già creata. # La classe è di tipo cbq, la bandwidth totale è di 10Mbit, alla classe sono assegnati 8Mbit, # la priorità assegnata è 3 e inoltre non si desidera che la banda possa essere condivisa # (bounded). Gli altri parametri (allot 1514, avpkt 1000, ...) sono sempre gli stessi. # ---------------------------------------------------------------------------------------------- tc class add dev eth0 parent 10:1 classid 10:100 cbq bandwidth 10Mbit rate 8Mbit allot 1514 weight 800kbit prio 3 maxburst 20 avpkt 1000 bounded # ---------------------------------------------------------------------------------------------- # Crea e associa una classe all'interfaccia eth0, la classe parent è root 10:1 già creata. # La classe è di tipo cbq, la bandwidth totale è di 10Mbit, alla classe sono assegnati 2Mbit, la # priorità assegnata è 2 e inoltre non si desidera che la banda possa essere condivisa (bounded). # ---------------------------------------------------------------------------------------------- tc class add dev eth0 parent 10:1 classid 10:200 cbq bandwidth 10Mbit rate 2Mbit allot 1514 weight 200kbit prio 2 maxburst 20 avpkt 1000 bounded 9.4. Associare una qdisc alle classi A questo punto è possibile associare alle classi create una qdisc (SFQ, RED, FIFO, TBF, ...) utilizzando il classid assegnato. # ---------------------------------------------------------------------------------------------- # Associamo alla classe 10:100 una qdisc SFQ #----------------------------------------------------------------------------------------------- tc qdisc add dev eth0 parent 10:100 sfq quantum 1514b perturb 15 #----------------------------------------------------------------------------------------------- # Associamo alla classe 10:200 una qdisc FIFO bfifo #----------------------------------------------------------------------------------------------- tc qdisc add dev eth0 parent 10:200 bfifo Conclusa questa fase le classi sono completate. Non resta che utilizzare i classificatori/filtri per smistare i pacchetti in arrivo nelle classi create. 9.5. DSMARK Per creare una class dsmark è necessario utilizzare il comando tc class e quindi impostare i parametri della classe: Usage: ... dsmark [ mask MASK ] [ value VALUE ] Es.: tc class change dev eth0 classid 1:1 dsmark 0x3 value 0xb8 10. Classificatori 10.1. Introduzione Per specificare come indirizzare i pacchetti nelle classi corrispondenti è possibile utilizzare i filtri o classificatori. Ogni pacchetto che arriva è sottoposto ai filtri che decidono, in base alle indicazioni fornite, in quale classe/coda devono essere collocati. Riprendendo il grafico precedente e aggiungendo i filtri si completa la realizzazione del tc basato su CBQ: +------------------- QDISC CBQ -------------------+ |+--------------- CLASSE CBQ ROOT ---------------+| ______ || || / \ || +-CLASSE A 8Mbit prio 3 ---+ || | ROOT | || +---+ | +----------------+ | || \______/ Pacchetto -->==--+-|F1 |-= -> | SFQ |--> = ---+ || /10:1\ || | +---+ | +----------------+ | | || 8Mbit / \ 2Mbit || | +--------------------------+ | || ______ ______ || | +--> ==---> / \ / \ || | +-CLASSE B 2Mbit prio 2 ---+ | || |CLASSE A| |CLASSE B| || | +---+ | +--------------+ | | || \______/ \______/ || +-|F2 |-= -> | FIFO | ---> = ---+ || 10:100 10:200 || +---+ | +--------------+ | || || +--------------------------+ || |+-----------------------------------------------+| +-------------------------------------------------+ F1 e F2 sono i due filtri che in base alle impostazioni fornite provvedono a smistare i pacchetti nelle classi previste. Per creare, rimuove, cambiare un filtro è necessario utilizzare, in modo simile alle discipline, il comando tc filter: # tc filter help Usage: tc filter [ add | del | change | get ] dev STRING [ pref PRIO ] [ protocol PROTO ] [ estimator INTERVAL TIME_CONSTANT ] [ root | classid CLASSID ] [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ] tc filter show [ dev STRING ] [ root | parent CLASSID ] Where: FILTER_TYPE := { rsvp | u32 | fw | route | etc. } FILTERID := ... format depends on classifier, see there OPTIONS := ... try tc filter add help dev: si deve specificare l'interfaccia/dispositivo su cui si desidera controllare il traffico. (es. dev eth0). pref: priorità associata alla disciplina protocol: protocollo dei pacchetti che devono essere filtrati (es. protocol ip) estimator:estimatore handle: identificatore della classe verso cui devono essere inviati i pacchetti filtrati con successo FILTER_TYPE: filtro che si intende utilizzare (rsvp, route, fw, ...) 10.2. Filtri Si possono utilizzare diversi filtri, alcuni anche molto complessi e completi: · Tabella di routing · Firewall · U32 · RSVP · RSVP IPv6 · Traffic policing (needed for in/egress) Tabella di routing Utilizzando il programma ip, presente nel paccheto iproute2, è possibile associare ad ogni instradamento un "identificatore" che lo contraddistingua. Attraverso tc è possibile poi definire un filtro in cui si può specificare verso quale classe/coda deve essere inviato un pacchetto in base all'identificatore assegnato. # tc filter add route help Usage: ... route [ from REALM | fromif TAG ] [ to REALM ] [ flowid CLASSID ] [ police POLICE_SPEC ] POLICE_SPEC := ... look at TBF CLASSID := X:Y from: provenienza dei pacchetti (REALM è il valore associato ad un instradamento con ip) to: destinazione dei pacchetti flowid: flusso, classe dove dirigere i pacchetti police: serve a specificare in determinati casi (numero eccessivo di pacchetti/bytes, raggiungimento limiti) l'azione (riclassifica, scarta, continua) da intraprendere. police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ] [ peakrate BPS ] [ avrate BPS ] [ ACTION ] Where: ACTION := reclassify | drop | continue Esempio: -------- # ------------------------------------------------------------------------------------------ # Aggiungiamo un instradamento che diriga i pacchetti destinati all'indirizzo 192.168.0.0/24 # verso l'instradamento di default 192.168.0.1 interfaccia eth1, inoltre gli associamo il # valore identificativo 1 # ------------------------------------------------------------------------------------------ ip route add 192.168.0.0/24 via 192.168.0.1 dev eth1 realm 1 # ------------------------------------------------------------------------------------------ # I pacchetti destinati all'indirizzo 192.168.0.0/24 (to 1) sono diretti alla classe 1:10 # 'to 1' si riferisce all'instradamento indicato con ip route precedentemente (...realm 1) # ------------------------------------------------------------------------------------------ tc filter add dev eth1 parent 1:0 protocol ip prio 10 route to 1 classid 1:10 # ------------------------------------------------------------------------------------------ # I pacchetti provenienti dall'indirizzo 192.168.0.0/24 (from 1) sono diretti alla classe 1:10 # ------------------------------------------------------------------------------------------ tc filter add dev eth1 parent 1:0 protocol ip prio 10 route from 1 classid 1:10 Firewall Netfilter/iptables consentono di manipolare i pacchetti e in particolare di contrassegnarli con un numero utilizzando l'obiettivo -j MARK. Attraverso questo numero è possibile poi indicare a tc come trattare il pacchetto, verso quale classe indirizzarlo. E' probabilmente la soluzione più semplice ma non la più efficiente. # tc filter add fw help Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ] POLICE_SPEC := ... look at TBF CLASSID := X:Y classid: id (identificatore) della classe a cui inviare i pacchetti (es. 10:1) police: vedi sopra Esempio: -------- # ------------------------------------------------------------------------------------------ # impostiamo una variabile MAIL a cui associamo il valore 1 # ------------------------------------------------------------------------------------------ MAIL=1 # ------------------------------------------------------------------------------------------ # con iptables impostiamo una regola che modifichi i pacchetti destinati alla porta smtp # (--dport smtp) "marcandoli" con il valore MAIL (=1) (--setmark $MAIL). # ------------------------------------------------------------------------------------------ iptables -I PREROUTING -t mangle -p tcp -d ... --dport smtp -j MARK --setmark $MAIL # ------------------------------------------------------------------------------------------ # Aggiungiamo e associamo un filtro all'interfaccia eth1 (dev eth1) che per i pacchetti con # protocollo ip (protocol ip) e marcati con MAIL ossia 1 (handle $MAIL) provveda a inviarli # alla classe 1:1 (classid 1:1) # ------------------------------------------------------------------------------------------ tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle $MAIL fw classid 1:1 U32 Questa tecnica permette di filtrare i pacchetti in base al contenuto delle intestazioni (IP/TCP/...), quindi può permettere un'ottimo controllo. Permette inoltre di evitare l'utilizzo del filtraggio dei pacchetti (firewall) e in particolare l'utilizzo del marcamento dei pacchetti garantendo così maggior efficienza. Per ragioni di comodità è possibile utilizzare anche u16 o u8. tc filter add u32 help Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ] [ police POLICE_SPEC ] [ offset OFFSET_SPEC ] [ ht HTID ] [ hashkey HASHKEY_SPEC ] [ sample SAMPLE ] or u32 divisor DIVISOR Where: SELECTOR := SAMPLE SAMPLE ... SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS FILTERID := X:Y:Z match: lunghezza del pattern espressa in numero di bit (u32 = 32 bit, u16 = 16 bit, ...) link: classid: id (identificatore) della classe a cui inviare i pacchetti (es. 10:1) police: vedi sopra offset: scostamento in bytes (1 bytes = 8 bit), permette di "saltare" alcuni bytes ht: hash table hashkey: ... sample: ... Il selettore U32 consente di specificare precisamente quali bits si desidera consultare nelle intestazioni. u32 specifica che il pattern deve essere di 32 bit, si può utilizzare se più comodo anche un patern da 16 bit (u16) o 8 bit (u8). Nel caso di pacchetti IP e TCP sono ad esempio consultabili i seguenti campi: 1 byte = 8 bit + 1mo byte + 2do byte + 3zo byte + 4to byte + 0 1 2 3 4 5 6 7|8 9 0 1 2 3 4 5|6 7 8 9 0 1 2 3|4 5 6 7 8 9 0 1 ----------------------------------------------------------------- |Version| IHL |Type of Service| Total Length | = 4 byte = 32 bit ----------------------------------------------------------------- | Identification |Flags| Fragment Offset | = 4 byte ----------------------------------------------------------------- | Time to Live | Protocol | Header Checksum | = ... ----------------------------------------------------------------- | Source Address | ----------------------------------------------------------------- | Destination Address | ----------------------------------------------------------------- | Options | Padding | ----------------------------------------------------------------- [INTESTAZIONE IP totale 20 byte] 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ----------------------------------------------------------------- | Source Port | Destination Port | ----------------------------------------------------------------- | Sequence Number | ----------------------------------------------------------------- | Acknowledgment Number | ----------------------------------------------------------------- | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | ----------------------------------------------------------------- | Checksum | Urgent Pointer | ----------------------------------------------------------------- [INTESTAZIONE TCP] Per identificare i campi è necessario indicare il PATTERN (valore da confrontare) e la MASK (gruppo di bit interessati). Opzionalmente è possibile inoltre specificare uno scostamento (OFFSET) e l'intestazione (IP/TCP) che si desidera esaminare. I pacchetti TCP, UDP e ICMP sono incapsulati in pacchetti IP. bit 0 1 2 3|4 5 6 7|8 9 0 1|2 3 4 5|6 7 8 9|0 1 2 3|4 5 6 7|8 9 0 1 ----------------------------------------------------------------- |Version| IHL |Type of Service| Total Length | = 4 byte = 32 bit ----------------------------------------------------------------- \__ ____/\___ __/ \ \______ \ | -------------v V protocol ip u32 match 0 0 00 0000 ^ ^ ^^ ^^^^ | | | '> 16 bit = Total lenght | | '> 8 bit = TOS | '> 4 bit = IHL '> 4 bit = version Per specificare TOS dovremo allora utilizzare come MASK 0 0 FF 0000. Per specificare IHL dovremo utilizzare come MASK 0 F 00 0000. Per specificare Total length .... 0 0 00 FFFF. Per spostarci sulla seconda linea è necessario usare l'OFFSET (scostamento) espresso in byte: bit 0 1 2 3|4 5 6 7|8 9 0 1|2 3 4 5|6 7 8 9|0 1 2 3|4 5 6 7|8 9 0 1 ----------------------------------------------------------------- | Identification |Flags| Fragment Offset | = 4 byte ----------------------------------------------------------------- \______________________________/ \ \__ v protocol ip u32 match 0000 0000 at 4 ^^^^ ^^^^ | '> scostamento OFFSET 4 byte '> 16 bit = Identification Per spostarci all'intestazione successiva è necessario utilizzare l'opzione nexthdr (eventualmente si può indicare anche un offset). protocol ip u32 match ........ at nexthdr+0 Questo metodo non è molto intuitivo per cui è stata aggiunta la possibilità di utilizzare al posto dei numeri delle stringhe: ---------------------------------------------------------------------- | Protocollo | Selettore | Parametri | Descrizione | | | | pattern mask | | ---------------------------------------------------------------------- | match ip | | | | | | src | prefix/32 | indirizzo IP sorgente | | | dst | prefix/32 | indirizzo IP destinazione| | | tos | tos u8 | TOS (Type Of Service) | | | dsfield | tos u8 | " (sinonimo) | | | precedence | tos u8 | " (sinonimo) | | | ihl | ihl u8 | campo IP Total Lenght | | | protocol | prot u8 | campo IP protocol | | | nofrag | | pacchetto non frammentato| | | firstfrag | | pacchetto primo frammento| | | df | | Don't Fragment impostato | | | mf | | More Fragments impostato | | | sport | port u16 | Porta sorgente (tcp/udp)| | | dport | port u16 | Porta destinazione (") | | | icmp_type | type u8 | tipo pacchetto ICMP | | | icmp_code | code u8 | codice pacchetto ICMP | |match ip6 | | | | | | src | prefix/128 | indirizzo IPv6 sorgente | | | dst | prefix/128 | indirizzo IPv6 dest. | | | flowlabel | flow u32 | IPv6 flow label | |match udp,tcp| | | | | | src | src u16 | porta sorgente | | | dst | dst u16 | porta destinazione | |match icmp | | | | | | type | type u8 | tipo pacchetto ICMP | | | code | code u8 | codice pacchetto ICMP | |_____________|_____________|______________|__________________________| u8 = 0xff u16 = 0xffff u32 = 0xffffffff USO --- protocollo selettore PATTERN (www) MASK (u16) / / / / tc filter add ... u32 match tcp dst 80 0xffff tc filter add ... u32 match ip dst 192.168.0.1/24 match ip protocol 6 0xff match ip tos 0x10 0xff Esempi: -------- # ------------------------------------------------------------------------------------------ # Crea un filtro che identifichi i pacchetti ip con bit tos pari a 0x10 e li invii alla # classe 1:4. 0xff è la maschera ossia i bit da controllare. # ------------------------------------------------------------------------------------------ tc filter add dev eth0 parent 1:10 prio 10 u32 match ip tos 0x10 0xff flowid 1:4 # ------------------------------------------------------------------------------------------ # Crea un filtro che identifichi i pacchetti tcp (campo Protocol presente nell'intestazione # ip impostato a tcp ossia 0x6) con porta destinazione (presente nell'intestazione tcp) # pari a 80 (www) e li invii alla classe 1:3. 0xffff e 0xff sono le maschera. # ------------------------------------------------------------------------------------------ tc filter add dev eth0 parent 1:10 prio 10 u32 match tcp dport 80 0xffff match ip protocol 0x6 0xff flowid 1:3 rsvp rsvp presenta i seguenti parametri: tc filter add rsvp help Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ] [ sender SRC[/PORT | GPI ] [ classid CLASSID ] [ police POLICE_SPEC ] [ tunnelid ID ] [ tunnel ID skip NUMBER ] Where: GPI := { flowlabel NUMBER | spi/ah SPI | spi/esp SPI | u{8|16|32} NUMBER mask MASK at OFFSET} POLICE_SPEC := ... look at TBF FILTERID := X:Y ipproto: protocollo session: indirizzo destinazione ed eventuale porta sender: indirizzo sorgente e porta classid: identificatore della classe police: ... es.: tc filter add dev eth0 parent 1:10 protocol ip rsvp ipproto udp session 10.0.0.1 flowid 1:200 11. Varie 11.1. Dettagli sul traffico Con il tool tc è possibile ottenere varie informazioni e dettagli sul traffico gestito con le opzioni -s (statistics), -d (details), -r (raw). Esempio: # tc -s -d qdisc qdisc sfq 8002: dev eth0 quantum 1514b limit 128p flows 128/1024 perturb 15sec Sent 0 bytes 0 pkts (dropped 0, overlimits 0) qdisc sfq 8001: dev eth0 quantum 1514b limit 128p flows 128/1024 perturb 15sec Sent 0 bytes 0 pkts (dropped 0, overlimits 0) qdisc cbq 10: dev eth0 rate 10Mbit cell 8b (bounded,isolated) prio no-transmit/8 weight 10Mbit allot 1514b level 2 ewma 5 avpkt 1000b maxidle 23us Sent 5598228 bytes 18672 pkts (dropped 0, overlimits 0) borrowed 0 overactions 0 avgidle 624 undertime 0 11.2. Impostazioni E' possibile inoltre controllare le impostazioni correnti con il comando show o ls: # tc qdisc show qdisc sfq 8002: dev eth0 quantum 1514b perturb 15sec qdisc sfq 8001: dev eth0 quantum 1514b perturb 15sec qdisc cbq 10: dev eth0 rate 10Mbit (bounded,isolated) prio no-transmit # tc class show dev eth0 class cbq 10: root rate 10Mbit (bounded,isolated) prio no-transmit class cbq 10:100 parent 10:1 leaf 8001: rate 80Kbit (bounded) prio 5 class cbq 10:1 parent 10: rate 10Mbit prio no-transmit class cbq 10:200 parent 10:1 leaf 8002: rate 15Kbit (bounded) prio 5 # tc filter show dev eth0 filter parent 10: protocol ip pref 1 fw filter parent 10: protocol ip pref 1 fw handle 0x1 classid 10:100 11.3. Unità Oltre a BYTES e KBPS è possibile utilizzare anche altre unità di misura: · Mbit (Megabit) (*1024*1024/8) · kbit (kilobit) (*1024/8) · mbps (megabytes per second) (1024*1024) · kbps (kilobytes per second) (*1024) Quindi 1Mbit corrisponde a 1 * 1024*1024/8=128kbps Per quanto riguarda il tempo è possibile specificarlo in diversi modi: · s, sec, secs (secondi) · ms, msec, msecs (millisecondi) · us, usec, usecs (microsecondi) 12. Esempi Seguono una serie di esempi, alcuni si possono trovare su internet agli indirizzi presenti nel capitolo "Risorse". 12.1. Esempio 1 - CBQ e filtro route Questo esempio basato sull'example 1 reperibile all'indirizzo http://qos.ittc.ukans.edu/howto/node47.html crea due classi (1:2 e 1:3) derivate dalla classe root (1:1) aventi rispettivamente una bandwidth di 3Mbit, 7Mbit. I pacchetti sono smistati dal filtro route in base alle rotte specificate. #!/bin/bash # # ____ # /1:1 \ # \____/ # 3Mbit prio 3 / \ 7Mbit prio 7 # __/_ __\_ # /1:2 \ /1:3 \ # \____/ \____/ # ------------------------------------------------------------------------- # Creazione di una qdisc cbq basata su classi. # La bandwidth a disposizione dell'interfaccia è di 10 Mbit (128k) # Dimensione media dei pacchetti (avpkt) è di 1000 byte (caso ethernet) # ------------------------------------------------------------------------- tc qdisc add dev eth0 root handle 1: cbq bandwidth 10Mbit cell 8 avpkt 1000 \ mpu 64 # ------------------------------------------------------------------------- # Creazione della prima classe ROOT. # bandwidth assegnata 10Mbit, priorità della classe 8. # allot nel caso ethernet è da impostare a 1514 (allot=MTU+MAC) # weight è da scegliere proporzionale a rate, in genere 1/10 di rate. # ------------------------------------------------------------------------- tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate 10Mbit \ allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe discendente di ROOT. # bandwidth assegnata 3Mbit, priorità della classe 3. # id che permette di identificare la classe: 1:2. # ------------------------------------------------------------------------- tc class add dev eth0 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 3Mbit \ allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 avpkt 1000 # ------------------------------------------------------------------------- # Creazione della seconda classe discendente di ROOT. # bandwidth assegnata 8Mbit, priorità della classe 7. # id che permette di identificare la classe: 1:3. # ------------------------------------------------------------------------- tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 10Mbit rate 7Mbit \ allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 avpkt 1000 split 1:0 # ------------------------------------------------------------------------- # Associamo al nodo root il classificatore route # ------------------------------------------------------------------------- tc filter add dev eth0 parent 1:0 protocol ip prio 100 route # ------------------------------------------------------------------------- # Impostiamo una rotta che invii i pacchetti destinati all'indirizzo # 129.237.125.146 attraverso 129.237.125.149 utilizzando la classe # 1:2 a cui abbiamo assegnato una bandwidth di 3Mbit. # ------------------------------------------------------------------------- ip route add 129.237.125.146 via 129.237.125.149 dev eth0 realm 10 # ------------------------------------------------------------------------- # Impostiamo una rotta che invii i pacchetti destinati all'indirizzo # 129.237.125.148 attraverso 129.237.125.149 utilizzando la classe # 1:3 a cui abbiamo assegnato una bandwidth di 7Mbit. # ------------------------------------------------------------------------- ip route add 129.237.125.148 via 129.237.125.149 dev eth0 realm 20 # ------------------------------------------------------------------------- # Creiamo i filtri che in base ai valori realm assegnati (10 e 20) # smistino i pacchetti alle classi desiderate # ------------------------------------------------------------------------- tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 10 classid 1:2 tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 20 classid 1:3 12.2. Esempio 2 - CBQ e filtro u32 In questo caso si suppone di avere un firewall/router che riceve i pacchetti e li smista in base all'indirizzo di destinazione verso l'ufficio (OFFICE) a cui viene messa a disposizione una banda di 2Mbit, oppure verso gli altri computer server (SERVERS) presenti a cui viene messa a disposizione una banda totale di 8Mbit. La banda totale a disposizione è di 10Mbit. #!/bin/bash # ------------------------------------------------------------------------- # Definizione delle variabili # ------------------------------------------------------------------------- ETH=eth0 ROOT=10:1 # ------------------------------------------------------------------------- # Rete di server # ------------------------------------------------------------------------- SERVERS=10:2 SERVERS_RATE=8Mbit SERVERS_LAN=150.150.10.0/16 # ------------------------------------------------------------------------- # Computer presente nell'ufficio # ------------------------------------------------------------------------- OFFICE=10:3 OFFICE_RATE=2Mbit OFFICE_PC=150.150.10.2 # ------------------------------------------------------------------------- # Creazione di una qdisc cbq basata su classi. # La bandwidth a disposizione dell'interfaccia è di 10 Mbit (128k) # Dimensione media dei pacchetti (avpkt) è di 1000 byte (caso ethernet) # ------------------------------------------------------------------------- tc qdisc add dev $ETH root handle 10: cbq bandwidth 10Mbit avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe ROOT. # bandwidth assegnata 10Mbit, priorità della classe 8. # allot nel caso ethernet è da impostare a 1514 (allot=MTU+MAC) # weight è da scegliere proporzionale a rate, in genere 1/10 di rate. # ------------------------------------------------------------------------- tc class add dev $ETH parent 10: classid $ROOT cbq bandwidth 10Mbit \ rate 10Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe discendente di ROOT, denominata SERVERS. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $SERVERS cbq bandwidth 10Mbit \ rate $SERVERS_RATE allot 1514 weight 400kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Creazione della seconda classe discendente di ROOT, denominata OFFICE. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $OFFICE cbq bandwidth 10Mbit \ rate $OFFICE_RATE allot 1514 weight 100kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Associamo alla classe SERVERS una qdisc sfq utilizzando i parametri standard # Se non si associa nessuna qdisc, per default è assegnata la qdisc FIFO. # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $SERVERS sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Associamo anche alla classe OFFICE una qdisc sfq # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $OFFICE sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Creazione dei filtri che smisteranno i pacchetti nelle classi create # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e destinati all'indirizzo # corrispondente al PC dell'ufficio (match ip dst OFFICE_PC) saranno # indirizzati nella classe OFFICE (quella con 2Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 100 u32 match ip dst $OFFICE_PC flowid $OFFICE # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e destinati alla rete dei # server (match ip dst SERVERS_LAN) saranno indirizzati nella classe SERVERS # (quella con 8Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 25 u32 match ip dst $SERVERS_LAN flowid $SERVERS 12.3. Esempio 3 - CBQ e filtro fw In questo caso il firewall/router utilizza Netfilter/iptables per marcare i pacchetti interessati, i filtri provvederanno in base a questi valori a indirizzare i pacchetti nelle classi prescelte. #!/bin/bash # ------------------------------------------------------------------------- # Definizione delle variabili # ------------------------------------------------------------------------- ETH=eth0 ROOT=10:1 # ------------------------------------------------------------------------- # Rete di server # ------------------------------------------------------------------------- SERVERS=10:2 SERVERS_RATE=8Mbit SERVERS_LAN=150.150.10.0/16 SERVERS_MARK=2 # ------------------------------------------------------------------------- # Computer presente nell'ufficio # ------------------------------------------------------------------------- OFFICE=10:3 OFFICE_RATE=2Mbit OFFICE_PC=150.150.10.2 OFFICE_MARK=1 # ------------------------------------------------------------------------- # Creazione di una qdisc cbq basata su classi. # La bandwidth a disposizione dell'interfaccia è di 10 Mbit (128k) # Dimensione media dei pacchetti (avpkt) è di 1000 byte (caso ethernet) # ------------------------------------------------------------------------- tc qdisc add dev $ETH root handle 10: cbq bandwidth 10Mbit avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe ROOT. # bandwidth assegnata 10Mbit, priorità della classe 8. # allot nel caso ethernet è da impostare a 1514 (allot=MTU+MAC) # weight è da scegliere proporzionale a rate, in genere 1/10 di rate. # ------------------------------------------------------------------------- tc class add dev $ETH parent 10: classid $ROOT cbq bandwidth 10Mbit \ rate 10Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe discendente di ROOT, denominata SERVERS. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $SERVERS cbq bandwidth 10Mbit \ rate $SERVERS_RATE allot 1514 weight 400kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Creazione della seconda classe discendente di ROOT, denominata OFFICE. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $OFFICE cbq bandwidth 10Mbit \ rate $OFFICE_RATE allot 1514 weight 100kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Associamo alla classe SERVERS una qdisc sfq utilizzando i parametri standard # Se non si associa nessuna qdisc, per default è assegnata la qdisc FIFO. # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $SERVERS sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Associamo anche alla classe OFFICE una qdisc sfq # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $OFFICE sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Rispetto all'esempio 1 invece di utilizzare il filtro u32, utilizziamo # il firewall, che nei kernel 2.3/2.4 è costituito dall'infrastruttura # Netfilter e dal programma iptables. # Con iptables marchiamo con un valore (mark) i pacchetti in base al # loro indirizzo IP di destinazione. # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- # I pacchetti destinati all' OFFICE_PC devono essere marcati con il valore # OFFICE_MARK ossia 1. # ------------------------------------------------------------------------- iptables -A PREROUTING -i $ETH -t mangle -p tcp --destination $OFFICE_PC \ -j MARK --set-mark $OFFICE_MARK # ------------------------------------------------------------------------- # I pacchetti destinati alla LAN dei SERVERS (SERVERS_LAN) devono essere # marcati con il valore SERVERS_MARK ossia 2. # ------------------------------------------------------------------------- iptables -A PREROUTING -i $ETH -t mangle -p tcp --destination $SERVERS_LAN \ -j MARK --set-mark $SERVERS_MARK # ------------------------------------------------------------------------- # Creazione dei filtri che smisteranno i pacchetti nelle classi create # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e marcati con il valore # OFFICE_MARK sono da indirizzare nella classe OFFICE # (quella con 2Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 5 handle $OFFICE_MARK fw flowid $OFFICE # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e marcati con il valore # SERVERS_MARK sono da indirizzare nella classe SERVERS # (quella con 8Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 5 handle $SERVERS_MARK fw flowid $SERVERS 12.4. Esempio 4 - CBQ e filtro fw In questo caso si utilizza ancora il firewall e in particolare si distinguono i pacchetti in base alla porta di destinazione (www, smtp). #!/bin/bash # ------------------------------------------------------------------------- # Definizione delle variabili # ------------------------------------------------------------------------- ETH=eth0 ROOT=10:1 # ------------------------------------------------------------------------- # Rete di server # ------------------------------------------------------------------------- SERVERS=10:2 SERVERS_RATE=8Mbit SERVERS_LAN=150.150.10.0/16 SERVERS_MARK=2 # ------------------------------------------------------------------------- # Computer presente nell'ufficio # ------------------------------------------------------------------------- OFFICE=10:3 OFFICE_RATE=2Mbit OFFICE_PC=150.150.10.2 OFFICE_MARK=1 # ------------------------------------------------------------------------- # Creazione di una qdisc cbq basata su classi. # La bandwidth a disposizione dell'interfaccia è di 10 Mbit (128k) # Dimensione media dei pacchetti (avpkt) è di 1000 byte (caso ethernet) # ------------------------------------------------------------------------- tc qdisc add dev $ETH root handle 10: cbq bandwidth 10Mbit avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe ROOT. # bandwidth assegnata 10Mbit, priorità della classe 8. # allot nel caso ethernet è da impostare a 1514 (allot=MTU+MAC) # weight è da scegliere proporzionale a rate, in genere 1/10 di rate. # ------------------------------------------------------------------------- tc class add dev $ETH parent 10: classid $ROOT cbq bandwidth 10Mbit \ rate 10Mbit allot 1514 weight 1Mbit prio 8 maxburst 20 avpkt 1000 # ------------------------------------------------------------------------- # Creazione della prima classe discendente di ROOT, denominata SERVERS. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $SERVERS cbq bandwidth 10Mbit \ rate $SERVERS_RATE allot 1514 weight 400kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Creazione della seconda classe discendente di ROOT, denominata OFFICE. # bandwidth assegnata 8Mbit, priorità della classe 5. # La classe è "bounded" ossia non può eccedere il rate assegnato. # ------------------------------------------------------------------------- tc class add dev $ETH parent $ROOT classid $OFFICE cbq bandwidth 10Mbit \ rate $OFFICE_RATE allot 1514 weight 100kbit prio 5 maxburst 20 avpkt 1000 bounded # ------------------------------------------------------------------------- # Associamo alla classe SERVERS una qdisc sfq utilizzando i parametri standard # Se non si associa nessuna qdisc, per default è assegnata la qdisc FIFO. # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $SERVERS sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Associamo anche alla classe OFFICE una qdisc sfq # ------------------------------------------------------------------------- tc qdisc add dev $ETH parent $OFFICE sfq quantum 1514b perturb 15 # ------------------------------------------------------------------------- # Rispetto all'esempio 1 invece di utilizzare il filtro u32, utilizziamo # il firewall, che nei kernel 2.3/2.4 è costituito dall'infrastruttura # Netfilter e dal programma iptables. # Con iptables marchiamo con un valore (mark) i pacchetti in base al # loro indirizzo IP di destinazione. # ------------------------------------------------------------------------- # Tutti i pacchetti pacchetti sono marcati con il valore 0 # I pacchetti www e smtp subiscono però un'ulteriore modifica iptables -A PREROUTING -i $ETH -t mangle -j MARK --set-mark 0 # I pacchetti destinati al server WWW devono essere marcati con il valore # WWW ossia 1. iptables -A PREROUTING -i $ETH -t mangle -p tcp --dport www \ -j MARK --set-mark $WWW # I pacchetti destinati alla LAN dei SERVERS (SERVERS_LAN) devono essere # marcati con il valore MAIL ossia 2. iptables -A PREROUTING -i $ETH -t mangle -p tcp --dport smtp \ -j MARK --set-mark $MAIL # ------------------------------------------------------------------------- # Creazione dei filtri che smisteranno i pacchetti nelle classi create # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e marcati con il valore # WWW sono da indirizzare nella classe WWW_SERVER # (quella con 8Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 10 handle $WWW fw flowid $WWW_SERVER # ------------------------------------------------------------------------- # I pacchetti aventi protocollo ip (protocol ip) e marcati con il valore # MAIL sono da indirizzare nella classe MAIL_SERVER # (quella con 2Mbit di bandwidth). # ------------------------------------------------------------------------- tc filter add dev $ETH parent 10:0 protocol ip prio 5 handle $MAIL fw flowid $MAIL_SERVER 12.5. Esempio 5 - ingress Esempio di utilizzo della qdisc ingress presente all'indirizzo www.davin.ottawa.on.ca/ols/img33.htm, qui modificato in modo da utilizzare iptables. #!/bin/bash iptables -A PREROUTING -t mangle -i eth0 -s 10.2.0.24/32 -j MARK --set-mark 1 iptables -A PREROUTING -t mangle -i eth0 -p tcp --syn -j MARK --set-mark 2 # ------------------------------------------------------------------------- # associa una qdisc ingress all'interfaccia eth0 # ------------------------------------------------------------------------- tc qdisc add dev eth0 handle ffff: ingress # ------------------------------------------------------------------------- # per i pacchetti marcati con il valore 1 accetta almeno 60 pacchetti come # burst (si assume una dimensione dei pacchetti di circa 1.5KB, 90/1.5=60) # nel "lungo" intervallo e fino a 6 pacchetti nel "breve" intervallo. # ------------------------------------------------------------------------- tc filter add dev eth0 parent ffff: protocol ip prio 50 handle 1 fw \ police rate 1500kbit burst 90k mtu 9k drop flowid :1 # ------------------------------------------------------------------------- # I pacchetti con flag SYN impostato hanno dimensione pari a 40 byte (320 bit) # quindi 10 pacchetti SYN sono 3Kbps; accettiamo solo 10 pacchetti SYN/sec # ------------------------------------------------------------------------- tc filter add dev eth0 parent ffff: protocol ip prio 50 handle 2 fw \ police rate 3kbit burst 40 mtu 9k drop flowid :1 12.6. Esempio 6 - ingress e dsmark Questo esempio è stato preso tra quelli disponibili con il pacchetti iproute2. Sono state aggiunte delle modifiche e i commenti. #!/bin/bash # ------------------------------------------------------------------------- # Definizione delle variabili # ------------------------------------------------------------------------- ETH=eth0 ROOT=10:0 INDEV=eth2 # ingress device EGDEV="dev eth1" # egress device PC1=1 PC2=2 RETE=3 iptables -A PREROUTING -t mangle -s 10.2.0.0/24 -j MARK --set-mark $RETE iptables -A PREROUTING -t mangle -i $INDEV -s 10.2.0.24 -j MARK --set-mark $PC1 iptables -A PREROUTING -t mangle -i $INDEV -s 10.2.0.3 -j MARK --set-mark $PC2 # ------------------------------------------------------------------------ # INGRESS - interfaccia di ingresso # ------------------------------------------------------------------------ # ------------------------------------------------------------------------- # Creazione di una qdisc ingress che viene associata all'interfaccia # INDEV (eth2) di ingresso. # ------------------------------------------------------------------------- tc qdisc add dev $INDEV handle ffff: ingress # ------------------------------------------------------------------------- # Alla qdisc ingress viene associato un filtro che limita il traffico dei # pacchetti marcati con iptables con il valore RETE (3) ad un massimo di # 1.5Mbps (police rate 1500kbit). Il burst è impostato a 90K. # mtu (maximum transfer unit) è di 9k. I pacchetti in eccedenza al limite # fissato sono scartati (drop). # ------------------------------------------------------------------------- tc filter add dev $INDEV parent ffff: protocol ip prio 50 handle $RETE fw \ police rate 1500kbit burst 90k mtu 9k drop flowid :1 # ------------------------------------------------------------------------ # EGRESS - interfaccia di uscita # ------------------------------------------------------------------------ # ------------------------------------------------------------------------- # Associamo all'interfaccia EGDEV (eth1) la qdisc dsmark # ------------------------------------------------------------------------- tc qdisc add $EGDEV handle 1:0 root dsmark indices 64 # ------------------------------------------------------------------------- # Definiamo tre classi e associamo un valore DSCP (Differentiated Service # Code Point) # ------------------------------------------------------------------------- tc class change $EGDEV classid 1:1 dsmark 0x3 value 0xb8 tc class change $EGDEV classid 1:2 dsmark 0x3 value 0x28 tc class change $EGDEV classid 1:3 dsmark 0x3 value 0x48 # ------------------------------------------------------------------------- # Impostiamo dei filtri che smistino i pacchetti marcati nelle classi # corrispondenti # ------------------------------------------------------------------------- tc filter add $EGDEV parent 1:0 protocol ip prio 4 handle $PC1 fw classid 1:1 tc filter add $EGDEV parent 1:0 protocol ip prio 4 handle $PC2 fw classid 1:2 tc filter add $EGDEV parent 1:0 protocol ip prio 4 handle $RETE fw classid 1:3 13. Risorse Per scrivere questo documento ho trovato di notevole interesse i seguenti siti: · http://qos.ittc.ukans.edu · http://snafu.freedom.org · ipqos · www.davin.ottawa.on.ca 14. Marchi registrati Tutti i marchi sono registrati. Linux è un marchio registrato di Linus Torvalds. MS-DOS, Windows NT sono marchi registrati di Microsoft Corporation.