Настройка BGP-маршрутизации для небольшого провайдера: от нуля до отказоустойчивости

Исходная ситуация: провайдер без динамической маршрутизации

В начале 2026 года к нам обратился региональный интернет-провайдер СетьТелеком — небольшая компания из Воронежа, обслуживающая 2 000 абонентов. У провайдера была собственная автономная система AS213579, блок адресов /21 (2 048 IP), и три аплинка: Ростелеком, ТТК и Мегафон.

Проблема была в том, что маршрутизация осуществлялась статическими маршрутами. Дежурный инженер вручную переключал трафик при отказе одного из аплинков — это занимало от 15 до 40 минут. Кроме того:

  • Нет балансировки — весь трафик шёл через Ростелеком (самый дешёвый канал), а ТТК и Мегафон простаивали
  • Нет автоматического failover — падение аплинка означало ручное вмешательство
  • Нет контроля входящего трафика — 70% входящего трафика приходило через самый дорогой канал Мегафон
  • Нет RPKI — уязвимость к BGP hijacking, дважды страдали от утечки маршрутов соседних AS

Инфраструктура: два граничных маршрутизатора на базе Linux (Debian 12), каждый с 4 сетевыми интерфейсами. Задача — поднять полноценный BGP на BIRD2, настроить фильтрацию, балансировку и мониторинг.

Основы BGP: что нужно знать провайдеру

Прежде чем лезть в конфигурацию, мы провели обучающую сессию для инженеров СетьТелеком. Вот ключевые концепции, без которых нельзя работать с BGP:

Автономная система (AS) — это сеть под единым административным управлением с единой политикой маршрутизации. У СетьТелеком это AS213579. У каждого аплинка своя AS: Ростелеком AS12389, ТТК AS20485, Мегафон AS31133.

Prefix (префикс) — блок IP-адресов, объявляемый в BGP. СетьТелеком объявляет 185.120.88.0/21 — свои 2 048 адресов. Этот префикс должен быть зарегистрирован в RIPE как route object:

# Проверяем route object в RIPE
whois -h whois.ripe.net 185.120.88.0/21

# route:          185.120.88.0/21
# descr:          SetTelecom network
# origin:         AS213579
# mnt-by:         MNT-SETTELECOM
# source:         RIPE

BGP Communities — метки, которые навешиваются на маршруты для управления политиками. Стандартные форматы:

  • Standard communities (RFC 1997) — 32-битные, формат AS:VALUE, например 12389:100
  • Large communities (RFC 8092) — 96-битные, формат AS:F1:F2, например 213579:100:0
  • Well-known — NO_EXPORT (65535:65281), NO_ADVERTISE (65535:65282), BLACKHOLE (65535:666)

AS-PATH — последовательность номеров AS, через которые прошёл маршрут. Используется для предотвращения петель и выбора лучшего пути. Чем короче AS-PATH, тем предпочтительнее маршрут.

Local Preference — атрибут для управления исходящим трафиком внутри AS. Чем выше значение, тем предпочтительнее маршрут. По умолчанию 100.

Установка и базовая конфигурация BIRD2

Мы выбрали BIRD2 вместо FRRouting по нескольким причинам: лёгкий (потребляет 80-120 MB RAM при full view), стабильный, отличная фильтрация на собственном языке, активное сообщество. Установка:

# Установка BIRD2 на Debian 12
apt update && apt install -y bird2

# Проверяем версию
bird --version
# BIRD version 2.14

# Основной конфиг: /etc/bird/bird.conf
systemctl enable bird
systemctl start bird

Базовая конфигурация BIRD2 для граничного маршрутизатора:

# /etc/bird/bird.conf — основной конфигурационный файл

# Router ID — обычно primary IP маршрутизатора
router id 185.120.88.1;

# Таблицы маршрутизации
ipv4 table master4;
ipv6 table master6;

# Логирование
log syslog all;
log "/var/log/bird.log" { debug, trace, info, remote, warning, error, auth, fatal, bug };

# Ограничение debug для production
debug protocols { states, routes, filters, interfaces };

# Watchdog — перезапуск при зависании
watchdog warning 5 s;
watchdog timeout 30 s;

# Определяем наши префиксы
define OUR_AS = 213579;
define OUR_NET4 = [ 185.120.88.0/21 ];
define OUR_NET4_DEAGG = [ 185.120.88.0/22, 185.120.92.0/22 ];

# Протокол device — мониторинг интерфейсов
protocol device {
    scan time 10;
}

