How to Configure Linux Traffic Control (tc) fq_codel to Eliminate Bufferbloat

When users experience profound latency on a high-speed broadband connection—such as voice calls dropping while a large file download occurs in the background—they usually assume they lack sufficient bandwidth. In reality, the issue is almost always Bufferbloat.

Bufferbloat occurs when network hardware (routers, switches, or the Linux kernel itself) uses excessively large queues to buffer packets during bursts of traffic. If a heavy download saturates the connection, the queue fills up. Subsequent packets—such as tiny, latency-sensitive VoIP packets or TCP ACKs—are forced to wait at the back of this massive queue, creating hundreds of milliseconds of artificial latency.

The solution is Active Queue Management (AQM), specifically the Fair Queuing Controlled Delay (fq_codel) algorithm. Standardized in RFC 8290, fq_codel automatically segregates traffic into hundreds of distinct flows (fair queuing) and aggressively drops packets from heavy, bandwidth-hogging flows if they sit in the queue too long (controlled delay), ensuring that latency-sensitive traffic immediately bypasses the congestion.

This guide explains how to configure fq_codel on a Linux gateway or server using the tc (Traffic Control) utility.

Understanding the Architecture of fq_codel

The Linux kernel uses queuing disciplines (qdiscs) to manage how packets are transmitted out of a network interface.

Historically, the default qdisc was pfifo_fast (a simple First-In, First-Out queue with three priority bands). If a large file transfer filled the FIFO queue, all other traffic was blocked.

fq_codel replaces this with a two-pronged approach:

  1. Fair Queuing (FQ): It hashes incoming packets into 1024 separate “buckets” based on their 5-tuple (Source IP, Dest IP, Source Port, Dest Port, Protocol). It then uses a round-robin scheduler to service each bucket. If a VoIP call is bucket 4, and a 50GB file transfer is bucket 7, the file transfer cannot block the VoIP call, because the scheduler ensures bucket 4 gets equal transmission opportunities.
  2. CoDel (Controlled Delay): It measures exactly how long a packet sits in the queue (the “sojourn time”). If the sojourn time exceeds the target (default 5ms) for an extended period, CoDel starts dropping packets from that specific bucket. This forces the TCP congestion control algorithm of the file transfer to slow down, keeping the queue constantly empty and latency near zero.

Step 1: Checking the Current Queuing Discipline

To view the active qdisc on your network interface (e.g., eth0), use the tc command:

tc qdisc show dev eth0

If your system is running an older kernel, you might see pfifo_fast. Modern systems (systemd v217+) often default to fq_codel, but it is critical to verify.

qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn

Step 2: Enabling fq_codel Globally (Sysctl)

If your system is not using fq_codel by default, you can instruct the Linux kernel to use it as the default qdisc for all newly initialized network interfaces.

Open the sysctl configuration file:

sudo nano /etc/sysctl.d/99-fq-codel.conf

Add the following line:

net.core.default_qdisc = fq_codel

Apply the change immediately:

sudo sysctl --system

Note: This only affects interfaces brought up after the change. You must reboot or manually apply it to active interfaces.

Step 3: Manually Applying fq_codel via tc

To instantly apply the qdisc to an active interface without rebooting, you use the tc utility.

To replace the root qdisc on eth0 with fq_codel:

sudo tc qdisc replace dev eth0 root fq_codel

Advanced Configuration:
While the defaults are excellent, you can tune the parameters for specific network links (e.g., highly latent satellite links or ultra-fast local fiber).

sudo tc qdisc replace dev eth0 root fq_codel limit 10000 target 5ms interval 100ms noecn
  • limit: The hard limit of packets the queue can hold before forced tail-dropping.
  • target 5ms: The acceptable delay. If a packet waits longer than 5ms, CoDel considers the queue congested.
  • interval 100ms: How long the queue must remain congested before CoDel starts dropping packets to signal TCP backoff.
  • noecn: Disables Explicit Congestion Notification (ECN) marking. (By default, fq_codel marks ECN-capable packets instead of dropping them).

Step 4: Shaping Ingress Traffic with Intermediate Functional Block (IFB)

The tc command only controls traffic leaving the interface (egress). fq_codel cannot directly control traffic coming into the interface (ingress), because by the time the kernel sees the packet, it has already traversed the congested bottleneck.

To solve ingress bufferbloat (e.g., if you are building a Linux router for a residential connection), you must redirect incoming traffic to a virtual IFB device, and apply fq_codel there.

Load the IFB kernel module:

sudo modprobe ifb numifbs=1
sudo ip link set dev ifb0 up

Create an ingress qdisc on eth0, redirect all traffic to ifb0, and apply fq_codel to ifb0:

# Create ingress hook
sudo tc qdisc add dev eth0 handle ffff: ingress

# Redirect traffic
sudo tc filter add dev eth0 parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev ifb0

# Apply fq_codel to the virtual interface
sudo tc qdisc add dev ifb0 root fq_codel

Conclusion

Bufferbloat fundamentally destroys the responsiveness of TCP/IP networks by holding latency-sensitive packets hostage behind massive data transfers. By configuring the fq_codel active queue management algorithm via Linux Traffic Control, network engineers can enforce strict flow isolation and autonomous delay management, guaranteeing that SSH, VoIP, and gaming traffic remain perfectly responsive even when the network is pushed to absolute capacity.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.