MikroTik RouterOS Firewall Mangle: Packet Marking and Traffic Classification
MikroTik RouterOS Firewall Mangle: Packet Marking and Traffic Classification
Section titled “MikroTik RouterOS Firewall Mangle: Packet Marking and Traffic Classification”TL;DR (Quick Start)
Section titled “TL;DR (Quick Start)”For the impatient: here’s the 30-second version.
# Mark web traffic connections and packets for QoS/ip firewall mangle add chain=forward connection-state=new protocol=tcp dst-port=80,443 action=mark-connection new-connection-mark=web_conn/ip firewall mangle add chain=forward connection-mark=web_conn action=mark-packet new-packet-mark=web_pkt passthrough=noOverview
Section titled “Overview”The firewall mangle is RouterOS’s traffic classification engine - it marks packets, connections, and routes for processing by other facilities like queues, NAT, and routing tables. Unlike the firewall filter (which allows or blocks traffic), mangle identifies and categorizes traffic without affecting whether it passes or not.
Understanding mangle is essential because:
- QoS depends on it: Queue trees use packet marks to apply bandwidth policies
- Policy routing needs it: Route marks direct traffic through specific gateways
- Traffic shaping requires it: Connection marks enable per-client bandwidth management
- Advanced NAT uses it: Marked connections can be treated differently by NAT rules
This guide explains how mangle fits into the packet processing pipeline, the three types of marks, and practical patterns for traffic classification.
The Mangle Processing Pipeline
Section titled “The Mangle Processing Pipeline”Mangle operates at specific points in the packet flow. Understanding where each chain processes packets is critical for effective traffic marking:
Key insight: PREROUTING runs before the routing decision, making it ideal for policy routing marks. FORWARD only processes transit traffic, making it efficient for QoS marking of client traffic.
The Five Mangle Chains
Section titled “The Five Mangle Chains”RouterOS has five predefined mangle chains that cannot be deleted. Each processes packets at a specific point:
PREROUTING Chain: First Contact
Section titled “PREROUTING Chain: First Contact”When: Immediately after packet arrives on interface, before routing decision.
Use cases:
- Policy routing (mark-routing)
- Early traffic classification
- Marking traffic before it splits into INPUT or FORWARD
Example: Mark all traffic from a specific VLAN for a separate routing table:
/ip firewall mangle add chain=prerouting in-interface=vlan100 action=mark-routing new-routing-mark=isp2INPUT Chain: Traffic to the Router
Section titled “INPUT Chain: Traffic to the Router”When: After routing decision, for packets destined to the router itself.
Use cases:
- Mark management traffic for QoS
- Classify services running on the router
- Monitor traffic to router services
Example: Mark DNS queries to the router:
/ip firewall mangle add chain=input protocol=udp dst-port=53 action=mark-packet new-packet-mark=dns_queriesFORWARD Chain: Transit Traffic
Section titled “FORWARD Chain: Transit Traffic”When: After routing decision, for packets passing through the router.
Use cases:
- QoS packet marking for client traffic
- Connection marking for bandwidth management
- Traffic classification between networks
Example: Mark HTTP traffic for queue tree:
/ip firewall mangle add chain=forward protocol=tcp dst-port=80 action=mark-packet new-packet-mark=http_trafficOUTPUT Chain: Router-Generated Traffic
Section titled “OUTPUT Chain: Router-Generated Traffic”When: After local process generates packet, before routing decision.
Use cases:
- Mark router-generated traffic for policy routing
- Classify traffic from router services
- QoS for router’s own traffic
Example: Mark router’s backup traffic:
/ip firewall mangle add chain=output protocol=tcp dst-port=21 action=mark-routing new-routing-mark=backup_linkPOSTROUTING Chain: Final Processing
Section titled “POSTROUTING Chain: Final Processing”When: Just before packet leaves the router, after all routing decisions.
Use cases:
- Final packet modifications (DSCP, TTL)
- Marking after NAT has been applied
- Last chance to classify outbound traffic
Example: Set DSCP for all outbound VoIP traffic:
/ip firewall mangle add chain=postrouting protocol=udp dst-port=5060 action=change-dscp new-dscp=46Understanding Mark Types
Section titled “Understanding Mark Types”Mangle creates three distinct types of marks, each serving different purposes:
Packet Marks: Per-Packet Classification
Section titled “Packet Marks: Per-Packet Classification”Scope: Individual packet only Persistence: Transient - exists only while packet is processed Primary use: Queue trees for bandwidth management
/ip firewall mangle add chain=forward protocol=tcp dst-port=80 action=mark-packet new-packet-mark=web_trafficHow queues use packet marks:
/queue tree add name=web_queue parent=global packet-mark=web_traffic max-limit=10MImportant: Packet marks are router-internal only. They are not transmitted across the network and cannot be seen by other devices.
Connection Marks: Efficient Classification
Section titled “Connection Marks: Efficient Classification”Scope: All packets in a connection Persistence: Stored in connection tracking table Primary use: Reduce CPU by marking once, matching many
The connection marking pattern is essential for performance:
# Rule 1: Mark new connections (inspects headers once)/ip firewall mangle add chain=forward connection-state=new src-address=192.168.88.0/24 \ action=mark-connection new-connection-mark=lan_conn
# Rule 2: Mark packets based on connection mark (fast lookup)/ip firewall mangle add chain=forward connection-mark=lan_conn \ action=mark-packet new-packet-mark=lan_trafficWhy this matters: Without connection marks, every packet requires header inspection. With connection marks, only the first packet of each connection is fully analyzed - subsequent packets use a fast connection table lookup.
Routing Marks: Policy Routing
Section titled “Routing Marks: Policy Routing”Scope: Packet’s routing decision Persistence: Until routing decision is made Primary use: Direct traffic through specific routing tables
# RouterOS v7: Create routing table first (required)/routing table add name=via_isp2 fib
# Mark traffic for secondary ISP (exclude local traffic!)/ip firewall mangle add chain=prerouting src-address=192.168.100.0/24 \ dst-address-type=!local action=mark-routing new-routing-mark=via_isp2
# Route marked traffic through ISP2/ip route add dst-address=0.0.0.0/0 gateway=10.0.0.1 routing-table=via_isp2Critical notes:
- RouterOS v7 requires pre-created routing tables: Create with
/routing table add name=myTable fibbefore usingmark-routing - Always exclude local traffic: Use
dst-address-type=!localto prevent breaking router’s own connectivity - FastTrack incompatible: Traffic with routing marks cannot use FastTrack
The Passthrough Parameter
Section titled “The Passthrough Parameter”The passthrough parameter controls whether rule processing continues after a match:
passthrough=yes (default): Continue to next rule after action passthrough=no: Stop processing after action
When to Use passthrough=yes
Section titled “When to Use passthrough=yes”Use when you need multiple marks on the same packet:
# Mark connection first (passthrough=yes by default)/ip firewall mangle add chain=forward connection-state=new src-address=192.168.88.0/24 \ action=mark-connection new-connection-mark=internal_conn
# Then mark packet (same packet, second mark)/ip firewall mangle add chain=forward connection-mark=internal_conn \ action=mark-packet new-packet-mark=internal_pkt passthrough=noWhen to Use passthrough=no
Section titled “When to Use passthrough=no”Use when the mark is final and no further processing is needed:
# Final classification - stop processing/ip firewall mangle add chain=forward protocol=tcp dst-port=22 \ action=mark-packet new-packet-mark=ssh_traffic passthrough=noPerformance tip: Use passthrough=no on your final rules to avoid unnecessary rule traversal.
Mangle Actions Reference
Section titled “Mangle Actions Reference”| Action | Description | Use Case |
|---|---|---|
mark-packet | Add packet mark | Queue tree classification |
mark-connection | Add connection mark | Efficient per-connection classification |
mark-routing | Add routing mark | Policy-based routing |
change-dscp | Modify DSCP field (0-63) | QoS marking for upstream devices |
change-ttl | Modify TTL value | Prevent traceroute, hide hops |
change-mss | Modify Maximum Segment Size | Fix path MTU discovery issues |
set-priority | Set VLAN/WMM priority | Layer 2 QoS |
clear-df | Remove Don’t Fragment flag | Allow fragmentation |
sniff-tzsp | Export to TZSP receiver | Packet capture to Wireshark |
Configuration Steps
Section titled “Configuration Steps”This section provides a practical configuration that demonstrates the core mangle concepts.
Step 1: Create Connection Marks for Traffic Classification
Section titled “Step 1: Create Connection Marks for Traffic Classification”Mark connections by traffic type for efficient processing:
/ip firewall mangleadd chain=forward connection-state=new protocol=tcp dst-port=80,443 \ action=mark-connection new-connection-mark=web_conn comment="Mark web connections"add chain=forward connection-state=new protocol=udp dst-port=53 \ action=mark-connection new-connection-mark=dns_conn comment="Mark DNS connections"add chain=forward connection-state=new protocol=tcp dst-port=22 \ action=mark-connection new-connection-mark=ssh_conn comment="Mark SSH connections"Step 2: Create Packet Marks from Connection Marks
Section titled “Step 2: Create Packet Marks from Connection Marks”Convert connection marks to packet marks for queue trees:
/ip firewall mangleadd chain=forward connection-mark=web_conn action=mark-packet \ new-packet-mark=web_pkt passthrough=no comment="Web packet mark"add chain=forward connection-mark=dns_conn action=mark-packet \ new-packet-mark=dns_pkt passthrough=no comment="DNS packet mark"add chain=forward connection-mark=ssh_conn action=mark-packet \ new-packet-mark=ssh_pkt passthrough=no comment="SSH packet mark"Step 3: Use Packet Marks in Queue Tree (Optional)
Section titled “Step 3: Use Packet Marks in Queue Tree (Optional)”Apply bandwidth policies based on marks:
/queue treeadd name=download parent=global max-limit=100Madd name=web_download parent=download packet-mark=web_pkt max-limit=50Madd name=dns_download parent=download packet-mark=dns_pkt max-limit=5M priority=1add name=ssh_download parent=download packet-mark=ssh_pkt max-limit=10M priority=2Verification
Section titled “Verification”Confirm your mangle rules are active and processing traffic.
Check 1: Verify Rules Are Created
Section titled “Check 1: Verify Rules Are Created”/ip firewall mangle printExpected Output:
Flags: X - disabled, I - invalid, D - dynamic # CHAIN ACTION CONNECTION-MARK NEW-CONN-MARK NEW-PKT-MARK 0 forward mark-connection web_conn 1 forward mark-connection dns_conn 2 forward mark-connection ssh_conn 3 forward mark-packet web_conn web_pkt 4 forward mark-packet dns_conn dns_pkt 5 forward mark-packet ssh_conn ssh_pktCheck 2: Monitor Rule Statistics
Section titled “Check 2: Monitor Rule Statistics”/ip firewall mangle print statsExpected Output:
# CHAIN ACTION BYTES PACKETS 0 forward mark-connection 0 0 1 forward mark-connection 0 0 2 forward mark-connection 0 0 3 forward mark-packet 1,234,567 8,901 4 forward mark-packet 45,678 234 5 forward mark-packet 98,765 543Check 3: Verify Connection Marks in Tracking Table
Section titled “Check 3: Verify Connection Marks in Tracking Table”/ip firewall connection print where connection-mark!=""Expected Output:
# PROTOCOL SRC-ADDRESS DST-ADDRESS CONNECTION-MARK 0 tcp 192.168.88.10:4521 93.184.216.34:443 web_conn 1 udp 192.168.88.10:5353 8.8.8.8:53 dns_connCommon Patterns
Section titled “Common Patterns”Pattern 1: Per-Client Bandwidth Management
Section titled “Pattern 1: Per-Client Bandwidth Management”Mark each client’s traffic separately for individual queue limits:
# Mark connections per client/ip firewall mangleadd chain=forward connection-state=new src-address=192.168.88.10 \ action=mark-connection new-connection-mark=client10_connadd chain=forward connection-state=new src-address=192.168.88.11 \ action=mark-connection new-connection-mark=client11_conn
# Mark packets for queuingadd chain=forward connection-mark=client10_conn action=mark-packet \ new-packet-mark=client10_pkt passthrough=noadd chain=forward connection-mark=client11_conn action=mark-packet \ new-packet-mark=client11_pkt passthrough=noPattern 2: Dual-WAN Load Balancing
Section titled “Pattern 2: Dual-WAN Load Balancing”Mark traffic for different ISPs based on source:
# Mark traffic from different subnets for different ISPs/ip firewall mangleadd chain=prerouting src-address=192.168.10.0/24 action=mark-routing \ new-routing-mark=to_isp1add chain=prerouting src-address=192.168.20.0/24 action=mark-routing \ new-routing-mark=to_isp2
# Create routing table entries/ip routeadd dst-address=0.0.0.0/0 gateway=10.0.1.1 routing-mark=to_isp1add dst-address=0.0.0.0/0 gateway=10.0.2.1 routing-mark=to_isp2Pattern 3: MSS Clamping for PPPoE/VPN
Section titled “Pattern 3: MSS Clamping for PPPoE/VPN”Fix path MTU discovery issues by clamping TCP MSS for tunneled connections:
# Clamp MSS for outbound traffic through PPPoE/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn \ out-interface=pppoe-out tcp-mss=1301-65535 action=change-mss new-mss=1300 \ passthrough=yes comment="Clamp MSS for PPPoE outbound"
# Clamp MSS for inbound traffic through PPPoE/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn \ in-interface=pppoe-out tcp-mss=1301-65535 action=change-mss new-mss=1300 \ passthrough=yes comment="Clamp MSS for PPPoE inbound"Why this works: PPPoE adds 8 bytes of overhead, reducing effective MTU. When PMTUD fails (ICMP blocked), TCP connections stall with large packets. MSS clamping forces smaller TCP segments, avoiding fragmentation issues.
Pattern 4: DSCP Marking for Upstream QoS
Section titled “Pattern 4: DSCP Marking for Upstream QoS”Set DSCP values for traffic that will be prioritized by upstream devices:
/ip firewall mangleadd chain=postrouting protocol=udp dst-port=5060-5061 action=change-dscp \ new-dscp=46 comment="VoIP signaling - EF"add chain=postrouting protocol=udp dst-port=10000-20000 action=change-dscp \ new-dscp=46 comment="VoIP RTP - EF"add chain=postrouting protocol=tcp dst-port=22 action=change-dscp \ new-dscp=26 comment="SSH - AF31"Pattern 5: Bypass FastTrack for Marked Traffic
Section titled “Pattern 5: Bypass FastTrack for Marked Traffic”When using policy routing, ensure marked traffic bypasses FastTrack:
# FastTrack unmarked traffic only/ip firewall filteradd chain=forward connection-state=established,related routing-mark="" \ action=fasttrack-connectionadd chain=forward connection-state=established,related action=acceptTroubleshooting
Section titled “Troubleshooting”Problem: “Mangle rules show zero packet counts”
Section titled “Problem: “Mangle rules show zero packet counts””Cause: Rules may be unreachable, or traffic doesn’t match criteria.
Solution:
- Check rule order - earlier rules may match first with
passthrough=no - Verify traffic exists:
/ip firewall connection print - Check chain selection - use
forwardfor transit traffic, notinput - Ensure connection tracking is enabled:
/ip firewall connection tracking print
Problem: “Connection marks not appearing in connection table”
Section titled “Problem: “Connection marks not appearing in connection table””Cause: Rule may be in wrong chain or connection-state not specified.
Solution:
- For new connection marks, use
connection-state=new - Use
preroutingorforwardchain, notpostrouting - Verify rule matches: add
log=yestemporarily to debug
Problem: “Policy routing marks don’t affect traffic”
Section titled “Problem: “Policy routing marks don’t affect traffic””Cause: Routing table or routes may be misconfigured.
Solution:
- Verify routing mark is set in
preroutingchain (before routing decision) - Check route exists with matching routing-mark:
/ip route print where routing-mark=your_mark - Ensure FastTrack isn’t processing marked connections
- Verify with:
/ip firewall mangle print stats
Problem: “Packet mark limit exceeded” error
Section titled “Problem: “Packet mark limit exceeded” error”Cause: RouterOS has a limit of 4096 unique packet marks.
Solution:
- Use connection marks instead of packet marks where possible
- Consolidate similar traffic under fewer marks
- Review if all marks are necessary
- Check for dynamic mark generation that may be creating excessive marks
Problem: “Queue tree doesn’t apply to marked traffic”
Section titled “Problem: “Queue tree doesn’t apply to marked traffic””Cause: Packet marks may not match queue configuration.
Solution:
- Verify exact packet mark name in both mangle and queue
- Check queue tree parent interface matches traffic path
- Ensure
passthrough=noon final packet mark rule - Verify marks are created:
/ip firewall mangle print stats
Performance Considerations
Section titled “Performance Considerations”Use Connection Marks for Efficiency
Section titled “Use Connection Marks for Efficiency”Wrong approach (CPU intensive):
# Every packet inspected/ip firewall mangle add chain=forward src-address=192.168.88.0/24 \ action=mark-packet new-packet-mark=lan_pktRight approach (efficient):
# First packet inspected, connection marked/ip firewall mangle add chain=forward connection-state=new src-address=192.168.88.0/24 \ action=mark-connection new-connection-mark=lan_conn# Subsequent packets use fast connection lookup/ip firewall mangle add chain=forward connection-mark=lan_conn \ action=mark-packet new-packet-mark=lan_pktRule Order Matters
Section titled “Rule Order Matters”- Place most frequently matched rules at the top
- Use
passthrough=nowhen no further matching is needed - Mark connections first, then derive packet marks
- Group related rules together to improve cache efficiency
FastTrack Interaction
Section titled “FastTrack Interaction”FastTrack bypasses firewall processing for marked connections. This is incompatible with:
- Policy routing (routing marks)
- Queue trees requiring packet marks
- Any mangle processing of established connections
To use mangle with FastTrack, exclude marked traffic:
/ip firewall filter add chain=forward connection-state=established,related \ connection-mark="" action=fasttrack-connectionCommon Mistakes
Section titled “Common Mistakes”Mistake 1: Using Wrong Chain
Section titled “Mistake 1: Using Wrong Chain”Wrong: Marking transit traffic in INPUT chain
# INPUT is for traffic TO the router, not through it/ip firewall mangle add chain=input src-address=192.168.88.0/24 action=mark-packet new-packet-mark=client_pktRight: Use FORWARD for transit traffic
/ip firewall mangle add chain=forward src-address=192.168.88.0/24 action=mark-packet new-packet-mark=client_pktMistake 2: Routing Marks in Wrong Chain
Section titled “Mistake 2: Routing Marks in Wrong Chain”Wrong: Setting routing mark after routing decision
# Routing decision already made - mark has no effect/ip firewall mangle add chain=forward action=mark-routing new-routing-mark=isp2Right: Set routing marks in PREROUTING
# Before routing decision - mark affects route selection/ip firewall mangle add chain=prerouting action=mark-routing new-routing-mark=isp2Mistake 3: Forgetting passthrough=no
Section titled “Mistake 3: Forgetting passthrough=no”Problem: Packet gets marked multiple times, wasting CPU
# All rules process because passthrough=yes (default)/ip firewall mangle add chain=forward protocol=tcp dst-port=80 action=mark-packet new-packet-mark=web/ip firewall mangle add chain=forward protocol=tcp dst-port=443 action=mark-packet new-packet-mark=https/ip firewall mangle add chain=forward action=mark-packet new-packet-mark=otherSolution: Add passthrough=no to terminal rules
/ip firewall mangle add chain=forward protocol=tcp dst-port=80 action=mark-packet new-packet-mark=web passthrough=no/ip firewall mangle add chain=forward protocol=tcp dst-port=443 action=mark-packet new-packet-mark=https passthrough=no/ip firewall mangle add chain=forward action=mark-packet new-packet-mark=other passthrough=noMistake 4: Not Using Connection Marks
Section titled “Mistake 4: Not Using Connection Marks”Inefficient: Inspecting every packet
/ip firewall mangle add chain=forward src-address=192.168.88.100 action=mark-packet new-packet-mark=client100Efficient: Mark connection once, then match connection mark
/ip firewall mangle add chain=forward connection-state=new src-address=192.168.88.100 \ action=mark-connection new-connection-mark=client100_conn/ip firewall mangle add chain=forward connection-mark=client100_conn \ action=mark-packet new-packet-mark=client100Related Topics
Section titled “Related Topics”Prerequisites
Section titled “Prerequisites”- IP Address Configuration - interface addressing fundamentals
- Static Routes - routing concepts for policy routing
Related Firewall Topics
Section titled “Related Firewall Topics”- Firewall Filter Basics - packet filtering (complementary to mangle)
- NAT Masquerade - NAT works with mangle marks
- Address Lists - address groups for mangle matching
Uses Mangle Marks
Section titled “Uses Mangle Marks”- Simple Queues - bandwidth limiting
- Queue Tree - advanced QoS using packet marks
Multi-WAN
Section titled “Multi-WAN”- DHCP Client - multi-WAN with mangle-based load balancing