SwordArMor

BGP avec bird : favorisation d’un fournisseur par rapport à un autre en cas d’égalité sur l’AS path

Introduction à BGP

C’est la première fois que je parle de BGP, ça me semble donc être une bonne idée de dire ce que c’est. Il s’agit d’un protocole de niveau 7 se basant sur TCP et permettant un échange dynamique de routes entre des entités sur Internet possédant un ASN (Autonomous System Number). Son nom complet est Border Gateway Protocol.
À la différence d’autres protocoles de routage dynamique, BGP n’a pas de métrique simple mais tout un tas de critères que l’on évalue séquentiellement et on s’arrête dès qu’il n’y a plus égalité. Voici ce que donne la doc de bird :

  1. Préférer les routes avec la plus grande préférence locale
  2. Préférer les routes avec le chemin d’AS le plus court
  3. Préférer l’origine IGP par rapport à EGP et incomplète
  4. Préférer la plus faible valeur du discriminant des sorties multiples
  5. Préférer les routes reçues en eBGP à celles reçues en iBGP
  6. Préférer les routes avec la plus petite distance interne
  7. Préférer les routes du routeur avec le plus petit identifiant

Notre cas

Chez grifon on a deux fournisseurs de transit : cogent et quantic télécom. On a donc une session BGP entre chacun de nos routeurs vers leurs routeurs.
Cogent étant un opérateur bien plus gros que quantic, ils gagnaient très souvent en raison de leur capacité à se brancher directement avec beaucoup de monde, ce qui leur permet donc d’avoir un AS path plus court. Nous nous retrouvions alors avec 20651 routes pour quantic contre 608776 pour cogent.

Quantic a un très gros avantage, on peut facilement boire des bières avec eux. De plus, ils sont normands alors que cogent est américain. Ça m’a donc semblé logique de les favoriser, en plus de pouvoir apprendre comment faire.

Par contre, je ne voulais pas favoriser quantic dans tous les cas afin de ne pas amputer sur la qualité du réseau.

La solution

Nos différents pairs BGP sont définis par rapport à des templates :

template bgp UPSTREAM
{
    local as myasn;

    # Be able to see filtered routes with "sh route filtered" command
    import keep filtered;

    # Protect ourselves from massive routes leaks
    receive limit 640000 action block;

    # Announce only our IP allocations
    export where proto = "static_grifon_allocations";
    export limit 1 action disable;
}
Et ensuite, nous les déclarons depuis ce template, avec un filtre pour chaqun :
filter bgp_filter_quantic_in
{
    if (check_import(198507, 169.254.1.1)) then
    {
        # Here we can set localpref or remove a prefix, for example

        accept;
    }
    else
    {
        reject "Prefix filtered IN quantic";
    }
}
protocol bgp bgp_quantic from UPSTREAM
{
    description "quantic";

    neighbor 169.254.1.1 as 198507;

    # Local address we use to establish the BGP session
    source address 169.254.1.3;

    # We cannot use TCP-MD5 auth because we use a poorly designed OS ;)
    # password=''

    # Accept all routes from Cogent except bogons and other bad stuff
    import filter bgp_filter_quantic_in;
}
Avec cette configuration, tous les critères de choix de BGP était égaux en cas de longueur d’AS égale sauf le dernier (router-id) qui faisait gagner cogent.
Nous sommes ici dans un cas où on peut faire gagner quantic sans perdre en latence. Mais comme dit plus haut, je ne veux faire gagner quantic que dans ce cas, il n’est donc pas possible d’utiliser la localpref. Il faut donc chercher dans les critère suivants :
  • Les deux routes sont d’origine IGP, on ne peut rien y faire,
  • les deux routes ont la même MED, ça on peut le changer.

Jouer sur la MED

Pour faire varier ce paramètre, il faut commencer par le définir dans le filtre BGP correspondant à quantic :

