Upload
lythuy
View
213
Download
0
Embed Size (px)
Citation preview
SAMODZIELNY ZAKŁAD SIECI KOMPUTEROWYCH
P O L I T E C H N I K A ŁÓ D Z K A
90-924 Łódź ul. Stefanowskiego 18/22
tel./fax. (42) 6 360 300
e-mail: [email protected]
i
Kształtowanie ruchu w sieciach
komputerowych
Pra
Krzysztof Pijewsk
ca dyplomowa magisterska
Promotor:
dr inż. Michał Morawski
Dyplomant:
Krzysztof Pijewski
nr albumu: 101074
.
Łódź, wrzesień 2004rSpis treści
Spis treści.............................................................................................................. 2
Wprowadzenie ..................................................................................................... 4
Cel i zakres pracy ................................................................................................ 6
Rozdział 1 QoS i kształtowanie ruchu w sieciach. .................................... 7
1.1 Podstawowe parametry QoS ...................................................................................... 7
1.2 Zakres zastosowania................................................................................................. 10
1.3 Mechanizmy Quality of Service............................................................................... 11
1.3 Zalety i wady kształtowania ruchu........................................................................... 14
Rozdział 2 Algorytmy kształtowania ruchu ............................................ 20
2.1 Algorytmy kolejkowania.......................................................................................... 20
2.2 Manipulowanie rozmiarem okna TCP ..................................................................... 25
2.3 Idea „cieknącego wiadra” i „wiadra z żetonami”..................................................... 25
2.4 „Hierarchiczne wiadro z żetonami” ......................................................................... 31
Rozdział 3 Komercyjne rozwiązania kształtowania ruchu .................... 41
3.1 Przełączniki i routery z możliwością kształtowania ruchu ...................................... 41
3.2 Specjalistyczne urządzenia zarządzające przepustowością...................................... 44
Rozdział 4 Biblioteka NDIS i sterowniki sieciowe .................................. 48
4.1 Czym jest NDIS?...................................................................................................... 48
4.2 Wersje biblioteki NDIS............................................................................................ 49
4.3 Rodzaje sterowników NDIS..................................................................................... 50
4.4 Struktura pakietu w bibliotece NDIS. ...................................................................... 53
4.5 Budowa sterownika pośredniego ............................................................................. 55
4.6 Sposoby komunikacji ze sterownikiem.................................................................... 58
2
Podsumowanie ................................................................................................... 61
Załącznik 1 Instrukcja użytkownika programu „BandMan” ................. 63
Przeznaczenie programu ...................................................................................................... 63
Wymagania........................................................................................................................... 64
Instalacja............................................................................................................................... 64
Polecenia menu .................................................................................................................... 68
Konfiguracja......................................................................................................................... 68
Usuwanie programu z systemu ............................................................................................ 75
Załącznik 2 Dokumentacja techniczna programu.................................... 77
Wprowadzenie...................................................................................................................... 77
Struktura projektu................................................................................................................. 77
Budowa sterownika .............................................................................................................. 78
Budowa aplikacji użytkownika ............................................................................................ 81
Zarządzanie pakietami.......................................................................................................... 82
Komunikacja sterownik – program użytkownika ................................................................ 85
Funkcja kształtowania ruchu................................................................................................ 89
Załącznik 3 Testy programu ....................................................................... 93
Wprowadzenie...................................................................................................................... 93
Test 1 Kształtowanie ruchu wychodzącego UDP ........................................................... 93
Test 2 Ograniczanie ruchu wchodzącego TCP ............................................................... 95
Test 3 Ograniczanie ruchu wchodzącego UDP............................................................... 97
Test 4 Znaczenie rozmiaru „wiadra” dla UDP i TCP ..................................................... 98
Test 5 Pożyczanie przepustowości pomiędzy klasami.................................................. 103
Test 6 Wpływ „priorytetu” na pożyczanie przepustowości .......................................... 105
Test 7 Wpływ „kwantu” na pożyczanie przepustowości .............................................. 107
Podsumowanie ................................................................................................................... 110
Załącznik 4 Płyta CD-ROM ...................................................................... 111
Literatura ......................................................................................................... 112
3
Wprowadzenie
W nowoczesnych sieciach komputerowych mamy do czynienia z wieloma rodzajami
przepływów informacji o odrębnych charakterystykach i wymaganiach odnośnie zasobów
sieciowych. Przykładowo, występują transmisje dźwięku i wideo, szczególnie przy
przekazach na żywo, które muszą docierać do użytkowników w jak najkrótszym czasie, bez
opóźnień, przy stałych, niezbyt dużych zapotrzebowaniach na przepustowość.
W codziennej pracy z komputerem niejednokrotnie wysyłamy duże pliki, dla których czas
przesłania poszczególnych pakietów nie jest aż tak istotny jak średnia prędkość transmisji.
Jednak chcąc w tym samym czasie wysłać np. ważny email, który przecież zajmuje zaledwie
kilka kilobajtów, lub połączyć się z serwerem poprzez Telnet, napotykamy na duże
opóźnienia, co zmusza nas niejednokrotnie do przerwania innych, bardziej wymagających
transmisji.
Tego typu problemy są szczególnie odczuwalne gdy jesteśmy połączeni z Internetem za
pośrednictwem wąskich łącz o przepustowości od kilkudziesięciu do kilkuset kilobitów na
sekundę lub dzielimy nasze łącze z innymi użytkownikami. Jest to bardzo pospolite zjawisko.
Powyższe przykłady stanowią tylko niezmiernie uproszczoną ilustrację problemu stale
powiększającego się zapotrzebowania na przepustowość sieci i konieczności
zagwarantowania pewnych parametrów łącza. Z zagadnieniem tym boryka się wiele firm i
instytucji, a z pomocą przychodzą bardzo zaawansowane technologie i duże grona
naukowców i specjalistów ds. sieci komputerowych na całym świecie.
Mając na uwadze takie zagadnienia, ogół cech i mechanizmów jakie mają zapewnić pewną
gwarantowaną jakość usług sieciowych zebrano pod wspólną nazwą Quality of Service
(w skrócie QoS). Inaczej mówiąc QoS jest to charakterystyka sieci komputerowych, która
pozwala w szczególny sposób traktować różne rodzaje ruchu dzieląc go na bardziej i mniej
ważny, przy czym zapewniając jednym i drugim pewne określone ilości zasobów. Jednym z
4
mechanizmów gwarantowania jakości usług jest kształtowanie ruchu, czyli określanie jaki
dostęp do przepustowości mają poszczególne grupy transmisji.
5
Cel i zakres pracy
Główny cel pracy stanowi omówienie podstawowych mechanizmów kształtowania ruchu w
sieciach komputerowych, a także praktyczna ich realizacja w środowisku Microsoft Windows
przy użyciu specjalnie napisanego programu.
W niniejszym opracowaniu przedstawiono najważniejsze informacje dotyczące standardów
zarządzania przepustowością. Ukazano także ich powiązanie z gwarantowaną jakością usług –
Quality of Service. Ponadto omówione zostało komercyjne podejście czołowych producentów
urządzeń sieciowych do tego zagadnienia.
W pracy można także przeczytać, w jaki sposób praktycznie zrealizować kształtowanie ruchu
we własnym zakresie. Zawarto w niej bowiem opis biblioteki NDIS, która pozwala na
implementację omówionych mechanizmów. Cennej pomocy w tym zakresie udzieli
dołączony program – sterownik dla systemu Microsoft Windows XP napisany na potrzeby
niniejszej pracy.
6
Rozdział 1 QoS i kształtowanie ruchu w sieciach.
Quality of Service – w skrócie QoS – czyli gwarantowana jakość usług i kształtowanie ruchu
w sieciach komputerowych są pojęciami nierozerwalnymi. Kształtowanie ruchu (ang. traffic
shaping) jest bowiem jednym z podstawowych mechanizmów mających za zadanie poprawić
działanie sieci.
W tym rozdziale przedstawiono pokrótce podstawowe parametry służące do pomiaru
poziomu dostarczanych usług, mechanizmy umożliwiające ich polepszenie, zakres
zastosowania, a także zalety i wady wprowadzenia w sieci kształtowania ruchu.
Główną specyfikację dotyczącą gwarantowanej jakości usług można odnaleźć w dokumencie
[RFC-2212]. Dodatkowo pomocne opracowania znajdują się w [BCR] oraz [LINK].
1.1 Podstawowe parametry QoS
Mówiąc o Quality of Service ważne jest zdefiniowanie pewnych parametrów, dzięki którym
możliwe będzie rozpoznanie, kiedy usługi oferowane przez daną sieć stoją na wysokim czy
niskim poziomie i w konsekwencji czy daną sieć będzie można wykorzystać do pewnych
szczególnych typów zastosowań. Jest to najbardziej istotne, gdy w grę wchodzą duże sumy
jakie należy płacić usługodawcom internetowym, których obecnie na rynku jest bardzo wielu.
Oczywiście zasięg, lokalizacja i to, przez kogo dana sieć jest posiadana powodują, że QoS
oraz niżej wymienione współczynniki będą postrzegane przez różne kręgi zainteresowań w
odmienny sposób. Przykładowo przedsiębiorstwo może wdrożyć gwarantowaną jakość usług
w swojej sieci wewnętrznej, chcąc poprawić parametry transmisji multimedialnych. Również
wielkości te pozwalają w łatwiejszy sposób tworzyć umowy dotyczące jakości usług
7
pomiędzy usługodawcami internetowymi a ich klientami. Warto w tym miejscu wspomnieć,
że umowy tego typu nazywane są kontraktami SLA (service-level agreements) i mogą
zawierać jeszcze dodatkowe parametry, takie jak np. gwarantowany procentowy czas
funkcjonowania połączenia w skali pewnego przedziału czasu.
Poniżej wymieniono najważniejsze spośród parametrów Quality of Service.
Prędkość transmisji danych (ang. Throughput)
Inaczej mówiąc przepustowość, oznacza ilość danych jakie można wysłać przez sieć
pomiędzy dwoma jej punktami w jednostce czasu. Jest mierzona w bitach na sekundę, jednak
w skali całego łącza można także posługiwać się wielkościami wyrażonymi w procentach, co
jest użyteczne np. przy ustalaniu pewnych reguł na dostępność przepustowości. Parametr ten
jest szczególnie istotny przy transmisjach dużych ilości danych takich jak transfer plików
przez protokół FTP.
Zagwarantowanie przepustowości jest łatwe do wprowadzenia w sieciach opartych o
technologię ATM, jednak w sieciach pakietowych, a przecież Internet reprezentuje taką sieć,
stanowi pewne wyzwanie dla osób zajmujących się zapewnianiem parametrów Quality of
Service.
Straty Pakietów (ang. Packet loss)
Kiedy współdzielone łącze zostaje wykorzystane w coraz większym stopniu, kolejki w
urządzeniach sieciowych zaczynają wypełniać się pakietami, a w konsekwencji nawet
odrzucać kolejne pakiety. Stosując jednak odpowiednią strategię zarządzania buforami
takiego urządzenia można zredukować liczbę straconych pakietów.
Straty pakietów mogą być wyrażane procentową ilością zagubionych paczek danych w
stosunku do łącznej liczby pakietów, przesłanych w pewnym przedziale czasu. Wzrost tego
niekorzystnego zjawiska można szczególnie zauważyć, gdy pewien węzeł sieci łączy dwa jej
segmenty o odmiennych prędkościach transmisji. Wtedy na interfejsie po stronie szybszego
łącza pojawia się więcej pakietów niż może zostać wysłanych z drugiego interfejsu i w
konsekwencji pewna ilość danych zostaje stracona. Takie krytyczne miejsca w sieci nazywa
się często potocznie „wąskimi gardłami” a w literaturze anglojęzycznej „bottleneck”.
8
Opóźnienie (ang. Delay)
Oznacza czas w jakim pakiety wędrują pomiędzy dwoma wyznaczonymi węzłami sieci, czyli
czas przez jaki pakiet znajduje się w sieci zanim dotrze do punktu przeznaczenia. Parametr
ten jest szczególnie istotny dla aplikacji interaktywnych taki jak Telnet, a także służących do
transmisji głosu np. w telefonii IP czy wideokonferencjach.
Opóźnienia pojawiają się przede wszystkim, gdy pakiety oczekują na obsługę wewnątrz
kolejek napotykanych na swej drodze routerów.
Polepszenie tego wskaźnika może być dość łatwo uzyskana w sieciach opartych o ATM,
trudniej o nie w sieciach pakietowych.
Zmienność opóźnienia (ang. Jitter)
Ten parametr jest równie ważny jak samo opóźnienie szczególnie dla transmisji o charakterze
izochronicznym czyli np. przekazach multimedialnych.
Główną przyczyną powstawania zmienności opóźnień przy transmitowaniu pakietów jest
przechowywanie ich w kolejkach routerów. Gdy kolejki te są puste wówczas router przesyła
pakiety natychmiast. Przy zapełnianiu się kolejek opóźnienia rosną. Wzrosty opóźnień są
szczególnie zauważalne dla długich kolejek, jednak ustalanie zbyt krótkich buforów może
prowadzić do zwiększenia współczynnika gubienia pakietów.
Zmienność opóźnienia jest też konsekwencją faktu, że pakiety mogą przechodzić przez sieć
różnymi drogami, a tak zawsze może się zdarzyć gdy topologia sieci pozwala połączyć w niej
dwa punkty różnymi ścieżkami. W konsekwencji istnieje możliwość, że w docelowym węźle
sieci, paczki przesyłanych danych zostaną odebrane w innych odstępach czasu, niż zostały
wysłane lub nawet w niewłaściwej kolejności.
Częściowo tego typu niedogodność może zostać złagodzona poprzez stosowanie protokołów
połączeniowych jak np. TCP, które naprawią wszelkie błędy transmisji wynikające z
zaburzenia kolejności pakietów, ale niestety tego rodzaju połączeniowe rozwiązanie nie zdaje
egzaminu przy transmisjach multimedialnych, które wymagają tylko aktualnych danych a
wszelkie ponowienia transmisji są dla nich bezużyteczne.
9
1.2 Zakres zastosowania
Największy stopień jakości usług otrzymuje się, gdy ma się do czynienia z niepodzielonym
łączem komunikacyjnym, tzn. w przypadku gdy dwa komputery połączone są pojedynczym
przewodem i tylko one dwa transmitują przez niego dane. Przykładowo sieć na bazie
Ethernetu z przełącznikiem, w której do jednego portu tego przełącznika podłączony jest
pojedynczy komputer, charakteryzuje się bardzo wysokim poziomem QoS. Tutaj sytuacja gdy
dwa komputery konkurują ze sobą o dostęp do łącza występuje tylko przy wymianie
informacji miedzy nimi dwoma, a gdy łącze jest typu Full Duplex, czyli dwukierunkowego,
nie ma nawet takiej rywalizacji.
Zagadnienie spadku jakości usług daje o sobie znać dopiero w momencie gdy dwóch lub
więcej użytkowników musi dzielić ten sam kanał komunikacji. Może ono zostać dodatkowo
spotęgowane niską wydajnością sprzętu sieciowego, który nie może obsłużyć zbyt nasilonego
ruchu i wówczas pojawiają się opóźnienia, a także przekroczenia rozmiarów buforów. Akurat
problem niewydajnego sprzętu w obecnych czasach nie jest bardzo trudny do rozwiązania
ponieważ na rynku stale pojawiają się nowe urządzenia o coraz bardziej wyśrubowanych
parametrach, a ich ceny ciągle maleją.
Dużo poważniejsze przeszkody przy zapewnianiu gwarantowanej jakości usług pojawiają się
gdy odległości pomiędzy komputerami osiągają rozmiary rzędu kilku tysięcy kilometrów jak
np. przy łączach satelitarnych czy międzypaństwowych.
Także i w krótszych połączeniach radiowych, dla których dużą rolę w jakości połączeń
odgrywają warunki pogodowe nie są łatwym teatrem działań dla specjalistów od QoS.
Parametry jakości transmisji danych obniżają się również w przypadku zatłoczenia sieci przez
pakiety. W takich przypadkach protokoły, które prowadzą transmisję niejednokrotnie
próbując ratować sytuację i ponawiając transmisje pakietów, dodatkowo pogarszają ten stan.
Jako proste panaceum na wyżej wymienione problemy od razu na myśl przychodzi dołożenie
dodatkowych mega- czy gigabitów przepustowości. Przeważnie jest to rozwiązanie dobre i
tanie. Szczególnie tyczy się to poprawiania parametrów sieci lokalnych, których jesteśmy
właścicielami. Jednak sytuacje, kiedy wymiana kabli jest dość kłopotliwa i wymaga
przedsięwzięcia na wysoką skalę – tak jest w przypadku sieci WAN – lub gdy po prostu nie
należą one do nas samych, są polem działania strategii Quality of Service.
10
Jednym słowem wszędzie tam gdzie polepszenie jakości połączenia nie jest proste do
zapewnienia, przez oczywiste dokładanie przepustowości, implementacja mechanizmów QoS
jest konieczna, a w miejscach, w których o dodatkową przepustowość jest łatwo, warto jednak
zadbać o QoS.
1.3 Mechanizmy Quality of Service
W celu zniwelowania spadku poziomu jakości usług dostarczanych przez sieć komputerową
stosuje się kilka standardowych technik. Poniżej wymieniono najogólniejsze i najbardziej
znane, które najczęściej pojawiają się w opracowaniach dotyczących gwarantowania jakości
usług.
Zapobieganie zatorom (ang. Congestion management)
Jest kluczowym elementem QoS. Oznacza zbiór czynności jakie wykonuje węzeł sieci przy
napotkaniu przeciążenia, a także umożliwiających jego uniknięcie. Podstawą radzenia sobie z
przeciążeniami jest umiejętne i celowe odrzucanie pakietów pojawiających się na interfejsie
wejściowym urządzenia przy wystąpieniu zatoru lub w chwili tuż przed utworzeniem się
zatoru. Wówczas węzeł wysyłający pakiety może zwolnić trochę transmisję. W przypadku
protokołu TCP, dodatkowo można oprócz gubienia pakietów, które jest dość nieefektywne,
posłużyć się polem w pakiecie TCP określającym szerokość okna transmisji, czyli liczbę
wysyłanych bez potwierdzenia pakietów. Taki mechanizm wymaga jednak współdziałania
wszystkich węzłów sieci, w jakich istnieje potrzeba polepszenia parametrów przesyłania
danych i jest możliwy do implementacji w sieciach, do których mamy pełen dostęp. Więcej o
protokole TCP można przeczytać w dokumentach [RFC-0793], [RFC-1072], [RFC-1146],
[RFC-1693] oraz późniejszych.
Algorytmem, który usprawnia zapobieganie przeciążeniom jest RED (ang. Random Early
Discard). Pozwala on na wcześniejsze odrzucanie pakietów, gdy bufory węzła sieci nie są
jeszcze przepełnione, dzięki czemu statystycznie gubiona jest mniejsza ilość pakietów. Jednak
główną zasadą zapobiegania przeciążeniu jest wciąż nieprzyjemne odrzucanie prawidłowych
pakietów. Więcej o RED można przeczytać w [ICSI].
Radą dla tej przykrej konieczności może być algorytm ECN (ang. Explicit Congestion
Notification), czyli mechanizm kontroli przeciążeń między dwoma punktami sieci, który w
chwili napotkania przeciążenia znakuje przekazywane pakiety odpowiednim bitem. Bit ten
11
powoduje, że docelowy odbiorca pakietu nakazuje zwolnić nadajnikowi. Algorytm ECN
wymaga jednak pewnego przystosowania urządzeń i protokołów sieciowych (np. IP).
Dokładną specyfikacja tego mechanizmu znajduje się w dokumencie [RFC-3168].
Niestety wyżej opisany schemat postępowania nie jest wystarczający z punktu widzenia
zapewniania jakości usług. Spowodowane jest to tym, że poprawę działania sieci osiągamy
tylko do czasu wystąpienia następnego przeciążenia, ponieważ po pewnym czasie nadajnik
zwiększy natężenie swojej transmisji i sytuacja będzie powtarzać się cyklicznie.
Więcej o technikach zapobiegania zatorom można znaleźć w źródle [ICSI].
Kształtowanie ruchu (ang. Traffic shaping)
Mechanizm kształtowania ruchu jest głównym tematem niniejszej pracy. Metoda ta również
zapobiegającą powstawaniu zatorów. Jej zadanie opera się o wygładzanie ruchu, który
wypływa z węzła do sieci, przez co odbiorca transmisji nie zostanie zalany zbyt dużą ilością
docierających do niego pakietów.
U podstaw kształtowania ruchu leży wykorzystanie kolejki, do której pakiety mogą napływać
w dowolnej częstotliwości, jednak wyprowadzane są z niej w sposób równomierny, ze stałym
natężeniem.
Tworząc reguły kształtowania ruchu można także określać pewien nadmiar pakietów jakie są
wysyłane z kolejki przez kilka początkowych chwil transmisji. Takie działanie jest
szczególnie przydatne przy transmisjach krótkotrwałych o dużym nasileniu (ang. bursty), jak
np. ruch generowany przez protokół HTTP. W protokole tym bowiem żądania i odpowiedzi
pomiędzy komputerami wysyłane są stosunkowo rzadko ale niosą dość dużą ilość informacji.
Na przykład otwierając jakąś stronę internetową zlecamy jej załadowanie do przeglądarki w
naszym komputerze. Wtedy dane zostają przesyłane i proces ten zabiera pewną nadwyżkową
część przepustowości. Następnie kiedy czytamy zawartość strony żadne informacje nie są
przesyłane, a więc na korzyść naszej transmisji powstaje pewien deficyt przepustowości,
który możemy po chwili znowu wykorzystać szybciej otwierając kolejną stronę.
Poprawne ze względów QoS kształtowanie ruchu wiąże się także nierozerwalnie z doborem
odpowiednich mechanizmów kolejkowania i klasyfikowania przepływów.
12
Klasyfikowanie i kolejkowanie (ang. Classification and queuing)
Ten sposób implementacji Quality of Service grupuje pakiety w oparciu o różnego typu
reguły i kryteria, którymi mogą być: adresy źródłowy i docelowy, numery portów itp..
Następnie każda z takich grup podlega pewnemu mechanizmowi ogólnie nazwanego
kolejkowaniem, który zazwyczaj jest dużo bardziej wymyślną strukturą niż przychodząca od
razu na myśl kolejka FIFO. W ostatnim etapie dane wybierane są z kolejek też w określonym
porządku, którego głównym założeniem jest jak najbardziej sprawiedliwy przydział
przepustowości łącza poszczególnym przepływom.
Wszystkie tego typu sposoby postępowania z danymi oparte są o dwie podstawowe
architektury: klasową i bezklasową.
Kolejki bezklasowe czyli np. zwykła kolejka FIFO, kolejka priorytetowa, czy różnego typu
kolejki sprawiedliwe: stochastyczne, ważone i karuzelowe w większości żądzą się własnymi
regułami przyporządkowywania pakietów i nie mają zbyt wygórowanych wymagań jeśli
chodzi o ich konfigurację. Taka prostota obsługi jest także poniekąd ich wadą.
Niedogodności niskiej konfigurowalności nie posiadają natomiast kolejki klasowe. Są one
dużo bardziej rozbudowane, ponieważ umożliwiają tworzenie hierarchii klas o różnych
parametrach, z których głównym pozostaje przydzielona przepustowość. Klasowe wersje
kolejek stanowią obecnie podstawę działanie wszelkich urządzeń mających zapewnić
optymalne parametry jakości usług w sieciach. Dodatkowo tworzone klasy potrafią korzystać
z mechanizmów bezklasowych, a więc mogą być użyte w sposób niezmiernie elastyczny.
Ponieważ podstawowe mechanizmy kolejkowania łączą się nieodzownie z tematem tego
opracowania czyli kształtowaniem ruchu w sieciach komputerowych, zostały omówione
szczegółowo w osobnym rozdziale.
Techniki rezerwowania łącza (ang. Bandwidth reservation)
Techniki te są realizowane przez zastosowanie dodatkowych protokołów takich jak np. RSVP
[RFC-2205], działający na routerach serwisów zintegrowanych (IntServ), omówionych w
dokumencie [RFC-1633]. Protokoły te potrafią „zamówić” u poszczególnych węzłów sieci
przez który ma być prowadzona transmisja pewne poziomy wymaganych parametrów łącza.
Niestety technika ta jest trudna do zaimplementowana w sieci Internet, gdyż nie jest wiadome
czy wszystkie węzły sieci zgodzą się dokonać taką rezerwację.
13
Znakowanie pakietów (ang. Packet tagging/Label switching)
Do pakietów dodawane są specjalne znaczniki, które pozwalają na określenie drogi pakietów
w sieci pomiędzy poszczególnymi przełącznikami. Znaczniki takie mogą być umieszczane w
ramkach protokołów warstwy drugiej jak w przypadku standardu IEEE 802.1p lub w
warstwie trzeciej w polu Type of Service pakietu protokołu IP ([RFC-0791]) dla metody
serwisów zróżnicowanych ([RFC-2475]). Metody tego typu definiują zazwyczaj priorytet i
sposób w jakim urządzenia sieciowe mają traktować określoną paczkę z danymi.
Kolejną technologią, o której warto w tym miejscu wspomnieć jest Multiprotocol Label
Switching. Pozwala ona na dołączanie do pakietów w sieciach IP, ATM lub FrameRelay
pewnych znaczników Label Switched Paths, pozwalających jednokrotnie i dokładnie określić
ścieżkę, po jakiej dany pakiet będzie przesyłany poprzez sieć. Więcej informacji o protokole
MPLS znajduje się w źródłach [RFC-3031] oraz [PROT].
Tego rodzaju postępowanie z pakietami w wymienionych przykładowych technikach pozwala
poszczególnym węzłom sieci na łatwiejsze rozpoznawanie pakietów, bez wgłębiania się w
inne ich parametry, a znakowanie pakietów odbywa się tylko jednokrotnie w obrębie danej
sieci.
1.4 Zalety i wady kształtowania ruchu
Poniżej przedstawiono najważniejsze wady i zalety kształtowania ruchu w sieciach
komputerowych. Więcej informacji dotyczących tego podrozdziału można znaleźć na
stronach firmy Packeteer [PACK] – producenta urządzeń kształtujących ruch oraz stronie
organizacji Bussines Communications Review [BCS] (szczególnie artykuł David’a
Passmore’a „The Big vs. Managed Bandwidth Debate” z 1998r.).
Zalety
Oszczędności
Wprowadzenie w sieci komputerowej kształtowania ruchu na dłuższą metę pozwala
zaoszczędzić wydatki, które spowodowane byłyby inwestowaniem w zwiększenie dostępnej
przepustowości.
14
Według badań organizacji Gartner [GART] ruch w cieciach komputerowych przedsiębiorstw
do roku 2005 wzrośnie od 14 do 16 razy w stosunku do roku 2002. Dodatkowo koszty
przepustowości podniosą się o 7 procent. Do roku 2010 koszty związane z rozbudową sieci
wzrosną od 5 do 10 procent. Te dane jednoznacznie wskazują, że stosowanie tylko prostej
metody dokładania przepustowości, jako środka zapobiegawczego na powstawanie zatorów w
sieci nie jest rozsądną drogą.
Zwiększenie wydajności sieci
Ponieważ zastosowanie technik kształtowania ruchu zapobiega powstawaniu zatorów w sieci,
to w konsekwencji daje wyraźną poprawę działania aplikacji. To stwierdzenie szczególnie
dotyczy wrażliwych na opóźnienia transmisji multimedialnych.
Bez stosowania tej techniki, bez względu na to jak dużo przepustowości byłoby dostępne w
sieci, rywalizowanie poszczególnych transmisji o zasoby miałoby tylko charakter „best
efford” czyli kto „pierwszy ten lepszy”. Takie podejście nie daje natomiast żadnych
gwarancji, że usługi o specyficznych wymaganiach jak aplikacje interaktywne będą działały
wydajnie.
Dodatkowe możliwości kontroli
Dzięki zastosowaniu kształtowania ruchu, organy zarządzające infrastrukturą sieci otrzymują
nowe narządzie o dużych możliwościach, dzięki któremu możliwe jest odgórne i dokładne
rozdysponowanie zasobów jakimi sieć dysponuje. Jest to szczególnie istotne gdy jedna sieć
fizyczna jest współdzielona przez kilka pododdziałów o zróżnicowanym wpływie na
prowadzoną działalność przedsiębiorstwa. Taka polityka umożliwia przeznaczenie większej
części przepustowości sieci dla użytkowników, którym jest ona niezbędna.
Bardziej sprawiedliwe rozdysponowanie zasobów
W sytuacji kiedy wielu użytkowników współdzieli dane połączenie sieciowe, bardzo ważne
jest zastosowanie reguł które umożliwią im równy dostęp do zasobów sieci. Nie może mieć
miejsca okoliczność, gdy jedna osoba zajmuje całą dostępną przepustowość, która pierwotnie
miała być rozdysponowana między większą ilość użytkowników sieci.
15
Przykładowo osoba taka może pobierać z Internetu duży plik, co utrudni lub w skrajnym
przypadku uniemożliwi pozostałym prowadzenie nawet mało wymagających transmisji. Taka
sytuacja jest niezmiernie prawdopodobna jeśli nie zostanie zastosowane kształtowanie ruchu.
Poniższy przykład ilustruje jak pojedynczy użytkownik stosując aplikacje charakteryzujące
się dużym zapotrzebowaniem na przepustowość zajmuje większą część łącza.
Rysunek 1 Niesprawiedliwy dostęp do łącza.
W powyższym przykładzie zastosowanie urządzenia kształtującego ruch zaraz za węzłem
łączącym sieć lokalną z Internetem, pozwoliłoby na zapewnienie poszczególnym
użytkownikom równego dostępu do łącza.
Wzrost poziomu wiedzy o działaniu sieci
Z zainstalowaniem urządzeń i oprogramowania związanych z kształtowaniem ruchu w sieci
związane są też nierozłącznie narzędzia umożliwiające monitorowanie jej wydajności. Wielu
producentów sprzętu do tego rodzaju zastosowań ma w swojej ofercie szeroki wachlarz
aplikacji o dużych możliwościach administracyjnych i kontrolnych. Pozwala to spojrzeć na
zagadnienia administracyjne i całą sieć pod trochę odmiennym kątem i poznać jej dodatkowe
właściwości.
Prowadzenie takiej diagnostyki pozwala także wyeliminować pewne aplikacje zakłócające
pracę sieci lub obniżające jej wydajność. Bez takiej wiedzy osoba zarządzająca siecią
mogłaby podejmować niewłaściwe decyzje np. o niepotrzebnej i kosztownej rozbudowie w
przypadku częstego występowania zatorów.
16
Poprawa działania szczególnie ważnych aplikacji
Stosowanie określonych algorytmów i reguł kształtowania ruchu umożliwia zagwarantowanie
pewnych części dostępnego łącza dla aplikacji szczególnie ważnych dla misji
przedsiębiorstwa. Jest to bardzo istotne zagadnienie w organizacji pracy wielu firm. Zdarza
się bowiem bardzo często, że użytkownicy oprócz pracy z firmowymi aplikacjami, korzystają
również z innych produktów, które zajmują dużą część przepustowości. Dotyczy to przede
wszystkim aplikacji służących do słuchania muzyki przez Internet np. RealPlayer, czy też
pobierania dużych plików jak Kazaa i Emule.
Poniższy rysunek pokazuje jak kształtowanie ruchu może wpłynąć na proporcje w jakich
poszczególnym grupom aplikacji przydzielona została przepustowość w skali całego łącza:
Rysunek 2 Poprawa działania aplikacji kluczowych dla misji przedsiębiorstwa
Większa wymierność finansowa poziomu usług
Zarządzanie zasadami przydzielania użytkownikom przepustowości, w ogromnej mierze
usprawnia sposób, w jakim można pobierać od nich opłaty za tego typu usługi. Umożliwia to
wprowadzenie kilku poziomów usług o różnej dostępnej przepustowości i cenie. Ta cecha
przydaje się przede wszystkim dostawcom internetowym i dzięki niej mogą oni zróżnicować
swoją ofertę.
Wady
Większa złożoność sieci
Zarządzanie siecią komputerową przy wprowadzeniu mechanizmów Quality of Service, a w
szczególności kształtowania przepustowości wiąże się z pojawieniem się wielu dodatkowych
17
elementów, z którymi administrator sieci musi się zapoznać. Elementami tymi mogą być
routery i przełączniki z możliwością zarządzania przepustowością lub specjalistyczne
urządzenia przeznaczone wyłącznie do tego celu tzw. „traffic shapers”. Brak znajomości
zasad ich działania, lub nie do końca dokładne zrozumienie mechanizmów rządzących
kształtowaniem ruchu, może doprowadzić nawet do spadku wydajności sieci zamiast ją
poprawić.
Dodatkowe koszty
Tą niekorzystną cechę wprowadzenia kształtowania ruchu w sieci komputerowej można
podzielić na dwa zasadnicze aspekty.
Pierwszy z nich wiąże się z koniecznością zakupu dodatkowych urządzeń i oprogramowania,
które umożliwiają wprowadzenie tej technologii. Częstokroć oferowany przez dostawców
sprzęt sieciowy wyposażony jest w funkcje, które działają dopiero jeśli cała sieć zbudowana
jest tylko w oparciu o produkty tego jednego producenta.
Drugi niekorzystny aspekt polega na potrzebie zatrudnienia wyspecjalizowanego personelu
potrafiącego obsługiwać skomplikowane techniki kształtowania ruchu.
Problemy organizacyjne
Poza wzrostem kosztów lub problemami technicznymi zarządzanie przepustowością ciągle
może powodować duże dylematy wśród osób zarządzających siecią z powodów
organizacyjnych. W odróżnieniu od strategii stawiającej na proste zwiększanie
przepustowości, przy zachowaniu dla wszystkich użytkowników równych praw w dostępie do
łącza, techniki związane z kształtowaniem przepustowości wymagają jawnego przypisania
użytkowników bądź aplikacji do pewnych grup o odmiennym traktowaniu.
W jaki sposób administrator sieci czy ktokolwiek inny może określić kto zostanie bardziej lub
mniej uprzywilejowany przy dostępie do łącza? Jak wiele klas usług należy utworzyć i jak
przypisać do nich użytkowników i aplikacje?
Poza tym z wprowadzeniem kształtowania ruchu w sieci wiąże się dodatkowa konieczność
sprawdzania poprawności wprowadzonych konfiguracji i pomiarów wydajności. Firmy, które
zdecydują się na wprowadzenie zarządzania przepustowością w swojej sieci, mogą w końcu
dojść do wniosku, że wymaga to od nich wprowadzenia dodatkowych, często niechcianych
przedsięwzięć.
18
Zwiększone ryzyko awarii
Niejednokrotnie zaawansowane funkcje urządzeń, które nie zostaną do końca zrozumiane
przez administratorów sieci, mogą pogorszyć funkcjonowanie aplikacji krytycznych dla
działalności firmy. To stanowi duże ryzyko dla organów zarządzających firmą i musi zostać
dokładnie rozważone przed decyzją o implementacji kształtowania przepustowości w sieci
przedsiębiorstwa.
Utrudnienia przy rozwiązywaniu problemów z siecią
Uruchomienie kształtowania ruchu w sieci komputerowej jest dodatkowym potencjalnym
czynnikiem, który może powodować jej złe działanie. Ten fakt prowadzi do spowolnienia
czynności mających na celu znalezienie przyczyny niewłaściwego funkcjonowania sieci.
Trudności z zastosowaniem w Internecie
Mechanizm kształtowania ruchu jest trudny do wprowadzenia w sieciach, które wykorzystują
Internet, jako ogniwo łączące pewne ich części. Jest to szczególnie widoczne, gdy ruch
pakietów ma być prowadzony poprzez kilka węzłów należących do różnych dostawców. Żeby
kształtowanie ruchu mogło poprawnie funkcjonować w takiej infrastrukturze konieczne jest
porozumienie pomiędzy takimi dostawcami i podobna konfiguracja zaangażowanych w
transmisję urządzeń. Obecnie jednak powstaje szereg rozwiązań pozwalających
wyeliminować taką niedogodność o czym więcej w części trzeciej niniejszej pracy.
Doświadczenia historyczne
Powszechnie wiadomo, że najlepiej przyjmują się technologie proste, którymi łatwo
zarządzać. Przedsiębiorstwa niechętnie podchodzą do sieci, które wymagają zwiększonych
czynności administracyjnych.
Istnieje wiele przykładów z historii sieci komputerowych jak technologia ATM, która mimo
swoich wielu zalet i cech wspierających Quality of Service, nie zyskała tak dużej
popularności wśród użytkowników jak produkty prostsze oparte np. na protokole Ethernet.
19
Rozdział 2 Algorytmy kształtowania ruchu
2.1 Algorytmy kolejkowania
Algorytmy kolejkowania są podstawowymi mechanizmami kształtowania ruchu w sieciach
komputerowych. Umożliwiają bowiem utworzenie pewnych kategorii przepływu danych, do
których można zastosować określone reguły dostępu do łącza. Poniżej przedstawiono
najważniejsze z algorytmów kolejkowania.
Kolejkowanie priorytetowe
Algorytmy kolejkowania priorytetowego tworzą wiele kolejek dla każdego interfejsu
sieciowego i każdej z takich kolejek przypisują odpowiedni priorytet. Urządzenia
korzystające z kolejek priorytetowych najpierw decydują, do których kolejek przypisać jaki
rodzaj ruchu poprzez sprawdzanie pewnych reguł skonfigurowanych wcześniej. Następnie
algorytm przepuszcza jako pierwsze pakiety pochodzące z kolejek o wysokim priorytecie, a
dopiero kiedy kolejki te zostaną opróżnione, obsługuje kolejno bufory o niższych
priorytetach. Oznacza to, że pewne przepływy będą lepiej traktowane od innych.
Taki typ kolejkowania jest oczywiście lepszym rozwiązaniem przy zapewnianiu
zróżnicowanego poziomu obsługi dla różnych typów ruchu niż zwykłe kolejki FIFO.
Jednakże kolejkowanie priorytetowe przeznacza dla bufora, który aktualnie obsługuje, całą
dostępną przepustowość łącza. Jest to oczywiście działanie niepożądane z punktu widzenia
Quality of Service
Potencjalnym rezultatem takiego postępowania jest to, że kolejkowanie priorytetowe może
doprowadzić do całkowitego zatrzymania ruchu o niższym priorytecie. Taki scenariusz jest
20
szczególnie prawdopodobny gdy algorytm ten jest jedyną stosowaną metodą kolejkowania w
danym urządzeniu. Nie jest zatem zaskakujące, że omawiany typ kolejkowania używany jest
w połączeniu z innymi technikami jak: ważonym sprawiedliwym kolejkowaniem, czy
sterowaniem szerokością okna transmisji w protokole TCP.
Kolejkowanie sprawiedliwe
SFQ (ang. Stochastic Fairness Queuing)
Ten rodzaj sprawiedliwego kolejkowania tworzy po jednej kolejce FIFO dla każdego
przepływu danych. Powstałe przepływy nazywane są konwersacjami i grupują pakiety ze
względu na adresy źródłowe i docelowe oraz typy używanych protokołów.
Proces grupowania odbywa się przy pomocy funkcji haszującej, która na podstawie
wybranych parametrów pakietu generuje dla niego numer kolejki. Nadany w ten sposób
identyfikator grupy powinien być w miarę możliwości unikalny, jednak ponieważ liczba
kolejek jest skończona i relatywnie nieduża, to może się zdarzyć, że kilka konwersacji będzie
dzielić tę samą kolejkę.
Poszczególne kolejki przechowujące każdą z konwersacji obsługiwane są w porządku
karuzelowym (ang. round robin) tzn. pakiety opuszczają bufory kolejno i cyklicznie. Oznacza
to, że kolejkowanie stochastyczne jest sprawiedliwe, jedynie gdy wszystkie pakiety mają
podobną długość.
Sytuacja, w której dwa przepływy dzielą jedną kolejkę jest niepożądana, ponieważ
zmniejszeniu ulega wówczas czas dostępu do łącza dla każdego z nich. Problem ten został
rozwiązany poprzez losowe zmiany algorytmu funkcji haszującej co pewien okres, co
zapewnia, że niekorzystne przypisywanie numerów kolejek do przepływów będzie miało
miejsce przez krótką chwilę.
Więcej o SFQ można przeczytać w artykule [SFQ91].
WFQ (ang. Weighted Fairness Queuing)
Ważone sprawiedliwe kolejkowanie podobnie jak kolejkowanie priorytetowe tworzy wiele
kolejek dla różnych typów ruchu. Powiązanie pomiędzy kolejkami i przepływami otrzymuje
się poprzez zastosowanie pewnych ustalonych kryteriów. Również do każdej z kolejek
przypisywana jest określona wartość priorytetu.
21
Oprócz tego każdej z kolejek nadawana jest też waga proporcjonalna to posiadanego
priorytetu. Przeznaczeniem wspomnianej wagi jest ustalenie jaka część dostępnej
przepustowości przypadnie dla danej kolejki. Inaczej mówiąc wagi kolejek gwarantują, że
bufory o wyższych priorytetach będą mogły wykorzystać więcej przepustowości niż bufory o
niskich priorytetach.
Opróżnianie kolejek odbywa się przy zastosowaniu algorytmu „Bit-by-bit Round-robin”,
który cyklicznie wybiera z każdej kolejki po jednym bicie. Pakiet zostaje wysłany gdy ostatni
jego bit opuści bufor. Zapewnia to sprawiedliwość kolejki dla pakietów o różnych
długościach.
Dokładna ilość przepustowości jaką każda kolejka otrzymuje, jest jednak zależna od liczby
kolejek, które w tym samym czasie korzystają z łącza i nie może być dokładnie określona.
Przykładowo mając trzy kolejki o wysokim priorytecie i dwie o niskim, w sytuacji gdy
pakiety oczekują na wysłanie w jednej kolejce o wysokim priorytecie i w dwóch o niskim,
wówczas kolejka o wysokim priorytecie otrzyma połowę dostępnej przepustowości, a
pozostałe dwa bufory po jednej czwartej. Jeśli zaś pakiety pojawią się tylko w trzech
kolejkach o wysokim priorytecie, to każda z tych kolejek będzie mogła wykorzystać po jednej
trzeciej dostępnej przepustowości.
Powyższy przykład ilustruje, że ważone kolejkowanie priorytetowe zapewnia każdej klasie
ruchu dostęp do łącza, ale nie gwarantuje określonej przepustowości.
Algorytm „Deficit Round Robin”
Algorytm „Deficit Round Robin” umożliwia sprawiedliwe kolejkowanie pakietów
pochodzących z wielu różnych przepływów. Przepływy takie reprezentują kolejki FIFO, w
których przechowywane są pakiety i mogą oznaczać np. klasy w algorytmie „hierarchicznego
wiadra z żetonami”.
Ponieważ DRR jest typem algorytmu karuzelowego, to poszczególne przepływy obsługiwane
są cykliczne. Istotny jest jednak sposób, w jaki kolejne przepływy otrzymują prawo do
wysyłania.
Transmitowanie po jednym pakiecie z każdego przepływu mogłoby spowodować
niesprawiedliwe zwiększenie się czasu oczekiwania na wysłanie w kolejkach
przechowujących krótsze pakiety. Jest do zjawisko niepożądane z punktu widzenia Quality of
Service.
22
Zmniejszenie takiego niekorzystnego efektu uzyskuje się, poprzez przyznanie każdemu
przepływowi pewnej kumulującej się puli bajtów, które może on wysłać podczas jednego
obiegu algorytmu. Za każdym razem kiedy algorytm wybiera następną kolejkę do wysyłania,
otrzymuje ona dodatkową część tej puli, nazywaną kwantem. Dla poszczególnych kolejek
kwanty mogą mieć różną wielkość zależną od charakteru danego przepływu. Po wysłaniu
pakietu przeznaczona na ten cel część puli bajtów zostaje odebrana kolejce. Pozostała zaś
część nazywana jest deficytem i pozostaje w kolejce do następnej wysyłki.
Poniższy rysunek przedstawia przykład działania algorytmu DRR. Na rysunku widać, że z
każdą kolejką powiązane są osobne liczniki deficytu oraz wartości kwantu. Zmienna DRRptr
wskazuje na kolejkę, która aktualnie może wysyłać pakiety.
Rysunek 3 Algorytm DRR – krok 1
Na początku pojedynczego etapu wartość licznika deficytu inkrementowana jest o wartość
kwantu. W zamieszczonym przykładzie jest to 500 bajtów. Następnie algorytm sprawdza czy
wartość licznika deficytu jest większa od wielkości pakietu. W tym przypadku pakiet ma 200
bajtów, a więc może zostać wysłany. Jego długość odejmowana jest od licznika deficytu,
który przyjmuje wartość 300. Wskaźnik DRRptr pozostaje nieruchomy.
Kolejna próba wysłania pakietu z pierwszej kolejki kończy się jednak niepowodzeniem, gdyż
rozmiar pakietu wynoszący 750 bajtów przekracza wielkość deficytu (300). Powoduje to, że
wskaźnik DRRptr przechodzi do następnej kolejki. Ta sytuacja przedstawiona została na
poniższym rysunku.
23
Rysunek 4 Algorytm DRR – krok 2
Można tu zauważyć, że z kolejki drugiej w następnym kroku nie zostanie wysłany żaden
pakiet. Nie pozwala na to bowiem zbyt niski poziom deficytu (400). Bufor ten będzie mógł
zostać opróżniony dopiero gdy algorytm wykona pełny obieg po wszystkich kolejkach.
Po obsłużeniu wszystkich kolejek, wskaźnik DRRptr przechodzi z powrotem do kolejki
pierwszej.
W omawianym algorytmie najistotniejszym faktem jest to, że wartość deficytu
inkrementowana jest przy przechodzeniu pomiędzy kolejnymi kolejkami, tzn. gdy zostanie on
wyczerpany, a nie przy próbie wysłania pakietu.
Algorytm DRR został opisany w artykule [DRR95].
Kolejki klasowe
Kolejki klasowe są najbardziej rozbudowanymi mechanizmami kolejkowania. Umożliwiają
bowiem tworzenie pewnych klas ruchu, pomiędzy którymi istnieją zależności hierarchiczne.
Poszczególne klasy grupują pakiety w oparciu o różnego typu kryteria, którymi mogą być
adresy warstwy sieciowej, numery portów warstwy transportowej, typy aplikacji przez jakie
zostały wygenerowane oraz inne. Każdej klasie przypisywana jest też przeznaczona dla niej
przepustowość. Klasy potomne mogą dziedziczyć przepustowość od swoich przodków, a
także pożyczać ją pomiędzy sobą. Dodatkowo każda klasa ruchu może posługiwać się
własnym algorytmem kolejkowania bezklasowego, przykładowo którymś z wymienionych
powyżej.
Takie cechy kolejek klasowych zapewniają dużą elastyczność przy tworzeniu reguł na
przydzielanie przepustowości. To sprawia, że obecnie stają się one największym obiektem
zainteresowań producentów sprzętu potrafiącego zarządzać przepustowością.
24
Spośród kolejek klasowych należy wymienić przede wszystkim: CBQ (ang. Class Based
Queuing), H-PFQ (ang. Hierarchical Packet Fair Queueing) omówiony w [HPFQ96] oraz
HTB (ang. Hierarchical Token Bucket) opisany w [DEVIK].
Ponieważ do praktycznej realizacji kształtowania ruchu został wybrany algorytm HTB, to
omówiono go dokładnie osobnym rozdziale – „Hierarchiczne wiadro z żetonami”. Informacje
dotyczące pozostałych algorytmów można znaleźć w źródłach: [HPFQ], [ICSI].
2.2 Manipulowanie rozmiarem okna TCP
Aby zrozumieć zasadę działanie tego mechanizmu, należy w pierwszej kolejności poznać
kilka szczegółów dotyczących transmisji w protokole TCP. Urządzenia komunikujące się
poprzez ten protokół wysyłają pakiety określane często skrótem ACK, które oznaczają
potwierdzenie odebrania danych. Takie pakiety potwierdzające zawierają także wielkość
nazywaną szerokością okna. Informuje ona nadajnik jaką ilość danych może wysłać zanim
odbierze potwierdzenie ich otrzymania przez odbiornik. Przy wystąpieniu zatoru, kolejki
urządzeń wypełniają się i odrzucają pakiety. To sprawia, że rozmiar okna zostaje
automatycznie zmniejszony przez protokół i zator ustępuje. Problem pojawiają się jednak w
momencie, gdy strony transmisji znowu zaczynają zwiększać rozmiar okna i wysyłać coraz to
większe ilości danych. TCP wykorzystuje bowiem dostępną przepustowość dość agresywnie,
co doprowadza do występowania kolejnych zatorów.
Węzeł sieci, który znajduje się na drodze transmisji TCP może zwiększać lub zmniejszać
rozmiar okna. Taka cecha sprawia, że można próbować unikać „zapychania” łącza.
Urządzenia stosujące technikę dostosowywania rozmiaru okna przechwytują pakiety ACK i
ustawiają w nich własne wielkości w polu „window” pakietu.
Szczegóły mechanizmu potwierdzania i dostosowywania rozmiaru okna w protokole TCP
można odnaleźć w dokumencie [RFC-0813] .
2.3 Idea „cieknącego wiadra” i „wiadra z żetonami”
Algorytmy „cieknącego wiadra” oraz „wiadra z żetonami” używane są do kontroli zajętości
przepustowości w sieci komputerowej. Umożliwiają nałożenie ograniczeń na prędkość z jaką
pakiety są transmitowane w jednostkach danych na sekundę.
25
Stosuje się je przy wyprowadzaniu pakietów z kolejek. Oznacza to, że algorytmy te nie są
same w sobie algorytmami kolejkowania, ale służą do pewnego zaplanowania procesu
wysyłania pakietów.
Pozwalają dokładnie określić jaką część łącza otrzyma dany przepływ informacji, do którego
zostały zastosowane. Ich implementacjom przyświecają dwa nieco odmienne podejścia do
ograniczania przepływów, co zostało dokładnie omówione poniżej.
Przedstawiane algorytmy w poniższych opisach nazywane są także funkcjami kształtującymi
przepływ.
„Cieknące wiadro” (ang. Leaky bucket)
Parametrami algorytmu są: wielkość bufora – „wiadra” – oraz liczba danych jakie opuszczają
bufor w jednostce czasu podana w bajtach lub bitach na sekundę.
Algorytm ten umożliwia dokładne określenie z jaką częstością dane będą pobierane z kolejek
i przesyłane przez sieć. Natężenie przepływu danych objętego taką strategią charakteryzuje
się płaskim przebiegiem. Gwarantuje to zabezpieczenie przed wystąpieniem przeciążenia w
docelowym dla interfejsu który stosuje kształtowanie ruchu węźle sieci.
Podstawę działania „cieknącego wiadra” stanowi pojedynczy bufor – kolejka FIFO
gromadząca pakiety. Posiada określoną maksymalną długość. Jednym z najistotniejszych
faktów jest to, że elementami, które podlegają buforowaniu są właśnie pakiety, a nie żetony,
jak w przypadku drugiego z omawianych algorytmów.
Element algorytmu planujący wysyłanie pakietów wybiera je z kolejki przy zachowaniu
zasady, że zawierana przez pakiety liczba bajtów, która została wysłana w jednostce czasu
jest stała i ściśle zdefiniowana jako parametr całej procedury. Takie postępowanie gwarantuje,
że chociaż na wejściu funkcji kształtującej przepływ pakiety pojawiają się w różnych
odstępach czasu i czasami maksymalna przepustowość jest przekroczona, to wyjście ma stałe
i określone natężenie.
26
Poniższy rysunek ilustruje w schematyczny sposób działanie algorytmu i jego analogię do
rzeczywistego cieknącego wiadra.
Rysunek 5 Algorytm „cieknącego wiadra”
Dodatkowo należy wspomnieć, że pewne pakiety wchodzące do bufora mogą zostać
odrzucane na skutek ich przedawnienia lub przekroczenia rozmiaru samej kolejki. Wówczas
takie nadmiarowe pakiety muszą zostać odrzucone. Jednak zyskiwana jest pewność, że łącze,
w którym zastosowano kształtowanie ruchu nie będzie przeciążone.
Wadą tego algorytmu jest to, że nie pozwala on na chwilowe wzrosty natężenia ruchu zaraz
po jego rozpoczęciu. Taka właściwość jest pożądana gdy istnieje potrzeba szybkiego
przesłania większej liczby informacji, ale przez krótki okres czasu. Niedogodność tą niweluje
omówiony dalej algorytm „wiadra z żetonami”.
„Wiadro z żetonami” (ang. Token bucket)
Parametrami algorytmu są: maksymalna wielkość bufora – „wiadra” – który przechowuje
żetony oraz prędkość z jaką żetony są generowane. Dodatkowo przydatne jest określenie
jakiej liczbie wysyłanych danych odpowiada pojedynczy żeton. Dla ułatwienia można
przyjąć, że do wysłania pojedynczego bajta potrzebny jest jeden żeton.
Algorytm ten podobnie jak „cieknące wiadro” również umożliwia określenie z jakim
natężeniem dane będą wysyłane. Jednak w odróżnieniu od poprzednio omawianego, pozwala,
aby ruch wychodzący zmieniał się częściowo w zależności od stopnia nasilenia żądań
27
wysyłania pakietów. Jest to szczególnie istotne np. dla protokołu HTTP, który ma dość duże
zapotrzebowanie na przepustowość, jednak poszczególne transfery danych nie są bardzo
częste i wówczas przepustowość nie jest wykorzystywana w ogóle.
Na przykład podczas otwierania strony internetowej przesyłane są duże ilości informacji –
tekst, grafika, dane XML itp. – co powoduje, że aby przesłać pakiety żetony wybierane są z
„wiadra”. Po załadowaniu witryny użytkownik ją przegląda i w tym czasie nowe żetony z
powrotem zapełniają bufor, ponieważ chwilowo nic nie trzeba przesyłać. Następnie cały
proces się powtarza. Taki typ ruchu w sieci często nazywany jest w anglojęzycznej literaturze
„bursty” czyli wybuchowy.
Podstawą działania tego algorytmu jest bufor gromadzący żetony. Stanowi to również różnicę
w stosunku do algorytmu ”cieknącego wiadra”, ponieważ tam algorytm przechowywał
pakiety. Każdy taki żeton może przypominać bilet umożliwiający przesłanie pewnej porcji
danych (w najprostszym przypadku pojedynczego bajta). Po przesłaniu pakietu pewna ilość
wykorzystanych do tego celu biletów ulega zniszczeniu.
Efekt wygładzenia przepływu i ograniczenie wykorzystania przepustowości otrzymuje się
przez stałe w czasie generowanie nowych żetonów. Liczba żetonów nie może jednak
przekroczyć maksymalnej pojemności bufora czyli inaczej głębokości wiadra. Wielkość ta
jest parametrem algorytmu.
Gdy nie ma aktualnie danych do wysłania, żetony są gromadzone, aż wypełnią bufor i mogą
zostać użyte do wysłania zwiększonej liczby pakietów i obsłużenia nagłych wzrostów
natężenia ruchu (ang. burst rate).
Warto jeszcze wspomnieć, że jedna z różnic pomiędzy algorytmem „cieknącego wiadra”
i „wiadra z żetonami” polega na tym, iż w pierwszym z nich w przypadku przekroczenia
rozmiaru bufora odrzucane są pakiety a nie żetony. Oczywiście stosując algorytm wiadra z
żetonami również możemy napotkać zjawisko gubienia pakietów, jednak będzie ono
spowodowane działaniem innego algorytmu, który zarządza samym buforem.
Poniższy rysunek ilustruje w schematyczny sposób działanie algorytmu „wiadra z żetonami”.
Na rysunku widać, że fakt zgromadzenia w buforze pewnej dodatkowej liczby żetonów
pozwala na wysłanie pakietów pojawiających się na początku z taką prędkością w jakiej
wchodzą one do kolejki. Uważny obserwator zauważy, że w przedstawionym przykładzie
wszystkie pakiety mają tą samą wielkość i pojedynczy żeton pozwala na wysłanie jednego
pakietu. Jest to dość idealna sytuacja i raczej niespotykana. Na poniższym rysunku można
28
także dostrzec, że od głębokości „wiadra” zależy jak długo będzie trwało zwiększone
natężenie ruchu.
Rysunek 6 Algorytm „wiadra z żetonami”
Sposób implementacji algorytmu „wiadra z żetonami”.
Jako praktyczną realizację algorytmu wiadra z żetonami stosuje się liczbę 32-bitową bez
znaku, która odpowiada po prostu liczbie żetonów znajdujących się aktualnie w wiadrze.
W chwili gdy pakiet ma zostać przesłany liczba ta jest inkrementowana o pewną wartość
oznaczającą, ile żetonów powstało od czasu ostatniego wysyłania. Dla ułatwienia
i przejrzystości można założyć, że bez względu na prędkość danego interfejsu w ciągu jednej
milisekundy generowany jest pojedynczy żeton. Oznacza to, że w ciągu sekundy powstaje
1000 żetonów. Takie założenie umożliwia łatwo obliczyć wartość, o jaką należy zwiększyć
liczbę żetonów w wiadrze, gdyż większość systemów operacyjnych jako jednostkę czasu
stosuje właśnie jedną milisekundę.
Największą granulację czasu można uzyskać odczytując czas procesorowy liczony w taktach
zegara (ang. ticks), jednak częste stosowanie tego typu zabiegu niestety może zmniejszyć
prędkość działania kodu i jest odradzane w dokumentacji Device Driver Kit [MSDN].
Sumaryczna wielkość liczby żetonów, które były w wiadrze i które zostały wygenerowane,
nie może jednak przekroczyć pewnej wartości oznaczającej wielkość wiadra.
29
Następnie proces wysyłający sprawdza czy liczba żetonów znajdujących się obecnie w
wiadrze (po inkrementacji), pozwala na to by kolejny pakiet mógł zostać przesłany. Należy
tutaj zauważyć, że liczba bajtów pakietu odpowiadająca pojedynczemu żetonowi może być
różna w zależności od częstości, z jaką dane mają być wysyłane.
Znajomość współczynnika zamieniającego liczbę bajtów na liczbę żetonów jest kluczowa dla
wykonania tej operacji. Do jego wyznaczenia można posłużyć się wzorem:
ratetpstb =2
Wzór 1
W powyższym wzorze tps oznacza prędkość generowania żetonów wyrażoną w żetonach na
sekundę, rate – prędkość wysyłania danych w bajtach na sekundę, b2t jest wspomnianym
współczynnikiem zamieniającym bajty na żetony.
Przykładowo gdy żetony generowane są z prędkością 1000 żetonów na sekundę, a prędkość
transmisji ma wynosić 2000 bajtów na sekundę, wówczas pojedynczy żeton będzie
umożliwiał wysłanie 2 bajów.
Po obliczeniu liczby żetonów potrzebnej do wysłania pakietu, jeśli jest ona wystarczająca
można zdecydować o jego wysłaniu i wówczas zmniejszyć wykorzystaną liczbę żetonów w
buforze.
Jeśli liczba żetonów w buforze nie byłaby wystarczająca, należy wstrzymać proces
wysyłający do czasu kiedy niezbędne żetony zostaną wygenerowane.
Podwójne „wiadro z żetonami”
Stosowanie jednego „wiadra z żetonami” jako sposobu kształtowania ruchu w sieci, nie jest
zbyt mile widziane z punku widzenia Quality of Service. Jest to spowodowane faktem, że
choć usługi, których charakter niemal wymaga zezwalania na chwilowe wzrosty zajętości
przepustowości, są przez omawiany algorytm traktowane poprawnie, to jednak te nagłe skoki
natężenia nie mogą być w żaden sposób kontrolowane. Określane są one jedynie poprzez
wielkość wiadra, jednak w większości przypadków wiadro jest na tyle duże, aby możliwe
było kształtowanie również wysokich przepustowości.
Ta niedogodność niwelowana jest dzięki wprowadzeniu dodatkowego wiadra z żetonami,
którego zadaniem jest kształtowanie tylko takiego gwałtownego zwiększenia natężenia ruchu.
30
Wiadro takie ma głębokość pozwalającą na wysłanie pakietu o największej możliwej
długości. W sieci Ethernet przyjmuje się, że jest to 1500 bajtów. Wielkość tę określa się
skrótem MTU (ang. Maximum Transmission Unit).
Częstotliwość jaka jest przypisana do drugiego wiadra, stanowi z kolej maksymalną
dozwoloną częstotliwość szczytową i musi być większa od częstości ustalonej dla pierwszego
wiadra.
Można zauważyć, że gdy maksymalna częstość szczytowa określona przez dodatkowe wiadro
dąży do nieskończoności, wówczas takie podwójne wiadro coraz bardziej staje się
odpowiednikiem pojedynczego.
Mechanizm podwójnego wiadra z żetonami, po pewnej modyfikacji, stosowany jest również
w algorytmie „hierarchicznego wiadra z żetonami”. Dzięki takiemu modelowi dualnego
bufora na żetony możliwe staje się pożyczanie przepustowości pomiędzy klasami.
2.4 „Hierarchiczne wiadro z żetonami”
Hierarchiczne wiadro z żetonami jest typem kolejki klasowej, która podobnie jak CBQ
pozwala na tworzenie w sieci komputerowej rozmaitych klas ruchu ułożonych w strukturę
drzewa. Ma jednak wiele cech, które sprawiają, że obecnie jest coraz częściej
wykorzystywana przez projektantów sprzętu i oprogramowania służącego do kształtowania
ruchu.
Między innymi zaletą HTB (ang. Hierarchical Token Bucket), jest to, że potrafi dokładnie
określić przepustowości przypisane poszczególnym klasom, inaczej nić w CBQ, gdzie
wyliczanie przyznawanego klasom pasma ma raczej charakter aproksymacyjny i niekiedy nie
przynosi oczekiwanych rezultatów.
HTB jest także algorytmem dużo mniej skomplikowanym i stanowi właściwie pewną
modyfikację poprzednio omawianego algorytmu „dualnego wiadra z żetonami”. Modyfikacja
ta polega na utworzeniu hierarchii klas oraz założeniu, że klasy na niższych poziomach mogą
pożyczać zasoby przepustowości od swoich rodziców.
Algorytm ten został wykorzystany jako główny element implementacji kształtowania ruchu
dokonanej w części praktycznej niniejszej pracy.
31
Definicje
Klasa
Jest podstawowym pojęciem dla zagadnienia kolejek klasowych. Oznacza pewną grupę typów
transmisji, zdefiniowaną na podstawie ustalonych kryteriów, którymi mogą być pola w
pakietach, ale także i inne wielkości jak np. czas astronomiczny wystąpienia przesyłania
danych.
W klasach można wyróżnić także podklasy, których dotyczą tylko niektóre kryteria
określające klasę główną. Oznacza to istnienie pewnej hierarchii klas, w której klasy rodzice
charakteryzują się łącznym zbiorem cech swoich potomków.
Klasa może posiadać rodzica. Dla klasy znana jest również wielkość aktualnej częstości
wysyłania R (ang. actual rate). Jest to natężenie przepływu pakietów opuszczających klasę,
mierzone w małym odcinku czasu. Dla klasy wewnętrznej R oznacza sumę tej wielkości
zmierzonej dla wszystkich jej potomków.
Liściem jest klasa, która nie posiada żadnych potomków. Tylko liście przechowują kolejki z
pakietami. W ogólnym przypadku kolejka taka może posiadać dowolną architekturę, także
klasową. Również tylko dla liści istotny jest ich priorytet i kwant.
Przykład hierarchii klas ukazany został na poniższej ilustracji.
Rysunek 7 Hierarchiczna struktura podziału przepustowości
32
Na rysunku można zobaczyć, że dwa oddziały firmy współdzielą jedno łącze. Chcemy
zapewnić, aby dostęp do łącza dla tych oddziałów został przydzielony w proporcjach 2 do 3.
Dodatkowo dla oddziału A zakładamy, że będzie on mógł wykorzystywać przepustowość
przy korzystaniu z protokołów Telnet, FTP i HTTP w proporcjach 1 do 5 do 4 w skali
oddziału. Dla całego łącza wymienione protokoły otrzymają 4%, 20% i 16% całej dostępnej
przepustowości. Podobnie przepustowość zostanie rozdysponowana dla usług
wykorzystywanych przez oddział B.
Więcej na temat podziału łącza można znaleźć w artykule [LINK95].
Niżej przedstawiono najważniejsze wielkości powiązane z klasami.
Zapewniona częstość AR (ang. assured rate)
Oznacza minimalną część przepustowości łącza, którą klasa otrzyma zawsze, gdy będzie
przechowywać pakiety. Po przekroczeniu tej wielkości klasa może wysłać kolejne porcje
danych, ale tylko pod warunkiem, że uda jej się na ten cel pożyczyć od któregoś z przodków
pewną ilość przepustowości. W praktyce pożyczanie przepustowości oznacza pożyczanie
żetonów, które umożliwiają wysyłanie pakietów.
Częstość szczytowa CR (ang. ceil rate)
Wprowadzenie tej wielkości umożliwia klasie pożyczanie przepustowości od jej rodzica.
Kiedy klasa przekroczy tę wartość nie może już wysyłać pakietów, ani nawet pożyczać
przepustowości. Wielkość ta jest obliczana na podstawie liczby żetonów w dodatkowym
„wiadrze z żetonami” dotyczącym szczytowej częstości wysyłania.
Priorytet P
Pozwala określić, która z klas ma pierwszeństwo w pożyczaniu przepustowości od ich
przodków, znajdujących się na tym samym poziomie.
Poziom (ang. level)
Określa pozycję klasy w hierarchii klas. Liście mają poziom 0, klasa korzenia poziom
mniejszy od maksymalnej liczby poziomów, zaś każda klasa wewnętrzna posiada poziom o
jeden mniejszy niż jej rodzic.
33
Kwant Q (ang. quantum)
Pozwala, by klasy mogły wysyłać na raz większe porcje danych niż tylko jeden pakiet.
Określa dokładnie ilość bajtów jakie klasa może wysłać, zanim przyjdzie kolej innej klasy tak
samo uprawnionej do wysyłanie. Wielkość ta stanowi główny parametr algorytmu „Deficit
Round Robin” (DRR), określającego sprawiedliwy porządek w jakim klasy wysyłają pakiety.
Stan (ang. mode)
Jest sztuczną wielkością obliczoną z R, AR, CR i może przyjmować wartości:
• Czerwony – gdy R > CR (klasa osiągnęła częstość szczytową),
• Żółty – gdy R ≤ CR i R > AR (klasa przekroczyła częstość zapewnioną, ale może
pożyczać przepustowość od przodków),
• Zielony – gdy R ≤ AR (klasa może sama wysyłać pakiety).
Szczegóły implementacji
Na poniższym rysunku przedstawiono przykładową strukturę klas. Taka struktura jest lokalna
względem interfejsu, dla którego zostało włączone kształtowanie ruchu. Oznacza to że
poszczególne interfejsy otrzymają własne drzewa z klasami.
Rysunek 8 Przykładowa hierarchia klas (1)
34
Klasa A jest korzeniem drzewa, klasy C, D, E stanowią jej liście i to one będą przechowywać
pakiety. Z kolei klasę B nazywać będziemy klasą wewnętrzną. Dodatkowo przyjęto istnienie
dwóch priorytetów klas liści: wysokiego – oznaczanego kolorem czerwonym – i niskiego –
oznaczanego na niebiesko. Klasami o niskim priorytecie są C i E, zaś wysoki priorytet
posiada klasa D.
Można zauważyć, że omawiane klasy ułożone są w hierarchii trzech poziomów. Poziom
zerowy został zarezerwowany dla klas liści. Klasa korzeń ma poziom najwyższy, który w tym
wypadku wynosi dwa, zaś wszystkie klasy wewnętrzne, czyli tutaj klasa B, mają poziom o
jeden niższy od swojego rodzica, a zatem poziom pierwszy w przypadku klasy B.
Algorytm HTB zakłada istnienie trzech rodzajów list, które przechowywać będą wskazania
do klas. Listy oznaczone zostały prostokątami w kolorach: białym, czerwonym i niebieskim.
Pierwszy rodzaj list tzw. listy wewnętrzne priorytetowe – zostały przypisane do klas. Dzięki
tym listom możliwe jest utworzenie pomiędzy klasami ścieżek o określonym priorytecie
umożliwiających pożyczanie przepustowości. Kolor listy oraz ścieżki wskazuje na priorytet.
Na wewnętrznych listach priorytetowych pojawiają się klasy wyłącznie, gdy liście będące ich
potomkami przechowują pakiety i mają kolor żółty, a także wszystkie klasy na utworzonej
ścieżce również posiadają kolor żółty.
Listy kolejnego rodzaju, które zostały ukazane na rysunku w kolumnie po prawej stronie za
pomocą czerwonych i niebieskich prostokątów to tzw. zewnętrzne listy priorytetowe. Ich
zadaniem jest przechowywanie wskazań do aktywnych klas w zielonym kolorze. Aktywna
klasa to taka która przechowuje pakiety sama lub przechowują je jej potomkowie, do których
biegnie ścieżka pożyczania przepustowości utworzona za pomocą wewnętrznych list
priorytetowych.
Ostatni rodzaj list stanowią listy oczekiwania klas na zmianę stanu. Na rysunku mają postać
białych prostokątów. Do list takich trafiają klasy żółte lub czerwone i są one przechowywane
wg czasu, w którym zmieni się ich kolor z czerwonego na żółty lub z żółtego na zielony.
35
Kolejny rysunek ukazuje przykładową sytuację, w której pakiety trafiają do klas C i D.
Oznaczone to zostało pogrubieniem konturów kół symbolizujących te klasy.
Rysunek 9 Przykładowa hierarchia klas (2)
Ponieważ klasy C i D nie przechowywały wcześniej pakietów i nie były aktywne, to
konieczne jest ich umieszczenie na odpowiednich listach priorytetowych. Skoro klasy te mają
stan zielony, a więc mogą zostać umieszczone od razu na zewnętrznych listach
priorytetowych na danym poziomie. C ma priorytet niski, a więc trafia na listę o niskim
priorytecie. D ma priorytet wysoki, zatem jest umieszczana na liście o wysokim priorytecie.
W tym miejscu istotne staje się określenie w jaki sposób można wybrać pakiety z drzewa.
Otóż procedura dekolejkująca przegląda zewnętrzne listy priorytetowe od dołu, aż do
napotkania pierwszej niepustej listy. Po jej znalezieniu należy określić zbiór klas liści, które
należą do takiej listy bezpośrednio lub jako potomkowie klas wyższych umieszczonych tutaj.
Do jednoznacznego wyznaczenia klasy mającej wysłać pakiet z takiego zbioru stosuje się
algorytm „Deficit Round Robin” omówiony dokładnie w rozdziale o tej samej nazwie. Na
mocy tych rozważań jedyną klasą, która w tej chwili może wysłać pakiety jest D.
Na kolejnym przykładzie widać, że klasa D wysłała pewną liczbę danych co spowodowało, że
zajęła ona zapewnioną dla siebie przepustowość. Innymi słowy wyczerpała cały limit
żetonów jaki był dla niej przeznaczony. Jednak pozostała jej jeszcze część żetonów w drugim
36
wiadrze służącym do kształtowania natężenia szczytowego. Może zatem pożyczać
przepustowość od swoich przodków.
Rysunek 10 Przykładowa hierarchia klas (3)
Kiedy klasa staje się żółta, musi zostać utworzona ścieżka pożyczania przepustowości.
Ścieżka taka ma określony kolor i prowadzi od zewnętrznej listy priorytetowej po prawej
stronie, poprzez szereg klas wewnętrznych, aż do klasy liścia. Wszystkie klasy na takiej
ścieżce muszą mieć kolor żółty za wyjątkiem pierwszej klasy dodanej do listy zewnętrznej.
W tym wypadku ścieżkę pożyczania przepustowości symbolizuje czerwona linia.
Dodatkowo trzeba zauważyć, że klasa D pojawiła się na liście oczekiwania na zmianę stanu
po prawej stronie. Pozostanie ona tutaj, aż zmieni swój kolor na zielony. Ponieważ klasa D
jest teraz dostępna dla procedury wysyłającej przez listę zewnętrzną na poziomie pierwszym,
to klasa C zyskała pierwszeństwo w wysyłaniu pakietów.
Przypuśćmy, że klasa C po wysłaniu pakietu stała się czerwona i nie może dalej nic wysyłać.
W takim przypadku nie może nawet pożyczać przepustowości od przodków. Pozostaje zatem
dodać ją do białej listy oczekiwania po prawej stronie. Pozostanie ona na tej liście, aż zmieni
swój kolor na żółty. Sytuację taką ilustruje kolejny rysunek.
37
Rysunek 11 Przykładowa hierarchia klas (4)
Na ilustracji widzimy, że klasa D kontynuując wysyłanie pożycza przepustowość od coraz
wyższych poziomów klas. Kolejne klasy, które stają się żółte, dodawane są do odpowiednich
list oczekiwania i list wewnętrznych klas ich przodków. Klasa A będąc wciąż zielona,
pozostaje na szczycie hierarchii użyczając swoich zasobów przepustowości. Czerwona linia
biegnąca od korzenia do klasy D pokazuje ścieżkę, według której klasa liść pożycza
przepustowość.
Co się jednak stanie, gdy korzeń drzewa wyczerpie wszystkie żetony jakie może pożyczać
potomkom? Wówczas podobnie jak inne klasy trafi do listy oczekiwania na zmianę stanu na
swoim poziomie. Również nie będą mogły być prowadzone żadne transmisje, które od niego
zależą. Taka sytuacja widoczna jest na kolejnym rysunku
38
Rysunek 12 Przykładowa hierarchia klas (5)
Można tu też zobaczyć, że jeśli pakiety pojawią się w klasie E, która nie pożycza
przepustowości od klasy korzenia i jest zielona, to będą one mogły zostać wysłane. Pozostałe
transmisje w klasach C i D muszą czekać na zmianę stanu korzenia drzewa, klasy B, lub gdy
same staną się zielone.
Ostatnia ilustracja służy ukazaniu czytelnikowi, że proces pożyczania przepustowości polega
na rozpinaniu w głównym drzewie klas pewnych poddrzew o określonych priorytetach.
Każde takie drzewo aby mogło wysłać pakiet, musi wyrastać, z którejś z list zewnętrznych.
Łatwo bowiem dostrzec, że klasy wewnętrzne mogą się znajdować na kilku wewnętrznych
listach priorytetowych swoich rodziców w zależności od priorytetów klas potomnych – liści.
Istotne jest także zauważenie, że w tym przykładzie klasy C i E mają równe prawa do
wysłania pakietu. Gdyby w klasie D nie było pakietów to, w tej sytuacji do jednoznacznego
wybrania klasy wysyłającej, należałoby skorzystać z algorytmu Deficit Round Robin.
39
Rysunek 13 Przykładowa hierarchia klas (6)
Dodatkowe informacje dotyczące algorytmu „hierarchicznego wiadra z żetonami” można
znaleźć na stronie jego autora – Martina Devery [DEVIK] oraz w źródłach programów dla
systemu Linux [LINSRC].
40
Rozdział 3 Komercyjne rozwiązania kształtowania ruchu
Oferowany na rynku sprzęt sieciowy, który pozwala na kształtowanie ruchu, można podzielić
na dwie zasadnicze grupy.
Do pierwszej z tych grup zaliczają się przełączniki i routery wyposażone w elementy
umożliwiające zarządzanie przepustowością.
Drugą zaś grupę produktów stanowią specjalistyczne urządzenia, dla których kształtowanie
ruchu jest podstawowym zadaniem. Produkty tego typu umieszcza się przeważnie w
krytycznych miejscach sieci pomiędzy przełącznikiem a routerem. Punktem takim może być
przykładowo połączenie sieci wewnętrznej przedsiębiorstwa z Internetem.
3.1 Przełączniki i routery z możliwością kształtowania ruchu
Funkcje kształtowania ruchu wbudowane w routery i przełączniki niestety nie prezentują zbyt
wygórowanych możliwości. Jest to spowodowane głównie tym faktem, że projektanci tych
urządzeń zwracają przede wszystkim uwagę na obsługiwane przez nie protokoły oraz
prędkości działania.
Mechanizmy zarządzające przepustowością w tych produktach stanowią przede wszystkim
ograniczniki przepustowości oraz kolejki zapewniające jedynie sprawiedliwy dostęp do łącza
różnym transmisjom.
Warto jednak zapoznać się z podstawowymi możliwościami przełączników i routerów w
zakresie kształtowania ruchu, ponieważ w większości przypadków zastosowanie tylko tych
urządzeń wystarcza do zapewnienia właściwego zagospodarowania przepustowości w sieci.
41
Poniżej przedstawiono przykładowe rozwiązania dwóch firm Cisco Systems oraz Enterasys
(wcześniej Cabletron). Materiał zaczerpnięto ze stron internetowych producentów [CISCO]
i [ESYS]. Zainteresowani tym tematem mogą znaleźć więcej informacji o sprzęcie również na
stronach innych firm: [3COM], [NORTEL], [LUCENT], [JUNIP].
Cisco Systems
Routery produkowane przez firmę Cisco obsługiwane są przez system operacyjny IOS, który
posiada wbudowane cechy pozwalające na zagwarantowanie jakości usług. Spośród
mechanizmów wykorzystanych w tym celu wymienić należy przede wszystkim kształtowanie
ruchu przy wykorzystaniu różnego typu algorytmów. Dodatkowo system IOS zapewnia
wsparcie dla nadawania priorytetów różnym typom ruchu. Wyposażony jest także w funkcje
filtrujące przesyłane pakiety, zapobiegające zatorom oraz wiele innych mechanizmów
mających zapewnić poprawę jakości usług w danej sieci.
Ze punktu widzenia samego kształtowania ruchu najistotniejszym zagadnieniem przy
omawianiu urządzeń Cisco jest zwrócenie uwagi na to, jakie oferują rozwiązania w zakresie
klasyfikowania oraz kolejkowania przepływów.
Klasyfikowanie ruchu możliwe jest na podstawie takich cech pakietów jak:
• typ protokołu,
• długość komunikatu,
• numery portów TCP,
• adres interfejsu wejściowego,
• adresy MAC.
Sklasyfikowany w ten sposób ruch można poddać następnie ograniczeniu dostępnej
przepustowości.
Spośród dostępnych dla IOS mechanizmów kolejkowania należy wymienić:
• proste kolejki FIFO – pakiety pojawiają się na interfejsie wyjściowym w tym samym
porządku w jakim dotarły do interfejsów wejściowych.
• kolejkowanie priorytetowe – tworzony jest zespół kolejek FIFO o różnych
priorytetach. Pakiety przypisywane są do poszczególnych kolejek przy pomocy
klasyfikatora korzystającego ze zdefiniowanych wcześniej reguł. Opróżnianie kolejek
42
odbywa się w porządku od najwyższego do najniższego priorytetu.
IOS pozwala na przypisanie pakietom czterech priorytetów (w kolejności od
najważniejszego): high, medium, normal i low.
• „custom queuing” – umożliwia administratorowi utworzenie zestawu kolejek o
określonych charakterystykach i przyznanie im zasobów przepustowości.
Poszczególne kolejki obsługiwane są w porządku karuzelowym przy czym kolejny
bufor opróżniany jest tak długo, aż zostanie wyczerpany ustalony dla niego limit
przepustowości. Taki sposób kolejkowania pozwala także na pożyczanie
przepustowości pomiędzy przepływami.
• ważone sprawiedliwe kolejkowanie – algorytm automatycznie tworzy zestaw kolejek
dla każdej konwersacji przepływającej przez router. Wybór bufora mogącego w danej
chwili wysłać pakiet odbywa się przy zastosowaniu algorytmu karuzelowego
wybierającego po jednym bicie z każdego bufora (Bit-by-bit Round-robin).
Konwersacje czyli przepływy pakietów o pewnych charakterystykach wyznaczane są
na podstawie następujących danych:
numery portów TCP i UDP,
adresy źródłowy i docelowy IP, typ protokołu, pole ToS,
identyfikator połączenia DLCI dla medium Frame Relay,
Logical Channel Number (LCN) w sieci X.25,
adresy MAC.
Przykładowymi urządzeniami spośród routerów firmy Cisco, które umożliwiają kształtowanie
ruchu są routery z serii Cisco 2600 przeznaczone do zastosowań na skalę biura średniej
wielkości. Dodatkowo routery tego typu można wyposażyć w moduły kompresujące dane co
pozwala na lepsze zagospodarowanie dostępnej przepustowości np. przy łączeniu oddziałów
firmy wykorzystując sieć rozległą.
Enterasys (Cabletron)
Firma Enterasys oferuje w produkowanych przez siebie przełącznikach z serii Matrix
oznaczonych symbolami E7, N3 i N7 wielowarstwowe klasyfikowanie ruchu. Wymienione
urządzenia zarządzane są przez system NetSight Atlas Policy Manager, który potrafi
zapamiętać szereg serwisów utworzonych przez administratora. Serwisy takie stanowią po
43
prostu grupy przepływów pakietów tworzone na podstawie charakterystyk zawierających
następujące informacje:
• adresy MAC,
• typy protokołów warstwy 3 określone w polu „EtherType” nagłówka protokołu
ethernet (IP, IPX, Apple Talk, itd.),
• adresy IP,
• typ protokołu warstwy 4 określone w polu „Protocol” nagłówka protokołu IP (TCP,
UDP, itp.),
• pole ToS protokołu IP,
• numery portów TCP/UDP (HTTP, SAP, itp.).
Do każdego z utworzonych serwisów można następnie przypisać odpowiednie akcje, którymi
z punktu widzenia kształtowania ruchu najistotniejsze są ograniczanie dostępnej
przepustowości – CAR (Commited Access Rate) – i ustalanie priorytetu czyli kolejności w
jakiej przepływy zostaną obsłużone.
Z kolei przykładowy router Enterasys X-Pedition 8000, przeznaczony do zastosowania w
sieci szkieletowej małego przedsiębiorstwa, przy kształtowaniu ruchu umożliwia skorzystanie
z algorytmu WFQ oraz ograniczania przepustowości CAR.
3.2 Specjalistyczne urządzenia zarządzające przepustowością
Dla urządzeń tego typu zarządzanie przepustowością w sieci stanowi zadanie podstawowe.
Mogą poza tym posiadać funkcje monitorujące sieć, a także kompresujące dane. Aby
poprawić działanie sieci nie trzeba stosować ich wiele. Wystarczy wpiąć do sieć po jednym z
tych produktów w najbardziej przeciążonych jej punktach.
Zamieszczone poniżej informacje zaczerpnięto ze stron producentów wymienionych urządzeń
czyli [PACK] i [ALLOT].
Packeteer Inc.
Podstawowym urządzeniem oferowanym przez firmę Packeteer pozwalającym na
kształtowanie ruchu jest PacketShaper. Produkt ten skupia w sobie szereg mechanizmów
44
pozwalających zarządzać zarówno ruchem wychodzącym jak i wchodzącym. Wykorzystana
w nim technologia bazuje przede wszystkim na klasowym algorytmie opracowanym przez
producenta, a także zawiera elementy manipulowania szerokością okna TCP.
Poniższy rysunek ilustruje przebieg przykładowej sesji TCP i zmianę okna transmisji przez
urządzenie PacketShaper.
PacketShaper
Nadawca danych
Dane od 20000 do 21000
ACK 21001 Okno 8000
ACK 21001 Okno 2000
Dane od 21001 do 23000
ACK 23001 Okno 8000
ACK 23001 Okno 2000
Dane od 23001 do 25000
upływ czasu
Rysunek 14 Manipulowanie szerokością okna TCP przez urządzenie PacketShaper
Istnieje szereg wersji tego produktu różniących się między sobą prędkością sieci z jaką są
zdolne pracować. Obsługiwane prędkości mieszczą się w zakresie od 2 Mb/s do 500 Mb/s.
Dolny kraniec tego przedziału obsługiwany jest przez PacketShaper serii 1550, który potrafi
rozróżnić do 256 różnych klas ruchu.
Górny kraniec czyli 500 Mb/s przypada dla PacketShaper 9500, będącego wstanie
zdefiniować do 2048 klas.
45
Przykładowe rozmieszczenie urządzeń PacketShaper w sieci znajduje się na poniższej
ilustracji.
Rysunek 15 Rozmieszczenie urządzeń firmy Packeteer w sieci
Ważną zaletą urządzeń PacketShaper jest zdolność do rozpoznawania szerokiego wachlarza
rodzajów ruchu generowanego przez aplikacje. Szczególnie dotyczy to aplikacji trudnych do
rozpoznania z racji dynamicznie zmieniających się numerów portów, na których pracują,
takich jak np. Kazaa i innych służących do komunikacji P2P (peer to peer).
Dodatkowo urządzenia PacketShaper z serii Xpress umieją poddawać przesyłane dane
kompresji. Dzięki temu łącząc oddziały firmy poprzez sieć rozległą otrzymuje się pewną
oszczędność przepustowości.
Allot Communications
Czołowymi produktami firmy Allot Communications przeznaczonymi do zarządzania
przepustowością, są urządzenia NetEnforcer z serii 1000. Potrafią one pracować z sieciami o
dużych prędkościach rzędu 1 Gb/s i kształtować ruch w obu kierunkach.
Ważną zaletą NetEnforcer’a jest możliwość zintegrowania go z systemami obsługi klienta
CCB (customer care and biling) poprzez zastosowanie protokołu LDAP3 opisanego w
dokumencie [RFC-2251]. Pozwala to na szybkie wprowadzanie reguł na dostępność
46
przepustowości dla nowych użytkowników sieci. NetEnforcer potrafi bowiem automatycznie
odczytać kontrakt SLA klienta i na jego podstawie ustawić odpowiednie limity.
Kolejny atut urządzeń firmy Allot stanowi umiejętność klasyfikowania ruchu na poziomie
warstwy aplikacji. Odbywa się to poprzez odczytywanie sygnatur obecnych w pakietach.
Dzięki temu możliwe jest np. dławienie ruchu P2P dla takich programów jak Kazaa czy
Gnutella.
Algorytm kolejkujący wykorzystany w NetEnforcerze jest własnym pomysłem firmy Allot
i stanowi rodzaj kolejki klasowej. Poszczególne klasy ruchu tworzone są na podstawie takich
charakterystyk jak:
• adresy IP (możliwość wprowadzania zakresów adresów, adresów podsieci i nazw
komputerów). Odczytywanie tych adresów jest możliwe poprzez pliki tekstowe i
protokół LDAP;
• protokoły sieciowe (ARP, IPX, PPPoE);
• protokoły IP (ICMP, IGMP, RSVP, EGP);
• porty UDP i TCP;
• sygnatury w warstwie siódmej modelu ISO dla aplikacji wykorzystujących
dynamiczne przydzielanie portów;
• identyfikatory i priorytety w sieciach wirtualnych;
• czas astronomiczny
Zasada podłączania do sieci omawianych produktów jest bardzo prosta. Umieszcza się je
bowiem pomiędzy przełącznikiem a routerem. NetEnforcer z numerem 1020 potrafi także
obsługiwać połączenia redundantne i dla każdego z takich łącz automatycznie ustawiać reguły
dostępności pasma.
47
Rozdział 4 Biblioteka NDIS i sterowniki sieciowe
4.1 Czym jest NDIS?
NDIS oznacza w skrócie „Network Driver Interface Specification”. Główny cel NDIS
stanowi zdefiniowanie standardowego interfejsu aplikacji dla kontrolerów sieciowych
określanych skrótem NIC czyli „Network Interface Cards”. Pozwala to na abstrakcyjne
traktowanie sprzętu przez sterowniki sieciowe. Wszelkie szczegóły implementacyjne karty
sieciowej ukryte są w sterowniku urządzenia nazwanego „Media Access Controller” w
skrócie MAC. Dzięki temu dowolne urządzenia pracujące z tym samem typem medium (np.
Ethernetem) mogą być obsługiwane w jednakowy sposób.
NDIS udostępnia również bibliotekę funkcji, mogących być używanymi zarówno przez
kontrolery MAC jak i protokoły wyższego rzędu (jak np. TCP/IP). Biblioteka ta definiuje
standardowy interfejs komunikacji pomiędzy ułożonymi warstwowo sterownikami. Ma postać
zestawu procedur NdisXxx.
Taka architektura umożliwia łatwiejsze tworzenie sterowników sieciowych, a także, do
pewnego stopnia, ukrycie różnic pomiędzy poszczególnymi systemami operacyjnymi.
Biblioteka NDIS dostarcza także zespół parametrów kontrolnych wliczając: wskaźniki do
funkcji, uchwyty i inne wielkości systemowe.
Dodatkowo NDIS zawiera tzw. „spin locks” czyli mechanizmy synchronizacji dostępu do
współdzielonych zasobów dla procesów działających na różnym poziomie przerwań.
Elementy te potrafią współpracować z systemami wieloprocesorowymi.
Umożliwia też tworzenie „timerów” czyli funkcji uruchamianych przez system jednorazowo
w zaplanowanej wcześniej chwili lub cyklicznie co określony czas.
48
Pozwala również na synchronizację procesów za pomocą zdarzeń (ang. events). Dzięki
zdarzeniom tym możliwe jest wstrzymanie działania pewnego procesu w oczekiwaniu na
zakończenie się innego wykonywanego współbieżnie.
Ważną cechą biblioteki NDIS jest także to, że tworzy ona własną strukturę pakietów
zrozumiałą dla sterowników różnych warstw. Takie abstrakcyjne pakiety przenoszone są
pomiędzy poszczególnymi sterownikami i mogą być przez nie dowolnie modyfikowane.
Dokładne informacje na temat biblioteki NDIS można odnaleźć w źródłach [MSDN] i
[NDIS].
4.2 Wersje biblioteki NDIS
Pisząc sterowniki sieciowe dla różnych systemów operacyjnych należy być świadomym, jakie
funkcjonalności biblioteki NDIS są wspierane przez poszczególne platformy Windows. Z
każdą wersją biblioteki NDIS wiąże się bowiem dodanie do niej nowych cech. Również
niektóre cechy uważane są w nowszych wersjach tej biblioteki za przestarzałe, a część z nich
nawet usunięto.
Poniższa tabela ilustruje, które wersje biblioteki NDIS są wspierane przez poszczególne
systemy Windows.
System operacyjny Wersja NDIS
Windows 95 3.1
Windows OSR2 4.0
Windows 98 4.1
Windows 98 SE 5.0
Windows Me 5.0
Windows NT 3.5 3.0
Windows NT 4.0 4.0
Windows 4.0 SP3 4.1
Windows 2000 5.0
Windows XP 5.1
Tabela 1 Wersje biblioteki NDIS
49
Dokładne informacje na temat funkcji jakie są dostępne dla poszczególnych wersji NDIS,
można odszukać w specyfikacji Device Driver Kit znajdującej się w [MSDN].
4.3 Rodzaje sterowników NDIS
Biblioteka NDIS wspiera następujące typy sterowników sieciowych:
• sterowniki miniportów (ang. miniport drivers )
• sterowniki pośrednie (ang. intermediate drivers)
• sterowniki protokołów (ang. protocol drivers)
Poniższy rysunek ilustruje sposób w jaki te typy sterowników są rozmieszczone w systemie
operacyjnym.
Interfejs TDI
Rysunek 16 Rodzaje sterowników NDIS
Sterowniki tych rodzajów pracują w trybie jądra systemu i implementują pierwsze cztery
warstwy modelu OSI.
Sterowniki miniportu
Sterowniki tego typu zarządzają kartą sieciową wliczając wysyłanie i odbieranie przez nią
pakietów. Poza tym komunikują się ze sterownikami wyższych warstw czyli sterownikami
protokołów i sterownikami pośrednimi dostarczając im niezbędnych parametrów kontrolnych.
Protokoły LAN
Sterownik miniportu
Karta sieciowa Karta sieciowa
Inte
rfej
s ND
IS
Sterownik miniportu
Sterowniki pośrednie
Protokoły
rozpoznające
stosowane medium Medium LAN
Stosowany typ medium
50
Biblioteka NDIS eksportuje zestaw funkcji NdisXxx, które sterownik miniportu może
wywoływać. Funkcje te pozwalają sterownikowi współdziałać bezpośrednio z kartą sieciową
lub sterownikami wyżej położonymi czyli sterownikami protokółów i ewentualnie
sterownikami pośrednimi. Istotny jest fakt, że sterownik miniportu nie musi być w ogóle
świadomy z jakimi sterownikami się komunikuje, ponieważ w procesie tym w całości
pośredniczy biblioteka NDIS.
Sterownik miniportu musi wyeksportować własny zestaw funkcji MiniportXxx, które
biblioteka NDIS będzie wywoływała dla własnych celów lub w imieniu sterowników
wyższych warstw.
Przykładem komunikacji między sterownikiem miniportu a biblioteką NDIS jest proces
wysyłania i odbierania pakietów opisany dalej.
Kiedy sterownik transportowy chce wysłać pakiet przez sieć wywołuje pewną funkcję
NdisXxx biblioteki. Dalej NDIS przenosi pakiet do sterownika miniportu wywołując z kolei
jego funkcję MiniportXxx. Następnie miniport przesyła pakiet przez sieć wywołując
odpowiednią funkcję NdisXxx.
W drugą stronę w momencie gdy kontroler sieciowy odbiera pakiet, zgłasza przerwanie
sprzętowe. To przerwanie obsługiwane jest przez sam sterownik miniportu lub poprzez NDIS,
która powiadamia następnie odpowiedni sterownik miniportu wywołując jego funkcję
MiniportXxx. Dalej sterownik ustanawia transfer danych od karty sieciowej i powiadamia
wyższe warstwy o odebraniu pakietu korzystając z odpowiedniej funkcji NdisXxx.
Biblioteka NDIS wspiera zarówno miniporty zorientowane połączeniowo jak
i bezpołączeniowe. Bezpołączeniowe sterowniki miniportów obsługują kontrolery sieciowe
dla mediów o charakterze bezpołączeniowym takich jak Ethernet, FDDI, oraz Token Ring.
Sterowniki połączeniowe z kolei obsługują media typu połączeniowego czyli przykładowo
ATM i ISDN.
Sterowniki pośrednie
Sterowniki pośrednie umiejscowione są zwykle pomiędzy sterownikami miniportu a
sterownikami protokołów transportowych. Z tego też powodu zmuszone są one komunikować
zarówno ze sterownikami jednego jaki i drugiego typu. Wiąże się to ze zdefiniowaniem
punktów wejściowych – tzw. „handlerów” – czyli pewnych funkcji ProtocolXxx oraz
51
MiniportXxx. Dzięki tym funkcjom biblioteka NDIS będzie w stanie przesyłać
komunikaty pomiędzy poszczególnymi warstwami sterowników. Możliwe jest warstwowe
układanie tego rodzaju sterowników.
Istnieje kilka podstawowych zastosowań sterowników pośrednich.
Sterowniki pośrednie mogą być stosowane do tłumaczenia zasad transmisji pomiędzy
różnymi typami medium. Przykładową funkcją takiego sterownika położonego pomiędzy
sterownikami transportowymi dla Ethernetu lub Token Ring a miniportem obsługującym sieć
ATM, jest mapowanie pakietów pomiędzy tymi typami medium.
Sterowniki pośrednie mogą także służyć do balansowania obciążenia pomiędzy kilkoma
kartami sieciowymi. Wówczas pojedynczy wirtualny adapter jest eksponowany dla
sterowników protokołów, natomiast pakiety w rzeczywistości przesyłane są przez więcej niż
jeden adapter fizyczny. Możliwe jest również tworzenie wielu wirtualnych adapterów dla
jednego fizycznego. Tego typu sterowniki określane są skrótem MUX oznaczającym
multiplekser.
Innym zadaniem przeznaczonym dla sterowników pośrednich jest filtrowanie pakietów. W
tym przypadku przykładowy sterownik może zmieniać kolejność i czas wysyłania pakietów.
Ta funkcja sterowników pośrednich została użyta w części praktycznej niniejszej pracy do
implementacji kształtowania ruchu.
Sterowniki protokołów
Protokół sieciowy, który jest najwyżej położonym sterownikiem w hierarchii biblioteki NDIS,
jest często używany jako z kolei najniżej położony sterownik spośród tworzących stos
protokołów transportowych takich jak TCP/IP czy IPX/SPX.
Sterownik protokołu rezerwuje zasoby dla pakietów, kopiuje do nich dane pochodzące od
aplikacji i przesyła je niżej wykorzystując funkcje biblioteki NDIS. Zapewnia również
interfejs, przez który odbiera pakiety od niższych sterowników. Odebrane pakiety są
następnie przekazywane do czekających na nie aplikacji.
Protokół komunikuje się ze sterownikami miniportów lub sterownikami pośrednimi. W tym
celu wywołuje funkcje typu NdisXxx, aby wysyłać pakiety, a także odczytywać lub ustawić
pewne informacje dotyczące miniportów.
52
Eksponuje również własne metody ProtocolXxx, które biblioteka NDIS może
wykorzystywać sama lub w imieniu niżej położonych sterowników w hierarchii. Funkcje te
wiążą się z odbieraniem pakietów, a także odczytywaniem stanu urządzeń sieciowych i
innych informacji.
Przy omawianiu sterowników protokołów istotne jest wyjaśnienie w jaki sposób następuje
odbieranie przez nie pakietów. Odbywa się to w ten sposób, że gdy najwyżej położony
sterownik pośredni lub sterownik miniportu powiadamia NDIS o odebraniu pakietu, wówczas
biblioteka ta korzystając z funkcji ProtocolReceive lub ProtocolReceivePacket
informuje każdy z protokołów z osobna o pojawieniu się pakietu. W tym miejscu sterownik
protokołu może wykorzystać pakiet, jeśli stwierdzi, że jest mu on potrzebny lub odrzucić go.
Górną krawędź sterownika protokołu stanowi jego prywatny interfejs do wyżej położonych
sterowników na stosie protokołu.
4.4 Struktura pakietu w bibliotece NDIS.
Biblioteka NDIS definiuje własną strukturę o identyfikatorze NDIS_PACKET reprezentującą
pakiet przesyłany przez sieć. Pakiety NDIS tworzone są przez sterowniki protokołów. Mogą
następnie posłużyć do wysłania paczek danych przez sieć lub jako miejsce, w którym
sterownik miniportu umieszcza odebrane dane. Również sterowniki miniportów mają
możliwość tworzenia pakietów i przechowywania w nich informacji o odbieranych z sieci
danych. Nie jest to jednak obowiązkowe, ponieważ NDIS pozwala na przekazywanie do
warstw wyższych samych buforów z danymi.
Struktura NDIS_PACKET nazywana jest często deskryptorem pakietu, ponieważ zawiera
szereg informacji dotyczących pakietu, ale nie przechowuje go fizycznie. Rolę tę pełnią
natomiast bufory z danymi, które z kolei opisywane są przez deskryptory buforów
zdefiniowane przez strukturę o identyfikatorze NDIS_BUFFER.
53
Poniższy schemat przedstawia strukturę pakietu NDIS.
Pamięć wirtualna
Rysunek 17 Budowa pakietu NDIS
Na powyższym rysunku widać także, że system operacyjny ukrywa przed sterownikiem
fizyczną przestrzeń adresową, a udostępnia mu jej wirtualną reprezentację. Przestrzeń
wirtualnych adresów jest mapowana wewnętrznie na adresy rzeczywiste. Dokładne
informacje dotyczące zarządzania pamięcią w systemach Windows można odnaleźć w książce
[INW2K].
Pojedynczy pakiet może być przechowywanych w kilku buforach jednak niektóre źródła
zalecają skupianie go tylko w jednym buforze. Można o tym przeczytać np. na stronie [WD3].
Gdy pakiet składa się z kilku buforów wówczas ich deskryptory połączone są w listę. Każdy
deskryptor bufora posiada bowiem jedno z pól będące wskaźnikiem do kolejnego deskryptora
w łańcuchu. Łańcuch deskryptorów buforów jest natomiast przyczepiony do deskryptora
samego pakietu.
Głównym zadaniem deskryptora pakietu jest składowanie danych kontrolnych dotyczących
pakietu takich jak całkowita długość pakietu, długość nagłówka protokołu warstwy drugiej,
danych out-of-band i innych parametrów omówionych szczegółowo w specyfikacji Device
Driver Kit [MSDN]. Dostęp do tych informacji programista otrzymuje poprzez stosowanie
odpowiednich makr typu NDIS_SET_PACKET_XXX i NDIS_GET_PACKET_XXX, a pola te
Deskryptor pakietu Flagi Całkowita długość Pierwszy bufor ...
Deskryptor bufora Wirtualny adres Długość Następny bufor ...
Deskryptor bufora Wirtualny adres Długość Następny bufor ...
NULL
Bufory
Strona Strona
Strona Strona
Strona Strona
Strona Strona
Strona Strona
Pamięć fizyczna
54
nazywane są często polami prywatnymi pakietu. Taki sposób pomaga zachować przenośność
kodu pomiędzy różnymi wersjami NDIS.
Deskryptor pakietu może także przechowywać dowolne dane kontekstowe użytkownika
w specjalnie do tego przeznaczonych polach. Dostęp do tych pól można realizować
bezpośrednio bez konieczności używania makr. Takie pola zostały wprowadzone ponieważ
deskryptory pakietów są pożyczane pomiędzy sąsiednimi sterownikami w hierarchii. Każdy
ze sterowników ma bowiem obowiązek utworzenia własnej kopii deskryptora pakietu, który
przekazuje do niższej lub wyższej warstwy. Wyjątkiem od tej reguły jest sytuacja, w której
możliwe staje się wykorzystanie nowej techniki wprowadzonej w NDIS 5.1 tzw. „packet
stacking” czyli globalnego składowania deskryptorów. W takim wypadku sama biblioteka
przechowuje deskryptory, a poszczególne sterowniki mogą przeglądać ich zawartość
i przekazywać je do sąsiednich warstw baz konieczności kopiowania.
4.5 Budowa sterownika pośredniego
Ten podrozdział omawia podstawowe zagadnienia związane z budową sterowników
pośrednich. Wybrany został akurat ten typ sterowników NDIS, gdyż posiada on cechy dwóch
pozostałych czyli sterowników miniportów i protokołów. Poza tym do implementacji
praktycznej części niniejszej pracy został użyty właśnie sterownik pośredni.
Funkcja DriverEntry
Wszystkie sterowniki sieciowe działające z biblioteką NDIS mają podobną budową. W ich
skład wchodzi przede wszystkim funkcja DriverEntry czyli punkt wejściowy sterownika.
Pojawia się ona we wszystkich typach sterowników Windows, działających nie tylko z
biblioteką NDIS, ale również określonych specyfikacją WDM (Windows Driver Model).
Więcej o specyfikacji WDM można przeczytać w źródłach: [MSDN], [W2KDDB] oraz
[PWDM].
Istotne jest aby funkcja DriverEntry miała właśnie taką nazwę, ponieważ w ten sposób
rozpoznaje ją system operacyjny i wywołuje w momencie gdy do pamięci zostanie
załadowany kod sterownika. W jej ciele sterownik powinien wykonać wszelkie czynności
inicjujące. W szczególności dla sterowników pośrednich NDIS istnieje kilka standardowych
procedur, które trzeba wykonać w tym miejscu. Procedury te omówiono poniżej.
55
Po pierwsze sterownik wywołuje funkcję NdisMInitializeWraper, która informuje
bibliotekę NDIS o załadowaniu nowego sterownika sieciowego i podaje pewien, uchwyt,
który należy zachować.
W kolejnym etapie sterownik poprzez wywołanie NdisIMRegisterLayeredMiniport
rejestruje zestaw funkcji MiniportXxx, charakterystycznych dla sterownika miniportu.
Przy wywoływaniu tej funkcji musi przekazać do niej uchwyt otrzymany w poprzednim
kroku.
Trzeci etap stanowi wywołanie NdisRegisterProtocol pozwalające na zarejestrowanie
zestawu funkcji ProtocolXxx typowych dla sterownika protokołu.
Proces rejestrowania funkcji sterownika nazywany jest często „serializacją”, a sterowniki,
które wykonują tego typu operację „zdeserializowanymi”. Dzięki serializacji wszystkie
„handlery” mogą mieć dowolne nazwy, ponieważ system odwołuje się do nich przez adres.
W ostatnim kroku inicjalizacji wewnątrz DriverEntry sterownik wykorzystuje funkcję
NdisIMAssociateMiniport, aby zgłosić bibliotece NDIS powiązanie między
funkcjami reprezentującymi dolną krawędź miniportu i górną krawędź protokołu.
W przypadku gdyby inicjalizacja nie mogła zostać zakończona pomyślnie, sterownik ma
obowiązek zwolnić wszelkie zarezerwowane zasoby wliczając utworzone uchwyty.
Wykorzystuje w tym celu z odpowiednie metody biblioteki NDIS.
Pojęcie kontekstu
Ważnym pojęciem pojawiającym się przy omawianiu procedur sterownika jest kontekst w
jakim te procedury są wywoływane przez bibliotekę NDIS. Ponieważ programowanie
sterowników w Windows ma charakter proceduralny to odpowiednie wskaźniki do obiektów,
na których dane funkcje mają pracować przekazywane są do nich przez wskaźnik.
Przykładami obiektów, w których kontekście pracują procedury sterownika, jest sam obiekt
sterownika jaki system tworzy przy jego załadowaniu, a także obiekty adapterów sieciowych
wysyłających i odbierających pakiety.
Istotnie jest, że programista piszący sterownik może do tych kontekstów dodawać także
własne informacje i wówczas programowanie nabiera pewnych cech obiektowości.
Obecnie pojawiają się liczne próby rozbudowy sposobu pisania sterowników w Windows o
obiektowość. Przykładem tego typu działania jest komercyjny produkt Driver Studio firmy
56
Compuware Corporation, rozszerzający podstawową bibliotekę NDIS o zestaw tzw.
„wraperów” czyli klas zbudowanych na bazie NDIS i WDM, umożliwiających w pełni
obiektowe podejście do zagadnienia programowania sterowników różnych typów. Więcej na
ten temat można przeczytać na stronie [COWRE].
Funkcje charakterystyczne dla sterowników miniportów
Poniżej przedstawiono najistotniejsze przykładowe procedury rejestrowane przez sterownik
pośredni, które charakteryzują go jako rodzaj miniportu.
• HaltHandler – uruchamiana w momencie usuwania lub wyłączania sterownika.
Umożliwia sterownikowi zwolnienie zasobów i działanie porządkujące.
• InitializeHandler – wywoływana przy inicjalizowaniu każdego wirtualnego
miniportu, może przykładowo posłużyć do utworzenia struktury symbolizującej adapter
sieciowy. Struktura ta stanowić będzie później kontekst dla funkcji wysyłających i
odbierających pakiety.
• SendPacketsHandler – przekazuje deskryptor jednego lub większej ilości
wysyłanych pakietów, które mają być wysłane przez sieć. Sterownik przed przesłaniem
pakietu do niżej położonych sterowników musi skopiować jego zawartość jeśli nie
posługuje się techniką „packet stacking” omówioną w podrozdziale dotyczącym pakietów
NDIS.
Funkcje charakterystyczne dla sterowników protokołów
Poniższe przykładowe procedury charakteryzują sterownik pośredni jako sterownik
protokołu.
• BindAdapterHandler – biblioteka NDIS wywołuje tę funkcję w celu powiązania
sterownika z położonym niżej wirtualnym lub rzeczywistym miniportem.
• UnbindAdapterHandler – wywoływana w celu przerwania powiązania z położonym
niżej wirtualnym lub rzeczywistym miniportem.
• ReceivePacketHandler/ReceiveHandler – są wykonywana gdy znajdujący się
poniżej sterownik odbierze pakiet z sieci. NDIS w zależności od sposobu w jaki miniport
sygnalizuje odebranie pakietu, wywołuje jedną lub drugą z tych funkcji.
57
• PnPEventHandler – NDIS wywołuje tę funkcję po wystąpieniu zdarzenia typu „Plug
and Play” lub związanego z zarządzaniem energią. Może posłużyć do konfigurowania
sterownika podczas jego pracy przy użyciu Notify Objects.
4.6 Sposoby komunikacji ze sterownikiem
Notify Objects
Notify objects czyli obiekty powiadamiania mogą być tworzone dla potrzeb różnych
komponentów sieciowych m.in. dla sterowników pośrednich. Dla sterowników tych stanowią
składniki opcjonalne, umożliwiają jednak łatwe skonfigurowanie tego typu komponentów. Są
obiektami COM zatem implementują pewne standardowe interfejsy. Rezydują w plikach
bibliotecznych z rozszerzeniem .dll, a o ich powiązaniu ze sterownikiem decydują
odpowiednie dyrektywy w pliku instalacyjnym sterownika (pliki z rozszerzeniem .inf).
Obiekty powiadamiania tworzone są przez podsystem konfigurowania sieci podczas
instalowania, zmiany parametrów i usuwania komponentów sieciowych.
Zadanie obiektów powiadamiania stanowi obsługa powiadomień jakie podsystem
konfigurowania sieci wysyła w imieniu danego komponentu.
Wykorzystując obiekty powiadamiania możemy zmienić zachowanie się sterownika
sieciowego podczas jego pracy. Potrafią one bowiem wyświetlić karty z właściwościami
komponentu w aplecie konfigurowania połączeń sieciowych, a poprzez komunikat
ApplyPnpChanges wysłać odpowiednie parametry bezpośrednio do samego sterownika,
do funkcji PnPEventHandler.
WMI (Windows Management Instrumentation)
WMI jest rozszerzeniem WDM (Windows Driver Model) i stanowi usługę działającą w trybie
jądra systemu, dzięki której sterowniki mogą ustanawiać interfejs do komunikacji z
programami użytkownika. Umożliwia przykładowo przesyłanie konfiguracji z programu do
sterownika, a w odwrotną stronę np. danych statystycznych.
Podstawową zaletą takiego sposobu komunikacji jest to, że utworzony interfejs ma charakter
ogólny i może być wykorzystywany przez różne aplikacje, a nie tylko pojedynczy panel
58
kontrolny specjalnie zaprojektowany do pracy z konkretnym sterownikiem. Dodatkowo zaletę
tę potęguje możliwość opisywania danych jakie sterownik udostępnia.
Istnieje również sposobność tworzenia połączenia między sterownikiem a aplikacjami
zarządzającymi poprzez sieć.
Podstawą działania WMI jest definiowanie przez sterownik pewnych bloków z danymi oraz
zdarzeń, które mają być dostępne dla aplikacji. Definicje te są opisane w formacie MOF
(Managment Object Format) i skompilowane wraz z binarnym obrazem sterownika. WMI
dodaje te informacje do swojej bazy danych określanej jako CIMOM (Common Information
Model Object Managment) dostępnej dla programów użytkowych.
Niestety ta technika mimo swoich niewątpliwych zalet nie jest jeszcze zbyt popularna.
Zdecydowanie bardziej znany jest standartowy interfejs wejścia/wyjścia definiowany przez
„I/O Requests Packets”. Nie jest również dobrą metodą do komunikacji o dużym natężeniu
jak np. przesyłanie pakietów od sterownika bezpośrednio do aplikacji. Nadaje się przede
wszystkim do konfiguracji.
IRP (I/O Request Packets)
W tej metodzie proces komunikacji pomiędzy sterownikiem a aplikacją użytkownika odbywa
się poprzez przesyłanie pewnych zgłoszeń określanych jako „I/O Request Packets”.
Przed rozpoczęciem połączenia z programem sterownik tworzy reprezentujący go obiekt
urządzenia i rejestruje swoją nazwę, która daje możliwość rozpoznania go przez programy
kontrolne. W tym miejscu rejestruje także zestaw funkcji – „handlerów” – wywoływanych w
momencie, gdy program użytkowy chce nawiązać komunikację ze sterownikiem, zrywa ją lub
zgłasza inne żądanie.
Jako parametr do każdej z takich procedur system przekazuje pewną strukturę IRP, która
zawiera przede wszystkim kod wykonywanej operacji, bufor z danymi jakie zostały
przekazane do sterownika oraz bufor, w którym sterownik ma umieścić swoją odpowiedź.
W tym miejscu można zauważyć, że to program działający w trybie użytkownika jest
inicjatorem połączenia. Chcąc nawiązać komunikację i korzystając z funkcji CreateFile
tworzy on po prostu uchwyt do pliku reprezentującego urządzenie – sterownik. Następnie
może wykorzystywać funkcje zapisu i odczytu danych czyli WriteFile i ReadFile oraz
59
funkcję ogólnego przeznaczenia DeviceIoControl, która musi zawierać zdefiniowany
przez użytkownika kod operacji określany często jako IOCTL.
Wymienione funkcje mogą od razu odczytywać informacje od sterownika lub zgłaszać tylko
pewne żądanie, które sterownik wypełni w przyszłości (tzw. zgłoszenia oczekujące – ang.
pending). Taki mechanizm można wykorzystać w sytuacji, kiedy sterownik musi
powiadamiać aplikację o zajściu pewnych nieprzewidzianych zdarzeń. W tym celu powinien
on przechowywać zgłoszenia IRP wewnętrznie i finalizować je w stosownym dla siebie
momencie. Dokładne informacje jak zrealizować takie połączenie można znaleźć w artykule
117308 w Bazie Wiedzy Microsoft znajdującej się w [MSSUP].
Przy omawianiu komunikacji aplikacja – sterownik istotne jest zwrócenie uwagi na fakt, że
sterownik nie może zostać poprawnie usunięty z systemu, gdy wskazują na niego nie
zamknięte uchwyty. Projektując zatem program należy albo otwierać połączenia ze
sterownikiem tylko na krótko, albo przeznaczyć jedno zgłoszenie IRP na powiadomienie
aplikacji o odłączaniu sterownika.
Ważną zaletą mechanizmu IRP jest jego prostota oraz fakt, że może być wykorzystywany do
transmisji o dużym natężeniu. Wadą jest natomiast konieczność przechowywania zgłoszeń
IRP oraz dość sztywne zasady komunikacji.
Mechanizm ten został wykorzystany w części praktycznej niniejszej pracy.
60
Podsumowanie
Śledząc zagadnienia dotyczące sieci komputerowych można zauważyć nie zwalniający tempa
rozwój związanych z nimi technologii. Dotyczy to zarówno sprzętu jak i oprogramowania.
Stale powstają coraz to nowe aplikacje i usługi, a ich wymagania dotyczące sprzętu rosną.
Przez linie komunikacyjne przebiegają gigabity wszelkiego typu informacji.
Taką zbiorowość różnorodnych transmisji bez mechanizmów potrafiących nimi zarządzać
można porównać do zatłoczonej autostrady, po której wszystkie pojazdy pędzą bez żadnych
ograniczeń. W takim środowisku słabi po prostu nie mają szans. Ale przecież nie każdy
używa sieci komputerowych wyłącznie do ściągania filmów czy muzyki. Istnieją też usługi o
delikatnych parametrach i wyrafinowanych wymaganiach jak np. aplikacje interaktywne,
którym należy zapewnić odpowiednie parametry, gdyż same się o nie niestety nie zatroszczą.
Można oczywiście rozwiązać ten problem dokładając dodatkowe megabity przepustowości
nie rozwiąże to jednak problemu na długo. Charakter programów wykorzystujących sieć
komputerową a nade wszystko użytkowników je obsługujących jest taki, że zawsze znajdą
sposób aby zagospodarować tę dodatkową przestrzeń.
Z takich też powodów zapewnianie gwarantowanych poziomów usług i w szczególności
kształtowanie ruchu w sieciach jest obecnie bardzo popularnym tematem. Naukowcy
zajmujący się problemami sieci udoskonalają algorytmy kolejkowania. Podstawowe sposoby
buforowania takie jak kolejki priorytetowe i sprawiedliwe nie są już dostatecznie dobre na
potrzeby dzisiejszych sieci. Konieczne staje się wprowadzanie bardziej elastycznych
algorytmów klasowych takich jak CBQ (Class Based Queuing), H-PFQ (Hierarchical Packet
Fair Queueing) oraz HTB (Hierarchical Token Bucket).
Stosowanie zwykłych routerów i przełączników także już nie wystarcza. Producenci tego
sprzętu, tacy jak Sisco Systems, 3Com Corporation, Nortel Networks czy inni wyposażają
swoje produkty w coraz wymyślniejsze algorytmy pozwalające lepiej różnicować sposób
61
obsługi odmiennych rodzajów ruchu, zapewniając im sprawiedliwy dostęp do łącza.
Algorytmami tymi są przede wszystkim kolejkowanie priorytetowe i sprawiedliwe. Można też
odnaleźć wśród nich elementy klasowości.
Powstała również zupełnie nowa grupa produktów sieciowych – wyspecjalizowane
urządzenia pozwalające na lepsze zagospodarowanie dysponowanej przepustowości, tzw.
„traffic shapers” lub „traffic tuner”. Producentami oferującymi te rozwiązania są przykładowo
Allot Communications oraz Packeteer Inc.. Opracowują oni własne algorytmy kolejkowania
bazujące na kolejkach klasowych.
Kształtowanie ruchu nie musi jednak wiązać się z zakupem drogich urządzeń. Do zastosowań
o małym wymiarze takich jak sieć w domu czy małym biurze wystarcza wybranie
odpowiedniego oprogramowania kształtującego ruch. Zwykłe „biurkowe” systemy
operacyjne posiadają bowiem szereg mechanizmów pozwalających na dość prostą
implementację tego zagadnienia. Przykładowe rozwiązanie polega na przeznaczeniu jednego
z komputerów na router zdolny odpowiednio zarządzać pakietami.
Użyte oprogramowanie może stanowić sterownik napisany specjalnie na potrzeby niniejszej
pracy. Załączone testy wskazują na jego przydatność i szerokie możliwości konfiguracji przy
zarządzaniu przepustowością. Każdy użytkownik Internetu wie jak uciążliwą staje się praca
ze źle zagospodarowanym łączem. Dzięki zastosowaniu tego programu możliwe staje się
pobieranie z sieci dużych plików, przy jednoczesnym zapewnieniu dobrego działania
wszystkich innych usług sieciowych takich jak poczta elektroniczna, Telnet czy WWW.
Wspomniany program wykorzystuje ułatwiającą pisanie sterowników sieciowych, bibliotekę
NDIS w systemach Microsoft Windows.
62
Załącznik 1 Instrukcja użytkownika programu „BandMan”
Przeznaczenie programu
Program „BandMan – Menadżer Przepustowości” utworzony został na potrzeby pracy
„Kształtowanie ruchu w sieciach komputerowych”. Jego głównym zadaniem jest ustalenie
reguł na dostęp do łącza sieciowego dla różnych klas ruchu. Przepływy takie można
zdefiniować dla każdego z interfejsów sieciowych z osobna. Obsługiwanymi typami medium
są:
• Ethernet
• WAN
• FDDI
• Token Ring
Program potrafi rozróżnić dowolną ilość klas na podstawie takich charakterystyk jak:
• adresy IPv4 źródłowy i docelowy z możliwością określenia całej sieci
• typu protokołów wykorzystujących IP
• Numery portów TCP/UDP
Poszczególne przepływy można grupować w drzewiastą hierarchię klas. Pomiędzy klasami
dostępny jest mechanizm pożyczania przepustowości.
63
Wymagania
Podstawowym wymogiem stawianym przed użytkownikiem chcącym korzystać z programu
„BandMan” jest posiadanie przez niego komputera klasy minimum Pentium 2 ze 128 MB
pamięci. Przy instalacji automatycznej konieczne jest posiadanie 5MB wolnego miejsca na
dysku twardym. Sam program zajmuje mniej niż 1 MB.
Na komputerze musi być też zainstalowany systemem operacyjnym Microsoft Windows XP.
Program nie wymaga żadnych dodatków i uaktualnień typu ServicePack.
Instalacja
Uwaga! Proces instalacji sterownika może przerwać na kilka chwil połączenia sieciowe.
Instalacja automatyczna
W celu automatycznego zainstalowania programu należy posłużyć się programem
instalacyjnym umieszczonym na dołączonym dysku CD-ROM w katalogu Instalacja.
Ręczny proces instalacji
Znajomość ręcznego procesu instalacji przydatna jest przede wszystkim w procesie tworzenia
i rozbudowy programu. Ten sposób jest jednak równie dobry jak instalacja automatyczna.
W celu ręcznego zainstalowania programu „BandMan” należy wykonać niżej wymienione
czynności.
• Przekopiowanie zawartości katalogu „Binaria” znajdującego się na dysku CD-ROM do
dowolnego utworzonego wcześniej folderu na dysku twardym. Może to być przykładowo
C:\Program Files\BandMan.
• Zainstalowanie sterownika, który znajduje się wśród przekopiowanych plików. W tym
celu należy otworzyć folder „Połączenia sieciowe” i dla dowolnego adaptera wybrać jego
właściwości. Ukaże się wówczas okno ukazane na poniższej ilustracji. Zawartość okna w
zależności od rodzaju zainstalowanych usług może być inna.
64
Rysunek 18 Aplet właściwości połączenia sieciowego
• W oknie właściwości połączenia należy wybrać opcję zainstaluj. Ukaże się wtedy
następujące okno wyboru rodzaju komponentu, który ma zostać zainstalowany.
Rysunek 19 Dodawanie usługi sieciowej
65
• Jako typ składnika sieci należy wybrać usługę, następnie wskazać katalog, w którym
umieszczono program.
• Podczas instalowania sterownika może ukazać się ekran ostrzegający o tym, że sterownik
nie przeszedł jeszcze testów pozwalających na otrzymanie tzw. „Logo Windows”.
Komunikat ten ma postać ukazaną na poniższej ilustracji i może ukazywać się
kilkakrotnie w zależności od liczby zainstalowanych urządzeń sieciowych.
Rysunek 20 Komunikat o zgodności z systemem Windows XP
• Dla każdego z tych komunikatów należy wybrać „Mimo to kontynuuj”
• Po zainstalowaniu w oknie „Właściwości połączenia” powinien ukazać się zainstalowany
sterownik. Zostało to ukazane poniżej.
66
Rysunek 21 Aplet właściwości po zainstalowaniu sterownika
• Proces instalowania sterownika wystarczy przeprowadzić jednokrotnie.
Po wykonaniu powyższych czynności można już przystąpić do pracy z programem.
Uruchamianie i wyłączanie programu
Program uruchamia się poprzez plik wykonywalny BandMan.exe znajdujący się w głównym
katalogu instalacji.
Należy zauważyć, że usługa kształtowania przepustowości jest aktywna tylko podczas
działania programu. Po wyłączeniu aplikacji połączenia sieciowe zachowują się tak jak przez
instalacją programu. Nie trzeba więc za każdym razem instalować i usuwać sterownika chcąc
włączyć i wyłączyć kształtowanie ruchu.
67
Polecenia menu
W menu „plik” dostępne są następujące opcje:
• „Zapisz” – powoduje zapisanie bieżącej konfiguracji w sterowniku oraz w głównym
pliku konfiguracyjnym programu – config.ini – znajdującego się w katalogu głównym
programu.
• „Import” – umożliwia odczytanie konfiguracji z dowolnego pliku konfiguracyjnego.
Zmiany nie są jednak zapisywane w sterowniku ani w głównym pliku konfiguracyjnym.
• „Export” – zapisuje bieżącą konfigurację w wybranym pliku. Zmiany nie są jednak
zapisywane w sterowniku ani w głównym pliku konfiguracyjnym.
• „Koniec” – wyłącza program i kształtowanie ruchu. Jeśli od ostatniego zapisu
wprowadzono jakieś zmiany wówczas program powiadomi o tym użytkownika.
Konfiguracja
Po uruchomieniu programu BandMan.exe, użytkownikowi ukazuje się okno dialogowe, które
po lewej stronie zawiera drzewko ze strukturą interfejsów i klas. Po prawej stronie okna
umieszczono formularz zawierające opcje dotyczące wybranego w drzewie węzła.
Istnieje kilka typów węzłów w drzewie.
Interfejsy
Węzeł ten grupuje wszystkie adaptery jakie występują w danym komputerze.
Węzeł adaptera
Przechowuje najważniejsze informacje dotyczące danego urządzenia sieciowego.
Przykładowy ekran umieszczono na poniższym rysunku.
68
Rysunek 22 Właściwości adaptera
Na ekranie tym znajdują się następujące informacje:
• Nazwa – nazwa urządzenia dostarczana przez jego producenta
• Wirtualny adapter – identyfikator wirtualnego adaptera udostępnianego dla sterowników
wyższego poziomu.
• Dolny adapter – identyfikator niżej położonego adaptera.
• Typ medium – może to być 802.3 czyli Ethernet, 802.5 – Token Ring, FDDI lub WAN.
• Adres sieciowy – adres warstwy sieciowej czyli np. adres protokołu IP.
• Adres MAC – adres urządzenia
• Stan – stan urządzenia: połączony/rozłączony
W miarę następowania zmian we właściwościach adapterów, są one także ukazywane na
liście w programie „BandMan”.
69
We/Wy
Ekran umożliwia włączenie kształtowania ruchu tylko dla poszczególnych interfejsów
wyjściowych lub wejściowych adapterów.
Rysunek 23 Włączanie kształtowania ruchu dla interfejsu
Klasy
W programie możliwe jest tworzenie hierarchicznej struktury klas ruchu. Struktura ta może
mieć maksymalnie 8 poziomów. Korzeń klasy umieszczony jest na poziomie 7, zaś liść na
poziomie 0. Wszystkie klasy pomiędzy liśćmi a korzeniem mają poziom o jeden niższy niż
ich rodzice. Istnieją dwa podstawowe typy klas:
• Klasy wewnętrzne – na poniższej ilustracji oznaczono te klasy nazwami „Root” oraz „b”.
Są nimi klasy posiadające inne podklasy. Klasy wewnętrzne nie mogą mieć bezpośrednio
filtrów.
• Klasy liście – na rysunku nadano im nazwy „a”, „c” i „d”. Klasy te nie posiadają podklas i
można dołączać do nich filtry.
70
Poniżej ukazano ekran dotyczący klasy wewnętrznej.
Rysunek 24 Właściwości klasy wewnętrznej
Widać tutaj, że każdej klasie można przypisać nazwę. Nazwa ta może być dowolna i powinna
jak najlepiej opisywać klasę. Może mieć ona do 255 znaków.
Dla klas wewnętrznych aktywne są dodatkowo następujące pola:
• Zapewniona przepustowość – umożliwia wprowadzenie wartości przepustowości jaką
klasa wewnętrzna może udostępniać klasom leżącym poniżej, bez konieczności
pożyczania przepustowości od wyżej położonych klas wewnętrznych.
• Maksymalna przepustowość – przed osiągnięciem tej wartości, klasa może udostępniać
własne zapasy przepustowości lub pożyczać przepustowość od wyżej położonych klas.
Wartości te muszą być całkowite z przedziału od 0 do 1000000. Można je wprowadzić w
bitach, kilobitach lub megabitach na sekundę co określa się stosując przełączniki „bit/s”,
„Kbit/s”, „Mbit/s”.
Przepustowość maksymalna nie ma znaczenia dla korzenia drzewa klas.
71
• Rozmiar wiadra – pozwala określić maksymalną liczbę bajtów, które klasa wewnętrzna
umożliwi wysłać naraz pożyczając przepustowość, gdy zgromadzi pełną pulę żetonów.
Parametr może być określony dla przepustowości zapewnionej i szczytowej. Należy
zwiększać rozmiar wiadra przy ustalaniu dużych limitów prędkości. Domyślne 0 oznacza,
że program automatycznie dobierze odpowiedni rozmiar wiadra jako MTU (maksymalny
rozmiar pakietu) plus pewną wielkość zależną od przepustowości.
Kolejny rysunek przedstawia formularz przeznaczony dla klasy liścia.
Rysunek 25 Właściwości klasy liścia
Znaczenie tych parametrów, które zostały udostępnione dla klasy wewnętrznej jest tutaj
podobne. Różnicę stanowi fakt, że zapewniona przepustowość, jest wykorzystywane przez
klasę liść do wysyłania pakietów. Nie służy natomiast do pożyczania.
Spośród pozostałych parametrów należy wymienić:
• „Priorytet” – oznacza porządek w jakim klasy będące w stanie pożyczać przepustowość
od swojego rodzica, mogą otrzymać przydziały tej przepustowości. Zawsze klasy o
najniższym liczbowo priorytecie maja w procesie pożyczania pierwszeństwo. Więcej
72
szczegółów na ten temat można odnaleźć w przeprowadzonym teście dotyczącym
parametru priorytet w załączniku „Testy programu”. W programie można określić
maksymalnie 8 różnych priorytetów.
• „Długość kolejki” – oznacza liczbę pakietów jakie gromadzone są w kolejce FIFO.
Pakiety, które nie mieszczą się w kolejce są odrzucane. Parametr ten może należeć do
zakresu liczb całkowitych od 2 do 20.
• „Kwant” – pozwala określić ile bajtów danych dana klasa może wysłać zanim zacznie
wysyła kolejna klasa, która jest tak samo do tego uprawniona. Klasy równouprawnione do
wysyłania to takie, które maja ten sam priorytet i wysyłają pakiety same lub pożyczając
przepustowość od klas leżących na tym samym poziomie.
• Pole „domyślna” oznacza czy do klasy mogą być przypisywane wszystkie pakiety nie
sklasyfikowane przez żadną inną klasę. Oznacza to, że tylko jedna klasa w interfejsie
wejściowym lub wyjściowym może mieć status „domyślna”.
• Przycisk „nowa podklasa” pozwala na rozbudowywanie hierarchii klas. Wszystkie filtry
utworzone dla bieżącej klasy zostaną przeniesione do nowej klasy.
• Dodawanie filtru do klasy odbywa się przez wciśnięcie przycisku „nowy filtr”. Możliwe
jest tworzenie dowolnej liczby filtrów.
Filtry
Filtry pozwalają określić jakie pakiety mają przynależeć do danej klasy. Bez przypisania
filtrów dana klasa jest bezużyteczna chyba, że została określona jako domyślna.
Wszystkie filtry sprawdzane są dla pakietu kolejno patrząc od góry. Pierwszy filtr, do którego
pakiet pasuje definiuje przypisanie pakietu do odpowiedniej klasy.
Mając to na uwadze tworząc hierarchię klas, najlepiej rozpoczynać jej budowę od klas o
wąskim zakresie i stopniowo przechodzić do ogólniejszych.
73
Poniżej ukazano przykładowy ekran dotyczący filtra.
Rysunek 26 Właściwości filtra
Każdy filtr można dezaktywować bez potrzeby jego usuwania za pomocą pola „włączony”.
Filtrom można też nadawać nazwy. Nie są one istotne i mogą być dowolne. Pomagają jednak
łatwo zorientować się, jakiego typu ruch dany filtr definiuje.
74
Poniżej opisano poszczególne opcje dotyczące filtrów.
• Na liście „adresy IP” można umieszczać dowolną liczbę pozycji. Wprowadzone adresy
porównywane są z adresami w pakiecie w sposób alternatywny. Oznacza to, że gdy choć
jeden adres się zgadza, wówczas dany pakiet pasuje do filtra i można przejść do
sprawdzenia pozostałych charakterystyk.
• Przy porównywaniu adresów dużą ważną odgrywa maska, która definiuje, jakie bity
adresów są porównywane. Zerowa maska określa dowolny adres. Również pusta lista
adresów oznacza dowolny adres IP.
• Lista „protokoły IP” pozwala zdefiniować dowolną liczbę protokołów, dla których filtr
ma być aktywny. Brak protokołów na liście „wybrane” oznacza dowolny protokół.
• Gdy jako protokół zostały wybrane TCP lub UDP wówczas możliwe jest także określenie
jakich dokładnie portów filtr ma dotyczyć. Porty należy umieszczać na liście „wybrane” w
grupie „porty TCP/UDP”, a ich brak oznacza dowolne porty.
Usuwanie programu z systemu
Uwaga! Proces usuwania sterownika może przerwać na kilka chwil połączenia sieciowe.
Usuwanie automatyczne
W przypadku gdy program zainstalowano w sposób automatyczny, wówczas możliwe jest też
jego automatyczna usunięcie. W tym celu należy skorzystać z apletu „Dodaj lub usuń
programy” w menu „Panel sterowania”.
Ręczny proces usuwania
Jeśli program został zainstalowany tak jak opisano w punkcie „Ręczny proces instalacji”,
wówczas należy go również usuwać w sposób samodzielny. W tym celu trzeba skasować
katalog, do którego przekopiowano pliki z programu.
Kolejnym etapem jest usunięcie samego sterownika. Aby tego dokonać należy otworzyć aplet
„właściwości” dowolnego połączenia znajdującego się w folderze „Połączenia sieciowe”.
Powinien wówczas ukazać się ekran podobny do poniższego.
75
Rysunek 27 Wyszukiwanie sterownika w aplecie właściwości adaptera
Po wybraniu składnika „BandMan Driver” należy wcisnąć przycisk „odinstaluj”. To
spowoduje usunięcie sterownika z systemu.
76
Załącznik 2 Dokumentacja techniczna programu
Wprowadzenie
Niniejsza dokumentacja dotyczy sterownika oraz programu użytkownika napisanych na
potrzeby pracy magisterskiej „Kształtowanie ruchu w sieciach komputerowych”.
Sterownik został utworzony na bazie przykładowego sterownika pośredniego o nazwie
„Passthru” dostarczonego przez firmę Microsoft wraz z Device Driver Kit. Ten przykład
stanowi szkielet zawierający podstawowe procedury jakie sterownik pośredni musi zawierać.
Jego działanie polega jedynie na przekazywaniu pakietów pomiędzy sterownikami
miniportów a protokołów. Oznacza to, że jest on właściwie przezroczysty dla systemu.
Program zarządzający napisano w całości od podstaw przy wykorzystaniu biblioteki MFC.
Struktura projektu
W skład głównego projektu utworzonego przy pomocy Microsoft Visual Studio .NET 2002
wchodzą dwa podprojekty. Pierwszy dotyczy sterownika drugi zaś programu zarządzającego.
Dokładną listę plików wraz z opisami można odnaleźć w dodatkowej dokumentacji
sporządzonej przy wykorzystaniu programu „Doxygen” [DOX] ze źródeł programu.
Warto jednak zwrócić uwagę na fakt, że kilka plików stanowi część wspólną dla tych
projektów. Są nimi iocommon.h oraz io_trans.h. Plik iocommon.h zawiera wszystkie kody
komunikatów, jakie są przekazywane pomiędzy obydwoma programami. Z kolei plik
io_trans.h definiuje struktury danych, które programu użytkownika wysyła do sterownika w
procesie konfiguracji.
77
Budowa sterownika
W skład kodu źródłowego sterownika wchodzi kilka modułów. Poniżej wymieniono te
moduły wraz z krótkimi informacjami.
Podstawowy moduł składa się z plików: passthru.c, protocol.c i miniport.c. Tworzą one
szkieletową strukturę sterownika dostarczoną wraz z przykładem Microsoftu – „Passthru”.
Moduł zawiera funkcje takie jak:
• DriverEntry stanowiącą punkt wejściowy sterownika. Funkcja ta jest odpowiedzialna
za powiązanie procedur sterownika z biblioteką NDIS, czyli za tzw. „serializację”.
• zbiór funkcji PtXxx charakterystycznych dla sterownika protokołu. W skład tych funkcji
wchodzi między innymi procedura PtReceive, wywoływana przy odbieraniu pakietu,
która posiada szczególne znaczenie dla kształtowania ruchu.
• zbiór funkcji MPXxx charakterystycznych dla sterownika miniportu. W skład tych funkcji
wchodzi między innymi procedura MPSendPackets, wywoływana przy wysyłaniu
pakietów. Posiada ona szczególne znaczenie dla kształtowania ruchu.
W module podstawowym znajduje się także definicja struktury o identyfikatorze ADAPT,
która zawiera zmienne dotyczące pojedynczego adaptera sieciowego. Między innymi jej
składowymi są dwie struktury typu sched_interface, służące do przechowywania
zmiennych związanych z modułem zarządzającym przepustowością.
W sterowniku tworzona jest lista struktur typu ADAPT, po jednej dla każdego adaptera.
Ponadto do funkcji wywoływanych w kontekście któregoś z adapterów, czyli np. przy
odbieraniu czy wysyłaniu przez niego pakietu, przekazywana jest odpowiadająca mu struktura
ADAPT.
Moduł ptextend.c stanowi rozszerzenie modułu podstawowego. Główna jego część została
zapożyczona z innego przykładowego sterownika dostępnego na stronie [WD3]. Wzbogaca
on sterownik „Passthru” o mechanizm zliczania referencji struktur ADAPT, reprezentujących
adaptery (funkcje PtRefAdapter oraz PtDerefAdapter). Zliczanie referencji
zapobiega usunięciu struktury adaptera z pamięci, gdy jeszcze istnieją do niego odwołania.
Plik ptextend.c zawiera też pomocniczą metodę wyszukującą adapter o podanej nazwie
(funkcja PtLookupAdapterByName) oraz zestaw procedur służących do prowadzenia
78
komunikacji z programem użytkownika. Procedury te obsługują kilka standardowych
zdarzeń, które mogą wystąpić przy komunikacji i są nimi:
• DevOpen – uruchamiana podczas otwierania uchwytu do sterownika w programie
użytkownika (przez wywołanie funkcji CreateFile);
• DevClose – wywoływana przy zamykaniu uchwytu przez aplikację;
• DevIoControl – reaguje na wysłanie żądania z odpowiednim kodem IOCTL do
sterownika (wywołanie funkcji DeviceIoControl). Na podstawie kodu operacji
procedura wywołuje z kolei odpowiednią funkcję, która tylko jego dotyczy.
Modułami, które zostały utworzone specjalnie na potrzeby niniejszej pracy są: duio.c,
irpqueue.c, shed.c wraz z shed_priv.c.
Plik duio.c zawiera dodatkowe funkcje służące do komunikacji sterownik – aplikacja
zarządzająca. Jest wykorzystywany przez moduł ptextend.c do obsługi poszczególnych żądań
użytkownika. Najważniejszymi funkcjami, które w nim zostały zdefiniowane są:
• duio_get_new_adapt_name – funkcja ta odpowiada na synchroniczne zapytania
programu o nowy adapter przekazując jego nazwę. Kiedy nie ma już żadnego nowego
adaptera przesyła do programu użytkownika pusty łańcuch. Sformułowanie nowy adapter
oznacza, że nie jest on znany przez sterownik. Po załadowaniu, sterownika struktury
adapterów są inicjowane jako nowe. W chwili kiedy program rozłącza się ze
sterownikiem wszystkie adaptery także stają się z powrotem nowe.
• duio_conf_interface – obsługuje synchroniczne żądanie skonfigurowania
interfejsu wejściowego lub wyjściowego przez sterownik. Gdy nie ma interfejsu, funkcja
zwraca do aplikacji status błędu i wówczas może ona usunąć taki adapter ze swojej listy
adapterów. Jeśli interfejs został znaleziony, następuje jego konfiguracja i odpowiadający
mu adapter przestaje być nowy. Sam proces konfiguracji polega na wywołaniu funkcji
sched_on_configure, która znajduje się w module sched.c i przekazanie jej całego
bufora powiązanego z żądaniem IRP.
• duio_on_change_adapt – służy do asynchronicznych powiadomień wysyłanych
przez sterownik, które oznaczają dodanie nowego adaptera do listu lub usunięcie go z niej.
79
Dzięki tym powiadomieniom program jest w stanie utrzymać stale aktualną listę
adapterów.
• duio_on_unload_driver – pozwala na asynchroniczne przekazanie do programu
informacji o odłączeniu sterownika przez system. Jest to ważne ponieważ otwarte
uchwyty do sterownika uniemożliwiają jego usunięcie.
Kolejny moduł – irpqueue.c – zawiera implementację pomocniczego mechanizmu o nazwie
Cancel-Safe Queue, który jest wbudowany w DDK i pozwala na standardowe zarządzanie
żądaniami IRP. Moduł ten definiuje pewne elementarne operacje na kolejce z IRP, jakie
biblioteka obsługująca Cancel-Safe Queue może wywołać. Dzięki temu mechanizmowi
możliwe jest gromadzenie w prosty i uporządkowany sposób komunikatów IRP, które
sterownik wykorzystuje do powiadamiania programu użytkownika.
Ostatni z modułów sched.c i jego prywatna część sched_priv.c zawierają wszystkie elementy,
które zostały wykorzystywane do implementacji kolejki HTB zarządzającej przepustowością.
W pliku shed.c umieszczono wszystkie funkcje, jakie mogą być wywoływane w innych
częściach sterownika. Z kolei funkcje z sched_priv.c wykonywane są wyłącznie w sched.c.
Podstawowymi funkcjami stanowiącymi publiczny interfejs do kolejki HTB są:
• sched_on_init – umożliwia inicjalizację kolejki dla każdego interfejsu, w chwili gdy
tworzona jest nowa struktura adaptera;
• sched_on_configure – dokonuje konfiguracji kolejki interfejsu na podstawie
danych przekazanych z programu użytkownika;
• sched_on_stop – pozwala na zatrzymanie działania kolejki w chwili gdy program
użytkownika zamknął połączenie ze sterownikiem;
• sched_on_destroy – usuwa strukturę kolejki dla interfejsu przy usuwaniu adaptera
sieciowego;
• sched_on_enqueue – umieszcza pakiet w kolejce HTB. Wywoływana przy
odbieraniu i wysyłaniu pakietu.
Więcej na temat tych funkcji można przeczytać w podrozdziale „Funkcja kształtowania
ruchu” oraz w dokumentacji wygenerowanej z kodu programu.
80
Budowa aplikacji użytkownika
Podstawowym komponentem tworzącym program użytkownika jest obiekt głównego okna
dialogowego klasy CMainDialog.
Składową tego obiektu jest między innymi kontrolka drzewa zawierająca dane dotyczące
poszczególnych interfejsów, klas oraz filtrów. Dane każdego z tych elementów
przechowywane są wewnątrz węzłów drzewa jako wskaźniki do obiektów klas
CXxxFormData. Wszystkie klasy CXxxFormData posiadają wspólnego przodka – klasę
CFormaData. Obiekty zawierające dane węzłów potrafią zapisać te dane i odczytać je ze
struktury przechowywanej w pliku, a także przekazać je do bufora z konfiguracją sterownika.
Kolejnym ważnym polem w oknie dialogowym jest też tablica obiektów reprezentujących
formularze dotyczące poszczególnych węzłów w drzewie. Obiekty te są przedstawicielami
klas CXxxForm, które dziedziczą po klasie CCommonForm. CCommonForm jest z kolei
potomkiem CFormView należącej do biblioteki MFC. Klasy z tej rodziny posiadają metody
umożliwiające przenoszenie danych pomiędzy ich kontrolkami a odpowiednimi obiektami
klas CXxxFormData.
Dzięki takiej strukturze możliwe jest wyświetlenie dla każdego typu węzła w drzewie
odpowiedniego formularza, który zawiera dane tego węzła. Umożliwia to także dość szybkie
dodawanie nowych parametrów do klas i filtrów. W celu rozbudowy formularzy o dodatkowe
pole należy wykonać kilka czynności, którymi są:
1. dodanie kontrolki w edytorze zasobów do formularza;
2. utworzenie zmiennej odnoszącej się do tej kontrolki w klasie CXxxForm formularza;
3. dodanie pola dotyczącego tej kontrolki w klasie CXxxFormData. Zmienna ta pozwoli na
zapamiętanie wartości nowej zmiennej dla różnych węzłów drzewa;
4. napisanie instrukcji przenoszących dane pomiędzy obiektami klas CXxxForm a
CXxxFormData. Instrukcje te muszą znajdować się w funkcjach LoadForm i
SaveForm klasy CXxxForm, które używane są odpowiednio przy pokazywaniu i
ukrywaniu formularza;
5. dodanie instrukcji zapisujących i odczytujących zmienną z pliku w funkcjach
BuildFromFile i DumpToFile w klasie CXxxFormData;
81
6. utworzenie zmiennej w strukturze sched_trans_xxx służącej do przenoszenia danych
węzła drzewa z aplikacji do sterownika;
7. napisanie instrukcji przenoszącej wartość zmiennej z CXxxFormData do
sched_trans_xxx wewnątrz procedury Dump klasy CXxxFormData;
8. dodanie zmiennej do struktury sched_xxx;
9. wprowadzenie instrukcji przenoszących zmienną z sched_trans_xxx do
sched_xxx w funkcjach sched_init_xxx.
W powyższym opisie xxx oznacza „class”/”Klasa” albo „filter”/”Filtr”. Po wykonaniu tych
czynności będzie można zapisywać wartość z formularza w odpowiednich strukturach
wewnątrz sterownika.
W programie użytkownika oprócz wątku głównego okna dialogowego, pracuje również
dodatkowy wątek InputThread służący do odbierania asynchronicznych powiadomień od
sterownika. Po odebraniu takich notyfikacji wątek wysyła do okna dialogowego odpowiednią
wiadomość używając funkcji PostMessage, a następnie ponawia żądanie kolejnych
komunikatów przy użyciu DeviceIoControl.
Zarządzanie pakietami
Poniżej opisano zasady jakimi kieruje się sterownik przy odbieraniu i wysyłaniu pakietów.
Procesy te nie są traktowane przez bibliotekę NDIS tak samo. Szczegółowe informacje na ten
temat można także odnaleźć w dokumentacji wygenerowanej z kodu źródłowego programu.
Wysyłanie pakietów
Sterownik pośredni w funkcji MPSendPackets odbiera od sterownika położonego wyżej
tablicę z deskryptorami pakietów (NDIS_PACKET), które mają zostać przesłane przez sieć.
Aby móc umieścić takie pakiety w kolejce HTB korzystając z funkcji
sched_on_enqueue, należy wcześniej utworzyć kopię każdego deskryptora w puli
deskryptorów służących do wysyłania. W nowym pakiecie w polu ProtocolReserved
zapamiętujemy oryginalny pakiet aby móc go później zwrócić sterownikowi powyżej.
82
Wyjątkiem od tego obowiązku jest sytuacja, gdy możliwe staje się wykorzystanie techniki
„packet stacking”. Wówczas deskryptorami zarządza sama biblioteka NDIS i nie trzeba ich
kopiować, ponieważ cały czas używany jest jeden deskryptor dla całego stosu sterowników.
Przygotowany deskryptor trafia następnie do kolejki HTB, gdzie oczekuje na wysłanie. Gdy
nadejdzie ta chwila, wewnątrz funkcji sched_pass_packet_dn w kontekście procedury
wątku dekolejkującego sched_dequeue_thread_proc, następuje wysłanie pakietu
przy pomocy funkcji NdisSend.
Po zakończeniu wysyłania należy wywołać funkcję NdisMSendComplete, która
poinformuje sterownik wyżej położony, że może zwolnić bufory zarezerwowane dla pakietu.
Wywołanie NdisMSendComplete może nastąpić gdy:
• chcemy odrzucić pakiet,
• zaraz po zakończeniu NdisSend, gdy funkcja ta zwróci STATUS_SUCCESS,
• wewnątrz PtSendComplete, gdy wysłanie nie zostało przeprowadzone natychmiast
(status powrotu – NDIS_STATUS_PENDING). Biblioteka NDIS wywołuje
PtSendComplete automatycznie, gdy niższy sterownik zakończy wysyłanie pakietu.
Jest to jedna ze standardowych procedur dla sterownika protokołu.
Po wysyłaniu pakietu możemy również usunąć utworzony w lokalnej puli deskryptor pakietu,
jeśli nie używano „packet stacking”. Przydatna w tym miejscu okazuje się być umiejętność
rozpoznania czy pakiet został utworzony w puli, czy też użyto „packet stacking”. Można w
tym celu posłużyć się funkcją dla biblioteki NDIS 5.1 NdisGetPoolFromPacket, która
podaje uchwyt do puli zawierającej deskryptor.
Odbieranie pakietów
Biblioteka NDIS powiadamia sterownik pośredni o odebraniu nowego pakietu w funkcji
PtReceive lub PtReceivePacket, przy czym druga z tych funkcji jest opcjonalna
jednak usprawnia proces odbierania pakietów.
W funkcji PtReceive odebrany pakiet ma postać dwóch buforów. Jeden z nich zawiera
nagłówek pakietu, drugi zaś początkową jego część. Istotne jest to, że do buforów tych nie
można odwołać się poza kontekstem funkcji PtReceive. Aby temu zaradzić i móc dodać
83
do kolejki tak odebrany pakiet, należy utworzyć strukturę pakietu NDIS oraz powiązany z nią
bufor od początku.
W tym celu trzeba utworzyć nowy deskryptor pakietu, zarezerwować bufor dla zawartości
całego pakietu oraz utworzyć nowy deskryptor tego bufora. Dodatkowo jeśli niżej położony
sterownik udostępnia własny deskryptor pakietu, co można sprawdzić wywołując procedurę
NdisGetReceivedPacket, wówczas do nowego deskryptora należy przekopiować jego
pola tzn.: dane out-of-band, flagi oraz informacje dotyczące medium. Ponadto w nowym
deskryptorze należy ustalić wartość kilku jego dodatkowych parametrów. Szczegóły można
znaleźć w wygenerowanej ze źródeł sterownika dokumentacji.
Jeśli powiadomienie w PtReceive dotyczyło tylko początkowej części pakietu, wówczas
sterownik pośredni musi zlecić sterownikowi położonemu niżej transfer pozostałych danych.
Dokonuje tego używając NdisTransferData. Biblioteka NDIS informuje o zakończenie
kopiowania przez wywołanie funkcji sterownika pośredniego PtTransferComplete. W
tym miejscu można dopiero dodać pakiet do kolejki HTB poprzez wykonanie procedury
sched_on_enqueue.
W przypadku funkcji PtReceivePacket biblioteka NDIS powiadamia sterownik o
odebraniu całego pakietu w formie struktury NDIS_PACKET. Należy jednak zwrócić uwagę
na kilka elementów. Jeśli przekazany pakiet ma status NDIS_STATUS_RESOURCES,
oznacza to, że jest on ważny tylko w kontekście tej funkcji i aby móc dodać go do kolejki,
trzeba utworzyć od nowa cały pakiet. W innym przypadku jeśli nie można zastosować
„packet stacking” wystarczy jedynie utworzyć nowy deskryptor pakietu i skopiować do niego
oryginalne dane, a także zapamiętać oryginalny deskryptor. Przygotowany pakiet
umieszczany jest w kolejce za pomocą sched_on_enqueue.
W chwili gdy wątek dekolejkujący stwierdzi, że pakiet ma zostać przekazany do sterownika
położonego powyżej, wykonuje funkcję NdisMIndicateReceivePacket. Zasoby
związane z pakietem można zwolnić wewnątrz procedury MPReturnPacket,
uruchomionej gdy sterowniki protokołów zakończą obsługę odbierania pakietu i każdy z nich
wywoła NdisReturnPackets. Istnieje kilka scenariuszy zwalniania zasobów przez sterownik
pośredni.
1. Sterownik zwalnia deskryptory pakietu i bufora oraz pamięć przydzieloną na bufor. Ma to
miejsce, gdy deskryptor należy do lokalnej puli i nie zapamiętano w nim oryginalnego
pakietu.
84
2. Sterownik zwalnia tylko deskryptor. Należy to wykonać, jeśli w deskryptorze
zapamiętano oryginalny pakiet.
3. Sterownik nie zwalnia zasobów, jeżeli wykorzystywano „packet stacking” czyli
deskryptor nie należy do lokalnej puli.
Jeśli sterownik pośredni wykorzystywał części pakietu, które do niego nie należą, to oprócz
zwalniania własnych zasobów musi też, korzystając z NdisReturnPackets, zwrócić zasoby
będące własnością niżej położonego sterownika. Ma to miejsce w przypadku scenariusza 2
oraz 3.
Komunikacja sterownik – program użytkownika
Program komunikuje się ze sterownikiem wykorzystując standardowy interfejs
wejścia/wyjścia dostępny w systemie Windows. Mechanizm ten bazuje na przesyłaniu do
sterownika urządzenia pewnych żądań IRP (IO Request Packets).
Rodzaje komunikatów
Aby ustanowić tego typu połączenie sterownik musi najpierw zarejestrować w systemie
reprezentujące go urządzenie o określonej nazwie. Dokonuje tego poprzez jednokrotne
wywołanie funkcji NdisMRegisterDevice w kontekście procedury inicjalizującej
miniport MPInitialize. Następnie program użytkownika używając CreateFile tworzy
uchwyt do pliku reprezentującego sterownik. Jako nazwę pliku należy podać zarejestrowaną
wcześniej nazwę urządzenia. Od tej chwili program może wysyłać żądania IRP do sterownika
korzystając z funkcji DeviceIoControl.
Funkcja DeviceIoControl może pracować w dwóch trybach:
• synchronicznym, wówczas odpowiedź sterownika możemy odczytać natychmiast po
zakończeniu DeviceIoControl,
• asynchronicznym, wtedy sterownik odpowie w stosownym dla siebie czasie i w tym
wypadku należy zdefiniować zdarzenie, które wystąpi przy odpowiedzi sterownika.
Następujący schemat ilustruje jakie komunikaty przesyłane są pomiędzy sterownikiem a
aplikacją.
85
skonfiguruj interfejs podaj nowy adapter
Rysunek 28 Komunikacja sterownik – program użytkownika.
Na rysunku ciągłą linią oznaczono komunikaty związane z żądaniami synchronicznymi, zaś
przerywaną żądana asynchroniczne.
Każdy z przesyłanych komunikatów ma podobny format. Składa się z kodu operacji IOCTL,
bufora z parametrami oraz bufora na odpowiedź. Wszystkie kody IOCTL zostały
zdefiniowane w pliku iocommon.h. Poniżej omówiono główne zadania tych wiadomości.
• „skonfiguruj interfejs” – powoduje wysłanie do sterownika ustawień związanych z
zarządzaniem przepustowością. Zawiera nazwę identyfikującą adapter w formacie
UNICODE zakończoną znakiem NULL, rodzaj interfejsu (0 – wejściowy, 1 – wyjściowy)
oraz binarną reprezentację drzewa z klasami i filtrami. Po skonfigurowaniu sterownik
zaznacza odpowiedni adapter poprzez ustawienie jego zmiennej bNowy na FALSE.
Poniższy schemat przedstawia przykład ilustrujący sposób przekazywania struktury klas
od aplikacji do sterownika.
Sterownik
podaj informację o adapterze
Aplikacja usuń adapter
zażądaj powiadomienia
dodaj adapter usuwanie sterownika
86
Rysunek 29 Reprezentacja struktury klas
• „podaj nowy adapter” – zleca sterownikowi przesłanie nazwy adaptera, który nie został
jeszcze skonfigurowany, tzn. takiego, że jego zmienna bNowy jest równa TRUE. Jeśli
wszystkie adaptery zostały skonfigurowane, odpowiedzią jest pusty łańcuch.
• „podaj informację o adapterze” – pozwala na odczytanie z miniportu poszczególnych
parametrów takich jak jego opisowa nazwa, prędkość transmisji, adres MAC itp.
Komunikat tego typu składa się z nazwy identyfikującej adapter oraz kodu definiującego
właściwość miniportu, którą IRP ma odczytać.
• „zażądaj powiadomienia” – to żądanie jest typu asynchronicznego. Oznacza to że
aplikacja wykorzystując obiekt zdarzenia (event) powinna poczekać aż sterownik wykona
zleconą operację.
Dzięki temu żądaniu sterownik może powiadamiać aplikację o zajściu pewnych stanów
takich jak dodanie czy usunięcie adaptera lub też usunięcie sterownika. Musi jednak w
tym celu przechowywać takie żądania w specjalnej kolejce – Cancel-Safe Queue.
B
Root
Interfejs
A
C D
F1 F2 F3 F4
Hierarchia klas dla interfejsu: Bufor transportowy:
Dane interfejsu 1
Dane klasy Root 2
Dane klasy A 2
Dane klasy B 1
Dane filtra F1 0
Dane klasy C 2
Dane filtra F2 0
Dane klasy D 2
Dane filtra F3 0
Dane filtra F4 0
Liczba potomków węzła
87
Po zakończeniu żądania przez sterownik, aplikacja wysyła natychmiast kolejne. Dzięki
temu możliwa jest ciągłość komunikacji.
• „usuń adapter” i „dodaj adapter” – te dwa komunikaty pozwalają na asynchroniczne
powiadomienie aplikacji o usunięciu lub dodaniu adaptera. Składają się z nazwy adaptera
oraz kodu operacji: dodaj lub usuń. Do ich przesłania do aplikacji sterownik wykorzystuje
zgromadzone IRP typu „zażądaj powiadomienia”.
• „usuwanie sterownika” – dzięki temu asynchronicznemu powiadomieniu
wykorzystującemu oczekujące w kolejce IRP typu „zażądaj powiadomienia”, sterownik
może zlecić aplikacji zamknięcie uchwytu. Jest to niezbędne do prawidłowego usunięcia
sterownika z systemu. Jedynym parametrem komunikatu jest jego kod rozpoznawany
przez aplikację.
Algorytm komunikacji
1. Po załadowaniu sterownika inicjalizuje on w systemie urządzenie, które go reprezentuje.
W tym celu posługuje się funkcją NdisMRegisterDevice.
2. Aplikacja (wątek interfejsu użytkownika – UIT) otwiera uchwyt do sterownika. Jeśli
operacja nie powiodła się, program zostaje zamknięty z odpowiednim komunikatem błędu
(„nie można połączyć się ze sterownikiem”). O otwieraniu uchwytu sterownik zostaje
powiadomiony przez system w funkcji DevOpen.
3. UIT otwiera główny plik konfiguracyjny i w oparciu o niego tworzy drzewko interfejsów,
klas i filtrów.
4. UIT uruchamia wątek (WT) odpowiadający za asynchroniczną komunikację ze
sterownikiem i czeka aż ten wątek rozpocznie komunikację ze sterownikiem.
5. WT wysyła do sterownika komunikat „zażądaj powiadomienia”, który zleca
asynchroniczne powiadamianie o zmianach w adapterach. Sterownik kolejkuje zlecenie
IRP i wykorzysta je dopiero, gdy wystąpi taka potrzeba.
6. UIT dla każdego interfejsu (wejściowego i wyjściowego) w drzewku wysyła
synchroniczne polecenie „skonfiguruj interfejs”.
7. W odpowiedzi sterownik, jeśli znalazł odpowiedni adapter, konfiguruje wybrany interfejs
i ustawia pole adaptera bNowy na FALSE. Żądanie zostaje zakończone ze statusem
88
sukcesu. Jeśli nie znaleziono adaptera żądanie kończy się ze statusem błędu. W tej
sytuacji aplikacja może usunąć adapter ze swojego drzewa.
8. UIT wysyła synchroniczne zlecenie „podaj nowy adapter”. Sterownik rozpoczyna
przeglądanie listy adapterów w poszukiwaniu adaptera z ustawionym polem bNowy na
TRUE. Jeśli taki znajdzie przekazuje do aplikacji nazwę tego adaptera. Żądanie
ponawiane jest tak długo, aż sterownik zwróci pustą nazwę adaptera oznaczającą brak
nowych adapterów.
9. Następnie UIT może wysłać szereg żądań odczytania pewnych parametrów dotyczących
adapterów przy użyciu „podaj informację o adapterze”. Parametrami tymi mogą byś opis
adaptera w systemie, adres MAC itp.
10. Przy dodawaniu i usuwaniu adapterów sterownik asynchroniczne powiadamia o tym
aplikację wysyłając zgłoszenia „usuń adapter” i „dodaj adapter”. Po odebraniu każdego
takiego komunikatu aplikacja wysyła kolejne zlecenie „zażądaj powiadomienia”, co
pozwala na ciągłość komunikacji.
11. Gdy sterownik ma zostać odłączony wysyła on powiadomienie „usuwanie sterownika”.
Wtedy aplikacja zmyka uchwyt do sterownika i wyłącza się wyświetlając odpowiedni
komunikat (sterownik został odłączony).
12. W momencie zamykania uchwytu do sterownika system automatycznie wywołuje jego
funkcję DevClose i w jej kontekście wszystkie oczekujące pakiety zostają przesłane,
cała struktura klas zostaje usunięta, a sterownik staje się przeźroczysty dla transmisji
pakietów.
Funkcja kształtowania ruchu
Poniższy rozdział pozwala na łatwiejsze zrozumienie kodu kolejki kształtującej ruch. Przed
jego przeczytaniem wskazane jest zapoznanie się z algorytmem HTB opisanym w głównej
części pracy.
Funkcja kształtowania ruchu została zrealizowana w module sched.c oraz jego prywatnej
części sched_priv.c. Kolejkowanie pakietów następuje tylko, gdy program użytkownika jest
włączony. W innym wypadku sterownik nie wpływa na odbieranie i wysyłanie pakietów.
Cykl życia kolejki HTB zaimplementowanej w sterowniku składa się z kilku etapów.
89
Inicjalizacja
Kolejka zostaje utworzona wewnątrz procedury sched_on_init w kontekście funkcji
MPInitialize uruchamianej przez NDIS. Ma to miejsce przy inicjalizacji nowego
miniportu i powiązaniu go ze sterownikami wyższych warstw, czyli przede wszystkim
podczas instalowania sterownika.
Funkcja sched_on_init uruchamia wątek planujący wysyłanie pakietów, który następnie
oczekuje pod semaforem na rozpoczęcie pracy. Poza tym inicjalizuje listy priorytetowe i listy
oczekiwania na zmianę stanu przeznaczone dla klas, a także listę filtrów.
Uruchomienie i konfiguracja
Kształtowanie ruchu rozpoczyna się w chwili, gdy program użytkownika wysyła konfigurację
do sterownika. Wtedy uruchamiana jest funkcja sched_on_configure, która usuwa starą
strukturę klas i filtrów przy pomocy sched_destroy, a na podstawie danych z aplikacji
generuje nową strukturę. Wywołanie funkcji sched_on_configure może mieć miejsce
wielokrotnie, za każdym razem, gdy użytkownik zapisuje nową konfigurację.
Kolejkowanie
Do umieszczania pakietów w kolejce HTB służy funkcja sched_on_enqueue. Pakiet,
który jest do niej przekazywany musi spełniać warunki, aby mógł być przekazany do
sąsiedniego sterownika z kontekstu innej funkcji niż PtReceive, PtReceivePacket lub
MPSendPackets. Dokładne informacje na ten temat można przeczytać w rozdziale
„Zarządzanie pakietami”.
W funkcji kolejkującej pakiet podlega w pierwszym rzędzie klasyfikowaniu przez
zastosowanie sched_find_class. Polega to na sprawdzaniu, który z kolejnych filtrów
pasuje do pakietu. Przy obecnym stanie pakiety rozpoznawane są na podstawie adresów IP
oraz portów TCP/UDP. To czy filtr pasuje do pakietu czy nie określa procedura
sched_try_filter. Chcąc zwiększyć możliwości filtrów należy rozbudować właśnie tę
funkcję.
Jeśli żaden z filtrów nie pasuje do pakietu i nie wybrano klasy domyślnej pakiet jest
przesyłany natychmiast.
90
Po dodaniu pakietu do kolejki wybranej klasy następuje jej aktywacja przez wywołanie
sched_activate_class. Zadaniem tego procesu jest umieszczenie klasy na zewnętrznej
liście priorytetowej bezpośrednio, gdy klasa ma stan CAN_SEND, lub za pośrednictwem jej
przodków, jeśli klasa może jedynie pożyczać przepustowość – stan CAN_BORROW. W drugim
wypadku tworzony jest łańcuch klas „żółtych” przy pomocy wewnętrznych list
priorytetowych znajdujących się w klasach. Górny koniec tego łańcucha, jeśli ma stan
zielony, zostaje umieszczony na zewnętrznej liście priorytetowej.
Aktywowaniu klasy towarzyszy też zwolnienie semafora, pod którym oczekuje proces
dekolejkujący – sched_dequeue_thread_proc.
Dekolejkowanie
Wybieraniem pakietów z kolejki HTB i przesyłaniem i ich do sterowników położonych wyżej
lub niżej zajmuje się proces sched_dequeue_thread_proc.
Główna pętla procedury sched_dequeue_thread_proc działająca do chwili usunięcia
kolejki (zmienna logiczna working w strukturze sched_interface przyjmuje wartość
FALSE) wybiera po jednym pakiecie z odpowiedniej klasy. Klasę wyznacza algorytm HTB w
połączeniu z algorytmem DRR.
Pierwszą czynność, która jest wykonywana w celu wysłania pakietu, stanowi pobranie
aktualnego czasu. Obecnie czas wyznaczany jest w milisekundach od chwili uruchomienia
systemu, przy użyciu funkcji KeQueryTickCount. Możliwe jest dokładniejsze obliczanie
upływu czasu dzięki KeQueryPerformanceCounter, jednak specyfikacja Device Driver
Kit odradza zbyt częstego wykonywania tej funkcji.
W dalszym etapie przeglądana zostaje zewnętrzna lista priorytetowa od najniższego poziomu
i priorytetu w poszukiwaniu poddrzewa klas, z którego można wybrać pakiet. W celu
łatwiejszego określenia na którym poziomie i priorytecie w zewnętrznej liście priorytetowej
umieszczone są klasy, posłużono się dodatkową tablicą masek active_prios. Na każdym
z poziomów poszczególne bity maski określają, które priorytety są aktywne.
Dla każdego poziomu obsługiwane są też zdarzenia, polegające na zmianie stanu klasy
(funkcja sched_do_events).
Po odnalezieniu niepustej zewnętrznej listy priorytetowej stosuje się do niej funkcję
sched_dequeue_subtree. Procedura ta wyszukuje klasę do wysłania pakietu przy
91
zastosowaniu algorytmu DRR. Następnie jeśli w klasie nie ma już pakietów, zostaje ona
deaktywowana czyli usunięta z odpowiednich list priorytetowych.
Na końcu wewnątrz sched_charge_class zmieniane są liczby żetonów posiadane przez
klasę wysyłającą i jej przodków. Wiąże się to również ze zmianami stanów i umieszczaniem
klas na listach oczekiwania (sched_add_to_wait_queue) i ewentualną ich deaktywacją
przy osiągnięciu stanu czerwonego (sched_deactivate_class).
Po wysłaniu pakietu procedura sched_dequeue_thread_proc może oczekiwać na
semaforze przez czas potrzebny, by pewne klasy znów mogły wysyłać lub gdy pojawią się
nowe pakiety. Może także próbować wysłać kolejny pakiet od razu. Zależy to od tego czy w
listach oczekiwania są umieszczone klasy i czy kolejka HTB zawiera pakiety.
Zatrzymanie
Kształtowanie ruchu jest wstrzymywane w chwili, gdy program użytkownika zamyka uchwyt
reprezentujący połączenie ze sterownikiem. Następuje to w kontekście procedury DevClose
poprzez wywołanie sched_on_stop. Funkcja ta usuwa całą strukturę drzewa klas oraz
listę filtrów. Możliwe są wielokrotna konfiguracja i zatrzymanie kolejki.
Usunięcie
Wewnątrz procedury sched_on_destroy wywołanej w kontekście MPHalt następuje
wyłączenie wątku dekolejkującego oraz zwolnienie obiektu blokującego dostęp do interfejsu.
Usuwanie kolejki jest konsekwencją odłączenia adaptera np. przy odinstalowaniu sterownika.
92
Załącznik 3 Testy programu
Wprowadzenie
Poniżej przedstawiono kilka testów przeprowadzonych dla programu napisanego na potrzeby
pracy „Kształtowanie ruchu w sieciach”. Ukazują one działanie najistotniejszych parametrów
użytego algorytmu którym jest „Hierarchiczne wiadro z żetonami”. Szczegółowe informacje
na temat tego algorytmu można odnaleźć w głównej części pracy.
Do przeprowadzenia doświadczeń użyto sieci złożonej z dwóch komputerów. Zastosowano
dwa typy medium – Ethernet oraz połączenie przy pomocy kabla szeregowego (traktowane
przez system jako sieć WAN). Na jednym ze stanowisk został zainstalowany sterownik oraz
związany z nim program zarządzający.
Jako program służący do generowania i monitorowania ruchu UDP i TCP użyto LanTraffic
V2 (wersja ewaluacyjna dostępna na stronie http://www.zti-telecom.com). Program ten
skonfigurowano w ten sposób, aby obliczał poszczególne wartości przepustowości co jedną
sekundę na podstawie danych gromadzonych przez jedną lub dwie sekundy.
Test 1 Kształtowanie ruchu wychodzącego UDP
Cel testu
Test ma zadanie ukazać w jaki sposób program pozwala kształtować ruch wychodzący
transmisji bezpołączeniowych przykładowo dla protokołu UDP.
93
Przebieg doświadczenia
W doświadczeniu wykorzystano połączenie przy pomocy kabla szeregowego. Maksymalna
prędkość transmisji UDP dla tego połączenia wynosiła ok. 180 Kb/s (wielkość odczytana z
wykresu poniżej) W programie konfiguracyjnym utworzono strukturę klas ukazaną na
poniższym schemacie.
Klasy A Przepustowość
zapewniona – pz [Kb/s]
Schemat 1
Należy zauważyć, że została określona tylko jedna klasa ruchu podczas gdy w teście
prowadzone były dwie transmisje.
Na poniższym wykresie ukazano przebieg zajętości przepustowości odczytany w odbiorniku.
0
50
100
150
200
0 30 60 90 120 150 180 210czas [s]
prze
pust
owość
[Kb/
s]
A B A+B
Wykres 1
50
Rozmiar wiadra kształtującego pz
[B] 1600
Przepustowość szczytowa – ps
[Kb/s] 50
Rozmiar wiadra kształtującego ps
[B] 1600
Priorytet -
Kwant -
Długość kolejki -
WYJŚCIE
A
F
94
Przed włączeniem kształtowania ruchu nadajnik rozpoczął wysyłanie pakietów UDP do
portów 2009 i 2010 odbiornika. Każda z tych transmisji miała docelowe natężenie 100 Kb/s.
W sumie obie transmisje w pełni zajmowały całe łącze nie mogąc osiągnąć prędkości 200
Kb/s. Na wykresie tę sumę oznaczono szarą linią.
W 90-tej sekundzie testu włączono w nadajniku kształtowanie ruchu, które ograniczyło
transmisję dla przepływu A do 50 Kb/s. Można w tym miejscu zauważyć, że przepływ B
osiągnął wówczas swoje docelowe natężenie 100Kb/s.
Wnioski
Przeprowadzony test ukazał przydatność programu do kształtowania bezpołączeniowego
ruchu wychodzącego. To implikuje również, że program będzie też w stanie ograniczać
wychodzące transmisje połączeniowe TCP.
Test 2 Ograniczanie ruchu wchodzącego TCP
Cel testu
Zadanie testu stanowi przedstawienie kształtowania ruchu wchodzącego dla protokołu TCP.
Przebieg doświadczenia
W doświadczeniu użyto połączenia szeregowego między komputerami. Wygenerowano dwa
przepływy TCP do portów 2009 i 2010. Przepływom tym nadano maksymalne prędkości
transmisji po 400 Kb/s każda, które zajęły całe łącze o przepustowości ok. 450 Kb/s
(odczytanej z poniższego wykresu).
Przed przeprowadzeniem testu w programie konfiguracyjnym na komputerze stanowiącym
odbiornik utworzono następującą strukturę klas. Należy zauważyć, że kształtowaniu objęto
tylko jeden przepływ.
95
Klasy B Przepustowość
zapewniona – pz [Kb/s]
Schemat 2
W odbiorniku uzyskano przebieg zajętości przepustowości umieszczony na poniższym
wykresie.
0
50
100
150
200
250
300
350
400
450
500
0 30 60 90 120 150 180 210czas [s]
prze
pust
owość
[Kb/
s]
A B A+B
Wykres 2
Można tutaj zauważyć, że przed rozpoczęciem kształtowania oba przepływy docierają do
odbiorniku z tym samym natężeniem. Po ograniczeniu przepływu B do 50 Kb/s w setnej
sekundzie testu, drugi przepływ zajął zwolniony zapas przepustowości.
50
Rozmiar wiadra kształtującego pz
[B] 1600
Przepustowość szczytowa – ps
[Kb/s] 50
Rozmiar wiadra kształtującego ps
[B] 1600
Priorytet -
Kwant -
Długość kolejki -
WEJŚCIE
B
F
96
Wnioski
Test ukazał, że program może być wykorzystany do kształtowania wchodzących przepływów
o charakterze połączeniowym. Nie wynika z tego jednak dobre jego działanie dla protokołu
UDP co zostało dokładnie omówione w kolejnym teście.
Test 3 Ograniczanie ruchu wchodzącego UDP
Cel testu
Przeznaczeniem doświadczenia jest ukazanie trudności przy kształtowaniu wchodzących
transmisji połączeniowych dla przykładu UDP.
Przebieg doświadczenia
W doświadczeniu wykorzystano połączenie przy pomocy kabla szeregowego. Maksymalna
prędkość transmisji UDP dla tego połączenia wynosiła ok. 180 Kb/s (wielkość odczytana z
wykresu poniżej) W programie konfiguracyjnym na komputerze stanowiącym odbiornik
utworzono następującą hierarchię klas.
Klasy A Przepustowość
zapewniona – pz [Kb/s]
Schemat 3
Przed włączeniem kształtowania ruchu, rozpoczęto nadawanie dwóch strumieni pakietów
UDP do portów 2009 i 2010. Każdy z tych strumieni miał docelowe natężenie 100 Kb/s i w
sumie zajęły one całe dostępne łącze nie mogąc osiągnąć tej prędkości. Przebieg transmisji
zarejestrowany w odbiorniku ukazany jest na poniższym wykresie dla czasu od 0 do 100
sekund.
50
Rozmiar wiadra kształtującego pz
[B] 1600
Przepustowość szczytowa – ps
[Kb/s] 50
Rozmiar wiadra kształtującego ps
[B] 1600
Priorytet -
Kwant -
Długość kolejki -
WEJŚCIE
A
F
97
0
50
100
150
200
0 30 60 90 120 150 180 210czas [s]
prze
pust
owość
[Kb/
s]
A B A+B
Wykres 3
W 100 sekundzie transmisji włączono kształtowanie ruchu w odbiorniku. Można zauważyć,
że przepływ A został ograniczony do 50 Kb/s, jednak mimo to przepływ B nie zwiększył
swojej prędkości. Oznacza to, że część przepustowości zostało zmarnowane.
Wnioski
Przeprowadzony test ukazuje, że kształtowanie ruchu bezpołączeniowego dla interfejsu
wejściowego odbiornika jest zabiegiem bezcelowym i prowadzi jedynie do marnowania
przepustowości. Odbiornik nie ma bowiem wpływu na to co jest do niego wysyłane. Jedynym
wyjściem dla tej sytuacji jest wprowadzenie kształtowania ruchu w interfejsie wyjściowym
nadajnika.
Test 4 Znaczenie rozmiaru „wiadra” dla UDP i TCP
Cel testu
Zadaniem doświadczenia jest ograniczanie przepustowości przepływu pakietów TCP i UDP o
wybranych właściwościach. W przykładzie zostało też zilustrowane znaczenie
najważniejszego parametru algorytmu HTB – rozmiaru „wiadra na żetony".
98
Istotne jest zwrócenie na fakt, że wielkość tę przy tworzeniu konfiguracji wprowadza się w
bajtach ([B]) a nie w żetonach. Dopiero program znając prędkość generowania żetonów oraz
przepustowość przypisaną do danej klasy, przelicza bajty na żetony. Taka reprezentacja
rozmiaru wiadra pozwala na łatwiejsze zrozumienie jego znaczenia i nie zmusza użytkownika
do znajomości mechanizmu generującego żetony. Głębokość wiadra określona w żetonach
oznacza bowiem liczbę danych jaką maksymalnie można przesłać wykorzystując wszystkie
znajdujące się w nim żetony.
Przebieg doświadczenia
Do przeprowadzenia testu użyto sieci typu Ethernet. W przykładzie przy pomocy programu
zarządzającego utworzono strukturę klas dla interfejsu wychodzącego nadajnika ukazaną na
poniższym schemacie. Pakiety są przypisywane do klasy B za pomocą filtru.
Schemat 4
Test zrealizowano w dwóch etapach – pierwszy dla protokołu UDP, a drugi dla TCP.
Etap 1 – ruch pakietów UDP
Po skonfigurowaniu nadajnik rozpoczął wysyłanie w kierunku odbiornika pakietów UDP o
losowej długości z przedziału od 128 do 1460 bajtów z natężeniem 400Kb/s w kilku seriach
trwających ok. 40 sekund każda. Pomiędzy poszczególnymi seriami nadajnik przerywał
wysyłanie na ok. 20 sekund. Poniższy przebieg natężenia ruchu otrzymano w odbiorniku.
A
B
Klasy A Przepustowość zapewniona –
pz [Kb/s] 200
Rozmiar wiadra
kształtującego pz [B]
1600
Przepustowość szczytowa –
ps [Kb/s] 200
Rozmiar wiadra
kształtującego ps [B]
1600
Priorytet -
Kwant -
WEJŚCIE
F
99
0
50
100
150
200
250
0 30 60 90 120 150 180 210
czas [s]
prze
pust
owość
[Kb/
s]
Wykres 4
Wykres ukazuje, że ograniczony ruch dla klasy B nie przekracza ustalonej dla niego
przepustowości szczytowej – 100Kb/s
W dalszej części ćwiczenia zwiększono głębokość wiadra kształtującego przepustowość
szczytową z 1600 bajtów (umowna maksymalna długość pakietu) na 200 kilobajtów.
Podobnie naprzemian zatrzymywano i wznawiano ruch pakietów o tym samym jak wcześniej
natężeniu. W odbiorniku otrzymano następujący przebieg zajętości przepustowości.
0
50
100
150
200
250
0 30 60 90 120 150 180 210
czas [s]
prze
pust
owość
[Kb/
s]
Wykres 5
100
Na wykresie tym można dostrzec wzrost natężenia ruchu zaraz po jego wznowieniu.
Nadwyżka ta nie przekracza jednak przepustowości, jaka została ustalona dla klasy A –
200KB/s i po pewnym czasie ustępuje. Dalej pakiety przypisane do klasy B wysyłane są już z
natężeniem szczytowym przeznaczonym dla tej klasy – 100KB/s.
Taki stan spowodowany jest użyciem wiadra o dużym rozmiarze. Powoduje to gromadzenie
się większej ilości żetonów w sytuacji, gdy natężenie ruchu jest mniejsze niż ustalona
przepustowość maksymalna. Zapas ten jest wykorzystywany gdy istnieje potrzeba wysłania
większej liczby pakietów.
Etap 2 – ruch pakietów TCP
W drugim etapie doświadczenia ustalono z powrotem rozmiar wiadra kształtującego
przepustowość szczytową klasy B na 1600 bajtów. Zmieniono także rodzaj protokołu w
filtrze F na TCP.
Pomiędzy odbiornikiem i nadajnikiem została zainicjowana transmisja TCP o docelowym
natężeniu 400 Kb/s. W odbiorniku otrzymano następujący przebieg zajętości przepustowości
przez tę transmisję.
0
50
100
150
200
250
0 30 60 90 120 150 180 210
czas [s]
prze
pust
owość
[Kb/
s]
Wykres 6
Na wykresie widać charakterystyczny dla protokołu TCP „poszarpany” przebieg natężenia
ruchu. Czarną pogrubioną linią oznaczono średnią wartość tego natężenia – umiejscowiona
jest ona pod wartością graniczną – 100KB/s.
101
Pewne wzrosty zajmowanej przepustowości ponad ustaloną wartość maksymalną
spowodowane są tym, że protokół napotykając limit przepustowości, spowalnia transmisję na
krótką chwilę. Przez ten czas w wiadrze gromadzone są żetony i później można wysłać
zwiększoną liczbę danych. Pozwala to na bardziej sprawiedliwe ograniczanie przepustowości
dla transmisji określanych w anglojęzycznych opracowaniach „bursty”.
Na kolejnym wykresie widać, jak zmienił się charakter transmisji po zwiększeniu rozmiaru
wiadra kształtującego maksymalną przepustowość do 200KB. Zauważalny jest wzrost
skoków natężenia ruchu. Również średnia wartość zajętości przepustowości znajduje się
bliżej poziomu granicznego.
0
50
100
150
200
250
0 30 60 90 120 150 180 210
czas [s]
prze
pust
owość
[Kb/
s]
Wykres 7
Wnioski
Powyższe doświadczenie ukazało, że program spełnia swoje zadanie jeśli chodzi o
ograniczanie ruchu UDP oraz TCP. Ukazało także znaczenie rozmiaru „wiadra na żetony”
przy kształtowaniu przepustowości. Parametr ten jest przydatny przy ograniczaniu ruchu,
który gwałtownie zmienia swoje natężenie. Jego zwiększenie pozwala bowiem na chwilowe
wzrosty zajętości przepustowości w sytuacji, gdy wcześniej przydzielone łącze nie było
całkowicie zajmowane.
102
Test 5 Pożyczanie przepustowości pomiędzy klasami
Cel testu
Zadaniem tego eksperymentu jest sprawdzenia, jak działa zaimplementowany w programie
mechanizm umożliwiający dzielenie przepustowości pomiędzy przepływami. Poszczególne
klasy ruchu, jeśli posiadają wspólnego przodka w hierarchii klas i przydzielono im pewną
wspólną ilość przepustowości, mogą przejmować części łącza niewykorzystanej pozostałe
przepływy.
Przebieg doświadczenia
Doświadczenie przeprowadzono dla sieci Ethernet. Przy pomocy programu zarządzającego
utworzono następującą strukturę klas i filtrów dla interfejsu wychodzącego nadajnika.
Klasy A
Schemat 5
Po wygenerowaniu dwóch transmisji UDP do portów docelowych 2009 i 2010 obie z
natężeniem docelowym 150Kb/s, w odbiorniku otrzymano przebieg zajętości łącza
umieszczony na poniższym wykresie. Długości wysyłanych pakietów były losowe z
przedziału od 128 do 512 bajtów. Poszczególne wartości przepustowości zliczano jw każdym
z jednosekundowych przedziałów.
Przepustowość zapewniona –
pz [Kb/s] 150
Rozmiar wiadra
kształtującego pz [B]
1600
Przepustowość szczytowa –
ps [Kb/s] 150
Rozmiar wiadra
kształtującego ps [B]
1600
Priorytet -
Kwant -
B
F
C
WEJŚCIE
A
G
103
0
50
100
150
200
0 30 60 90 120 150 180 210
czas [s]
prze
pust
owość
[Kb/
s]`
B+C C B
I II
Wykres 8
Obszary oznaczone na wykresie przez I oraz II dotyczą przerywania na pewien czas
wysyłania przez nadajnik. W obszarze I zaprzestano nadawania do portu 2009 czyli dla klasy
C, zaś w obszarze II wyłączono nadawanie do portu 2010 czyli dla klasy B.
W tych obszarach można zauważyć, że klasa, która kontynuowała transmisję, otrzymała całą
dostępną przepustowość przypisaną dla obydwu klas. W pozostałych przypadkach obie klasy
mogły w pełni wykorzystać tą część łącza, która została im zapewniona czyli 50KB/s dla
klasy B i 100KB/s dla klasy C.
Wnioski
Doświadczenie ukazuje sposób w jaki można zrealizować pożyczanie przepustowości między
klasami przy zastosowaniu programu. Ukazuje również, że algorytm istotnie zapewnia
klasom ustaloną dla nich przepustowość. Pozwala także innym klasom wykorzystać ten
przydział gdy nie jest używany.
104
Test 6 Wpływ „priorytetu” na pożyczanie przepustowości
Cel testu
Głównym celem niniejszego doświadczenie jest ukazać, jaki charakter ma pożyczanie
przepustowości pomiędzy klasami ruch w sytuacji, gdy różnią się one priorytetem.
Przebieg doświadczenia
W doświadczeniu użyto sieci Ethernet. Do przeprowadzenia testu dla interfejsu wyjściowego
nadajnika użyto hierarchii klas umieszczonej na poniższym schemacie. Można tutaj
zauważyć, że klasy B i C mają zapewnioną tą samą przepustowość tzn. 75Kb/s, przy czym ich
przepustowości maksymalne wynoszą 200KB/s. Ma im to umożliwić pożyczanie
przepustowości od klasy rodzica – A.
Klasy A
Schemat 6
W kierunku odbiornika rozpoczęto wysyłanie pakietów o losowej długości z przedziału od
128 do 512 bajtów. Wykorzystano dwa przepływy pakietów UDP. Jeden skierowany do portu
docelowego 2009 drugi do portu 2010. Docelowe natężenie każdego z wygenerowanych
ruchów wynosiło 200Kb/s. W odbiorniku otrzymano ukazane poniżej przebiegi zajętości
przepustowości.
Przepustowość zapewniona –
pz [Kb/s] 200
Rozmiar wiadra
kształtującego pz [B]
1600
Przepustowość szczytowa –
ps [Kb/s] 200
Rozmiar wiadra
kształtującego ps [B]
1600
Priorytet -
Kwant -
B
F
C
WEJŚCIE
A
G
105
0
50
100
150
200
250
0 30 60 90 120 150 180 210czas [s]
prze
pust
owość
[b/s
]
B+C C B
I II
Wykres 9
Obszary zaznaczone na wykresie liczbami rzymskimi I oraz II określają przedziały czasu, w
których w, programie zarządzającym, ustawiono priorytet jednej z klas na 1. W przedziale I
klasa C uzyskała priorytet 1, klasa B pozostała natomiast przy swoim priorytecie 0. W
przedziale II odwrotnie, klasa C dostała priorytet 0, zaś klasa B priorytet 1.
Wykres ilustruje, że klasa o priorytecie liczbowo większym traciła możliwość pożyczania
przepustowości od klasy A. Klasa o priorytecie równym zero otrzymywała natomiast całą
nadwyżkę przepustowości, jaka była przeznaczona dla klas B i C. W sytuacji gdy obydwie
klasy miały ten sam priorytet, mogły pożyczać nadwyżkę przepustowości w tym samym
stopniu. Należy także zauważyć, że żadna z klas przy zmianach priorytetów nie straciła
swojej zapewnionej przepustowości – 75 Kb/s.
Sumę przebiegów zaznaczono linią szarą. Można zauważyć, że jest ona ograniczona przez
poziom 200KB/s oznaczający przepustowość szczytową dla klas. Linia ta jest umieszczona
dość nisko pod maksymalnym poziomem, ponieważ, dla większej przejrzystości,
poszczególne wartości przepustowość obliczano w czasie 2 sekund. Przy wyliczaniu ich co 1
sekundę różnice między kolejnymi wartościami przepustowości byłyby dość duże, co
niekorzystnie wpłynęłoby na przejrzystość wykresu.
106
Wnioski
Przeprowadzone doświadczeniu ukazuje, że ustalanie różnych priorytetów dla klas wpływa
wyłącznie na pożyczanie przez nie przepustowości. Klasa o priorytecie najważniejszym czyli
liczbowo najmniejszym otrzymuje całą nadwyżkę pasma, jaką można w danej chwili
wykorzystać. W tym samym czasie klasa o priorytecie mniej ważnym utrzymuje jednak
zapewnionym dla niej poziom ruchu.
Test 7 Wpływ „kwantu” na pożyczanie przepustowości
Cel testu
Posługiwanie się priorytetem do ustalania dostępu poszczególnych klas do zgromadzonego
zapasu przepustowości jest dość nieelastyczne. Można bowiem wyznaczyć jedynie, która
klasa lub grupa klas przejmie całą nadwyżkę. Aby temu zaradzić można posłużyć się
parametrem kwant algorytmu „Deficit Round Robin”. Algorytm DRR dokładnie omówiono w
głównej części pracy. Kwant oznacza, ile danych może wysłać naraz klasa ze zbioru klas,
które mogą w danej chwili wysyłać, zanim zacznie nadawać kolejna klasa z tego zbioru.
Zadaniem aktualnego testu jest sprawdzenie, jaki charakter ma pożyczaniu przepustowości
przy zmianie wartości kwantu jednej z klas.
Przebieg doświadczenia
Do przeprowadzeniem testu w programie konfiguracyjnym na komputerze stanowiącym
nadajnik utworzono następującą hierarchię klas dla interfejsu wejściowego sieci Ethernet.
107
Klasy A
Schemat 7
Następnie nadajnik rozpoczął wysyłanie pakietów UDP do portów docelowych 2009 i 2010 z
docelowym natężeniem 200Kb/s. Użyto pakietów o losowej długości od 128 do 512 bajtów.
W odbiorniku w celu obliczenia przepustowości w każdej sekundzie, otrzymywane bajty
sumowano przez okres 2 sekund. Pozwoliło to na otrzymanie bardziej czytelnych wykresów
przedstawionych poniżej.
0
50
100
150
200
250
0 30 60 90 120 150 180 210czas [s]
prze
pust
owość
[b/s
]
A B A+B
I II
Wykres 10
Podczas wysyłania pakietów w programie konfiguracyjnym zmieniono wartość kwantu dla
klasy C. Na wykresie rzymską liczbą I oznaczono przedział czasu, w którym klasa C
otrzymała kwant 10KB. Wartość ta oznacza liczbę bajtów jakie klasa może wysłać naraz,
Przepustowość zapewniona –
pz [Kb/s] 200
Rozmiar wiadra
kształtującego pz [B]
1600
Przepustowość szczytowa –
ps [Kb/s] 200
Rozmiar wiadra
kształtującego ps [B]
1600
Priorytet -
Kwant -
B
F
C
WEJŚCIE
A
G
108
zanim algorytm DRR wybierze kolejną klasę. Ustalenie tylko tego parametru nie pozwoli
jednak na to, aby klasa C mogła faktycznie wysłać taką ilość danych, ponieważ uniemożliwi
jej to mały rozmiar „wiadra” kształtującego przepustowość szczytową. Trzeba zatem
zwiększyć i ten parametr. W przykładzie ustalono rozmiar wiadra dla przepustowości
szczytowej klasy C na 200KB.
Po ustaleniu wyszczególnionych wyżej parametrów widać na wykresie, że klasa C przejęła w
obszarze I większą część przepustowości. W tym samym czasie jednak klasa B cały czas
mogła wysyłać ze swoim zapewnionym natężeniem.
W obszarze II ustalono rozmiar wiadra dla przepustowości szczytowej klasy C z powrotem na
1600 bajtów. Zmniejszono także dla niej rozmiar kwantu na 250 bajtów. Po tych zabiegach
można zaobserwować, jak klasa B przejmuje większą część przepustowości pożyczanej od
klasy rodzica. Jednocześnie klasa C cały czas zachowuje swoje wymagane natężenie
wysyłania.
W pozostałej części wykresu obydwie klasy mają przypisane takie parametry jak ukazano na
schemacie powyżej.
Należy zauważyć, że podczas całego doświadczenia obydwie klasy zachowywały
przeznaczony dla nich poziom przepustowości zapewnionej.
Wnioski
Powyżej omówione doświadczenie ukazało, że parametr „kwant” pozwala płynnie określić w
jakich proporcjach klasy mogą pożyczać przepustowość od wspólnego rodzica. Ukazało też,
że przy zwiększaniu tego parametru konieczne jest także powiększenie rozmiaru „wiadra”
kształtującego przepustowość szczytową.
109
Podsumowanie
Powyższe testy programu kształtującego ruch pakietów ukazały przeznaczenie
poszczególnych parametrów dotyczących zastosowanego w nim algorytmu „hierarchicznego
wiadra z żetonami”. Parametrami tymi są głębokość „wiader na żetony” kształtujących
przepustowość zapewnioną i szczytową, kwant i priorytet. Doświadczenia zilustrowały także
przeznaczenie hierarchii klas użytej w algorytmie.
Wykazano również, że kształtowanie ruchu wychodzącego jest możliwe dla wszystkich
rodzajów transmisji. Z kolei ustalanie reguł dla na dostęp do przepustowości dla interfejsu
wejściowego, ma sens wyłącznie dla transmisji połączeniowych kontrolujących prędkość
transmisji.
110
Załącznik 4 Płyta CD-ROM
Na dołączonej płycie CD-ROM umieszczono następujące składniki:
• wersja elektroniczna niniejszej pracy w formacie pdf;
• źródła w języku C++ sterownika i aplikacji użytkownika służących do kształtowania
ruchu;
• dokumentacja sterownika i aplikacji wygenerowane z kodu źródłowego;
• skompilowana wersja programu dla systemu Windows XP;
• program instalacyjny;
111
Literatura
Strony internetowe
[GART] Strona organizacji Gartner,
http://www.gartner.com
[LINK] Internetowa encyklopedia informatyki,
http://www.linktionary.com
[BCR] Bussines Communications Review,
http://www.bcr.com
[PACK] Strona firmy Packeteer, producenta urządzeń sieciowych,
http://www.packeteer.com
[ICSI] Strona organizacji ICSI Center for Internet Research
http://www.icir.org
[PROT] Strona omawiająca różne protokoły sieciowe
http://www.protocols.com
[DOX] Strona projektu Doxygen (generator dokumentacji technicznej)
http://www.doxygen.org
[3COM] 3Com Corp.
http://www.3com.com
[CISCO] Sisco Systems Inc.
http://www.cisco.com
[ESYS] Enterasys
http://www.enterasys.com
112
[JUNIP] Juniper Networks
www.juniper.net
[LUCENT] Lucent Technologies
http://www.lucent.com
[NORTEL] Nortel Networks Corp.
http://www.nortel.com
[ALLOT] Allot Communications
http://www.allot.com
[NDIS] NDIS Developer’s Reference
http://www.ndis.com
[WD3] Windows Driver Developer’s Digest
http://www.wd-3.com
[MSSUP] Strony pomocy technicznej Microsoftu
http://support.microsoft.com
[MSDN] Biblioteka MSDN na stronie Microsoftu w tym Device Driver Kit
http://msdn.microsoft.com
[OSR] OSR Online
http://www.osronline.com
[COWRE] Strona firmy Compuware Corporation producenta Driver Studio
http://www.compuware.com
Dokumenty RFC
[RFC-0791] Darpa Internet Program, „Internet Protocol”,
(Specyfikacja protokołu IP), sierpień 1981
http://www.ietf.org/rfc/rfc791.txt
[RFC-0793] Darpa Internet Program, „Transmission Control Protocol”
(Pierwsza specyfikacja protokołu TCP), sierpień 1981
http://www.ietf.org/rfc/rfc793.txt
[RFC-0813] David D. Clark, „Window and Acknowledgement Strategy In TCP”, lipiec 1982
http://www.ietf.org/rfc/rfc813.txt
113
[RFC-1072] V. Jacobson, „TCP Extensions for Long-Delay Paths”, sierpień 1988
http://www.ietf.org/rfc/rfc1072.txt
[RFC-1146] J. Zweig, „TCP Alternate Checksum Options”, marzec1990
http://www.ietf.org/rfc/rfc1146.txt
[RFC-1633] „Integrated Services in the Internet Architecture: an Overview”
(Wprowadzenie do serwisów zintegrowanych), styczeń 1991
http://www.ietf.org/rfc/rfc1633.txt
[RFC-1693] T. Connolly, „An Extension to TCP : Partial Order Service”, październik 1994
http://www.ietf.org/rfc/rfc1693.txt
[RFC-2205] „Resource ReSerVation Protocol” (Specyfikacja protokołu RSVP), sierpień 1997
http://www.ietf.org/rfc/rfc2205.txt
[RFC-2212] „Specification of Guaranteed Quality of Service”, (Specyfikacja gwarantowanej
jakości usług), sierpień 1997
http://www.ietf.org/rfc/rfc2212.txt
[RFC-2251] M. Wahl „Lightweight Directory Access Protocol (v3)”, grudzień 1997
http://www.ietf.org/rfc/rfc2251.txt
[RFC-2475] „An Architecture for Differentiated Services”, (Architektura serwisów
zróżnicowanych), grudzień 1998
http://www.ietf.org/rfc/rfc2475.txt
[RFC-3031] „Multiprotocol Label Switching Architecture”, (Architektura protokołu MPLS),
styczeń 2001
http://www.ietf.org/rfc/rfc3031.txt
[RFC-3168] „The Addition of Explicit Congestion Notification (ECN) to IP”, (Specyfikacja
ECN), sierpień 2001
http://www.ietf.org/rfc/rfc3168.txt
Artykuły
[HPFQ96] Jon C.R. Bennett and H. Zhang, „Hierarchical Packet Fair Queueing
Algorithms”, IEEE/ACM Transactions on Networking, sierpień 1996,
http://www.acm.org/sigcomm/ccr/archive/1996/conf/bennett.pdf
114
[LINK95] Sally Floyd, Van Jacobson, „Link-sharing and Resource Managment Models for
Packet Networks”, IEEE/ACM Transactions on Networking, Vol. 3 No. 4,
sierpień 1995,
http://www.icir.org/floyd/papers/link.pdf
[DRR95] M. Shreedhar, George Varghese, „Efficient Fair Queueing using Deficit Round
Robin”, wrzesień 1995
Artykuł dostępny na stronie http://citeseer.ist.psu.edu
[SFQ91] Paul E. McKenney, „Stochastic Fairness Queuing”, styczeń 1991
Artykuł dostępny na stronie http://citeseer.ist.psu.edu
Książki
[W2KDDB] Art Baker, Jerry Lozano, „The Windows 2000 Device Driver Book, A Guide for
Programmers, Second Edition”, Prentice Hall, listopad 2000
[PWDM] Walter Oney, „Programming the Microsoft Windows Driver Model”, Microsoft
Press, 2003
[INW2K] David A. Solomon, Mark E. Russinovich, „Inside Microsoft Windows 2000”,
Microsoft Press, 2002
115