Home / Alt manpages / tc-skbprio(8)

  • tc-skbprio(8)
  • Admin command
  • linux

Protect High-Priority Packets with tc skbprio

By the end of this guide, a Linux interface will have an skbprio root queue with one global packet limit, and you will know how to inspect and remove it. The queue sends higher-priority packets first and, when full, makes room by dropping the lowest-priority queued packet. This is useful when a busy or attacked router must keep the most trustworthy traffic moving.

Allow about 15 minutes if the interface already has the classification you need. You need the iproute2 package, an interface whose traffic you control, and elevated privileges for changes. The examples use eth0; replace it with a real interface name. Do not run the replacement command on a production interface until you have recorded its current qdisc and have a recovery command ready.

1. Check the tool and the current qdisc

The installed system used for this guide has iproute2 6.1.0-1ubuntu6.4. First confirm the binary and inspect the interface without changing anything. These commands do not need root privileges on a normal installation.

tc -V
tc qdisc show dev eth0

Save the second command's output somewhere outside the terminal scrollback. A common result is a qdisc such as mq, fq_codel or noqueue. The exact output depends on the driver and distribution. If another administrator or service manages the interface, stop here and agree who owns the root qdisc.

Checkpoint

You have the correct interface name and a copy of its current qdisc configuration.

2. Choose the global packet limit

skbprio counts packets, not bytes. Its limit is the maximum number of packets held by the whole queue, across all priorities. The default is 64 packets, and the documented range is 0 through the maximum unsigned 32-bit value. Start with an explicit, modest value so the configuration is visible and repeatable:

LIMIT=256

A larger limit can absorb a burst but also keeps more data waiting and may increase latency. A smaller limit sheds pressure sooner. There is no universal correct number: relate it to the link speed, packet sizes, and the latency budget of the service. Do not mistake this setting for a bandwidth guarantee. It only bounds this queue.

3. Install skbprio as the root queue

Run the following as root, or prefix it with sudo. replace installs the requested root qdisc whether one already exists or not, so it can disrupt traffic briefly and discard packets already waiting in the old queue.

Warning

This changes live traffic handling. It also replaces the existing root qdisc. If the current output from step 1 is valuable, do not rely on memory. Record its complete configuration and arrange out-of-band access before continuing.

sudo tc qdisc replace dev eth0 root skbprio limit 256

A successful tc command normally prints nothing. Verify the result with:

tc -s qdisc show dev eth0

Look for a root qdisc identified as skbprio and a limit of 256 packets. The statistics format is not a stable interface for scripts, so use the qdisc name and the command's exit status as the basic check. The packet counters may still be zero on a quiet interface.

Checkpoint

The interface reports an skbprio root queue and the configured limit.

4. Understand where priority comes from

The qdisc does not classify packets itself. It reads the kernel packet field skb->priority. There are 64 priority lists, numbered 0 through 63. Packets enter the tail of their own list, and the scheduler takes packets from the head of the highest non-empty list. Packets with equal priority therefore leave in arrival order.

When the queue is full, the tail packet in the lowest-priority list is considered for removal. A newly arriving packet replaces it only when the new packet has a higher priority. Otherwise the new packet is dropped. This is a global limit: one busy priority cannot consume a separate allowance that defeats the total bound.

Priorities below 64 are used as supplied. A value of 64 or higher is treated as 63. This makes the top bucket a range, not a set of distinct priorities. Design the classifier with that boundary in mind.

The manpage describes a typical arrangement in which the IPv4 or IPv6 DS field is copied into skb->priority by the tc-skbedit(8) action. That action is separate from the queue. An skbprio command alone does not make DS markings, firewall marks or application priorities trustworthy. If you use skbedit inheritdsfield, check the classifier that invokes it and test the policy under your own traffic; packets without the intended classification still reach the qdisc with whatever priority they already have.

5. Test without guessing from a quiet queue

There is no useful priority demonstration in tc qdisc show alone. That command confirms installation, not the values assigned to individual packets. Test with a controlled workload and observe the application behaviour, qdisc statistics, and the classifier's counters. Keep the test below the link's normal capacity unless you deliberately want to exercise queue pressure.

tc -s qdisc show dev eth0
tc -s filter show dev eth0 parent ffff:

The second command is only an inspection example: it shows filters attached at the ingress parent when that parent exists, but it does not prove that a filter sets skb->priority. Use the actual parent and filter chain from your configuration. For a defensible test, generate separately identifiable low- and high-priority traffic, confirm the classifier assigns the intended values, then watch which packets survive during a controlled burst. Do not infer priority from DS markings alone if another action can overwrite the kernel field.

6. Remove the queue or restore the previous design

To remove the root qdisc, run this as root:

sudo tc qdisc del dev eth0 root

This changes the live interface again. After deletion, the driver or parent configuration may expose a default qdisc such as noqueue, or a different qdisc may be recreated by network management. Verify rather than assuming:

tc qdisc show dev eth0

If you replaced an earlier qdisc, restore it with the original command recorded in step 1, adapted to your system. The exact command cannot be reconstructed safely from the generic skbprio example. If the interface is managed by NetworkManager, systemd-networkd or another service, make the persistent configuration there as well, or the service may undo the manual change later.

Common traps

  • Wrong queue layer: a root qdisc is not the same as a class beneath another qdisc. Confirm the device and parent in every command.
  • Priority is not classification: skbprio consumes skb->priority; it does not assign it.
  • DS is only six bits here: values at or above 64 collapse to priority 63.
  • Limit units are packets: a 256-packet queue can hold very different amounts of data depending on packet size.
  • Permission errors are expected: changing qdiscs generally requires CAP_NET_ADMIN; sudo cannot help if the account is not permitted to administer the host.

Done means

  • The correct interface and installed iproute2 version were checked.
  • The previous root qdisc was recorded before making a change.
  • skbprio is installed with an intentional packet limit.
  • The priority source and the 0 to 63 boundary are understood.
  • tc -s qdisc show dev eth0 confirms the live state.
  • You have either a tested restoration command or have removed the temporary queue.