О, сколько боли в слове MultiWAN! Стоит погуглить что-нибудь типа “есть два провайдера, как сделать так, чтобы можно было пользоваться одновременно или использовать второй как бекапный”, так сразу высыпается куча советов про метрики, маркировку трафика с помощью iptables и так далее. Правда, в последнее время все поутихло, но это потому, что в большинстве прошивок для домашних роутеров наконец-то доделали этот функционал.
Но я-то другой! У меня закидоныпросы! Вот прямо сейчас мне надо разрулить аж трех “провайдеров” на одной точке. Плюс пустить один из адресов через одного провайдера… В общем, попробовал я сначала натыкать галочек в любимом кинетике, потом сдался в сторону {pf|opn}sense, но и так не преуспел… Нет, наверняка можно было допинать, но я устал и сдался.
Итак, первоначальные условия. Есть три провайдера: через сотовую связь, ADSL и GPON. Работают одновременно. Рядом стоит сервер, который легко потянет кучу виртуалок. Необходимо клиентов (то есть меня) пускать в интернет, при этом приоритет gpon, adsl, сотик. Но один из служебных маршрутов должен уходить через ADSL. Вроде бы просто, да?
Для начала я вообще решил проверить, а возможно ли это без боли. Для этого я сделал стенд из трех виртуалок. Две я обозвал router1 и router2, а клиента – естественно client.
internet - (ens18)router1(ens19) - 10.0.0.1 - network
internet - (ens18)router2(ens19) - 10.0.0.2 - network
client (ens19) - 10.0.0.3 - network
Я опускаю настройку роутеров и клиента. Все друг друга видят, на роутерах включен форвард пакетов и SNAT, в общем, все работает на ручном приводе хорошо. Теперь необходима автоматика.
Ставлю на каждый хост FRR. Редактирую /etc/frr/daemons
на предмет включения ospfd и запускаю. Далее скармливаю на всех хостах одну и ту же конструкцию, только меняю router id
!
interface ens18
ip ospf passive
exit
!
interface ens19
ip ospf dead-interval 30
exit
!
router ospf
ospf router-id 10.0.0.1
network 10.0.0.0/24 area 0.0.0.0
exit
!
Никакой авторизации и прочих заморочек. Поднимаю OSPF, запрещаю ему спамить в сторону провайдера и говорю, что все в сети 10/24 – наше. Проверяю, что роутеры видят друг друга.
client# show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface RXmtL RqstL DBsmL
10.0.0.1 1 Full/DR 27.376s 10.0.0.1 ens19:10.0.0.3 0 0 0
10.0.0.2 1 Full/Backup 28.362s 10.0.0.2 ens19:10.0.0.3 0 0 0
В принципе, теперь можно расставлять роуты куда надо и радоваться жизни. Но мне-то надо рулить default роутом. И тут засада: по-умолчанию, чтобы не расхреначить все, роутеры по умолчанию дропают роуты на 0.0.0.0/0. Можно, конечно, воспользоваться хаком имени OpenVPN и анонсировать роуты 0.0.0.0/1 и 128.0.0.0/1, но это не наш метод. Немного погуглив, выянил, что достаточно добавить default-information originate always
в секцию router ospf
и все получится. Дескать, я edge/border/ваще_крутой роутер и ходи через меня.
client# show ip ospf route
============ OSPF network routing table ============
N 10.0.0.0/24 [1] area: 0.0.0.0
directly attached to ens19
============ OSPF router routing table =============
R 10.0.0.1 [1] area: 0.0.0.0, ASBR
via 10.0.0.1, ens19
============ OSPF external routing table ===========
N E2 0.0.0.0/0 [1/1] tag: 0
via 10.0.0.1, ens19
И действительно, стоило мне такое сказать, как client тут же все увидел и обновил. Добавляю ту же строку в конфиг второго. Вуаля!
root@client:~# ip r
default nhid 22 proto ospf metric 20
nexthop via 10.0.0.1 dev ens19 weight 1
nexthop via 10.0.0.2 dev ens19 weight 1
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
Клиент прописал себе оба роута и казалось бы наступила красота. И даже все заработало, как положено: если один из роутеров исчезал или я дропал на нем интерфейс, то соответствующий роут исчезал тоже. И тут я познал боль (правда, небольшую, на уровне фейспалма)
В чем боль? А боль возникла из-за того, что для клиента оба роутера видны через один интерфейс. И он совершенно справедливо полагает, что между ними нет разницы. А если нет разницы, то роутим туда, куда получится.
Ладно, моя ошибка. Добавляю еще одну сеть, сажу туда router3 и один из интерфейсов клиента. В остальном повторяю все выше. Проверяю, что все завелось.
client# show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface RXmtL RqstL DBsmL
10.0.0.1 1 Full/DR 24.884s 10.0.0.1 ens19:10.0.0.3 0 0 0
10.0.0.2 1 Full/Backup 25.013s 10.0.0.2 ens19:10.0.0.3 0 0 0
10.1.0.4 1 Full/Backup 22.051s 10.1.0.4 ens20:10.1.0.3 0 0 0
client#
client# show ip ospf border-routers
============ OSPF router routing table =============
R 10.0.0.1 [1] area: 0.0.0.0, ASBR
via 10.0.0.1, ens19
R 10.0.0.2 [1] area: 0.0.0.0, ASBR
via 10.0.0.2, ens19
R 10.1.0.4 [1] area: 0.0.0.0, ASBR
via 10.1.0.4, ens20
root@client:~# ip r
default nhid 79 proto ospf metric 20
nexthop via 10.0.0.1 dev ens19 weight 1
nexthop via 10.0.0.2 dev ens19 weight 1
nexthop via 10.1.0.4 dev ens20 weight 1
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
10.1.0.0/24 dev ens20 proto kernel scope link src 10.1.0.3
Как видно, теперь у меня аж три некстхопа. Ходи – не хочу.
Проверяю, как OSPF на client видит интерфейсы
client# show ip ospf interface
ens19 is up
ifindex 3, MTU 1500 bytes, BW 4294967295 Mbit <UP,BROADCAST,RUNNING,MULTICAST>
Internet Address 10.0.0.3/24, Broadcast 10.0.0.255, Area 0.0.0.0
MTU mismatch detection: enabled
Router ID 10.0.0.3, Network Type BROADCAST, Cost: 1
Transmit Delay is 1 sec, State DROther, Priority 1
Designated Router (ID) 10.0.0.1 Interface Address 10.0.0.1/24
Backup Designated Router (ID) 10.0.0.2, Interface Address 10.0.0.2
Saved Network-LSA sequence number 0x80000004
Multicast group memberships: OSPFAllRouters
Timer intervals configured, Hello 10s, Dead 30s, Wait 30s, Retransmit 5
Hello due in 6.368s
Neighbor Count is 2, Adjacent neighbor count is 2
ens20 is up
ifindex 4, MTU 1500 bytes, BW 4294967295 Mbit <UP,BROADCAST,RUNNING,MULTICAST>
Internet Address 10.1.0.3/24, Broadcast 10.1.0.255, Area 0.0.0.0
MTU mismatch detection: enabled
Router ID 10.0.0.3, Network Type BROADCAST, Cost: 1
Transmit Delay is 1 sec, State DR, Priority 1
Designated Router (ID) 10.0.0.3 Interface Address 10.1.0.3/24
Backup Designated Router (ID) 10.1.0.4, Interface Address 10.1.0.4
Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
Timer intervals configured, Hello 10s, Dead 30s, Wait 30s, Retransmit 5
Hello due in 0.712s
Neighbor Count is 1, Adjacent neighbor count is 1
Все правильно, по умолчанию для ethernet cost 1.
Добавляю на клиенте на интерфейс ens19, который смотрит на первые два роутера, опцию ip ospf cost 100
. Согласно мануалам, это должно сказать, что туда надо трафик отправлять в последнюю очередь (ведь 100>1)
Проверяю. Вот это было до.
root@client:~# ip r
default nhid 87 proto ospf metric 20
nexthop via 10.0.0.1 dev ens19 weight 1
nexthop via 10.0.0.2 dev ens19 weight 1
nexthop via 10.1.0.4 dev ens20 weight 1
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
10.1.0.0/24 dev ens20 proto kernel scope link src 10.1.0.3
Включаю ip ospf cost
root@client:~# ip r
default nhid 91 via 10.1.0.4 dev ens20 proto ospf metric 20
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
10.1.0.0/24 dev ens20 proto kernel scope link src 10.1.0.3
Проверяю, что вообще-то роуты вернутся, если что-то случится с router3
root@client:~# ip link set ens20 down
root@client:~# ip r
default nhid 95 proto ospf metric 20
nexthop via 10.0.0.1 dev ens19 weight 1
nexthop via 10.0.0.2 dev ens19 weight 1
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
Работает, прямо как я и задумал. Теперь садим на каждый роутер по скрипту, который будет проверять доступность интернета. Таких скриптов уйма на любой вкус, цвет и запах. Можно вообще какой-нибудь zabbix присобачить. Но главное, чтобы они шли и пускали два скриптика
root@router3:~# cat enable.sh
#!/bin/bash
cat << EOF | /usr/bin/vtysh
conf t
router ospf
default-information originate always
exit
exit
exit
EOF
root@router3:~# cat disable.sh
#!/bin/bash
cat << EOF | /usr/bin/vtysh
conf t
router ospf
no default-information originate always
exit
exit
exit
EOF
Их названия говорят сами за себя, как и то, что они делают. Позапускал их, проверил, что таблица роутинга перестраивается, как и положено, согласно правилам.
Теперь последнее: пустить определенный маршрут через определенный роутер. Пусть это будет 1.2.3.4/32 на router2. Это вообще просто. Просто создаем статический роут и просим распростанить статику.
root@router2:~# vtysh
Hello, this is FRRouting (version 8.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
router2# conf t
router2(config)# ip route 1.2.3.4/32 192.168.1.1
router2(config)# router ospf
router2(config-router)# redistribute static
И все получается согласно заветам лучших сетевиков.
root@client:~# ip r
default nhid 113 via 10.1.0.4 dev ens20 proto ospf metric 20
1.2.3.4 nhid 115 via 10.0.0.2 dev ens19 proto ospf metric 20
10.0.0.0/24 dev ens19 proto kernel scope link src 10.0.0.3
10.1.0.0/24 dev ens20 proto kernel scope link src 10.1.0.3
Теперь осталось развести router1 и router2 по разным подсетям, донастроить точно так же, как и router3, забекапить все и забыть до появления новых вводных.
А, да. Ну и всех жаждущих интернета отправить на client. Теперь точно все.