QoS (Quality of Service) is often misunderstood. People expect it to “make the internet faster.” It doesn’t. QoS is about managing scarcity — when there’s not enough bandwidth for everyone, QoS decides who gets priority.
The key insight: QoS only works when you control the bottleneck. If your ISP is the bottleneck, traffic shaping on your router shapes what leaves your network, not what your ISP does. Understanding this is crucial for effective QoS.
Understanding the Problem: Bufferbloat
Modern networks have a hidden enemy: bufferbloat. Network devices have large buffers that queue packets when congested. Large buffers = high latency during congestion.
Scenario: You’re on a video call. Someone starts a large download. Suddenly your call has 500ms latency because packets are stuck in buffers behind download packets.
QoS solves this by:
- Shaping traffic below the actual link speed (to control where queuing happens)
- Prioritizing latency-sensitive traffic
- Using smart queue disciplines that prevent buffer buildup
Measuring the Problem
Before configuring QoS, measure your baseline:
# Test bufferbloat (from client, while running a speed test)ping 8.8.8.8
# Watch for latency increase during upload/download# Normal: ~20ms, Bufferbloat: 200-1000msOr use the Bufferbloat test — it specifically measures latency under load.
VyOS Traffic Shaping Basics
VyOS uses Linux tc (traffic control) under the hood. Two main components:
Shaper: Limits overall bandwidth Classes/Queues: Divide bandwidth among traffic types
configure
# Basic traffic shaping on WAN interfaceset traffic-policy shaper WAN-OUT bandwidth '95mbit'set traffic-policy shaper WAN-OUT default bandwidth '50%'set traffic-policy shaper WAN-OUT default ceiling '100%'set traffic-policy shaper WAN-OUT default queue-type 'fq-codel'
# Apply to outbound on WAN interfaceset interfaces ethernet eth0 traffic-policy out 'WAN-OUT'
commitKey points:
- bandwidth ‘95mbit’: Total shaper bandwidth. Set this ~95% of your actual upload speed
- fq-codel: Fair Queue with Controlled Delay — fights bufferbloat
- ceiling ‘100%’: Can burst to full bandwidth if available
Why 95% of Your Actual Speed?
If your upload is 100Mbps and you shape at 100Mbps, congestion still happens at your ISP’s edge. You’re not controlling the bottleneck.
Shape at 95Mbps (or even 90Mbps for very stable latency), and congestion happens at your router, where you control the queue. Your router’s smart queue (fq-codel) manages latency instead of your ISP’s dumb FIFO buffer.
Traffic Classes: Prioritizing Different Traffic
configure
# Create shaper with classesset traffic-policy shaper WAN-OUT bandwidth '95mbit'
# Voice/Video - highest priority, guaranteed bandwidthset traffic-policy shaper WAN-OUT class 10 bandwidth '20%'set traffic-policy shaper WAN-OUT class 10 ceiling '50%'set traffic-policy shaper WAN-OUT class 10 priority '0'set traffic-policy shaper WAN-OUT class 10 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 10 match VOIP ip dscp 'ef'
# Interactive (SSH, gaming) - high priorityset traffic-policy shaper WAN-OUT class 20 bandwidth '10%'set traffic-policy shaper WAN-OUT class 20 ceiling '100%'set traffic-policy shaper WAN-OUT class 20 priority '1'set traffic-policy shaper WAN-OUT class 20 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 20 match SSH ip protocol 'tcp'set traffic-policy shaper WAN-OUT class 20 match SSH ip destination port '22'
# Web browsing - normal priorityset traffic-policy shaper WAN-OUT class 30 bandwidth '30%'set traffic-policy shaper WAN-OUT class 30 ceiling '100%'set traffic-policy shaper WAN-OUT class 30 priority '3'set traffic-policy shaper WAN-OUT class 30 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 30 match HTTP ip protocol 'tcp'set traffic-policy shaper WAN-OUT class 30 match HTTP ip destination port '80,443'
# Bulk downloads - lowest priorityset traffic-policy shaper WAN-OUT class 40 bandwidth '20%'set traffic-policy shaper WAN-OUT class 40 ceiling '90%'set traffic-policy shaper WAN-OUT class 40 priority '5'set traffic-policy shaper WAN-OUT class 40 queue-type 'fq-codel'
# Default for unclassified trafficset traffic-policy shaper WAN-OUT default bandwidth '20%'set traffic-policy shaper WAN-OUT default ceiling '100%'set traffic-policy shaper WAN-OUT default priority '4'set traffic-policy shaper WAN-OUT default queue-type 'fq-codel'
set interfaces ethernet eth0 traffic-policy out 'WAN-OUT'
commitUnderstanding the Parameters
bandwidth: Guaranteed minimum bandwidth for this class ceiling: Maximum bandwidth when other classes aren’t using theirs priority: Lower number = higher priority (0 is highest) queue-type: Algorithm for managing the queue
Bandwidth percentages should roughly add up to 100%. The ceiling allows classes to borrow unused bandwidth.
Queue Types: fq-codel vs Others
fq-codel (Fair Queue Controlled Delay): Best for most cases. Maintains low latency, fair sharing between flows. Use this unless you have specific needs.
sfq (Stochastic Fair Queue): Simpler, less effective at latency control. Legacy option.
pfifo/bfifo: Simple FIFO queues. Don’t fight bufferbloat. Avoid.
cake: Advanced shaper (may need additional packages). Even better than fq-codel for some scenarios.
# If cake is availableset traffic-policy shaper WAN-OUT default queue-type 'cake'Inbound Shaping: The Hard Problem
You can’t directly control inbound traffic — it’s already at your doorstep. But you can:
- Police incoming traffic: Drop/mark packets exceeding rate
- Use ingress shaping: Shape traffic after it arrives
- Rely on TCP feedback: Shaping outbound ACKs affects inbound TCP rate
configure
# Ingress policing on WAN interfaceset traffic-policy limiter WAN-IN class 10 bandwidth '95mbit'set traffic-policy limiter WAN-IN class 10 match ALL ip source address '0.0.0.0/0'set traffic-policy limiter WAN-IN default bandwidth '95mbit'
set interfaces ethernet eth0 traffic-policy in 'WAN-IN'
commitThis is less precise than outbound shaping. For better download QoS, shape slightly below your download speed and let fq-codel manage queuing.
Practical Examples
Home Office: Prioritize Video Calls
# Identify video call traffic (Zoom, Teams, etc use UDP on various ports)set traffic-policy shaper WAN-OUT class 10 match VIDEO-UDP ip protocol 'udp'set traffic-policy shaper WAN-OUT class 10 match VIDEO-UDP ip destination port '3478-3481,8801-8810,19302-19309'
# Give video 30% guaranteed, can burst to 60%set traffic-policy shaper WAN-OUT class 10 bandwidth '30%'set traffic-policy shaper WAN-OUT class 10 ceiling '60%'set traffic-policy shaper WAN-OUT class 10 priority '0'Gaming: Low Latency
# Gaming often uses specific ports (varies by game)set traffic-policy shaper WAN-OUT class 15 match GAMING ip protocol 'udp'set traffic-policy shaper WAN-OUT class 15 match GAMING ip source port '1024-65535'set traffic-policy shaper WAN-OUT class 15 bandwidth '15%'set traffic-policy shaper WAN-OUT class 15 ceiling '50%'set traffic-policy shaper WAN-OUT class 15 priority '0'
# Also prioritize small packets (often game updates)set traffic-policy shaper WAN-OUT class 15 match SMALL ip ip-length '<256'Torrent/Backup Deprioritization
# Bulk traffic class - low priorityset traffic-policy shaper WAN-OUT class 50 bandwidth '10%'set traffic-policy shaper WAN-OUT class 50 ceiling '80%'set traffic-policy shaper WAN-OUT class 50 priority '7'
# Match by ports commonly used by bulk transfersset traffic-policy shaper WAN-OUT class 50 match TORRENT ip destination port '6881-6889'DSCP Marking
DSCP (Differentiated Services Code Point) is a field in IP header used to classify traffic. Many applications set DSCP; you can use it for classification:
# Match on DSCP values set by applicationsset traffic-policy shaper WAN-OUT class 10 match VOICE ip dscp 'ef'set traffic-policy shaper WAN-OUT class 20 match VIDEO ip dscp 'af41'Common DSCP values:
- EF (46): Expedited Forwarding - voice
- AF41 (34): Assured Forwarding - video
- AF21 (18): Assured Forwarding - business critical
- CS1 (8): Scavenger - bulk/background
You can also mark traffic yourself:
# Mark VoIP traffic with EFset firewall ipv4 name MARK-QOS rule 10 action 'accept'set firewall ipv4 name MARK-QOS rule 10 protocol 'udp'set firewall ipv4 name MARK-QOS rule 10 destination port '5060'set firewall ipv4 name MARK-QOS rule 10 set dscp 'ef'Monitoring QoS
# Show current traffic policy statisticsshow queueing interface eth0
# Show class statisticstc -s class show dev eth0
# Watch queue lengthswatch tc -s qdisc show dev eth0Look for:
- drops: Some drops are normal (fq-codel drops to signal congestion)
- backlogs: Should be low, high backlog = buffer building up
- overlimits: Traffic exceeding class bandwidth (borrowing from ceiling)
Debugging QoS Issues
Traffic Not Being Classified
# Most traffic in default class? Check your matchesshow queueing interface eth0If priority traffic isn’t getting classified, verify:
- Port/protocol matches are correct
- Traffic isn’t using unexpected ports (HTTPS multiplexes everything over 443)
- Match rules are specific enough
Latency Still High
- Shaper bandwidth too high: Lower it (try 90% of link speed)
- Not using fq-codel: Change queue-type
- Inbound is the problem: Need ingress shaping too
- ISP QoS: Your ISP might have their own queuing
VoIP Quality Still Poor
- Jitter buffer: Some jitter is handled by endpoints
- Packet loss: Check
show queueingfor excessive drops - Misclassified traffic: Verify VoIP is hitting the right class
Complete QoS Configuration
# === Traffic Policy ===set traffic-policy shaper WAN-OUT bandwidth '95mbit'
# Voice/Video - highest priorityset traffic-policy shaper WAN-OUT class 10 bandwidth '20%'set traffic-policy shaper WAN-OUT class 10 ceiling '50%'set traffic-policy shaper WAN-OUT class 10 priority '0'set traffic-policy shaper WAN-OUT class 10 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 10 match VOIP ip dscp 'ef'set traffic-policy shaper WAN-OUT class 10 match REALTIME ip protocol 'udp'set traffic-policy shaper WAN-OUT class 10 match REALTIME ip destination port '3478-3481,5060,16384-32767'
# Interactiveset traffic-policy shaper WAN-OUT class 20 bandwidth '15%'set traffic-policy shaper WAN-OUT class 20 ceiling '100%'set traffic-policy shaper WAN-OUT class 20 priority '1'set traffic-policy shaper WAN-OUT class 20 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 20 match SSH ip protocol 'tcp'set traffic-policy shaper WAN-OUT class 20 match SSH ip destination port '22'set traffic-policy shaper WAN-OUT class 20 match DNS ip protocol 'udp'set traffic-policy shaper WAN-OUT class 20 match DNS ip destination port '53'
# Webset traffic-policy shaper WAN-OUT class 30 bandwidth '35%'set traffic-policy shaper WAN-OUT class 30 ceiling '100%'set traffic-policy shaper WAN-OUT class 30 priority '3'set traffic-policy shaper WAN-OUT class 30 queue-type 'fq-codel'set traffic-policy shaper WAN-OUT class 30 match WEB ip protocol 'tcp'set traffic-policy shaper WAN-OUT class 30 match WEB ip destination port '80,443'
# Bulkset traffic-policy shaper WAN-OUT class 40 bandwidth '10%'set traffic-policy shaper WAN-OUT class 40 ceiling '80%'set traffic-policy shaper WAN-OUT class 40 priority '6'set traffic-policy shaper WAN-OUT class 40 queue-type 'fq-codel'
# Defaultset traffic-policy shaper WAN-OUT default bandwidth '20%'set traffic-policy shaper WAN-OUT default ceiling '100%'set traffic-policy shaper WAN-OUT default priority '4'set traffic-policy shaper WAN-OUT default queue-type 'fq-codel'
# === Apply ===set interfaces ethernet eth0 traffic-policy out 'WAN-OUT'The Lesson
QoS works when you understand the bottleneck:
- Shape below link speed: This moves the bottleneck to your router where you control queuing
- Use smart queues (fq-codel): They maintain low latency automatically
- Prioritize appropriately: Not everything can be high priority — that’s just no priority
The goal isn’t faster internet — it’s predictable internet. Video calls that don’t stutter when someone starts a download. SSH that stays responsive during backups. Gaming that doesn’t spike during updates.
Test before and after. Measure latency under load. If it doesn’t improve, you haven’t identified the real bottleneck yet.