Пользователь
0,0
рейтинг
12 ноября 2014 в 22:31

Администрирование → Mikrotik автоматическое переключение на резервный канал для динамического ip адреса (выдаваемого по DHCP) из песочницы



Приветствую, Хабр! В связи с плохим качеством линии меня попросили настроить автоматическое переключение на резервный канал. Для этой цели предоставили роутер MikroTik RB 951Ui.

Думал, что проблем не возникнет… Всего-то настроить проверку канала и маршруты. Но, к сожалению, оба провайдера выдают IP динамически. Сначала я попробовал подставить в маршрут название интерфейса, но пинг не проходил. Прочитав несколько статей, включая зарубежные сайты, но не нашел решения проблемы, которое мне подошло бы. Пришлось знакомится с RouterOS по ближе, а в частности с созданием скриптов…


В этой ОС можно создавать маршрут двумя способами:
  • вручную (через графический интерфейс или через терминал);
  • автоматически DHCP-клиентом.

При создании маршрута вручную не получится обновлять шлюз динамически. Для этого придется писать несколько достаточно больших скриптов и добавлять множество проверок. При их написании заметил, что в RouterОS проблематично заставить работать сложные скрипты. Очень тяжело отследить логику работы, хотя использовались логи и переменные для проверки. Скрипты были написаны, но работали нестабильно, несмотря на оптимизацию кода и добавления проверок. Когда количество проверок начало расти в геометрической прогрессии и многократная оптимизация логической схемы ненамного улучшила ситуацию — я решил отказаться от этого варианта и попробовать использовать в скрипте опцию автоматического создания маршрута DHCP- клиентом.

/ip dhcp-client set [/ip dhcp-client find interface=$Iface] add-default-route=yes [no]

Для нужного интерфейса в настройках DHCP-клиента устанавливается опция автоматического создания маршрута по умолчанию.

Итак, скрипт будет работать по такому алгоритму:



Объяснение алгоритма



Для каждого интерфейса будет запущена копия скрипта. Каждая копия будет автономно создавать маршрут по умолчанию. Приоритет маршрута будет зависеть от distance. То есть, когда «упадет» соединение на маршруте с Distance 10 произойдет переключение на 11. Благодаря этому переключение получается бесшовным.

Для начала скрипт пингует выбранный хост в интернете по маршруту по умолчанию. Если пинг меньше чем ($PingCount-$Margin) (Margin — задается погрешность для контроля точности), тогда пингуем по тестовому маршруту для проверки «живое» ли соединение. В случае негативного результата проверяем маршрут и наличие проблем с настройками:

  • перегружаем интерфейс каждые $TimeToWait раз (снижаем нагрузку на процессор);
  • ждем загрузки интерфейса;
  • проверяем есть ли настройки DHCP — клиента для данного интерфейса, в противном случае создаем;
  • проверяем статус DHCP клиента (иногда RouterOS может «подсунуть свинью»);
  • ждем получение DHCP lease;
  • добавляем к значению $CurrentGateway нужный интерфейс;
  • проверяем есть ли тестовый маршрут;
  • проверяем правильный ли в тестовом маршруте шлюз.


Скорость реакции на состояние соединения можно индивидуально подстраивать с помощью следующих переменных:

  • PingCount — количество посылаемых icmp запросов (также можно добавить еще одну переменную для определения количества посылаемых запросов по тестовому маршруту и на шлюз провайдера, то есть уменьшится количество запросов и соответственно увеличится скорость работы скрипта);
  • Margin — коэффициент нужен для задания погрешности. Например, при $Margin=1 цикл проверки маршрутов запускается только тогда, когда пропадет больше одного пакета, что немаловажно в моей ситуации;
  • TimeToWait при ожидании соединения интерфейс перегружается каждый $TimeToWait раз (это нужно для того, чтобы снять нагрузку на процессор)


Подготовительная настройка


Описывать стандартные настройки роутера я не буду по двум причинам: во-первых, эта тема не раз поднималась в интернете, в том числе на Хабре, во-вторых, сети отличаются своей конфигурацией. Так как работа скрипта затрагивает только маршруты по умолчанию и настройки DHCP клиента, думаю у вас не возникнет трудностей при адаптации скрипта под вашу сеть.

