FRRouting – alternatywa dla Quagga

FRRouting to alternatywa dla Quagga. Fork, który wydaje się być bardziej przyszłościowy. Niektórzy operatorzy już przeszli migrację, co o czymś też świadczy – a musiał być jakiś powód, by przeprowadzić taką migrację. Ponoć jedna z dystrybucji też już zaczęła korzystać z FRRouting.

Aktualnie najbardziej przemawiającym aspektem za migracją jest błąd w Quagga (objawił się w 2018 roku już kilka razy i odczuło go wielu operatorów), który przy otrzymaniu prefixa bardzo mocno zprependowanego kilkaset razy (coraz więcej omyłkowych śmiałków, a mam nadzieję, że nie robią tego specjalnie w pełni świadomości) powoduje błędne przekazanie go przez Quagge kolejnemu peerowi (niekoniecznie Quagga), które to otrzymując błędną informację o prefixie postanawiają zresetować sesję BGP – chyba w nadzieji, że przy kolejnej porcji UPDATE otrzymają poprawne informacje. Jednak po podniesieniu sesji znowu otrzymują prefixa z błędem…i zaczyna sesja BGP flapować. Rezultat ciągłego flapowania…oczywisty.

W wyniku flapowania sesji (czyli ciągłych przeliczeń tras) widać duże skoki obciążenia CPU na serwerach BGP – nawet do 100% – i telefony od klientów.

Z kolei peer z Quaggą, który Ci przekazuje błędne UPDATE – w logach widzi tylko tyle, że Twój BGP resetuje sesje. Nic więcej u niego nie widać – więc jak nie zna tego problemu, to może odbijać pałeczkę, że to z Twoim BGP jest coś nie tak, bo u niego żadnych błędów nie ma w logach.

Ciekawostka dodatkowa: wraz z przejściem z Quagga na FRRouting zauważyłem znaczący spadek obciążenia CPU na systemie: DELL R610, 2x CPU intel X5650, karta sieciowa intel X520-DA2, BGP z dwoma sesjami, OSPF z sześcioma sesjami, ilość forwardowanego ruchu na poziomie 1,5-2 Gbit/s w godzinach szczytu. Na Quagga obciążenie CPU dochodziło w godzinach szczytu do 0,8%, LOAD do 0,3 – na FRRouting: CPU tylko do 0,2%, LOAD tylko do 0,15 – czyli aż kilkukrotny spadek.

Opis problemu z jednego z forum:

My current understanding is that the oversize UPDATE mentioned by Pawel triggered a bug in Quagga which caused that the UPDATE message sent out by Quagga to its peers was malformed.

The error message you see in the logs is then emited by the peers of the Quagga host when they receive the malformed UPDATE message.

źródło: https://lists.gt.net/quagga/users/32649?page=last

Fragment loga z Quaggi (proces BGP):

2017/10/14 08:52:33 BGP: xxx.xxx.xxx.xxx: BGP <b>type 2 length 3294 is too large</b>, attribute total length is 2289.  attr_endp is 0x7fd919d93e9d.  endp is 0x7fd919d93aa8
2017/10/14 08:52:33 BGP: %NOTIFICATION: sent to neighbor xxx.xxx.xxx.xxx 3/5 (<b>UPDATE Message Error/Attribute Length Error</b>) 0 bytes
2017/10/14 08:52:33 BGP: Notification sent to neighbor xxx.xxx.xxx.xxx: type 3/5
2017/10/14 08:52:33 BGP: %ADJCHANGE: <b>neighbor xxx.xxx.xxx.xxx Down BGP Notification send</b>

Przykład sprawdzenia, czy posiadamy długie prependy w tablicy routingu za pomocą vtysh:

bgp# sh ip bgp regexp ^([0-9]+ ){42,}[0-9]+$
BGP table version is 0, local router ID is xxx.xxx.xxx.xxx
Network          Next Hop            Metric LocPrf Weight Path
*>i106.77.88.0/21   yyy.yyy.yyy.yyy                   300      0 51155 174 9498 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 55644 45271 i

To jest przypadek z niezbyt długim prependem (42), ale na dzień pisania artykułu jest najdłuższy i wisi taki jeden w tablicy – więc tylko ten mogę zaprezentować. On nie powoduje problemu, ale ostatnio ktoś rozgłasza czasami znacznie dłuższe prependy.

Jeżeli masz podobny komunikat w logach, to tego felernego prependu nie znajdziesz w swojej tablicy, bo go Twoja Quagga nie otrzymała – odrzuca go na poziomie rozmowy ze źródłowym peerem i nie inicjuje go nawet w tablicy. Widzi go jedynie Twój peer, który Ci go przekazuje – i tylko (ponoć tylko on) może go odfiltrować, by nie przekazywać dalej – do Ciebie. No chyba że nie ma Quaggi, a coś innego – wtedy poprawnie przekaże Ci owego długiego prependa i wtedy będziesz mógł odfiltrowywać takie u siebie.