# Протокол direct — подключённые сети
protocol direct {
    ipv4;
    interface "eth*", "ens*";
}

# Kernel protocol — синхронизация с таблицей маршрутизации ядра
protocol kernel {
    ipv4 {
        export filter {
            # Экспортируем в ядро только best routes
            if source = RTS_BGP then accept;
            reject;
        };
        import none;
    };
    scan time 15;
    learn;
    merge paths on;  # ECMP — балансировка по нескольким путям
}

# Static protocol — объявление наших сетей
protocol static static_bgp {
    ipv4;
    route 185.120.88.0/21 blackhole;  # Агрегат — всегда в таблице
    route 185.120.88.0/22 blackhole;  # Деагрегация для traffic engineering
    route 185.120.92.0/22 blackhole;
}

Ключевой момент — маршруты на наши префиксы указаны как blackhole. Это стандартная практика: если трафик дошёл до нашего маршрутизатора, но конкретный хост недоступен внутри сети — пакет отбрасывается, а не уходит в петлю.

BGP-сессии с аплинками и фильтрация маршрутов

Теперь самое важное — настройка BGP-сессий с каждым аплинком. Для каждого провайдера создали отдельный конфиг с фильтрами:

# /etc/bird/peers/rostelecom.conf — BGP с Ростелеком

# Фильтр экспорта — что мы объявляем Ростелекому
filter export_rostelecom {
    # Объявляем только наши префиксы
    if net ~ OUR_NET4 then accept;
    if net ~ OUR_NET4_DEAGG then accept;
    reject;
}

# Фильтр импорта — что принимаем от Ростелекома
filter import_rostelecom {
    # Отбрасываем наши собственные префиксы (защита от петель)
    if net ~ OUR_NET4 then reject;
    if net ~ OUR_NET4_DEAGG then reject;

    # Отбрасываем bogons — RFC 1918, RFC 6598 и т.д.
    if net ~ [
        0.0.0.0/0,           # default route — принимаем отдельно
        0.0.0.0/8+,          # "This" network
        10.0.0.0/8+,         # RFC 1918
        100.64.0.0/10+,      # RFC 6598 Shared Address Space
        127.0.0.0/8+,        # Loopback
        169.254.0.0/16+,     # Link-local
        172.16.0.0/12+,      # RFC 1918
        192.0.0.0/24+,       # RFC 6890
        192.0.2.0/24+,       # TEST-NET-1
        192.168.0.0/16+,     # RFC 1918
        198.18.0.0/15+,      # Benchmarking
        198.51.100.0/24+,    # TEST-NET-2
        203.0.113.0/24+,     # TEST-NET-3
        224.0.0.0/4+,        # Multicast
        240.0.0.0/4+         # Reserved
    ] then reject;

    # Отбрасываем слишком длинные AS-PATH (>64 хопов — аномалия)
    if bgp_path.len > 64 then reject;

    # Отбрасываем слишком специфичные префиксы (длиннее /24)
    if net.len > 24 then reject;

    # Устанавливаем Local Preference — Ростелеком приоритетный
    bgp_local_pref = 200;

    # Помечаем community для идентификации источника
    bgp_large_community.add((OUR_AS, 1, 1));  # 1 = uplink, 1 = rostelecom

    accept;
}

protocol bgp rostelecom {
    description "Rostelecom AS12389";
    local 185.120.88.1 as OUR_AS;
    neighbor 10.255.1.1 as 12389;
    
    ipv4 {
        import filter import_rostelecom;
        export filter export_rostelecom;
        import limit 1000000 action restart;  # Защита от full table flood
        export limit 10 action disable;       # Мы не должны объявлять много
        receive limit 1000000 action disable;
    };

    hold time 90;
    keepalive time 30;
    graceful restart on;
    long lived graceful restart on;
}

Аналогичные конфиги создали для ТТК (Local Preference 150) и Мегафона (Local Preference 100). Разные значения LP задают приоритет для исходящего трафика: сначала Ростелеком, потом ТТК, потом Мегафон.

# Подключаем peer-конфиги
include "/etc/bird/peers/*.conf";

# Проверяем конфигурацию перед применением
bird -p
# Configuration OK

# Применяем без перезагрузки
birdc configure
# Reading configuration from /etc/bird/bird.conf
# Reconfigured

Через birdc можно проверить состояние сессий:

birdc show protocols all rostelecom
# Name       Proto      Table      State  Since       Info
# rostelecom BGP        ---        up     2026-01-15  Established
#   Neighbor address: 10.255.1.1
#   Neighbor AS:      12389
#   Local AS:         213579
#   Routes:           850432 imported, 3 exported