Для работы скрипта не нужно создавать маршруты по умолчанию — он создаст их автоматически. Единственное, нужно подобрать подходящий distance для тестовых маршрутов (можно оба с $Distance = 1) и $DistanceDefault 10 и 11 для маршрутов по умолчанию (по одному для каждого провайдера). Также не нужно создавать dhcp клиентов.

При настройке роутера я использовал SSH и Winbox (специализированная программа для настройки устройств управляемых RouterOS, работает даже в *nix с помощью Wine).

Приступим.

В Interfaces меняем названия двух интерфейсов, чтобы совпадали со значением переменной $Iface в скрипте (у меня isp1, isp2):



Меняем DNS адреса на google-кие:



Создаем скрипт: System → Scripts → Add и вставляем код указанный ниже:



Код скрипта
:delay 10s
:local Iface			"isp1"
:local StatusIface
:local CurrentGateway 
:local pingInet
:local pingLink
:local pingGateway
:local IPToPingInet		"213.180.193.3"
:local IPToPing			"8.8.4.4"
:local PingCount        5
:local Margin           1
:local Distance         1
:local DistanceDefault  10
:local RunTime          0
:local TimeToWait       20



#Первый цикл
while (true) do={
# пингуем общий интернет
	:set pingInet [/ping $IPToPingInet count=$PingCount interface=$Iface]
	:log debug "$pingInet $Iface $IPToPingInet"
	:if ($pingInet < ($PingCount-$Margin)) do={
	  :log error "No internet connection on $Iface."
	  /ip dhcp-client set [/ip dhcp-client find interface=$Iface] add-default-route=no 
		
# Второй цикл
	  :while ($pingInet < ($PingCount-$Margin)) do={
# пингуем интернет через тест
        :set pingLink [/ping $IPToPing count=$PingCount interface=$Iface]
		:log debug "$pingLink $Iface $IPToPing"
		:if ($pingLink < ($PingCount-$Margin)) do={
# Первая перезагрузка			
		  /interface ethernet disable $Iface; /interface ethernet enable $Iface
          :while ($pingLink < ($PingCount-$Margin)) do={
            :log debug "$pingLink $Iface $IPToPing"
			:set RunTime ($RunTime + 1)
			:log debug $RunTime
# Time to wait
			:if ( $RunTime =  $TimeToWait ) do={
# 			  Reboot interface 
			  :log info "reboot and release $Iface"
			  /interface ethernet disable $Iface; /interface ethernet enable $Iface
			  :set RunTime 0
			}
# 			Ждем загрузки интерфейса
			:if ([/interface ethernet get $Iface disabled] = false) do={
			    :log debug "Interface $Iface enabled"
#			  Проверяем линк 
			    /interface ethernet monitor $Iface once do={
			      :set StatusIface $status
			    }
			    :if ($StatusIface = "link-ok") do={
			      :log debug "$Iface link-ok." 
# 			  Проверяем dhcp
			      :if ([/ip dhcp-client find interface=$Iface] != "") do={
			        :log debug "test1"
# 					 Проверяем или нет ошибки DHCP
			        :if ( [/ip dhcp-client get [/ip dhcp-client find interface=$Iface] invalid ]  != true)  do={
				      :log debug "test2"
# 						Ждем получения DHCP lease
				      :set CurrentGateway [/ip dhcp-client get [/ip dhcp-client find interface=$Iface] gateway ]
					  :log debug "Waiting DHCP lease"
					  :if ($CurrentGateway != nil) do={
					    :set CurrentGateway [:put ("$CurrentGateway" . "%$Iface")]
					    :log debug "CurrentGateway $CurrentGateway"
#						  Looking for route test
					    :log debug "Cheking test route for $Iface..."
					    :local a [ /ip route find comment="$Iface" ]
					    :if (($a) = "") do={
					      :log info ("Adding test route for $Iface...")
					      /ip route add dst-address=$IPToPing gateway=$CurrentGateway comment="$Iface" distance=$Distance	
					    } else={
						:local EstablishedGateway [/ip route get [/ip route find comment="$Iface"] gateway ] 
   					    :log debug "EstablishedGateway $EstablishedGateway"
					      :if ( $CurrentGateway = $EstablishedGateway ) do={
						    :log debug "No route changes needed for $Iface." 
						  } else={
						      :log info "Updating test route for $Iface..."
						      /ip route set  [/ip route find comment="$Iface" ] dst-address=$IPToPing gateway=$CurrentGateway comment="$Iface" distance=$Distance
						    }
					    }
					    :set pingGateway [/ping [/ip dhcp-client get [/ip dhcp-client find interface=$Iface] gateway ] count=$PingCount interface=$Iface]
					    :log debug "$pingGateway $Iface $IPToPing"
					    :if ($pingGateway < ($PingCount-$Margin)) do={
					      :log error "route error on $Iface"
						  :log debug [/ip dhcp-client get [/ip dhcp-client find interface=$Iface] gateway ]
						  /ip dhcp-client release	[/ip dhcp-client find interface=$Iface]
					    }
					  } else={
					      :log error "DHCP no lease."
					      :delay 1s
					    }
					  } else={
						:log error "DHCP failure on $Iface."
						:log info "reboot and release $Iface"
						/interface ethernet disable $Iface; /interface ethernet enable $Iface
						:delay 1s
					  }
			      } else={ :log info "adding DHCP client for $Iface"
				    /ip dhcp-client add interface=$Iface disabled=no add-default-route=yes default-route-distance=$DistanceDefault use-peer-dns=no use-peer-ntp=no 
				  }
			    } else={
				  :log debug "No-link on $Iface."
				  :delay 1s
				}
			} else={
							:log error "Interface $Iface disabled."
					}
				:set pingLink [/ping $IPToPing count=$PingCount interface=$Iface]
				}
		} else={
				:log info "add default route= yes for $Iface"
				/ip dhcp-client set [/ip dhcp-client find interface=$Iface] add-default-route=yes	 
		  }
		  :set pingInet [/ping $IPToPingInet count=$PingCount interface=$Iface]
	  }
	} else={
		:log debug "Internet on $Iface connected."
	}
}



