Jak zrobić dzielenie łącza pod Linux'em - wersja dla ipchains (CBQ)
(dla zaawansowanych!)

UWAGA
Projekt ten jest już od dawna nie rozwijany. Obecnie pracuję nad bardziej uniwersalnym shaperem (nazywa się shaperd), pracującym zarówno na ipchains jak i na iptables. Dlatego zalecam instalowanie daemona shaperd.


UWAGA
Dzielenie łącza to uproszczona nazwa określająca różne metody regulowania szybkości pobierania danych z internetu przez użytkowików. Dzielenie łącza nie ma nic wspólnego z udostępnianiem łącza czyli z umożliwieniem użytkownikom wewnątrz sieci łączenia się z internetem za pośrednictwem serwera. Udostępnianie jest osobnym zagadnieniem i nie jest omówione na tej stronie (szukaj na wyszukiwarkach hasła: maskarada, masquerade, nat, firewall)

Uwaga
Jeśli nie potrafisz się posługiwać ipchains, o samodzielnym pisaniu skryptów w shellu nawet nie wspomnę - to nie masz tu czego szukać. Nie będę pomagał instalować ten skrypt ludziom, którzy nie mają pojęcia o podstawach. Jak ktoś się nie czuje na siłach a mieszka w Krakowie to nie ma problemu - zainstaluję mu to osobiście (pewnie nie za darmo ;-) Reszta musi sobie radzić sama. Jeśli komuś nie pasuje ten skrypt z powodu założeń to wolna droga - proszę sobie go przerobić. Nie mam czasu na pisanie ludziom skryptów pod kątem ich potrzeb - przykro mi bardzo.


historia:

Moja zabawa z dzieleniem łącza zaczęła się od znanego CBQ.init. Skrypt ten dzieli łącze na stałe i niezależnie od tego, czy jest wykorzystywane czy nie. Dla zastosowań providerskich jest może i dobry (a który provider go używa? ;-) ale dla sieci osiedlowych jest beznadziejny. Napisałem więc własny skrypt (a właściwie kilka) do dzielenia łącza w zależności od ilości osób łączących się z internetem w danym momencie jak i od wykorzystywanego przez nich przydzielonego transferu.

Zasada działania
Po włączeniu się w sieć nowego użytkownika i rozpoczęciu transmisji z internetem (lokalne połączenia nie rezerwują łącza), skrypt testuje czy użytkownik nie łączy się przypadkiem z jednym z adresów ip lub portów wpisanych w liście wyjątków (plik /etc/shaper/ignore). Jeśli nie znajdzie takiego wyjątku to przydziela część łącza wynikającą z prostego podziału szybkości maksymalnej łącza przez ilość aktualnie przez nie pracujących komputerów.
Po określonym czasie (zależnie od ustawienia w cronie) - np. po 1 minucie - shaper sprawdza, czy użytkownik wykorzystał co najmniej 50% z przydzielonego łącza. Jeśli nie wykorzystał to zostaje mu przydział zmniejszony o 25%. Jeśli użytkownik wykorzystuje przydział w granicach 50%-75% to skrypt niczego nie zmienia a jeśli wykorzystuje więcej od 75% to shaper zwiększa mu transfer o minimalny transfer (np o 8000 czyli 1KBajt) - pod warunkiem, że coś jeszcze zostało do przydzielenia. Zasada jest taka, że w pierwszej części skrypt sprawdza, komu można obciąć a dopiero na samym końcu z tego co zostanie z przydzielania szybkości dodaje tym co dużo ciągną.
Dzięki temu skrypt zapobiega przejęciu całkowitej kontroli nad łączem przez jednego nawiedzonego maniaka programów P2P lub idioty otwierającego kilkadziesiąt sesji WWW. Skrypt reguluje tylko transfer przychodzący z internetu do użytkowników.

