[OpenBSD]

[Wstecz: Zakotwiczenia] [Spis treści] [Dalej: Pule adresów i kierowanie ruchem]

PF: Kolejkowanie i priorytetowanie


Spis treści


Kolejkowanie

Terminem "kolejkowanie" określa się przechowywanie pewnej rzeczy w oczekiwaniu na dalszą jej obróbkę. W sieciach komputerowych, każde dane, zanim zostaną wysłane umieszczane są w kolejce, w której oczekują na przetworzenie. System operacyjny decyduje zaś, które pakiety i z jakiej kolejki zostaną w danym momencie wysłane. Kolejność w jakiej system operacyjny wybiera pakiety do przetworzenia może wpływać na wydajność sieci. Na przykład, użytkownik uruchomił dwa programy wykorzystujące sieć: SSH oraz FTP. Teoretycznie pakiety SSH powinny być obsłużone przed pakietami FTP ponieważ protokół SSH jest uzależniony czasowo; w trakcie wpisywania czegoś w kliencie SSH wymaga się natychmiastowej odpowiedzi, a opóźnienie transferu danych z FTP na kilka sekund nie powoduje właściwie żadnych problemów. A co się stanie, gdy router kierujący ruchem sieciowym przetwarza duże ilości pakietów FTP przed obsłużeniem połączeń SSH? Pakiety należące do sesji SSH zostaną umieszczone w kolejce (w przypadku nadmiernego wydłużenia kolejki, najprawdopodobniej będą porzucone), a połączenie SSH będzie miało tendencję do dużych opóźnień (ang. lag) lub wręcz bardzo spowolnią się odpowiedzi strony zdalnej. Modyfikując jednak bieżącą strategię kolejkowania dostępne pasmo sieci będzie sprawiedliwie podzielone pomiędzy aplikacje, użytkowników i komputery.

Proszę zwrócić uwagę, że kolejkowanie jest tylko użyteczne w przypadku pakietów wychodzących. W momencie, gdy pakiet osiągnie kartę sieciową, właściwie już jest za późno na to, by go skolejkować - bowiem właśnie wykorzystał część pasma w celu dostania się do karty sieciowej, która go odebrała. Jedynym rozwiązaniem jest włączenie kolejkowania na routerze bądź maszynie, która pełni funkcję routera i odebrała pakiet. Kolejkowanie należy włączyć na wewnętrznym interface, tzn. tam gdzie pakiety opuszczają router.

Algorytmy szeregowania

Algorytm szeregowania (ang. scheduler) jest tym, co decyduje którą kolejkę przetwarzać i w jakiej kolejności. Domyślnie OpenBSD używa algorytmu szeregowania FIFO (pierwszy wszedł, pierwszy wyjdzie). Kolejki FIFO działają podobnie jak kolejka w supermarkecie lub w banku - pakiet znajdujący się na czele kolejki będzie przetworzony jako pierwszy. Kiedy nadchodzą nowe pakiety, dodawane są na koniec kolejki. Jeśli kolejka zapełni się, nowo przybyłe pakiety są odrzucane. Taka metoda zwana jest "odrzucaniem ogona".

W OpenBSD dostępne są dwa algorytmy szeregowania:

Class Based Queueing

Class Based Queueing (CBQ) jest algorytmem, który dzieli pasmo połączenia sieciowego na wiele kolejek lub klas. Do każdej kolejki przypisywane są pakiety zależnie od adresu źródłowego lub docelowego, numeru portu, protokołu, itp. Kolejka może być skonfigurowana w sposób umożliwiający pożyczenie pasma od swojej kolejki nadrzędnej, gdy jej dostępna przepustowość nie jest całkowicie wykorzystywana. Kolejki mogą posiadać przypisany priorytet w taki sposób, że te zawierające dane wymagające dużej interaktywności, np. SSH, będą obsługiwane przed tymi, które zawierają dane nie wymagające interakcji np. FTP.

