FRR (Free Range Routing) на Linux — рабочий инструмент, чтобы поднять BGP на сервере, подключить два аплинка (multihoming), управлять исходящим/входящим трафиком и при этом не «протечь» маршрутами наружу. Ниже — практический каркас конфигурации: prefix-list и route-map, базовые communities, настройка local-preference и MED, и обязательные меры против route leak. В конце — безопасное внедрение RTBH (blackhole community).
Предпосылки и терминология: что мы строим
Типовая схема: у вас свой AS (например, AS65001), свой публичный префикс (например, 203.0.113.0/24) и два провайдера (Upstream A и Upstream B). Цели:
- анонсировать наружу только свои префиксы (и ровно в согласованных масках);
- получать от провайдеров «полную таблицу» или только default — и уметь выбрать предпочтительный выход;
- не отдавать провайдеру маршруты, полученные от другого провайдера (классический route leak);
- использовать communities для политик провайдера (prepend/no-export/blackhole — зависит от аплинка).
Ключевая практика: политика всегда явная. На каждого соседа — отдельные правила in и out через route-map. А prefix-list — ваш «белый список» того, что вообще допустимо.
В BGP вы управляете не «маршрутами вообще», а тем, какие маршруты готовы принять от соседа и какие готовы ему отдать.
Базовая подготовка Linux и FRR
Пример для Debian/Ubuntu: установите FRR и включите нужные демоны.
sudo apt update
sudo apt install -y frr frr-pythontools
Проверьте файл /etc/frr/daemons: для BGP должен быть bgpd=yes. После правок:
sudo systemctl enable frr
sudo systemctl restart frr
Работать удобнее через vtysh:
sudo vtysh
Адресация и роль сервера
Для eBGP вам нужен L3-линк до каждого аплинка (часто /31 или /30). Если этот же сервер маршрутизирует трафик (шлюз), заранее проверьте:
- включён ли форвардинг:
net.ipv4.ip_forward=1; - не мешает ли firewall TCP/179 (и TTL, если используете eBGP-multihop);
- понимаете ли вы, какие маршруты попадут в BGP (особенно если планируете
redistribute).
Если BGP планируется держать на отдельной виртуалке, удобный вариант — поднять её на VDS и развести роли: маршрутизация/фильтрация в FRR, сервисы — отдельно.
Анти-route-leak: «не транзит» по умолчанию
Самая частая авария — случайно стать транзитной AS: принять у Upstream A кучу маршрутов и отдать их Upstream B. Это и есть route leak. Предотвращается дисциплиной экспорта/импорта и лимитами.
Минимальный набор правил, который реально спасает:
- Экспорт только своего: наружу анонсируем только свои префиксы (и, при необходимости, агрегаты).
- Импорт с охранниками: либо default-only, либо full table, но всегда с фильтрацией и лимитами.
maximum-prefixна каждого соседа, особенно при full table.- Раздельные
route-mapin/out для каждого соседа и явныйdenyв конце.
Дальше показываю шаблон, который проще поддерживать: один набор списков/карт на экспорт, отдельные — на импорт, и приоритеты в route-map по seq.

