Жили-были несколько серверов, в разных локациях. Сколько именно - это непринципиально, поэтому упростим, пусть будет два: A и B.
Каждый занимался своими задачами, а между собой они были соединены виртуальной приватной сетью (ну, то, что теперь нельзя называть).
Причем сеть эта использовалась по своему прямому назначению - просто обеспечить передачу локального трафика через публичные сети, дабы посторонние не совали в него свой любопытный клюв.
Однако, с некоторых пор начались проблемы: одна известная организация начала ломать рунет, блокируя соединения то там, то тут.
Сначала заблокировали один протокол - пришлось переходить на другой. Потом заблокировали другой - пришлось переходить на третий.
Третий периодически рвался, потому что начали портить уже соединения между сетями: через одного провайдера канал есть, через другого нет, потом меняются.
Как вы понимаете, нормальной работе это отнюдь не способствовало, пришлось искать какое-то решение. А ведь оно давно известно - динамическая маршрутизация!
Просто до поры она, казалось бы, совсем тут не нужна - не те масштабы, да и работало всё прекрасно...
Смысл простой: если основной канал внезапно падает - используем резервный.
Портится резервный -- меняем провайдера или ищем обходные маршруты.
Но для этого надо оперативно перенастраивать маршруты на роутерах, причем на всех сторонах всех участников процесса.
Каналы связи в данном случае - различные виды того-что-нельзя-называть в различных сочетаниях.
Тут вполне подходит протокол OSPF: он как раз и предназначен для решения подобных задач.
Не буду пытаться обьяснять тонкости работы лучше, чем это делают профессионалы-сетевики, просто остановлюсь на некоторых практических нюансах реализации.
А роутеры будут программные - для этого можно использовать пакет FRR.
Он стандартно присутствует в репозитарии Debian (apt search frr), но как показалось - лучше сделать немного по-другому: запустить его через docker - тогда на всех узлах он будет одной версии, и не будет ни с чем конфликтовать.
Есть даже готовый образ - но, по обычаю, можно сделать и самостоятельно:
mkdir -p /etc/frr
docker run -ti --name frr -v /etc/frr:/etc/frr --privileged --network host debian:latest
Это запускает контейнер с правами, близкими к хост-системе - но при этом сохраняется некоторая изоляция от системных библиотек и установленных версий ОС.
Попадаем внутрь контейнера - устанавливаем:
apt update
apt upgrade
apt install frr
exit
Теперь в контейнере живет frr, а его настроечные файлы - в /etc/frr host-системы.
То есть, их можно редактировать вручную в привычном редакторе.
vim /etc/frr/daemons
ospfd=yes
Теперь немного сетевых настроек.
Разрешаем форвардинг, если еще не:
sysctl net.ipv4.ip_forward=1
Назначаем фиксированные, независимые от интерфейсов адреса для серверов, присваивая их локальному интерфейсу, ну например, адрес сервера A - 192.168.10.1
Таким образом, их наличие никак не будет связано с работоспособностью тех или иных сетевых интерфейсов:
ip addr add 192.168.10.1/32 dev lo
Разбираемся с каналами: это у нас различные типы того-что-нельзя-называть, причем нам от них по сути нужна связь "точка-точка": соединяются сервера A, B, а также несколько дополнительных, размещенных в других локациях - для организации подобия mesh-сети.
По сути для каждого из них нужны всего 2 адреса + широковещательный и адрес подсети, итого 4.
Для этого можно выделить специальную отдельную подсеть, например, 192.168.5.0, и нарезать ее на подсети /30.
Кто забыл: маска подсети - количество неизменяемых битов подсети, т.е. /24 - первые три октета фиксированы(192.168.5.), и еще 6 бит - тоже.
В двоичном виде последний октет будет выглядеть так:
(0000 00)00 - в скобках фиксированная часть подсети, без скобок - 00, 01, 10, 11 - адреса сети, узлов и широковещательный соответственно.
А номера сетей меняются от 0000 00 до 1111 11.
Поскольку всё это принято записывать в десятичном виде - можно для удобства использовать встроенную в шелл возможность расчёта:
echo $(( 2#00000001 )) # 1 - 1 адрес сети 0
echo $(( 2#00000010 )) # 2 - 2 адрес сети 0
echo $(( 2#00000101 )) # 5 - 1 адрес сети 1
echo $(( 2#00000110 )) # 6 - 2 адрес сети 1
echo $(( 2#00001001 )) # 9 - 1 адрес сети 2
echo $(( 2#00001010 )) # 10 - 2 адрес сети 2
Ну и так далее. Несложно.
К примеру, связываем сервера A и B двумя прямыми каналами:
192.168.5.1/30 - 192.168.5.2/30 # то-что-нельзя-называть тип 1
192.168.5.5/30 - 192.168.5.6/30 # то-что-нельзя-называть тип 2
Ну и так далее. Еще раз отмечу, что это чисто "связные подсети", на них не будет работающих сервисов.
Сервисы у нас на 192.168.10.1 и подобных.
Теперь запускаем frr:
docker start frr
docker exec -ti frr /usr/lib/frr/frrinit.sh start
У frr есть Cisco-подобный интерфейс, через который можно делать настройки и смотреть состояние:
(TAB помогает)
docker exec -ti frr vtysh
configure terminal
router ospf
ospf router-id 1.1.1.1
maximum-paths 1
network 192.168.10.1/32 area 0
network 192.168.5.0/24 area 0
exit
exit
write memory
exit
И смотрим, что получилось:
vim /etc/frr/frr.conf
frr version 10.3
frr defaults traditional
hostname alice
log syslog informational
service integrated-vtysh-config
!
router ospf
ospf router-id 1.1.1.1
maximum-paths 1
network 192.168.10.1/32 area 0
network 192.168.5.0/24 area 0
exit
!
Синтаксис простой, блоки выделяются отступом, символ ! или # - комментарий, в данном случае они вообще не обязательны и служат просто для визуальной отметки конца блока.
(тут, к слову, та самая ситуация, когда один лишний пробел может поломать всё)
Если что-то поменять - потом достаточно перезапустить frr:
docker exec -ti frr /usr/lib/frr/frrinit.sh restart
Ну или воспользоваться vtysh для правки, кому что привычнее.
Что сейчас настроено:
- роутер OSPF с ID 1.1.1.1 (похоже на IP, но на самом деле просто номер, номера должны быть разными)
- анонсируется маршрут к сети 192.168.10.1/32, состоящей из единственного адреса.
- анонсируются маршруты всех сетей, попадающих в маску 192.168.5.0/24, то есть всех "связных".
- ограничено количество одновременно работающих путей - чтобы не нарушалась работа TCP-соединений.
По интерфейсам, подпадающим под маску, будут рассылаться сообщения Hello от OSPF - предполагается, что с другой стороны их будут слушать другие OSPF-роутеры.
По такой же схеме настраиваем FRR на других машинах.
Если там нет своих "сервисных адресов" - достаточно указать только одну сеть, через которую идёт связь, в данном случае 192.168.5.0/24
И в общем-то это всё.
Перезапускаются frr, они обмениваются между собой данными о доступных маршрутах - и теперь на любой машине можно обратиться к 192.168.10.1 - запрос уйдет именно на сервер A, по кратчайшему маршруту, в зависимости от того какие каналы где сейчас работают.
Проверить работу можно так:
docker exec -ti frr vtysh
show running-config
show ip ospf neighbor
show ip ospf route
...
А вот теперь нюансы:
Протокол OSPF - это не TCP и не UDP, это отдельный протокол 89.
Поэтому некоторые, эээ, каналы, его не пропускают.
Решить эту проблему можно примерно следующим образом: сначала поднять просто TCP/IP канал, потом поверх него VXLAN (L2, "езернет", инкапсулированный в UDP), потом поверх него "связную сеть", и вот уже тогда пускать OSPF.
Слоёный пирог, но работает. Альтернатива - использовать BGP, но там настройка несколько сложнее.
Address = 192.168.3.1/30
Table = off
PostUp = ip link add vxlwgA type vxlan id 12 dev %i remote 192.168.3.2 dstport 4789
PostUp = ip link set dev vxlwgA up
PostUp = ip addr add 192.168.5.9/30 dev vxlwgA
В данном случае сначала устанавливается "транспортная подсеть" 192.168.3.0/30, поверх нее "связная подсеть" 192.168.5.4/30, и вот уже по ней и будет работать OSPF.
А 192.168.3.0 в маршруты не попадёт (хотя можно и ее добавить, еще одной network).
Заметим, что статические маршруты тут не нужны, и даже вредны - оно само всё разрулит лучше.
Теперь включаем ping, и начинаем портить:
отключаем один прямой канал - маршрут перестаивается через другой.
отключаем второй - маршрут перестраивается в обход, через другой интерфейс.
отключаем и там - маршрут пошел через третий сервер
Для приложений, работающих с 192.168.10.1, будут лишь кратковременные потери пакетов, может вырасти время пинга, особенно если меняется вообще способ подключения - но в целом всё работает, хоть и идет неведомыми путями.
А значит, цель достигнута.
aborouhin
Иногда одна известная организация ломает инет так, что связность вроде бы и есть, но по факту пользоваться невозможно, потери пакетов >30% и latency плавает вплоть до нескольких секунд. И вот тут к OSPF (который у меня уже настроен ровно для той же задачи, что Вы решаете, только что bird, а не frr) неплохо бы добавить BFD. Никак руки не дойдут, так что изредка такие "зомби-каналы" приходится руками отключать, чтобы OSPF их мёртвыми признал.
JBFW Автор
Совершенно верно
И bfd там тоже есть, кстати, надо его с ospf подружить...