Klasifikace provozu sítě

Jaroslav Kučera, xkucera4@fi.muni.cz


Obsah


K čemu je to dobré

Klasifikace síťového provozu je užitečná v těch případech, kdy potřebujeme zaručit dostupnost některých síťových služeb i v případě značného zatížení síťového připojení. Typickým příkladem může být velmi "agresivní" protokol FTP, který dokáže zablokovat slabší linky prakticky sám pro sebe. Pokud během stahování pomocí FTP chceme pracovat s využitím SSH připojení na vzdáleném stroji nebo i jen prohlížet webové stránky, pak budeme mít problém. Řešením je právě nastavení priorit, podle potřeby.

Dalším příkladem může být síť s více uživateli, kteří sdílí jedno Internetové připojení (ADSL, kabelový rozvod, bezdrát 802.11b, ...). Vždy se totiž najde nějaký ten aktivní stahovač, který neúměrně toto připojení zatěžuje a ostatní jsou nuceni se spokojit s pásmem menším, než na jaké by měli mít nárok. Abychom tomuto problému předšli, můžeme buď rozdělit kapacitu linky na pevno (například linku 128 kbps na 2x64 kbps podle IP adres) a nebo podobně, ale s půjčováním volné kapacity.
Pevné rozdělení je většinou používáno Internetovými providery, jako nástroj pro zaručení přenosové kapacity zákazníkovi, kdy ovšem nechceme aby jeho rychlost připojení byla větší, než kolik si ve skutečnosti platí! Půjčování kapacity je naopak vyborným nástrojem pro uplatnění agregace (něco jako agregace 1:50 u ADSL v současné době) u linek s nezaručenou rychlostí připojení.


Jaké prostředky máme k dispozici?

K prosazování usměrnění síťového provozu se používají tzv. qdisc (qdisc=queuing discipline). K dispozici máme tyto qdiscy:

- FIFO (First In, First Out)
FIFO qdisc je standardně používán linuxovými systémy, pokud neřekneme jinak. Jedná se pouze o frontu paketů, které jsou obsluhovány v pořadí, v jakém přišly. Tato politika je nenáročná na výkon stroje, ale pro klasifikaci provozu se použít sama o sobě nedá.

- PRIO
PRIO qdisc je možné využít k priorizování síťového provozu. Pokud vytvoříme nový PRIO qdisc, ten obsahuje 3 PFIFO fronty odstupňované podle priority. Když je zcela vyprázdněna fronta 1, pokračuje se s frontou 2 a až potom s frontou 3. Tento přístup se může stát velkou nevýhodou v případě, že je fronta s číslem 1 neustále doplňována novými pakety. Potom se může stát, že pakety ve frontách 2 a především 3 budou váznout a nemusí se na ně dostat. Model je také výpočetně nenáročný, ale samotný se nepoužívá.

- TBF (Token Bucket Filter)
První použitelný přístup. Mějme jakýsi zásobník (Bucket) plněný konstantní rychlostí, který je navíc omezen shora. Podle toho jaký je v tomto zásobníku počet tokenů, můžeme propouštět packety. Klesne-li hodnota na nulu nebo pod velikost dalšího packetu, nemůžeme jej propustit. Běžně se používá poměr 1 token = 1 byte, tedy s každým bytem packetu odebereme také jeden token ze zásobníku. Tohoto přístupu se dá využít k jednoduchému a výpočetně nenáročnému omezení rychlosti připojení. Je-li rychlost s jakou přicházejí pakety nižší nebo stejná, než rychlost s jakou se zásobník plní, pak je vše v pořádku. Je-li ale rychlost vyšší, než dovoluje obsloužit stav zásobníku, dochází k zahazování paketů! TBF se dá například využít k zlepšení PRIO front.

- SFQ (Stochastic Fairness Queuing)
Jedná se vlastně o implementaci politiky Round-Robin na síťovém zařízení, tedy rovný přístup k prostředkům sítě. Provoz je rozdělen do omezeného, ale relativně velkého počtu front (pomocí proměného hashování), kdy každé je dána možnost vyslat nějaký objem dat. SFQ samotné je použitelné jen můžeme-li zaručit plné využití síťového rozhraní!

