I wrote some code a few years ago that I have been running to do per-route checking along with distance adjustments (weighting for different lines).
You can use any RouterOS command for the route check by creating a comment on the route that starts with "ROUTE_CHECK:". This allows you to use specific routing tables and have compound statements. On my systems, I ping two addresses and sum their status (which gives either a 0, 1, or 2) and anything other than 0 will be success. If it returns 0, it will either be disabled or have the distance adjusted depending on the variables minDistance/maxDistance being there. All of this can be tied together to give "priorities" for lines that are up, such that there can always be a last resort available.
This is all run via the scheduler every 5s.
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
If anyone wants to try it - add this scheduler/script. I'm pasting a more readable version below as well.
/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={\ \n:local actualroute [:tostr [/ip route get \$k]]\ \n:local disabled [/ip route get \$k disabled]\ \n:local comment [/ip route get \$k comment]\ \n:local distance [/ip route get \$k distance]\ \n:local cmd [:pick \$comment 13 [:len \$comment]]\ \n:local parsedcmd [:parse \"\$cmd\"]\ \n:global minDistance \"\"\ \n:global maxDistance \"\"\ \n:global stepDistance 5\ \n:local status [\$parsedcmd]\ \n:set minDistance [:tonum \$minDistance]\ \n:set maxDistance [:tonum \$maxDistance]\ \n#:put \"STATUS: \$status \$[:type \$status]\"\ \n:if ([:type \$status] != \"num\") do={\ \n\t:error \"\$comment returned non-number type (need return on expression\?)\"\ \n}\ \nif ([:type \$minDistance] != \"nil\" && [:type \$maxDistance] != \"nil\") do={\ \n\tif (\$minDistance >= \$maxDistance) do={\ \n\t\t:error \"minDistance >= maxDistance\"\ \n\t}\ \n\t:local newDistance \$distance\ \n\tif (\$status = 0) do={\ \n\t\t:set newDistance (\$distance + \$stepDistance)\ \n\t}\ \n\tif (\$status != 0) do={\ \n\t\t:set newDistance (\$distance - \$stepDistance)\ \n\t}\ \n\tif (\$newDistance < \$minDistance) do={ :set newDistance \$minDistance; }\ \n\tif (\$newDistance > \$maxDistance) do={ :set newDistance \$maxDistance; }\ \n\tif (\$newDistance != \$distance) do={\ \n\t\t/log warning \"distance (\$status): \$distance [\$minDistance, \$maxDistance] -> \$newDistance - \$actualroute\"\ \n\t\t/ip route set \$k distance=\$newDistance\ \n\t}\ \n} else {\ \n\t:if (\$status = 0 && !\$disabled) do {\ \n \t\t/ip route disable \$k\ \n\t\t/log warning \"Command: \$cmd status=\$status\"\ \n\t\t/log warning \"distance (\$status): \$distance DISABLE - \$actualroute\"\ \n\t} else {\ \n\t\t:if (\$status != 0 && \$disabled) do {\ \n\t\t\t/ip route enable \$k\ \n\t\t\t/log warning \"distance (\$status): \$distance ENABLE - \$actualroute\"\ \n\t\t}\ \n\t}\ \n}\ \n}" /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 / ip路由发现~”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 returned non-number type (need return on expression?)" } 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 "Command: $cmd status=$status" /log warning "distance ($status): $distance DISABLE - $actualroute" } else { :if ($status != 0 && $disabled) do { /ip route enable $k /log warning "distance ($status): $distance ENABLE - $actualroute" } } } }