Klasifikace provozu sítě

Otakar Lávička, xlavick1 at fi.muni.cz


Obsah


1. Úvod

Přenos dat na zatížených sítích v režimu best effort nezaručuje kvalitu služby a rovnoměrné využití sítě různými aplikacemi. Organizace ITU-T definuje kvalitu služby (QoS) jako souhrnný efekt výkonnosti služby, který určuje stupeň uspokojení uživatele této služby. Hlavními parametry QoS jsou propustnost a zpoždění mezi zdrojovou a cílovou stanicí.

Na kvalitu služby mají vliv všechny uzly sítě mezi komunikujícími stanicemi. Model QoS zvaný integrované služby (IntServ) předpokládá záruky pro QoS po celé trase mezi zdrojovou a cílovou stanicí. Pro tento účel musí všechny uzly na trase získat informace o parametrech požadovaných pro daný datový tok a vyhradit pro něj odpovídající zdroje. To je spojeno s režií na každém takovém aktivním prvku mezi stanicemi (napříč celým Internetem).

Pracovní skupina IETF pro diferencované služby (DiffServ) proto vytvořila podstatně jednodušší model QoS, který je založen na agregaci datových toků do malého počtu tříd (Class of Service - CoS) a jim odpovídajících kvalitativních typů služeb. Režie, spojená s rozdělováním kapacity sítě, je přesunuta na hraniční routery (např. router mezi klienty ISP a samotnou sítí ISP), které jednotlivým datovým tokům přidělují šířku pásma na základě tříd (klasifikace paketů). Routery v jádru sítě (nehraniční) již komunikují režimem best effort.

Podrobněji na http://www.cesnet.cz/doc/seminare/ei2000liberec/lhotka.html.


2. Fronty paketů, řazení do front

Fronta paketů je pořadí, v jakém budou pakety odeslány ze síťového rozhraní. Způsob řazení do této fronty je právě algoritmus pro zajištění kvality služeb. Protože nemůžeme ovlivnit pořadí, v jakém obdržíme data na vstupu, je problematické uplatňovat QoS pro příchozí traffic. Díky vlastnostem protokolu TCP můžeme zahazovat pakety, pokud chceme docílit snížení rychlosti přijímaných dat. To se ale netýká jiných protokolů, kde zahazování paketů nemá na rychlost žádný vliv.

Příchozí traffic na síťovém rozhraní se souhrně označuje ingress a jeho tvarování (přeuspořádání, zpomaleni či zahození paketů) se nazává policing. V Linuxu lze na ingress uplatnit pouze omezení šířky pásma pomocí zahazování paketů, žádné pokročilé způsoby klasifikace provozu nelze použít.

Odchozí traffic na síťovém rozhraní se označuje egress a jeho tvarování se nazývá shaping. Pomocí shapingu lze pakety zpomalovat, přeuspořádávat i zahazovat za použití různě složitých algoritmů.

Způsob řazení paketu do fronty je označován qdisc (queue discipline). Lišíme classless qdisc a classful qdisc.

2.1 Classless qdisc

Classless qdisc nemohou obsahovat jiné qdisc (resp. se to nedoporučuje). Určují pouze, jak bude naloženo s paketem (zda bude zařazen, zdržen nebo zahozen).

2.1.1 pfifo_fast

Výchozí fronta pro síťová rozhraní je pfifo_fast. Jak název napovídá, jedná se opravdu o frontu FIFO. Pakety jsou odesílány v pořadí, v jakém byly přijaty. Nejedná se tedy o příliš spravedlivou nebo nastavitelnou qdisc, ale částečně se její chování dá ovlivnit.

pfifo_fast obsahuje tři fronty 0, 1 a 2. Nejprve se vyřizují pakety ve frontě 0, pokud je prázdná, přijde na řadu fronta 1, pokud i ta je prázdná, zpracovává se fronta 2. Pakety jsou do front řazeny podle příznaku TOS (type of service). Jednotlivé fronty jsou již typu FIFO bez dalších možností nastavení.

Seznam příznaků TOS a jejich mapování na jednotlivé fronty jsou na http://lartc.org/howto/lartc.qdisc.classless.html.

