PLD i kilka łącz (routing wielobramowy)

Jakiś, spory już czas temu stanąłem przed zadaniem konfiguracji load-balance'ingu w oparciu o moje ulubione PLD Linux pomiędzy kilkoma łączami zewnętrznymi. Po przeszukaniu sieci prawdę powiedziawszy, nie znalazłem kompleksowego HOW-TO. Może po prostu przeoczyłem, nie mniej jednak dziś postaram się opisać sposób w który ja rozwiązałem powyższy problem

Trochę teorii.

Największą bolączką powszechnie dostępnych tanich łącz klasy TPSA Internet DSL jest ich niesymetryczność. Jeśli cały ruch z wewnętrznej sieci puścimy przez niesymetryczne łącze, to nawet pomimo stosowania QOS istnieje duże prawdopodobieństwo, że użytkownicy programów p2p szybko zapchają upload, co skutkuje skutecznymi opóźnieniami na łączu niezależnymi od wysycenia downloadu. Warto zauważyć również, iż zwykły użytkownik relatywną prędkość jego łącza ocenia poprzez jakość działania najpopularniejszych usług takich jak poczta czy WWW. Interesującym zatem, z punktu widzenia jakości usługi jest priorytetyzacja/izolacja pewnych usług, które mają bezpośredni wpływ na zadowolenie klientów z posiadanego łącza.

Założenia:

  • trzy lub więcej łącz zewnętrznych (InternetDSL)
  • PLD Linux 2.4 jako NAT+HTB. Kernel 2.4 jest z mojego doświadczenia stabilny dla proponowanego rozwiązania. Z kernelami 2.6 nie udało mi się tego uruchomić (być może to jakiś PLD specyfic) nie mniej jednak powszechnie znane są problemy dla tego kernela z HTB.
  • dwie wewnętrzne klasy adresowe

Rozważmy taki układ:

  • eth0, ip: 80.0.0.2, gw: 80.0.0.1: ruch domyślny dla klasy 192.168.1.0/24
  • eth1, ip: 80.0.1.2, gw: 80.0.1.1: ruch domyślny dla klasy 192.168.2.0/24
  • eth2, ip: 80.0.2.2, gw: 80.0.2.1: łącze na wyizolowane usługi dla obu klas
  • eth3, ip: 192.168.1.254: klasa adresowa wewnętrzna
  • eth4, ip: 192.168.2.254: klasa adresowa wewnętrzna

Poprzez ruch domyślny rozumiem wszystkie, nie oznaczone specjalnie pakiety, ruch izolowany to WWW, POP3, SMTP

Implementacja:
Poniższa implementacja jest słuszna właściwie dla każdego systemu wspierającego iproute2 i iptables. Konfigurujemy standardowo 5 interfejsów sieciowych przypisując im właściwe adresy. Nie definiujemy w pliku /etc/sysconfig/network bramy ustawiając parametry na:

GATEWAY=""
GATEWAYDEV=""

Zestaw magicznych komend do skonfigurowania ręcznego routingu.

Przypisujemy kazde łacze do osobnej tablicy routingu:

ip route add default via 80.0.0.1 table 10
ip route add 192.168.1.0/24 via 192.168.1.254 table 10
ip route add 192.168.2.0/24 via 192.168.2.254 table 10           

ip route add default via 80.0.1.1 table 20
ip route add 192.168.1.0/24 via 192.168.1.254 table 20
ip route add 192.168.2.0/24 via 192.168.2.254 table 20           

ip route add default via 80.0.3.1 table 30
ip route add 192.168.1.0/24 via 192.168.1.254 table 30
ip route add 192.168.2.0/24 via 192.168.2.254 table 30

Następnie definiujemy która klasa powinna być routowana przez którą tablicę, przez 10 i 20 puszczamy ruch w całości per klasa adresowa, przez 30 tylko ruch znaczony:

ip rule add from 192.168.1.0/24 table 10
ip rule add from 192.168.2.0/24 table 20
ip rule add from 192.168.1.0/24 fwmark 0x41 table 30
ip rule add from 192.168.2.0/24 fwmark 0x42 table 30           

