| |

LFCE 87 ๐Ÿง QoS โ€” Priority and Queuing

โฑ๏ธ Estimated read: 15 min | |

Quality of Service on Linux is the practice of classifying traffic into different priority levels and queuing each level according to its latency and bandwidth requirements. The previous chapter covered shaping and policing, which enforce a rate on a single stream or interface. This chapter covers the queuing disciplines and classifiers that divide the interface’s bandwidth among multiple traffic classes, giving latency-sensitive trafficโ€”VoIP, SSH, DNSโ€”a higher priority than bulk transfers. The LFCE exam expects the candidate to monitor and tune network performance, and QoS is the toolset that makes priority-based tuning possible .

The priority and queuing mechanisms are the prio qdisc for simple priority ordering and the htb qdisc for hierarchical bandwidth guarantees with priority inheritance. The prio qdisc is a scheduler that never delays packets; it dequeues the higher-priority bands first and only serves the lower bands when the higher ones are empty . The htb qdisc is a shaper that guarantees a minimum rate to each class and allows borrowing up to a ceiling, and its prio parameter determines which class is served first when multiple classes have packets to send . The filtersโ€”u32, flower, and fwโ€”classify the packets into the classes.

Key point: The prio qdisc has a fixed number of bands created at qdisc creation time, and band 0 is tried first, band 1 second, and so on. It is a work-conserving scheduler, which means it does not shape or delay traffic; it only orders the dequeue. The htb qdisc has a prio parameter on each class, and the classes with the lowest priority number are tried first in the round-robin process. The htb qdisc also has a default class that receives the unclassified packets, and the filters that classify the packets must be attached to the root qdisc, not to the child classes .


Why QoS requires explicit classification and queuing

The unclassified-default problem.

Every packet that enters a classful qdisc must be classified into one of its classes. If no filter matches, the packet goes to the qdisc’s default class. For htb, the default parameter is mandatory in the sense that the unclassified traffic must have a destination, and the default class is usually the bulk class with the lowest guarantee . The filters that classify the traffic are attached to the root qdisc, and a common mistake is to attach them to a child class, where they never match because the packet is enqueued at the root and dequeued from the leaf.

The priority-inheritance problem.

The htb qdisc’s prio parameter is the priority within the parent class. When the parent has bandwidth to distribute, it tries the classes with the lowest priority number first. The prio qdisc, by contrast, has bands that are always dequeued in order, and the band 0 always wins when it has a packet . The htb priority is a preference within the borrowing process, and the prio band is a strict order. The choice depends on whether the goal is to guarantee bandwidth with a preference (htb) or to strictly order the traffic by latency (prio).

The leaf-qdisc problem.

Each htb class has a leaf qdisc attached to it, and the default leaf is pfifo. The leaf qdisc determines how the packets within the class are queued. A class that carries latency-sensitive traffic should have a fq_codel or pfifo leaf, and a class that carries bulk traffic should have a fq_codel leaf for fairness . The leaf qdisc is the last stage before the packet is transmitted, and it determines the queueing behavior within the class.


a. The prio qdisc for strict priority

The prio qdisc is the simplest priority mechanism. It creates a fixed number of bands, and the bands are dequeued in order.

# Create a prio qdisc with three bands
sudo tc qdisc add dev eth0 root handle 1: prio bands 3

# The bands are 1:1, 1:2, and 1:3
# Band 1:1 is the highest priority

The bands 3 parameter creates three classes: 1:1, 1:2, and 1:3. The band 1:1 is tried first, then 1:2, then 1:3 . The priomap parameter maps the packet’s TOS field to a band, and the default priomap sends the normal traffic to band 1 (the middle band) and the minimize-delay traffic to band 2 (the lowest priority, which is counterintuitive). The tc filter command overrides the priomap for the specific traffic.

# Send SSH traffic to band 1:1 (highest priority)
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip dport 22 0xffff flowid 1:1

# Send DNS traffic to band 1:1
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \
  match ip dport 53 0xffff flowid 1:1

# Send HTTP traffic to band 1:2 (normal priority)
sudo tc filter add dev eth0 parent 1: protocol ip prio 2 u32 \
  match ip dport 80 0xffff flowid 1:2

The flowid 1:1 sends the matching packets to the highest-priority band. The prio 1 on the filter determines the filter evaluation order, not the band priority . The unmatched packets go to the band that the priomap assigns, which is typically band 1 for the normal traffic.

The prio qdisc is a scheduler, not a shaper. It does not limit the rate of any band, and it does not delay the packets unless the lower-priority bands have to wait for the higher-priority bands to empty. It is the correct choice when the goal is to reduce latency for the critical traffic without guaranteeing a specific bandwidth.


