Classification and matching — filters, match rules, fwmark, QoS classes
What you'll learn
- Explain packet classification (filter, match, fwmark)
- Configure VyOS QoS classes with match criteria
- Use fwmark for routing-policy-based classification
- Recognise the production failure modes of classification
Prerequisites
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling) · 2026-08-15
Packet classification is the process of matching packets to QoS classes. A filter rule specifies a match criterion (DSCP value, fwmark, source/destination IP, port, etc.); matching packets are placed in the corresponding class. The classifier is the bridge between packet-level details (markings, addresses) and QoS classes (which determine queueing and scheduling).
This lesson covers how classification works, the various match criteria (DSCP, fwmark, port, IP), how to configure classifiers on VyOS, and the production failure modes.
How classification works
The Linux kernel implements classification as part of the traffic control subsystem. A filter rule:
- Has a match criterion (e.g., DSCP = 46, fwmark = 0x1, destination IP).
- Specifies a target (the QoS class).
- Is attached to a qdisc (queueing discipline) on an interface.
When a packet arrives at the qdisc (typically on egress), the filter evaluates the match criterion. If the criterion matches, the packet is placed in the target class.
flowchart LR
PKT["Packet arrives at qdisc"]
FILT["Filter rules"]
DSCP["DSCP = 46?<br/>→ class voice"]
IP["dest IP = 10.0.0.0/8?<br/>→ class lan"]
FWM["fwmark = 0x1?<br/>→ class vpn"]
VOICE["Class voice"]
LAN["Class lan"]
VPN["Class vpn"]
PKT --> FILT
FILT --> DSCP
FILT --> IP
FILT --> FWM
DSCP --> VOICE
IP --> LAN
FWM --> VPN
Multiple filters may exist; the first matching filter wins. If no filter matches, the packet goes to the default class.
Match criteria
Several match criteria are available:
DSCP
Match on the DSCP value in the IP header. Useful when the packets are already marked (e.g., at the trust boundary). DSCP values: 0-63.
# Match packets with DSCP 46 (EF, voice)
set qos policy shaper WAN-OUT class voice match dscp 46
fwmark
Match on the firewall mark (fwmark) — an integer value (0-65535) set by iptables. Useful when the routing policy or firewall needs to mark packets for QoS.
# Set fwmark in the mangle table
set firewall ipv4 mangle rule 10 action accept
set firewall ipv4 mangle rule 10 protocol udp
set firewall ipv4 mangle rule 10 destination port 5060
set firewall ipv4 mangle rule 10 set fwmark 0x1
# Match fwmark in the QoS policy
set qos policy shaper WAN-OUT class voip match fwmark 0x1
Source/destination IP
Match on source/destination IP or subnet. Useful when the operator wants to prioritise specific subnets (e.g., server farm vs office LAN).
# Match packets from a specific subnet
set qos policy shaper WAN-OUT class lan-priority match source 10.0.0.0/24
Port
Match on source or destination port. Useful for marking specific applications.
# Match packets to port 5060 (SIP)
set qos policy shaper WAN-OUT class voip match destination port 5060
Configure classification on VyOS
A typical classification configuration:
configure
# Mark VoIP traffic with fwmark 0x1
set firewall ipv4 mangle rule 10 action accept
set firewall ipv4 mangle rule 10 protocol udp
set firewall ipv4 mangle rule 10 destination port 5060
set firewall ipv4 mangle rule 10 set fwmark 0x1
# Mark video traffic with fwmark 0x2
set firewall ipv4 mangle rule 20 action accept
set firewall ipv4 mangle rule 20 protocol tcp
set firewall ipv4 mangle rule 20 destination port 1720
set firewall ipv4 mangle rule 20 set fwmark 0x2
# Mark bulk traffic with fwmark 0x3
set firewall ipv4 mangle rule 30 action accept
set firewall ipv4 mangle rule 30 protocol tcp
set firewall ipv4 mangle rule 30 destination port 22
set firewall ipv4 mangle rule 30 set fwmark 0x3
# QoS policy with classes matching fwmark
set qos policy shaper WAN-OUT default bandwidth 1gbit
set qos policy shaper WAN-OUT default burst 15k
set qos policy shaper WAN-OUT default queue-type fq-codel
set qos policy shaper WAN-OUT class voip match fwmark 0x1
set qos policy shaper WAN-OUT class voip priority 0
set qos policy shaper WAN-OUT class voip queue-type fq-codel
set qos policy shaper WAN-OUT class voip ceiling 200mbit
set qos policy shaper WAN-OUT class video match fwmark 0x2
set qos policy shaper WAN-OUT class video priority 2
set qos policy shaper WAN-OUT class video queue-type fq-codel
set qos policy shaper WAN-OUT class video ceiling 300mbit
set qos policy shaper WAN-OUT class bulk match fwmark 0x3
set qos policy shaper WAN-OUT class bulk priority 7
set qos policy shaper WAN-OUT class bulk queue-type fq-codel
set interfaces ethernet eth0 traffic-policy out WAN-OUT
commit
save
The configuration:
- fwmark rules in the mangle table mark traffic based on protocol/port.
- QoS policy classes match on the fwmark.
- Apply to WAN interface for the egress direction.
Filter inspection
The Linux kernel implements classification as filters. To inspect the active filters:
# Inspect filters on the WAN interface
tc -s filter show dev eth0
# Inspect a specific filter
tc filter show dev eth0 parent 1:0
# Shows the filters attached to the root qdisc (parent 1:0 in HTB)
The output shows:
- The filter type (u32, fwmark, etc.).
- The match criteria.
- The action (target class).
For example:
filter parent 1:0 protocol ip pref 10 u32
filter parent 1:0 protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1:0 protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0
match IP protocol 17 0xff
match ip dport 5060 0xffff
police 0x3e8 rate 200mbit burst 15k mtu 2k action reclassify
classid 1:10
The output shows the filter matching IP protocol 17 (UDP) and destination port 5060; the action places the packet in class 1:10 (the voice class).
Validation
# Verify the fwmark rules
show firewall ipv4 mangle
iptables -t mangle -L -v
# Verify the QoS classes
tc class show dev eth0
tc filter show dev eth0
# Lists the classes and filters
# Test with traffic
# Generate traffic matching the class
iperf3 -c <server> -p 5060 # VoIP port (might not work; depends on server)
# Or just observe the counters
# Run traffic; observe `tc -s class show dev eth0` to see packet counts
A clean validation: the fwmark rules apply to matching traffic; the QoS classes see the matching packets; the counters increase under load.
Production failure modes
Filter match is wrong
The filter does not match the intended traffic. Cause: the match criterion is incorrect (e.g., wrong port, wrong IP, wrong fwmark value).
Diagnostic: tc -s filter show dev eth0 shows the filter match counters.
Fix: correct the match criterion.
Filter order issue
Multiple filters exist; the wrong one matches first. Cause: filter priority or order.
Diagnostic: tc -s filter show dev eth0 shows all filters with priorities.
Fix: adjust the filter priority (lower number = higher priority; processed first).
fwmark not propagated
The fwmark is set in the mangle table but is not visible to the QoS filter. Cause: the mangle table is on a different chain (FORWARD vs INPUT vs OUTPUT); the fwmark is not set when the QoS filter evaluates it.
Diagnostic: iptables -t mangle -L -v shows 0 matches on the fwmark rule.
Fix: ensure the mangle rule applies to the correct chain.
Multiple classes for the same traffic
Two classes match the same traffic. Cause: overlapping filters.
Diagnostic: tc -s class show dev eth0 shows traffic in two classes.
Fix: ensure the filters are mutually exclusive; only one filter should match each packet.
Classification on the wrong interface
The QoS policy is applied to the wrong interface (e.g., on eth1 instead of eth0). The traffic is not classified correctly.
Fix: apply the policy to the correct interface (typically the WAN egress).
Rollback
# Enter configuration mode and write the running configuration to a
# file you can load back. `save` is a configuration-mode command that
# takes a path; operational mode has no `| save` pipe.
configure
save /config/pre-change-qos-classify-TICKET.conf
# Remove the classification rules
delete qos policy shaper WAN-OUT
delete firewall ipv4 mangle rule 10
delete firewall ipv4 mangle rule 20
delete firewall ipv4 mangle rule 30
# Read the diff before committing anything
compare
commit
# Or restore a previous configuration
load /config/pre-change-qos-classify-TICKET.conf
commit
save
The rollback removes the QoS policy and the classification rules; traffic is no longer classified.
Production discipline
Cross-course references
- Part XLV-01 (
XLV-VyOS-QoS/ concept) covers the overall QoS pipeline. - Part XLV-02 (
XLV-VyOS-QoS/ DSCP marking) covers DSCP marking, which classification matches on. - Part XLV-04 (
XLV-VyOS-QoS/ queuing and shaping) covers the queueing discipline.
Quiz
Knowledge check · 4 questions
Q1. What is the role of fwmark in QoS classification?
Q2. In Linux tc, filters are processed in priority order; lower numeric priority (e.g., 1) is processed before higher priority (e.g., 10).
Q3. An operator configures a QoS policy with a class matching fwmark 0x1. The mangle table has a rule that sets fwmark 0x1 for VoIP traffic. However, the QoS class sees no packets. What is the issue?
The mangle rule sets fwmark 0x1 in the POSTROUTING chain. The QoS filter matches on fwmark 0x1 on the WAN egress interface. However, the mangle rule does not apply because the traffic goes through the mangle table BEFORE the QoS filter evaluates. The traffic leaves with fwmark 0x1 — but the QoS filter on the WAN interface does not see packets because the packets are bridged or routed before the mangle rule applies.
Q4. An operator configures a QoS policy. The voice class has fwmark 0x1, set by a mangle rule for UDP port 5060. The voice class is consistently full of packets, but the voice traffic rate is well below the class's ceiling. What is wrong?
The mangle rule marks UDP port 5060 with fwmark 0x1. The voice class matches fwmark 0x1. However, the voice class is full. The expected voice traffic (RTP streams on dynamic ports) is on UDP ports 16384-32767, not on port 5060 (which is just the SIP control signalling). The mangle rule only marks SIP signalling, not the actual voice media.
Passing score: 75%. Answers are checked in this browser.