Traffic engineering: управление входящим трафиком

Исходящий трафик мы контролируем через Local Preference — это просто. А вот входящий трафик определяется решениями чужих маршрутизаторов. Здесь у нас два инструмента: AS-PATH prepending и BGP communities аплинков.

AS-PATH prepending — искусственное удлинение AS-PATH, чтобы сделать маршрут менее привлекательным через определённый аплинк:

# Фильтр экспорта для Мегафона — делаем путь через него длиннее
filter export_megafon {
    if net ~ OUR_NET4 then {
        # Добавляем 2 копии нашей AS в path
        bgp_path.prepend(OUR_AS);
        bgp_path.prepend(OUR_AS);
        accept;
    }
    if net ~ OUR_NET4_DEAGG then {
        bgp_path.prepend(OUR_AS);
        bgp_path.prepend(OUR_AS);
        bgp_path.prepend(OUR_AS);  # Деагрегаты — ещё длиннее
        accept;
    }
    reject;
}

# В результате:
# Через Ростелеком: AS213579 (length 1) — приоритетный
# Через ТТК:        AS213579 AS213579 (length 2)
# Через Мегафон:    AS213579 AS213579 AS213579 (length 3) — наименее приоритетный

BGP communities аплинков — более тонкий инструмент. Каждый крупный провайдер публикует список community для управления анонсами. Например, Ростелеком поддерживает:

# Использование community Ростелекома для управления анонсами
filter export_rostelecom_advanced {
    if net ~ OUR_NET4 then {
        # Просим Ростелеком установить LP=80 для наших маршрутов
        # (вместо дефолтного LP=100 для клиентов)
        bgp_community.add((12389, 80));
        
        # Или: не объявлять определённым пирам Ростелекома
        # bgp_community.add((12389, 9999));  # no-export to specific peer
        
        accept;
    }
    reject;
}

Мы также использовали деагрегацию префиксов для более точного управления. Вместо одного /21 объявляли два /22 через разные аплинки — половина интернета шла через Ростелеком, другая через ТТК:

# Деагрегация: 185.120.88.0/22 через Ростелеком, 185.120.92.0/22 через ТТК
filter export_rostelecom_deagg {
    if net = 185.120.88.0/21 then accept;     # Агрегат — всегда
    if net = 185.120.88.0/22 then accept;     # Первая половина — без prepend
    if net = 185.120.92.0/22 then {
        bgp_path.prepend(OUR_AS);
        bgp_path.prepend(OUR_AS);
        accept;                                # Вторая половина — с prepend
    }
    reject;
}

После настройки traffic engineering распределение входящего трафика стало: Ростелеком 45%, ТТК 35%, Мегафон 20% — вместо прежних 70% через Мегафон.

RPKI/ROA валидация и Looking Glass

После двух инцидентов с BGP hijacking (когда чужая AS объявляла наши префиксы) мы внедрили RPKI — Resource Public Key Infrastructure. Это криптографическая валидация принадлежности префиксов к автономным системам.

Шаг 1: создание ROA (Route Origin Authorization) в RIPE Database:

# ROA создаётся в RIPE через веб-интерфейс или API
# Указывает: этот префикс МОЖЕТ объявляться ТОЛЬКО из этой AS
# Prefix: 185.120.88.0/21
# Max Length: /22 (разрешаем деагрегацию до /22)
# Origin AS: AS213579

# Проверяем созданный ROA
whois -h whois.ripe.net -T route 185.120.88.0/21
# route:   185.120.88.0/21
# origin:  AS213579
# remarks: ROA validated

Шаг 2: установка RPKI-валидатора. Мы использовали Routinator от NLnet Labs:

# Установка Routinator
curl -fsSL https://packages.nlnetlabs.nl/aptkey.asc | apt-key add -
echo "deb https://packages.nlnetlabs.nl/linux/debian/ bookworm main" > \
    /etc/apt/sources.list.d/nlnetlabs.list
apt update && apt install -y routinator

# Инициализация (принятие ARIN TAL)
routinator init --accept-arin-rpa

# Запуск как сервис
systemctl enable routinator
systemctl start routinator

# Routinator слушает RTR-протокол на порту 3323
# и HTTP API на порту 8323
curl -s http://localhost:8323/api/v1/status | jq .
# {
#   "version": "0.13.2",
#   "vrps": 482356,
#   "last_update": "2026-01-20T14:30:00Z"
# }