b. The htb qdisc for guaranteed bandwidth and priority

The htb qdisc is the hierarchical shaper that guarantees a minimum rate to each class and allows borrowing. The prio parameter on each class determines the order in which the classes are served when the parent has bandwidth to distribute.

# Create the HTB root qdisc with a default class
sudo tc qdisc add dev eth0 root handle 1: htb default 30

# Root class: 100 Mbps total
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

# Critical class: 40 Mbps guaranteed, priority 1
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb \
  rate 40mbit ceil 100mbit prio 1

# Interactive class: 40 Mbps guaranteed, priority 2
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb \
  rate 40mbit ceil 100mbit prio 2

# Bulk class: 20 Mbps guaranteed, priority 3
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb \
  rate 20mbit ceil 100mbit prio 3

The rate is the guaranteed minimum, and the ceil is the maximum that the class can send when the parent has spare bandwidth . The prio 1 on the critical class means it is tried first in the round-robin process. The prio 2 on the interactive class means it is tried second, and the prio 3 on the bulk class means it is tried last. The default 30 sends the unclassified packets to the bulk class.

The leaf qdiscs are attached to each class. The fq_codel leaf is the recommended choice for the interactive and bulk classes because it provides fair queueing and low latency within the class.

# Add fq_codel leaf qdiscs to each class
sudo tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
sudo tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
sudo tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

The parent 1:10 attaches the leaf qdisc to the critical class. The handle 10: is the leaf qdisc’s handle, which is used to reference it in the statistics . The leaf qdisc is the last stage before the packet is transmitted, and it determines the queueing behavior within the class.


c. The filters for classification

The filters classify the packets into the classes. The u32 filter is the most common for port-based classification, and the flower filter is the newer alternative with a simpler syntax for the common matches.

# SSH traffic to the critical class
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 \
  match ip dport 22 0xffff flowid 1:10

# DNS traffic to the critical class
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 \
  match ip dport 53 0xffff flowid 1:10

# HTTP and HTTPS traffic to the interactive class
sudo tc filter add dev eth0 protocol ip parent 1: prio 2 u32 \
  match ip dport 80 0xffff flowid 1:20

sudo tc filter add dev eth0 protocol ip parent 1: prio 2 u32 \
  match ip dport 443 0xffff flowid 1:20

The parent 1: attaches the filter to the root qdisc. The prio 1 on the filter is the filter’s evaluation order, and the filters with the lower prio number are evaluated first . The flowid 1:10 sends the matching packets to the critical class. The unmatched packets go to the default class, which is the bulk class.

The flower filter is the alternative with a simpler syntax for the common matches.

# SSH traffic to the critical class with flower
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 flower \
  ip_proto tcp dst_port 22 classid 1:10

The ip_proto tcp dst_port 22 matches the TCP destination port 22, and the classid 1:10 sends the matching packets to the critical class . The flower filter is less flexible than u32 for the arbitrary packet offsets, but it is simpler for the port and address matches that are the most common in QoS configurations.

The fw filter matches the firewall mark that iptables or nftables has set on the packet. It is the mechanism that connects the firewall’s classification to the traffic control’s scheduling.

# Mark the RTP audio traffic with iptables
sudo iptables -t mangle -A POSTROUTING -o eth0 -p udp --dport 10000:20000 -j MARK --set-mark 10

# Classify the marked traffic with tc
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 handle 10 fw classid 1:10

The --set-mark 10 sets the firewall mark on the matching packets, and the handle 10 fw matches the packets with that mark . The classid 1:10 sends them to the critical class. The fw filter is the correct choice when the classification depends on criteria that the u32 or flower filters cannot express, such as the connection state or the application-layer protocol.


Complete Example Session

# ============================================
# PART 1: CREATE THE HTB ROOT QDISC
# ============================================
sudo tc qdisc add dev eth0 root handle 1: htb default 30

# ============================================
# PART 2: CREATE THE ROOT CLASS
# ============================================
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

# ============================================
# PART 3: CREATE THE PRIORITY CLASSES
# ============================================
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 100mbit prio 1
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 40mbit ceil 100mbit prio 2
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 20mbit ceil 100mbit prio 3

# ============================================
# PART 4: ADD THE LEAF QDISCS
# ============================================
sudo tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
sudo tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
sudo tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

