Shape Link Sharing with the Linux tc ETS Scheduler

Some traffic must go first no matter what; the rest should just share whatever bandwidth is left fairly. Enhanced Transmission Selection (ETS) gives you both in one queueing discipline: strict bands for traffic that must go first, and bandwidth-sharing bands for traffic that should share the remaining link. You will also check the resulting class map, change a quantum, and remove the temporary configuration safely.

Allow about 15 minutes for a first test. You need Linux with the iproute2 package, the tc command, and an interface you can briefly disrupt. The commands below use eth0 as a placeholder. Replace it with the real interface name, and run configuration commands as root or through sudo. Inspecting an existing qdisc normally needs no elevated privileges.

Checkpoint: do not start until you know how to undo the change. Record the current root qdisc first:

$ tc qdisc show dev eth0

Replacing a root qdisc changes how packets leave the interface and can affect a live connection. Test over a local console or an independent management path if the interface carries your access.

1. Confirm the local implementation

ETS is a classful qdisc combining strict priority scheduling with deficit round robin (DRR) style bandwidth sharing. This guide was checked with Ubuntu's iproute2 package version 6.1.0-1ubuntu6.4, reporting tc utility, iproute2-6.1.0. The syntax on another release may differ, so ask the installed command for its ETS options:

$ tc qdisc add dev lo root handle 1: ets help
Usage: ... ets [bands NUMBER] [strict NUMBER] [quanta Q1 Q2...] [priomap P1 P2...]

The command above only requests help. It does not create a qdisc. The names in that output are the options used below.

2. Choose the bands and classification

An ETS qdisc creates a fixed number of bands when it is added. Band numbers start at zero in the configuration, but the corresponding class minor number is one higher: band 0 is class 1:1 when the handle is 1:, band 1 is 1:2, and so on.

Tip: if the priomap list is shorter than 16 values, unmentioned priorities use the final value in the list. This default-to-the-last-entry behaviour is an easy source of accidental classification.

3. Create equal sharing bands

This example creates eight bandwidth-sharing bands. The interface MTU supplies their default quanta, so continuously busy bands receive approximately equal service. Priorities 0 through 7 are mapped in reverse order, making priority 7 use band 0 and priority 0 use band 7.

# sudo tc qdisc add dev eth0 root handle 1: ets bands 8 priomap 7 6 5 4 3 2 1 0

Verify the installed state before attaching child qdiscs or filters:

$ tc qdisc show dev eth0
qdisc ets 1: root refcnt 2 bands 8 quanta ... priomap 7 6 5 4 3 2 1 0 ...

The exact refcnt, MTU-derived quantum, and repeated fallback priorities can vary. What matters here is the ETS handle, eight bands, and the mapping you supplied.

4. Give selected traffic strict service

To reserve the first three bands for strict service and leave three sharing bands, replace the temporary qdisc with this configuration. The three sharing quanta have weights 3500, 3000, and 2500, so their approximate busy-link proportions are 35%, 30%, and 25% of the sharing service. Strict traffic can consume more than that because it is served first.

# sudo tc qdisc replace dev eth0 root handle 1: ets strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 5 6 7

Here priorities 0, 1, 2, 3 and 4 go to bands 0, 1, 1, 1 and 2. Priorities 5, 6 and 7 go to bands 5, 6 and 7. Because three strict bands are reserved, band 5 is the first sharing band in this six-band configuration. Check the result:

$ tc qdisc show dev eth0
qdisc ets 1: root refcnt 2 bands 6 strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 5 6 7 ...

replace is deliberate: it updates the root qdisc in one operation, but it still changes live traffic. If you are not ready to change service, use tc qdisc show and postpone the replace command.

5. Change one sharing weight

A sharing band's quantum can be changed through its class. In the six-band example, class 1:4 is band 3, the first bandwidth-sharing band. Increase its quantum to 4000:

# sudo tc class change dev eth0 classid 1:4 ets quantum 4000

Confirm that the qdisc reports the new value:

$ tc qdisc show dev eth0
qdisc ets 1: root ... quanta 4000 3000 2500 ...

The displayed quanta are not a hard reservation. They influence the DRR share only when the sharing bands have queued traffic. Strict bands are still examined first, so a busy strict band can reduce the service available to every sharing band.

6. Attach child qdiscs with care

ETS bands are classes, so filters can target them with flowid, and packet priority can directly select a class handle. A filter is not required for the priomap examples above.

Warning: if you do attach a child qdisc below a sharing band, it must own its queue. The ETS manual specifically warns that a non-work-conserving qdisc such as TBF does not make sense there: ETS can skip that band until its dequeue operation succeeds, allowing other active bands to be skipped as well. The same limitation does not apply to strict bands.

Keep classification and queueing separate while testing. First confirm the root ETS mapping. Then add one filter or child qdisc, inspect the result, and send a known test flow. This makes a wrong flowid, an unexpected priority, or an empty child queue easier to locate.

7. Restore the previous state

When the test is over, remove the ETS root qdisc. This is a privileged, service-affecting command. It removes the ETS configuration and returns the interface to the kernel's default root behaviour unless another qdisc is configured.

# sudo tc qdisc del dev eth0 root
$ tc qdisc show dev eth0

If the interface had a previous custom qdisc, deletion does not recreate it. Restore that earlier configuration from the command or configuration management record you saved before step 1. If you used a disposable interface, deleting the root qdisc is usually sufficient.

Common traps

Done means