BGP-фейловер и мультихоминг с двух VPS-локаций

9 мин чтения·Matthieu·bird2bfdfailoverfrrbgpmultihoming|

Анонсируйте один и тот же префикс с двух локаций через BGP для автоматического фейловера. Рассматриваются LOCAL_PREF, MED, AS-path prepending, BFD и graceful shutdown с полными конфигурациями BIRD2 и FRR.

В этом руководстве разбирается анонсирование одного и того же IP-префикса с двух отдельных VPS-локаций через BGP. Вы настроите приоритет основного/резервного узла с помощью LOCAL_PREF и MED, включите BFD для обнаружения сбоев менее чем за секунду и реализуете graceful shutdown для планового обслуживания. Все примеры приведены параллельно для BIRD2 и FRR.

Предварительные требования:

Что такое BGP-мультихоминг и зачем он на VPS?

BGP-мультихоминг означает анонсирование одного и того же IP-префикса с двух или более локаций через eBGP. Каждая локация поддерживает независимую BGP-сессию со своим аплинком. Если одна локация выходит из строя, другая продолжает анонсировать префикс и автоматически принимает весь трафик. Время конвергенции зависит от hold-таймеров (обычно 180-240 секунд при стандартных настройках) или BFD (менее секунды при правильной конфигурации).

На VPS мультихоминг даёт резервирование без привязки к одному дата-центру. Вы запускаете два VPS в разных локациях, оба анонсируют ваш префикс. Один работает как основной, другой как резервный. Атрибуты управления трафиком (LOCAL_PREF, MED, AS-path prepending) определяют, какой путь обрабатывает трафик в нормальных условиях.

Как спроектировать BGP-фейловер между двумя локациями?

Схема использует два Virtua VPS в разных европейских локациях, каждый с eBGP-сессией к локальному аплинк-маршрутизатору. Оба анонсируют одинаковые /24 и /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

Оба узла принадлежат вашему AS (AS 64500 в этих примерах). Замените ASN, префиксы и IP-адреса пиров на свои реальные значения.

Правила файрвола для обоих узлов:

BGP использует TCP-порт 179. BFD использует UDP-порты 3784 и 3785. Откройте их между вашим VPS и аплинк-пиром, прежде чем продолжать.

# 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

Как управлять предпочтением BGP-маршрута?

Три атрибута позволяют влиять на выбор пути для трафика. Каждый работает на своём уровне.

Атрибут Направление Область Передаётся пирам? Когда использовать
LOCAL_PREF Исходящий (ваш выход) Внутри вашего AS Нет (только iBGP) Управление тем, какой узел отправляет исходящий трафик
MED Входящий (от аплинка) Между вами и одним AS-аплинком Да (прямому соседу) Указать аплинку, какую точку входа предпочесть
AS-path prepending Входящий (глобальный) Все AS в пути Да (распространяется) Сделать путь длиннее для всего интернета

LOCAL_PREF и MED — точные инструменты. AS-path prepending — грубый, но работает, когда ваши локации подключены к разным аплинкам.

Как настроить LOCAL_PREF для основного и резервного маршрутов?

LOCAL_PREF определяет, какой выходной путь предпочитает ваш AS для исходящего трафика. Побеждает большее значение. По умолчанию — 100. Установите 200 на основном узле и оставьте 100 на резервном. Это влияет только на трафик, покидающий вашу сеть.

Настройка LOCAL_PREF в BIRD2

На основном узле (VPS-PRI) создайте или измените фильтр импорта:

# /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;
    };
}

На резервном узле (VPS-BKP) оставьте LOCAL_PREF по умолчанию:

# /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;
    };
}

Перезагрузите BIRD2 и проверьте маршруты:

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

Значение BGP.local_pref: 200 на основном узле означает, что он будет предпочтён для исходящего трафика.

Настройка LOCAL_PREF в FRR

На основном узле:

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"

На резервном узле задайте set local-preference 100 (или опустите route-map, так как 100 — значение по умолчанию).

Проверьте таблицу маршрутизации:

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

Как использовать MED для управления входящим трафиком?

MED (Multi-Exit Discriminator) говорит вашему аплинку, какую точку входа предпочесть. Побеждает меньшее значение. Установите MED 0 на основном и MED 100 на резервном узле. MED сравнивается только между маршрутами от одного и того же соседнего AS, поэтому лучше всего работает, когда обе локации пирятся с одним аплинк-провайдером.

Настройка MED в BIRD2

На основном узле задайте MED в фильтре экспорта:

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;
    };
}

На резервном узле:

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

Настройка MED в FRR

На основном узле:

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"

На резервном узле используйте set metric 100.

Проверьте экспортируемые маршруты:

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

