Policy-Based Routing
Policy-Based Routing
Section titled “Policy-Based Routing”Policy-based routing (PBR) selects the forwarding path based on packet attributes beyond the destination address. RouterOS supports routing decisions based on source address, incoming interface, firewall marks, protocol, and port numbers, enabling flexible traffic engineering for multi-WAN environments, VPN steering, and ISP load balancing. Rather than following a single routing table for all traffic, PBR directs different traffic flows through different gateways or network paths according to administrator-defined policy.
RouterOS 7 implements PBR through two complementary mechanisms: firewall mangle rules that mark packets with routing table references, and /ip/route/rule entries that match packet attributes and select routing tables. Understanding how these mechanisms interact and their relative priority is essential for building predictable PBR configurations that behave correctly under all conditions.
Routing Tables
Section titled “Routing Tables”RouterOS maintains a main routing table that receives all static routes, connected routes, and protocol-learned routes by default. Policy-based routing requires creating additional routing tables to hold alternative forwarding paths. Custom routing tables isolate different sets of routes so that marked traffic consults only the routes in its designated table rather than the global routing table.
Creating Custom Routing Tables
Section titled “Creating Custom Routing Tables”In RouterOS 7, custom routing tables must be explicitly created before any routes or marks can reference them. The fib flag installs routes from the table into the kernel forwarding information base, which is required for actual packet forwarding.
# Create routing tables for dual-ISP setup/routing/tableadd name=to-isp1 fibadd name=to-isp2 fib
# Verify tables were created/routing/table/printTables without the fib flag exist only for routing policy evaluation and cannot forward traffic. Always include fib unless the table is used solely for route filtering or policy evaluation purposes.
Adding Routes to Custom Tables
Section titled “Adding Routes to Custom Tables”Routes are assigned to specific tables using the routing-table parameter. Each custom table typically receives at least a default route pointing to its designated gateway, along with any additional static routes required for that traffic path.
# Default routes for each ISP in their respective tables/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp1 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp2 check-gateway=ping
# Main table still requires its own default routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=main check-gateway=pingThe main routing table must contain routes sufficient to resolve next-hop addresses used by custom tables. RouterOS uses the main table to resolve gateway reachability even when forwarding marked traffic through a custom table, so a broken or missing main table default route can prevent custom-table traffic from forwarding correctly.
Routing Table Lookup Order
Section titled “Routing Table Lookup Order”RouterOS evaluates routing tables in the following order for each packet:
- Mangle mark-routing check: if the packet carries a routing mark, the corresponding table is consulted immediately
- Routing rules:
/ip/route/ruleentries are evaluated in order by rule priority - Main table fallback: unmarked traffic with no matching rule uses the main routing table
Mangle takes precedence over routing rules. A packet marked by mangle will not be evaluated against routing rules, making the two mechanisms mutually exclusive for any individual packet. Design configurations using one mechanism per traffic flow to avoid unexpected interactions.
Routing Rules
Section titled “Routing Rules”Routing rules provide stateless PBR without requiring firewall processing. Each rule matches packet attributes and specifies the routing table to consult. Rules are evaluated in ascending priority order, with the first matching rule determining the lookup table.
Rule Configuration
Section titled “Rule Configuration”# Route traffic from subnet 10.10.10.0/24 through ISP1/ip/route/ruleadd src-address=10.10.10.0/24 action=lookup table=to-isp1 priority=10
# Route traffic from subnet 10.20.20.0/24 through ISP2add src-address=10.20.20.0/24 action=lookup table=to-isp2 priority=20
# All other traffic uses the main table (implicit default)Rules support matching on source address, destination address, incoming interface, routing mark, and IP TOS/DSCP fields. The action parameter determines what happens when a rule matches: lookup searches the specified table, lookup-only-in-table restricts the lookup to that table without fallback to main, and drop discards matching packets.
Rule Priority
Section titled “Rule Priority”Lower priority numbers are evaluated first. Rules without an explicit priority value receive a default that places them after manually prioritized rules. When multiple rules could match a packet, only the first match takes effect.
# More specific rule evaluated first (lower priority number)/ip/route/ruleadd src-address=10.10.10.100/32 action=lookup table=to-isp2 priority=5add src-address=10.10.10.0/24 action=lookup table=to-isp1 priority=10In this example, the specific host 10.10.10.100 routes through ISP2 while the rest of the subnet routes through ISP1.
Mangle Route Marking
Section titled “Mangle Route Marking”Firewall mangle rules provide stateful PBR that tracks connections and applies consistent routing throughout the life of each flow. Mangle operates in the prerouting chain for transit traffic and the output chain for router-originated traffic, running before routing decisions are made.
mark-routing Action
Section titled “mark-routing Action”The mark-routing action attaches a routing table name to a packet, directing it to that table during the forwarding lookup. Unlike packet marks that persist to other subsystems, routing marks are consumed by the routing engine and are not visible to other firewall chains.
# Mark traffic from specific source for ISP2/ip/firewall/mangleadd chain=prerouting src-address=192.168.10.50 \ action=mark-routing new-routing-mark=to-isp2 passthrough=noSetting passthrough=no stops processing in the mangle chain after the mark is applied. Use passthrough=yes when subsequent mangle rules need to process the same packet for other purposes such as QoS marking.
Connection-Based Marking
Section titled “Connection-Based Marking”Stateful marking ensures all packets in a connection use the same path, preventing asymmetric routing that breaks TCP sessions. The pattern uses mark-connection to tag the first packet of a new connection, then mark-routing to mark all subsequent packets in that connection.
/ip/firewall/mangle# Step 1: Mark new connections from the source subnetadd chain=prerouting src-address=192.168.10.0/24 \ connection-state=new action=mark-connection \ new-connection-mark=isp2-conn passthrough=yes
# Step 2: Apply routing mark to all packets in marked connectionsadd chain=prerouting connection-mark=isp2-conn \ action=mark-routing new-routing-mark=to-isp2 passthrough=noThis two-step pattern ensures that reply packets returning through the router are also marked, maintaining symmetric routing for the entire connection lifetime.
Router-Originated Traffic
Section titled “Router-Originated Traffic”Traffic generated by the router itself, such as DNS queries, NTP synchronization, and management connections, passes through the output chain rather than prerouting. Mark router-originated traffic separately when it needs to follow specific ISP paths.
/ip/firewall/mangle# Mark router DNS queries for ISP1 exitadd chain=output protocol=udp dst-port=53 \ action=mark-routing new-routing-mark=to-isp1 passthrough=no
# Mark all other router-originated traffic for ISP1add chain=output action=mark-routing \ new-routing-mark=to-isp1 passthrough=noOmitting output chain rules causes router-originated traffic to use the main routing table regardless of PBR policy, which is often the desired behavior but can cause issues when the main table’s default route is not the intended exit path.
Multi-WAN Failover
Section titled “Multi-WAN Failover”Multi-WAN failover maintains internet connectivity when a primary ISP link fails by automatically switching to a backup link. RouterOS implements failover through route distance values combined with gateway health monitoring.
Distance-Based Failover
Section titled “Distance-Based Failover”Routes with lower distance values are preferred over higher-distance routes to the same destination. Installing a primary default route with distance 1 and a backup default route with distance 2 creates automatic failover behavior: the backup route becomes active only when the primary route is removed from the routing table.
/ip/route# Primary ISP — preferred due to lower distanceadd dst-address=0.0.0.0/0 gateway=192.0.2.1 distance=1 check-gateway=ping
# Backup ISP — activates when primary failsadd dst-address=0.0.0.0/0 gateway=198.51.100.1 distance=2 check-gateway=pingGateway Health Monitoring
Section titled “Gateway Health Monitoring”The check-gateway parameter enables RouterOS to detect gateway failures and remove the associated routes from the active routing table. RouterOS supports two monitoring modes:
| Mode | Behavior |
|---|---|
ping | Sends ICMP echo requests to the gateway address; marks gateway down after consecutive failures |
arp | Sends ARP requests to resolve the gateway MAC; marks down when ARP responses stop |
/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 distance=1 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=198.51.100.1 distance=2 check-gateway=pingWhen the primary gateway stops responding to pings, RouterOS marks it as unreachable and removes the primary default route, causing traffic to use the backup route automatically. The primary route is restored once the gateway resumes responding.
Recursive Route Health Monitoring
Section titled “Recursive Route Health Monitoring”Direct gateway pinging only detects link-layer failures. When an ISP gateway remains reachable but upstream internet connectivity fails, gateway ping continues to succeed and the primary route stays active despite the broken internet path. Recursive routing with probe targets addresses this limitation.
# Probe targets — specific hosts reachable only through each ISP/ip/routeadd dst-address=1.1.1.1/32 gateway=192.0.2.1 scope=10add dst-address=8.8.8.8/32 gateway=198.51.100.1 scope=10
# Default routes resolve through probe targets instead of gateways directlyadd dst-address=0.0.0.0/0 gateway=1.1.1.1 distance=1 \ check-gateway=ping scope=30 target-scope=11add dst-address=0.0.0.0/0 gateway=8.8.8.8 distance=2 \ check-gateway=ping scope=30 target-scope=11In this pattern, the default route’s gateway is a public IP address reachable through the ISP. RouterOS pings that public IP; if the ISP’s upstream path is broken, pings fail and the route is removed even though the ISP gateway itself remains reachable. The scope and target-scope values control recursive resolution depth.
Failover with PBR Tables
Section titled “Failover with PBR Tables”Multi-WAN PBR configurations require check-gateway on routes in each custom table to enable per-table failover behavior.
/routing/tableadd name=to-isp1 fibadd name=to-isp2 fib
/ip/route# ISP1 table routesadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp1 check-gateway=ping distance=1add dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp1 check-gateway=ping distance=2
# ISP2 table routesadd dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp2 check-gateway=ping distance=1add dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp2 check-gateway=ping distance=2This configuration allows traffic marked for each ISP to fall back to the other ISP if its primary gateway fails, providing both PBR control and redundancy.
ECMP Load Balancing
Section titled “ECMP Load Balancing”Equal-cost multi-path routing distributes traffic across multiple gateways simultaneously. RouterOS selects among equal-cost routes based on a hash of packet fields, distributing flows across available paths.
Configuring ECMP
Section titled “Configuring ECMP”Install multiple default routes with identical distance values to enable ECMP:
/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 distance=1 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=198.51.100.1 distance=1 check-gateway=pingRouterOS distributes new connections across both gateways. When one gateway fails its health check, RouterOS removes that route and remaining traffic shifts entirely to the surviving gateway until the failed gateway recovers.
Per-Connection Load Balancing
Section titled “Per-Connection Load Balancing”ECMP in RouterOS uses a flow-based hash that assigns each connection to a single gateway for its duration, ensuring individual TCP sessions remain on one path. This per-flow behavior prevents packet reordering that would degrade TCP performance if packets within a connection used different paths.
The hash algorithm considers source address, destination address, and protocol by default. All connections from the same source to the same destination will use the same gateway, which can create uneven distribution when a small number of clients generate the majority of traffic.
PCC-Based Load Balancing
Section titled “PCC-Based Load Balancing”Per-Connection Classifier provides deterministic traffic distribution using firewall mangle rules. PCC divides connections into groups based on configurable packet fields and assigns each group to a specific routing table.
/routing/tableadd name=to-isp1 fibadd name=to-isp2 fib
/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp1 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp2 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=main check-gateway=ping
/ip/firewall/mangle# Connections where (src+dst hash) % 2 == 0 go to ISP1add chain=prerouting in-interface=ether3 connection-state=new \ per-connection-classifier=both-addresses:2/0 \ action=mark-connection new-connection-mark=isp1-conn passthrough=yesadd chain=prerouting connection-mark=isp1-conn \ action=mark-routing new-routing-mark=to-isp1 passthrough=no
# Connections where (src+dst hash) % 2 == 1 go to ISP2add chain=prerouting in-interface=ether3 connection-state=new \ per-connection-classifier=both-addresses:2/1 \ action=mark-connection new-connection-mark=isp2-conn passthrough=yesadd chain=prerouting connection-mark=isp2-conn \ action=mark-routing new-routing-mark=to-isp2 passthrough=noPCC ensures deterministic assignment that survives table lookups and connection tracking, providing more even distribution than pure ECMP when traffic profiles vary.
Practical PBR Examples
Section titled “Practical PBR Examples”Per-Source-IP ISP Selection
Section titled “Per-Source-IP ISP Selection”Route specific hosts or subnets through designated ISPs regardless of destination:
/routing/tableadd name=to-isp1 fibadd name=to-isp2 fib
/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp1 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp2 check-gateway=pingadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=main check-gateway=ping
/ip/firewall/mangle# VLAN 10 hosts use ISP1add chain=prerouting src-address=192.168.10.0/24 \ action=mark-routing new-routing-mark=to-isp1 passthrough=no
# VLAN 20 hosts use ISP2add chain=prerouting src-address=192.168.20.0/24 \ action=mark-routing new-routing-mark=to-isp2 passthrough=noNAT masquerade rules must be configured per-interface to ensure outbound traffic uses the correct source IP for each ISP:
/ip/firewall/natadd chain=srcnat out-interface=ether1 action=masquerade # ISP1 interfaceadd chain=srcnat out-interface=ether2 action=masquerade # ISP2 interfacePort-Based ISP Routing
Section titled “Port-Based ISP Routing”Direct specific application traffic through a designated ISP based on destination port:
/ip/firewall/mangle# Route HTTPS traffic through ISP2 (higher-bandwidth link)add chain=prerouting protocol=tcp dst-port=443 connection-state=new \ action=mark-connection new-connection-mark=https-conn passthrough=yesadd chain=prerouting connection-mark=https-conn \ action=mark-routing new-routing-mark=to-isp2 passthrough=no
# Route bulk FTP/SFTP through ISP1add chain=prerouting protocol=tcp dst-port=20-21,22 connection-state=new \ action=mark-connection new-connection-mark=bulk-conn passthrough=yesadd chain=prerouting connection-mark=bulk-conn \ action=mark-routing new-routing-mark=to-isp1 passthrough=noVPN Split Routing
Section titled “VPN Split Routing”Route specific destination networks through a VPN tunnel while sending all other traffic through the ISP:
/routing/tableadd name=to-vpn fib
/ip/route# Corporate network routes through VPNadd dst-address=10.0.0.0/8 gateway=<vpn-tunnel-interface> routing-table=mainadd dst-address=172.16.0.0/12 gateway=<vpn-tunnel-interface> routing-table=main
# Default traffic through ISP (already in main table)
/ip/firewall/mangle# Force specific hosts to use VPN for all destinationsadd chain=prerouting src-address=192.168.1.50 \ action=mark-routing new-routing-mark=to-vpn passthrough=no
/ip/routeadd dst-address=0.0.0.0/0 gateway=<vpn-tunnel-interface> routing-table=to-vpnWireGuard tunnels route traffic to destinations listed in each peer’s allowed-address parameter automatically, without requiring additional mangle rules for standard split-routing scenarios:
/interface/wireguard/peersadd interface=wg1 public-key="PEER_PUBLIC_KEY" \ endpoint-address=vpn.example.com endpoint-port=51820 \ allowed-address=10.0.0.0/8,172.16.0.0/12# Only these prefixes are routed through the WireGuard peerSource-Based Routing with Routing Rules
Section titled “Source-Based Routing with Routing Rules”Use /ip/route/rule for stateless PBR without firewall processing overhead:
/routing/tableadd name=to-isp1 fibadd name=to-isp2 fib
/ip/routeadd dst-address=0.0.0.0/0 gateway=192.0.2.1 routing-table=to-isp1add dst-address=0.0.0.0/0 gateway=198.51.100.1 routing-table=to-isp2
/ip/route/ruleadd src-address=192.168.10.0/24 table=to-isp1 priority=10add src-address=192.168.20.0/24 table=to-isp2 priority=20Routing rules do not track connections, so reply packets may not match the same rule as the initial packet. This can cause asymmetric routing for scenarios where the router also performs NAT. Use mangle-based marking for NAT environments to ensure connection symmetry.
Troubleshooting Policy-Based Routing
Section titled “Troubleshooting Policy-Based Routing”Verifying Active Routes in Custom Tables
Section titled “Verifying Active Routes in Custom Tables”# View routes in a specific routing table/ip/route/print where routing-table=to-isp1
# View all routing rules/ip/route/rule/print
# Check gateway health status/ip/route/print where active=yesChecking Routing Mark Assignment
Section titled “Checking Routing Mark Assignment”Use the RouterOS packet sniffer or firewall logging to verify marks are being applied:
# Add temporary logging to mangle rules for debugging/ip/firewall/mangleadd chain=prerouting src-address=192.168.10.0/24 \ action=log log-prefix="PBR-mark:" passthrough=yesDiagnosing Asymmetric Routing
Section titled “Diagnosing Asymmetric Routing”Asymmetric routing occurs when forward and return paths use different gateways. Symptoms include broken TCP connections, NAT failures, and intermittent connectivity. Check for asymmetry by:
- Verifying mangle connection marks cover both new and established connections
- Confirming that
mark-connectionrules usepassthrough=yesbeforemark-routingrules - Checking that routing rules apply to both directions if used without connection tracking
NAT and PBR Interaction
Section titled “NAT and PBR Interaction”Policy-based routing must be configured before NAT translation occurs in the packet processing pipeline. Mangle prerouting runs before NAT dstnat, ensuring marks are applied to the original (pre-DNAT) addresses. Source NAT in the srcnat chain runs after routing decisions, so masquerade rules correctly use the interface determined by PBR.
When troubleshooting NAT with PBR, verify that masquerade rules cover all WAN interfaces used by PBR tables. Traffic marked for a secondary ISP that exits through the secondary WAN interface requires a masquerade rule on that interface.