Skupina qdisců využívajících FIFO (FIFO, PRIO, TBF, SFQ) se také nazývá "DropTail queues". Jejich společným rysem je hrozba skokového způsobu zatížení linky v případě zaplnění front, což paradoxně vede k neefektivnímu využívání pásma a plýtvání prostředky.

- RED (Random Early Detection)
Klíčem k předcházení skokovému zatížení je metodika RED. Předcházení je realizováno proměnou délkou fronty a inteligentní predikcí zaplnění fronty. V případě, že hrozí zaplnění fronty, gateway vyšle zdrojům dat informaci o snížení rychlosti plnění. A to buď formou náhodného zahazování paketů nebo formou ECN (Explicit Congestion Notification), je-li podporováno. Každý paket je zahozen v jiném časovém okamžiku, tak aby nemohlo dojít k efektu, kdy všechny zdroje sníží svou vysílací rychlost a kapacita zůstane nevyužita.

- GRED (generalized RED)
Jedná se o rozšíření RED qdisc na více front s doplněním priorit.

- HTB (Hierarchichal Token Bucket)
Bude podrobněji popsáno níže.

- CBQ (Class-Based Queueing)
Bylo překonáno HTB qdiscem, který jej plně nahrazuje. Jeho hlavní nevýhodou je nepřehlednost příkazů a také fakt, že CBQ není úplně přesné!


Příklad: HTB

Takže podrobněji. HTB je classfull qdisc (tedy s podporou tříd) shaper. S jeho pomocí je možné vytvářet stromovou strukturu tříd a pomocí ní jemně nastavit naše priority síťového provozu. Tedy omezování jednotlivých uživatelů nebo služeb, propůjčování nevyužitého pásma mezi nimi. Tedy to co bylo zmíněno v úvodu.
HTB se umísťuje na odchozí zařízení, neboť filtrovat už na příchozím rozhraní nejsme schopni. Chceme-li filtrovat příchozí i odchozí provoz, musíme HTB zavěsit na obě rozraní.
Abychom mohli HTB využívat musíme mít kernel alespoň verze 2.4.20 a sadu nástrojů iproute (především program 'tc').
Na každou koncovou třídu, tedy tu, která nemá další classfull potomky, můžeme navěsit jeden z přechozích qdisců, například SFQ. Nezavěsíme-li nic, předpokládá se použití qdiscu FIFO. Musíme si uvědomit, že pokud navěsíme více classfull qdisců na sebe stoupají nároky na hardware a může docházet ke zpomalování přenosu.

Nyní pár příkladů na nastavení HTB:
tc qdisc del root dev eth1
Nejprve odstraníme všechny qdiscy, které se na daném zařízení mohly vyskytovat.

tc qdisc add dev eth1 root handle 1: htb default 99
Tímto příkazem se nastaví na zařízení eth1 kořenový qdisc formátu htb s defaultním využíváním podtřídy 99.

tc class add dev eth1 parent 1: classid 1:1 htb rate 512kbit burst 5k quantum 1700
tc class add dev eth1 parent 1:1 classid 1:10 htb rate 120kbit ceil 512kbit burst 1k quantum 1700 prio 1
tc class add dev eth1 parent 1:1 classid 1:20 htb rate 50kbit ceil 320kbit burst 5k quantum 1700 prio 2
tc class add dev eth1 parent 1:1 classid 1:99 htb rate 320kbit burst 1k quantum 1700 prio 3
Přidá htb třídu 1:1 na zařízení eth1 zavěšenou na rodičovskou třídu 1: (root) s parametrem rate, který stanovuje rychlost jakou má třída zaručenu, v tomto případě 512 kbit. Parametr burst zde určuje, kolik se může odeslat maximálně (zde 5kb) dat aniž by se shaper snažil jakkoli omezit přenosovou rychlost a parametr quantum určuje kolik minimálně bytu bude obslouženo, než se předá slovo následující třídě.
Další dva příkazy vytvoří třídy 1:10 a 1:20 se zaručenou rychlostí 120 a 50 kbps a pujčováním pásma až do 512 kbps u třídy 1:10 a 320 kbps v případě třídy 1:20. Třídy jsou priorizované (parametr prio). Čím nižší číslo, tím vyšší priorita a nižší latence.
Třída 1:99 má zaručenou rychlost 320 kbps, ovšem bude obsloužena až jako poslední a nemůže si pujčovat pásmo ani v případě, že jej ostatní třídy nevyužijí!
Základní konfigurace je vysvětlena, ještě zbývá návod, jak paketům říci, do které třídy patří. To můžeme provést dvěma způsoby. Můžeme pakety označovat pomocí tabulky iptables mangle+tc filtrem a nebo čistě jen s použitím tc filtru.