OSTRZEŻENIE
Autor tego oprogramowania nie bierze odpowiedzialności za jakiekolwiek błedy, awarie i uszkodzenia wywołane przez działanie tego skryptu. Wszystko co robisz - robisz na własną odpowiedzialność.
Skrypt ten testowany jest na systemach opartych na jądrze 2.2.9, 2.2.13, 2.2.20 oraz Mandrake 6.0, Mandrake 6.1, Slackware 8.0 na łączach SDI oraz 460kbit dzierżawione od ISP (tu musiałem w cronie w zależności od pory dnia wpisywać inne wartości maksymalnego transferu dla skryptu bo provider sprzedał więcej łącz niż sam miał i w dzień transfer był dużo niższy niż w nocy ;-)
Wersje programów z którymi testowany był shaper:
ipchains 1.3.8, 27-Oct-1998 (100KB)
iproute2-2.2.4-now-ss990417-2 (77KB)
iproute2-2.2.4.ss001007-3.i386.rpm (330KB)
iproute2-ss000305
iproute2-ss010824

Szukaj iproute2-2.2.4
Szukaj iproute2
Nie testowałem tego skryptu na systemach z większą ilością interfejsów - nie mam na razie gdzie. Będę wdzięczny za przetestowanie i przysłanie mi relacji.

Pobierz shaper_cbq.tar.gz (4.09-03.05.2002)

Uwaga użytkownicy ipchains w kernelach 2.4.x

Skrypt ten nie był testowany na kernelach 2.4.x a doszły mnie słuchy, że w tych kernelach występują pewne trudności z ipchains i maskowanymi połączeniami, które "wiszą" po kilka dni pomimo faktu, że komputer, który je utworzył, od dawna jest wyłączony. Musiałem zrobić specjalne obejście tego problemu i dlategow archiwum niektóre skrypty są dostępne w dwóch wersjach (dla 2.2.x i 2.4.x) oraz w przypadku 2.4.x należy dodatkowo zainstalować skrypt ckexpire do katalogu /sbin.


