Failover BGP y multihoming desde dos ubicaciones VPS

12 min de lectura·Matthieu·bird2bfdfailoverfrrbgpmultihoming|

Anuncia el mismo prefijo desde dos ubicaciones con BGP para failover automático. Cubre LOCAL_PREF, MED, AS-path prepending, BFD y apagado graceful con configuraciones completas de BIRD2 y FRR.

Este tutorial explica cómo anunciar el mismo prefijo IP desde dos VPS separados usando BGP. Configurarás la preferencia primario/backup con LOCAL_PREF y MED, habilitarás BFD para detección de fallos en menos de un segundo, e implementarás apagado graceful (graceful shutdown) para mantenimiento planificado. Todos los ejemplos muestran BIRD2 y FRR en paralelo.

Requisitos previos:

¿Qué es el multihoming BGP y por qué usarlo en un VPS?

El multihoming BGP consiste en anunciar el mismo prefijo IP desde dos o más ubicaciones mediante eBGP. Cada ubicación mantiene una sesión BGP independiente con su proveedor upstream. Si una ubicación falla, la otra continúa anunciando el prefijo y absorbe todo el tráfico automáticamente. El tiempo de convergencia depende de los hold timers (normalmente 180-240 segundos con configuración por defecto) o de BFD (menos de un segundo con configuración adecuada).

En un VPS, el multihoming proporciona redundancia sin depender de un solo centro de datos. Ejecutas dos instancias VPS en ubicaciones diferentes, ambas anunciando tu prefijo. Una actúa como primaria, la otra como backup. Los atributos de ingeniería de tráfico (LOCAL_PREF, MED, AS-path prepending) controlan qué camino gestiona el tráfico en condiciones normales.

¿Cómo se diseña el failover BGP entre dos ubicaciones?

La configuración utiliza dos VPS Virtua en ubicaciones europeas diferentes, cada uno manteniendo una sesión eBGP con el router upstream local. Ambos anuncian el mismo /24 y /48.

                    Internet
                   /        \
            Upstream A     Upstream B
            (Frankfurt)    (Amsterdam)
                |              |
           eBGP session   eBGP session
                |              |
          +-----------+  +-----------+
          |  VPS-PRI  |  |  VPS-BKP  |
          | AS 64500  |  | AS 64500  |
          | BIRD2/FRR |  | BIRD2/FRR |
          +-----------+  +-----------+
           announces       announces
          198.51.100.0/24  198.51.100.0/24
          2001:db8::/48    2001:db8::/48

Ambos nodos pertenecen a tu AS (AS 64500 en estos ejemplos). Sustituye el ASN, los prefijos y las IPs de peering por tus valores reales.

Reglas de firewall para ambos nodos:

BGP usa el puerto TCP 179. BFD usa los puertos UDP 3784 y 3785. Abre estos puertos entre tu VPS y el peer upstream antes de continuar.

# nftables example - adjust PEER_IP to your upstream
nft add rule inet filter input ip saddr PEER_IP tcp dport 179 accept
nft add rule inet filter input ip saddr PEER_IP udp dport { 3784, 3785 } accept

¿Cómo se controla la preferencia de ruta BGP?

Tres atributos permiten influir en el camino que toma el tráfico. Cada uno opera a un nivel diferente.

Atributo Dirección Alcance ¿Se envía a los peers? Cuándo usarlo
LOCAL_PREF Saliente (tu salida) Dentro de tu AS No (solo iBGP) Controlar qué nodo envía el tráfico saliente
MED Entrante (desde upstream) Entre tú y un AS upstream Sí (al vecino directo) Indicar a un upstream qué punto de entrada preferir
AS-path prepending Entrante (global) Todos los AS en la ruta Sí (se propaga) Hacer que una ruta parezca más larga para todo Internet

LOCAL_PREF y MED son precisos. El AS-path prepending es una herramienta gruesa pero funciona cuando tus ubicaciones están conectadas a upstreams diferentes.

¿Cómo se configura LOCAL_PREF para rutas primaria y backup?

LOCAL_PREF determina qué ruta de salida prefiere tu AS para el tráfico saliente. El valor más alto gana. El valor por defecto es 100. Establece 200 en el nodo primario y deja 100 en el backup. Esto solo afecta al tráfico que sale de tu red.

Configuración de LOCAL_PREF con BIRD2

En el nodo primario (VPS-PRI), crea o modifica el filtro de importación:

# /etc/bird/bird.conf - Primary node