2.1.2 TBF

Algoritmus TBF (Token Bucket Filter) je jednoduchý a nenáročný na výkon. Je vhodný pro jednoduché omezení rychlosti na síťovém rozhraní.

Funguje na bázi "kapes", které plní daty k odeslání a postupně vyprazdňuje danou rychlostí při odesílání dat. Je tak zaručeno, že se nezahltí (pokud je kapsa plná, data se zahazují), ale zároveň nejsou data při krátkodobém větším zatížení zbytečně zahazována.

Podrobněji o nastavení TBF na http://lartc.org/howto/lartc.qdisc.classless.html.

2.1.3 SFQ

SFQ (Stochastic Fairness Queueing) je jednoduchý algoritmus pro zajištění rovnoměrného využití sítě všemi aktivními datovými proudy. Nezajistí férové využití mezi uživateli či programy, ale např. mezi jednotlivými TCP spojeními vzhledem ke své jednoduchosti docela obstojně.

Vytváří více front, do kterých rozděluje jednotlivá TCP spojení a UDP proudy podle hashovací funkce. Tyto fronty jsou zpracovávány algoritmem round robin. Každé spojení má tak šanci na vyřízení a jeden objemný datový proud nezahltí většinu kapacity linky. Hashovací funkce se v čase mění a jsou tak řešeny kolize (dva proudy ve stejné frontě dlouho nezůstanou).

2.1.4 RED

RED (Random Early Detect, Random Early Drop) je určen pro vytížené páteřní spoje. Podle vypočítaných statistik snižuje zátěž zahazováním paketů před zahlcením linky. Čím blíže je celkový traffic maximální hodnotě, tím více jsou pakety zahazovány.

Tento algoritmus neposkytuje žádné možnosti shapingu a chová se ke všem datovým proudům stejně. Na vytížených strojích ovšem nemá tak vysoké výpočetní nároky a udržuje co největší průchodnost a co nejnižší zpoždění linky.

2.2 Classful qdisc

Classful qdisc jsou třídy, které mohou obsahovat další qdisc (classles i classful). Tvoří tak strom tříd, jehož uzly obsahují další classful qdisc a listy právě jednu classless qdisc.

Každé síťové rozhraní má na egress jednu kořenovou qdisc, která je ve výchozím nastavení pfifo_fast. Ta se používá pro shaping (odchozí směr). Pro policing je qdisc na ingress, ale ta má velmi omezené možnosti nastavení. Dále bude probírán pouze shaping.

Třídy a qdisc

Každá qdisc a třída (méně často i filtr) je označena pro odkazování z dalších příkazů. Toto značení se skládá ze dvou čísel oddělených dvojtečkou (<major>:<minor>) a může být zadáno ručně nebo automaticky. Číslo <major> musí být jedinečné v rámci celého nastavení egress (nebo ingress). Číslo <minor> musí být jedinečné v rámci qdisc.

Kořenová qdisc se obvykle značí 1: nebo 1:0 (totéž). Číslo <major>: se nazvá handle. Třídy pod qdisc sdílí <major> a liší se v <minor> (číslo třídy se nazývá classid) Je zvykem pojmenovávat podtřídy přidáním čísla k <minor> rodiče, tedy např. třída 1: má podtřídy 1:1 a 1:2, a třída 1:2 má podtřídy 1:21 a 1:22. Pokud přidáváme qdisc do třídy, vytvoříme nový <major> podle <minor> třídy (tedy ve třídě 1:22 bude qdisc 22:0 a v něm případné další 22:1, 22:2).

Klasifikace, filtry

Způsob rozdělení paketů do tříd je klasifikace (classifier) a provádí se pomocí filtrů. Každá classful qdisc může mít tyto filtry, kterými se určí další qdisc, do které budou pakety předány.

Jádro předá paket do kořenové qdisc, ze které pak putuje po uzlech dle filtrů až do listu, kde je zařazen do fronty podle classles qdisc. Filtry nemusí být v každé třídě, ale paket může být zařazen do koncové qdisc již v kořenové qdisc.