Шаг 3: подключение RPKI к BIRD2:

# /etc/bird/rpki.conf — подключение к Routinator
protocol rpki rpki_validator {
    roa4 { table roa_v4; };
    roa6 { table roa_v6; };
    remote "127.0.0.1" port 3323;
    retry keep 90;
    refresh keep 900;
    expire keep 172800;
}

# Создаём ROA-таблицы
roa4 table roa_v4;
roa6 table roa_v6;

# Обновляем фильтр импорта — отбрасываем RPKI Invalid
filter import_with_rpki {
    # ... (предыдущие проверки bogons и т.д.)
    
    # RPKI-валидация
    if (roa_check(roa_v4, net, bgp_path.last) = ROA_INVALID) then {
        print "RPKI INVALID: ", net, " from AS", bgp_path.last;
        reject;
    }
    if (roa_check(roa_v4, net, bgp_path.last) = ROA_VALID) then {
        # Бонус к LP для валидированных маршрутов
        bgp_local_pref = bgp_local_pref + 20;
        bgp_large_community.add((OUR_AS, 100, 1));  # RPKI Valid
    }
    if (roa_check(roa_v4, net, bgp_path.last) = ROA_UNKNOWN) then {
        bgp_large_community.add((OUR_AS, 100, 0));  # RPKI Unknown
    }
    
    accept;
}

Looking Glass — веб-интерфейс для просмотра таблицы маршрутов. Развернули Alice-LG:

# Docker-compose для Looking Glass
version: '3'
services:
  alice-lg:
    image: ecix/alice-lg:latest
    ports:
      - "8080:80"
    volumes:
      - ./alice.conf:/etc/alice-lg/alice.conf
    restart: always

# alice.conf — подключение к BIRD через birdwatcher API
[source.router1]
name = "Router-1 (Primary)"
api = "http://router1:29184/"
type = birdwatcher

Теперь любой сотрудник СетьТелеком может посмотреть таблицу маршрутов, проверить доступность префикса и статус BGP-сессий через веб-интерфейс — без доступа к CLI маршрутизатора.

Мониторинг BGP-сессий и алертинг

BGP без мониторинга — бомба замедленного действия. Мы настроили три уровня мониторинга:

1. BIRD встроенный мониторинг через birdc:

#!/bin/bash
# /opt/scripts/bgp_health.sh — проверка BGP-сессий каждые 60 секунд

BOT_TOKEN="7012345678:AAH..."
CHAT_ID="-100123456789"

# Получаем статус всех BGP-сессий
SESSIONS=$(birdc show protocols | grep BGP)

# Проверяем каждую сессию
while IFS= read -r line; do
    NAME=$(echo "$line" | awk '{print $1}')
    STATE=$(echo "$line" | awk '{print $6}')
    
    if [ "$STATE" != "Established" ]; then
        MSG="BGP session $NAME is $STATE on $(hostname)"
        curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
            -d chat_id="$CHAT_ID" \
            -d text="$MSG"
    fi
done <<< "$SESSIONS"

# Проверяем количество принятых маршрутов
for PEER in rostelecom ttk megafon; do
    ROUTES=$(birdc show protocols all $PEER | grep 'Routes:' | awk '{print $2}')
    # Если маршрутов меньше 100K — что-то не так (обычно ~850K при full view)
    if [ "$ROUTES" -lt 100000 ] 2>/dev/null; then
        MSG="Low route count from $PEER: $ROUTES routes (expected 800K+)"
        curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
            -d chat_id="$CHAT_ID" \
            -d text="$MSG"
    fi
done

2. Prometheus + bird_exporter:

# Установка bird_exporter для Prometheus
wget https://github.com/czerwonk/bird_exporter/releases/download/v1.4.3/bird_exporter_1.4.3_linux_amd64.deb
dpkg -i bird_exporter_1.4.3_linux_amd64.deb
systemctl enable bird_exporter
systemctl start bird_exporter

# Метрики доступны на :9324/metrics
# bird_protocol_up{name="rostelecom"} 1
# bird_protocol_imported_routes{name="rostelecom"} 850432
# bird_protocol_exported_routes{name="rostelecom"} 3
# bird_protocol_uptime_seconds{name="rostelecom"} 1728000

3. Внешний мониторинг через RIPE RIS и BGPStream:

# Скрипт мониторинга BGP hijacking через RIPE RIS API
#!/bin/bash
# /opt/scripts/bgp_hijack_monitor.sh