Kolejki CBQ tworzone są hierarchicznie. Na szczycie struktury znajduje się kolejka-korzeń (ang. root), która definiuje maksymalną dostępną przepustowość łącza. Kolejki podrzędne tworzone są pod kolejką główną. Do każdej z podrzędnych kolejek przypisana jest część pasma kolejki głównej. Na przykład, kolejki mogą być zdefiniowane jak poniżej:

Root Queue (2Mbps)
Queue A (1Mbps)
Queue B (500Kbps)
Queue C (500Kbps)

W tym przypadku, całe dostępne pasmo ustawione jest na wartość 2 megabity na sekundę (Mbps). Pasmo to jest następnie dzielone na trzy kolejki podrzędne.

Struktura może dalej być rozszerzana poprzez definiowanie nowych kolejek z kolejek pierwszego poziomu. Aby podzielić pasmo pomiędzy różnych użytkowników oraz sklasyfikować ich ruch w taki sposób, aby niektóre protokoły nie obciążały pasma innych, struktura kolejek może być zdefiniowana tak:

Root Queue (2Mbps)
UserA (1Mbps)
ssh (50Kbps)
bulk (950Kbps)
UserB (1Mbps)
audio (250Kbps)
bulk (750Kbps)
http (100Kbps)
other (650Kbps)

Należy zauważyć, iż na każdym poziomie suma przepustowości przypisanych do poszczególnych kolejek nie przekracza przepustowości kolejki będącej dla nich kolejką nadrzędną.

Kolejka może być skonfigurowana w taki sposób, aby pożyczać (ang. borrow) pasmo od swojego rodzica, jeśli jest dostępna u niego nadwyżka, która powstaje gdy inne kolejki pochodne nie wykorzystują pasma. Rozważmy następującą konfiguracje:

Root Queue (2Mbps)
UserA (1Mbps)
ssh (100Kbps)
ftp (900Kbps, borrow)
UserB (1Mbps)

Jeśli ruch w kolejce ftp przekracza 900Kbps, a ruch w kolejce UserA jest mniejszy niż 1Mbps (ponieważ kolejka ssh wykorzystuje mniej niż 100Kbps pasma), wówczas kolejka ftp pożyczy nadmiar pasma od UserA. W ten sposób kolejka ftp jest w stanie korzystać z większego pasma, niż przydzielone jej, w sytuacji gdy jest przeładowana. Jeśli wzrośnie zapotrzebowanie na pasmo w kolejce ssh, wówczas udostępniane pasmo zostanie oddane.

CBQ przypisuje każdej kolejce poziom priorytetu. Kolejki o większym priorytecie są częściej wybierane podczas przeciążenia sieci niż kolejki o niższym priorytecie, pod warunkiem, że kolejki mają tego samego rodzica (innymi słowy, tak długo jak kolejki znajdują się w tej samej gałęzi hierarchii). Kolejki o tym samym priorytecie są przetwarzane w sposób rotacyjny (ang. round-robin). Na przykład:

Root Queue (2Mbps)
UserA (1Mbps, priority 1)
ssh (100Kbps, priority 5)
ftp (900Kbps, priority 3)
UserB (1Mbps, priority 1)

CBQ będzie przetwarzać kolejki UserA i UserB w sposób rotacyjny - żadna z kolejek nie będzie miała pierwszeństwa przed inną. W czasie gdy kolejka UserA będzie przetwarzana, CBQ będzie także obsługiwać jej kolejki pochodne. W tym przypadku kolejka ssh ma większy priorytet i będzie miała pierwszeństwo przed kolejką ftp, gdy sieć będzie przeciążona. Zauważ, że priorytety kolejek ssh i ftp nie są porównywane w stosunku do kolejek UserA i UserB, ponieważ nie znajdują się one w tej samej gałęzi hierarchii.

Osoby zainteresowane szczegółowymi informacjami na temat teorii stojącej za kolejkowaniem CBQ, mogą odwiedzić stronę z materiałami referencyjnymi na temat CBQ.

Kolejkowanie priorytetowe

