I make a 10 wan load balance (dsl) with PCC, but i have a big problem, in my country sometimes we have a intermitent down of a various adls at same time, sometimes i have 4 or 5 wand down at same time, this is a big problem because the RouterOS send all the traffic of this 5 down wan for the default gateway saturating this link, i make a script that first count the number of active routes and then re-create the mangle rules changing the PCC parameter and inserting the new rules. maybe is more easy to resolve this issue (i wait opinions) but this is the way i think by now.
i dont know much about scripting, maybe there is best and easy way to do this, i’ll wait advices.
:global activeroutesold;
:local activeroutes 0;
:local route;
:local tes;
:local divs 0;
:local less;
:local routingmarks;
:local arrayrouting;
:local routemark;
:log info "BEGIN***********************************************************"
:foreach route in=[/ip route find where comment~"^[a-z]*balanceo" active=yes] do={
:set tes [ /ip route get $route routing-mark ];
:set activeroutes ($activeroutes + 1)
:set routingmarks ($routingmarks, $tes);
}
:log info $activeroutes;
:log info $activeroutesold;
:if ($activeroutes != $activeroutesold) do={
/ip firewall
mangle {
:foreach a in=[find where comment~"^[a-z]*balance" ] do={
remove $a }
}
:set arrayrouting [:toarray $routingmarks]
:set divs $activeroutes;
:set less $activeroutes;
:for i from=0 to=($activeroutes-1) do={
:set routemark [:pick $routingmarks $i]
:set divs ($activeroutes - $less);
:set less ($less - 1);
:log info "$routemark";
:log info "$activeroutes/$divs"
/ip firewall mangle
:log info "Setting filters";
add action=mark-connection chain=prerouting comment="balance conn $routemark" \
disabled=no dst-address-type=!local in-interface=local \
new-connection-mark="$routemark" passthrough=yes per-connection-classifier=\
"both-addresses:$activeroutes/$divs" place-before=3
add action=mark-routing chain=prerouting comment="balance route $routemark" \
connection-mark="$routemark" disabled=no in-interface=local new-routing-mark=\
"$routemark" passthrough=no place-before=3
}
} else={:log info "routes has no changed"};
:log info ("$activeroute active routes");
:set activeroutesold $activeroutes;
:log info "END********************************************************************"
Hi max, this is working in my router i dont know whats the problem..
hola, max nos conocimos en el mum de argentina, el script que esta alli lo copie y pegue de la configuracion actual, aca te pegare el mismo pero con algunas modificaciones que he hecho sobre la marcha, pero como te digo esta trabajando en una rb493 con v4.5
:global activeroutesold;
:local activeroutes 0;
:local route;
:local tes;
:local divs 0;
:local less;
:local routingmarks;
:local arrayrouting;
:local routemark;
:log info "BEGIN************"
:foreach route in=[/ip route find where comment~"^[a-z]*balanceo" active=yes] do={
:set tes [ /ip route get $route routing-mark ];
:set activeroutes ($activeroutes + 1)
:set routingmarks ($routingmarks, $tes);
}
:if ($activeroutes != $activeroutesold) do={
/ip firewall
mangle {
:foreach a in=[find where comment~"^[a-z]*balance" ] do={
remove $a }
}
:set arrayrouting [:toarray $routingmarks]
:set divs $activeroutes;
:set less $activeroutes;
:log info "email enviado";
:for i from=0 to=($activeroutes-1) do={
:set routemark [:pick $routingmarks $i]
:set divs ($activeroutes - $less);
:set less ($less - 1);
:log info "$routemark";
:log info "$activeroutes/$divs"
/ip firewall mangle
:log info "Setting filters";
add action=mark-connection chain=prerouting comment="balance conn $routemark" \
disabled=no dst-address-type=!local in-interface=local \
new-connection-mark="$routemark" passthrough=yes per-connection-classifier=\
"both-addresses:$activeroutes/$divs" place-before=3
add action=mark-routing chain=prerouting comment="balance route $routemark" \
connection-mark="$routemark" disabled=no in-interface=local new-routing-mark=\
"$routemark" passthrough=no place-before=3
}
} else={:log info "rutas no han cambiado"};
:log info ("$activeroutes rutas activas");
:set activeroutesold $activeroutes;
:log info "END**************"
Thanks Janisk for edit the code part and show me that it’s possible, jejeje
Load balancing and failover does not work properly.
Until 2019, load balancing and failover not worked properly.
High time to do something about it.
This would be a great asset for the Mikrotik routers
No Chupaka, he has been unable to get mangling and PCC working in another thread so he bitches about it like spam everywhere else.
However, if you want to help out, I would ask that you join us at this thread as I have been unable to solve what should be straightforward… http://forum.mikrotik.com/t/load-balancing-dont-work/128208/1
What I find interesting on this thread is that the configuration is designed to deal with not all the WANs being available and thus I see no need for a script??
In the mangled routes, we check gateway = ping. Thus if one is not available the load is distributed amongst the remaining mangled routes and so on?
What am I missing in the logic??
Caveat: I cannot script or MT config myself out of a paper bag.
I am talking about the tutorials that were made and in which year. Steve Discher’s tutorial is not working.
Something must have changed in the Mikrotik routers.
In RouterOS 6.37 the load balancing and failover worked perfectly.
There is also a failover tutorial made in 2019 (PDF file) and this does not work either. This is what I mean.
If I send a supout.rif to Mikrotik they are very vague and give no concrete solution.
What do you mean with my account hacked.
My Mikrotik account or forum account?
I’ve been editing and working on a script to run in production on R7. After a lot of tweaking, the script below is the closest I’ve gotten.
However, we need to consider a few issues.
First, go to IP → IP settings → RP Filter: loose. I found that mangle does not work correctly when set to strict.
Next, go to Routing → Tables. There, you need to create routes for your ISPs with the comment “LB-Route”, enter the name you want, and enable the FIB function.
You need to define fallbacks with different distances in Routes for each of your ISPs, a DNS blackhole pointing to each of the ISPs’ gateways, and a few more details that I can explain in more detail if anyone is interested.
Script:
# ============================================================
# DYNAMIC PCC LOAD BALANCING (WITH WEIGHTS) - RouterOS v7
# VERSION 4.4 - Fixed Time Lock + Safe Parsing
# Based on: https://forum.mikrotik.com/t/solved-script-to-recreate-the-load-balance-mangle-rules/36203/5 (adapted for ROS7)
# ============================================================
# ============================================================
# EXECUTION TIME LOCK (FIXED)
# ============================================================
:global lbLockTime;
# Define TTL as TIME TYPE to avoid comparison errors
:local lbLockTTL 00:00:30;
:local now [:totime [/system clock get time]];
:if ([:typeof $lbLockTime] != "nothing") do={
# Protection against midnight rollover
# If the current time is less than the lock time, the day rolled over -> Reset
:if ($now < $lbLockTime) do={
:log warning "LB: Day rollover detected. Resetting Lock.";
} else={
# Safe comparison (Time < Time)
:if (($now - $lbLockTime) < $lbLockTTL) do={
:log warning "LB: Script already running (lock active). Aborting.";
:return;
} else={
:log warning "LB: Lock expired (Previous crash?). Resuming execution.";
}
}
}
:set lbLockTime $now;
# ============================================================
# GLOBAL VARIABLES
# ============================================================
:global activeroutesold;
:global lbScenarioOld;
:if ([:typeof $activeroutesold] = "nothing") do={ :set activeroutesold 0; }
:if ([:typeof $lbScenarioOld] = "nothing") do={ :set lbScenarioOld ""; }
# --- CONFIGURATION ---
:local LANLIST "PPPOE_CLIENTS";
# WEIGHTS (routing-table = weight)
# Example: ISP1=3 (750Mbps), ISP2=1 (250Mbps) -> Correct Proportion
:local linkWeights {"ISP1"=1; "ISP2"=1};
# --------------------
:local activeroutes 0;
:local routingmarks "";
:log info "LB: Starting deterministic scan..."
# ============================================================
# 1. ROUTE DISCOVERY
# ============================================================
:foreach r in=[/ip route find where comment="LB-Route" disabled=no] do={
:local rTable [/ip route get $r routing-table];
# Protection against invalid routes or undefined tables
:if ([:len $rTable] = 0) do={
:log error "LB: LB-Route detected without routing-table. Ignored.";
} else={
:set routingmarks ($routingmarks . "," . $rTable);
:set activeroutes ($activeroutes + 1);
}
}
# ============================================================
# ROS7-SAFE PARSING
# ============================================================
:local routingArray ({});
:if ([:len $routingmarks] > 0) do={
:set routingArray [:toarray [:pick $routingmarks 1 [:len $routingmarks]]];
}
# ============================================================
# 2. BUILD CURRENT SCENARIO (TOPOLOGY + WEIGHTS)
# ============================================================
:local lbScenario "";
:foreach table in=$routingArray do={
:local w ($linkWeights->$table);
:if ([:typeof $w] = "nothing") do={ :set w 1; }
:set lbScenario ($lbScenario . "|" . $table . "=" . $w);
}
# ============================================================
# 3. PCC RECONSTRUCTION (IF NECESSARY)
# ============================================================
:if (($activeroutes != $activeroutesold) || ($lbScenario != $lbScenarioOld)) do={
:log warning ("LB: Change detected. Scenario: " . $lbScenario);
/ip firewall mangle remove [find where comment~"LB-Dynamic"]
:if ($activeroutes > 0) do={
# A. Calculate total weight
:local totalWeight 0;
:foreach table in=$routingArray do={
:local w ($linkWeights->$table);
:if ([:typeof $w] = "nothing") do={ :set w 1; }
:set totalWeight ($totalWeight + $w);
}
# B. Create PCC rules (mark-connection)
:local currentPccIndex 0;
:foreach table in=$routingArray do={
:local w ($linkWeights->$table);
:if ([:typeof $w] = "nothing") do={ :set w 1; }
:for k from=1 to=$w do={
# both-addresses-and-ports: Highly recommended for a small number of concurrent users
:local pccCalc ("both-addresses:" . $totalWeight . "/" . $currentPccIndex);
:local newMark ("conn_" . $table);
:local cComm ("LB-Dynamic conn " . $table . " (" . $k . "/" . $w . ")");
/ip firewall mangle add chain=prerouting \
action=mark-connection \
comment=$cComm \
in-interface-list=$LANLIST \
dst-address-type=!local \
connection-mark=no-mark \
per-connection-classifier=$pccCalc \
new-connection-mark=$newMark \
passthrough=yes
:set currentPccIndex ($currentPccIndex + 1);
}
}
# C. Create mark-routing rules (ONE per link)
:foreach table in=$routingArray do={
:local newMark ("conn_" . $table);
:local rComm ("LB-Dynamic route " . $table);
/ip firewall mangle add chain=prerouting \
action=mark-routing \
comment=$rComm \
in-interface-list=$LANLIST \
connection-mark=$newMark \
new-routing-mark=$table \
passthrough=no
}
:set activeroutesold $activeroutes;
:set lbScenarioOld $lbScenario;
:log info ("LB: SUCCESS! Total Weight: " . $totalWeight);
} else={
:set activeroutesold 0;
:set lbScenarioOld "";
:log error "LB: ERROR! No active 'LB-Route' found.";
}
} else={
:log info "LB: No changes required.";
}
# ============================================================
# RELEASE LOCK (SAFE)
# ============================================================
# Setting to "nothing" is the correct way to clear a global variable in ROS
:set lbLockTime;