Экспорт: prefix-list и route-map для своих анонсов
Начните с самого важного: что вы отдаёте провайдерам. Создайте prefix-list «наше» и разрешите только согласованные маски. Для одного /24 обычно экспортируют ровно /24 (если более специфичные не согласованы отдельно).
configure terminal
!
ip prefix-list PL-OWNED-V4 seq 10 permit 203.0.113.0/24
ip prefix-list PL-OWNED-V4 seq 100 deny 0.0.0.0/0 le 32
!
route-map RM-TO-UPSTREAM-A permit 10
match ip address prefix-list PL-OWNED-V4
set community 65001:100 additive
!
route-map RM-TO-UPSTREAM-A deny 100
!
route-map RM-TO-UPSTREAM-B permit 10
match ip address prefix-list PL-OWNED-V4
set community 65001:100 additive
!
route-map RM-TO-UPSTREAM-B deny 100
!
end
write memory
Community 65001:100 здесь «внутренняя метка» (для вашей читаемости/аналитики). Провайдерские communities (prepend/no-export/blackhole) всегда берите из документации аплинка: универсального значения нет.
BGP multihoming в FRR: скелет конфигурации
Добавим BGP-процесс, соседей и назначим политики in/out. Пример для двух eBGP-соседей по прямым линкам:
configure terminal
!
router bgp 65001
bgp router-id 203.0.113.10
no bgp ebgp-requires-policy
!
neighbor 198.51.100.1 remote-as 64500
neighbor 198.51.100.1 description UPSTREAM-A
!
neighbor 192.0.2.1 remote-as 64501
neighbor 192.0.2.1 description UPSTREAM-B
!
address-family ipv4 unicast
network 203.0.113.0/24
!
neighbor 198.51.100.1 route-map RM-FROM-UPSTREAM-A in
neighbor 198.51.100.1 route-map RM-TO-UPSTREAM-A out
!
neighbor 192.0.2.1 route-map RM-FROM-UPSTREAM-B in
neighbor 192.0.2.1 route-map RM-TO-UPSTREAM-B out
exit-address-family
!
end
write memory
no bgp ebgp-requires-policy удобно в лаборатории, но в проде не стоит воспринимать как «можно без политик». Делайте фильтры явными (как в шаблоне), а для максимальной строгости можете убрать эту опцию и проверить, что все соседи имеют назначенные route-map.
Импорт: local-pref, MED и два практичных сценария
Что важно понимать про атрибуты:
local-preferenceвлияет на выбор исходящего пути внутри вашего AS (выше — предпочтительнее).- MED теоретически подсказывает соседу предпочтительный вход, но провайдер может игнорировать или переопределять.
- Communities — самый прикладной способ влиять на поведение провайдера (если он поддерживает нужные метки).
Сценарий A: принимаем только default (рекомендуемый старт)
Для небольшого пограничного сервера самый спокойный вариант — принимать только 0.0.0.0/0 от каждого аплинка и выбирать предпочтительный выход через local-preference. Так вы экономите память/CPU и резко снижаете риск инцидентов.
configure terminal
!
ip prefix-list PL-DEFAULT seq 10 permit 0.0.0.0/0
ip prefix-list PL-DEFAULT seq 100 deny 0.0.0.0/0 le 32
!
route-map RM-FROM-UPSTREAM-A permit 10
match ip address prefix-list PL-DEFAULT
set local-preference 200
!
route-map RM-FROM-UPSTREAM-A deny 100
!
route-map RM-FROM-UPSTREAM-B permit 10
match ip address prefix-list PL-DEFAULT
set local-preference 150
!
route-map RM-FROM-UPSTREAM-B deny 100
!
end
write memory
Итог: при живом A вы почти всегда выходите через него; при падении A — через B (если B продолжает отдавать default).
Сценарий B: принимаем full table (и не падаем)
Если вам нужна полная таблица, добавьте защиту до того, как включите импорт:
maximum-prefixна соседа (с запасом, но не бесконечно);- базовую фильтрацию «слишком длинных» префиксов (под вашу политику);
- осознанную оценку ресурсов: RAM, CPU и скорость конвергенции.
Пример: отсечь всё длиннее /24 и выставить лимит по префиксам. Значения подберите под реальность вашего провайдера.
configure terminal
!
ip prefix-list PL-ACCEPT-V4 seq 10 deny 0.0.0.0/0 ge 25
ip prefix-list PL-ACCEPT-V4 seq 20 permit 0.0.0.0/0 le 24
!
route-map RM-FROM-UPSTREAM-A permit 10
match ip address prefix-list PL-ACCEPT-V4
set local-preference 200
!
route-map RM-FROM-UPSTREAM-A deny 100
!
router bgp 65001
address-family ipv4 unicast
neighbor 198.51.100.1 maximum-prefix 1200000 90 restart 5
exit-address-family
!
end
write memory
maximum-prefix 1200000 90 restart 5 означает: при достижении 90% лимита — предупреждение; при превышении — защитная реакция и попытка восстановиться через 5 минут. Уточните поведение под вашу версию FRR и процессы эксплуатации (иногда лучше отключать автоперезапуск и разбирать причину руками).
Communities: как использовать в живой конфигурации
В FRR communities обычно задают через set community ... additive. Два практичных правила:
- без
additiveвы можете стереть существующие communities; - держите провайдерские метки в одном месте (в одном route-map или в отдельных «слоях»), чтобы проще менять политику.
Кейс: ограниченный экспорт (no-export)
Well-known community no-export просит соседа не экспортировать маршрут за пределы своей AS. Это может помочь для тестов или ограниченных объявлений, но не заменяет нормальные фильтры.
configure terminal
!
route-map RM-TO-UPSTREAM-A permit 10
match ip address prefix-list PL-OWNED-V4
set community no-export additive
!
end
write memory
RTBH (blackhole community): внедрение без самострела
RTBH (remote triggered blackhole) — вы анонсируете точечный маршрут /32 для атакуемого IP и помечаете его community, по которой провайдер «гасит» трафик (обычно на своей границе, отправляя в null). Это защищает ваш канал, но делает атакуемый адрес недоступным.
Чтобы не «похоронить» весь префикс:
- разрешайте для RTBH только /32;
- делайте отдельный
prefix-listи отдельное правило вroute-mapс более высоким приоритетом (меньшийseq).
Важно: у соседа может быть только один outbound route-map. Поэтому RTBH-логику обычно встраивают в общий RM-TO-UPSTREAM-A отдельным permit-правилом выше «обычного» экспорта.
configure terminal
!
ip prefix-list PL-RTBH-V4 seq 10 permit 203.0.113.123/32
ip prefix-list PL-RTBH-V4 seq 100 deny 0.0.0.0/0 le 32
!
route-map RM-TO-UPSTREAM-A permit 5
match ip address prefix-list PL-RTBH-V4
set community 64500:666 additive
!
route-map RM-TO-UPSTREAM-A permit 10
match ip address prefix-list PL-OWNED-V4
set community 65001:100 additive
!
route-map RM-TO-UPSTREAM-A deny 100
!
end
write memory
Community 64500:666 — пример. Подставьте значение, которое требует ваш провайдер для blackhole, и убедитесь, что он принимает RTBH именно в таком виде (некоторые просят aнонсировать /32 только при наличии заранее согласованного «blackhole» next-hop или специальных условий).