Způsob první, iptables mangle+tc:
iptables -t mangle -A POSTROUTING -d 192.168.0.1 -j MARK --set-mark 1
tc filter add dev eth0 parent 1:0 protocol ip handle 1 fw flowid 1:10
Mangle označí paket jako paket třídy '1' a tc filtr si jej podle toho zařadí do určené třídy (zde 1:1).

Způsob druhý, označování bez použití iptables, pomocí tc filtru:
tc filter add dev eth1 protocol ip parent 1:0 u32 match ip sport 22 0xffff flowid 1:10
tc filter add dev eth1 protocol ip parent 1:0 u32 match ip dport 22 0xffff flowid 1:10
Pomocí těchto dvou pravidel jsme řekli, že pro všechny IP adresy patří port 22 do třídy 1:10.

Je zřejmé, že právě použití priorizovaných tříd se hodí pro všechny důležité služby, které chceme komfortně používat aniž by jejich komunikace byla rušena ostatním provozem (např. SSH, ale i UDP stream v případě on-line her, kde je důležitý nízký ping...).

Problematika omezení šířky pásma na vstupním rohraní

Omezovat šírku pásma již na vstupním rozraní je téměř nemožné, protože okolní svět nejsme schopni kontrolovat a pokud se někdo rozhodne, že nám svou rychlejší linkou zablokuje provoz, my s tím neuděláme nic. Cesta jak alespoň částečně omezit provoz na vstupním rozhraní se jmenuje virtuální rozhraní IMQ (Intermediate Queueing Device), na které zavěsíme náš shaper. Toto ovšem neřeší problém nastíněný v první větě!

Rozdělení zátěže přes více rozhraní

Pro zvýšení propustnosti našeho připojení můžeme využít tzv. bonding, tedy slučování více fyzických rozhraní (eth0, eth1, ...) do jednoho virtuálního (bond0), kdy se kapacita sčítá. Abychom mohli něco takového podniknout, je nutné používat kernel se zakompilovanou podporou bondingu (CONFIG_BONDING=y).
Zde je ukázka /etc/sysconfig/network-scripts/ifcfg-bond0:
DEVICE=bond0
IPADDR=192.168.1.1
NETMASK=255.255.255.0
NETWORK=192.168.1.0
BROADCAST=192.168.1.255
ONBOOT=yes
BOOTPROTO=none
USERCTL=no
/etc/sysconfig/network-scripts/ifcfg-eth0:
DEVICE=eth0
USERCTL=no
ONBOOT=yes
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
/etc/sysconfig/network-scripts/ifcfg-eth1:
DEVICE=eth1
USERCTL=no
ONBOOT=yes
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
Blíže je nastavení bondingu objasněno v dokumentaci k linuxovému kernelu (kernel_directory/Documentation/networking/bonding.txt)


Měření a odkazy

Jako vhodný měřící nástroj se mi osvědčil
iftop.

Odkazy:
Stránka vysvětlující téměr vše
Domovská stránka projektu HTB
Linux Advanced Routing & Traffic Control HOWTO
htb.init skript
Testy HTB a CBQ
Výborný článek o HTB na www.root.cz