jak pewnie można było zauważyć miałem ostatnio okazję pobawić się ponownie paczkami routingu dynamicznego w ogólnodostępnych OSach. z perspektywy znajomości CLI trzymałem się FRRouting, który jest ewolucją pakietu Quagga, która z kolei jest ewolucją pakietu Zebra. a składnia poleceń i cały interfejs linii poleceń (CLI) przypomina Cisco IOS.

FRRouting

podziękowania dla Joba Snijdersa za korektę - ten projekt już nie nazywa się OpenFRR tylko FRRouting. przepraszam! :)

niestety, o ile FRRouting sprawdza się doskonale w mojej sieci, w trakcie wdrożenia AS112 trafiłem na niemiłą niespodziankę. FRRouting “zapominał” wpisów do ARP do bezpośrednio podłączonych adresów next-hop. to powodowało, że BGP nie chciał używać tras jako najlepszych… i ruch był wysyłany złymi ścieżkami. było to o tyle problematyczne, że o ile i tak ściągamy i odrzucamy “prywatne” zapytania DNS, nie zwracaliśmy pytającemu odpowiedniej informacji co mogło powodować np. przedłużone oczekiwanie użytkownika danej aplikacji na wygaśnięcie zapytania DNS.

najpierw założyłem, że to wina tuningu stosu sieciowego, który dla porządku robi się w sysctl.conf albo reguł filtrowania ruchu w pf.conf.

jednak po wyczyszczeniu wszystkich modyfikacji problem nadal występował. FRRouting krótko po starcie nadal zapominał next-hopy. podejrzewam, że jest to związane w jakiś sposób z zawodzącą komunikacją, którą posługują się procesy bgpd i zebra w systemach BSD. pójście dalej oznaczałoby jednak, że muszę sam zakasać rękawy i oglądać kod - twórcy projektu FRRouting na razie wydają się koncentrować bardziej na Linuksie a nie systemach BSD.

OpenBGPd

