BGP LLGR : sessions BGP fiables et réactives

Vincent Bernat

Sur un ré­seau routé via BGP et dis­po­sant de mul­tiples che­mins re­don­dants, deux ob­jec­tifs concer­nant la fia­bi­lité sont sou­vent re­cherchés :

  1. Un dys­fonc­tion­ne­ment sur un che­min doit ra­pi­de­ment faire tom­ber la ses­sion BGP cor­res­pon­dante. On s’at­tend gé­né­ra­le­ment à se re­mettre d’une telle dé­faillance en moins d’une se­conde en dé­viant le tra­fic vers les autres che­mins dis­ponibles.

  2. Aussi long­temps qu’un che­min est opé­ra­tion­nel, les ses­sions BGP qui y sont liées doivent res­ter fonc­tion­nelles, même sous la pression.

Détection rapide des pannes : BFD#

Pour dé­tec­ter ra­pi­de­ment une panne, BGP peut être as­so­cié à BFD, un pro­to­cole de dé­tec­tion d’ano­ma­lies sur les che­mins bi­di­rec­tion­nels1, dé­fini dans la RFC 5880 et la RFC 5882. BFD peut ré­agir sur des dé­lais très courts, de l’ordre de 100 ms.

Tou­te­fois, lorsque BFD est géré dans un pro­ces­sus au-des­sus d’un noyau gé­né­rique2, no­tam­ment lorsque BGP tourne sur l’hôte, il est pos­sible de perdre quelques pa­quets BFD lorsque le sys­tème est sous pres­sion : le dé­mon gé­rant les ses­sions BFD peut man­quer de CPU pour ré­pondre dans le temps im­parti. Dans ce scé­na­rio, il n’est pas rare que toutes les ses­sions BGP ter­mi­nant sur l’hôte tombent au même mo­ment, créant un in­ci­dent comme illus­tré dans le der­nier cas du dia­gramme ci-dessous.

Exemples de dysfonctionnements sur un réseau
BGP
Exemples de dysfonctionnements sur un réseau utilisant BGP. Un problème sur un lien est détecté par BFD et le chemin défectueux est retiré de la route ECMP. Toutefois, en cas d’usage intensif du CPU sur le routeur du bas, les paquets BFD ne sont pas traités assez rapidement et tous les chemins disponibles sont disqualifiés.

À ce ni­veau, nous avons donc deux pos­si­bi­li­tés ap­pa­rem­ment ir­ré­con­ci­liables :

  • des­cendre le temps de dé­tec­tion de BFD pour rendre le ré­seau plus ré­ac­tif aux problèmes ;
  • aug­men­ter le temps de dé­tec­tion de BFD pour s’as­su­rer que les ses­sions BGP res­tent opé­ra­tionnelles.

Correction des faux positifs : BGP LLGR#

Long-li­ved BGP Gra­ce­ful Res­tart (BGP LLGR) est une nou­velle ca­pa­cité pour BGP per­met­tant de gar­der les routes pé­ri­mées (stale) pen­dant une cer­taine pé­riode après la fin de la ses­sion BGP mais en les trai­tant avec une pré­fé­rence in­fé­rieure. Une nou­velle com­mu­nauté « bien connue » per­met de par­ta­ger cette in­for­ma­tion avec les autres rou­teurs. BGP LLGR est dé­fini dans la RFC 9494 et plu­sieurs im­plé­men­ta­tions existent déjà :

  • Ju­ni­per Ju­nos (de­puis la ver­sion 15.1, voir la do­cu­men­tation) ;
  • Cisco IOS XR (testé sur une 7.3.2) ;
  • BIRD (de­puis les ver­sions 1.6.5 and 2.0.3) ;
  • GoBGP (de­puis la ver­sion 1.33) ;
  • FRR (de­puis la ver­sion 8.2).