filter upstream_import_primary {
    bgp_local_pref = 200;
    accept;
}

protocol bgp upstream_v4 {
    local 192.0.2.2 as 64500;
    neighbor 192.0.2.1 as 64496;
    ipv4 {
        import filter upstream_import_primary;
        export where net = 198.51.100.0/24;
    };
}

protocol bgp upstream_v6 {
    local 2001:db8:1::2 as 64500;
    neighbor 2001:db8:1::1 as 64496;
    ipv6 {
        import filter upstream_import_primary;
        export where net = 2001:db8::/48;
    };
}

En el nodo backup (VPS-BKP), mantén el LOCAL_PREF por defecto:

# /etc/bird/bird.conf - Backup node

filter upstream_import_backup {
    bgp_local_pref = 100;
    accept;
}

protocol bgp upstream_v4 {
    local 203.0.113.2 as 64500;
    neighbor 203.0.113.1 as 64497;
    ipv4 {
        import filter upstream_import_backup;
        export where net = 198.51.100.0/24;
    };
}

Recarga BIRD2 y comprueba las rutas:

birdc configure
birdc show route for 0.0.0.0/0 all
0.0.0.0/0          unicast [upstream_v4 12:00:00] * (100/?) [AS64496i]
        via 192.0.2.1 on eth0
        Type: BGP univ
        BGP.origin: IGP
        BGP.as_path: 64496
        BGP.local_pref: 200

El valor BGP.local_pref: 200 en el nodo primario indica que será preferido para el tráfico saliente.

Configuración de LOCAL_PREF con FRR

En el nodo primario:

vtysh -c "configure terminal
route-map UPSTREAM-IN permit 10
 set local-preference 200
exit
router bgp 64500
 neighbor 192.0.2.1 remote-as 64496
 address-family ipv4 unicast
  neighbor 192.0.2.1 route-map UPSTREAM-IN in
  network 198.51.100.0/24
 exit-address-family
 neighbor 2001:db8:1::1 remote-as 64496
 address-family ipv6 unicast
  neighbor 2001:db8:1::1 route-map UPSTREAM-IN in
  network 2001:db8::/48
 exit-address-family
exit
exit"

En el nodo backup, usa set local-preference 100 (u omite el route-map ya que 100 es el valor por defecto).

Comprueba la tabla de rutas:

vtysh -c "show ip bgp"
   Network          Next Hop            Metric LocPrf Weight Path
*> 0.0.0.0/0        192.0.2.1                     200      0 64496 i

¿Cómo se usa MED para controlar el tráfico entrante?

MED (Multi-Exit Discriminator) indica a tu upstream qué punto de entrada preferir. El valor más bajo gana. Establece MED 0 en el primario y MED 100 en el backup. MED solo se compara entre rutas recibidas del mismo AS vecino, por lo que funciona mejor cuando ambas ubicaciones hacen peering con el mismo proveedor upstream.

Configuración de MED con BIRD2

En el nodo primario, establece MED en el filtro de exportación:

filter upstream_export_primary {
    if net = 198.51.100.0/24 || net = 2001:db8::/48 then {
        bgp_med = 0;
        accept;
    }
    reject;
}

protocol bgp upstream_v4 {
    local 192.0.2.2 as 64500;
    neighbor 192.0.2.1 as 64496;
    ipv4 {
        import filter upstream_import_primary;
        export filter upstream_export_primary;
    };
}

En el nodo backup:

filter upstream_export_backup {
    if net = 198.51.100.0/24 || net = 2001:db8::/48 then {
        bgp_med = 100;
        accept;
    }
    reject;
}

Configuración de MED con FRR

En el nodo primario:

vtysh -c "configure terminal
route-map UPSTREAM-OUT permit 10
 set metric 0
exit
router bgp 64500
 address-family ipv4 unicast
  neighbor 192.0.2.1 route-map UPSTREAM-OUT out
 exit-address-family
exit
exit"

En el nodo backup, usa set metric 100.

Comprueba las rutas exportadas:

vtysh -c "show ip bgp neighbors 192.0.2.1 advertised-routes"
   Network          Next Hop            Metric LocPrf Weight Path
*> 198.51.100.0/24  0.0.0.0                  0         32768 i

La columna Metric muestra 0 en el primario. El backup mostrará 100.

¿Cuándo usar AS-path prepending en lugar de MED?

