Несколько лет назад я написал код, который запускаю для проверки каждого маршрута с учетом поправок по расстоянию (веса для разных линий). Можно использовать любую команду RouterOS для проверки маршрута, создав комментарий к маршруту, который начинается с “ROUTE_CHECK:”. Это позволяет использовать конкретные таблицы маршрутизации и составные выражения. У меня на системах пингуются два адреса, и суммируется их статус (получается 0, 1 или 2), причём любое значение, кроме 0, считается успешным. Если возвращается 0, маршрут либо отключается, либо у него корректируется дистанция в зависимости от переменных minDistance/maxDistance. Всё это объединяется, чтобы задавать «приоритеты» для доступных линий, так чтобы всегда оставался последний запасной вариант. Запуск происходит через планировщик каждые 5 секунд.
add check-gateway=ping comment="ROUTE_CHECK: :global minDistance 5; :global maxDistance 55; return ([/ping PUBLICIP1 count=1 interface=OutsideComcast routing-table=Comcast]+[/ping PUBLICIP2 count=1 interface=OutsideComcast routing-table=Comcast])" distance=5 gateway=GATEWAYMASKED routing-mark=PhoneInternet
add check-gateway=ping comment="ROUTE_CHECK: :global minDistance 10; :global maxDistance 50; return ([/ping PUBLICIP1 count=1 interface=OutsideVerizon routing-table=Verizon]+[/ping PUBLICIP2 count=1 interface=OutsideVerizon routing-table=Verizon])" distance=10 gateway=GATEWAYMASKED routing-mark=PhoneInternet
add check-gateway=ping comment="ROUTE_CHECK: :global minDistance 5; :global maxDistance 50; return ([/ping PUBLICIP1 count=1 interface=OutsideVerizon routing-table=Verizon]+[/ping PUBLICIP2 count=1 interface=OutsideVerizon routing-table=Verizon])" distance=5 gateway=GATEWAYMASKED pref-src=SRCMASKED
add check-gateway=ping comment="ROUTE_CHECK: :global minDistance 10; :global maxDistance 55; return ([/ping PUBLICIP1 count=1 interface=OutsideComcast routing-table=Comcast]+[/ping PUBLICIP2 count=1 interface=OutsideComcast routing-table=Comcast])" distance=10 gateway=GATEWAYMASKED
Если кто-то хочет попробовать — добавьте этот планировщик/скрипт. Ниже привожу более читабельную версию.
/system script add name=route_check owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":foreach k in [/ip route find comment~\"ROUTE_CHECK\"] do={
:local actualroute [:tostr [/ip route get \$k]]
:local disabled [/ip route get \$k disabled]
:local comment [/ip route get \$k comment]
:local distance [/ip route get \$k distance]
:local cmd [:pick \$comment 13 [:len \$comment]]
:local parsedcmd [:parse \"\$cmd\"]
:global minDistance \"\"
:global maxDistance \"\"
:global stepDistance 5
:local status [\$parsedcmd]
:set minDistance [:tonum \$minDistance]
:set maxDistance [:tonum \$maxDistance]
#:put \"STATUS: \$status \$[:type \$status]\"
:if ([:type \$status] != \"num\") do={
:error \"\$comment вернул значение не числового типа (нужен return в выражении?)\"
}
if ([:type \$minDistance] != \"nil\" && [:type \$maxDistance] != \"nil\") do={
if (\$minDistance >= \$maxDistance) do={
:error \"minDistance >= maxDistance\"
}
:local newDistance \$distance
if (\$status = 0) do={
:set newDistance (\$distance + \$stepDistance)
}
if (\$status != 0) do={
:set newDistance (\$distance - \$stepDistance)
}
if (\$newDistance < \$minDistance) do={ :set newDistance \$minDistance; }
if (\$newDistance > \$maxDistance) do={ :set newDistance \$maxDistance; }
if (\$newDistance != \$distance) do={
/log warning \"distance (\$status): \$distance [\$minDistance, \$maxDistance] -> \$newDistance - \$actualroute\"
/ip route set \$k distance=\$newDistance
}
} else {
:if (\$status = 0 && !\$disabled) do {
/ip route disable \$k
/log warning \"Команда: \$cmd статус=\$status\"
/log warning \"distance (\$status): \$distance ОТКЛЮЧАЮ - \$actualroute\"
} else {
:if (\$status != 0 && \$disabled) do {
/ip route enable \$k
/log warning \"distance (\$status): \$distance ВКЛЮЧАЮ - \$actualroute\"
}
}
}
}"
/system scheduler add interval=5s name=route_check on-event=route_check policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=feb/09/2016 start-time=03:39:20
:foreach k in [/ip route find comment~"ROUTE_CHECK"] do={
:local actualroute [:tostr [/ip route get $k]]
:local disabled [/ip route get $k disabled]
:local comment [/ip route get $k comment]
:local distance [/ip route get $k distance]
:local cmd [:pick $comment 13 [:len $comment]]
:local parsedcmd [:parse "$cmd"]
:global minDistance ""
:global maxDistance ""
:global stepDistance 5
:local status [$parsedcmd]
:set minDistance [:tonum $minDistance]
:set maxDistance [:tonum $maxDistance]
#:put "STATUS: $status $[:type $status]"
:if ([:type $status] != "num") do={
:error "$comment вернул значение не числового типа (нужен return выражения?)"
}
if ([:type $minDistance] != "nil" && [:type $maxDistance] != "nil") do={
if ($minDistance >= $maxDistance) do={
:error "minDistance >= maxDistance"
}
:local newDistance $distance
if ($status = 0) do={
:set newDistance ($distance + $stepDistance)
}
if ($status != 0) do={
:set newDistance ($distance - $stepDistance)
}
if ($newDistance < $minDistance) do={ :set newDistance $minDistance; }
if ($newDistance > $maxDistance) do={ :set newDistance $maxDistance; }
if ($newDistance != $distance) do={
/log warning "distance ($status): $distance [$minDistance, $maxDistance] -> $newDistance - $actualroute"
/ip route set $k distance=$newDistance
}
} else {
:if ($status = 0 && !$disabled) do {
/ip route disable $k
/log warning "Команда: $cmd статус=$status"
/log warning "distance ($status): $distance ОТКЛЮЧАЮ - $actualroute"
} else {
:if ($status != 0 && $disabled) do {
/ip route enable $k
/log warning "distance ($status): $distance ВКЛЮЧАЮ - $actualroute"
}
}
}
}