How to Restore Default pfifo_fast Queue Discipline in Linux Traffic Control After Temporary Rate Limiting


2 views

When working with Linux Traffic Control (tc), many developers encounter an unexpected behavior when removing custom queue disciplines:

# Setup temporary rate limiting
tc qdisc add dev eth1 root tbf rate 600kbit latency 50ms burst 1540

# Later attempt to remove it
tc qdisc del dev eth1 root

Instead of reverting to the default pfifo_fast qdisc, this completely removes the queuing discipline, causing network operations to fail.

The default pfifo_fast queue discipline is special - it's automatically created by the kernel when a network interface comes up. Attempting to manually create it fails:

# This doesn't work
tc qdisc add dev eth1 root pfifo_fast

This occurs because pfifo_fast is a built-in qdisc without configurable parameters through the tc command.

The correct approach is to replace (rather than delete) the existing qdisc:

# Replace existing qdisc with default pfifo_fast
tc qdisc replace dev eth1 root pfifo

Alternatively, you can use the following equivalent command:

# Another way to restore default queuing
tc qdisc add dev eth1 root pfifo_fast 2>/dev/null || \
tc qdisc change dev eth1 root pfifo_fast

In cases where you need to temporarily use a different qdisc before returning to default, consider these patterns:

# Store original qdisc configuration
ORIG_QDISC=$(tc qdisc show dev eth1)

# Apply temporary shaping
tc qdisc add dev eth1 root tbf rate 1mbit burst 32kbit latency 400ms

# Later restore original configuration
eval "tc qdisc $ORIG_QDISC"

# Or for simple cases:
tc qdisc replace dev eth1 root pfifo

The pfifo_fast qdisc has three bands (priority queues) that handle traffic differently:

# View default pfifo_fast configuration
tc qdisc show dev eth1

Key characteristics include:
- Packets are classified by Type of Service (ToS) bits
- Band 0 is highest priority
- Each band uses FIFO queuing
- Default priomap determines classification

Here's a complete workflow for temporary rate limiting:

#!/bin/bash

# Backup current qdisc
CURRENT_QDISC=$(tc qdisc show dev eth1 | awk '{print $2,$3,$4}')

# Apply temporary rate limit
tc qdisc add dev eth1 root tbf rate 500kbit latency 50ms burst 10kb

# ... perform operations with rate limiting ...

# Restore original qdisc
if [ "$CURRENT_QDISC" = "pfifo_fast 0:" ]; then
    tc qdisc replace dev eth1 root pfifo
else
    tc qdisc replace dev eth1 root $CURRENT_QDISC
fi

The Linux kernel automatically creates a pfifo_fast queue discipline (qdisc) for each network interface during initialization. This is the default queuing mechanism with three priority bands:

qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

When we remove a custom qdisc with:

# tc qdisc del dev eth1 root

The interface becomes effectively unconfigured, which breaks network functionality. This occurs because:

  • The kernel doesn't automatically recreate pfifo_fast
  • The network stack expects a qdisc to be present
  • Packets have no queuing mechanism

The proper way to handle temporary qdisc changes is:

# tc qdisc replace dev eth1 root tbf rate 600kbit latency 50ms burst 1540
# tc qdisc replace dev eth1 root pfifo_fast

If you've already deleted the qdisc, recreate it with:

# tc qdisc add dev eth1 root pfifo_fast

Some systems may require additional parameters:

# tc qdisc add dev eth1 root handle 1: pfifo_fast

For systems where pfifo_fast recreation fails, a similar alternative is:

# tc qdisc add dev eth1 root handle 1: prio bands 3
# tc qdisc add dev eth1 parent 1:1 pfifo limit 1000
# tc qdisc add dev eth1 parent 1:2 pfifo limit 1000
# tc qdisc add dev eth1 parent 1:3 pfifo limit 1000

Always verify your qdisc configuration:

# tc qdisc show dev eth1
# tc -s qdisc show dev eth1

Check kernel messages for errors:

# dmesg | grep qdisc

To make changes persistent across reboots, add to your network configuration:

post-up /sbin/tc qdisc add dev $IFACE root pfifo_fast