Kolejkowanie priorytetowe PRIQ (ang. priority queueing) pozwala nadać priorytet kolejkom na interfejsie sieciowym. Kolejka o większym priorytecie jest zawsze przetwarzana przed kolejką o mniejszym priorytecie. Jeżeli dwie lub więcej kolejek mają przydzielony ten sam priorytet, wówczas kolejki te są obsługiwane zgodnie mechanizmem round-robin.

Struktura kolejek PRIQ jest zawsze płaska - nie można definiować kolejek w kolejkach. Kolejka-korzeń jest definiowana aby określić całkowitą dostępną przepustowość, po czym definiowane są podkolejki korzenia. Rozważmy następujący przykład:

Root Queue (2Mbps)
Queue A (priority 1)
Queue B (priority 2)
Queue C (priority 3)

Zadeklarowano, że kolejka-korzeń ma dostępną przepustowość 2Mbps oraz że posiada trzy kolejki podrzędne. Kolejka o najwyższym priorytecie (posiadająca największy numer priorytetu) jest obsługiwana jako pierwsza. Gdy wszystkie pakiety są przetworzone, lub gdy kolejka jest pusta, wówczas PRIQ przechodzi do przetwarzania następnej kolejki o kolejnym najwyższym priorytecie. W obrębie kolejki pakiety są przetwarzane na zasadzie First In First Out (FIFO).

Istotne jest, aby bardzo uważnie planować swoje kolejki korzystające z PRIQ ponieważ algorytm ten zawsze przetwarza kolejkę o wyższym priorytecie przed kolejką o niższym priorytecie. Jest możliwe, że kolejka o wysokim priorytecie spowoduje, że pakiety kolejki o niższym priorytecie będą opóźnione lub nawet porzucone (ang. drop) w sytuacji, gdy kolejka o wyższym priorytecie otrzymuje ciągły strumień pakietów.

Mechanizm wczesnego wykrywania RED

Mechanizm wczesnego wykrywania RED (ang. Random Early Detection) jest algorytmem pozwalającym uniknąć przeciążenia łącza. Jest to realizowane poprzez zagwarantowanie, że dana kolejka nie zostanie zapełniona. Algorytm osiąga to poprzez nieustanne obliczanie średniej długości (wielkości) kolejki i porównywanie jej z dwoma progami: minimalnym i maksymalnym. Jeśli średnia wielkość kolejki jest poniżej minimalnego progu wówczas żaden przybywający pakiet nie będzie porzucony. Jeśli średnia wielkość kolejki jest powyżej maksymalnego progu, wtedy wszystkie nowo przybyłe pakiety są porzucane. Jeśli średnia jest pomiędzy wartościami progów wówczas pakiety są porzucane bazując na obliczeniach prawdopodobieństwa dokonywanych na podstawie średniej wielkości kolejki. Innymi słowy, czym bardziej wielkość kolejki zbliża się do wartości maksymalnego progu, tym więcej pakietów jest porzucanych. Gdy pakiety są porzucane, RED wybiera losowo połączenia, których pakiety mają być porzucane. Połączenia wykorzystujące większe pasmo są bardziej narażone na porzucanie ich pakietów.

RED jest użyteczny, ponieważ pozwala uniknąć scenariusza zwanego "globalną synchronizacją", a także jest w stanie obsłużyć "wybuchy" ruchu. Termin "globalna synchronizacja" odnosi się do utraty łącznej przepustowości z powodu porzucania pakietów wielu połączeń w tym samym czasie. Na przykład, jeśli przeciążenie pojawi się na routerze obsługującym ruch dla 10 połączeń FTP i pakiety z wszystkich (lub prawie) tych połączeń są porzucane (jak to ma miejsce w przypadku kolejkowania FIFO) wówczas ogólne wykorzystanie łącza drastycznie spadnie. Nie jest to idealna sytuacja, ponieważ powoduje to zmniejszenie prędkości wszystkich połączeń FTP i oznacza, że maksymalny potencjał sieci nie jest wykorzystany optymalnie. Algorytm RED pozwala tego uniknąć poprzez losowy wybór połączeń, których pakiety mają być porzucane, zamiast wybierać je wszystkie. Połączenia wykorzystujące dużą przepustowość są bardziej narażone na prawdopodobieństwo porzucenia ich pakietów. W ten sposób mocno obciążające sieć połączenia będą tłumione, przeciążenia unikane, a utrata maksymalnego wykorzystania przepustowości nie będzie mieć miejsca. Dodatkowo, RED jest w stanie poradzić sobie z "wybuchami" ruchu, ponieważ zaczyna porzucać pakiety zanim dana kolejka zostaje zapełniona. Gdy "wybuch" ruchu ma miejsce, jest wystarczająco dużo wolnego miejsca w kolejce, aby poradzić sobie z nowymi pakietami.