Aby wogóle dzielenie łącza pod Linuxem zaczęło działać to musi być spełnione wiele warunków:
  1. zainstalowany pakiet iproute2
  2. przekompilowane jądro aby obsługiwało CBQ. Jeśli nie wiesz, co ustawić do kompilacji to zaglądnij tutaj.
  3. Skrypt korzysta z ipchains. Aby działał z iptables albo ipfwadm trzeba go przerabiać. Potrzebne jest dopisanie kilku regułek do ipchains aby umożliwić skryptowi kontrolę wykorzystania łącza.
    Przykład takiej regułki:
    ipchains -M -S 300 10 60
    
    ipchains -N eth0-out
    ipchains -A output -i eth0 -j eth0-out
    ipchains -A eth0-out -p all -s ! 192.168.1.1 -d 192.168.1.2 -j ACCEPT
    ipchains -A eth0-out -p all -s ! 192.168.1.1 -d 192.168.1.3 -j ACCEPT
    ipchains -A eth0-out -p all -s ! 192.168.1.1 -d 192.168.1.4 -j ACCEPT
    
    Gdzie:
    192.168.1.1 to numer ip bramki (lokalny)
    192.168.1.2-255 to numery ip komputerów w sieci
    eth0 nazwa interfejsu lokalnego w sieci (patrz opis konfiguracji - plik /etc/shaper/shaper.cfg)
    ipchains -M -S 300 10 60 zmniejsza czas trzymania połączenia na maskaradzie do 5 minut.
    Takie regułki rejestrują ilość danych pobraną z internetu przez poszczególnych użytkowników (z jednego interfejsu).
    Aby sprawdzić, czy te regułki rejestrują prawidłowo ilość pobranych danych wystarczy wklepać:
    ipchains -vL eth0-out -n | grep ! | awk '{print $11,$2}'
    Co powinno wyświetlić mniej wiecej coś takiego:
    192.168.1.2 414M
    192.168.1.3 0 
    192.168.1.4 0 
    192.168.1.5 93M 
    192.168.1.6 304M
    192.168.1.7 51M 
    192.168.1.9 347M
    
    Jeśli wszytkie numery ip są takie same to znaczy, że twoja wersja ipchains różni się od mojej i w innej kolumnie trzyma te numery. Sprawdź to wpisując:
    ipchains -vL eth0-out -n | grep !
    
    Otrzymasz w wyniku coś mniej więcej takiego (podaję jako przykład jedną linijkę, choć na ekranie mieści się w dwóch):
     991K  858M ACCEPT     all  ------ 0xFF 0x00  *          0x1f                 !192.168.1.1           192.168.1.2           n/a
    
    I teraz policz kolumny od lewej do prawej (traktując te dwie linijki jak jedną długą). W tym przypadku wartość 192.168.1.2 znajduje się w 11 kolumnie, a ilość pobranych danych w kolumnie 2, czyli komenda:
    ipchains -vL eth0-out -n | grep ! | awk '{print $11,$2}'
                                                    ^^  ^
                                                    |   |
                    pozycja numeru ip docelowego ---/   \---- pozycja licznika pobranych danych
    
    Jeśli u Ciebie potrzebne dane są w innej pozycji w zmień je w skrypcie /root/ckspeed - na samym końcu skryptu jest:
    ipchains -vxL eth0-out -n | grep ! | awk -v pos=$dt '{print $11,$2,pos}' > /var/shaper/bitrate_user.tmp
    
    Jeśli regułki nie rejestrują żadnego ruchu przychodzącego (są same zera) to poczytaj sobie man do ipchains lub ipchains-HOWTO. Pewnie wcześniej w regułkach masz wpisane coś, co spełnia wszystkie warunki dla każdego numeru ip. Jeśli masz kilka interfejsów to może być troche kłopotliwe wpisywanie ręczne tylu regułek. Dlatego do archiwum shaper_cbq dołączyłem skrypt ipallow w wersji obsługującej wiele lokalnych interfejsów i korzystającego częściowo z konfiguracji shapera_cbq. Jedyne co w skrypcie ipallow trzeba skonfigurować to zmienić nazwę interfejsu który jest dołączony do internetu w linijce:
    internet_iface="ppp0"
    Reszta opisu do tego skryptu znajduje się na stronie Maskarada mogę tylko jeszcze wspomnieć, że jakby ktoś chciał to mogę mu podesłać dodatkowo skrypt do generowania statystyk poszczególnych użytkowników w programie lstat-0.94 (działa na pewno z wersją 0.94 - z nowszą nie sprawdzałem) z zapisów generowanych przez ipallow.
  4. Jeśli używasz na serwerze squida to niestety - skrypt dla niego nie przydzieli szybkości i może się okazać, że łącze będzie zapychane nie przez użytkowników, ale przez squida. Na razie nie mam rozwiązania tengo problemu i dlatego trzeba się zdecydować co używać: albo shaper albo squid. Jedno trzeba wyłączyć.
  5. Aby przetestować jądro pod kątem zgodności z CBQ trzeba zainstalować iproute2 i wpisać komendę:
  6. tc -d qdisc
    Jeśli w wyniku jej działania pojawi się jakiś komunikat typu RTNETLINK error to jądro nie obsługuje CBQ (lub nie ma załadowanego modułu).
    Jeśli jest gotowe to ta komenda nic nie wyświetli (wyświetla przydzielone widełki).
  7. Skrypt shaper działa przy pewnych założeniach:
    • parametry łącz lokalnych w sieci należy wpisać do pliku konfiguracyjnego /etc/shaper/shaper.cfg
      Przykładowy plik konfiguracyjny dla serwera z 1 interfejscem lokalnym eth0 o przepustowości 10Mbit. Używam go dla SDI i normalnej dzierżawki.
      mainip=212.17.14.118
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      
      Gdzie:
      • mainip numer ip zewnętrzny serwera
      • local_int parametry lokalnych interfejsów
      • eth0 - nazwa interfejsu. Nie wpisuj tutaj interfejsu łączącego z internetem!
      • 10485760 - szybkośc interfejsu w bitach/sek (10MBit=10*1024*1024 bit)
      • 192.168.0.0/16 - numer ip interfejsu (w tym przypadku jest to maska sieci klasy C co powoduje, że wszystkie transfery od numerów ip pasujących do tej maski nie będą miały ograniczeń. Chodzi o to aby transfer lokalny z serwera bądź rutowany przez interfejsy od ludzi lokalnych w sieci nie był przycinany).
      • 192.168.1.0/24 - numer ip docelowy z maską dla którego stosowany jest shaper (czyli maska podsieci stosowana na danym interfejsie - np eth0 może mieć 192.168.1.0/24 a eth1 192.168.2.0/24 - nuery ip w podsieci to 192.168.2.0-255)
      • 10 - identyfikator klasy (starszy bajt) (dla każdego interfejsu musi być inny - najlepiej kolejny po 10).

    • Przykładowy plik konfiguracyjny dla serwera z 2 interfejsami lokalnymi eth0 i eth1 o przepustowości 10Mbit i 100Mbit.
      mainip=212.17.14.118
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      local_int=eth1;104857600;192.168.0.0/16;192.168.2.0/24;11
      

      Przykładowy plik konfiguracyjny dla serwera z 3 interfejsami lokalnymi eth0, eth1, ppp1 (łącze dzierżawione miedzy np dwoma budynkami) o przepustowości 10Mbit, 100Mbit i 768Kbit (dla tego interfejsu ograniczamy transfery również lokalne).
      mainip=212.17.14.118
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      local_int=eth1;104857600;192.168.0.0/16;192.168.2.0/24;11
      local_int=ppp1;786432;192.168.3.1/32;192.168.3.0/24;12
      
    • Należy wklepać wszystkie lokalne numery ip i obok nazwy interfejsów przez które te numery pracują (nie chciało mi się robić rozpoznawania w skrypcie po maskaradzie ;-) w pliku /etc/shaper/iplist.Przykład:
      192.168.1.2=eth0
      192.168.1.3=eth0
      192.168.1.4=eth0
      192.168.1.5=eth0
      192.168.2.2=eth1
      192.168.2.3=eth1
      192.168.2.4=eth1
      192.168.2.5=eth1
      
    • Prędkość łącza internetowego (nazwa jest nie ważna byle tylko było) jest podawana jako argument skryptu np.
      /sbin/shaper 115200 8000
      gdzie 115200 to maksymalnie 115kbit a 8000 to 8kbit czyli minimalny przydział dla użytkownika (podzielić sobie szybkość na ilość użytkowników sieci). Dobrze jest podawać szybkość nie deklarowaną a rzeczywistą, jaką udaje się uzyskać ciągnąc coś przez dłuższy czas przez to łącze w kierunku z internetu do sieci. Inaczej dzielenie wirtualnej szybkości mija się z celem. Łącze SDI nie pracuje z szybkością 115kbit tylko 96kbit (w jedną stronę) więc wpisywanie większych wartości powoduje tylko tyle, że ktoś dostanie w sieci przydział szybkości, którego nigdy nie uda mu się osiągnąć. Po co więc kogoś oszukiwać. Ja dla SDI daję 100000.
    • Jeśli CBQ jest w modułach to przy starcie systemu trzeba wrzucić następujące moduły:
      modprobe sch_cbq
      modprobe sch_tbf
      modprobe cls_u32
      
  8. Skrypt musi działać na prawach root i mieć możliwość zapisu do katalogu /var/shaper. Katalog taki trzeba założyć z właścicielem root i prawami 755
  9. Skrypt najlepiej dopisać do crona np. w pliku /etc/crontab dopisać taką linijkę:
    */1 * * * * root /sbin/shaper 115200 8000
    
  10. W /etc/shaper sa wpisane wyjątki dla których shaper nie rezerwuje łącza. Mogą to być przykładowo:
    217.96.55.5 411 - numer ip i port 411
    213.180.130.190 - numer ip i kazdy port
    22$ - każdy numer ip i port 22 (telnet)
    Zrobione jest to po to, żeby skrypt nie rezerwował łącza na transmisje nie generujące praktycznie ruchu (np. GaduGadu, IRC, telnet, Chaty itp). Aktualną listę branych pod uwagę numerów ip i portów na maskaradzie można podglądnąć skryptem:
    shaper_test
  11. W katalogu /var/shaper generowane są przez skrypt pliki robocze:
    • bitrate_user.tmp - zawiera listę numerów ip i ilość pobranych z internetu danych w bajtach. Aby był właściwy musza być prawidłowo dokonane wpisy ipchains. Tak to wygląda u mnie:
      192.168.1.2 441127061 1008227523
      192.168.1.3 0 1008227523        
      192.168.1.4 0 1008227523        
      192.168.1.5 93120766 1008227523 
      192.168.1.6 304302374 1008227523
      192.168.1.7 51299622 1008227523 
      192.168.1.9 373967723 1008227523
      n/a 0 1008227523                
      
    • /var/shaper/bitrate_user_sh.old - zawiera numery ip oraz przydzielone widełki. Można to wykorzystać do wizualizacji na stronie www - przykład użycia. A może wyglądać tak:
      192.168.1.2 40000
      192.168.1.9 58000
      
    • /var/shaper/bitrate_user_out_sh.old - obecnie nie używany.
    • /var/shaper/masq.tmp - spis numerów ip którym są przydzielane widełki. Może wyglądać tak:
      192.168.1.5
      192.168.1.9
      
  12. W katalogu /root znajdują się dodatkowe skrypty używane przez shapera. Są to:
    • ckspeed - skrypt wykorzystywany przez shapera do obliczania transferu
    • ckbitrate_user - pokazuje aktualny wykorzystywany transfer (w bit/sek) przez dany numer ip. Przykład:
      ckbitrate_user 192.168.1.2
      
    • ckbitrate_user_last - pokazuje ostatni przydzielony transfer (w bit/sek) dla danego numeru ip. Przykład:
      ckbitrate_user_last 192.168.1.2
      
    • shaper_test - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza. Przykład:
      shaper_test
      
    • shaper_test - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza. Przykład:
      shaper_test
      
    • shaper_test_dns - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza (i zamienia je na domeny - dla czytelnosci). Przykład:
      shaper_test_dns 192.168.1.2
      
    • shaper_off - usuwa przydziały łącz (służy jedynie do testów). Jak skrypt jest uruchamiany przez crona to i tak za chwile się włączy. Przykład:
      shaper_off
      
  13. Jeśli w sieci jest dużo użytkowników to czas uruchamiania skryptu może się tak wydłużyć, że dłużej będzie się uruchamiał niż działał. Należy wtedy zmniejszyć częstotliwość uruchamiania skryptu na rzadziej np co 2 lub 3 minuty. Skrypt bardzo obciąża system.
  14. Warto sprawdzić jak skrypt działa dajac komendę:
    tc -s qdisc
    
    Wyniki jej działania mogą wygladac tak:
     qdisc tbf d09f: dev eth0 rate 5430bps burst 10Kb lat 1.2s              
     Sent 108930 bytes 73 pkts (dropped 0, overlimits 0)                   
                                                                           
     qdisc tbf d09e: dev eth0 rate 5430bps burst 10Kb lat 1.2s             
     Sent 126618 bytes 89 pkts (dropped 0, overlimits 0)                   
                                                                           
     qdisc tbf d09d: dev eth0 rate 1638bps burst 10Kb lat 3.8s             
     Sent 54699 bytes 65 pkts (dropped 0, overlimits 321)                  
     backlog 6110b 5p                                                      
                                                                           
     qdisc tbf d09c: dev eth0 rate 10Mbit burst 10Kb lat 4.8ms             
     Sent 0 bytes 0 pkts (dropped 0, overlimits 0)                         
                                                                           
     qdisc tbf d09b: dev eth0 rate 10Mbit burst 10Kb lat 4.8ms             
     Sent 5690 bytes 53 pkts (dropped 0, overlimits 0)                     
                                                                           
     qdisc cbq 10: dev eth0 rate 10Mbit (bounded,isolated) prio no-transmit
     Sent 310829 bytes 302 pkts (dropped 0, overlimits 1555)               
     backlog 5p                                                            
      borrowed 0 overactions 0 avgidle 624 undertime 0
    
    Nalezy zwrócić szczególną uwagę na linie z rate innym niż 10Mbit (lub innym w przypadku posiadania łącza lokalnego o innej szybkości maksymalnej). W tym przypadku trzy pierwsze klasy obrazują transfery trzech różnych komputerów w sieci lokalnej. Należy zwrócić uwagę, czy rejestrowane są wielkości wysłanych danych Sent i czy pojawiają się jakieś wartości przy dropped i overlimits. Jeśli tak to znaczy, że CBQ działa i obcina transfer przekraczający widełki.
  15. W razie wystąpienia problemów przy uruchomieniu skryptu, zanim do mnie napiszesz - postaraj się przeczytać ten opis jeszcze raz i sprawdź, czy nie popełniłeś gdzieś błedu. Potem dopiero możesz pisać do mnie. Ze względu na brak czasu moja pomoc może być trochę opóżniona więc polecam zaglądnięcie do Księgi gości. Może ktoś z wpisanych tam adminów zechce pomóc wcześniej niż ja będę w stanie to zrobić.
  16. Jeśli przebrniesz przez instalację i uda Ci się skonfigurować ten skrypt na swoim serwerze, może zechcesz się wpisać do Księgi gości. Proszę, podaj w niej:
    • Opis systemu na serwerze (dystrybucja, wersja kernela, inne uwagi)
    • swój e-mail kontaktowy (możesz go zakończyć jakimś "ściemniaczem anyspamowym" ;) typu .NOSPAM)
    • url strony www (jesli isnieje) serwera
    Może pomożesz innym w instalacji tego skryptu a mnie trochę odciążysz. Będę bardzo wdzięczny.
  17. Będzie mi miło, jeśli jakiś szczęśliwy administrator wrzuci gdzieś na swoją stronę sieciową ten mały banerek:

    Powered by Shaper CBQ

    A tutaj jest kod html do wklejenia:
    <p><a href="http://sp9wun.republika.pl/">
    <img src="http://sp9wun.republika.pl/linux/pics/shaper.png" border="0" 
    width="89" height="32" alt="Powered by Shaper CBQ"></a></p>
