Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Mikrotik RouterOS Script to do proper uplink failover/failback (more reliable than Netwatch)
# Mikrotik RouterOS Script to do proper uplink failover/failback (more reliable than Netwatch).
# Supports both Generic and PPPoE interfaces.
# Policy: read, write, policy, test
### Configuration ###
# Define Names of all Interfaces that will be checked:
:local "interface-names" { "internet-speedy";"internet-biznet" };
# Define Gateway Addresses of Interfaces with static gateways:
#:local "interface-gateways" { "internet-tunnel1"="192.168.100.1" };
:local "interface-gateways" { "" };
# Define whether Order of priority follows fixed ordering of "interface-names" array (otherwise uses default route distance):
:local "fixed-priority" yes;
# Define whether will automatically failback to higher priority interfaces (when connectivity is restored):
:local "auto-failback" yes;
### Script ###
# Get IDs of Generic Interfaces:
:local "interface-ids";
:if ($"fixed-priority" = yes) do={
:global "cached-interface-ids";
:if ([:typeof $"cached-interface-ids"] = "array" && [:len $"cached-interface-ids"] = [:len $"interface-names"]) do={
:set "interface-ids" $"cached-interface-ids";
} else={
:set "interface-ids" [:toarray ""];
:foreach idx,"interface-name" in=$"interface-names" do={
:local "interface-id" [/interface find where name=$"interface-name"];
if ($"interface-id"!="") do={
:set ($"interface-ids"->$idx) [:tostr $"interface-id"];
}
}
:set "cached-interface-ids" $"interface-ids";
}
} else={
:set "interface-ids" [:toarray ""];
:foreach idx,"interface-name" in=$"interface-names" do={
:local "interface-id" [/interface find where name=$"interface-name"];
# Priority Order by Default-Route Distance:
:if ([/interface get $"interface-id" type] = "pppoe-out") do={
:local "interface-route-distance" [/interface pppoe-client get $"interface-id" default-route-distance];
:set ($"interface-ids"->[:tostr $"interface-route-distance"]) [:tostr $"interface-id"];
} else={
:local "interface-gw-address" ($"interface-gateways"->$"interface-name");
:local "interface-route-id" [/ip route find dst-address="0.0.0.0/0" gateway=$"interface-gw-address" routing-mark~"^(main)\?\$"];
:if ([:len $"interface-route-id"] = 1) do={
:local "interface-route-distance" [/ip route get $"interface-route-id" distance];
:set ($"interface-ids"->[:tostr $"interface-route-distance"]) [:tostr $"interface-id"];
}
}
}
}
:local "request-failback" no;
# Loop over each Generic Interface in defined order:
:foreach idx,"interface-id" in=$"interface-ids" do={
:if (![/interface get $"interface-id" disabled]) do={
# Get Configured Gateway Address:
:local "interface-gateway-address";
:local "interface-name" [/interface get $"interface-id" name];
:if ([/interface get $"interface-id" type] = "pppoe-out") do={
/interface pppoe-client monitor $"interface-id" once do={ :set "interface-gateway-address" $"remote-address" };
} else={
:set "interface-gateway-address" ($"interface-gateways"->$"interface-name");
}
# Get Current Gateway State:
:local "interface-gateway-state";
:local "interface-nexthop-id" [/ip route nexthop find address=$"interface-gateway-address"];
:if ([:len $"interface-nexthop-id"] = 1) do={
:set "interface-gateway-state" [/ip route nexthop get $"interface-nexthop-id" gw-state];
} else={
:set "interface-gateway-state" "unreachable";
}
# Ensure interface-gateway-states global variable is defined:
:global "interface-gateway-states";
:if ([:typeof $"interface-gateway-states"] != "array") do={
:set "interface-gateway-states" [:toarray ""];
}
#:log warn ("name: " . $"interface-name" . ", distance: " . $idx . ", gw-state: " . $"interface-gateway-state");
# Detect Change in Gateway Connectivity / State:
:if ($"interface-gateway-state" != $"interface-gateway-states"->$"interface-id" ) do= {
:log info ($"interface-name" . ": Internet Gateway State changed from \"" . $"interface-gateway-states"->$"interface-id" . "\" to \"" . $"interface-gateway-state" . "\"");
:set ($"interface-gateway-states"->$"interface-id") $"interface-gateway-state";
:if ($"interface-gateway-state" = "unreachable") do={
:log info "------- INTERNET GATEWAY DOWN -------";
/interface disable $"interface-id";
/interface enable $"interface-id";
} else={
:if ($"interface-gateway-state" = "reachable") do={
:log info "------- INTERNET GATEWAY UP -------";
:set "request-failback" $"auto-failback"
} else={
/log warn ("------- INTERNET GATEWAY ".$"interface-gateway-state"." -------");
}
}
#/system script run UpdateDynamicIP;
} else={
if ($"request-failback" = yes) do={
# Failback by disabling and re-enabling interface
:if ($"interface-gateway-state" = "reachable") do={
:log info "------- INTERNET GATEWAY FAILBACK -------";
/interface disable $"interface-id";
/interface enable $"interface-id";
:set "request-failback" no
}
}
}
}
}
# Add self (this script) to system scheduler
:if ([:len [/system scheduler find name=NetwatchGatewayStates]] = 0) do={
/system scheduler add interval=5s name=NetwatchGatewayStates on-event=NetwatchGatewayStates \
policy=read,write,policy,test start-time=startup;
}
@louismburu

This comment has been minimized.

Copy link

commented Jul 7, 2018

Hi.Are you available.The script is updated so many times and its confusing..Which is the complete cript?

@murdz112

This comment has been minimized.

Copy link

commented Jul 12, 2018

Hi,

Just wondering if someone could elaborate on this part:

Define Gateway Addresses of Interfaces with static gateways:

#:local "interface-gateways" { "internet-tunnel1"="192.168.100.1" };
:local "interface-gateways" { "" };

Do I replace interface-gateways with something or am I putting something in the { "" };

Is anyone able to assist me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.