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