[Precedente: Ancore] [Indice] [Successivo: Address Pools e Load Balancing]
Si accoda qualcosa per conservarlo affinchè possa essere processato successivamente. In una rete di computer, quando alcuni pacchetti di dati sono inviati da un host, vengono inseriti in una coda dove attendono di essere processati dal sistema operativo. Il sistema operativo quindi decide quale coda e quale pacchetto o serie di pacchetti appartenenti a quella coda dovrebbero essere processati. L'ordine con il quale il sistema operativo seleziona i pacchetti da processare può avere effetto sulle performance della rete. Per esempio, supponiamo che un utente stia eseguendo due applicazioni di rete: SSH e FTP. Idealmente, i pacchetti SSH dovrebbero essere processati prima dei pacchetti FTP a causa della natura time-sensitive di SSH; quando un tasto viene premuto nel client SSH, si ci aspetta una risposta immediata mentre un eventuale ritardo di pochi secondi in un trasferimento FTP non viene notato. Ma cosa succede se il router deve gestire un grosso quantitativo di pacchetti da una connessione FTP prima di riuscire a processare la connessione SSH? I pacchetti della connessione SSH resteranno accodati (o verranno addirittura gettati via dal router se la memoria non dovesse essere sufficientemente ampia da contenere tutti i pacchetti) e la connessione SSH potrebbe apparire rallentata. Utilizzando una strategia per le code, la banda della rete può essere condivisa in modo opportuno tra le diverse applicazioni, utenti e computer.
C'è da notare che il queueing è utile solo per i pacchetti in uscita. Una volta che i pacchetti arrivano a un interfaccia nella direzione d'ingresso è ormai troppo tardi per il queue. Infatti, quando i pacchetti arrivano all'interfaccia è stata già consumata banda. L'unica soluzione è di abilitare il queueing sul router adiacente o, se l'host che ha ricevuto il pacchetto agisce come router, abilitare il queueing sull'interfaccia interna dove i pacchetti escono dal router.
OpenBSD supparta due altri scheduler:
Le code CBQ sono ordinate in maniera gerarchica. Al di sopra della gerarchia vi è la coda root, la quale definisce il totale ammontare di banda disponibile. Le code figlie sono create a partire dalla coda root, ad ognuna delle quali può essere assegnata una porzione della banda della coda root. Per esempio alcune code potrebbero essere definite come di seguito:
In questo caso, la banda totale disponibile è di 2 megabit al secondo (Mbps). Questa banda è suddivisa tra tre code figlie.
La gerarchia può essere ulteriormente espansa definendo code all'interno di altre code. Per suddividere la banda in modo corretto tra differenti utenti e classificare il loro traffico così da evitare che alcuni protocolli non limitino la banda ad altri, può essere definita una struttura come la seguente:
Da notare che ad ogni livello la somma delle bande assegnate ad ognuna delle code non è mai superiore alla banda assegnata alla coda madre.
Una coda può essere configurata per prendere in prestito banda dalla sua coda madre se questa momentaneamente ha un eccesso di banda disponibile non utililizzata da altre code figlie. Consideriamo una configurazione come la seguente:
Se il traffico nella coda ftp dovesse eccedere i 900Kbps e il traffico nella coda UserA è inferiore a 1Mbps (perchè la coda ssh sta utilizzando meno banda di quella assegnata, 100Kbps), la coda ftp prenderà in prestito l'eccesso di banda da UserA. In questo modo la coda ftp è in grado di utilizzare più della banda ad essa assegnata quando viene richiesto un incremento del carico di dati. Se la coda ssh dovesse incrementare il suo carico, la banda prestata sarà restituita.
CBQ assegna ad ogni coda un livello di priorità. Durante una congestione del traffico, le code con una più elevata priorità sono da preferire rispetto a code con una bassa priorità anche se entrambe le code sono figlie di una stessa coda genitrice (in altre parole appartenenti allo stesso ramo gerarchico). Code con la stessa priorità sono processate in maniera round-robin. Per esempio:
CBQ processerà le code UserA e UserB seguendo uno stile round-robin -- cioè nessuna coda verrà preferita all'altra. Nel tempo dedicato a processare la coda UserA, CBQ processerà anche le sue code figlie. In questo caso la coda ssh avrà una priorità superiore e avrà un trattamento privilegiato rispetto alla coda ftp se la rete dovesse essere congestionata. C'è da notare che le priorità delle code ssh e ftp non vengono confrontate con quelle delle code UserA e UserB perchè non appartengono a uno stesso ramo gerarchico.
Per maggiori dettagli riferirsi alla teoria CBQ, Riferimenti su CBQ.
La struttura delle code in PRIQ è piatta -- non è possibile definire code all'interno di altre code. Viene definita la coda root, la quale configura il totale ammontare di banda disponibile, e le sotto-code vengono definite al di sotto della root. Consideriamo il seguente esempio:
La coda root è definita con una disponibilità di banda per se stessa e per le tre sub-code pari a 2Mbps. La coda con più alta priorità (il più alto numero di priorità) è servita per prima. Una volta che tutti i pacchetti di quella coda sono processati, o la coda è vuota, PRIQ sposta il suo interesse per la coda successiva con valore di priorità più elevato. All'interno di una data coda i pacchetti sono processati secondo un modello First In First Out (FIFO).
E' importante notare che quando si usa PRIQ occorre pianificare le code con estrema attenzione. Perchè PRIQ processa sempre la coda a più alta priorità prima di una a bassa priorità, è quindi possibile che una coda ad alta priorità ricevendo un flusso continuo di pacchetti possa ritardare o addirittura causare l'eliminazione di pacchetti appartenenti a una coda a più bassa priorità.
RED è utile perchè evita una situazione conosciuta come sincronizzazione globale ed è in grado di gestire burst di traffico. La sincronizzazione globale si riferisce alla totale perdita di traffico a causa della contemporanea perdita di pacchetti da diverse connessioni. Per esempio, se la congestione avviene in un router che trasporta traffico relativo a 10 connessioni FTP e i pacchetti da tutte (o la maggior parte) queste connessioni sono gettati via (come nel caso del queueing FIFO), tutto il traffico ne risentirà. Questa non è una situazione ideale perchè comporta che tutte le connessioni FTP debbano ridurre il loro traffico e significa anche che la rete non può più essere utilizzata al suo massimo potenziale. RED evita tutto questo scegliendo casualmente da quale connessione gettare via i pacchetti invece di scegliere tutte le connessioni simultaneamente. In questo modo, connessioni con elevata banda avranno maggiore probabilità di avere i loro pacchetti gettati. In questo modo, connessioni ad elevata banda saranno rallentate, la congestione evitata e la rapida perdita di tutto il traffico non avverrà. Inoltre, RED è in grado di gestire i burst di traffico perchè inizia a gettare via pacchetti prima che le code si possano riempire. Quando un burst di traffico giunge c'è sufficiente spazio nella coda per ospitare i nuovi pacchetti.
RED dovrebbe essere usato solo quando il protocollo di trasporto è in grado di rispondere agli indicatori di congestione della network. Nella maggior parte dei casi questo significa che RED dovrebbe essere usato per code di traffico TCP e non per traffico UDP o ICMP.
Per maggiori dettagli relativi alla teoria RED, Riferimenti su RED.
Per maggiori informazioni su l'ECN riferirsi a RFC 3168.
Siccome ALTQ è stato integrato con PF, affinchè il queueing funzioni occorre attivare PF. Istruzioni su come abilitare PF si trovano in Getting Started.
Il Queueing è configurato in pf.conf. Ci sono due tipi di direttive che possono essere utilizzate per configurare il queueing:
La sintassi per la direttiva altq on:
altq on interface scheduler bandwidth bw qlimit qlim \
tbrsize size queue { queue_list }
Per esempio:
altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }Viene abilitata CBQ sull'interfaccia fxp0. La banda totale disponibile è configurata a 2Mbps. sono definite tre code figlie: std, ssh, e ftp.
La sintassi per la direttiva queue è la seguente:
queue name [on interface] bandwidth bw [priority pri] [qlimit qlim] \
scheduler ( sched_options ) { queue_list }
Continuiamo con l'esempio visto precedentemente:
queue std bandwidth 50% cbq(default)
queue ssh bandwidth 25% { ssh_login, ssh_bulk }
queue ssh_login bandwidth 25% priority 4 cbq(ecn)
queue ssh_bulk bandwidth 75% cbq(ecn)
queue ftp bandwidth 500Kb priority 3 cbq(borrow red)
Qui vengono definiti i parametri delle code figlie definite precedentemente. Alla coda std viene assegnata una banda pari al 50% della banda della coda root (1Mbps) e viene settata anche come coda di default. Alla coda ssh viene assegnato il 25% della banda della coda root (500kb) e inoltre contiene due code figlie, ssh_login e ssh_bulk. Alla coda ssh_login viene assegnata una più elevata priorità rispetto a ssh_bulk ed entrambe hanno l'ECN abilitato. Alla coda ftp viene assegnato una banda di 500kbps e data una priorità di 3. Può anche prendere in prestito banda extra quando questa è disponibile e RED abilitato.
NOTA: Ogni definizione di coda figlia ha la sua banda specificata. Senza specificare la banda, PF darà alla coda il 100% di banda della coda madre. In questa situazione, quando vengono caricate le regole di configurazione si avrebbe un errore perchè con con una coda con il 100% di banda nessun altra coda potrà essere definita a quel livello per mancanza di banda disponibile.
Per assegnare traffico a una coda, la keyword queue viene usata insieme alle regole di filtraggio di PF. Per esempio, consideriamo un set di regole di filtraggio contenente una riga come la seguente:
pass out on fxp0 from any to any port 22
I pacchetti che hanno corrispondenza con questa regola possono essere assegnati a una specifica coda usando la keyword queue:
pass out on fxp0 from any to any port 22 queue ssh
Quando si usa la keyword queue con la direttiva block, ogni pacchetto che risulta TCP RST o ICMP Unreachable packet viene assegnato a una specifica coda.
Notare che la designazione di una coda può avvenire su un'interfaccia oltre che su quella definita nella direttiva altq on:
altq on fxp0 cbq bandwidth 2Mb queue { std, ftp }
queue std bandwidth 500Kb cbq(default)
queue ftp bandwidth 1.5Mb
pass in on dc0 from any to any port 21 queue ftp
Il Queueing è abilitato su fxp0 ma la designazione avviene su dc0. Se i pacchetti hanno corrispondenza con la regola pass in uscita dall'interfaccia fxp0, saranno inseriti nella coda ftp. Questo tipo di queueing può essere molto utile sui routers.
Normalmente con la keyword queue si definisce un solo nome di coda, se viene specificato un secondo nome quella coda sarà usata per pacchetti con un Type of Service (ToS) a ritardo inferiore e per pacchetti con TCP ACK senza payload. Un ottimo esempio di questo si ha quando si utilizza SSH. La sessione di login di SSH sarà configurata con il ToS a low-delay mentre non lo saranno le sessioni SCP e SFTP. PF può usare queste informazioni per accodare pacchetti appartenenti a un login di una connessione in una coda differente che non sia la connessione di login. Questo è utile per dare priorità a pacchetti appartenenti a login di connessioni nel trasferimento di file.
pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)
Questo assegna i pacchetti appartenenti a login di connessioni SSH alla coda ssh_login e i pacchetti appartenenti alle connessioni SCP e SFTP alla coda ssh_bulk. Le connessioni di login SSH avranno quindi i loro pacchetti processati in testa alle connessioni SCP e SFTP perchè la coda ssh_login ha una priorità più elevata rispetto a ssh_bulk.
Assegnare i pacchetti TCP ACK ad una coda a più elevata priorità è utile nelle connessioni asimmetriche, cioè connessioni a differenti bande in upload e download come per le linee ADSL. Con una linea ADSL, quando l'upload è al massimo e parte il download, questo avrà delle difficoltà perchè i pacchetti TCP ACK avranno bisogno di essere inviati nel canale congestionato di upload. Alcuni test hanno mostrato che per ottenere i migliori risultati, la banda nella coda di upload dovrebbe essere configurata a un valore inferiore al valore massimo consentito. Per esempio, se una linea ADSL ha un valore massimo di upload di 640kbps i migliori risultati si otterrano configurando la banda della coda root a un valore ad esempio di 600kbps. Prove ed errori porteranno alla configurazione ottimale.
Quando si usa la keyword queue con le regole keep state:
pass in on fxp0 proto tcp from any to any port 22 flags S/SA \
keep state queue ssh
PF registrerà la coda nella tabella di stato così i pacchetti che viaggiano indietro al di fuori di fxp0 che avranno corrispondenza con la connessione finiranno nella coda ssh. Nota che sebbene la keyword queue è usata su una regola di filtraggio nel traffico entrante, l'obiettivo è di specificare una coda per il corrispondente traffico uscente; la regola precedente non accoda pacchetti in ingresso.
[ Alice ] [ Charlie ]
| | ADSL
---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
|
[ Bob ]
In questo esempio, OpenBSD è stato usato su un gateway per Internet per una piccola rete domestica con tre workstation. Il gateway si occupa del filtraggio dei pacchetti e della NAT. La connessione Internet avviene su una linea ADSL a 2Mbps in downloading e 640kbps in uploading.
La policy di queueing per questa network:
Di seguito sono riportate le regole che soddisfano questa policy. Da notare che sono presenti solo la direttive pf.conf applicate direttamente alle policy precedenti; nat, rdr, options, ecc., non sono mostrate.
# abilita il queueing su un interfaccia esterna per controllare il traffico che va verso
# Internet. Utilizza lo scheduler priq per controllare solo la priorità. Configura la
# banda a 610kbps per ottenere la migliore performance per i pacchetti in uscita TCP ACK.
altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
tcp_ack_out }
# definisce i parametri per le code figlie.
# std_out - la coda standard. ogni regola di filtraggio di seguito che non appartiene
# esplicitamente a una coda avrà il suo traffico aggiunto a questa coda.
# ssh_im_out - traffico di SSH interattivo e vari messaggi istantanei.
# dns_out - interrogazioni DNS.
# tcp_ack_out - pacchetti TCP ACK senza data payload.
queue std_out priq(default)
queue ssh_im_out priority 4 priq(red)
queue dns_out priority 5
queue tcp_ack_out priority 6
# abilita il queueing sull'interfaccia interna per controllare il traffico in
# ingresso da Internet. utilizza lo scheduler cbq per controllare la banda. Il
# valore massimo di banda è 2Mbps.
altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }
# definizione dei parametri per le code figlie.
# std_in - la coda standard. Ogni regola di filtraggio seguente che non
# appartiene esplicitamente a una coda avrà il suo traffico
# su questa coda.
# ssh_im_in - traffico SSH interrattivo e vari messaggi istantanei.
# dns_in - risposte DNS.
# bob_in - banda riservata per la workstation di Bob. consentire a lui di
# prendere in prestito banda.
queue std_in bandwidth 1.6Mb cbq(default)
queue ssh_im_in bandwidth 200Kb priority 4
queue dns_in bandwidth 120Kb priority 5
queue bob_in bandwidth 80Kb cbq(borrow)
# ... nella sezione di filtraggio di pf.conf ...
alice = "192.168.0.2"
bob = "192.168.0.3"
charlie = "192.168.0.4"
local_net = "192.168.0.0/24"
ssh_ports = "{ 22 2022 }"
im_ports = "{ 1863 5190 5222 }"
# regole di filtraggio per traffico in ingresso a fxp0
block in on fxp0 all
# regole di filtraggio per il traffico in uscita da fxp0
block out on fxp0 all
pass out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
keep state queue(std_out, tcp_ack_out)
pass out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
keep state queue dns_out
pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
flags S/SA keep state queue(std_out, ssh_im_out)
pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
flags S/SA keep state queue(ssh_im_out, tcp_ack_out)
# regole di filtraggio per l'ingresso su dc0
block in on dc0 all
pass in on dc0 from $local_net
# regole di filtraggio per il traffico in uscita da dc0
block out on dc0 all
pass out on dc0 from any to $local_net
pass out on dc0 proto { tcp udp } from any port domain to $local_net \
queue dns_in
pass out on dc0 proto tcp from any port $ssh_ports to $local_net \
queue(std_in, ssh_im_in)
pass out on dc0 proto tcp from any port $im_ports to $local_net \
queue ssh_im_in
pass out on dc0 from any to $bob queue bob_in
|
( IT Dept ) [ Boss's PC ]
| | T1
--+----+-----+---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
| fxp1
[ COMP1 ] [ WWW ] /
| /
--+----------'
In questo esempio l'host OpenBSD si comporta da firewall per una rete aziendale. L'azienda ha un server WWW nella porzione DMZ della loro rete dove i clienti eseguono l'upload dei loro siti web via FTP. Il dipartimento IT ha la loro subnet connessa alla network principale, e il boss ha un PC sulla sua scrivania che utilizza per l'email e per navigare sul web. La connessione a Internet avviene mediante una linea T1 a 1.5Mbps in entrambe le direzioni. Tutti gli altri segmenti di rete stanno usando una Fast Ethernet (100Mbps).
L'amministratore di rete ha deciso le seguenti policy:
Di seguito sono riportate le regole che soddisfano la policy della network. Notare che sono presenti solo le direttive pf.conf applicate direttamente alle policy precedenti; nat, rdr, options, ecc., non vengono mostrate.
# abilita il queueing sull'interfaccia esterna per accodare i pacchetti
# in uscita verso Internet. Utilizza lo scheduler cbq così da controllare
# la banda utilizzata da ogni coda. il massimo valore della banda è pari a 1.5Mbps.
altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
# definisce i parametri per le code figlie.
# std_ext - la coda standard. inoltre la coda di default per il traffico
# in uscita sulla fxp0.
# www_ext - coda che ospita per le code WWW server. limitata a
# 500Kbps.
# www_ext_http - traffico http traffic dal server WWW; la più elevata priorità.
# www_ext_misc - tutto il traffico non-http dal server WWW.
# boss_ext - traffico in arrivo dal computer del boss.
queue std_ext bandwidth 500Kb cbq(default borrow)
queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc }
queue www_ext_http bandwidth 50% priority 3 cbq(red borrow)
queue www_ext_misc bandwidth 50% priority 1 cbq(borrow)
queue boss_ext bandwidth 500Kb priority 3 cbq(borrow)
# abilita il queueing sull'interfaccia interna per controllare il traffico in arrivo
# da Internet o dalla DMZ. Utilizza lo scheduler cbq per controllare la banda
# di ogni coda. La banda su questa interfaccia è configurata al massimo.
# il traffico proveniente dalla DMZ sarà in grado di usare tutta questa banda
# mentre il traffico proveniente da Internet sarà limitato a 1.0Mbps
# (perchè 0.5Mbps (500kbps) è stata allocata per la fxp1).
altq on dc0 cbq bandwidth 100% queue { net_int, www_int }
# definizione dei parametri per le code figlie.
# net_int - coda per il traffico proveniente da Internet. la banda
# è 1.0Mbps.
# std_int - la coda standard. inoltre coda di default per il traffico
# in uscita su dc0.
# it_int - traffico verso la rete IT Dept; riserva loro 500Kbps.
# boss_int - traffico verso il PC del the boss; assegnazione della più alta priorità.
# www_int - traffico dal server WWW nella DMZ; massima velocità.
queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int }
queue std_int bandwidth 250Kb cbq(default borrow)
queue it_int bandwidth 500Kb cbq(borrow)
queue boss_int bandwidth 250Kb priority 3 cbq(borrow)
queue www_int bandwidth 99Mb cbq(red borrow)
# abilita il queueing sull'interfaccia DMZ per controllare il traffico destinato al
# server WWW. sarà usato il cbq su questa interfaccia per il necessario controllo
# della banda. la banda su questa interfaccia è configurata al valore massimo.
# il traffico dalla rete interna potrà utilizzare tutta la banda disponibile mentre
# il traffico da Internet sarà limitato a 500Kbps.
altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
# definizione dei parametri delle code figlie.
# internal_dmz - traffico dalla rete interna.
# net_dmz - coda per il traffico da Internet.
# net_dmz_http - traffico http; elevata priorità.
# net_dmz_misc - tutto il traffico non-http. questa è anche la coda di default.
queue internal_dmz bandwidth 99Mb cbq(borrow)
queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc }
queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow)
queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow)
# ... nella sezione di filtraggio di pf.conf ...
main_net = "192.168.0.0/24"
it_net = "192.168.1.0/24"
int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net = "10.0.0.0/24"
boss = "192.168.0.200"
wwwserv = "10.0.0.100"
# default deny
block on { fxp0, fxp1, dc0 } all
# regole di filtraggio per il traffico in ingresso a fxp0
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue www_ext_http
# regole di filtraggio per il traffico in uscita a fxp0
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext
# regole di filtraggio per il traffico in ingresso a dc0
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
> 49151 } flags S/SA keep state queue www_int
# regole di filtraggio per il traffico in uscita a dc0
pass out on dc0 from dc0 to $int_nets
# regole di filtraggio per il traffico in ingresso a fxp1
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
keep state
# regole di filtraggio per il traffico in uscita a fxp1
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
21, > 49151 } flags S/SA keep state queue internal_dmz
|
[Precedente: Ancore] [Indice] [Successivo: Address Pools e Load Balancing]