# ============================================
# PART 5: ADD THE FILTERS
# ============================================
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 22 0xffff flowid 1:10
sudo tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dport 53 0xffff flowid 1:10
sudo tc filter add dev eth0 protocol ip parent 1: prio 2 u32 match ip dport 80 0xffff flowid 1:20
sudo tc filter add dev eth0 protocol ip parent 1: prio 2 u32 match ip dport 443 0xffff flowid 1:20

# ============================================
# PART 6: VERIFY THE CONFIGURATION
# ============================================
tc qdisc show dev eth0
tc class show dev eth0
tc filter show dev eth0

# ============================================
# PART 7: CHECK THE STATISTICS
# ============================================
tc -s class show dev eth0
# Output shows the packets and bytes per class

The seven parts demonstrate the QoS configuration: the HTB root qdisc, the root class, the priority classes, the leaf qdiscs, the filters, the verification, and the statistics. The critical distinction is between Parts 3 and 5: the classes define the bandwidth guarantees and the priority, and the filters route the traffic into the classes.


Quick Reference

Qdisc Comparison

QdiscTypePriority MechanismBandwidth Guarantee
prioClassfulFixed bands, dequeued in orderNone
htbClassfulprio parameter on each classrate and ceil
fq_codelClasslessFair queueingNone

htb Class Parameters

ParameterPurposeExample
rateGuaranteed minimumrate 40mbit
ceilMaximum with borrowingceil 100mbit
prioPriority within parentprio 1
burstBurst at ceilburst 15k

Filter Types

FilterUse CaseExample
u32Arbitrary packet fieldsmatch ip dport 22 0xffff
flowerSimple port/address matchesip_proto tcp dst_port 22
fwFirewall markhandle 10 fw

Verification Commands

CommandPurpose
tc qdisc show dev eth0Show the qdisc
tc class show dev eth0Show the classes
tc filter show dev eth0Show the filters
tc -s class show dev eth0Show the class statistics

Best Practices

โœ… Do This:

# Use HTB for guaranteed bandwidth and priority
tc qdisc add dev eth0 root handle 1: htb default 30            # โœ…

# Set the rate and ceil per class
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 100mbit prio 1 # โœ…

# Attach fq_codel to each class
tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel          # โœ…

# Attach filters to the root qdisc
tc filter add dev eth0 parent 1: u32 match ip dport 22 0xffff flowid 1:10 # โœ…

# Use the fw filter for connection-state-based classification
tc filter add dev eth0 parent 1: handle 10 fw classid 1:10     # โœ…

# Check the statistics
tc -s class show dev eth0                                      # โœ…

โŒ Don’t Do This:

# Attach filters to a child class
tc filter add dev eth0 parent 1:10 ...    # Never matches         # โŒ

# Forget the default class on HTB
tc qdisc add dev eth0 root handle 1: htb    # Unclassified traffic # โŒ

# Use prio for bandwidth guarantees
tc qdisc add dev eth0 root handle 1: prio   # No rate control     # โŒ

# Set rate equal to ceil for every class
# The classes cannot borrow; the sum must fit the parent          # โŒ

# Forget the leaf qdiscs
# The default pfifo is used, which may not be optimal             # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Class receives no trafficFilters not attached to the rootAttach to parent 1:
Unclassified traffic droppedNo default classAdd default parameter
Priority not respectedprio parameter missing or wrongSet prio 1 on the high-priority class
Bandwidth exceededSum of rates exceeds parentKeep the sum below the parent rate
Leaf qdisc not usedNo leaf qdisc attachedAttach fq_codel to each class

Real-World Examples

1. HTB root with default

tc qdisc add dev eth0 root handle 1: htb default 30

2. Root class

tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

3. High-priority class

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 100mbit prio 1

4. Low-priority class

tc class add dev eth0 parent 1:1 classid 1:30 htb rate 20mbit ceil 100mbit prio 3

5. Leaf qdisc

tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel

6. SSH filter

tc filter add dev eth0 parent 1: prio 1 u32 match ip dport 22 0xffff flowid 1:10

7. HTTP filter

tc filter add dev eth0 parent 1: prio 2 u32 match ip dport 80 0xffff flowid 1:20

8. Flower filter

tc filter add dev eth0 parent 1: prio 1 flower ip_proto tcp dst_port 22 classid 1:10

9. Firewall mark filter

tc filter add dev eth0 parent 1: handle 10 fw classid 1:10

10. Class statistics

tc -s class show dev eth0

Visual