2.2.1 PRIO

PRIO je podobné pfifo_fast, při vytvoření vytvoří 3 třídy, které mají prioriy 0, 1 a 2 a zpracovávají se postupně (od nejnižší, teprve až je prázdná, může se zpracovat další třída). Jednotlivé třídy zprácovávají pakety úplně obyčejnou frontou, ale lze na ně pověsit libovolnou jinou qdisc.

Počet tříd i klasifikaci můžeme nastavit, ve výchozím nastavení se používá obdobný způsob klasifikace jako u pfifo_fast. Přímo shaping tato qdisc neumožňuje, ale lze docílit pokročilých nastavení prioritního zpracování dat.

2.2.2 CBQ

CBQ (Class Based Queueing) je dlouho používaná a na nastavení velmi bohatá qdisc. Podporuje libovolné vnořování tříd a shaping. Třídy mohou půjčovat svou konektivitu podtřídám a získávat od svých předků. Podporuje také priority (obdobně jako PRIO).

Při výpočtech vychází z doby nečinnosti linky, průměrovaných velikostí paketů a šířky pásma. Mezi jednotlivými třídami pak vybírá algoritmem wighted round robin (který lze také ovlivnit nastavením).

2.2.3 HTB

Od českého autora (Martin Devera) pochází qdisc HTB (Hierarchical Token Bucket), která je méně složitá než CBQ, ale v mnoha případech plně dostačující. Podporuje podobné možnosti, lze shapovat i použít priority. Hodí se zvláště do situací, kdy je třeba pevnou šířku pásma rozdělit mezi více aplikací (uživatelů, služeb...) tak, aby každá měla zaručen základní přenos, ale aby mohla též použít větší šířku pásma, je-li dostupná.

HTB poskytuje podobnou funkčnost jako CBQ, ale nepoužívá propočty nečinnosti linky. Lze spíše přirovnat k TBF s třídami.


3. Instalace v Linuxu

3.1 Jádro

Podpora IMQ

Stáhnout IMQ patch: http://www.linuximq.net/patches.html a opatchovat jádro.

	# cd /usr/src/linux
	# patch -p1 < /usr/src/imq/linux-2.6.9-imq1.diff

Do jádra přidat (počet IMQ zařízení stačí 2):
CONFIG_IMQ (Network device support/IMQ (intermediate queueing device) support)
CONFIG_IP_NF_TARGET_IMQ (Networking options/IP: Netfilter Configuration/IMQ target support)

Popis instalace IMQ http://wiki.nix.hu/cgi-bin/twiki/view/IMQ/HowToInstall
nebo polské howto http://alfa.tailor.com.pl/imqhtb/2.4.26/imq_htb_pl.html

QoS a netfilter

V jádru je třeba mít podporu pro iptables a QoS (alespoň HTB, SFQ, TEQL, TBF, U32) - Drivers/Net.support/Net.options/QoS/...

3.2 Programy

Stáhnout zdrojové kódy iptables z http://www.netfilter.org, opatchovat pro IMQ a zkompilovat.

	# cd /usr/src/
	# wget ftp://ftp.netfilter.org/pub/iptables/iptables-1.3.1.tar.bz2
	# tar -xjf ./iptables-1.3.1.tar.bz2
	# cd /usr/src/iptables-1.3.1
	# wget http://www.linuximq.net/patchs/iptables-1.3.0-imq1.diff
	# patch -p1 < iptables-1.3.0-imq1.diff
	# chmod +x extensions/.IMQ-test*