RED powinien być stosowany jedynie, gdy protokół transportujący jest zdolny do odpowiadania na wskaźniki przepełnienia z sieci. W większości przypadków oznacza to, iż RED powinien być używany przy kolejkowaniu ruchu TCP, a nie UDP czy ICMP.

Bardziej szczegółowe informacje o teorii stojącej za kolejkowaniem RED, są dostępne na stronie z materiałami referencyjnymi na temat RED.

Jawne powiadomienie o przeciążeniu (ECN)

Jawne powiadomienie o przeciążeniu (ang. Explicit Congestion Notification - ECN) działa w połączeniu z RED, aby powiadomić dwa hosty komunikujące się za pośrednictwem sieci o jakimkolwiek przeciążeniu na trasie połączenia. Jest to osiągane poprzez umożliwienie RED ustawiania flagi w nagłówku pakietu zamiast jego porzucania. Zakładając, że wysyłający host obsługuje ECN, może on odczytać flagę i zdławić odpowiednio ilość wysyłanych pakietów.

Więcej informacji o ECN można znaleźć w RFC 3168.

Konfiguracja kolejkowania

Od wydania OpenBSD 3.0 implementacja kolejkowania Alternate Queueing (ALTQ) jest częścią podstawowego systemu. Począwszy od OpenBSD 3.3 ALTQ jest zintegrowane z PF. Implementacja ALTQ na OpenBSD wspiera algorytmy szeregowania Class Based Queueing (CBQ) i Priority Queueing (PRIQ). Poza tym obsługuje Random Early Detection (RED) i Explicit Congestion Notification (ECN).

Ponieważ ALTQ stało się częścią PF, dlatego PF musi być aktywne, aby kolejkowanie działało. Instrukcja, jak włączyć PF jest dostępna w sekcji Aktywacja.

Kolejkowanie jest konfigurowane w pliku pf.conf. Istnieją dwa typy dyrektyw, które służą do konfigurowania kolejkowania:

Składnia dyrektywy altq on wygląda następująco:

altq on interface scheduler bandwidth bw qlimit qlim \
   tbrsize size queue { queue_list }

Na przykład:

altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }
Linia ta uaktywnia CBQ na interfejsie fxp0. Całkowita dostępna przepustowość jest określona na 2Mbps. Zadeklarowane są trzy kolejki-dzieci: std, ssh i ftp.

Składnia dyrektywy queue jest następująca:

queue name [on interface] bandwidth bw [priority pri] [qlimit qlim] \
   scheduler ( sched_options ) { queue_list }

Kontynuując wcześniejszy przykład:

queue std bandwidth 50% cbq(default)
queue ssh bandwidth 25% { ssh_login, ssh_bulk }
  queue ssh_login bandwidth 25% priority 4 cbq(ecn)
  queue ssh_bulk bandwidth 75% cbq(ecn)
queue ftp bandwidth 500Kb priority 3 cbq(borrow red)

Powyżej zdefiniowane są wcześniej zadeklarowane kolejki-dzieci. Kolejka std ma przydzielone 50% przepustowości kolejki korzenia (czyli 1Mbps) i jest zaznaczona jako kolejka domyślna. Kolejce ssh przypisano 25% przepustowości kolejki korzenia (500kb) oraz zawiera dwie kolejki-dzieci ssh_login i ssh_bulk. Ssh_login ma większy priorytet niż ssh_bulk, a obie mają uaktywnione ECN. Kolejka ftp ma przypisaną przepustowość 500Kbps i nadany priorytet 3. Może ona także pożyczać pasmo, jeśli są ku temu warunki, oraz ma uaktywnione RED.