Повторяем предыдущий шаг для второго интерфейса, только заменяем значение переменной $Iface на «isp2», также меняем $DistanceDefault на вышеуказанные значения (у меня для isp1 — 10, а для isp2 — 11 ).



Теперь нужно настроить планировщик для автоматического запуска скриптов при загрузке роутера.
System → Scheduler->



Также это можно сделать с помощью ssh или же из консоли, если возникают проблемы с кириллицей в дате:

/system scheduler add name=CheckTestRoute1 start-time=startup on-event=CheckTestRoute1

Перегружаем…
Я думал, что возникнут проблемы с NAT при переключении маршрутов, но пока
полет нормальный. Если возникнут пишите…

Вот и все. Надеюсь, что эта статья окажется для кого-то полезной.

PS: Напоследок RouterOS подбросил еще одну задачку…



Как видите, несмотря на то, что маршрут указан верно — пинг не проходит.

Чтобы это исправить, добавил еще одну проверку (выше в коде скрипта она уже добавлена).
@Thund3rHabr
карма
3,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (20)

  • +2
    Можно сделать всё гораздо проще ))) В маршрутах можно указывать не IP-адрес, а интерфейс. Плюс — почему-бы не использовать параметр distance? Для примера два провайдера по PPPoE (с динамическими адресами как раз). Работает и гораздо короче конфигурация :)

    /interface pppoe-client
    add ac-name="" add-default-route=no allow=chap dial-on-demand=no disabled=no interface=ether9 name=PPPoEisp1 user=isp1 password=testPassword profile= default service-name="" 
    add ac-name="" add-default-route=no allow=chap dial-on-demand=no disabled=no interface=ether10 name=PPPoEisp2 user=isp2 password=testPassword profile= default service-name="" 
    
    /ip route
    add distance=1 gateway=PPPoEisp1
    add distance=2 gateway=PPPoEisp2


    PS: Вообще у использования скриптов есть свои минусы — пару раз встречался с умершими микротиками из-за них. Проблема в том, что внутренняя флеш-память с ограниченным числом циклов записи, соответственно при каждом изменении конфигурации скриптом идёт запись на неё и если каналы очень нестабильны и постоянно идёт переключение, то через 2-3 года флешка умирает (а с ней и микротик)
    • 0
      Мне кажется за 2-3 года флешка не ушатается. Может быть вам попались экземпляры неудачные, есть у меня один который из коробки показывает 0.1% битых блоков
      • 0
        Там был момент, что связь была не самая стабильная :) ADSL от Ростелекома как основной + МТСовский свисток — переключалось раз по 100 в день :) Но так как не люди сидели, а мониторинг, который мог и подождать с отправками, то не сильно критично. А у любой флешки предел по записи не очень большой.
    • 0
      Полностью с Вами согласен… С этого я и начал…
      Что-то типа этого:
      /ip route add gateway=isp1 dst-address=0.0.0.0 distance=10
      Я конечно не знаком, с предыдущими версиями Mikrotik, но в 6-й версии если указать интерфейс в маршруте по умолчанию, работать такой маршрут не будет… И из-за этого пришлось написать скрипт.
      Да, сложные скрипты тяжело написать, постоянно возникают ситуации тяжелые для отладки. Например, такая как описана в конце статьи.
      • 0
        У вас однозначно глюк. Так как пример я вам приводил с рабочего роутера (за исключением имён-паролей-других параметров). И у меня всё работает именно так. Если надо могу полную конфигу скинуть в личку, но сильно не изменится. Как вариант вообще в GNS поднять конфигурацию тестовую и погонять.
        • 0
          Вы видимо не внимательны. У вас pppoe, т.е. point-to-point соединение, для которого достаточно указать только исходящий интерфейс, ведь на том конце всего одна точка, и пакеты всегда придут куда надо. А автора статьи ethernet, и адрес шлюза тут обязателен, ведь что-бы пакеты достигли шлюза тут не достаточно просто отправить их через нужный интерфейс, а нужно ещё и указать в заголовке кадра мак адрес шлюза. Это же азы работы сетей…
        • 0
          Проверено на новой конфигурации самое новое обновление 6.27.
          Если ставлю название интерфейса у меня isp1, допустим gateway=172.16.0.1%isp1 пинг на ip 172.16.0.1 и 8.8.8.8 есть. Если ставлю gateway=isp1 пинг на 8.8.8.8, а, Вы не поверите, пинг до шлюза 172.16.0.1 есть… Я в шоке!!!
          Кто может помогите!!!
      • 0
        Ещё один плюс к варианту с глюком — по умолчанию в интерфейсе винбокса выбирается именно интерфейс (и как раз IP адрес можно только через консоль указать)

        • 0
          На счет глюка не спорю, вполне возможно. Так как я первый раз сталкиваюсь с Mikrotik-ом думал, что проблема в RouterOS. Ставил несколько версий прошивки — результат тот же.
          Ввожу команду /ip route add gateway=isp1 dst-address=0.0.0.0 distance=1
          Появляется маршрут

          Но пинга нет…
          Я знаю, что-то пропускаю, но что?
          • 0
            Трасерт + конфиг с затёртыми паролями смотреть надо.
            • 0
              Конфиг абсолютно пустой!
              В таблице маршрутизации только мост, интерфейс к провайдеру и шлюз по-умолчанию(введенный в ручную не dhcp-клиентом).

              На чем именно трасерт? На микротике? Он странный! Ничего не понятно…
              Показывает пять хопов и 100% lost
              Если трасероут запустить на клиенте…

              Заголовок спойлера
              traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
              1 192.168.3.1 8.597 ms 10.176 ms 12.527 ms
              2 172.16.0.246 544.065 ms !H 544.603 ms !H 545.437 ms !H
              thund3r@G3000:~$ traceroute -n 8.8.8.8
              traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
              1 192.168.3.1 5.389 ms 7.532 ms 9.664 ms
              2 172.16.0.1 12.916 ms 15.344 ms 15.804 ms
              3 * * *
              4 81.23.22.201 33.904 ms 35.799 ms 37.081 ms
              5 81.23.22.202 31.514 ms 32.024 ms 38.490 ms
              6 209.85.252.123 103.632 ms 99.047 ms 98.175 ms
              7 209.85.249.175 97.934 ms 209.85.249.79 96.358 ms 209.85.249.173 94.480 ms
              8 216.239.46.9 96.357 ms 72.14.233.174 80.920 ms 216.239.46.15 83.544 ms
              9 * * *
              10 8.8.8.8 77.494 ms 61.110 ms 61.874 ms


              Можно конечно с помощью DHCP-клиента назначать маршрут… но тогда не возможно проверить живой ли канал…
    • 0
      Интерфейс можно назначать только для PPP соединений, но не для ethernet. :(
  • 0
    А вот это wiki.mikrotik.com/wiki/Advanced_Routing_Failover_without_Scripting не поможет?
    Вообще у меня микротика нет, но давно присматриваюсь.
    • 0
      Это я читал… Этот вариант только для статического адреса. GW1 и GW2 это не переменные. Как написано в статье — в первом варианте скрипта подставлялась переменная в маршрут по умолчанию, но проявлялось много проблем с RouterOS.
    • +1
      У меня раньше было похожим образом настроено — отваливается 1 канал и микротик автоматом на второй переключает.
      Затем наткнулся на ЭТУ статью и теперь у меня просто напросто одновременно работают оба канала. Если один ложится — второй все равно активен.
      Юзаю недели 3 — проблем не встречал вообще.

      P.S.: 1 канал на 20 Мб/с, второй — 10 Мб/с.
      Запускаем торрент с большим количеством сидов — на входе в комп скорость 30 Мб/с.
      • 0
        Да, это здорово, но как я ответил выше, эта команда не работает
        /ip route add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=isp1
        а если добавлять маршрут dhcp-клиентом в нем нельзя указать routing-mark. Из-за этого пришлось придумывать костыли. Хотя ниже предложили VRF, возможно это и будет более оптимальным решением.
      • 0
        Затестил ЭТУ тему. Мои наблюдения:

        Качать с торрентов — ДА!. Скорость с обоих каналов по максимуму.
        Работа с онлайн банками — НЕТ! — через каждые 5-120 секунд теряется сигнал, а именно, открыв тот же 2ip.ru и тупо обновляя страницу через каждые 3-5 секунд, станет видно отображение внешнего IP-адреса то с одного провайдера, то с другого.
        Хотя, костыль вставил тем, что в роутах жестко прописал, мол, если идем в банк, то только через конкретного провайдера.
        В общем, схема полурабочая. К массовой реализации не рекомендую.
  • +2
    Ех, молодежжь. Берете засовываете WAN интерфейсы в VRF(Ip-routes-VRF) и вешаем роутмарк нужный. Теперь же нам остается по нужному критерию(например пинги пропали на 8,8,8,8) нетвотчем всему исходящему трафику вешать нужный марк роутинга в манглах. так мы сможем направлять в нужный аплинк трафик.
    В общем если у вас есть динамический внешний адрес и вам надо с ним работать(например направлять туда некоторых клиентов то локалки) то самый простой выход это юзать VRF
    • 0
      Спасибо за совет! Сейчас почитаю…
    • 0
      Почитал, сделать конфигурацию с помощью VRF… те же проблемы…
      1) С горем по-полам настроил! Форвардинг работает, но сам роутер не хочет видеть интернет (проблема назначения в маршруте по-умолчанию шлюза. Можно назначить только используя ip адрес, а не название интерфейса, можно использовать скрипт из статьи, но зачем тогда врф. С помощью лупбека тоже не работает)
      2) Если переключать с помощью Нетвотч: конечно один раз он переключит, когда пропадет пинг, а так как нельзя указать интерфейс через который пинговать, линк останется на втором интерфейсе, пока он не прервется…

      А скрипт проверяет постоянно оба интерфейса! И как только оживает первый интерфейс, сразу переключается…

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.