postanowiłem więc zwrócić się do swojego starego znajomego projektu OpenBGPd. kiedyś nawet popełniłem łatki pozwalające skomplikować OpenBGPd na FreeBSD i nadal używam OpenBGPd do części zastosowań (np. wszystkie tzw. feedery projektu BGP Blackholing PL pracują pod kontrolą tego systemu.

w drzewie portów FreeBSD można znaleźć obecnie dwie wersje OpenBGDd - opartą o 5.5 i o 6.6 (tzw. przenośną). ostatni raz dotykałem wersji 5.5, więc ucieszyłem się widząc, że jest już 6.6.

po przygotowaniu konfiguracji i odpaleniu jednego z serwerów tras i DNS jednocześnie pod kontrolą OpenBGPd zauważyłem jednak, że wersja 6.6 nie instaluje najlepszych tras do tablicy RIB kernela (a zatem, prefiksy od nich zależące nie są rozgłaszane do sąsiadów). po szybkim procesie grzebania w konfiguracji i debugu zachowania OpenBGPd zauważyłem, że nie instaluje on w ogóle żadnych tras w FIBie FreeBSD (czyli kernelu). zacząłem myśleć co takiego robię źle, ale na szczęście jeszcze raz sprawdzenie dokumentacji portu (RTFM!!!) przyniosło wytłumaczenie. niech mi wolno będzie zacytować:

root@as112:/usr/local/etc # pkg info openbgpd6
openbgpd6-6.6p0_1
Name           : openbgpd6
Version        : 6.6p0_1
[...]
Description    :
OpenBGPD is a FREE implementation of the Border Gateway Protocol, Version 4.
It allows ordinary machines to be used as routers exchanging routes with
other systems speaking the BGP protocol.
This is the portable version and it does not have the means to
influence kernel routing tables. It is only suitable for route
servers/collectors.

no cóż… jeśli w ogóle nie prowadzimy interakcji z RIBem i FIBem kernela, to w zasadzie rozwiązanie jest bezużyteczne. co prawda istotnie, dla rozwiązań w których istotny jest tylko control-plane może działać, w naszym AS112 z uwagi na różne konfiguracje, idealnie byłoby mieć coś co działa dla obu scenariuszy wdrożenia.

i wchodzi BIRD

moje pierwsze kroki z BIRD zrobiłem jeszcze gdy rozwijana była dopiero wersja 1. bird miał w niej osobne demony do IPv4 i IPv6. konfiguracja nie była też najbardziej przejrzysta i przyjazna, postanowiłem zatem go zostawić w spokoju.

w sytuacji w której się znalazłem, BIRD nagle stał się dobrą alternatywą biorąc pod uwagę problemy z FRRouting.

żeby nie przedłużać - BIRD w wersji 2 używa pojedynczego pliku konfiguracyjnego i po krótkiej lekturze dokumentacji daje się go całkiem szybko uruchomić. jest co prawda trochę niepotrzebnych “przeciążeń” słownictwa używanego w sieciach (np. słowo kluczowe protocol w BIRD używane jest na oznaczenie wewnętrznych kanałów komunikacji a nie faktycznych protokołów routingu), ale po jakimś czasie idzie się przyzwyczaić.

tak więc dla jednej z reprezentatywnych konfiguracji w projekcie AS112 (porównaj to do oryginalnej konfiguracji z FRRouting dla bgpd i staticd):

log syslog all;
router id A.B.C.D; # twój router-ID dla BGP

filter as112_v4
prefix set allnet4;
{
   allnet4 = [
     192.175.48.0/24,
     192.31.196.0/24
   ];
   if ! (net ~ allnet4) then reject;
   accept;
   # filtr sprawdza konkretne prefiksy, które rozgłaszamy
   # do sąsiadów po IPv4 w ramach AS112
}
filter as112_v6
prefix set allnet6;
{
   allnet6 = [
     2001:4:112::/48,
     2620:4f:8000::/48
   ];
   if ! (net ~ allnet6) then reject;
   accept;
   # to samo ale dla IPv6
}
protocol device {
        interface "vmx0" {
                preferred A.B.C.D;
                preferred 2001:A:B:C::1;
                # jeśli masz więcej adresów na interfejsach
                # (ja używam loopback0), w ten sposób można upewnić
                # się, że będą preferowane przez BIRD
        };
}       
protocol direct IF_VMX0 {
        interface "vmx0";
        ipv4;                   
        ipv6;                   
}
protocol kernel kipv4 {
        ipv4 {                  
                table master4;  
                import all;     # tutaj ostrożnie - BIRD zainstaluje w Twoim
                                # OSie trasy pozyskane z BGP, w moim
                                # przypadku tego właśnie chcę
                export all;     # eksportujemy również prefiksy z systemu
                                # operacyjnego do BGP
        };
        learn;
}
protocol kernel kipv6 {
        ipv6 {
                table master6;
                import all;
                export all;     # to samo dla IPv6
        };
        learn;                  
}
protocol static sipv4 {
        ipv4;                   # trasy statyczne przez nas samych
        route 192.175.48.0/24 via A.B.C.D;
        route 192.31.196.0/24 via A.B.C.D;
}
protocol static sipv6 {
        ipv6;                   # to samo dla IPv6
        route 2001:4:112::/48 via 2001:A:B:C::D;
        route 2620:4f:8000::/48 via 2001:A:B:C::D;
}
template bgp RS_v4 {                    # wzorzec dla sąsiadów IPv4 BGP
        local A.B.C.D as 112;
        ipv4 {
                import all;
                export filter as112_v4; # filtr zdefiniowany powyżej
        };
};
template bgp RS_v6 {                    # wzorzec dla sąsiadów IPv6 BGP
        local 2001:A:B:C::D as 112;
        ipv6 {
                import all;
                export filter as112_v6; # filtr zdefiniowany powyżej
        };
};
protocol bgp RS1_IPv4 from RS_v4 {
        description "RS IPv4 #1";
        neighbor C.D.E.F as 65055;       # sesja IPv4 używająca wzorca powyżej
};

protocol bgp RS1_IPv6 from RS_v6 {
        description "RS IPv6 #1";
        neighbor 2001:C:D:E::F as 65055; # sesja IPv6 używająca wzorca powyżej
};

po konfiguracji można zweryfikować co się dzieje korzystając z interaktywnego CLI (birdc) albo bezpośrednio z powłoki. żeby sprawdzić prefiksy rozgłoszone do sąsiadów należy wydać polecenie:

$ birdc show route export RS1_IPv4
BIRD 2.0.7 ready.
Table master4:
192.175.48.0/24      unicast [sipv4 14:06:50.346] * (200)
	via A.B.C.D on vmx0
192.31.196.0/24      unicast [sipv4 14:06:50.346] * (200)
	via A.B.C.D on vmx0

wszystkie kanały komunikacji (“protokoły”) można natomiast podejrzeć wraz z ich statusem w ten sposób:

$ birdc show protocols
BIRD 2.0.7 ready.
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     14:06:50.346  
IF_VMX0    Direct     ---        up     14:06:50.346  
kipv4      Kernel     master4    up     14:06:50.346  
kipv6      Kernel     master6    up     14:06:50.346  
sipv4      Static     master4    up     14:06:50.346  
sipv6      Static     master6    up     14:06:50.346  
RS_IPv4    BGP        ---        up     14:06:55.213  Established   
RS_IPv6    BGP        ---        up     14:06:55.212  Established

żeby sprawdzić ilość prefiksów rozgłoszonych i otrzymanych można wykonać polecenie:

$ birdc show route count
BIRD 2.0.7 ready.
13 of 13 routes for 9 networks in table master4
14 of 14 routes for 10 networks in table master6
Total: 27 of 27 routes for 19 networks in 2 tables

podsumowanie

mogę zarekomendować wykorzystanie BIRDv2 jako działającego rozwiązania routingu jeśli szukasz rozwiązań z otwartym kodem. konfiguracja może wydawać się początkowo skomplikowana, choć korzystając z wbudowanego CLI i trochę odmiennej konfiguracji - da się przyzwyczaić.