Zauważmy: Każda definicja potomnej kolejki posiada określoną przepustowość. Bez określania przepustowości, PF przydzieli kolejce 100% przepustowości kolejki rodzica. W takiej sytuacji spowoduje to błąd podczas ładowania reguł, ponieważ jeżeli istnieje kolejka ze 100% przepustowości, żadna inna kolejka nie może być zdefiniowana na tym poziomie, nie istnieje bowiem wolna przepustowość do przydzielenia.

Przypisywanie ruchu do kolejki

Aby przypisać ruch do kolejki, słowo kluczowe queue jest wykorzystywane w połączeniu z regułami filtrującymi PF. Na przykład, rozważmy zestaw reguł zawierający taką linię:

pass out on fxp0 from any to any port 22

Pakiety pasujące do tej reguły mogą być przypisane do konkretnej kolejki przy pomocy słowa kluczowego queue:

pass out on fxp0 from any to any port 22 queue ssh

Gdy używane jest słowo kluczowe queue wraz z dyrektywami block, jakiekolwiek wygenerowane pakiety TCP RST lub ICMP unreachable są przypisywane do podanej kolejki.

Ważne jest, że przypisywanie do kolejki może mieć miejsce na innym interfejsie niż zadeklarowano w dyrektywie altq on:

altq on fxp0 cbq bandwidth 2Mb queue { std, ftp }
queue std bandwidth 500Kb cbq(default)
queue ftp bandwidth 1.5Mb

pass in on dc0 from any to any port 21 queue ftp

Kolejkowanie jest uaktywnione na fxp0, lecz przypisywanie pakietów ma miejsce na dc0. Gdy pakiety pasujące do reguły pass wychodzą z interfejsu fxp0, będą przypisane do kolejki ftp. Ten typ kolejkowania może być bardzo użyteczny na ruterach.

Zwykle jest podawana tylko jedna nazwa kolejki po słowie kluczowym queue, ale jeśli druga nazwa jest obecna, wówczas kolejka ta będzie wykorzystywana dla pakietów z Type of Service (ToS) o małym opóźnieniu (ang. low-delay) i dla pakietów TCP ACK nie zawierających danych (ang. data payload). Dobrym przykładem wykorzystania tej funkcjonalności jest ruch SSH. Sesje logowania SSH będą mieć ustawione ToS na małe opóźnienie, podczas gdy sesje SCP i SFTP nie. PF może wykorzystać tą informacje do zakolejkowania pakietów należących do interaktywnej sesji do innej kolejki niż nieinteraktywne połączenia. Może to być użyteczne do nadawania priorytetu pakietom sesji interaktywnych przed pakietami transferu plików.

pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)

Reguła ta umieszcza pakiety należące do interaktywnych połączeń SSH w kolejce ssh_login, a pakiety należące do połączeń SCP i SFTP w kolejce ssh_bulk. Pakiety należące do połączeń interaktywnych SSH będą teraz przetwarzane przed pakietami połączeń SCP i SFTP ponieważ kolejka ssh_login ma większy priorytet.

Przydzielanie pakietów TCP ACK do kolejki o wyższym priorytecie jest przydatne w przypadku asymetrycznych połączeń, to znaczy połączeń, które mają inną przepustowość wysyłania i pobierania jak np linie ADSL. W przypadku linii ADSL, jeśli kanał wysyłający jest całkowicie zapełniony, a rozpoczynane jest pobieranie, wówczas pobieranie będzie utrudnione, ponieważ niezbędne pakiety TCP ACK, które powinny być wysłane będą próbować przebić się na przeciążonym kanale wysyłającym. Testy wykazały, iż aby uzyskać najlepsze rezultaty, przepustowość kolejki pobierania powinna mieć wartość mniejszą, niż wynosi maksymalna przepustowość. Dla przykładu, jeśli linia ADSL ma maksymalną prędkość wysyłania równą 640Kbps, ustawienie przepustowości bandwidth kolejki korzenia na wartość taką jak 600Kb powinno zaowocować lepszą wydajnością. Najlepszą wartość bandwidth można wyznaczyć metodą prób i błędów.

