There have been a number of improved netwatch scripts listed on the mikrotik wiki in the past however many of these are hard to understand, broken or both.
I had a request from an associate to assist them finding a solution to fall over VPN traffic from one link to another in the event of an outage; in a network configuration where it wasn’t possible to use the local upstream router as an indication of the VPNs status, so I took the opportunity to revise a netwatch script based loosely on the one located here: http://wiki.mikrotik.com/wiki/Improved_Netwatch_II
My rewrite of this allows both the “up” and “down” scripts to be called from the same place (preferably a scheduler entry) and to be extra nice I’ve commented the whole script so you’re all welcome to modify as you see fit.
Pre-requisites:
– Script has been tested on v4.13
– Requires 2 routes to a set address/address range, one with a distance of 1 (preferred route) the other with a distance of 2
Note: If the address you’re trying to test to lies within the range you’re wanting to route to (eg: 192.168.1.1 and 192.168.1.0/24 as the test address and route respectively) you’ll want to add a static route for the test address (eg: 192.168.1.1 via 192.168.2.1) to ensure you always try the primary path to get to it (otherwise the testing would flap back and forth between the 2 links!)
Example configuration:
The netwatch route in this case would be:
/ip route add dst-address=192.168.2.0/24 gateway=192.168.4.2 distance=1 comment="Netwatch-Route"
The script:
#define variables
:local i 0
#Check for specific route with distance of 1
:if ([/ip route find comment="Netwatch-Route" distance=1]!="") do={
#add +1 to $i while checking that $i is lower than 5 and there is no ping response (ping command returns 0)
#if either of the 2 clauses are not met, the command will terminate - that is if a ping response is received (breaking one of the clauses), it'll terminate before 5 loops
:do {:set i ($i + 1)} while ($i < 5 && ([/ping 192.168.2.1 interval=3 count=1]=0))
#when this point is reached check if $i=5 and if so do the following
:if ($i=5) do={
#add a log entry
:log info "Netwatch-Route has gone down"
#set the route distance to 5 (putting it at a lower priority than the alternative)
/ip route set [find comment="Netwatch-Route"] distance=3
}
#route not found, so...
} else={
#Check for specific route with distance of 3
:if ([/ip route find comment="Netwatch-Route" distance=3]!="") do={
#add +1 to $i while checking that $i is lower than 10 and there is a ping response (ping command returns 0)
#if either of the 2 clauses are not met, the command will terminate - that is if a ping response is received (breaking one of the clauses), it'll terminate before 10 loops
:do {:set i ($i + 1)} while ($i < 10 && ([/ping 192.168.2.1 interval=3 count=1]=1))
#when this point is reached, check if $i=10 and if so do the following
:if ($i=10) do={
#add a log entry
:log info "Netwatch-Route is back up"
#set the route distance to 1 (putting it back to the higher priority)
/ip route set [find comment="Netwatch-Route"] distance=1
}
#no matching route found
} else={
#log failure of script
:log info "Route Required does not exist"
#log failure to terminal (helpful for testing purposes)
:error "Route Required does not exist"
}
}
For Mikrotik 2, the check address would be 192.168.1.1 and route would be
/ip route add dst-address=192.168.1.0/24 gateway=192.168.4.1 distance=1 comment="Netwatch-Route"
Uncommented/untabbed version of the script for those copy-paste fanatics:
:local i 0
:if ([/ip route find comment="Netwatch-Route" distance=1]!="") do={
:do {:set i ($i + 1)} while ($i < 5 && ([/ping 192.168.1.1 interval=3 count=1]=0))
:if ($i=5) do={
:log info "Netwatch-Route has gone down"
/ip route set [find comment="Netwatch-Route"] distance=3
}
} else={
:if ([/ip route find comment="Netwatch-Route" distance=3]!="") do={
:do {:set i ($i + 1)} while ($i < 10 && ([/ping 192.168.1.1 interval=3 count=1]=1))
:if ($i=10) do={
:log info "Netwatch-Route is back up"
/ip route set [find comment="Netwatch-Route"] distance=1
}
} else={
:log info "Route Required does not exist"
:error "Route Required does not exist"
}
}