Нещодавно у зв'язку з переходом з ADSL на Ethernet представилася чудова можливість спробувати обладнання від Mikrotik. У зв'язку з чим був куплений роутер RB750GL . Залізниця виявилася чудовою як зовні, так і з погляду функціоналу та надійності.
У результаті я залишив обидва канали і вирішив налаштувати резервування з автоматичним перемиканням. Стандартні засоби перемикання шлюзів не покривають все різноманіття збоїв, тому потрібно писати свої скрипти.
Конфігурація мережі
1. Канал Ehernet від NLink встромляється в перший порт роутера, отримує IP DHCP і піднімає pptp з'єднання, назване nlink. Це буде основне з'єднання.
2. Канал ADSL від провайдера Домолінк проходить через DLink-2500 в режимі моста і встромляється в другий порт роутера, поверх піднімається pppoe з'єднання, назване domolink. Це буде резервне з'єднання.
3. Порти 3-5 роутера використовуються для підключення пристроїв локальної мережі.
Налаштування роутера
Налаштування підключень і маскарадингу для комп'ютерів локальна мережа є тривіальною і детально описана в офіційній вікі .
При налаштуванні ppp підключень потрібно відключити додавання маршрутів за замовчуванням, а потім створити статичні маршрути різними метриками та відповідними коментарями:
/ip route
add comment=MainGW disabled=no distance=1 dst-address=0.0.0.0/0 gateway=nlink scope=30 target-scope=10
add comment=RsrvGW disabled=no distance=2 dst-address=0.0.0.0/0 gateway=domolink scope=30 target-scope=10
Тепер щоб перемикати канали, достатньо змінювати параметр distance. Трафік піде через канал із меншим значенням цього параметра.
Скрипти
Встановлення глобальних параметрів під час запуску роутера
Скрипт називається set_global_parameters
#Main interface name
:global MainIf nlink
#Reserve interface name
:global RsrvIf domolink
#Main interface ip address
:global MainIfAddress ""
#Reserve interface ip address
:global RsrvIfAddress ""
Визначення IP-адрес інтерфейсів
Визначення IP-адреси основного інтерфейсу
Скрипт називається define_main_if_ip
:global MainIf
:global MainIfAddress ""
:set MainIfAddress [/ip address get [find interface=$MainIf] address]
Цей скрипт визначає IP-адресу основного інтерфейсу для доступу до Інтернету. Якщо цей інтерфейс відсутній, то скрипт завершуватиметься з помилкою, а в змінній MainIfAddress буде порожній рядок.
Визначення IP-адреси резервного інтерфейсу
Скрипт називається define_reserved_if_ip
:global RsrvIf
:global RsrvIfAddress ""
:set RsrvIfAddress [/ip address get [find interface=$RsrvIf] address]
Визначення цих адрес винесено на окремі скрипти, т.к. ці значення я використовую ще в ряді скриптів на роутері (наприклад, оновлення записів у DynDNS), а функції користувача тут створювати не можна. Слід зазначити, що команди визначення адрес не можна використовувати інших скриптах, т.к. у разі проблем з інтерфейсом вони генерують помилку та призводять до завершення скрипту.
Перемикання каналів
Скрипт називається connection_check
:global MainIf
:global RsrvIf
:global MainIfAddress
:global RsrvIfAddress
:local PingCount 3
#www.ru
:local PingTarget1 194.87.0.50
#ya.ru
:local PingTarget2 87.250.250.203
#google dns
:local PingTarget3 8.8.8.8
#Check main internet connection
:local MainIfInetOk false;
if ($MainIfAddress="") do={delay 5}
if ($MainIfAddress!="") do={
:local PingResult1 [/ping $PingTarget1 count=$PingCount interface=$MainIf]
:local PingResult2 [/ping $PingTarget2 count=$PingCount interface=$MainIf]
:local PingResult3 [/ping $PingTarget3 count=$PingCount interface=$MainIf]
:set MainIfInetOk (($PingResult1 + $PingResult2 + $PingResult3) >= (2 * $PingCount))
}
#Check reserved internet connection
:local RsrvIfInetOk false;
if ($RsrvIfAddress="") do={delay 5}
if ($RsrvIfAddress!="") do={
:local PingResult1 [/ping $PingTarget1 count=$PingCount interface=$RsrvIf]
:local PingResult2 [/ping $PingTarget2 count=$PingCount interface=$RsrvIf]
:local PingResult3 [/ping $PingTarget3 count=$PingCount interface=$RsrvIf]
:set RsrvIfInetOk (($PingResult1 + $PingResult2 + $PingResult3) >= (2 * $PingCount))
}
:put "MainIfInetOk=$MainIfInetOk"
:put "RsrvIfInetOk=$RsrvIfInetOk"
if (!$MainIfInetOk) do={
/log error "Main internet connection error"
}
if (!$RsrvIfInetOk) do={
/log error "Reserve internet connection error"
}
:local MainGWDistance [/ip route get [find comment="MainGW"] distance]
:local RsrvGWDistance [/ip route get [find comment="RsrvGW"] distance]
:put "MainGWDistance=$MainGWDistance"
:put "RsrvGWDistance=$RsrvGWDistance"
#SetUp gateways
if ($MainIfInetOk && ($MainGWDistance >= $RsrvGWDistance)) do={
/ip route set [find comment="MainGW"] distance=1
/ip route set [find comment="RsrvGW"] distance=2
/log info "Switch to main internet connection"
}
if (!$MainIfInetOk && $RsrvIfInetOk && ($MainGWDistance <= $RsrvGWDistance)) do={
/ip route set [find comment="MainGW"] distance=2
/ip route set [find comment="RsrvGW"] distance=1
/log warning "Switch to reserve internet connection"
}
Зверніть увагу на пінг через конкретний інтерфейс, а також на критерій визнання каналу несправним. Я пінгую три різних вузла і вважаю, що інтернет на даному інтерфейсі не працює, якщо приходить менше 2/3 відповідей.
Планувальник
1. Скрипт set_global_parameters запускається один раз під час запуску роутера.
2. Скрипти визначення IP-адрес запускаються кожні 27 секунд. Таке значення вибрано, щоб мінімізувати кількість одночасних запусків із основним скриптом.
3. Скрипт connection_check запускається щохвилини.
Висновки
Отримане рішення при мінімумі витрат суттєво підвищило надійність моєї домашньої мережі та успішно справляється з найвитонченішими збоями місцевих провайдерів, при цьому воно достатньо захищене від збоїв зовнішніх вузлів мережі.
Furukawa
Grandway
V-Solution
Ubiquiti Networks
D-Link
Mikrotik
TP-Link
Edge-core
BDCOM
Jirous
Ok-net
Cambium Networks
Tenda
ZTE
Huawei
Ripley
Fujikura
DVP
Jilong
Одескабель
Netis
FiberField
Totolink
Grandstream
Yokogawa
Mimosa
OpenVox
Hikvision
Keenetic
Ютекс
Signal Fire
Utepo
Dahua
ONV
Prolum
ATcom
Ritar
Zyxel
Ruijie
APC
Fibaro
Merlion
Mercusys
MULTITEST
Reolink
ЗЗКМ
GEAR
ATIS
CSV
Full Energy
Авторизуйтеся, щоб додати відгук