OUR_PREFIX="185.120.88.0/21"
OUR_AS="213579"

# Запрашиваем RIS API — кто объявляет наш префикс
RESPONSE=$(curl -s "https://stat.ripe.net/data/looking-glass/data.json?resource=$OUR_PREFIX")

# Проверяем, что все origins — наша AS
ORIGINS=$(echo "$RESPONSE" | jq -r '.data.rrcs[].peers[].as_path' | \
    awk '{print $NF}' | sort -u)

for ORIGIN in $ORIGINS; do
    if [ "$ORIGIN" != "$OUR_AS" ]; then
        MSG="HIJACK ALERT: prefix $OUR_PREFIX announced by AS$ORIGIN (expected AS$OUR_AS)"
        curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
            -d chat_id="$CHAT_ID" \
            -d text="$MSG" \
            -d parse_mode="HTML"
    fi
done

Все три скрипта добавили в systemd-таймеры: BGP health — каждые 60 секунд, hijack monitor — каждые 5 минут. За первый месяц мониторинг поймал 3 кратковременных сброса сессии с ТТК (проблема на их стороне) и одну попытку route leak от соседней AS.

Результаты и рекомендации

После внедрения полноценного BGP на BIRD2 провайдер СетьТелеком получил:

МетрикаДоПосле
Время переключения при отказе аплинка15-40 минут (вручную)3-5 секунд (автоматически)
Распределение входящего трафика70% Мегафон (дорогой)45% Ростелеком / 35% ТТК / 20% Мегафон
Экономия на трафике~120 000 ₽/мес
Инциденты BGP hijacking2 за год (без защиты)0 (RPKI + мониторинг)
Время реакции на проблемуКогда позвонят абоненты60 секунд (алерт в Telegram)

Рекомендации для провайдеров, которые только начинают работать с BGP:

  • Начните с фильтрации — bogon-фильтры и prefix-limit спасут от чужих аномалий
  • Настройте RPKI с первого дня — Routinator устанавливается за 10 минут, а защита от hijacking бесценна
  • Мониторьте количество маршрутов — резкое падение или рост числа принятых маршрутов — верный признак проблемы
  • Не злоупотребляйте prepending — более 3 prepend не имеет смысла, а иногда вредит
  • Тестируйте failover — раз в месяц отключайте один аплинк и проверяйте переключение

Инженеры itfresh.ru готовы помочь с настройкой BGP для провайдеров любого масштаба — от 500 до 50 000 абонентов.

Часто задаваемые вопросы

BIRD2 — оптимальный выбор для большинства провайдеров: потребляет 80-120 MB RAM при full view (850K+ маршрутов), имеет мощный язык фильтрации и стабилен в production. FRRouting подходит для более сложных сценариев с OSPF/IS-IS, но потребляет больше ресурсов. Для маленьких AS с 1-2 аплинками можно использовать OpenBGPD.
Route object в RIPE — это текстовая запись без криптографической защиты, её может создать кто угодно. RPKI (ROA) использует сертификаты X.509 и криптографически подтверждает, что конкретная AS имеет право объявлять конкретный префикс. При RPKI-валидации маршрутизаторы автоматически отбрасывают маршруты от неавторизованных AS.
Стандартная практика: основной аплинк — LP 200, резервный — LP 150, аварийный — LP 100. Шаг в 50 единиц оставляет пространство для тонкой настройки отдельных префиксов. Например, маршруты к CDN-провайдерам можно направить через аплинк с лучшей связностью, установив LP 250 для конкретных prefix-list.
BGP communities — это метки (теги), которые навешиваются на маршруты. Крупные провайдеры публикуют списки community, через которые клиенты могут управлять анонсами: задать Local Preference на стороне аплинка, запретить объявление определённым пирам, установить prepending. Это позволяет управлять входящим трафиком без изменения своей конфигурации.
Full IPv4 BGP table содержит ~950K маршрутов (на начало 2026 года). BIRD2 потребляет около 100-150 MB RAM на одну full view. Для двух аплинков с full view плюс RPKI-валидация рекомендуем минимум 2 GB RAM и 2 CPU. Linux-маршрутизатор на Debian 12 с BIRD2 стабильно работает на виртуалке с 4 GB RAM и 2 vCPU.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#bgp настройка#bird2 конфигурация#as path фильтрация#prefix list bgp#bgp communities#multihoming провайдер#traffic engineering bgp#rpki roa валидация
Комментарии 0

Оставить комментарий

загрузка...