Gdy używane jest słowo kluczowe queue wraz z regułami keep state jak na przykład:

pass in on fxp0 proto tcp from any to any port 22 flags S/SA \
   keep state queue ssh

PF odnotuje kolejkę we wpisie w tabeli stanów, więc pakiety podróżujące z powrotem z fxp0, które pasują do połączenia stanowego będą przydzielane do kolejki ssh. Zwróć uwagę, że pomimo iż słowo kluczowe queue jest użyte z regułą filtrującą przychodzący ruch, celem jest określenie kolejki dla wynikłego wychodzącego ruchu, a powyższa reguła nie kolejkuje przychodzących pakietów.

Przykład 1: Mała sieć domowa

  
    [ Alice ]    [ Charlie ]
        |             |                              ADSL
     ---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
              |
           [ Bob ]

W tym przykładzie, OpenBSD wykorzystywane jest jako bramka Internetowa dla małej sieci domowej z trzema stacjami roboczymi. Bramka realizuje filtrowanie pakietów i NAT. Połączenie internetowe stanowi linia ADSL pobierająca dane z prędkością 2Mbps i wysyłająca z prędkością 640Kbps.

Polityka kolejkowania dla tej sieci:

Poniżej znajduje się zestaw reguł, który spełnia te założenia. Warto zwrócić uwagę, że dyrektywy pf.conf, które odnoszą się bezpośrednio do powyższych założeń są obecne, podczas gdy dyrektywy nat, rdr, opcje, itd nie są pokazane.

# uaktywnienie kolejkowania na zewnętrznym interfejsie, aby kontrolować
# ruch idący do Internetu. wykorzystanie algorytmu szeregowania priq
# do kontrolowania jedynie priorytetów. ustawienie przepustowość
# kanału zwrotnego na 610Kbps dla uzyskać lepszą wydajność w kolejce TCP ACK.

altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
	tcp_ack_out }

# definiowanie parametrów dla kolejek-dzieci.
# std_out      - standardowa kolejka. każda reguła filtrująca poniżej,
#                która nie jest wyraźnie powiązana z konkretną kolejką
#                będzie domyślnie przypisywała do tej kolejki.
# ssh_im_out   - interaktywne sesje SSH i różne komunikatory.
# dns_out      - zapytania DNS.
# tcp_ack_out  - pakiety TCP ACK nie zawierające danych.

queue std_out     priq(default)
queue ssh_im_out  priority 4 priq(red)
queue dns_out     priority 5
queue tcp_ack_out priority 6

# uaktywnienie kolejkowania na wewnętrznym interfejsie, aby kontrolować
# ruch nadchodzący z Internetu. wykorzystanie algorytmu szeregowania cbq
# do kontrolowania przepustowości. maksymalna przepustowość to 2Mbps.

altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }

# zdefiniuj parametry dla kolejek-dzieci.
# std_in      - standardowa kolejka. każda reguła filtrująca poniżej,
#               która nie jest wyraźnie powiązana z konkretną kolejką
#               będzie domyślnie przypisywała do tej kolejki.
# ssh_im_in   - interaktywne sesje SSH i różne komunikatory.
# dns_in      - odpowiedzi DNS.
# bob_in      - pasmo zarezerwowane dla stacji roboczej Boba. zezwalamy
#               mu na pożyczanie wolnego pasma.

queue std_in    bandwidth 1.6Mb cbq(default)
queue ssh_im_in bandwidth 200Kb priority 4
queue dns_in    bandwidth 120Kb priority 5
queue bob_in    bandwidth 80Kb cbq(borrow)


# ... w sekcji reguł filtrujących pf.conf ...