ip rule add from 80.0.0.2 table 10
ip rule add from 80.0.2.2 table 20
ip rule add from 80.0.3.2 table 30

Definiujemy routing prywatny: domyślna brama, używając wszystkich łącz. Używane będzie dowolne dostępne (wszystko jako jedna komenda):

ip route add default scope global
  nexthop via 80.0.0.1 dev eth0 weight 1
  nexthop via 80.0.1.1 dev eth1 weight 1
  nexthop via 80.0.2.1 dev eth2 weight 1

Tyle z routingiem, komendy można wpisać do własnego skryptu uruchamianego zaraz po podniesieniu interfejsów sieciowych lub po prostu do rc.local

Dalej konfiguracja /proc Opcję rp_filter trzeba ustawić na 0 i uaktywnić ip_forward:

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo "0" > $f; done
sysctl -n -e -w net.ipv4.conf.all.rp_filter="0"
sysctl -n -e -w net.ipv4.ip_forward="1"

Jak wyżej, warto to wpisać razem z komendami konfigurującymi routing.

Teraz iptables:

Standardowo NAT:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to 80.0.0.2
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth0 -j SNAT --to 80.0.0.2
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 80.0.1.2
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth1 -j SNAT --to 80.0.1.2
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth2 -j SNAT --to 80.0.2.2
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth2 -j SNAT --to 80.0.2.2

I znaczymy pakiety które mają iść izolowanym łączem (wcięcie linii to kontunuacja poprzedniej):

iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth3 -p tcp -m mport --dports 25,80,110,443 
   -j MARK --set-mark 0x41
iptables -t mangle -A PREROUTING -i eth4 -p tcp -m mport --dports 25,80,110,443 
   -j MARK --set-mark 0x42
iptables -t mangle -A PREROUTING -m mark ! --mark 0x0 -j RETURN

I tyle.

Jak łatwo zauważyć konfiguracja jest nadmiarowa (np nie trzeba NATować wszystkich klas) ale w przypadku awarii np łącza 80.0.1.2 możemy szybko przełączyć cały ruch na łącze 80.0.0.2 puszczając go przez tablicę 10:

ip rule add from 192.168.2.0/24 table 20 -> ip rule add from 192.168.2.0/24 table 10

Pakiety można znaczyć (mark) wg dowolnych reguł, np. adresu docelowego, dla serwerów gier czy np. GG, adresu źródłowego: można wyizolować ruch dla poszczególnych klientów. Pewnym rozwiązaniem może być także przypisanie do każdej z tablic znacznika (tak jak dla tablicy 30) i znaczenie via iptables całego ruchu. Z doświadczenia: problematycznym jest znaczenie pakietów p2p przez moduł ipp2p ponieważ nie klasyfikuje on wszystkich pakietów poprawnie i występują problemy. Ruch p2p lepiej zostawić nieoznaczony i puścić domyślnym łączem. Nie pokusiłem się również o priorytetyzację VoIP czy eg. Skype. Można do tego użyć modułu Layer7 (??) niedostępnego standardowo w PLD.

Przypuszczalnie całość można, a nawet trzebaby zrobić "koszerniej", routing do /etc/sysconfig/static-routes  /etc/sysconfig/static-rules, konfig /proc do /etc/sysctrl, iptables via jakaś nakładka. Wszystkie udoskonalenia mile widziane w komentarzach.

  1. 2 Responses to “PLD i kilka łącz (routing wielobramowy)”

  2. By Wiktor on gru 14, 2007

    Do poprawienia:

    for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo “0″ > $f; done
    sysctl -n -e -q -w net.ipv4.conf.all.rp_filter=”0″
    sysctl -n -e -q -w net.ipv4.ip_forward=”1″

    PS: no cóż, pewnie jak bym opublikował swoje rozwiązanie (tak z roku 2005), to miałbyś gotowca.

  3. By Arek Kuryłowicz on gru 15, 2007

    Święta racja, zeżarło końcówkę linii przy edycji, oczywiście bez twojej korekty powyższa składnia nie miała prawa działać.

Post a Comment

Security Code: