Linux Traffic Control: How tc Shapes Bandwidth
The Linux Traffic Control (tc) subsystem regulates the
flow of network packets by scheduling, prioritizing, policing, and
shaping traffic as it traverses the kernel's networking stack. Bandwidth
shaping is primarily achieved on egress by delaying or queuing outbound
packets using specialized algorithms known as Queueing Disciplines
(qdiscs), supported by classes and filters. By intercepting packets
before they reach the network interface card (NIC), tc
ensures that transmission rates adhere to administrator-defined limits,
mitigating network congestion and eliminating bufferbloat.
The Three Core Components: Qdiscs, Classes, and Filters
The architecture of tc relies on three foundational
elements that structure how network packets are categorized and
scheduled:
- Queueing Disciplines (qdiscs): A qdisc represents
the algorithm applied to a network interface's packet queue. Qdiscs can
be classless (applied universally to all traffic, such as
pfifo_fast,fq_codel, ortbf) or classful (capable of containing nested sub-queues with different rules, such ashtborcbq). - Classes: Classes exist within classful qdiscs to partition total bandwidth into multiple virtual channels. Each class can be assigned specific parameters, such as a guaranteed minimum rate, a maximum burst rate, and a priority level.
- Filters (Classifiers): Filters inspect incoming or
outgoing packets using criteria like source/destination IP addresses,
port numbers, or protocol types (often utilizing
u32matching orebpf). When a filter matches a packet, it directs that packet to the appropriate class for processing.
The Token Bucket Mechanism for Shaping
True traffic shaping involves delaying packets rather than simply
discarding them (the latter being traffic policing). The tc
subsystem accomplishes this using the Token Bucket algorithm, commonly
implemented via the Token Bucket Filter (tbf) or
Hierarchical Token Bucket (htb).
In this model, a virtual bucket continuously accumulates tokens at a fixed, configured rate (representing allowed bandwidth). Each token grants permission to transmit a specific number of bytes:
- When a packet arrives for transmission, the kernel checks whether sufficient tokens exist to cover the packet's byte size.
- If enough tokens are present, the corresponding tokens are deducted, and the packet is immediately sent to the network driver.
- If there are insufficient tokens, the packet is held in a buffer until new tokens accumulate at the defined rate.
- If the buffer fills completely before tokens become available, excess packets are dropped to prevent memory exhaustion.
Hierarchical Token Bucket (htb) expands on this concept
by allowing idle classes to lend unused tokens to other classes under
heavy load, maximizing total link utilization while maintaining hard
rate ceilings.
Egress vs. Ingress Shaping
Bandwidth shaping inherently requires control over when a packet is transmitted, making it natively suited for outbound (egress) interfaces. At the egress point, the Linux kernel holds packets in system memory buffers and feeds them to the hardware device ring buffer strictly according to the qdisc's scheduler.
Because Linux cannot directly control the rate at which external
systems transmit inbound (ingress) traffic, standard qdiscs cannot delay
incoming packets. To apply full bandwidth shaping to ingress traffic,
tc typically redirects incoming packets to an Intermediate
Functional Block (ifb) pseudo-device. Once redirected, the
incoming traffic is treated as egress traffic on the ifb
device, allowing the full suite of classful schedulers and token-bucket
algorithms to shape the flow before it reaches higher-layer
applications.