L’illus­tra­tion ci-des­sous montre com­ment BGP LLGR per­met de sur­mon­ter cer­tains dys­fonc­tion­ne­ments. En ❷, une ano­ma­lie sur un lien est dé­tec­tée par BFD et le che­min cor­res­pon­dant est re­tiré de la route car il reste deux autres che­mins avec une pré­fé­rence su­pé­rieure. Quelques mi­nutes plus tard, le dé­lai de grâce ex­pire et ce che­min ne sera plus uti­lisé du tout. Peu de temps après, le rou­teur du bas est vic­time d’une charge pro­ces­seur éle­vée et ne peut plus gé­rer les pa­quets BFD dans un dé­lai suf­fi­sant. Les ses­sions BGP tombent et les deux che­mins res­tants sont mar­qués comme pé­ri­més. Tou­te­fois, comme il n’existe plus au­cun autre che­min, ils res­tent uti­li­sés jusqu’à l’ex­pi­ra­tion du dé­lai de grâce. Cela per­met de lais­ser le temps aux ses­sions BGP de remonter.

BGP avec LLGR
Exemples de dysfonctionnements sur un réseau utilisant BGP LLGR.

Du point de vue du rou­teur du haut, le pre­mier che­min a été consi­déré comme pé­rimé car la ses­sion BGP avec R1 a été rom­pue. Tou­te­fois, lors du se­cond in­ci­dent, les deux che­mins res­tants ont été mar­qués comme pé­ri­més via la com­mu­nauté « bien connue » LLGR_STALE (65535:6) par R2 et R3.

Un autre in­té­rêt de BGP LLGR est de pou­voir re­dé­mar­rer le dé­mon BGP sans im­pact, tant que les che­mins res­tent stables peu de temps avant et pen­dant le re­dé­mar­rage. C’est par­ti­cu­liè­re­ment in­té­res­sant si BGP tourne sur un hy­per­viseur3.

BIRD#

Voyons com­ment confi­gu­rer BIRD 1.6. Comme BGP LLGR se base sur une ca­pa­cité si­mi­laire ap­pe­lée BGP gra­ce­ful res­tart (BGP GR) mais pour la­quelle les routes sont gar­dées avec une pré­fé­rence in­chan­gée. Le mi­nu­teur pour LLGR dé­marre après ex­pi­ra­tion du mi­nu­teur pour GR. Aussi, il est im­por­tant de confi­gu­rer ce dernier à 0.

template bgp BGP_LLGR {
  bfd graceful;
  graceful restart yes;
  graceful restart time 0;
  long lived graceful restart yes;
  long lived stale time 120;
}

Quand un souci sur­vient sur un che­min, la ses­sion BGP se ter­mine et le mi­nu­teur pour LLGR commence :

$ birdc show protocol R1_1 all
name     proto    table    state  since       info
R1_1     BGP      master   start  11:20:17    Connect
  Preference:     100
  Input filter:   ACCEPT
  Output filter:  ACCEPT
  Routes:         1 imported, 0 exported, 0 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              2          0          0          0          4
    Import withdraws:            0          0        ---          0          0
    Export updates:             12         10          0        ---          2
    Export withdraws:            1        ---        ---        ---          0
  BGP state:          Connect
    Neighbor address: 2001:db8:104::1
    Neighbor AS:      65000
    Neighbor graceful restart active
    LL stale timer:   112/-

Le che­min lié à cette ses­sion est mar­qué comme pé­rimé (ce qui cor­res­pond au s dans 100s) et la com­mu­nauté LLGR_STALE est ajoutée :