alice         = "192.168.0.2"
bob           = "192.168.0.3"
charlie       = "192.168.0.4"
local_net     = "192.168.0.0/24"
ssh_ports     = "{ 22 2022 }"
im_ports      = "{ 1863 5190 5222 }"

# reguły filtrujące dla przychodzącego ruchu na fxp0
block in on fxp0 all

# reguły filtrujące dla wychodzącego ruchu na fxp0
block out on fxp0 all
pass  out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
	keep state queue(std_out, tcp_ack_out)
pass  out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass  out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
	keep state queue dns_out
pass  out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
	flags S/SA keep state queue(std_out, ssh_im_out)
pass  out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
	flags S/SA keep state queue(ssh_im_out, tcp_ack_out)

# reguły filtrujące dla przychodzącego ruchu na dc0
block in on dc0 all
pass  in on dc0 from $local_net

# reguły filtrujące dla wychodzącego ruchu na dc0
block out on dc0 all
pass  out on dc0 from any to $local_net
pass  out on dc0 proto { tcp udp } from any port domain to $local_net \
	queue dns_in
pass  out on dc0 proto tcp from any port $ssh_ports to $local_net \
	queue(std_in, ssh_im_in)
pass  out on dc0 proto tcp from any port $im_ports to $local_net \
	queue ssh_im_in
pass  out on dc0 from any to $bob queue bob_in

Przykład 2: Sieć w firmie


  ( IT Dept )  [ Boss's PC ]
       |          |                                   T1
     --+----+-----+---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
            |                         fxp1
         [ COMP1 ]    [ WWW ]         /
                         |           / 
                       --+----------' 

W tym przykładzie, maszyna OpenBSD odgrywa rolę firewalla dla sieci firmy. Firma posiada serwer WWW w "części zdemilitaryzowanej" DMZ swojej sieci, gdzie klienci umieszczają swoje strony web poprzez FTP. Dział IT ma własną podsieć podłączoną do głównej sieci, a szef posiada osobisty komputer na biurku, który wykorzystuje do sprawdzania poczty elektronicznej i surfowania po sieci. Połączenie z Internetem zapewnia linia T1 o przepustowości 1.5Mbps w obu kierunkach. Wszystkie pozostałe segmenty sieci wykorzystują Fast Ethernet (100Mbps).

Administrator sieci zdecydował o następującej polityce kolejkowania:

Poniżej znajduje się zestaw reguł, który spełnia te założenia. Warto zwrócić uwagę, że dyrektywy pf.conf, które odnoszą się bezpośrednio do powyższych założeń są obecne, podczas gdy dyrektywy nat, rdr, opcje, itd nie są pokazane.

# uaktywnienie kolejkowania na wewnętrznym interfejsie, aby kontrolować
# ruch nadchodzący z Internetu. wykorzystanie algorytmu szeregowania cbq
# tak, aby przepustowość każdej kolejki mogła być łatwo regulowana.
# maksymalna przepustowość wychodzącego ruchu to 1.5Mbps.

altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }

# zdefiniowanie parametrów dla kolejek-dzieci.
# std_ext        - standardowa kolejka. także domyślna kolejka dla
#                  wychodzącego ruchu na fxp0.
# www_ext        - kolejka zbiorcza dla kolejek serwera WWW. limit
#                  500Kbps.
#   www_ext_http - ruch http z serwera WWW; wyższy priorytet.
#   www_ext_misc - cały ruch nie-http z serwera WWW.
# boss_ext       - ruch z komputera szefa.

queue std_ext        bandwidth 500Kb cbq(default borrow)
queue www_ext        bandwidth 500Kb { www_ext_http, www_ext_misc }
  queue www_ext_http bandwidth 50% priority 3 cbq(red borrow)
  queue www_ext_misc bandwidth 50% priority 1 cbq(borrow)
queue boss_ext       bandwidth 500Kb priority 3 cbq(borrow) 

