Home / Alt manpages / tc-hfsc(8)

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

Shape a Linux Interface with HFSC Service Curves

HFSC shapes traffic by delay as well as by rate, so one class can get a low-latency slice while another takes what is left. This guide builds an HFSC qdisc on one Linux interface, adds a default class, and leaves you a class tree you can inspect and remove. Examples use the syntax shipped by iproute2 6.1.0, package version 6.1.0-1ubuntu6.4.

Allow about fifteen minutes, plus a maintenance window if the interface carries real traffic. You need tc, an interface you are authorised to reconfigure, and CAP_NET_ADMIN, normally obtained with sudo. HFSC changes packet scheduling; do not start on a production interface just to see whether the commands parse.

Checkpoint

This guide uses IFACE as a placeholder. Replace it with the interface you intend to shape, such as eth0 or ens18. Never paste IFACE literally.

1. Check the command and interface

These first checks are read-only and normally need no elevated privileges:

$ command -v tc
/usr/sbin/tc
$ tc -V
tc utility, iproute2-6.1.0, libbpf 1.3.0
$ ip -br link show
$ tc qdisc show dev IFACE

The final command may print an existing root qdisc, or nothing useful if the interface has none configured. Save the output before changing anything. If another tool manages the interface, make the change through that tool rather than racing it with a manual tc command.

2. Add an HFSC root qdisc

The qdisc has one option in the installed manual: default, which takes the minor part of a class ID. Without it, packets that no filter or classifier assigns are simply dropped. Create a class ID you will add in the next step:

$ sudo tc qdisc add dev IFACE root handle 1: hfsc default 10

This is the first state-changing command. A root qdisc replaces the interface's existing root scheduling arrangement, so stop if step 1 showed a qdisc owned by another service. To undo this test immediately, use the removal command in step 6.

Checkpoint

Confirm the qdisc exists before adding classes:

$ sudo tc qdisc show dev IFACE
qdisc hfsc 1: root refcnt 2 default 10

Counter values and some fields vary by kernel and traffic. What matters is the hfsc kind, root handle 1:, and default minor ID 10.

3. Add a class with a combined service curve

Every HFSC class needs at least one of rt, ls or sc. The sc form combines realtime and linkshare service curves. This example gives class 1:10 a two-segment curve, with an initial slope of 1 Mbit/s until 10 ms and a later slope of 5 Mbit/s:

$ sudo tc class add dev IFACE parent 1: classid 1:10 hfsc \
    sc m1 1mbit d 10ms m2 5mbit

In the manual's notation, m1 and m2 are slopes and d is the intersection time. The final slope is mandatory; omitting the first slope and its time makes a linear curve, for example sc 5mbit. Use full option names in scripts even where tc accepts abbreviations.

Class 1:10 is the qdisc's default, so it receives traffic that has not been classified elsewhere. That does not mean all traffic will automatically be divided between the classes you create later.

4. Add a second class with the alternative notation

HFSC also accepts a work-and-delay form. Here umax is the maximum unit of work, dmax is the maximum delay, and rate is the rate:

$ sudo tc class add dev IFACE parent 1: classid 1:20 hfsc \
    ls umax 1500 dmax 20ms rate 2mbit

This class uses ls, the linkshare curve. The values are an example policy, not a universal bandwidth recommendation: choose them from the traffic and link capacity you are actually managing, and do not assume 1500 is correct if your workload or device uses a different unit of work.

Checkpoint

Inspect the class tree and statistics:

$ sudo tc -s class show dev IFACE
class hfsc 1:10 root ...
class hfsc 1:20 root ...
$ sudo tc -s qdisc show dev IFACE

Exact formatting, byte counters and rate details vary. Check that both class IDs exist and the qdisc has not reported an error. A class entry alone does not prove the intended packets are actually entering it.

5. Understand upper limits and classification

An ul upper-limit curve may only be supplied with ls or sc. This example replaces class 1:20 with a linkshare curve and an upper limit of 1 Mbit/s:

$ sudo tc class replace dev IFACE parent 1: classid 1:20 hfsc \
    ls 2mbit ul 1mbit

replace is still a live policy change; use it only after checking the current class definition. The upper limit does not select packets: filters or another classifier still decide which class receives a packet. Before adding one, check the filters already used on the interface:

$ sudo tc filter show dev IFACE parent 1:

Do not add a filter with guessed match fields. A filter can divert production traffic immediately, and the correct syntax depends on the classifier and the traffic you actually intend to match.

6. Remove the test configuration safely

Warning

Deleting the root qdisc changes scheduling immediately and removes its child classes and filters with it. On a managed host, restore the configuration through its normal network-management system instead of using this command:

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

The second command should show the interface's post-removal state, which may be an automatically restored default qdisc or no explicit qdisc at all. If traffic becomes unexpectedly delayed or drops after a configuration change, remove the test qdisc, restore the previously recorded configuration, and check the service that normally owns the interface.

Common traps

  • Forgetting default can drop unclassified packets. Add a default class before testing traffic that has no filter.
  • Using ul with rt violates the documented combination rule. Pair it with ls or sc instead.
  • Confusing a class definition with classification hides a common failure: counters stay at zero because no filter sends packets there.
  • Running without CAP_NET_ADMIN produces an operation-not-permitted error. That is a privilege boundary, not evidence the HFSC syntax is invalid.
  • Applying a root qdisc twice fails if one is already present. Inspect first and use the owning service's configuration.

Done means

  • tc reports iproute2 6.1.0, or you have checked the syntax for your installed version.
  • HFSC root qdisc has an intentional default class.
  • Every class has a valid rt, ls or sc curve, and any ul curve is paired with ls or sc.
  • tc -s class show confirms the class IDs and gives you counters to monitor.
  • You know which classifier sends real traffic into each class.
  • Rollback command and interface owner's normal configuration recorded before production use.