Mikrotik failover script


Basic Info

This is an easy to use script for your failover needs. It is currently written for 2 connections and works by pinging any IP address you specify using both of your connections.

If a ping failure is detected a certain number of times, the script increases distance of all default routes that use the gateway present on the interface that failed the ping.

What to configure

To get this script working you need to fill in these values:

Exact names of both interfaces you use to connect to the internet.

IPs of both gateways that you use.

An IP address that you want to check connectivity against.

The ammount of ping failures after which the script fails-over.

The distance that the default routes will get increased by in order to become secondary.

The script

# ------------------- header -------------------
# Script by Tomas Kirnak, version 1.0.7
# If you use this script, or edit and
# re-use it, please keep the header intact.
#
# For more information and details about
# this script please visit the wiki page at
# http://wiki.mikrotik.com/wiki/Failover_Scripting
# ------------------- header -------------------



# ------------- start editing here -------------
# Edit the variables below to suit your needs

# Please fill the WAN interface names
:local InterfaceISP1 ether1
:local InterfaceISP2 ether2

# Please fill the gateway IPs (or interface names in case of PPP)
:local GatewayISP1 1.1.1.1
:local GatewayISP2 2.2.2.2

# Please fill the ping check host - currently: resolver1.opendns.com
:local PingTarget 208.67.222.222

# Please fill how many ping failures are allowed before fail-over happends
:local FailTreshold 3

# Define the distance increase of a route when it fails
:local DistanceIncrease 2

# Editing the script after this point may break it
# -------------- stop editing here --------------



# Declare the global variables
:global PingFailCountISP1
:global PingFailCountISP2

# This inicializes the PingFailCount variables, in case this is the 1st time the script has ran
:if ([:typeof $PingFailCountISP1] = "nothing") do={:set PingFailCountISP1 0}
:if ([:typeof $PingFailCountISP2] = "nothing") do={:set PingFailCountISP2 0}

# This variable will be used to keep results of individual ping attempts
:local PingResult



# Check ISP1
:set PingResult [ping $PingTarget count=1 interface=$InterfaceISP1]
:put $PingResult

:if ($PingResult = 0) do={
	:if ($PingFailCountISP1 < ($FailTreshold+2)) do={
		:set PingFailCountISP1 ($PingFailCountISP1 + 1)
		
		:if ($PingFailCountISP1 = $FailTreshold) do={
			:log warning "ISP1 has a problem en route to $PingTarget - increasing distance of routes."
			:foreach i in=[/ip route find gateway=$GatewayISP1 && static] do=\
				{/ip route set $i distance=([/ip route get $i distance] + $DistanceIncrease)}
			:log warning "Route distance increase finished."
		}
	}
}
:if ($PingResult = 1) do={
	:if ($PingFailCountISP1 > 0) do={
		:set PingFailCountISP1 ($PingFailCountISP1 - 1)
		
		:if ($PingFailCountISP1 = ($FailTreshold -1)) do={
			:log warning "ISP1 can reach $PingTarget again - bringing back original distance of routes."
			:foreach i in=[/ip route find gateway=$GatewayISP1 && static] do=\
				{/ip route set $i distance=([/ip route get $i distance] - $DistanceIncrease)}
			:log warning "Route distance decrease finished."
		}
	}
}



# Check ISP2
:set PingResult [ping $PingTarget count=1 interface=$InterfaceISP2]
:put $PingResult

:if ($PingResult = 0) do={
	:if ($PingFailCountISP2 < ($FailTreshold+2)) do={
		:set PingFailCountISP2 ($PingFailCountISP2 + 1)
		
		:if ($PingFailCountISP2 = $FailTreshold) do={
			:log warning "ISP2 has a problem en route to $PingTarget - increasing distance of routes."
			:foreach i in=[/ip route find gateway=$GatewayISP2 && static] do=\
				{/ip route set $i distance=([/ip route get $i distance] + $DistanceIncrease)}
			:log warning "Route distance increase finished."
		}
	}
}
:if ($PingResult = 1) do={
	:if ($PingFailCountISP2 > 0) do={
		:set PingFailCountISP2 ($PingFailCountISP2 - 1)
		
		:if ($PingFailCountISP2 = ($FailTreshold -1)) do={
			:log warning "ISP2 can reach $PingTarget again - bringing back original distance of routes."
			:foreach i in=[/ip route find gateway=$GatewayISP2 && static] do=\
				{/ip route set $i distance=([/ip route get $i distance] - $DistanceIncrease)}
			:log warning "Route distance decrease finished."
		}
	}
}

Another script

#-------------------------------------------------------------------------------
# MikroTik RouterOS WAN Failover
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# Settings
#-------------------------------------------------------------------------------
:local PRIMARYROUTELABEL "ISP1";
:local BACKUPROUTELABEL "ISP2";
# Hosts to ping via primary route (Google.DNS)
:local PRIMARYHOSTS {8.8.8.8; 8.8.4.4};
# Hosts to ping via backup route (Yandex.DNS)
:local BACKUPHOSTS {77.88.8.8; 77.88.8.7};
:local PINGCOUNT 3;
:local PINGTRESHOLD 70;

:local primaryDistance [/ip route get [find comment=$PRIMARYROUTELABEL] distance];
:local backupDistance [/ip route get [find comment=$BACKUPROUTELABEL] distance];

#-------------------------------------------------------------------------------
# Check primary route
#-------------------------------------------------------------------------------
:local primaryOk false;
:local primarySuccessPingCount 0;
:foreach host in=$PRIMARYHOSTS do={
    :local n [/ping $host count=$PINGCOUNT];
    :set primarySuccessPingCount ($primarySuccessPingCount + $n);
}
:set primaryOk (($primarySuccessPingCount * 100) >= ([:len $PRIMARYHOSTS] * $PINGCOUNT * $PINGTRESHOLD));
:if (!$primaryOk && ($primaryDistance <= $backupDistance)) do={
    :log error "Primary internet connection down"
};

#-------------------------------------------------------------------------------
# Check backup route
#-------------------------------------------------------------------------------
:local backupOk false;
:local backupSuccessPingCount 0;
:foreach host in=$BACKUPHOSTS do={
    :local n [/ping $host count=$PINGCOUNT];
    :set backupSuccessPingCount ($backupSuccessPingCount + $n);
};
:set backupOk (($backupSuccessPingCount * 100) >= ([:len $BACKUPHOSTS] * $PINGCOUNT * $PINGTRESHOLD));
:if (!$backupOk && ($primaryDistance >= $backupDistance)) do={
    :log error "Backup internet connection down"
};

#-------------------------------------------------------------------------------
# Failover
#-------------------------------------------------------------------------------
:if ($primaryOk && ($primaryDistance >= $backupDistance)) do={
# Switch to primary route
    /ip route set [find comment=$PRIMARYROUTELABEL] distance=1
    /ip route set [find comment=$BACKUPROUTELABEL] distance=2
    /log warning "Switched to primary internet connection"
# Remove all connections
    /ip firewall connection tracking set enabled=no
    :delay 5s
    /ip firewall connection tracking set enabled=yes
};
:if (!$primaryOk && $backupOk && ($primaryDistance <= $backupDistance)) do={
# Switch to backup route
    /ip route set [find comment=$PRIMARYROUTELABEL] distance=2
    /ip route set [find comment=$BACKUPROUTELABEL] distance=1
    /log error "Switched to backup internet connection"
# Remove all connections
    /ip firewall connection tracking set enabled=no
    :delay 5s
    /ip firewall connection tracking set enabled=yes
};