Колонка Metric показывает 0 на основном узле. Резервный покажет 100.

Когда использовать AS-path prepending вместо MED?

Используйте AS-path prepending, когда ваши две локации подключены к разным аплинк-провайдерам. MED сравнивается только между маршрутами от одного AS, поэтому не работает, если аплинки — разные AS. Prepending удлиняет резервный путь, направляя глобальные решения маршрутизации к основному узлу.

Добавьте свой ASN от 1 до 3 раз на резервном узле. Больше 3 prepend'ов редко меняет решения маршрутизации и только добавляет шум.

BIRD2 (фильтр экспорта резервного узла):

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 (резервный узел):

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

После применения проверьте AS-путь через looking glass или с удалённой машины:

# From an external machine
traceroute -A 198.51.100.1

Резервный путь теперь показывает 64500 64500 64500 (ваш ASN появляется трижды: один раз реальный, дважды добавленный), а основной показывает 64500 один раз.

Как включить BFD для быстрого обнаружения сбоев?

Без BFD протокол BGP полагается на hold-таймеры для обнаружения сбоя пира. Hold-таймер по умолчанию составляет 240 секунд в BIRD2 и 180 секунд в FRR. С BFD обнаружение падает до менее чем секунды на каналах с низкой задержкой.

Параметр По умолчанию Рекомендуется для VPS
Интервал передачи 300 мс 300 мс
Интервал приёма 300 мс 300 мс
Множитель обнаружения 3 3
Эффективное время обнаружения 900 мс 900 мс

Для VPS-сред на одном бэкбоне провайдера интервалы в 300 мс с множителем 3 дают надёжное обнаружение менее чем за секунду без ложных срабатываний. Не ставьте интервалы ниже 100 мс на VPS-инстансах. Джиттер виртуализации может вызвать флаппинг.

Настройка BFD в BIRD2

Добавьте протокол BFD и включите его на 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;
    };
}

Опция bfd graceful означает, что при обнаружении сбоя через BFD BIRD2 инициирует graceful restart (сохраняя устаревшие маршруты) вместо жёсткого сброса сессии. Если пир не поддерживает BFD, сессия устанавливается в обычном режиме.

После перезагрузки проверьте состояние 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

Настройка BFD в 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"

Проверьте состояние 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 требует открытых UDP-портов 3784 и 3785 между пирами. Если вы пропустили шаг с файрволом, BFD-сессии останутся в состоянии Down.

Как выполнить graceful shutdown для обслуживания?

RFC 8326 определяет well-known community GRACEFUL_SHUTDOWN (65535:0). Перед плановым обслуживанием вы помечаете все маршруты этим community. Пиры, которые его учитывают, устанавливают local-preference в 0 для этих маршрутов, перенаправляя трафик на альтернативные пути до отключения сессии. Это позволяет избежать чёрной дыры трафика, которая возникает при обычной конвергенции BGP.

Процедура graceful shutdown:

  1. Пометьте маршруты community GRACEFUL_SHUTDOWN на узле, который вы отключаете
  2. Дождитесь конвергенции (30-60 секунд, пока интернет перемаршрутизирует трафик)
  3. Убедитесь, что трафик переключился, через looking glass или счётчики трафика
  4. Остановите BGP-сессию
  5. Выполните обслуживание
  6. Восстановите сессию и удалите community
  7. Подтвердите реконвергенцию

Graceful shutdown в BIRD2

Чтобы инициировать graceful shutdown на основном узле перед обслуживанием, измените фильтр экспорта:

# 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;
}

Примените его, изменив фильтр экспорта в протоколе BGP и перезагрузив конфигурацию:

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

Чтобы учитывать graceful shutdown от пиров (примените на обоих узлах), добавьте проверку в фильтр импорта. Порядок важен: проверка graceful shutdown должна вызывать accept внутри блока if, иначе последующее присвоение bgp_local_pref перезапишет значение.

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

Graceful shutdown в FRR

FRR предоставляет одну команду, которая выполняет маркировку автоматически:

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

Это добавляет community GRACEFUL_SHUTDOWN (65535:0) ко всем маршрутам и устанавливает local-preference в 0. Всем пирам отправляется route refresh.

Чтобы подтвердить отправку community:

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

После обслуживания удалите:

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

Чтобы FRR учитывал graceful shutdown от пиров, настройте входящий route-map:

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"

Sequence 5 выбирает маршруты с community и снижает local-preference до 0. Sequence 10 обрабатывает все остальные маршруты в обычном режиме.

Как протестировать BGP-фейловер?

Протестируйте фейловер, отключив основную BGP-сессию и наблюдая с резервного узла и внешней точки.

Шаг 1: Проверьте текущее состояние маршрутизации на обоих узлах.

