OWI, comment injecter des préfixes dans un routeur BGP à partir d'une RIB au format MRT. Pratique quand on veut utiliser une full view dans un lab mais que l'on n'a pas un routeur de la DFZ sous la main.
Seul inconvénient : le parse pour injection avec bgpsimple est long : il faut compter ~20 mns pour un dump de 7,8 millions de lignes et jusqu'à ~1h pour un dump de 13 millions de lignes, en fonction de la vitesse de votre CPU. Bien que la la full view v4 tourne actuellement autour de 513000 routes, il ne faut pas oublier que la taille du dump dépend de la connectivité du routeur qui l'a produit : plusieurs chemins = plusieurs entrées dans la RIB, certains opérateurs désagrègent les préfixes, ...
Quelques améliorations/màj du tuto :
libbgpdump/bgpdump
* Dernière version de libbgpdump :
http://www.ris.ripe.net/source/bgpdump/libbgpdump-1.4.99.13.tgz
* apt-get install libbz2-dev zlib1g-dev
Si vous ne le faites pas avec le ./configure, alors vous aurez l'erreur suivante lors de la compilation :
libbgpdump.a(cfile_tools.o): In function `cfr_open':
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:91: undefined reference to `gzdopen'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:144: undefined reference to `BZ2_bzReadOpen'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:147: undefined reference to `BZ2_bzReadClose'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:162: undefined reference to `gzopen64'
libbgpdump.a(cfile_tools.o): In function `cfr_close':
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:206: undefined reference to `gzclose'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:199: undefined reference to `BZ2_bzReadClose'
libbgpdump.a(cfile_tools.o): In function `cfr_read':
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:307: undefined reference to `gzread'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:310: undefined reference to `gzeof'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:267: undefined reference to `BZ2_bzRead'
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:291: undefined reference to `BZ2_bzReadClose'
libbgpdump.a(cfile_tools.o): In function `cfr_getline':
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:394: undefined reference to `gzgets'
libbgpdump.a(cfile_tools.o): In function `cfr_strerror':
/home/guigui/libbgpdump-1.4.99.13/cfile_tools.c:473: undefined reference to `gzerror'
collect2: error: ld returned 1 exit status
Vous pourrez toujours relancer la config' de la compil' ou ajouter « -lz -lbz2 » à la variable CFLAGS.
* « ./configure --disable-ipv6 » -> non, en 2015 on compile avec le support IPv6 !
* Lors du make install, vous aurez l'erreur suivante :
make: *** Pas de règle pour fabriquer la cible « testbgpdump », nécessaire pour « install ». Arrêt.
Il suffit de : sed -i s/testbgpdump// Makefile puis de relancer make install
* bgpdump permet d'écrire directement dans un fichier, pourquoi écrire sur stdout puis rediriger ?
zcat bview.20090820.2359.gz | bgpdump -m - > rib.ris.20090820.2359
s'écrit
zcat bview.20090820.2359.gz | bgpdump -m -O rib.ris.20090820.2359 -
* Dans le même ordre d'idée, bgpdump accepte désormais les fichiers compressés (gzip, bzip2) en entrée
zcat bview.20090820.2359.gz | bgpdump -m - > rib.ris.20090820.2359
s'écrit
bgpdump -m -O rib.ris.20090820.2359 bview.20090820.2359.gz
* Il n'y a pas que le RIPE qui propose des RIB au format MRT. Le projet Route Views (
http://www.routeviews.org/) propose aussi cela.
Exemple :
wget
ftp://archive.routeviews.org/route-views.linx/bgpdata/2014.12/RIBS/rib.20141230.1400.bz2
bunzip2 rib.20141230.1400.bz2 ; bgpdump -m -O rib.rw.20141230.1400 rib.20141230.1400 ou, directement : bgpdump -m -O rib.rw.20141230.1400 rib.20141230.1400.bz2
bgpsimple
* Dernière version de bgpsimple : wget
http://bgpsimple.googlecode.com/svn/trunk/bgp_simple.pl
* chmod +x bgp_simple.pl
* Par défaut, il écrit les updates qu'il effectue sur stdout même si on ne lui demande pas d'être verbeux ! Ce comportement tue les performances (~6000 lignes parsées par minute avec affichage, ~13000 sans affichage !). Pour virer l'affichage, il faut mettre en commentaire les lignes 640 à 649 :
=pod
sub_debug ("u", "Send Update: ") if (!$dry);
sub_debug ("u", "Generated Update (not sent): ") if ($dry);
sub_debug ("u", "prfx [$prefix] aspath [$aspath] ");
sub_debug ("u", "locprf [$local_pref] ") if ($peer_type eq "iBGP");
sub_debug ("u", "med [$med] ") if ($med);
sub_debug ("u", "comm [@communities] ") if (@communities);
sub_debug ("u", "orig [$nlri[7]] ");
sub_debug ("u", "agg [@agg] ") if (@agg);
sub_debug ("u", "atom [$atomic_agg] ") if ($atomic_agg);
sub_debug ("u", "nxthp [$nexthop]\n");
=cut
* Si vous utilisez des routeurs logiciels, il vous faudra deux machines (ou jouer avec les netns / VM) car le routeur d'en face ne se laissera pas berner par une IP locale (une IP présente sur l'une des interfaces de la machine (lo, eth0, ...) + l'option « -nolisten » de bgpsimple. BIRD le signale très clairement : « bird: bgp1: Invalid remote address 198.18.0.1) »
* À l'usage, j'ai remarqué un problème : dès la fin de l'émission des updates, bgpdump se plaint que le hold timer a expiré. Pourtant le routeur d'en face (pour vérifier avec Quagga : sh ip bgp neighbor) lui a bien envoyé des keepalive régulièrement. Ce comportement est identique que bgpdump soit client ou serveur (que ce soit lui qui initie la connexion ou pas). La solution est que le holdtime soit supérieur à la durée que prendra le parse du fichier. Exemple : s'il faut 20 minutes pour injecter le fichier, un holdtime de 15 minutes ne passe pas. C'est plus ou moins approximatif : s'il faut 22 minutes pour injecter, un holdtime de 20 minutes semble passer.
Mon avis est que bgpsimple et surtout la lib utilisée, Net::BGP::, ne sont pas multi-threadés. Ils ne font donc qu'envoyer les updates sans prendre en compte les keepalive (la fonction de callback n'est pas exécutée) durant cet intervalle. Donc, à la fin de l'émission des updates, le holdtime a expiré, en effet.
La seule solution que je vois est de configurer un intervalle de keepalive et surtout un holdtime supérieur à la durée d'injection du fichier. Cela se fait avec les arguments « -keepalive <secs> » et « -holdtime <secs> ». Il faut que ça coïncide avec les intervalles définis dans le routeur à l'autre bout. Sous Quagga « timers bgp <keepalive en secs> <holdtime en secs> ». Pour BIRD : « keepalive time <secs>; » et « hold time <secs>; »
Comment produire vos propres dumps au format MRT avec des routeurs logiciels ?
De tous les messages BGP (OPEN, UPDATE, NOTIFICATION, ...) :
- Quagga : « dump bgp all path interval » dans bgpd.conf
- BIRD : « mrtdump "/path/to/filename";» en global puis soit « mrtdump protocols { messages }; » en global pour appliquer à toutes les instances BGP, soit « mrtdump { messages } ; » dans les instances désirées.
De tous les messages UPDATE :
- Quagga : « dump bgp updates path interval »
- BIRD : pas d'équivalent
De la RIB BGP :
- Quagga : « dump bgp routes-mrt path interval ». Exemple : dump bgp routes-mrt /var/run/bgpdata/%Y-%m/rib.%F.%H%M 15m , le dossier doit exister (même dernier niveau, ici /%Y-%m) et doit être accessible en écriture par l'utilisateur quagga (chown ...)
- BIRD : pas d'équivalent. mrtdump ne permet pas cela, la commande « dump resources|sockets|interfaces|neighbors|attributes|routes|protocols » de birdc ne produit pas une sortie au format MRT et il s'agit d'un dump de la FIB (on a perdu les attributs BGP autre que préfixe et next-hop, cf code : « FIB_WALK() » dans rt_dump() ). Exemple de sortie :
1.22.89.0 /24 KF=80 PF=00 pref=100 lm=17 p=bgp1 uc=1 RTS_BGP univ UNREACH h=52f2 <-198.18.0.1 EA: [SbC] 01:01.40=i:00000000 01:02.40=P[18]:020400001b6a00000da30000d8720000b1d8 01:03.40=I[4]:3f01000c 01:05.40=i:00000000 01:08.c0=S[8]:88136a1b70916a1b
Si vous aussi vous cherchez la « debugging output. » dont parle le manuel à propos de la commande dump, il ne s'agit pas des sorties configurées dans le fichier de conf' avec les directives « log » et « debug », non. Si l'on lit le code source (utilisation de la fonction debug() définie dans sysdep/unix/log.c qui écrit dans un handler ouvert par log_init_debug(char *f) toujours dans le même fichier qui elle, est appelée par main() dans sysdep/unix/main.c en fonction des arguments passés à BIRD), il faut lancer BIRD avec les arguments : « -D /path/to/filename » ou « -d (stderr implicite) ». En effet, ça fonctionne mais alors BIRD ne devient plus un démon... Pas top.