Home / Alt manpages / tc-cbq-details(8)

  • tc-cbq-details(8)
  • Admin command
  • linux

Build a Safe CBQ Class Hierarchy with tc

You will finish with a small CBQ hierarchy that limits a class to a chosen rate, plus commands to inspect and remove it. CBQ is the Class Based Queueing discipline in the locally installed iproute2 6.1.0-1ubuntu6.4 package. Allow 20 minutes if you already know tc, or longer if you need to map your interface and link rate first.

These commands need root privileges because they change kernel traffic-control state. Use a test interface or a maintenance window where possible. Attaching a root qdisc can affect every packet leaving the interface, and deleting an existing root qdisc can remove someone else's shaping policy.

1. Set the values before touching the interface

Choose an interface, its actual link bandwidth, and an average packet size. Replace the placeholder values in this shell snippet, then inspect them before continuing:

IFACE=eth0
LINK_RATE=100Mbit
AVG_PACKET=1000
CLASS_RATE=10Mbit

printf 'interface=%s link=%s average-packet=%s class-rate=%s\n' \
    "$IFACE" "$LINK_RATE" "$AVG_PACKET" "$CLASS_RATE"
ip link show dev "$IFACE"

bandwidth is not the rate you want to give the class. On a root CBQ qdisc it describes the underlying physical interface, or the parent qdisc, so CBQ can calculate idle time. The class's rate is the limit for that class and its children.

Checkpoint: the interface must exist, and LINK_RATE must describe the path as configured, not a guessed Internet speed. If the interface name is wrong, stop here.

2. Record the current qdisc

Before making a change, save the current root qdisc in your terminal or change log:

$ tc qdisc show dev "$IFACE"

The output is the baseline for recovery. An existing root qdisc may already be providing shaping, queueing, or a service dependency. Do not run the add command below over it unless you own that configuration and have an undo plan.

3. Add the CBQ root qdisc

CBQ needs an average packet size and the underlying bandwidth. The handle is optional, but assigning 1: gives the hierarchy a clear major number:

$ sudo tc qdisc add dev "$IFACE" root handle 1: cbq \
    avpkt "$AVG_PACKET" bandwidth "$LINK_RATE"

This creates the CBQ instance. It does not, by itself, impose a class rate. The root qdisc supplies the link-sharing machinery; shaping is configured on classes below it.

Verify that the kernel accepted the change:

$ tc -s qdisc show dev "$IFACE"

Look for a root qdisc whose kind is cbq and whose handle is 1:. The statistics are counters, so their exact values depend on traffic already sent.

4. Add a shaped class

Create a child class with a ten megabit rate. allot is the amount a class may dequeue during a scheduling round; prio chooses which class is tried first, with lower numbers having higher priority. avpkt is required in the class syntax:

$ sudo tc class add dev "$IFACE" parent 1: classid 1:10 cbq \
    allot 1514 rate "$CLASS_RATE" prio 1 avpkt "$AVG_PACKET" \
    bandwidth "$LINK_RATE"

The class rate applies to this class and any children. It only receives packets that classification sends to 1:10. A filter, socket priority, or another supported CBQ classification method must direct traffic there; creating the class does not automatically move all traffic into it.

Checkpoint: inspect the hierarchy and counters:

$ tc class show dev "$IFACE"
$ tc -s class show dev "$IFACE"

You should see class 1:10. Counters will stay at zero until traffic is actually classified into it. That is not evidence that the rate is being ignored.

5. Add more classes only when their policy is clear

Sibling classes share the parent's scheduling rounds. Their weight values are compared as ratios, while prio controls which priority group is tried first. A second class might look like this:

$ sudo tc class add dev "$IFACE" parent 1: classid 1:20 cbq \
    allot 1514 rate 20Mbit prio 2 avpkt "$AVG_PACKET" \
    bandwidth "$LINK_RATE"

Use bounded when a class must not borrow unused capacity from siblings. Use isolated when it must not lend unused capacity to siblings. These flags affect sharing; they do not repair an incorrect bandwidth value or classify packets.

Keep the first test small. CBQ's idle-time calculation depends on packet timing and the physical link's behaviour, so a virtual, tunnelled, or poorly behaving device can produce less predictable results than a straightforward physical link.

6. Monitor without changing the policy

Watch the installed hierarchy and its traffic counters while generating a known workload:

$ watch -n 1 'tc -s qdisc show dev eth0; tc -s class show dev eth0'

Replace eth0 with the value of IFACE. Confirm that the intended class's byte and packet counters increase. If they do not, investigate classification before tuning CBQ parameters. The most common distraction is changing minburst, maxburst, or priorities when no packets are reaching the class.

CBQ's ewma setting controls smoothing of measured idle time. Its default log value is 5, and the documented range is 0 to 31; lower values are more sensitive. Leave it at the default for a first test. Burst parameters change timing trade-offs, not the basic ownership of packets, and should be measured against the workload rather than copied blindly.

7. Remove the test configuration

Removing a root qdisc removes its child classes too and may briefly change the interface's queueing behaviour. Confirm the interface one more time before running this command:

$ printf 'About to remove the root qdisc from %s\n' "$IFACE"
$ sudo tc qdisc del dev "$IFACE" root
$ tc qdisc show dev "$IFACE"

To recover a previous policy, reapply the configuration recorded in step 2 using the owning service's documented method. The tc qdisc show output is evidence of the old state, not a complete configuration file, so do not assume it contains every filter or child-qdisc setting.

Done means

  • The interface and underlying bandwidth were checked before configuration.
  • The root qdisc was confirmed as cbq with the expected handle.
  • At least one class has the intended rate, packet size, priority, and parent.
  • Traffic counters were checked, with classification errors kept separate from shaping errors.
  • The test qdisc was removed, or its owner has a recorded configuration to restore.