Slowyslowyapp.com

04 Mechanisms

pf and ALTQ

The packet filter and the queueing discipline attached to it, and what each part is responsible for.

Entry 02 of 05What exists, and what each one can do.All of Mechanisms

A rack-mounted appliance with its lid off showing the board inside
Classification and scheduling are separate jobs; both happen on this board.slowyapp.com picture kit

The packet filter that became a queue manager

pf — "packet filter" — started life as OpenBSD's firewall replacement after the project dropped IPFilter over a licensing dispute in 2001. It was clean, readable, and rule-based, but a firewall on its own has no opinion about when a packet moves, only whether it moves. Queue disciplines handle when. The bridge between those two jobs was ALTQ.

ALTQ, the ALTernate Queueing framework, was developed by Kenjiro Cho at Sony Computer Science Laboratories in Japan during the late 1990s as a research framework for experimenting with different queue disciplines on BSD systems. It could be bolted onto various packet filters, but it found its most lasting home when OpenBSD integrated it alongside pf. The two components remained conceptually distinct: pf classifies and filters; ALTQ schedules. Understanding that division is the whole point.

Classification versus scheduling

When a packet arrives at an interface, pf inspects it against a ruleset — source, destination, protocol, port, state — and assigns it to a class, a named queue. That classification is pf's work. ALTQ then manages those queues: it decides in what order packets leave the interface, and at what rate, using one of several disciplines.

A terminal window showing configuration output, dim desk
A pipe with a rate, a delay and a loss probability, sitting under everything the machine sends.slowyapp.com picture kit

The classical discipline available through ALTQ is CBQ, Class-Based Queueing, which organises queues into a hierarchy of classes, each with a bandwidth allocation and a borrowing policy. A class that is underusing its allocation can lend capacity to busier siblings, up to a ceiling. HFSC — Hierarchical Fair Service Curve — goes further, offering separate control over delay-sensitive and bandwidth-sensitive traffic within the same hierarchy; it was designed specifically to give real-time traffic predictable latency without simply handing it a flat priority. PRIQ, priority queueing, is the simplest option: strict priority between queues, no bandwidth guarantees. A packet in the highest-priority queue always leaves first.

The importance of this split between classification and scheduling is that pf can match packets using everything it already knows — connection state, interface, address family, even the user process on the local machine — and the queueing discipline does not need to understand any of that. The disciplines are interchangeable because they only see the queue, not the rule that put a packet there.

What ALTQ cannot reach

ALTQ controls outbound traffic on an interface. That is where a scheduler can actually help: a queue can hold packets back, reorder them, or drop them according to its discipline. Inbound traffic arrives at whatever rate the sender chooses to send it; there is no outbound queue on the receiving side, so ALTQ cannot slow it. Shaping inbound traffic requires either a proxy that buffers and re-emits, or a queue at the far end of the link — typically at the router upstream. This is the same constraint that applies to shaping inside the kernel generally, not a limitation specific to pf.

The other boundary is that ALTQ operates below the application layer entirely. It sees packets, not HTTP requests or TLS records. An application that opens many parallel connections and aggregates them across a single queue entry can exhaust that entry's allocation without any individual connection triggering a rate limit. Fairness between flows at a finer granularity requires a discipline like SFQ or FQ-CoDel, which were not part of the original ALTQ set.

OpenBSD's own revision

OpenBSD later developed its own native queue syntax built into pf directly, deprecating the separate ALTQ configuration for most use cases. The newer syntax is simpler to write and maps onto HFSC internally, but the underlying scheduling machinery — the discipline, the hierarchy, the concept of a class — remains the same architecture that ALTQ established. dummynet, the FreeBSD-rooted alternative, takes a different structural approach, treating traffic conditioning as a pipeline of pipes and queues rather than a classified hierarchy, but it was solving the same problem from a different angle.

The packet filter's role in all of this is unremarkable in a useful way: it classifies traffic with great precision using rules that network engineers already write for security purposes, and the queueing framework consumes that classification. Neither component needs to reach into the other's logic. That separation is why the architecture has lasted as long as it has, and why similar divisions — classify here, schedule there — appear throughout the congestion-control literature that followed.

A small form-factor computer on a desk with two network cables attached
Selective by construction: only the clients pointed at it are shaped.slowyapp.com picture kit