Connection weighting is not bandwidth aggregation

With 100 and 50 Mbps internet links, you want user connections distributed roughly in proportion to capacity. RouterOS PCC, or Per Connection Classifier, hashes new connections into defined groups. This example has three groups, called buckets: two for WAN1 and one for WAN2. The goal is an approximate 2:1 connection count together with a backup path. Connection sizes vary, and one download does not combine both links' speeds.

Why the Configuration Uses PCC

Criterion ECMP PCC
Mechanism Route selection among equal-cost next hops Connection classification using hashes and marks
Distribution control Depends on routing and implementation hashing Designed through classifier buckets
Return paths NAT session return paths need separate validation Controlled through connection and routing marks

The original topic was unequal load balancing with failover using ECMP. That goal is retained. The RouterOS v7 configuration uses PCC for an explicit 2:1 bucket allocation and return-path policy. A connection ratio does not guarantee a bandwidth ratio. Test hashing, NAT and failover on the target version.

Before policy routing

This example uses RouterOS v7 syntax. Record the release and do not paste v6 route commands unchanged.

Preconfigure the lab interfaces and gateways. Check CPU and connection tracking under representative traffic. Classification depends on conntrack and marks.

Keep console access and an off-device export. The example assumes no existing DNAT or policy routing. Review production rules, VPNs and internal networks before adding marks.

Why the historical ECMP URL is retained

The historical URL preserves existing links, while this weighted example uses PCC. Repeating ECMP gateways is not a dependable 2:1 guarantee. In v7, create routing tables before referencing them.

Connection marks and routing tables

PCC first assigns a connection mark to a new connection. Later packets select the matching routing table, and replies to inbound connections must return through the arrival WAN. Internal and VPN destinations are bypassed before these marks so LAN traffic is not mistakenly sent towards the Internet.

Example addresses and interfaces

ether1/WAN1 uses 192.168.30.2/30 via 192.168.30.1. Ether2/WAN2 uses 172.30.30.2/30 via 172.30.30.1. Ether3 carries LAN 10.10.10.0/24. Replace these values from actual IPAM.

NAT and internal paths

NAT does not grant access. Keep WAN input default-deny and permit only approved forwarding. Include internal/VPN subnets in bypass policy. Existing DNAT needs independent return-path tests.

Configure tables, mangle and NAT

Review the export, routes and FastTrack rules. Exclude marked connections during a canary deployment. An existing FastTrack rule can be temporarily disabled in the lab.

ROUTEROS
/ip address print
/ip route print detail
/ip firewall mangle print detail
/ip firewall filter print where action=fasttrack-connection
/routing table add name=ent-wan1 fib
/routing table add name=ent-wan2 fib
/ip firewall address-list add list=ent-local address=10.10.10.0/24
/ip firewall address-list add list=ent-local address=192.168.30.0/30
/ip firewall address-list add list=ent-local address=172.30.30.0/30
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-list=ent-local action=accept comment="ENT-PCC local bypass"
/ip firewall mangle add chain=prerouting in-interface=ether1 connection-state=new connection-mark=no-mark action=mark-connection new-connection-mark=ent-c1 comment="ENT-PCC incoming WAN1"
/ip firewall mangle add chain=prerouting in-interface=ether2 connection-state=new connection-mark=no-mark action=mark-connection new-connection-mark=ent-c2 comment="ENT-PCC incoming WAN2"
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-type=!local connection-state=new connection-mark=no-mark per-connection-classifier=both-addresses-and-ports:3/0 action=mark-connection new-connection-mark=ent-c1 comment="ENT-PCC bucket0"
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-type=!local connection-state=new connection-mark=no-mark per-connection-classifier=both-addresses-and-ports:3/1 action=mark-connection new-connection-mark=ent-c1 comment="ENT-PCC bucket1"
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-type=!local connection-state=new connection-mark=no-mark per-connection-classifier=both-addresses-and-ports:3/2 action=mark-connection new-connection-mark=ent-c2 comment="ENT-PCC bucket2"
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-type=!local connection-mark=ent-c1 action=mark-routing new-routing-mark=ent-wan1 passthrough=no comment="ENT-PCC route1"
/ip firewall mangle add chain=prerouting in-interface=ether3 dst-address-type=!local connection-mark=ent-c2 action=mark-routing new-routing-mark=ent-wan2 passthrough=no comment="ENT-PCC route2"
/ip firewall mangle add chain=output connection-mark=ent-c1 action=mark-routing new-routing-mark=ent-wan1 passthrough=no comment="ENT-PCC reply1"
/ip firewall mangle add chain=output connection-mark=ent-c2 action=mark-routing new-routing-mark=ent-wan2 passthrough=no comment="ENT-PCC reply2"
/ip route add dst-address=0.0.0.0/0 gateway=192.168.30.1 routing-table=main distance=1 check-gateway=ping comment="ENT-PCC main1"
/ip route add dst-address=0.0.0.0/0 gateway=172.30.30.1 routing-table=main distance=2 check-gateway=ping comment="ENT-PCC main2"
/ip route add dst-address=0.0.0.0/0 gateway=192.168.30.1@main routing-table=ent-wan1 distance=1 check-gateway=ping comment="ENT-PCC table1 primary"
/ip route add dst-address=0.0.0.0/0 gateway=172.30.30.1@main routing-table=ent-wan1 distance=2 check-gateway=ping comment="ENT-PCC table1 backup"
/ip route add dst-address=0.0.0.0/0 gateway=172.30.30.1@main routing-table=ent-wan2 distance=1 check-gateway=ping comment="ENT-PCC table2 primary"
/ip route add dst-address=0.0.0.0/0 gateway=192.168.30.1@main routing-table=ent-wan2 distance=2 check-gateway=ping comment="ENT-PCC table2 backup"
/ip firewall nat add chain=srcnat src-address=10.10.10.0/24 out-interface=ether1 action=masquerade comment="ENT-PCC nat1"
/ip firewall nat add chain=srcnat src-address=10.10.10.0/24 out-interface=ether2 action=masquerade comment="ENT-PCC nat2"

