Nous avons déjà étudié un cas d'ingénierie de trafic BGP, voir
http://shaarli.guiguishow.info/?9sfiXw . Aujourd'hui, nous allons étudier un autre cas réel plus compliqué. :)
Chez ARN, on a 3 transitaires pour nous connecter au reste des réseaux qui composent Internet :
* Cogent
* Interoute
* Hurricane Electric dit HE (IPv6 uniquement)
L'interconnexion avec HE consiste en 2 tunnels 6in4 (car nous avons deux routeurs), un avec le PoP (Point of Presence, endroit/datacenter dans lequel un opérateur/hébergeur est présent) de HE à Francfort, l'autre avec le PoP de HE à Londres. Voir
http://shaarli.guiguishow.info/?X_2rrQ . Londres et Francfort, c'est pour éviter les pannes locales (qui concerne un seul PoP) côté HE qui arrivent bien plus souvent qu'on ne le croit.
Ces tunnels 6in4 étaient pleinement justifiés avant la mise en production de notre deuxième transitaire, Interoute puisque HE et Cogent sont en guéguerre commerciale depuis plus de 5 ans et qu'il est donc impossible de joindre le réseau HE (et tous les "abonnés" 6in4 qu'HE a...) depuis Cogent...
Depuis qu'Interoute est tombé en marche, nous faisons de l'ingénierie de trafic sur les sessions BGP que nous avons avec HE :
* On sort par HE uniquement si l'on n'a pas le choix c'est-à-dire si ni Cogent ni Interoute n'ont une route équivalente même si elle est moins optimale en terme de nombre de réseaux traversés. Pour ce faire, on diminue la local preference des préfixes IP qui nous arrivent via HE.
* On conseille aux autres réseaux d'Internet d'utiliser HE pour nous joindre uniquement en dernier secours, s'ils n'ont pas une route équivalente via Cogent/Interoute. Pour ce faire, on utilise la technique de l'AS-prepending pour rallonger l'AS_PATH en insérant 2 fois supplémentaires notre ASN dans celui-ci. Ce conseil peut être parfaitement ignoré par les réseaux qui peuvent utiliser la localpref ou un poids (weight) pour forcer leurs routeurs à passer par HE malgré nos recommandations.
Depuis la mise en production de notre deuxième transitaire, nous observons de sévères pertes de paquets régulières (plusieurs fois par jour, vraiment beaucoup trop) en IPv6. C'est très pénible car ça casse les sessions SSH et ça fait hurler notre monitoring externe (monitoring en dehors de notre AS pour vérifier que les services que nous proposons sont bien accessibles depuis l'extérieur de notre réseau ce qui permet de vérifier qu'on n'a pas fait une erreur de config' et qu'on a bien ouvert le pare-feu,...).
En faisant des recherches, on s'aperçoit que les réseaux impactés sont ceux qui utilisent HE pour communiquer avec nous. Nous utilisons bien Cogent ou Interoute pour leur livrer le trafic mais eux nous répondent via HE. Oui, le trafic n'est pas forcément symétrique sur Internet et c'est même plutôt l'inverse.
Vu que cela se produit depuis la mise en production de notre 2e transitaire, on peut s'interroger :
* Et si le problème venait du prestataire via lequel notre tunnel 6in4 est monté ? Nos routeurs choisissent Interoute pour communiquer avec HE en IPv4 car c'est le chemin le plus court. HE choisi Interoute car il n'a rien d'autre. Forcer le trafic IPv4 à destination d'HE à passer par Cogent ne changerait pas grand'chose puisque HE nous répondrait par Interoute donc s'il y a un embouteillage sur Interoute, on ne le contournerait pas.
* Néanmoins, un mtr (traceroute dynamique utilisant ICMP au lieu de paquets TCP) semble indiquer que la perte de paquets a lieu au PoP de HE à Francfort. Je dis « semble » car on ne peut avoir de certitude : mtr utilise ICMP qui est un protocole auquel les routeurs prêtent moins d'attention (car il nécessite d'être traité de manière logicielle là où le transfert de paquets IP se fait de manière matérielle), surtout quand ils ont du taff à faire. Autrement dit : une perte de paquets ICMP ne signifie pas une perte de paquets IP.
Revenons donc à IPv6, au dessus du tunnel 6in4. Prenons l'un des réseaux qui choisissent d'échanger avec nous via HE, Tetaneutral.net et regardons les choix de leur routeur (via leur looking glass :
http://lg.tetaneutral.net ) :
2a00:5881:8100::/40 via 2001:7f8:54::10 on eth0.4032 [FRANCEIX_RS1_6 2016-02-09 22:34:51 from 2001:7f8:54::250] * (370) [AS60630i]
Type: BGP unicast univ
BGP.origin: IGP
BGP.as_path: 6939 60630 60630 60630
BGP.next_hop: 2001:7f8:54::10 fe80::224:38ff:fe7e:7100
BGP.med: 1
BGP.local_pref: 100
BGP.community: (51706,64601) (51706,64650)
via 2001:7f8:54::10 on eth0.4032 [FRANCEIX_RS2_6 2016-02-09 22:34:51 from 2001:7f8:54::251] (369) [AS60630i]
Type: BGP unicast univ
BGP.origin: IGP
BGP.as_path: 6939 60630 60630 60630
BGP.next_hop: 2001:7f8:54::10 fe80::224:38ff:fe7e:7100
BGP.med: 1
BGP.local_pref: 100
BGP.community: (51706,64602) (51706,64650)
via 2001:7f8:54::10 on eth0.4032 [HE_FRANCEIX_6 2016-02-09 22:34:51] (360) [AS60630i]
Type: BGP unicast univ
BGP.origin: IGP
BGP.as_path: 6939 60630 60630 60630
BGP.next_hop: 2001:7f8:54::10 fe80::224:38ff:fe7e:7100
BGP.local_pref: 100
via 2a01:6600:3000:1::1 on eth0.2301 [FULLSAVE_TLS00_6 2016-02-02 17:31:01] (350) [AS60630i]
Type: BGP unicast univ
BGP.origin: IGP
BGP.as_path: 39405 3215 5511 8928 60630
BGP.next_hop: 2a01:6600:3000:1::1 fe80::f6b5:2f08:fdd7:7954
BGP.med: 0
BGP.local_pref: 100
BGP.community: (39405,22001) (39405,31000) (39405,31104)
via 2001:978:2:68::8:1 on eth4 [COGENT_TLS00_6 2016-02-02 08:19:20] (350) [AS60630i]
Type: BGP unicast univ
BGP.origin: IGP
BGP.as_path: 174 60630
BGP.next_hop: 2001:978:2:68::8:1 fe80::aa0c:dff:fe5e:c0df
BGP.med: 30051
BGP.local_pref: 100
BGP.community: (174,21101) (174,22008)
Verdict : Tetaneutral choisit bien de passer par HE (on repère la route sélectionnée car elle a une petite étoile « * »). Pourtant l'AS_PATH, donc le nombre de réseaux traversés est plus long ! Pour forcer une route même si la longueur de l'AS_PATH est défavorable, il faut utiliser la localpref. Mais ici la localpref est identique ! Il y a autre chose. Il faut regarder le nombre entre parenthèses vers la fin de chaque première ligne : 370 369, 360, 350.
Il s'agit d'un poids, soit ce qui a le plus de valeur dans l'algorithme de sélection d'une route en BGP : il passe devant la localpref qui elle-même passe avant la longueur de l'AS_PATH... Différence entre poids et préférence locale ? Le poids n'est pas propagé en iBGP. Le poids vaut 0 par défaut, le plus élevé est préféré.
Pour faire de même avec Quagga, il faut utiliser « neighbor 2001:db8::1 weight <poids> ». Pour faire de même avec BIRD : « protocol <nom> { preference <poids>; } ». Avec BIRD, je trouve que cette notion de préférence est un mélange confus entre un poids et une distance administrative (qui sert à déterminer quel protocole de routage (static, BGP, OSPF) l'emporte quand plusieurs ont sélectionné une route pour un même préfixe, voir
https://www.cisco.com/c/en/us/support/docs/ip/border-gateway-protocol-bgp/15986-admin-distance.html) chez Cisco...
Quel est l'objectif que Tetaneutral.net cherche à atteindre en faisant cela ? Privilégier les points d'échanges et les interconnexions privées directes (PNI), les deux composantes du peering, au transit. C'est un comportement des plus respectable : Internet devrait être uniquement du peering, c'est-à-dire de l'échange réciproque de trafic qui s'annule (en terme de débit consommé) sans rémunération. De plus, le peering offre souvent une meilleure qualité (latence et absence de perte de paquets) que le transit). Néanmoins, dans notre cas, ça entre en conflit avec notre volonté de ne pas utiliser un tunnel 6in4 tout crade (ça favorise la concentration du trafic chez un petit nombre d'acteurs donc centralisation dangereuse, surveillance & co et ça permet de maintenir le statu quo du non-déploiement d'IPv6) tout en sécurisant une route vers HE.
Que faire ? On veut que les réseaux utilisent Interoute ou Cogent pour échanger avec nous mais, si Interoute tombe en panne (ou maintenance programmée), on veut pouvoir encore communiquer avec HE (ce que Cogent ne permet pas, pour rappel ;) ). Réfléchissons :
* On ne peut pas forcer les réseaux à choisir un autre chemin qu'HE car le poids et la localpref ont plus d'impact que les critères sur lesquels nous pouvons influer.
* On pourrait couper nos sessions BGP avec HE et les monter uniquement quand Interoute est en panne. C'est très contestable : 1) les admins ARN n'auront pas le temps de réagir aux coupures courtes. 2) C'est le propre même d'utiliser un protocole de routage dynamique que de n'avoir rien à faire à la mano. 3) En associatif, ça consomme du temps libre que l'on n'a pas.
* On pourrait découper notre allocation IPv6 en blocs plus petits et les annoncer tous un à un uniquement sur Interoute et Cogent. Cela tient d'un concept fort du routage IP : on sélectionne la route la plus spécifique, la plus précise, celle qui porte sur le moins d'adresses (un bloc /25 (128 adresses) est plus précis qu'un /22 (1024 adresses), par exemple). Si l'on annonce des préfixes plus spécifiques uniquement sur Interoute et Cogent, alors le trafic arrivera forcément par là, +/- ce qu'on nomme le trafic résiduel qui provient de réseaux qui ne reçoivent pas ces annonces plus spécifiques pour diverses raisons...
Désagréger son allocation en sous-blocs dans le seul but de faire de l'ingénierie de trafic, ce n'est pas top du tout car ça contribue à ajouter des entrées inutiles dans la table de routage mondiale et donc à la faire grossir inutilement. Les cartes installées dans les routeurs qui transfèrent les paquets IP ont un nombre limité d'entrées dans leur mémoire TCAM et lorsqu'elle est saturée, le transfert des paquets s'effectue de manière logicielle donc plus lentement.
On constate aussi que les opérateurs configurent leurs routeurs qui ont trop peu de mémoire pour supporter toute la table IPv4 de manière à rogner sur le nombre d'entrées IPv6 possibles (voir
https://www.cisco.com/c/en/us/support/docs/switches/catalyst-6500-series-switches/117712-problemsolution-cat6500-00.html ) dans le but de prolonger leur durée d'exploitation.
Avec le plan d'adressage que nous avons choisi (voir
https://wiki.arn-fai.net/technique:adressage#public ), nous utilisons partiellement 2 * /44 et 3 * /48. Donc il faudrait rajouter au moins 2 entrées dans la table de routage mondiale. No way !
* En fait, ce que l'on voudrait c'est qu'HE ait une route vers nous, même si Interoute tombe mais qu'il ne la communique à personne. Cela existe et se nomme communauté no-export.
Une communauté est un tag que l'on place sur un ensemble de préfixes IP. Ce tag permet de déclencher une action qu'un pair BGP a programmée à l'avance comme ne pas réannoncer ces préfixes, les réannoncer en faisant de l'AS-prepending, les réannoncer mais uniquement aux peers européens,....
Plusieurs communautés sont normalisées à l'IETF (
https://www.iana.org/assignments/bgp-well-known-communities/bgp-well-known-communities.xhtml ) dont la fameuse « no-export » qui demande à ce que l'annonce ne soit pas relayée en dehors du réseau du pair.
C'est cette dernière méthode que nous allons choisir : nous allons définir une localpref défavorable pour que nos routeurs n'utilisent pas HE pour sortir sauf si c'est la seule possibilité restante et nous allons positionner la communauté no-export sur notre session avec HE pour qu'HE puisse communiquer avec nous, même si Interoute tombe et sans faire fuiter cette information.
Nous allons aussi ignorer les préfixes qui ne sont pas annoncés par HE. Ça se justifie dans un seul cas : si Interoute tombe en panne, alors on utilisera HE pour joindre le réseau HE. Cogent prendra la main sur tout le reste (grâce à la localpref ;) ). Et si Cogent IPv6 tombe en même temps ? Nos routeurs vont vouloir sortir par HE pour joindre le reste de l'Internet IPv6. HE va bien transmettre nos paquets à la destination... qui ne pourra pas nous répondre puisqu'aucune route ne sera disponible (on a dit a HE de ne pas dire qu'il a une route vers nous ;) ).
Avec BIRD (limité au strict minimum) :
filter bgp_filter_hurricane_electric_in
{
if bgp_path.last = 6939 then
{
bgp_local_pref = 90;
accept;
}
reject;
}
# "_ou" = "_out" mais nom trop long pour BIRD
filter bgp_filter_hurricane_electric_ou
{
# AS-prepending
bgp_path.prepend(60630);
bgp_path.prepend(60630);
# Ajout de la communaute no-export
bgp_community.add((65535,65281));
accept;
}
protocol bgp bgp_hurricane_electric
{
local as 60630;
neighbor 2001:470:12:74::1 as 6939;
source address 2001:470:12:74::2;
import filter bgp_filter_hurricane_electric_in;
export filter bgp_filter_hurricane_electric_ou;
}
Avec Quagga (limité au strict minimum) :
conf t
ip as-path access-list HE-asn permit _6939$
route-map disgrace-HE-in permit 5
match as-path HE-asn
set local-preference 90
route-map disgrace-HE-in deny 10
route-map disgrace-HE-out permit 5
set as-path prepend 60630 60630
set community additive no-export
router bgp 60630
neighbor 2001:470:12:74::1 remote-as 6939
no neighbor 2001:470:12:74::1 activate
neighbor 2001:470:12:74::1 interface he-ipv6
neighbor 2001:470:12:74::1 update-source 2001:470:12:74::2
address-family ipv6
neighbor 2001:470:12:74::1 activate
neighbor 2001:470:12:74::1 route-map disgrace-HE-in in
neighbor 2001:470:12:74::1 route-map disgrace-HE-out out
exit-address-family
On peut ensuite vérifier :
* Tetaneutral.net ne nous voit plus via HE :
http://lg.tetaneutral.net/prefix_detail/h7/ipv6?q=web.arn-fai.net
* Même chose à plus large échelle :
http://lg.ring.nlnog.net/prefix_bgpmap/lg01/ipv6?q=web.arn-fai.net
* HE dispose bien de deux routes directes vers nous (une par PoP où nous sommes interconnectés) qu'il conserve pour son usage propre :
http://lg.he.net/ (cocher « BGP Route » et saisir « 2a00:5881:8100::/40 » dans « IP/Hostname »).
* Cette méthode a résolu notre problème de perte de paquets. \o/
Les esprits taquins remarqueront qu'HE utilisera toujours les tunnels 6in4 pour échanger avec nous... Même quand une route via Interoute est disponible... C'est moche pour les raisons éthiques évoquées plus haut mais aussi parce qu'on peut présumer que le problème de paquets va persister entre nous.
Que pouvons-nous y faire ? HE positionne une localpref = 140 sur nos interconnexions directes alors qu'elle est de 100 (valeur par défaut) sur la route qu'il reçoit via Interoute... On ne peut rien y faire à distance puisque la localpref est prioritaire sur les critères sur lesquels nous pouvons influer.
On peut leur demander de faire une exception pour nous puisqu'Internet est avant tout une construction humaine de gens qui communiquent. Notre demande a été refusée. Et c'est parfaitement compréhensible : vu la taille (nombre de PoP et donc de routeurs à travers le monde) du réseau HE et les services proposés, des automates ont été programmés et des templates/peer-groups doivent être utilisés sur les routeurs, laissant peu de place à la bidouille au profit d'un seul réseau.
Les seules solutions restantes sont : couper nos sessions BGP avec HE et les monter seulement quand Interoute tombe en panne ou désagréger notre allocation IPv6... J'ai déjà expliqué ci-dessus pourquoi nous ne ferons pas ça.
On notera un dernier défaut à cette manière de faire : dans une config' à un seul transitaire restant (donc dans une situation de panne), on fait l'hypothèse que le prestataire restant aura au moins une route vers tous les réseaux IPv6 qui composent Internet. Le seul défaut peut se situer sur HE (puisqu'on est connecté avec eux aussi longtemps qu'on a une liaison IPv4).