filter bgp_filter_quantic_in
{
    if (check_import(198507, 169.254.1.1)) then
    {
        # Here we can set localpref or remove a prefix, for example
        bgp_med = 50;
        accept;
    }
    else
    {
        reject "Prefix filtered IN quantic";
    }
}
Et si nous rechargeons la configuration de bird, rien ne se passe… Pourquoi ? Parce que par défaut bird ne prend pas ce paramètre en compte dans le cas de routes reçues d’ASes différents, c’est écrit dans la documentation :
med metric switch
Enable comparison of MED attributes (during best route selection) even between routes received from different ASes. This may be useful if all MED attributes contain some consistent metric, perhaps enforced in import filters of AS boundary routers. If this option is disabled, MED attributes are compared only if routes are received from the same AS (which is the standard behavior).
Default: off.
Il faut alors, en plus de cela, ajouter la gestion de la MED dans notre template de configuration :
template bgp UPSTREAM
{
    local as myasn;

    # Be able to see filtered routes with "sh route filtered" command
    import keep filtered;

    # Protect ourselves from massive routes leaks
    receive limit 640000 action block;

    # Announce only our IP allocations
    export where proto = "static_grifon_allocations";
    export limit 1 action disable;

        med metric on;
}
Et là, une fois la configuration rechargée, nous passons bien par quantic lorsque l’AS path est égal, tout en gardant le mécanisme de sélection normal autrement :
root@budic:~ # birdc show route all for 37.187.103.228
BIRD 1.6.0 ready.
37.187.0.0/16      via 169.254.1.1 on re0.21 [bgp_quantic 14:53:28] * (100) [AS16276i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 198507 16276
        BGP.next_hop: 169.254.1.1
        BGP.med: 50
        BGP.local_pref: 100
                   via 149.6.72.97 on re0.20 [bgp_cogent 14:51:07] (100) [AS16276i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 174 16276
        BGP.next_hop: 149.6.72.97
        BGP.med: 15051
        BGP.local_pref: 100
        BGP.community: (174,21101) (174,22008)
                   unreachable [ibgp_nominoe 2017-02-09 from 89.234.186.7] (100/-) [AS16276i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 174 16276
        BGP.next_hop: 89.234.186.1
        BGP.med: 15051
        BGP.local_pref: 100
        BGP.community: (174,21101) (174,22008)
root@budic:~ # birdc show route all for 89.234.141.1
BIRD 1.6.0 ready.
89.234.141.0/24    via 149.6.72.97 on re0.20 [bgp_cogent 14:50:16] * (100) [AS60630i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 174 60630
        BGP.next_hop: 149.6.72.97
        BGP.med: 21051
        BGP.local_pref: 100
        BGP.community: (174,21101) (174,22008)
                   via 169.254.1.1 on re0.21 [bgp_quantic 14:49:45] (100) [AS60630i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 198507 174 60630
        BGP.next_hop: 169.254.1.1
        BGP.med: 50
        BGP.local_pref: 100
        BGP.community: (174,21101) (174,22008)
                   unreachable [ibgp_nominoe 2017-02-09 from 89.234.186.7] (100/-) [AS60630i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 174 60630
        BGP.next_hop: 89.234.186.1
        BGP.med: 21051
        BGP.local_pref: 100
        BGP.community: (174,21101) (174,22008)
root@budic:~ # birdc show route all for 216.66.84.42
BIRD 1.6.0 ready.
216.66.80.0/20     via 169.254.1.1 on re0.21 [bgp_quantic 14:50:27] * (100) [AS6939i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 198507 6939
        BGP.next_hop: 169.254.1.1
        BGP.med: 50
        BGP.local_pref: 100
        BGP.community: (24115,6939)
                   via 149.6.72.97 on re0.20 [bgp_cogent 14:50:56] (100) [AS6939i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 174 1299 6939 6939
        BGP.next_hop: 149.6.72.97
        BGP.med: 14040
        BGP.local_pref: 100
        BGP.community: (174,21100) (174,22008)
                   unreachable [ibgp_nominoe 2017-03-08 from 89.234.186.7] (100/-) [AS6939i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path: 198507 6939
        BGP.next_hop: 89.234.186.1
        BGP.local_pref: 100
        BGP.community: (24115,6939)
.

Conclusion

Nous nous retrouvons maintenant avec 49576 routes pour quantic (contre 20651 précédemment) et 579833 pour cogent (contre 608776 précédemment). Et cela se voit très bien sur le graph :