OPNsense traffic shaping and QoS explained, short version: the shaper is FreeBSD’s dummynet, built from pipes (hard bandwidth caps), queues (weighted shares inside a pipe) and rules (which packets go where). For a home or small-office WAN, the right setup is one FQ-CoDel pipe per direction at about 85% of advertised speed, not a stack of priority queues.
What does OPNsense traffic shaping actually do?
Traffic shaping on OPNsense moves the bottleneck queue from your ISP’s modem to the firewall. By capping throughput slightly below the real line rate, packets queue inside OPNsense, where a scheduler decides what leaves next and what gets dropped, instead of in a modem buffer you cannot configure. That is the whole point of QoS on a home WAN.
The symptom it fixes is bufferbloat: latency looks fine on an idle line, then climbs the moment someone starts a cloud backup, because the modem’s oversized buffer fills and every packet, DNS lookups and voice frames included, waits behind the bulk transfer.
The shaper runs on IPFW and dummynet, which the OPNsense documentation calls “a modern, reliable solution with a low cpu footprint”. Shaper rules live under Firewall ‣ Shaper ‣ Rules and are handled independently of firewall rules: a pass rule classifies nothing, and a shaper rule permits nothing. On a virtual machine, the docs recommend setting the kern.hz tunable to at least 1000.
Pipes, queues and rules: how the three objects fit
A pipe sets the bandwidth, a queue divides it, and a rule decides which traffic enters which. Field ranges come from the shaper’s model definition in opnsense/core.
| Object | What it does | Fields that matter |
|---|---|---|
| Pipe | Emulates a link with a given bandwidth, delay, queue size and loss rate | Bandwidth, scheduler type, mask, CoDel settings |
| Queue | Shares a pipe among flows by weight (WF2Q+) | Pipe, weight (1 to 100, default 100), mask |
| Rule | Sends matching packets to a pipe or queue | Sequence, interface, interface 2, protocol, source, destination, ports, direction, DSCP, target |
Direction. On WAN, in is download and out is upload. The rule model defaults to both directions, so set it explicitly; the docs call for separate download and upload pipes “to avoid undefined behaviour when mixing bidirectional traffic”.
Masks. A mask (source, destination or an IPv6 equivalent) behaves differently by placement. On a pipe, it creates one dynamic pipe per address at the full configured rate: the limit-per-user example gives every host on 192.168.1.0/24 its own 1 Mbit/s. On a queue, it creates one dynamic queue per address inside one pipe, so hosts share the pipe evenly. Mask destination for download, source for upload.
Sequence. The control plane how-to puts specific rules at a lower sequence than catch-alls so broad rules cannot intercept their traffic first. A catch-all ip any any at sequence 1 shadows everything below it, the usual reason a VoIP queue never sees a packet. Number specific rules low and leave gaps.
Which scheduler should you pick?
Pick FlowQueue-CoDel for any pipe whose job is stopping bufferbloat on a WAN, which is most of them. Keep the default Weighted Fair Queueing only when queue weights must mean something, such as a 9:1 split between two applications or a control plane class. The other four schedulers solve narrower problems.
| Scheduler | Use it for |
|---|---|
| Weighted Fair Queueing (default) | Weighted splits, guest caps, control plane classes |
| FlowQueue-CoDel | WAN bufferbloat control; ignores queue weights |
| FlowQueue-PIE | Alternative AQM; unsuitable for control plane traffic |
| QFQ | Weighted classes; accepted for control plane alongside WFQ |
| Deficit Round Robin | Round-robin service between queues |
| FIFO | A plain rate cap with no fairness |
There is no PRIQ, HFSC or CBQ in that list, so a guide prescribing a strict-priority VoIP queue describes a different shaper. The docs are blunt: “weights are not priorities; a flow with a lower weight is still guaranteed to get its fraction of the bandwidth even if a flow with a higher weight is permanently backlogged”.
Why does FQ-CoDel fix bufferbloat?
FQ-CoDel fixes bufferbloat by combining two mechanisms: it splits traffic into per-flow queues so a bulk download cannot sit in front of a DNS reply, and it drops or ECN-marks packets in any queue whose delay stays above a target, which tells the sender to slow down before the buffer fills.
RFC 8290, The Flow Queue CoDel Packet Scheduler and Active Queue Management Algorithm, hashes packets into 1024 queues by default and serves them by deficit round robin with a 1514-byte quantum, putting sparse flows such as DNS and VoIP ahead of flows holding a backlog. RFC 8289, Controlled Delay Active Queue Management, runs in each queue: once sojourn time stays above a 5 ms target for a 100 ms interval, it drops, raising the drop rate with the square root of the drop count until delay falls.
Defaults from the FQ_CoDel how-to, applied when fields are left empty:
| Parameter | Default | OPNsense guidance |
|---|---|---|
| Target | 5 ms | Raise only if gateway RTT for a full-size packet is higher |
| Interval | 100 ms | 10 to 300 ms works in most cases |
| Quantum | 1514 bytes | Match WAN MTU; 300 helps small packets below 100 Mbit/s |
| Limit | 10240 packets | Cut to about 1000 below 10 Gbit/s |
| Flows | 1024 | Don’t raise without testing; change needs a reboot |
| ECN | Off | Enable on downlinks; disable on uplinks under 4 Mbit/s |
The docs call FQ_CoDel “no-knobs” and suggest running defaults for a day before tuning. The lower limit is tied to OPNsense 25.7.8, which fixed a FreeBSD bug where exceeding the queue limit caused CPU-hogging log output.
How to set up FQ-CoDel on OPNsense
For a 500/40 Mbit/s cable plan, 85% of advertised speed means starting at 425 Mbit/s down and 34 Mbit/s up.
- Open Firewall ‣ Shaper ‣ Pipes in advanced mode. Create a pipe named Download: 425 Mbit/s, scheduler FlowQueue-CoDel, FQ-CoDel ECN checked, FQ-CoDel limit 1000, other CoDel fields empty. Create Upload the same way at 34 Mbit/s.
- Under Queues, create Download-Queue and Upload-Queue on their pipes, weight 100, masks empty.
- Under Rules, add sequence 100: interface WAN, protocol ip, source and destination any, direction in, target Download-Queue. Add sequence 110 identically with direction out and target Upload-Queue. The high numbers leave room for control plane rules.
- Apply.
Then measure with the Waveform bufferbloat test or Cloudflare’s speed test, both suggested by the how-to, or ping from a LAN host while a large download runs:
ping -c 60 1.1.1.1
If loaded latency barely rises above idle, raise both pipes in small steps and retest; when it climbs, step back. Tune during the evening peak, when a cable node’s real throughput sags. Optional target tuning, per the docs: from the OPNsense shell, run ping -s 1472 -c 1000 -D <gateway-ip> against the ISP gateway, then round the average RTT up into Target.
When do weighted queues make sense?
Weighted queues make sense when you need a proportional split under contention, not low latency. Typical cases are capping a guest VLAN, reserving a share for a backup job, or dividing a slow uplink between two applications. They need a weight-aware scheduler, the default WFQ or QFQ, because FQ-CoDel ignores queue weights entirely.
The weighted queues how-to splits a 10 Mbit/s pipe between Queue-SMTP at weight 9 and Queue-HTTP at weight 1, with rules at sequence 11 (port 25), 21 (port 80) and 31 (port 443). Saturated, mail gets nine times web’s bandwidth; idle, either can use the whole pipe.
The GuestNet how-to uses the interface 2 field: on a 10 Mbit/s symmetric line, WAN rules with interface 2 set to GuestNet hold guests to 2 Mbit/s down and 1 Mbit/s up while the main LAN stays unlimited.
Rules can also match DSCP (EF, AF11 to AF43, CS1 to CS7), packet length and a “tcp (ACK packets only)” protocol. Matching a desk phone’s EF marking into a heavily weighted WFQ queue still buys a proportional share, not strict priority.
Do you need a control plane class for IPv6?
Yes, if the WAN runs IPv6 or a dynamic routing protocol. The OPNsense docs rule out FQ-CoDel and FQ-PIE for control plane traffic because of their AQM back-pressure, and use ipv6-icmp as the example protocol. By extension, that would include ICMPv6 neighbour discovery and router advertisements, which are ipv6-icmp messages, so that traffic belongs in its own pipe with a weight-aware scheduler, matched before the catch-all rules.
The recipe: one pipe per direction at 1% of tuned bandwidth, minimum 1 Mbit/s, on WFQ or QFQ; a queue at weight 100; a WAN rule with protocol ipv6-icmp. Never share that class, and subtract its bandwidth from the main pipes. For the 500/40 example: control plane pipes of 4 and 1 Mbit/s at sequences 10 and 20, FQ-CoDel pipes trimmed to 421 and 33 Mbit/s.
The same applies to OSPF or BGP across a WireGuard site-to-site tunnel: routing hellos dropped by AQM during a saturated upload look like a flapping neighbour.
What does shaping cost?
Shaping itself is cheap: the project describes dummynet as having a low CPU footprint. The costs are indirect: one more per-packet task on a box already busy with Suricata or VPN crypto, and encrypted tunnels that collapse into single flows FQ-CoDel cannot see inside.
Size the box with OPNsense hardware requirements in mind. On tunnels, RFC 8290 hashes flows on header fields, typically addresses, ports and protocol, so a WireGuard tunnel crossing WAN is one UDP flow sharing one queue. For fairness inside it, classify on the tunnel’s assigned interface, where traffic is still cleartext. Protocol trade-offs are in WireGuard vs OpenVPN vs IPsec on OPNsense.
From the OPNsense shell, ipfw pipe show and ipfw queue show list each object with its counters; a queue that never fills usually sits behind a shadowing rule.
FAQ
does opnsense have qos?
Yes. OPNsense implements QoS through its traffic shaper under Firewall ‣ Shaper, built on FreeBSD’s ipfw and dummynet. It provides bandwidth-capped pipes, weighted queues and classification rules that match interface, address, port, protocol and DSCP, plus FlowQueue-CoDel and FlowQueue-PIE schedulers for active queue management against bufferbloat.
what bandwidth should i set for fq_codel on opnsense?
Start at 85% of your ISP’s advertised download and upload speeds, one pipe per direction. Then raise both values in small steps, running a bufferbloat test after each change, and stop when latency under load begins to rise. Tune during your ISP’s busiest hours, because cable throughput often sags in the evening.
does traffic shaping reduce internet speed?
Yes, slightly, and on purpose. A shaper must cap throughput below the real line rate so the queue forms inside OPNsense instead of the modem. The OPNsense docs start pipes at 85% of advertised speed and tune upward. In exchange, latency under load stays close to idle latency, which matters more for calls and games.
why is fq_codel not fixing bufferbloat on opnsense?
Usually the pipe bandwidth sits above the real line rate, so the queue still forms in the modem. Lower both pipes and retest. Then confirm the download rule uses direction in and the upload rule uses out on WAN, that no earlier sequence shadows them, and that you tested during peak hours.