Типовые причины route leak и как их быстро отловить
Осторожнее с redistribute
Команды вида redistribute connected, redistribute static и т.п. полезны, но легко приводят к «лишним» маршрутам в BGP. Если вы их используете, экспортный route-map обязан быть строгим (как в шаблоне: разрешаем только PL-OWNED-V4, остальное — deny).
Минимальный набор диагностики
sudo vtysh -c "show bgp ipv4 unicast summary"
sudo vtysh -c "show bgp ipv4 unicast neighbors 198.51.100.1 advertised-routes"
sudo vtysh -c "show bgp ipv4 unicast neighbors 198.51.100.1 received-routes"
sudo vtysh -c "show route-map"
sudo vtysh -c "show ip prefix-list"
Самая важная проверка — advertised-routes. Если там есть чужие сети (не ваши префиксы и не согласованные RTBH /32), это почти наверняка утечка, и её нужно гасить экспортной политикой.
local-pref и MED в реальной жизни multihoming
local-preference — главный рычаг выбора выхода (egress). Практика: задавайте «ступеньки» (например, 200/150/100), чтобы позже без боли добавить третий канал или временно понизить приоритет.
MED иногда помогает для входящего трафика (ingress), но рассчитывать на него как на «железное» управление не стоит. Для ingress чаще работают именно провайдерские communities (prepend на конкретные направления, география, blackhole, ограничения экспорта). Если вы параллельно настраиваете защиту периметра, полезно держать фильтрацию на уровне firewall отдельно; для Linux-узлов с динамическими списками блокировок пригодятся динамические set’ы в nftables.
Чек-лист перед вводом в прод
- Экспорт:
prefix-listразрешает только ваши префиксы; вroute-map outесть явныйdenyв конце. - Импорт: на каждом соседе есть
route-map in; при full table заданmaximum-prefix. - Communities: используете
additive, если не хотите стирать существующие метки. - RTBH: разрешены только /32; правило RTBH стоит выше «обычного» экспорта.
- Наблюдаемость: вы умеете быстро проверить received/advertised и понимаете, что именно изменилось.
Если сомневаетесь в фильтрах — начните с «default-only + owned-export». Это самый спокойный старт для FRR и multihoming.
Что улучшить дальше
Этот каркас закрывает базовый multihoming и анти-route-leak. Обычно дальше добавляют:
- RPKI/ROV-проверки (чтобы не принимать заведомо неверные объявления);
- BFD для ускорения детекта падения (если поддерживается аплинком);
- входящую балансировку через prepend/communities вместо надежды на MED;
- раздельные политики на разные префиксы (часть — приоритетно через A, часть — через B).
Если FRR у вас живёт на том же сервере, что и сервисы, заранее подумайте про изоляцию и hardening systemd-юнитов; для общего подхода пригодится материал про усиление sandboxing в systemd.
Если захотите продолжение — можно разобрать аналогичный шаблон для IPv6 и RPKI в FRR, а также практику эксплуатации full table без сюрпризов по памяти.


