Tune Linux FQ Pacing Safely with tc
You will configure the Linux Fair Queue (FQ) qdisc on one network interface, enable a shallow ECN marking threshold, and verify the live queue statistics. FQ separates traffic into flows and can honour pacing requested by applications or the TCP stack. The examples use the tc command from Ubuntu's iproute2 6.1.0-1ubuntu6.4 package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes if you already know which interface you are testing. You need a shell, the iproute2 package, and elevated privileges for changes. This guide changes the root qdisc, so test on a disposable host or a maintenance window. Replacing a root qdisc can affect traffic immediately.
Checkpoint 1: identify the interface and current qdisc
First, choose the interface that carries the traffic you want to observe. Replace IFACE below with a real name such as eth0 or ens3. These inspection commands do not change network state.
ip -brief link
tc qdisc show dev IFACE
Read the existing output before changing anything. A line such as qdisc fq_codel, qdisc mq or another root qdisc is not interchangeable with FQ. Save the output somewhere outside this guide if you need to restore a more complicated setup exactly.
FQ is a classless scheduler. It has no child classes to configure, and it is intended mainly for locally generated traffic. For forwarded traffic, FQ falls back to a packet hash rather than a socket-owned flow.
Checkpoint 2: add FQ with a conservative test setting
Run the following as root, or prefix it with sudo. The ce_threshold setting asks FQ to mark packets with ECN Congestion Experienced once queueing exceeds 4 milliseconds. This is useful for congestion-control schemes such as DCTCP that deliberately use shallow ECN marking, but it is not a general substitute for measuring your workload.
sudo tc qdisc add dev IFACE root fq ce_threshold 4ms
On success, tc normally prints nothing. If you get RTNETLINK answers: File exists, the interface already has a root qdisc. Do not keep retrying: inspect it, then decide whether replacing it is safe. If you get Operation not permitted, check that the command is elevated and that your account has the capability to change network configuration.
The command uses FQ defaults for settings you did not name. The queue limit is 10,000 packets overall and 100 packets per flow. The hash table has 1,024 buckets, and the orphan mask limits unowned traffic to at most 1,024 allocated flows. Flow pacing is enabled by default. These are queueing controls, not bandwidth guarantees.
Checkpoint 3: verify the active parameters and counters
Ask tc for both statistics and detailed parameters:
sudo tc -s -d qdisc show dev IFACE
For the example above, the output should include a line with values similar to these, although the handle, interface name, packet counters and MTU-derived byte values will differ:
qdisc fq 8001: dev IFACE root refcnt 2 limit 10000p flow_limit 100p buckets 1024 orphan_mask 1023 quantum 3028b initial_quantum 15140b ce_threshold 4.0ms
Look for qdisc fq, root, limit, flow_limit and ce_threshold. The default quantum is twice the interface MTU. A new flow starts with credit for ten MTUs, which avoids adding a delay to TCP's initial window. The exact byte values therefore depend on the interface MTU.
The statistics include sent bytes and packets, drops, backlog, flow counts, throttling, and ECN marks. Counters are cumulative for the lifetime of this qdisc. A zero ce_mark value does not prove that traffic never queued for 4 milliseconds; it only says that no packet has been marked by this qdisc so far.
Adjust limits only for a measured reason
You can set a hard total queue limit, a per-flow limit, and a maximum rate for every flow. This example limits each flow to 50 packets and caps a flow at 100 Mbit/s:
sudo tc qdisc replace dev IFACE root fq flow_limit 50 maxrate 100mbit
Use replace only when replacing the existing root qdisc is acceptable. When the total limit is reached, new packets are dropped. Lowering a limit can drop packets immediately so that the queue meets the new value. A small per-flow limit can also drop bursts even when the total queue is mostly empty.
maxrate is a ceiling for each flow, not a link-wide allocation. Application requests made through the SO_MAX_PACING_RATE socket option are ignored when they ask for more than this ceiling. Without maxrate, FQ's default is unlimited, subject to the pacing information supplied by the application or TCP.
Undo the test change
Warning
Deleting the root qdisc changes live packet scheduling and may briefly disrupt traffic. Run this only when you intend to remove the qdisc, and use the saved output from Checkpoint 1 if you need to recreate the previous configuration.
sudo tc qdisc del dev IFACE root
tc qdisc show dev IFACE
After deletion, the kernel or network manager may install another default qdisc. If the interface is managed by a service, make the persistent configuration change there as well; this command alone is not a permanent network-configuration record.
Done means
- You identified the correct interface and inspected its existing root qdisc.
tc -s -d qdisc show dev IFACEreportsqdisc fqwith the settings you intended.- You understand that the queue and flow limits can drop packets when reached.
- You checked the counters after representative traffic, including
ce_markif ECN marking is part of the test. - You either left the tested qdisc in place deliberately or removed it with the appropriate privileged command.