$ birdc show route 2001:db8:10::1/128 all
2001:db8:10::1/128 via 2001:db8:204::1 on eth0.204 [R1_2 10:35:01] * (100) [i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path:
        BGP.next_hop: 2001:db8:204::1 fe80::5254:3300:cc00:5
        BGP.local_pref: 100
                   via 2001:db8:104::1 on eth0.104 [R1_1 11:22:51] (100s) [i]
        Type: BGP unicast univ
        BGP.origin: IGP
        BGP.as_path:
        BGP.next_hop: 2001:db8:104::1 fe80::5254:3300:6800:5
        BGP.local_pref: 100
        BGP.community: (65535,6)

La route trans­mise au noyau n’est plus com­po­sée que du che­min restant :

$ ip route show 2001:db8:10::1
2001:db8:10::1 via 2001:db8:204::1 dev eth0.204 proto bird metric 1024 pref medium

Pour mettre à jour BIRD sans im­pact, il faut qu’il soit dé­marré avec le dra­peau -R et la di­rec­tive graceful restart yes pour les pro­to­coles kernel. Avant la mise à jour, il faut ar­rê­ter BIRD avec SIGKILL plu­tôt que SIGTERM pour ne pas lui lais­ser l’oc­ca­sion de fer­mer pro­pre­ment les ses­sions BGP.

Juniper Junos#

Avec Ju­nos, si BFD est déjà ac­tivé, il suf­fit d’ac­ti­ver BGP LLGR pour chaque famille :

# Enable BGP LLGR
edit protocols bgp group peers family inet6 unicast
set graceful-restart long-lived restarter stale-time 2m

Une fois qu’une er­reur sur­vient sur un che­min, la ses­sion BGP as­so­ciée se ter­mine et le mi­nu­teur BGP LLGR commence :

> show bgp neighbor 2001:db8:104::4
Peer: 2001:db8:104::4+179 AS 65000 Local: 2001:db8:104::1+57667 AS 65000
  Group: peers                 Routing-Instance: master
  Forwarding routing-instance: master
  Type: Internal    State: Connect        Flags: <>
  Last State: Active        Last Event: ConnectRetry
  Last Error: None
  Export: [ LOOPBACK NOTHING ]
  Options: <Preference HoldTime Ttl AddressFamily Multipath Refresh>
  Options: <BfdEnabled LLGR>
  Address families configured: inet6-unicast
  Holdtime: 6 Preference: 170
  NLRI inet6-unicast:
  Number of flaps: 2
  Last flap event: Restart
  Time until long-lived stale routes deleted: inet6-unicast 00:01:05
  Table inet6.0 Bit: 20000
    RIB State: BGP restart is complete
    Send state: not advertising
    Active prefixes:              0
    Received prefixes:            1
    Accepted prefixes:            1
    Suppressed due to damping:    0
    LLGR-stale prefixes:          1

Le che­min dé­fec­tueux est mar­qué comme pé­rimé et de­vient in­ac­tif car il existe de meilleurs che­mins dis­ponibles :

> show route 2001:db8:10::4 extensive
[…]
BGP    Preference: 170/-101
       Source: 2001:db8:104::4
       Next hop type: Router, Next hop index: 778
       Next hop: 2001:db8:104::4 via em1.104, selected
       Protocol next hop: 2001:db8:104::4
       Indirect next hop: 0xb1d27c0 1048578 INH Session ID: 0x15c
       State: <Int Ext>
       Inactive reason: LLGR stale
       Local AS: 65000 Peer AS: 65000
       Age: 4  Metric2: 0
       Communities: llgr-stale
       Accepted LongLivedStale
       Localpref: 100
       Router ID: 1.0.0.4
[…]

Je­tez un œil au dé­pôt Git pour les confi­gu­ra­tions com­plètes ainsi que les sor­ties des dif­fé­rentes com­mandes pour vé­ri­fier que tout fonc­tionne. Il existe aussi une va­riante qui uti­lise des ré­flec­teurs de routes. Main­te­nant que FRR im­plé­mente BFD, j’es­père qu’il adop­tera éga­le­ment LLGR.

Mise à jour (01.2022)

Do­na­tas Abrai­tis a ré­cem­ment ajouté le sup­port de LLGR dans FRR ! Il sera dis­po­nible dans la ver­sion 8.2.

Mise à jour (01.2024)

La RFC 9494 a été pu­bliée en no­vembre 2023.