Usa AS-path prepending cuando tus dos ubicaciones estén conectadas a proveedores upstream diferentes. MED solo se compara entre rutas del mismo AS, así que no tiene efecto si tus upstreams son ASes diferentes. El prepending hace que la ruta del backup parezca más larga, orientando las decisiones de enrutamiento globales hacia el primario.

Añade tu propio ASN de 1 a 3 veces en el nodo backup. Más de 3 prepends rara vez cambia las decisiones de enrutamiento y solo añade ruido.

BIRD2 (filtro de exportación del nodo backup):

filter upstream_export_backup_prepend {
    if net = 198.51.100.0/24 || net = 2001:db8::/48 then {
        bgp_path.prepend(64500);
        bgp_path.prepend(64500);
        accept;
    }
    reject;
}

FRR (nodo backup):

vtysh -c "configure terminal
route-map UPSTREAM-OUT permit 10
 set as-path prepend 64500 64500
exit
exit"

Tras aplicarlo, comprueba el AS path desde un looking glass o una máquina remota:

# From an external machine
traceroute -A 198.51.100.1

La ruta del backup ahora muestra 64500 64500 64500 (tu ASN aparece tres veces: una real, dos añadidas) mientras que la del primario muestra 64500 una sola vez.

¿Cómo se habilita BFD para detección rápida de fallos?

Sin BFD, BGP depende de los hold timers para detectar un fallo del peer. El hold time por defecto es de 240 segundos en BIRD2 y 180 segundos en FRR. Con BFD, la detección baja a menos de un segundo en enlaces de baja latencia.

Parámetro Por defecto Recomendado para VPS
Intervalo de transmisión 300 ms 300 ms
Intervalo de recepción 300 ms 300 ms
Multiplicador de detección 3 3
Tiempo de detección efectivo 900 ms 900 ms

Para entornos VPS en el mismo backbone del proveedor, intervalos de 300 ms con multiplicador 3 ofrecen detección fiable en menos de un segundo sin falsos positivos. No bajes de 100 ms en instancias VPS. El jitter de virtualización puede causar flapping.

Configuración de BFD con BIRD2

Añade un protocolo BFD y habilítalo en la sesión BGP:

protocol bfd {
    interface "*" {
        min rx interval 300 ms;
        min tx interval 300 ms;
        multiplier 3;
    };
}

protocol bgp upstream_v4 {
    local 192.0.2.2 as 64500;
    neighbor 192.0.2.1 as 64496;
    bfd graceful;
    ipv4 {
        import filter upstream_import_primary;
        export filter upstream_export_primary;
    };
}

La opción bfd graceful hace que BIRD2 lance un reinicio graceful (conservando rutas obsoletas) en lugar de un reinicio brusco de la sesión cuando BFD detecta un fallo. Si el peer no ejecuta BFD, la sesión se establece normalmente.

Tras recargar, comprueba el estado de BFD:

birdc show bfd sessions
BFD sessions:
IP address       Interface  State   Since       Interval  Timeout
192.0.2.1        eth0       Up      12:00:00    300 ms    900 ms

Configuración de BFD con FRR

vtysh -c "configure terminal
bfd
 profile vps-detect
  receive-interval 300
  transmit-interval 300
  detect-multiplier 3
 exit
exit
router bgp 64500
 neighbor 192.0.2.1 bfd profile vps-detect
 neighbor 2001:db8:1::1 bfd profile vps-detect
exit
exit"

Comprueba el estado del peer BFD:

vtysh -c "show bfd peers"
BFD Peers:
        peer 192.0.2.1 vrf default
                ID: 1
                Remote ID: 2
                Status: up
                Uptime: 5 minute(s)
                Diagnostics: ok
                Remote diagnostics: ok
                Peer Type: configured
                Local timers:
                        Receive interval: 300ms
                        Transmission interval: 300ms
                        Echo receive interval: disabled
                        Echo transmission interval: disabled
                Peer timers:
                        Receive interval: 300ms
                        Transmission interval: 300ms
                        Echo receive interval: disabled

BFD requiere que los puertos UDP 3784 y 3785 estén abiertos entre los peers. Si saltaste el paso del firewall, las sesiones BFD permanecerán en estado Down.

¿Cómo se realiza un apagado graceful para mantenimiento?

La RFC 8326 define la comunidad bien conocida GRACEFUL_SHUTDOWN (65535:0). Antes de un mantenimiento planificado, marcas todas las rutas con esta comunidad. Los peers que la respetan fijan la local-preference a 0 para esas rutas, redirigiendo el tráfico a rutas alternativas antes de cerrar la sesión. Esto evita el agujero negro de tráfico que ocurre durante la convergencia BGP normal.

