Shape Hostile Flows with tc-sfb Without Losing the Plot

SFB is the queueing discipline you reach for when a handful of flows that ignore congestion signals are starving everyone else. You will attach Linux's stochastic fair blue queue discipline, inspect its per-flow congestion statistics, and remove it cleanly if the result is not right. The examples use tc from iproute2 6.1.0 and the installed tc-sfb(8) documentation.

Allow about 15 minutes for a live test and a further review of the counters. You need an interface with a real transmit queue, the iproute2 package, and elevated privileges for changes to queueing. The commands below alter live packet handling, so use a maintenance window or a disposable test host. Replace IFACE with a real interface name, such as enp0s31f6.

1. Check the current queue before changing it

Start by recording the interface and its existing root qdisc:

$ ip -br link
$ tc qdisc show dev IFACE

On this machine, an interface may show output such as qdisc fq_codel 0: dev enp0s31f6 root. Save that output. A rollback is much safer when you know what was there before the experiment.

Checkpoint: confirm that IFACE is the egress interface you mean to affect. SFB is not an ingress firewall and does not classify packets by itself as a policy engine.

2. Attach SFB with conservative explicit settings

The shortest documented form is a privileged operation:

# tc qdisc add dev IFACE handle 1: root sfb

That uses the manpage defaults, including a 25-packet maximum bucket queue, a target that defaults to 20 with that maximum, a ten-minute rehash interval, and a one-minute double-buffer warm-up delay. The default penalty rate is only 10 packets per second, which the documentation calls probably too small for a normal uplink.

For a test where you want the important values visible in the command, use:

# tc qdisc add dev IFACE handle 1: root sfb \
    rehash 600000 db 60000 limit 10000 max 25 target 20 \
    increment 0.00050 decrement 0.00005 \
    penalty_rate 1000 penalty_burst 20

The values are examples, not universal tuning advice. max should be slightly larger than target and should not exceed 1.5 times it. Set penalty_rate as a reasonable fraction of the uplink capacity, then measure. A packet rate is not a bit rate: packet size and traffic mix matter.

Checkpoint: read the installed configuration back:

$ tc qdisc show dev IFACE

You should see sfb attached at root. If you see an error because another root qdisc exists, do not immediately replace it. Record the existing setup and decide whether this test belongs inside a classful qdisc instead.

3. Understand what SFB is doing

SFB keeps virtual state for flows rather than maintaining the complete packet queue itself. Each flow is mapped into one bin at each of eight levels, with 16 bins per level. A bin whose occupancy reaches its target gets a higher marking probability. An empty bin gets a lower probability. The flow receives the minimum probability from the bins it maps to.

A flow that ignores ECN marks and packet drops can therefore reach a probability of one and enter the penalty path. The implementation then rate-limits that flow to penalty_rate. Periodic rehashing changes the mappings so that a responsive flow is less likely to share every relevant bin with an aggressive flow for a long time.

There is still a false-positive boundary. Responsive and non-responsive flows can share all eight bins. The manpage gives an approximate misidentification probability of 0.2 percent with ten non-responsive flows. More hostile flows increase the risk. Use SFB as one queueing component, not as proof that a sender is malicious.

4. Inspect statistics while traffic is running

Ask tc for statistics:

$ tc -s qdisc show dev IFACE

Look for the SFB counters and read them as evidence about the queue:

High ratedrop means SFB is seeing many flows that do not react. The manpage suggests embedding SFB in a classful qdisc when those flows need a different shaping policy. High bucketdrop can point to many aggressive short-lived flows. Do not tune from one snapshot; compare counters over the same traffic test and time interval.

5. Account for ECN and the inner qdisc

SFB automatically enables ECN. That does not mean every sender or path will use ECN successfully. A marked packet still needs an end-to-end path and a responsive transport.

SFB does not queue packets itself. It uses an inner qdisc, which defaults to pfifo. Because SFB tracks a virtual queue, that inner qdisc must not drop a packet that SFB has already queued. If the marking probability becomes very high, SFB switches towards dropping because the condition indicates severe congestion or an unresponsive flow.

These details are a common distraction when a test appears to work but counters do not match expectations. Verify the actual qdisc tree and counters instead of assuming that SFB owns every queueing decision.

6. Remove the experiment safely

Removing a root qdisc is service-disrupting for the interface's packet queue. Stop or drain the test traffic first, then use the recorded command to restore the previous qdisc. To remove SFB itself:

# tc qdisc del dev IFACE root
$ tc qdisc show dev IFACE

The second command should show the host's resulting root qdisc, often the kernel default or a qdisc restored by another management service. If a network manager or orchestration system owns the interface, make the persistent configuration change there as well, or it may reapply SFB later.

Do not use tc qdisc replace casually on a production interface. It can discard the current root configuration and disrupt traffic. Test with add, capture the output, and use the exact previous configuration for recovery.

Done means