QoS and Traffic Shaping
Why QoS?
Section titled “Why QoS?”Networks have finite bandwidth. When the pipe is full, packets queue and then get dropped - this affects all traffic equally by default. Quality of Service (QoS) lets you prioritize some traffic over others, ensuring critical traffic (VoIP calls, video conferencing) isn’t degraded by bulk traffic (backups, downloads).
Without QoS: With QoS:┌────────────────┐ ┌────────────────┐│ VoIP (20 Kbps) │ ──mix──▶ 🚧 │ VoIP (20 Kbps) │ ──fast lane──▶ ✅│ Backup (100Mbps│ │ Backup (100Mbps) │ ──slow lane──▶ ✅│ All suffer! │ │ Both work! │└────────────────┘ └────────────────┘DSCP - Differentiated Services Code Point
Section titled “DSCP - Differentiated Services Code Point”DSCP is a 6-bit field in the IP header (within the former Type of Service byte). Routers read this field to determine how to treat the packet. The sender marks the packet, and every router along the path can honor that marking.
IPv4 Header - Type of Service (ToS) Byte:┌──────────────────────────┬─────┬───┐│ DSCP (6 bits) │ ECN │ ││ Differentiated Services │ (2b)│ │└──────────────────────────┴─────┴───┘DSCP Classes (Per-Hop Behaviors)
Section titled “DSCP Classes (Per-Hop Behaviors)”| PHB | DSCP Value | Binary | Traffic Type | Drop Probability |
|---|---|---|---|---|
| Default (BE) | 0 | 000000 | Best Effort - no priority | Standard |
| CS1 | 8 | 001000 | Background (lower than default) | High |
| AF11 | 10 | 001010 | Bulk data - low priority | Low |
| AF21 | 18 | 010010 | Bulk data - medium priority | Low |
| AF31 | 26 | 011010 | Business critical apps | Low |
| AF41 | 34 | 100010 | Video conferencing | Low |
| CS5 | 40 | 101000 | Signaling | Low |
| EF | 46 | 101110 | Expedited Forwarding - VoIP | Very Low |
| CS6 | 48 | 110000 | Network control (routing protocols) | Very Low |
| CS7 | 56 | 111000 | Network management | Very Low |
QoS Mechanisms
Section titled “QoS Mechanisms”1. Classification and Marking
Section titled “1. Classification and Marking”Before a packet can be prioritized, it must be identified:
| Method | How |
|---|---|
| DSCP/TOS marking | Read the DSCP field set by the sender |
| Port-based | TCP/UDP port number (SSH=22, SIP=5060) |
| IP address | Source or destination IP |
| Protocol | TCP, UDP, ICMP |
| Deep Packet Inspection (DPI) | Look inside the payload (detects apps using non-standard ports) |
2. Queuing
Section titled “2. Queuing”Queuing determines what to do when the link is congested:
| Algorithm | How it works | Best for |
|---|---|---|
| FIFO (First In, First Out) | No priority, pure order | Simple links, no QoS |
| WFQ (Weighted Fair Queuing) | Multiple queues, each gets bandwidth share | General QoS |
| CBWFQ (Class-Based WFQ) | Admin-defined classes each get minimum bandwidth % | Enterprise QoS |
| LLQ (Low-Latency Queuing) | Strict priority queue for real-time + CBWFQ for rest | VoIP environments |
| HTB (Hierarchical Token Bucket) | Linux’s class-based queuing | Linux servers/routers |
| HFSC | Hierarchical fair service curves | Complex multi-class scenarios |
3. Shaping vs Policing
Section titled “3. Shaping vs Policing”| Mechanism | What it does | Effect on excess |
|---|---|---|
| Traffic Shaping | Buffers excess traffic and sends later (smooth the burst) | Delay (no drop if buffer not full) |
| Traffic Policing | Drops or re-marks packets exceeding the rate | Drop or DSCP downgrade |
Shaping: ████░░████░░████ → ██████████████ (smoothed, delayed)
Policing: ████░░████░░████ → ████ ████ (excess dropped)Linux Traffic Control (tc)
Section titled “Linux Traffic Control (tc)”The tc command (from iproute2) implements QoS on Linux. It can:
- Set up queuing disciplines (qdiscs)
- Create traffic classes
- Add filters to classify traffic
Basic Rate Limiting with HTB
Section titled “Basic Rate Limiting with HTB”# Limit outbound traffic to 10 Mbit/s totalsudo tc qdisc add dev eth0 root handle 1: htb default 10
# Add a class with 10 Mbit/s ceilingsudo tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit
# Apply to all traffic on eth0sudo tc filter add dev eth0 protocol ip parent 1:0 u32 match ip dst 0.0.0.0/0 flowid 1:10
# View current qdisc setuptc qdisc show dev eth0tc class show dev eth0tc filter show dev eth0Priority Queuing - VoIP First
Section titled “Priority Queuing - VoIP First”# Create 3-priority prio qdiscsudo tc qdisc add dev eth0 root handle 1: prio priomap 0 0 0 0 1 1 1 1 2 2 2 2 2 2 2 2
# Band 0 (highest) = DSCP EF (VoIP)# Band 1 (medium) = DSCP AF# Band 2 (lowest) = best effort
# Filter: DSCP 46 (EF) → priority band 0sudo tc filter add dev eth0 parent 1:0 protocol ip handle 0x2e/0xfc fw flowid 1:1
# View stats (bytes/packets per queue)tc -s qdisc show dev eth0Simple Bandwidth Cap with Token Bucket Filter
Section titled “Simple Bandwidth Cap with Token Bucket Filter”# Limit a single IP to 1 Mbit/s (rate limiting for a client)sudo tc qdisc add dev eth0 root handle 1: htb default 10sudo tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit # default classsudo tc class add dev eth0 parent 1: classid 1:20 htb rate 1mbit # limited class
# Filter: traffic to 192.168.1.100 → limited classsudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 \ u32 match ip dst 192.168.1.100/32 flowid 1:20
# Clean upsudo tc qdisc del dev eth0 rootMarking with iptables
Section titled “Marking with iptables”# Mark packets for QoS classification using iptables (DSCP marking)
# Mark all SSH traffic as DSCP CS6 (network control)sudo iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp-class CS6
# Mark VoIP (SIP port 5060) as EFsudo iptables -t mangle -A OUTPUT -p udp --dport 5060 -j DSCP --set-dscp 46
# Mark backup traffic as CS1 (background, below best-effort)sudo iptables -t mangle -A OUTPUT -p tcp --dport 873 -j DSCP --set-dscp-class CS1 # rsync
# View marked packetssudo iptables -t mangle -L OUTPUT -n -vTroubleshooting QoS
Section titled “Troubleshooting QoS”# Check if packets are being queued/droppedtc -s qdisc show dev eth0# Output includes: sent X bytes X pkt (dropped X, overlimits X requeues X)
# Check DSCP markings on packets leaving your machinesudo tcpdump -nn -i eth0 -e 'ip[1] & 0xfc != 0'# Shows all packets where DSCP != 0 (i.e., marked packets)
# Monitor per-class traffic rateswatch -n 1 'tc -s class show dev eth0'
# ss - check for large receive queues (signs of congestion)ss -tnp | awk 'NR>1 && $2+0 > 0 {print "Recv-Q:", $2, $5}'Bufferbloat
Section titled “Bufferbloat”Bufferbloat happens when routers/modems have excessively large buffers. Traffic doesn’t get dropped fast enough, so it sits in the buffer causing high latency:
No buffer bloat: 20ms RTTWith bufferbloat: 500ms RTT (buffer filling = 480ms of queued data)Fix: CoDel (Controlled Delay) or FQ-CoDel manages queues intelligently:
# Replace default qdisc with FQ-CoDel (reduced bufferbloat)sudo tc qdisc replace dev eth0 root fq_codel
# Or cake (even better, does fairness + bufferbloat management together)sudo tc qdisc replace dev eth0 root cake bandwidth 100mbit