Priority Queuing with prio

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  PRIO DEQUEUES BAND 0 FIRST, THEN BAND 1, THEN BAND 2        โ”‚
โ”‚                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Band 1:1 (highest priority)                            โ”‚  โ”‚
โ”‚  โ”‚ โ†’ dequeued first when it has packets                   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Band 1:2 (normal priority)                             โ”‚  โ”‚
โ”‚  โ”‚ โ†’ dequeued when band 1:1 is empty                      โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Band 1:3 (lowest priority)                             โ”‚  โ”‚
โ”‚  โ”‚ โ†’ dequeued when bands 1:1 and 1:2 are empty            โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  The prio qdisc is work-conserving; it does not shape.       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

HTB Hierarchy with Priority

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  HTB GUARANTEES RATE AND HONORS PRIORITY                     โ”‚
โ”‚                                                              โ”‚
โ”‚  root 1: (htb, default 30)                                   โ”‚
โ”‚  โ””โ”€โ”€ class 1:1 (rate 100mbit)                                โ”‚
โ”‚      โ”œโ”€โ”€ class 1:10 (rate 40mbit, ceil 100mbit, prio 1)      โ”‚
โ”‚      โ”‚   โ””โ”€โ”€ leaf fq_codel                                   โ”‚
โ”‚      โ”œโ”€โ”€ class 1:20 (rate 40mbit, ceil 100mbit, prio 2)      โ”‚
โ”‚      โ”‚   โ””โ”€โ”€ leaf fq_codel                                   โ”‚
โ”‚      โ””โ”€โ”€ class 1:30 (rate 20mbit, ceil 100mbit, prio 3)      โ”‚
โ”‚          โ””โ”€โ”€ leaf fq_codel                                   โ”‚
โ”‚                                                              โ”‚
โ”‚  When the parent has bandwidth to distribute,                โ”‚
โ”‚  the class with the lowest prio is tried first.              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Filter Attachment

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FILTERS ATTACH TO THE ROOT QDISC, NOT THE CHILD CLASSES     โ”‚
โ”‚                                                              โ”‚
โ”‚  โœ… Correct:                                                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ tc filter add dev eth0 parent 1: u32 ... flowid 1:10   โ”‚  โ”‚
โ”‚  โ”‚ โ†’ the filter is evaluated at the root                  โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  โŒ Wrong:                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ tc filter add dev eth0 parent 1:10 u32 ... flowid 1:10 โ”‚  โ”‚
โ”‚  โ”‚ โ†’ the packet is already enqueued at the root           โ”‚  โ”‚
โ”‚  โ”‚ โ†’ the filter is never evaluated                        โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Strict priority qdiscprio
Bandwidth guarantee qdischtb
HTB priority parameterprio on each class
HTB rate parameterrate (guaranteed minimum)
HTB ceiling parameterceil (maximum with borrowing)
HTB default classdefault parameter on the root qdisc
Leaf qdiscfq_codel for fairness
Filter typesu32, flower, fw
Filter attachmentRoot qdisc (parent 1:)
Verificationtc class show, tc filter show

Key takeaways:

  • The prio qdisc is a strict priority scheduler. It dequeues band 0 first, band 1 second, and so on. It does not shape or delay traffic; it only orders the dequeue. It is the correct choice when the goal is to reduce latency for the critical traffic without guaranteeing a bandwidth .
  • The htb qdisc guarantees bandwidth and honors priority. The rate is the guaranteed minimum, the ceil is the maximum with borrowing, and the prio parameter determines which class is served first when the parent has bandwidth to distribute .
  • The filters must be attached to the root qdisc. A filter attached to a child class is never evaluated, because the packet is enqueued at the root and dequeued from the leaf. The parent 1: form is the correct attachment point for an HTB hierarchy .
  • The default class receives the unclassified traffic. The default 30 parameter on the HTB root qdisc sends the packets that match no filter to the bulk class. Without it, the unclassified traffic is enqueued at the root and may be dropped .
  • The leaf qdisc determines the queueing within the class. The fq_codel leaf provides fair queueing and low latency, and it is the recommended choice for the interactive and bulk classes .
  • The fw filter connects the firewall mark to the traffic control class. The iptables or nftables rule sets the mark, and the tc filter ... handle <mark> fw classid <class> matches it. This is the mechanism for the classification that depends on criteria the packet filters cannot express .

Remember: QoS is the combination of a qdisc that defines the queuing behavior and filters that classify the traffic into the qdisc’s classes. The prio qdisc provides strict priority ordering, and the htb qdisc provides guaranteed bandwidth with priority. The filters attach to the root qdisc, the default class catches the unclassified traffic, and the leaf qdiscs determine the queueing within each class. The result is a network that serves the latency-sensitive traffic first and gives the bulk traffic the remaining bandwidth.


Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!