Резервирование канала на Mikrotik с 3G модемом

Дано
1. Mikrotik 951Ui-2nD
2. RouterOS 6.40.3
3. 3G модем Huawei E3372
4. Основной канал, настройки по DHCP

Производит переключение на резервный канал путём смены Destation у роута по умолчанию, перед переключением производится сброс модема для устранения “подвисания” (зависит от модема, сброс может производиться как переподключением PPTP инерфейса так и сбросом питания по USB порту - параметр reconnectMobMethod в скрипте).

Работа скрипта
Скрипт проверяет доступность двух адресов путём “пинга” указанных адресов, один из адресов задаётся автоматически и является адресов шлюза основно канал, второй адрес задаётся вами в самом скрипте, в параметре extPingAddr (при проверке добавляется роут на этот адрес через основной канал).
В случае недостуаности хоть одного из адресов или большие потери пакетов (процент задаётся в параметре pingStatusOK), производится переключение на резервный канал.
Переодически производится проверка доступности основного канала, интервал задаётся в Schedulder (/system scheduler), в случае восстановления связи, прозводится обратное переключение на основной канал.

Недостатки
В лог постоянно сыпится запись об удалении/добавлении роута до второго адреса проверки доступности канала.

Скрипт

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Скрипт резервирования канала на 3G модем
# При DHCP WAN
# 09.09.2017 Samolyk Alexey [root[dog]sysalex.com]

# -- Настройки --
# Имя WAN интерфейса (основной канал)
:local wanIfaceName "ether1";
# Имя WAN интерфейса (модем)
:local mobIfaceName "pptp-out1";
# Адрес которые будем "пиговать для проверки наличия основного канала"
:local extPingAddr    "8.8.8.8";

# Метод реконекта модема
# 0 - сброс питания по USB
# 1 - Отключение/включение интерфейса
:local reconnectMobMethod 1;

# Процент допустимых потерь на основном интерфейсе
# при значении не неже, будет производиться переключение
# на основной канал
:local pingStatusOK 70;


# -- Функции --
# Определение шлюза на основном интерфейсе
:local getGeteway do={
    :return [/ip dhcp-client get [ /ip dhcp-client find status=bound interface=$wanIfaceName ] gateway];
}
# Очистка ARP таблицы (далеко не всегда нужно но лишним не будет)
:local clearARP do={
    :local dumplist [/ip arp find]
    :foreach i in=$dumplist do={
        /ip arp remove $i
    }
}

# Переподключение мобильного соединения
# Иногда сессия виснет если нет трафика
:local reconnectMobConnection do={
    :if ($method = 0) do={
        # Сбрасываем питание USB порта
        :log warning ("Reset mobile modem (USB power)")
        /system routerboard usb power-reset;
        # 10 секунд не инициализацию модема
        :delay 10s;
    } else={
        # Перезапускаем PPtP интерфейс
        :log warning ("Reconect mobile interface before using");
        /interface ppp-client set $mobIface disable=yes;
        :delay 1s;
        /interface ppp-client set $mobIface disable=no;
    }
}

# Проверка и при отсуствии создание маршрутов по умолчанию
# для основного и мобильного соединения.
:local checkRoutes do={
    # Проверяем наличие роута на основной канал
    :if ([/ip route find dst-address="0.0.0.0/0" gateway=$currentWanGateway] = "") do={
        /ip route add gateway=$currentWanGateway distance=1 disabled=no
        :log warning ("Default route to WAN interface create");
    }
    # Проверяем наличие роута на резервный канал
    :if ([/ip route find dst-address="0.0.0.0/0" gateway=$currentMobGateway] = "") do={
        /ip route add gateway=$currentMobGateway distance=2 disabled=no
        :log warning ("Default route to Modem interface create");
    }
}

# Пинг адресов для проверки доступности подключения на основном канале
:local pingStatus do={
        # Добавляем роут через шлюз
        /ip route add dst-address=$pingAddr1 gateway=$currentGateway;
        # пингуем
        :local status ((( [/ping $pingAddr0 interface=$wanIface count=4] + \
        [/ping $pingAddr1 interface=$wanIface count=4] ) / 8) * 100);
        # Удаляем роут
        /ip route remove [find dst-address=$pingAddr1."/32"];
        :return $status;
}


# Поехали :)
# Получаем текущий шлюз на основном канале
:local curGateway [$getGeteway wanIfaceName=$wanIfaceName];
# Ищем интерфейсы, пригодяться для операций с ними
:local mainIface [/ip route find dst-address="0.0.0.0/0" gateway=$curGateway];
:local mobIface  [/ip route find dst-address="0.0.0.0/0" gateway=$mobIfaceName];

# Проверяем наличие основных маршрутов и если отсуствуют то добавляем
$checkRoutes currentWanGateway=$curGateway currentMobGateway=$mobIfaceName;

# На всякий случай проверяем правильность выставленный "distance"
# у марштутов. Конечно маловероятно что с ними что-то не то но вдруг руками поменяли.
:if ( [/ip route get $mainIface distance] != 2 ) do={
    /ip route set $mainIface distance=2;
}
:if ( [/ip route get $mobIface distance] != 1 && [/ip route get $mobIface distance] != 3) do={
    /ip route set $mobIface distance=3;
}

# Выясняем статус основного канала
:local wanChanelStatus [$pingStatus pingAddr0=$curGateway pingAddr1=$extPingAddr wanIface=$wanIfaceName currentGateway=$curGateway];

:if ($wanChanelStatus < $pingStatusOK) do={

        # Если нет коннекта на основном канале то переключаемся на резервный
        # путём смены "distance" на 1 - у резервного роута
        :if ( [/ip route get $mobIface distance] != 1 ) do={
              $reconnectMobConnection mobIface=$mobIfaceName;
            /ip route set $mobIface distance=1;
            :log warning ("Reconnect to reserve chanel");
            $clearArp;
        }

    } else={
        # Если коннект на основном канале появился, то переключаемся на основной
        # путём смены "distance" на 3 - у резервного роута
        :if ( [/ip route get $mobIface distance] != 3 ) do={
            /ip route set $mobIface distance=3;
            :log warning ("Reconnect to Main chanel");
            $clearArp;
        }
    }

Установка

1
2
3
4
/system scheduler
add interval=30s name=rezerv_check on-event=NAME_SCRIPT policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup

NAME_SCRIPT - заменить на имя которое указали при добавлении скрипта.

P.S. Никоим случаем не претендую на оригинальность и полное авторство на скрипт, использовались разные источники.

Комментарии