El procedimiento de apagado graceful:

  1. Marca las rutas con la comunidad GRACEFUL_SHUTDOWN en el nodo que vas a apagar
  2. Espera la convergencia (30-60 segundos para que Internet redirija el tráfico)
  3. Comprueba que el tráfico ha cambiado de ruta usando un looking glass o contadores de tráfico
  4. Cierra la sesión BGP
  5. Realiza el mantenimiento
  6. Restablece la sesión y elimina la comunidad
  7. Confirma la re-convergencia

Apagado graceful con BIRD2

Para iniciar el apagado graceful en el nodo primario antes del mantenimiento, modifica el filtro de exportación:

# Temporary export filter for graceful shutdown
filter upstream_export_shutdown {
    if net = 198.51.100.0/24 || net = 2001:db8::/48 then {
        bgp_community.add((65535, 0));
        bgp_med = 65535;
        accept;
    }
    reject;
}

Aplícalo cambiando el filtro de exportación en el protocolo BGP y recargando:

# Edit bird.conf: change export filter to upstream_export_shutdown
# Then reload
birdc configure

Para respetar el apagado graceful de los peers (aplica esto en ambos nodos), añade una comprobación en el filtro de importación. El orden importa: la comprobación del apagado graceful debe llamar a accept dentro del bloque if, de lo contrario una asignación posterior de bgp_local_pref la sobrescribirá.

filter upstream_import_backup {
    if (65535, 0) ~ bgp_community then {
        bgp_local_pref = 0;
        accept;
    }
    bgp_local_pref = 100;
    accept;
}

Apagado graceful con FRR

FRR proporciona un solo comando que gestiona el marcado automáticamente:

vtysh -c "configure terminal
router bgp 64500
 bgp graceful-shutdown
exit
exit"

Esto añade la comunidad GRACEFUL_SHUTDOWN (65535:0) a todas las rutas y fija la local-preference a 0. Se envía un refresco de rutas a todos los peers.

Para confirmar que se está enviando la comunidad:

vtysh -c "show ip bgp neighbors 192.0.2.1 advertised-routes"
   Network          Next Hop            Metric LocPrf Weight Path
*> 198.51.100.0/24  0.0.0.0                  0      0  32768 i
                                         Community: graceful-shutdown

Tras el mantenimiento, elimínala:

vtysh -c "configure terminal
router bgp 64500
 no bgp graceful-shutdown
exit
exit"

Para que FRR respete el apagado graceful de los peers, configura un route-map de entrada:

vtysh -c "configure terminal
bgp community-list standard GRACEFUL_SHUTDOWN permit graceful-shutdown
route-map UPSTREAM-IN permit 5
 match community GRACEFUL_SHUTDOWN
 set local-preference 0
exit
route-map UPSTREAM-IN permit 10
 set local-preference 200
exit
exit"

La secuencia 5 coincide con las rutas que llevan la comunidad y reduce la local-preference a 0. La secuencia 10 procesa normalmente todas las demás rutas.

¿Cómo se prueba el failover BGP?

Prueba el failover cerrando la sesión BGP primaria y observando desde el nodo backup y un punto externo.

Paso 1: Comprueba el estado de enrutamiento actual en ambos nodos.

BIRD2:

birdc show route for 198.51.100.0/24 all

FRR:

vtysh -c "show ip bgp 198.51.100.0/24"

Paso 2: Cierra la sesión BGP primaria.

BIRD2 (en VPS-PRI):

birdc disable upstream_v4
birdc disable upstream_v6

FRR (en VPS-PRI):

vtysh -c "configure terminal
router bgp 64500
 neighbor 192.0.2.1 shutdown
 neighbor 2001:db8:1::1 shutdown
exit
exit"

Paso 3: Observa el nodo backup.

En VPS-BKP, la ruta debería aparecer ahora como el único camino:

# BIRD2
birdc show route for 198.51.100.0/24

# FRR
vtysh -c "show ip bgp summary"

Paso 4: Prueba desde fuera.

Desde tu máquina local o un looking glass, haz un traceroute a tu prefijo:

traceroute -A 198.51.100.1

El tráfico debería entrar ahora por la ubicación backup. Con BFD habilitado, la conmutación ocurre en menos de un segundo. Sin BFD, espera la duración completa del hold timer antes de la convergencia.