Poniżej można zobaczyć jak taki skrypt się zachowuje na statystykach. Statystyka jest dla ppp-out pomimo faktu, że skrypt dzieli tak na prawdę łącze eth0 (czyli lokalne).

Statystyki wygenerowano programem lstat-0.94

Jak ktoś chce sobie takie statystyki generować to tu można sobie ściągnąć skrypt do generowania ustawień dla lstat'a na podstawie wpisów generowanych przez skrypt ipallow.tar.gz.

Pobierz lstat-0.9_adds.tar

Ten skrypt działa u mnie ale u innych wcale nie musi. Mogą być inne ścieżki do plików i dlatego jak ktoś chce go używać to proszę sobie go poprzerabiać. Skrypt działa tylko z ipallow.

Zobacz skrypt CGI kto.cgi lub PHP kto.php (dodtakowy skrypt ckwintalk do kontroli wintalka - u mnie w sieci wintalk jest obowiązkowy) do generowania listy aktywnych komputerów wraz z przydzielonymi im widełkami przez shaper'a. Skrypt trzeba wyedytować i powpisywać dane ze swojej sieci. Wywołuje się go odwołując się do kto.cgi?60 (lub kto.php - dla PHP)
60 - oznacza, że skrypt będzie odświerzany co 60 sekund.



Powrót Linux
@
Webmaster Grzegorz Fitrzyk