Linux tc Traffic Shaping with HTB: Rate, Ceil and Filters - 夜莺博客

Linux tc Traffic Shaping with HTB: Rate, Ceil and Filters

The Linux tc (traffic control) framework shapes outbound bandwidth at the kernel level, which makes it perfect for enforcing per-host or per-destination rate limits on a gateway without buying QoS hardware. HTB (Hierarchical Token Bucket) is the classful qdisc that implements rate guarantees plus borrowing: each class gets a guaranteed rate and may burst up to ceil when the parent has spare bandwidth. This guide builds a working HTB shaper and verifies it with iperf3.

tc Components in One Minute

  • qdisc — the queueing discipline attached to the interface (default pfifo_fast has no shaping effect).
  • class — a child bucket inside a classful qdisc; HTB classes carry rate/ceil.
  • filter — classifies packets into classes, e.g. by destination IP with u32.

HTB Shape Script: Parent, Children and Filters

Model: the uplink is capped at 100 mbit. Two destinations — 192.168.5.0/32 and 192.168.5.1/32 — each start at 5 mbit and may borrow up to 80 mbit when the other is idle:

#!/bin/bash
TC=/sbin/tc
IF=ens160
LIMIT=100mbit
START_RATE=5mbit
CHILD_LIMIT=80mbit

# root qdisc: unclassified traffic goes to class 1:30
$TC qdisc add dev $IF root handle 1:0 htb default 30

# parent class (the 100mbit pool children borrow from)
$TC class add dev $IF parent 1:0 classid 1:1 htb rate $LIMIT

# children
$TC class add dev $IF parent 1:1 classid 1:10 htb rate $START_RATE ceil $CHILD_LIMIT
$TC class add dev $IF parent 1:1 classid 1:30 htb rate $START_RATE ceil $CHILD_LIMIT

# filters: send matching dst IPs into the right child
$TC filter add dev $IF protocol ip parent 1:0 prio 1 u32   match ip dst 192.168.5.0/32 flowid 1:10
$TC filter add dev $IF protocol ip parent 1:0 prio 1 u32   match ip dst 192.168.5.1/32 flowid 1:30

Read the parameters correctly: rate is the guaranteed bandwidth, ceil the maximum after borrowing, burst/cburst token-bucket sizes, and prio decides which class is served first under contention. Always pair each leaf class with an sfq or fq_codel qdisc to fair-queue the flows inside it:

$TC qdisc add dev $IF parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $IF parent 1:30 handle 30: sfq perturb 10

Verifying the Shaper

$TC qdisc show dev ens160
$TC class show dev ens160

Run iperf3 to each destination. With both hosts transmitting, each gets capped near its share; stop one flow and the other should climb toward ceil as it borrows the idle bandwidth. That borrowing behavior is the whole point of HTB versus a flat token bucket.

Cleanup and Notes

$TC qdisc del dev ens160 root

HTB only shapes egress on the interface it is attached to; shaping inbound requires ingress policing (e.g. tc police) or shaping on the peer. To simulate latency or loss instead of limiting bandwidth, see Linux tc netem; for interface-level diagnosis pair the shaper with ethtool diagnostics.

原文链接:https://joshrosso.com/c/tc/