Método de detección Tiempo de failover típico
Solo hold timer BGP (BIRD2 por defecto 240 s) 160-240 s
Solo hold timer BGP (FRR por defecto 180 s) 120-180 s
Hold timer reducido (ej. 30 s) 20-30 s
BFD (intervalos de 300 ms, multiplicador 3) < 1 s

Usa NLNOG Looking Glass o bgp.tools para confirmar la convergencia del enrutamiento global.

¿Cómo se recupera el servicio tras un failover?

Restablece la sesión primaria y confirma que el tráfico vuelve a la ruta preferida.

BIRD2:

birdc enable upstream_v4
birdc enable upstream_v6

FRR:

vtysh -c "configure terminal
router bgp 64500
 no neighbor 192.0.2.1 shutdown
 no neighbor 2001:db8:1::1 shutdown
exit
exit"

Tras unos segundos, comprueba que la ruta primaria vuelve a ser la preferida:

# BIRD2
birdc show route for 0.0.0.0/0 all | grep local_pref
        BGP.local_pref: 200
# FRR
vtysh -c "show ip bgp"
   Network          Next Hop            Metric LocPrf Weight Path
*> 0.0.0.0/0        192.0.2.1                     200      0 64496 i

Ejecuta un traceroute desde un host externo de nuevo para confirmar que el tráfico vuelve a entrar por la ubicación primaria.

Comparación de configuraciones BIRD2 y FRR

Funcionalidad BIRD2 FRR
LOCAL_PREF bgp_local_pref = 200; en el filtro de importación set local-preference 200 en el route-map
MED bgp_med = 0; en el filtro de exportación set metric 0 en el route-map
AS-path prepend bgp_path.prepend(64500); en el filtro de exportación set as-path prepend 64500 en el route-map
BFD protocol bfd {} + bfd graceful; en BGP sección bfd + neighbor X bfd profile Y
Apagado graceful (iniciar) Añadir (65535, 0) a bgp_community en el filtro de exportación bgp graceful-shutdown bajo router bgp
Apagado graceful (respetar) Comprobar (65535, 0) ~ bgp_community en el filtro de importación, fijar bgp_local_pref = 0 match community GRACEFUL_SHUTDOWN en el route-map, set local-preference 0
Deshabilitar sesión birdc disable <protocol> neighbor X shutdown
Recargar configuración birdc configure write memory y luego clear ip bgp * o reinicio

Monitorización de eventos de failover

Configura monitorización para recibir alertas cuando ocurra un failover. Monitorizar anuncios BGP con BGPalerter en Linux cubre BGPalerter para monitorización de rutas. Como mínimo, vigila:

  • Cambios de estado de sesiones BGP: journalctl -u bird o journalctl -u frr
  • Flaps de sesiones BFD: birdc show bfd sessions / vtysh -c "show bfd peers"
  • Cambios en el número de rutas: alerta si el número de prefijos exportados cae a cero

Resolución de problemas

Sesión BGP estancada en estado Active/Connect:

  • Comprueba las reglas de firewall para TCP 179
  • Verifica que la IP del peer y el ASN coincidan con lo que espera tu upstream
  • Revisa journalctl -u bird -f o journalctl -u frr -f en busca de mensajes de error

Sesión BFD estancada en estado Down:

  • Los puertos UDP 3784 y 3785 deben estar abiertos en ambas direcciones
  • Confirma que el peer soporta BFD y lo tiene configurado
  • Comprueba problemas de MTU en la ruta

MED no afecta al tráfico entrante:

  • MED solo se compara entre rutas del mismo AS. Si tus upstreams son ASes diferentes, usa AS-path prepending en su lugar
  • Algunos upstreams ignoran MED por política. Consulta con tu proveedor

La comunidad de apagado graceful no se respeta:

  • El peer debe soportar explícitamente la RFC 8326. No todos los upstreams lo hacen
  • Consulta con tu proveedor si respetan la comunidad GRACEFUL_SHUTDOWN
  • Algunas implementaciones requieren configuración explícita para respetar la comunidad

El tráfico no conmuta:

  • Verifica que ambos nodos anuncian el mismo prefijo con birdc show route export upstream_v4 o vtysh -c "show ip bgp neighbors X advertised-routes"
  • Comprueba desde un looking glass externo, no desde los propios nodos
  • El TTL de DNS puede mantener a los clientes apuntando a la IP antigua si usas IPs por ubicación para servicios sobre el prefijo anycast