BIRD2:

birdc show route for 198.51.100.0/24 all

FRR:

vtysh -c "show ip bgp 198.51.100.0/24"

Шаг 2: Отключите основную BGP-сессию.

BIRD2 (на VPS-PRI):

birdc disable upstream_v4
birdc disable upstream_v6

FRR (на VPS-PRI):

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

Шаг 3: Наблюдайте за резервным узлом.

На VPS-BKP маршрут теперь должен отображаться как единственный путь:

# BIRD2
birdc show route for 198.51.100.0/24

# FRR
vtysh -c "show ip bgp summary"

Шаг 4: Проверьте извне.

С вашей локальной машины или looking glass выполните traceroute к вашему префиксу:

traceroute -A 198.51.100.1

Трафик теперь должен входить через резервную локацию. С включённым BFD переключение происходит менее чем за секунду. Без BFD ожидайте полную длительность hold-таймера до конвергенции.

Метод обнаружения Типичное время фейловера
Только BGP hold-таймер (BIRD2 по умолчанию 240 с) 160-240 с
Только BGP hold-таймер (FRR по умолчанию 180 с) 120-180 с
Сниженный hold-таймер (напр. 30 с) 20-30 с
BFD (интервалы 300 мс, множитель 3) < 1 с

Используйте NLNOG Looking Glass или bgp.tools для подтверждения глобальной конвергенции маршрутизации.

Как восстановить работу после фейловера?

Восстановите основную сессию и убедитесь, что трафик вернулся на предпочтительный путь.

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"

Через несколько секунд проверьте, что основной путь снова предпочтён:

# 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

Снова выполните traceroute с внешнего хоста, чтобы подтвердить, что трафик вновь входит через основную локацию.

Сравнение конфигураций BIRD2 и FRR

Функция BIRD2 FRR
LOCAL_PREF bgp_local_pref = 200; в фильтре импорта set local-preference 200 в route-map
MED bgp_med = 0; в фильтре экспорта set metric 0 в route-map
AS-path prepend bgp_path.prepend(64500); в фильтре экспорта set as-path prepend 64500 в route-map
BFD protocol bfd {} + bfd graceful; в BGP секция bfd + neighbor X bfd profile Y
Graceful shutdown (инициация) Добавить (65535, 0) в bgp_community в фильтре экспорта bgp graceful-shutdown под router bgp
Graceful shutdown (учёт) Проверить (65535, 0) ~ bgp_community в фильтре импорта, установить bgp_local_pref = 0 match community GRACEFUL_SHUTDOWN в route-map, set local-preference 0
Отключение сессии birdc disable <protocol> neighbor X shutdown
Перезагрузка конфигурации birdc configure write memory затем clear ip bgp * или перезапуск

Мониторинг событий фейловера

Настройте мониторинг для получения оповещений при фейловере. Мониторинг BGP-анонсов с помощью BGPalerter на Linux описывает BGPalerter для мониторинга маршрутов. Как минимум отслеживайте:

  • Изменения состояния BGP-сессий: journalctl -u bird или journalctl -u frr
  • Флапы BFD-сессий: birdc show bfd sessions / vtysh -c "show bfd peers"
  • Изменения количества маршрутов: оповещение, если число экспортируемых префиксов падает до нуля

Устранение неполадок

BGP-сессия зависла в состоянии Active/Connect:

  • Проверьте правила файрвола для TCP 179
  • Убедитесь, что IP пира и ASN совпадают с тем, что ожидает ваш аплинк
  • Смотрите journalctl -u bird -f или journalctl -u frr -f на предмет ошибок

BFD-сессия зависла в состоянии Down:

  • UDP-порты 3784 и 3785 должны быть открыты в обоих направлениях
  • Убедитесь, что пир поддерживает BFD и настроил его
  • Проверьте проблемы MTU на пути

MED не влияет на входящий трафик:

  • MED сравнивается только между маршрутами от одного AS. Если ваши аплинки — разные AS, используйте AS-path prepending
  • Некоторые аплинки игнорируют MED по политике. Уточните у провайдера

Community graceful shutdown не учитывается:

  • Пир должен явно поддерживать RFC 8326. Не все аплинки это делают
  • Уточните у провайдера, учитывают ли они community GRACEFUL_SHUTDOWN
  • Некоторые реализации требуют явной настройки для учёта community

Трафик не переключается:

  • Убедитесь, что оба узла анонсируют один и тот же префикс: birdc show route export upstream_v4 или vtysh -c "show ip bgp neighbors X advertised-routes"
  • Проверяйте с внешнего looking glass, а не с самих узлов
  • DNS TTL может удерживать клиентов на старом IP, если вы используете отдельные IP для сервисов поверх anycast-префикса