This is an old revision of the document!
Pentru a fi capabili să evaluăm politicile de QoS setate în rețeaua administrată de noi, avem nevoie de un utilitar care să genereze diferite tipuri de pachete, de diferite dimensiuni (UDP, TCP) și să măsoare viteza cu care acestea au fost transmise. Cel mai folosit utilitar pentru acest lucru este iperf
. Acesta creează pachete direct în memorie și le trimite pe rețea, eliminând overhead-ul altor dispozitive I/O (exemplu: dacă testam cu un transfer FTP se adăuga overhead-ul citirii/scrierii pe disc a fișierului transferat).
Utilitarul iperf poate rula în 2 moduri:
În cadrul acestui laborator dorim să limităm traficul de download
, astfel clientul iperf
va rula pe gateway
, iar server-ul iperf
, cel care primește traficul, va rula pe mașinile virtuale client1
și client2
.
Instalați iperf
pe toate cele 3 stații:
root@client1:~# apt-get update root@client1:~# apt-get install iperf root@client2:~# apt-get update root@client2:~# apt-get install iperf root@gateway:~# apt-get update root@gateway:~# apt-get install iperf
Pe stația client1
, porniți iperf
în modul server:
iperf -s
Pe stația gateway
, porniti iperf
în modul client:
iperf -c 192.168.1.1
După 10 secunde, atât server-ul (client1
) cât și clientul (gateway
) vor afișa statistici legate de traficul schimbat:
root@gateway:~# iperf -c 192.168.1.1 ------------------------------------------------------------ Client connecting to 192.168.1.1, TCP port 5001 TCP window size: 22.9 KByte (default) ------------------------------------------------------------ [ 3] local 192.168.1.3 port 57685 connected with 192.168.1.1 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 190 MBytes 159 Mbits/sec root@client1:~# iperf -s ------------------------------------------------------------ Server listening on TCP port 5001 TCP window size: 85.3 KByte (default) ------------------------------------------------------------ [ 4] local 192.168.1.1 port 5001 connected with 192.168.1.3 port 57685 [ ID] Interval Transfer Bandwidth [ 4] 0.0-10.0 sec 190 MBytes 159 Mbits/sec
Generați trafic de tip UDP
între stația gateway
și stația client2
în care lungimea pachetelor să fie de 256 de octeți (Hint: --len
).
În cadrul laboratorului, vom explora principalele strategii de QoS din Linux. Pentru a observa comportamentul strategiilor implementate, vom folosi un model de trafic, compus din:
Traficul nu va fi real ci îl vom simula cu ajutorul lui iperf
prezentat anterior.
Fiecare tip de trafic din cele considerate mai sus are anumite caracteristici și constrângeri. Pentru o funcționare optimă, trebuie să ținem seama de acestea:
Dupa cum ați observat la exercițiul anterior, o conexiune iperf
client-server generează un singur tip de trafic (implicit, trafic TCP pe portul 5001). Noi dorim să generăm mai multe tipuri de trafic, concomitent, pentru a vedea cum se afectează între ele. Deci va trebui să instanțiem mai multe astfel de perechi, în background.
Vom crea un script cu numele iperf-client1.sh
care va porni 4 servere iperf
pe stația client1
(urmăriți comentariile):
#!/bin/bash # Asculta trafic UDP, pe port-ul 8000 - fluxul de voce iperf --server --udp --port 8000 &> out1.txt & # Asculta trafic UDP, pe port-ul 6000 - fluxul video iperf --server --udp --port 6000 &> out2.txt & # Asculta trafic TCP, pe port-ul 21 - fluxul FTP # Daca nu se specifica --udp, implicit este TCP iperf --server --port 21 &> out3.txt & # Asculta trafic TCP, pe port-ul 80 - fluxul HTTP # Daca nu se specifica --udp, implicit este TCP. iperf --server --port 80 &> out4.txt & echo "iperf servers started. Now run the script on the gateway."
Vom crea pe stația gateway
un script cu numele iperf-gateway.sh
care se va conecta la cele 4 servere pornite pe stația client1
, generând cele 4 tipuri de trafic prezentate anterior. Simulăm tipurile de trafic prin generare de pachete ce au caracteristici asemănătoare cu cele din cazurile reale. Urmăriți comentariile din fișier:
#!/bin/bash IP_VM="192.168.1.1" TIME=60 # Durata unui test # Initiaza un flux UDP catre server, pe portul 8000 # Fiecare datagrama are dimensiunea de 128 octeti (tipic pentru pachetele de voce) # Se trimite la o rata de 640Kbps (dorim sa simulam 10 conversatii VoIP, a cate 64Kbps) iperf -x SC --client $IP_VM --port 8000 --udp --len 128 --bandwidth 640K --time $TIME > out3.txt 2> /dev/null & # Initiaza un flux UDP catre server, pe portul 6000 # Fiecare datagrama are dimensiunea maxima (pentru ca nu o specificam explicit) # Se trimite la o rata de 30Mbps iperf -x SC --client $IP_VM --port 6000 --udp --bandwidth 30M --time $TIME > out4.txt 2> /dev/null & # Initiaza un flux TCP catre server, pe portul 80 (HTTP) # Limitam dimensiunea unui segment la 512 octeti iperf -x SC --client $IP_VM --port 80 --mss 512 --time $TIME > out1.txt 2> /dev/null & # Initiaza un flux TCP catre server, pe portul 21 (FTP) # Dimensiunea unui segment va fi de 1400 octeti (dorim ca fluxul FTP sa fie mai agresiv) # Dimensiunea ferestrei TCP va fi de 256K (dorim ca fluxul FTP sa fie mai agresiv) iperf -x SC --client $IP_VM --port 21 --window 256K --mss 1400 --time $TIME > out2.txt 2> /dev/null & wait for i in out*; do echo; cat $i; done rm out*.txt
Rulați script-urile create anterior (iperf-client1.sh
pe stația client1
și iperf-gateway.sh
pe stația gateway
). Așteptați 60 de secunde și inspectați output-ul de pe stația gateway
. Ce observați?
Observăm că fluxurile UDP au suferit packet loss, ele neavând nici un mecanism pentru retransmitere sau reglare a vitezei în funcție e starea legăturii. Pentru fluxul video, o pierdere de pachete de câteva procente este inacceptabilă. În continuare vom studia mecanismele implicite de QoS din Linux și cum putem preveni aceste pierderi de pachete.
În Linux, strategiile de QoS se inspectează și configurează folosind comanda tc
. Termenul folosit pentru strategiile de QoS este qdisc
(de la queueing discipline
).
Afisați detalii despre qdisc-ul implicit, asociat interfeței eth0
de pe stația gateway
:
# tc qdisc show dev eth0 qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Observați că qdisc-ul implicit este pfifo_fast
(strategia implicită de QoS):
priority FIFO
.0
conține pachete, cozile 1 si 2 NU vor fi servite.
Ce reprezintă priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
? În Linux, kernel-ul asociază fiecărui pachet o prioritate, în functie de campul TOS (Type of Service) din header-ul IP. Prioritatea ne selectează una din cele 3 (sub)cozi din pfifo_fast: coada 0, 1 sau 2. Asocierile se fac după următorul tabel:
TOS Means Linux Priority Band ------------------------------------------------------- 0x0 Normal-Service 0 Best Effort 1 0x2 Minimize-Monetary Cost 1 Filler 2 0x4 Maximize-Reliability 0 Best Effort 1 0x6 mmc+mr 0 Best Effort 1 0x8 Maximize-Throughput 2 Bulk 2 0xa mmc+mt 2 Bulk 2 0xc mr+mt 2 Bulk 2 0xe mmc+mr+mt 2 Bulk 2 0x10 Minimize-Delay 6 Interactive 0 0x12 mmc+md 6 Interactive 0 0x14 mr+md 6 Interactive 0 0x16 mmc+mr+md 6 Interactive 0 0x18 mt+md 4 Int. Bulk 1 0x1a mmc+mt+md 4 Int. Bulk 1 0x1c mr+mt+md 4 Int. Bulk 1 0x1e mmc+mr+mt+md 4 Int. Bulk 1
Observăm că pachetele normale (cu TOS 0x00) sunt introduse în (sub)coada 1. La punctul anterior, fluxul UDP avea o pierdere semnificativă de pachete. O primă soluție ar fi marcarea pachetelor de voce și video cu un ToS favorabil (de exemplu, 0x10
), pentru a avea prioritate mai mare față de pachetele. Marcarea se realizează folosind lanțul mangle
al comenzii iptables
:
root@gateway:~# iptables -t mangle -A OUTPUT -p udp --dport 6000:8000 -j TOS --set-tos Minimize-Delay
Comanda anterioară marchează toate pachetele UDP cu porturile în intervalul 6000 și 8000 cu tag-ul Minimize-Delay
. Se observă că se poate folosi numele tag-ului în loc de valoare (0x10
).
Rulați din nou scriptul iperf-gateway.sh
pe stația gateway
și observați că procentele pierdute s-au diminuat foarte puțin. Nu e suficientă doar o prioritizare a pachetelor.
Am observat faptul că policing-ul pe baza ToS-ului nu este suficient pentru a asigura echitatea între servicii. Soluția ce se apoate aplica este dată de limitarea serviciilor FTP și HTTP.
tbf
este cea mai simplă metodă de a face traffic shaping în Linux. Este, de asemenea, un qdisc classless (ca și pfifo_fast
).
Dorim să limităm viteza pentru fluxurile FTP și HTTP (însumate) la aproximativ 9Mbps. Deoarece fluxul de voce are 640kbps, iar cel video are 30Mbps, rezulta ca o valoare acceptabila pentru viteza totală ar fi 40Mbps. Pe stația gateway
ne dorim următoarele setări:
Vom seta qdisc-ul tbf
, pe interfața eth0
astfel:
root@gateway:~# tc qdisc add dev eth0 root tbf rate 50mbit burst 128kbit latency 50ms
Rulați din nou script-ul iperf-gateway.sh
de pe stația gateway
. Asteptați 60 de secunde și inspectați output-ul afișat. Ce observați? Pierderile de pachete pentru conexiunea UDP au dispărut, qdisc-ul tbf
asigurând echitate între conexiuni.
Cu toate că suma vitezelor fluxurilor este de aproximativ 50Mbps, ea nu este distribuită așa cum ne-am fi asteptat. Fluxurile FTP și HTTP ocupa mai mult decât 9Mbps. Motivul este că limitarea a fost facută printr-o metoda classless, ce limitează întreg traficul de pe o interfață, fără a avea posibilitatea de a selecta și clasifica diferite tipuri de trafic. Soluția este dată de aplicarea unui qdisc classful, ce trateaza in mod separat diferitele clase de trafic.
htb
este un qdisc classful (tratează traficul în mod diferențiat, în funcție de clasa din care face parte). Este varianta classful a tbf
(împarte traficul pe clase, apoi aplica tbf
pe fiecare în parte).
Clasele sunt organizate într-o structura de arbore. Cu cât o clasa este mai jos în ierarhie, cu atât este mai specifică. Fiecare clasă are asociată o strategie de QoS (qdisc). În mod implicit, qdisc-ul este pfifo_fast, iar acesta poate fi modificat.
Exemplu de ierarhie:
1: root qdisc (always present) | 1:1 child class (with default qdisc) / \ / \ 1:3 1:4 leaf classes (with user-defined qdiscs) | | 30: 40: qdiscs (sfq) (sfq)
Observații:
major:
este echivalentă cu major:0
.1:1
are un qdisc asociat (cel implicit).1:3
și 1:4
le-a fost schimbat qdisc-ul implicit (în loc de pfifo_fast
, avem sfq
, un qdisc ce funcționează după modelul Round Robin)Tratarea pachetelor:
1:1
, dar NU se potrivește cu clasa 1:3
sau 1:4
, va fi tratat conform qdisc-ului implicit al clasei 1:1
, adica pfifo_fast
.1:1
ȘI cu clasa 1:3
, va fi tratat conform qdisc-ului clasei 1:3
, adica sfq
.1:4
.Clasificarea pachetelor:
match
și clasa în care trebuie inclus pachetul.Ne propunem sa alocam cate o clasa fiecarui tip de trafic din cele definite în scenariu. Fiecare clasă de trafic va fi limitată la o lățime de bandă bine definită, astfel:
Toate configurațiile vor fi făcute pe interfața eth0
a stației gateway
(politifice de traffic shaping pot fi aplicate doar pentru traficul care iese pe o interfață). Mai întâi, trebuie să ștergem orice alt qdisc de pe interfața eth0
:
root@gateway:~# tc qdisc del dev eth0 root
Adăugam qdisc-ul htb
, cu majorul 1:
(sau 1:0
):
root@gateway:~# tc qdisc add dev eth0 root handle 1: htb
Definim prima clasa, cea pentru traficul de voce. Trebuie să specificăm:
1:
1:1
(majorul trebuie sa fie același cu al părintelui, minorul poate fi orice)root@gateway:~# tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit burst 128k
Procedăm analog și pentru restul claselor:
tc class add dev eth0 parent 1: classid 1:2 htb rate 40mbit burst 128k tc class add dev eth0 parent 1: classid 1:3 htb rate 5mbit burst 128k tc class add dev eth0 parent 1: classid 1:4 htb rate 3mbit burst 128k
Verificăm qdisc-ul asociat interfeței eth0
și ierarhia de clase adăugată:
root@gateway:~# tc qdisc show dev eth0 qdisc htb 1: root refcnt 2 r2q 10 default 0 direct_packets_stat 82 direct_qlen 1000 root@gateway:~# tc class show dev eth0 class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Kbit burst 128Kb cburst 1600b class htb 1:2 root prio 0 rate 40000Kbit ceil 40000Kbit burst 128Kb cburst 1600b class htb 1:3 root prio 0 rate 5000Kbit ceil 5000Kbit burst 128Kb cburst 1600b class htb 1:4 root prio 0 rate 3000Kbit ceil 3000Kbit burst 128Kb cburst 1599b
Cu toate că am definit ierarhia de clase, nu am definit cum selectăm traficul pentru aceste clase. Vom folosi noțiunea de filtre oferită de utilitarul tc
. Definim primul filtru, ce selectează trafic cu portul destinație 8000
. Trebuie să specificam:
1:
- vom atasa toate filtrele în nodul rădăcina1
- toate filtrele vor avea aceeași prioritateu32
, ce poate face match pe header-ul IP1:1
:root@gateway:~# tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 8000 0xffff flowid 1:1
Procedăm analog și cu celelalte filtre:
root@gateway:~# tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 6000 0xffff flowid 1:2 root@gateway:~# tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 21 0xffff flowid 1:3 root@gateway:~# tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 80 0xffff flowid 1:4
Verificăm filtrele create:
root@gateway:~# tc filter show dev eth0 filter parent 1: protocol ip pref 1 u32 filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1 filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 match 00001f40/0000ffff at 20 filter parent 1: protocol ip pref 1 u32 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2 match 00001770/0000ffff at 20 filter parent 1: protocol ip pref 1 u32 fh 800::802 order 2050 key ht 800 bkt 0 flowid 1:3 match 00000015/0000ffff at 20 filter parent 1: protocol ip pref 1 u32 fh 800::803 order 2051 key ht 800 bkt 0 flowid 1:4 match 00000050/0000ffff at 20
Pe stația gateway, rulați din nou script-ul iperf-gateway.sh
. Asteptați 60 de secunde și inspectați output-ul afișat. Ce observați?
tbf
) pentru flow-urile UDP.Ștergeți qdisc-ul root adăugat anterior.
Realizați configurațiile necesare astfel încât să limitați stația client1
la 5 mbps, iar stația client2
la 3mbps. În plus dorim ca cei 3mbps ai stației client2
să fie împărțiți după cum urmează:
match
ale clasificatorului u32
)
Testați folosind iperf
.