FRRouting ponoć nie przekazuje takich długich błędnych prefiksów. Niestety nie wiem, czy jest odporny w momencie kiedy on sam taki prefix z ogromnym prependem otrzyma od peera posiadającego quaggę z tym błędem.

Jest na to metoda obejściowa – wdrożenie filtru, który odfiltruje długie prependy i ty samym nie będzie przekazywał ich dalej.

router bgp XXXXX
neighbor xxx.xxx.xxx.xxx route-map ISP-in in
!
ip as-path access-list limit-to-100 permit ^[0-9]+(_[0-9]+_){0,100}$
!
route-map ISP-in permit 10
match as-path limit-to-100

Taka konfiguracja nie przyjmie do lokalnej tablicy routingu wpisów z prependami o długości 100 i więcej i tym samym nie będzie ich przekazywać dalej do kolejnych peerów.

Przy okazji możesz też zapoznać się z drugim fajnym filtrem – który nie przyjmie rozgłaszanych prefiksów z maską większą niż 24. Nie powinno się rozłaszać malutkich klas i póki co żaden operator tego nie robi….a czasem jakiś ziomek potrafi to zrobić „przypadkiem” na jakiś czas…aż zauważy, że rozgłoszenie z dużą maską spowoduje, że części ruchu po prostu nie będzie mieć, bo go wiele BGPów odfiltruje właśnie.

router bgp XXXXX
neighbor xxx.xxx.xxx.xxx route-map ISP-in in
!
ip prefix-list bgp_filter_mask_in seq 10 deny 0.0.0.0/0 ge 25
ip prefix-list bgp_filter_mask_in seq 20 permit 0.0.0.0/0 le 24
!
route-map ISP-in permit 10
match ip address bgp_filter_mask_in

Więc zainstalowałem sobie frrouting na Debianie.

Zastałem wersję 3.0-rc2, ale po 3 dniach pojawiła się już oficjalna wersja 3.0. Póki co wszystko działa już kilka dni i problemów żadnych nie spotkałem, w logach mam czyste i ładne informacje na temat tego, co się dzieje.

Trzeba było skompilować, bo nie ma paczki pod Debiana. Wersję rc2 skompilowałem, uruchomiłem (z malutkimi utrudnieniami), a na maszynie testowej z Debian Stretch spróbowałem zainstalować z oferowanej paczki deb – która była pod Jessie…i niestety nie chciała zajarzyć mówiąc, że jakieś biblioteki nie ma w jakieś tam wersji…która w Jessie jest, a w Stretchu jest nowsza…no i mimo że jest nowsza, to nie poszło. Wróciłem zatem do wersji kompilowanej z tą oficjalną wersją 3.0 i chyba przy tym sposobie zostane – przynajmniej wiem, co mam wkompilowane i mam pewność, że mam wkompilowaną np. obsługę SNMP, z której mam zamiar skorzystać w celach monitoringu i szybszej reakcji na ew. nietypowe up/down sesji.

Utrudnienia przy i po kompilacji, jakie napotkałem

  • make install nie stworzył mi usera i grupy frr w systemie – musiałem dodać ręcznie.
  • make install nie stworzył mi folderu /var/log/frr, ani /var/run/frr. Stworzyłem ręcznie oraz nadałem uprawnienia dla usera frr…jednak ten drugi folder jest w folderze wirtualnym (tmpfs), więc tworzenie jego musiałem sobie dodać do skryptu startującego
  • frr [start|stop|reload|restart|status] po prostu nie działa. Przedebugowałem go ręcznie i okazało się (to plik bashowy), że tuż po linii:
  • . /lib/lsb/init-functions
  • przestaje działać (Debian Jessie oraz Stretch). Coś widocznie nie pasuje temu dołączanemu skryptowi i on zakańcza działanie całego skryptu. Olałem to i napisałem własny prosty i perfekcyjny (jak dla mnie) skrypcik.

Póki co mam to tak:

./bootstrap.sh
./configure \
  --prefix=/opt/frr \
  --localstatedir=/var/run/frr \
  --enable-vtysh \
  --enable-watchfrr \
  --enable-user=frr \
  --enable-group=frr \
  --enable-fpm \
  --enable-snmp=agentx
make
make install

Oczywiście multum bibliotek było wymaganych w systemie, by przejść ten proces – ale to raczej nie problem. Jak jakiś błąd Ci wyskoczy, to odnajdujesz paczkę, która go zawiera i instalujesz…jest tego trochę. No a jeżeli się zniechęcisz…to zawsze możesz przejść na Birda – też go bardzo chwalą i to nawet przy posiadaniu bardzo dużej ilości sesji BGP.

Na moim Debianie Jessie musiałem doinstalować takie pakiety, by przejść proces kompilacji:

apt-get install dh-autoreconf libjson-c-dev libreadline-dev pkg-config libc-ares-dev libsnmp-dev flex byacc bison snmp-mibs-downloader

Dodanie usera „frr” i grupę „frr” – ja to robię bardzo ręcznie dodając kolejne linie w poniższych plikach:

/etc/passwd:

frr:x:111:117:FRRouting:/var/run/frr/:/bin/false

/etc/shadow:

frr:*:17100:0:99999:7:::

/etc/group:

frr:x:117:

Jeżeli chcesz skorzystać z tej samej metody, to tylko upewnij się, że nie użyjesz tych samych UID i GID – użyj takich, które nie są obecnie używane w Twoim systemie!!!

Uruchomienie procesów:

/opt/frr/sbin/zebra -d
/opt/frr/sbin/ospfd -d
/opt/frr/sbin/bgpd -d
/opt/frr/bin/vtysh #też działa i łączy się ładnie z demonami, by nimi zarządzać itp.

To było ręcznie uruchamianie procesów – które trzeba dodać do skryptu startowego, np /etc/rc.local (uwaga: od Debian Stretch nie ma domyślnie rc.local !!!) – o tym napiszę osobny artykuł niebawem wraz z rozwiązaniem, gdyż sam bardzo często używam tego rozwiązania.

Start FRRoutingu poniżej w nieco ulepszonej wersji. Zacznijmy jednak od watchfrr – skryptu monitorującego na bieżąco poprawność działania poszczególnych daemonów.

watchfrr wymaga podania w parametrach, w jaki sposób ma reagować, co ma uruchomić w przypadku padu któregoś z daemonów i które z nich ma monitorować.

Napisałem taki skrypcik i jednocześnie jego tak właściwie dodałem u siebie do /etc/rc.local i jest on moim właściwym skryptem startowym. W praktyce skrypt ten uruchamia nie daemony, a watchfrr, który będzie monitorować na bieżąco działanie poszczególnych daemonów i w razie wykrycia niedziałania któregoś z nich – uruchamia drugi skrypt uruchamiający daemony.

/opt/tymfrrwatch:

#!/bin/bash

DAEMONS="zebra ospfd bgpd"
mkdir /var/run/frr 2>/dev/null
chown frr:frr /var/run/frr 2>/dev/null
mkdir /var/log/frr 2>/dev/null
chown frr:frr /var/log/frr 2>/dev/null
/sun/frr/sbin/watchfrr -d -z -R '/opt/tymfrrrestart' zebra ospfd bgpd

Jak widać, skrypt ten od razu tworzy odpowiednie foldery niezbędne do pracy daemonów, a umieszczenie tego tutaj w jednym skrypcie zwalnia mnie od tworzenia ręcznego tych folderów na każdej nowej maszynie, na której będę instalował FRR, tym bardziej, że folder /var/run jest typu tmpfs, więc po restarcie maszyny trzeba ponownie stworzyć folder /var/run/frr.

i drugi plik, który jest uruchamiany w przypadku wykrycia niedziałania któregoś z monitorowanych daemonów:

/opt/tymfrrrestart:

#!/bin/bash

DAEMONS="zebra ospfd bgpd"
for daemon in $DAEMONS; do
  echo -n $daemon"..."
  echo -n "kill..."
  killall -TERM $daemon 2>/dev/null
  killall -TERM $daemon 2>/dev/null
  echo -n "rm pid..."
  rm -f /var/run/frr/$daemon.pid 2>/dev/null
  rm -f /var/run/frr/$daemon.vty 2>/dev/null
  echo -n "starting..."
  /opt/frr/sbin/$daemon -d
  echo
done

Jedna prymitywność skryptu jest taka, że w obu w nich trzeba zdefiniować daemony uruchamiane i monitorowane…mi takie rozwiązanie wystarczy. Dla moich potrzeb jakość skryptu jest wystarczająca i póki co się sprawdza. Jeżeli masz nadmiar energii Twórczej, to….Twórz

Czyli przy starcie systemu uruchamiam tymfrrwatch. Ten skrypt uruchamia watchfrr z pakietu frrouting. Jego opcje od razu wykryją, że żaden z daemonów nie działa, więc uruchomi skrypt tymfrrrestart, który dla pewności poubija ew. istniejące procesy (za pomocą polecenia killall, więc upewnij się, że masz zainstalowany pakiet psmisc zawierający te polecenie) oraz uruchomi je na nowo…no i masz już uruchomione wszystko.

I jeszcze jedno….utwórz pliki konfiguracyjne /opt/frr/etc/zebra.conf dla zebry oraz analogicznie dla pozostałych procesów (z uprawnieniami zapisu dla usera frr) – one są konieczne, by daemony mogły się uruchomić. Oczywiście wystarczy stworzyć puste pliki, uruchomić frrouting, uruchomić VTYSH za pomocą /opt/frr/sbin/vtysh i tą konsolką wszystko sobie skonfigurować, a na końcu nie zapmnij dać polecenia „write”.

UPDATE: 2018 marzec – widać już wersję 4.0 i paczki pod Debiana – zatem po poprawieniu pierwszych błędów, które się zapewne pojawią, dokonam upgradu i stosownej notki czy obyło się bez niespodzianek.

Reklamy