Nainstalovat balík iproute (http://linux-net.osdl.org/index.php/Iproute2).


4. Konfigurace

4.1 Shaping

Příklad: Chceme rozdělit linku 128 kbps tak, abychom na odchozím trafficu z rozhraní eth0 zaručili nejméně 64 kbps pro www a 32 kbps pro smtp, ale aby www používalo i případnou kapacitu nevyužitou smtp. Jiné služby než www a smtp na lince nepoběží, ale pokud by k tomu došlo, použije se pro ně třída www.

Vytvoříme strukturu HTB tříd, kde kořenová bude obsahovat celou kapacitu linky a její podtřídy budou pro www a smtp. Výchozí třída bude www. Jako konečnou (na listech) qdisc použijeme SFQ, což zajistí férové využití mezi všemi datovými proudy.

Při návrhu HTB tříd je dobré uvádět nejprve třídy s vyšší prioritou. Dále součet hodnot rate (garantovaná kapacita) potomků by neměl přesáhnout hodnotu rate rodiče a žádná z hodnot ceil (maximální propustnost) potomka by neměla přesáhnout ceil rodiče.

Pro rozdělení paketů do tříd použijeme markování paketů pomocí iptables. Jako výchozí třídu nastavíme přímo v kořenové qdisc 1:11 (stačí uvést 11, protože nelze poslat paket mimo samotnou qdisc).

	tc qdisc del dev eth0 root
	tc qdisc add dev eth0 root handle 1:0 htb default 11
	tc class add dev eth0 parent 1:0 classid 1:1 rate 128kbit

	tc class add dev eth0 parent 1:1 classid 1:11 rate 64kbit ceil 128kbit
	tc class add dev eth0 parent 1:1 classid 1:12 rate 32kbit

	tc qdisc add dev eth0 parent 1:11 handle 11:0 sfq perturb 5
	tc qdisc add dev eth0 parent 1:12 handle 12:0 sfq perturb 10

	tc filter add dev eth0 parent 1:0 protocol ip handle 11 fw flowid 1:11
	tc filter add dev eth0 parent 1:0 protocol ip handle 12 fw flowid 1:12

	iptables -t mangle -A POSTROUTING -p tcp --dport www -j MARK --set-mark 11
	iptables -t mangle -A POSTROUTING -p tcp --dport smtp -j MARK --set-mark 12

4.2 Pokročilý policing

Pro použití technik shapingu také pro policing v neomezené míře lze použít IMQ (Intermediate Queueing Device). Jedná se o virtuální rozhraní, které po přijetí paketu tento ihned odešle zpět. Máme tak rozhraní, které má vstup i výstup. Stačí již na vstupu klasického síťového rozhraní přesměrovat provoz na virtuální rozhraní a zde je na výstupu shapovat, čímž dosáhneme policingu.

Díky rozhraní IMQ tedy můžeme efektivně "shapovat" i příchozí traffic. Navíc je řešitelný další problém - shapování přes více rozhraní. Protože qdisc může být pouze na jednom rozhraní, nemůžeme např. určit jedinou globální třídu pro veškerý ftp provoz, pokud mohou být odchozí dvě rozhraní (museli bychom vytvořit dvě třídy, které by ovšem neměly společně omezovaný traffic).

Při vytváření qdisc dáme všechny na IMQ rozhraní a pomocí iptables přesměrujeme z různých rozhraní shapovaný/policingovaný provoz na IMQ.

Příklad: Máme router s třemi síťovými rozhraními eth0, eth1 a eth2. Rozhraní eth0 je síť 2 lidí (počítačů), další dvě rozhraní jsou do okolních sítí. Lidé mají dohodu, že jejich celkový provoz do okolních sítí nepřesáhne 1 Mbps a přitom má každý garantovánu odchozí rychlost 500 kbps.

Pomocí IMQ můžeme situaci řešit dvěma způsoby. Buď odchozí traffic na rozhraních eth1 a eth2 sloučíme do jednoho virtuálního imq0, nebo příchozí traffic na eth0 přesměrujeme na imq0. Každopádně na imq0 budou vždy stejné qdisc. Ukážeme obě možnosti.

Nejprve vytvoříme qdisc. Přidáme výchozí qdisc s nízkou rychlostí i prioritou pro případ jiných IP (a necháme mu výchozí classless qdisc pfifo_fast).

	ifconfig imq0 up

	tc qdisc del dev imq0 root
	tc qdisc add dev imq0 root handle 1: htb default 10
	tc qdisc add dev imq0 parent 1: classid 1:1 rate 1024kbit

	tc qdisc add dev imq0 parent 1:1 classid 1:10 rate 24kbit prio 1
	tc qdisc add dev imq0 parent 1:1 classid 1:11 rate 500kbit ceil 1024kbit prio 0
	tc qdisc add dev imq0 parent 1:1 classid 1:12 rate 500kbit ceil 1024kbit prio 0

	tc qdisc add dev imq0 parent 1:11 handle 11: sfq perturb 10
	tc qdisc add dev imq0 parent 1:12 handle 12: sfq perturb 10

	tc filter add dev imq0 parent 1:0 protocol ip handle 1 fw flowid 1:11
	tc filter add dev imq0 parent 1:0 protocol ip handle 2 fw flowid 1:12

Máme připraven shaper na imq0, nyní první řešení - odchozí traffic na eth1 a eth2 sloučíme do imq0.

	iptables -t mangle -A POSTROUTING -o eth1 -s 10.0.0.1 -j MARK --set-mark 1
	iptables -t mangle -A POSTROUTING -o eth2 -s 10.0.0.1 -j MARK --set-mark 1
	iptables -t mangle -A POSTROUTING -o eth1 -s 10.0.0.2 -j MARK --set-mark 2
	iptables -t mangle -A POSTROUTING -o eth2 -s 10.0.0.2 -j MARK --set-mark 2

	iptables -t mangle -A POSTROUTING -o eth1 -j IMQ --todev 0
	iptables -t mangle -A POSTROUTING -o eth2 -j IMQ --todev 0

Druhé řešení - příchozí traffic na eth0 budeme "shapovat". Aby nebyl omezován příchozí traffic na router, zavedeme markování a přesměrování na FORWARD.

	iptables -t mangle -A FORWARD -i eth0 -s 10.0.0.1 -j MARK --set-mark 1
	iptables -t mangle -A FORWARD -i eth0 -s 10.0.0.2 -j MARK --set-mark 2

	iptables -t mangle -A FORWARD -i eth0 -j IMQ --todev 0

4.3 Rozdělení zátěže

Rozdělit provoz mezi více síťových zařízení se dá více způsoby. Předpokládejme, že máme dva Linuxové routery, které chceme propojit dvěmi fyzickými rozhraními pro zvýšení propustnosti.

Jednou poměrně jednoduchou možností je použít qdisc TEQL (Trivial Link EQualizer). Celý mechanismus se chová trochu jako qdisc a trochu jako virtuální rozhraní. Utilitkou tc určíme fyzická rozhraní, která budou spojena do virtuálního rozhraní teql0. Qdisc TEQL pak rozděluje provoz mezi spojená rozhraní algoritmem round robin.

Na obou strojích tedy spojíme fyzická rozhraní (řekněme eth0 a eth1).

	tc qdisc add dev eth0 root teql0
	tc qdisc add dev eth1 root teql0
	ip link set dev teql0 up

Nyní nastavíme IP adresy tak, aby každé zařízení na jednom routeru bylo v jiné podsíti a samozřejmě aby síťově spojená zařízení měla stejnou síť.


	Router A (teql0 10.0.0.4/31)            Router B (teql0 10.0.0.5/31)
	  +----------------------+                +----------------------+
	  |           10.0.0.0/31|------eth0------|10.0.0.1/31           |
	  |           10.0.0.2/31|------eth1------|10.0.0.3/31           |
	  +----------------------+                +----------------------+
	

Routery by měly být schopny navzájem pingnout všechny IP uvedené na obrázku. Jako brány pro sítě za routery se nastaví IP teql0 rozhraní druhého routeru (router A bude mít bránu pro sítě za routerem B IP adresu 10.0.0.5).

Nakonec je třeba vypnout na spojených rozhraních return path filtering, aby se nezahazovaly pakety určeny pro jiné IP než má dané rozhraní.

	echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter
	echo 0 > /proc/sys/net/ipv4/conf/eth2/rp_filter

5. Odkazy

Linux Advanced Routing & Traffic Control HOWTO
IPROUTE2 Utility Suite Howto
HTB Linux queuing discipline manual
IMQ+HTB - polské howto
IMQ domovská stránka
Seriál na root.cz o HTB