Нещодавно у зв'язку з переходом з 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 запускається щохвилини.
Висновки
Отримане рішення при мінімумі витрат суттєво підвищило надійність моєї домашньої мережі та успішно справляється з найвитонченішими збоями місцевих провайдерів, при цьому воно достатньо захищене від збоїв зовнішніх вузлів мережі.
Авторизуйтеся, щоб додати відгук