# uaktywnienie kolejkowania na wewnętrznym interfejsie, tak aby kontrolować
# ruch nadchodzący z Internetu lub DMZ. wykorzystanie algorytmu
# szeregowania cbq, do regulowania przepustowość dla każdej kolejki.
# przepustowość na tym urządzeniu jest ustawiona na maksimum.
# ruch nadchodzący z DMZ jest w stanie korzystać z całego dostępnego
# pasma, podczas gdy ruch nadchodzący z Internetu będzie ograniczony
# do 1.0Mbps (ponieważ 0.5Mbps (500Kbps) jest zaalokowane dla fxp1).

altq on dc0 cbq bandwidth 100% queue { net_int, www_int }

# zdefiniowanie parametrów dla kolejek-dzieci.
# net_int    - zbiorcza kolejka dla ruchu z Internetu. przepustowość
#              wynosi 1.0Mbps.
#   std_int  - standardowa kolejka. także domyślna kolejka dla
#              wychodzącego ruchu na dc0.
#   it_int   - ruch do sieci działu IT, zarezerwowano dla nich 500Kbps.
#   boss_int - ruch do komputera szefa; przypisano wyższy priorytet.
# www_int    - ruch z serwera WWW w strefie DMZ; z pełną szybkością.

queue net_int    bandwidth 1.0Mb { std_int, it_int, boss_int }
  queue std_int  bandwidth 250Kb cbq(default borrow)
  queue it_int   bandwidth 500Kb cbq(borrow)
  queue boss_int bandwidth 250Kb priority 3 cbq(borrow)
queue www_int    bandwidth 99Mb cbq(red borrow)

# uaktywninie kolejkowania na interfejsie DMZ, aby kontrolować ruch
# skierowany do serwera WWW. cbq jest zastosowane dla tego
# interfejsu ponieważ szczegółowa kontrola pasma jest niezbędna.
# przepustowość na tym urządzeniu jest ustawiona na maksimum.
# ruch z sieci wewnętrznej będzie mógł korzystać z całej
# przepustowości, podczas gdy ruch z Internetu będzie ograniczony
# do 500Kbps.

altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }

# zdefiniowanie parametrów dla kolejek-dzieci.
# internal_dmz   - ruch z sieci wewnętrznej.
# net_dmz        - zbiorcza kolejka dla ruchu z Internetu.
#   net_dmz_http - ruch http; wyższy priorytet.
#   net_dmz_misc - cały ruch nie-http. jest to także domyślna kolejka.

queue internal_dmz   bandwidth 99Mb cbq(borrow)
queue net_dmz        bandwidth 500Kb { net_dmz_http, net_dmz_misc }
  queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow)
  queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow)


queue internal_dmz      # nie są potrzebne żadne dodatkowe ustawienia
queue net_dmz        bandwidth 500Kb { net_dmz_http, net_dmz_misc }
  queue net_dmz_http priority 3 cbq(red)
  queue net_dmz_misc priority 1 cbq(default)


# ... w sekcji reguł filtrujących pf.conf ...

main_net  = "192.168.0.0/24"
it_net    = "192.168.1.0/24"
int_nets  = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net   = "10.0.0.0/24"

boss      = "192.168.0.200"
wwwserv   = "10.0.0.100"

# domyślne blokowanie
block on { fxp0, fxp1, dc0 } all

# reguły filtrujące dla przychodzącego ruchu na fxp0
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
	> 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
	flags S/SA keep state queue www_ext_http

# reguły filtrujące dla wychodzącego ruchu na fxp0
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext

# reguły filtrujące dla przychodzącego ruchu na dc0
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
	> 49151 } flags S/SA keep state queue www_int

# reguły filtrujące dla wychodzącego ruchu na dc0
pass out on dc0 from dc0 to $int_nets

# reguły filtrujące dla przychodzącego ruchu na fxp1
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
	keep state

# reguły filtrujące dla wychodzącego ruchu na fxp1
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
	> 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
	flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
	21, > 49151 } flags S/SA keep state queue internal_dmz

[Wstecz: Zakotwiczenia] [Spis treści] [Dalej: Pule adresów i kierowanie ruchem]


[wstecz] www@openbsd.org
$OpenBSD$