These rules target a clean lab with an already secure firewall. On an existing network, integrate them with current rules, remove duplicate routes/NAT and add VPN/datacenter prefixes to ent-local. Test several hundred fresh connections: bucket0 plus bucket1 counters should approach twice bucket2, not necessarily twice the bytes. Then disconnect WAN1 in the lab and check each table's active route and a fresh connection.

Healthy gateway, failed upstream

A responding gateway does not establish a working Internet path. The check-gateway=ping setting tests only the direct gateway; an upstream ISP failure can leave that route active. Monitor each WAN's loss, latency and external reachability independently. Recursive or multi-destination probes require a separate design.

Inspect each policy table and connection bucket

ROUTEROS
/routing table print
/ip route print detail where routing-table=ent-wan1
/ip route print detail where routing-table=ent-wan2
/ip firewall mangle print stats where comment~"ENT-PCC"
/ip firewall connection print count-only where connection-mark=ent-c1
/ip firewall connection print count-only where connection-mark=ent-c2

Expect both FIB tables to exist, each with an active, reachable next hop. New client sessions should increase the classifier counters. Two WAN1 buckets versus one WAN2 bucket allocate connection counts, not guaranteed bytes or throughput. In an isolated lab, fail each link independently and retest new sessions. If the gateway responds while the ISP upstream is broken, a gateway-only ping check does not detect that failure and the route can remain active. Preserve existing connections; do not flush conntrack to force a passing test.

Uneven distribution and wrong return paths

For poor distribution, first establish that connections are fresh and not bypassed by FastTrack. Trace replies on the wrong WAN through connection marks and prerouting/output counters. For an inactive route, inspect next-hop resolution in main and scope. Destinations sensitive to public-IP changes may need pinning or another classifier, tested with redistribution.

Rollback and session behavior during failover

Rollback disables ENT-PCC mangle, restores prior routes/NAT and disables new rules. Remove tables after references are gone. Avoid blindly clearing conntrack. A public-IP change commonly requires existing TCP sessions to reconnect.

Test every table with fresh connections

Generate hundreds of fresh connections and compare bucket connection counts. Fail WAN1 and WAN2 independently and inspect every table’s active route and new-connection success. Gateway and upstream failure are different tests.

Disable only the new lab policy rules first

These commands modify the example configuration. With console access, disable the new mangle rules first, then disable only the example routes/NAT after reviewing the pre-change path. Do not remove FIB tables until every reference is gone. Restore the exact recorded prior policy, including any FastTrack change, and verify both forwarding and router management.

ROUTEROS
/ip firewall mangle disable [find where comment~"ENT-PCC"]
/ip route disable [find where comment~"ENT-PCC"]
/ip firewall nat disable [find where comment~"ENT-PCC"]

Best Practices

  • Version-control configuration and review changes.
  • Use least privilege and explicit allow-lists.
  • Automate repeatable checks and monitor the expected state.
  • Test upgrades and restores before production rollout.

Conclusion

A reliable implementation of Unequal Dual-WAN Load Balancing with PCC on RouterOS v7 is more than a successful first run. Keep the configuration documented, observable, recoverable, and aligned with the team's change-management process.

Frequently Asked Questions

Does 2:1 weighting guarantee a 2:1 bandwidth ratio?

No. Weighting applies to connections whose flow sizes differ.

Does failover preserve TCP sessions?

A changed public IP can terminate a session and require reconnection.

Official Sources

Share

Meet AJInfrastructure & DevOps
Loading…