TC(8)
๐ NAME ๐
okay so the manual name here is ETS, which stands for Enhanced Transmission Selection, and it's a scheduler ๐ฆ It's a classful queuing discipline that merges what PRIO and DRR qdiscs do into one scheduler. Iconic behavior, honestly ๐
โจ SYNOPSIS โจ
tc qdisc ... ets [ bands number ] [ strict number ] [ quanta bytes bytes bytes... ] [ priomap band band band... ]
tc class ... ets [ quantum bytes ]
๐ธ DESCRIPTION ๐ธ
bestie, ETS is the scheduler that makes it super easy to set up a bunch of strict and bandwidth-sharing bands so you get the transmission selection described in 802.1Qaz. It's giving organized ๐
When you create it with tc qdisc add, a fixed number of bands gets made. Every band is a class, but you can't add or remove bands directly with tc class commands ๐
โโ๏ธ Instead, you have to tell it how many bands you want right there on the command line when you add the qdisc.
The minor number of the classid you use to refer to a band is the band number plus one. So band 0 is classid major:1, band 1 is major:2, and so on. Easy peasy ๐
ETS bands come in two flavors: some number of them can be in strict mode, and the rest are in bandwidth-sharing mode โจ
๐ง ALGORITHM ๐ง
okay so when it's time to dequeue, strict bands get tried first, if there are any. Band 0 goes first. If it doesn't deliver a packet, band 1 gets a turn, then band 2, and so on, until one of them delivers a packet or the strict bands run out ๐โโ๏ธ
If none of the strict bands dequeued a packet, and there are bandwidth-sharing bands, the dequeuing follows the DRR algorithm. Each bandwidth-sharing band gets a deficit counter that starts at the quantum given by a quanta element. ETS keeps an (internal) "active" list of bandwidth-sharing bands whose qdiscs aren't empty, and that's the list it uses for dequeuing. A packet comes out of the band at the head of the list if the packet size is smaller than or equal to the deficit counter. If the counter is too small, it gets increased by quantum and the scheduler moves on to the next band in the active list ๐ซถ
โ ๏ธ Only qdiscs that own their queue should be added below the bandwidth-sharing bands. Attaching non-work-conserving qdiscs like TBF to them doesn't make sense, because other qdiscs in the active list will get skipped until the dequeue operation succeeds. This limitation doesn't exist with the strict bands, so you're fine there ๐
๐ฏ CLASSIFICATION ๐ฏ
the ETS qdisc gives you three ways to decide which band a packet gets enqueued to:
- Direct class handle โ you can set the packet priority straight to a class handle, and that class's queue is where the packet ends up. For example, band number 2 of a qdisc with handle
11:has classid11:3. To mark a packet for that band, set the packet priority to0x110003๐ฅ - Filter flowid โ a
tcfilter attached to the qdisc can put the packet in a band using theflowidkeyword ๐ - Priomap as a last resort โ if nothing else decided, the ETS qdisc checks its priomap (more on that below), which maps packets to bands based on packet priority ๐
๐ PARAMETERS ๐
strictโ the number of bands that should be created in strict mode. If you don't give it, this is0, so no strict bands ๐quantaโ every bandwidth-sharing band needs to know its quantum, which is how many bytes a band can dequeue before the scheduler hops to the next bandwidth-sharing band. Thequantaargument lists quanta for the individual bandwidth-sharing bands, and the minimum for each quantum is1. If you don't givequanta, the default is no bandwidth-sharing bands. But heads up: when you specify a big number of bands, the extra ones are in bandwidth-sharing mode by default ๐ฆbandsโ the number of bands, given explicitly. This has to be at least big enough to cover the strict bands from thestrictkeyword and the bandwidth-sharing bands fromquanta. If you give a bigger value, the extra bands are in bandwidth-sharing mode, and their quanta are deduced from the interface MTU โจ If you don't give a value at all, as many bands get created as needed to cover everything implied by thestrictandquantakeywords.priomapโ the priomap maps the priority of a packet to a band. The argument is a list of numbers. The first number says which band packets with priority 0 go to, the second is for priority 1, and so on. There can be up to 16 numbers in the list. If there are fewer than 16, the default band for traffic with any of the unmentioned priorities is the last one in the list ๐ง
๐ EXAMPLE & USAGE ๐
okay bestie, here are the vibes, step by step.
Add a qdisc with 8 bandwidth-sharing bands and use the interface MTU as their quanta. Since all the quanta are the same, you get equal bandwidth sharing between the bands, and each one gets about 12.5% of the link. The low 8 priorities go to individual bands in a reverse 1:1 fashion, so the highest priority goes to the first band ๐ธ
# tc qdisc add dev eth0 root handle 1: ets bands 8 priomap 7 6 5 4 3 2 1 0
# tc qdisc show dev eth0
qdisc ets 1: root refcnt 2 bands 8 quanta 1514 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
Next, tweak the first band of the qdisc above to give it a quantum of 2650. That gives it about 20% of the link, and about 11.5% to each of the remaining bands ๐
# tc class change dev eth0 classid 1:1 ets quantum 2650
# tc qdisc show dev eth0
qdisc ets 1: root refcnt 2 bands 8 quanta 2650 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
Now make a purely strict qdisc with a reverse 1:1 mapping between priorities and bands ๐ฅ
# tc qdisc add dev eth0 root handle 1: ets strict 8 priomap 7 6 5 4 3 2 1 0
# tc qdisc sh dev eth0
qdisc ets 1: root refcnt 2 bands 8 strict 8 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7
Add a qdisc with 6 bands: 3 strict and 3 ETS with 35%-30%-25% weights โจ
# tc qdisc add dev eth0 root handle 1: ets strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5
# tc qdisc sh dev eth0
qdisc ets 1: root refcnt 2 bands 6 strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5 5 5 5 5 5 5 5 5
Last one! Create a qdisc where traffic with priorities 2, 3 and 4 is strictly prioritized over everything else, and the rest goes into bandwidth-sharing classes with equal weights ๐
# tc qdisc add dev eth0 root handle 1: ets bands 8 strict 3 priomap 3 4 0 1 2 5 6 7
# tc qdisc sh dev eth0
qdisc ets 1: root refcnt 2 bands 8 strict 3 quanta 1514 1514 1514 1514 1514 priomap 3 4 0 1 2 5 6 7 7 7 7 7 7 7 7 7
๐ฆ SEE ALSO ๐ฆ
๐ซถ AUTHOR ๐ซถ
parts of both this manual page and the code itself are taken from the PRIO and DRR qdiscs ๐ The ETS qdisc itself was written by Petr Machata ๐
bestie, that's the whole page ๐ This manual came from iproute2, dated December 2019, and it's the TC(8) page. Stay iconic, and go touch some grass after all that bandwidth math ๐ฆ๐
๐ฆ where this page comes from
- alpine 3.22: iproute2-doc 6.15.0-r0 ยท GPL-2.0-or-later
- alpine 3.23: iproute2-doc 6.17.0-r0 ยท GPL-2.0-or-later
- alpine 3.24: iproute2-doc 7.0.0-r0 ยท GPL-2.0-or-later
- arch rolling: iproute2 7.2.0-1
- arch rolling: iproute2 7.3.0-1 ยท GPL-2.0-or-later
- centos-stream 10: iproute-tc 7.0.0-2.el10 ยท GPL-2.0-or-later
- centos-stream 9: iproute-tc 6.17.0-3.el9 ยท GPL-2.0-or-later
- debian bookworm: iproute2 6.1.0-3 ยท GPL-2.0-only
- debian trixie: iproute2 6.15.0-1 ยท GPL-2.0-only
- fedora 43: iproute-tc 6.14.0-2.fc43 ยท GPL-2.0-or-later
- fedora 44: iproute-tc 6.17.0-2.fc44 ยท GPL-2.0-or-later
- nixos 26.05: iproute2 7.0.0
- nixpkgs unstable: iproute2 7.2.0
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- ubuntu jammy: iproute2 5.15.0-1ubuntu2 ยท GPL-2.0-only
- ubuntu jammy: iproute2 5.15.0-1ubuntu2.2 ยท GPL-2.0-only
- ubuntu noble: iproute2 6.1.0-1ubuntu6 ยท GPL-2.0-only
- ubuntu noble: iproute2 6.1.0-1ubuntu6.4 ยท GPL-2.0-only
- ubuntu questing: iproute2 6.16.0-1ubuntu2
- ubuntu questing: iproute2 6.16.0-1ubuntu2.1 ยท GPL-2.0-only
- ubuntu questing: iproute2 6.16.0-1ubuntu2.2
- ubuntu resolute: iproute2 6.19.0-1ubuntu1 ยท GPL-2.0-only
- ubuntu resolute: iproute2 6.19.0-1ubuntu1.1 ยท GPL-2.0-only
- ubuntu stonking: iproute2 7.2.0-1ubuntu1 ยท GPL-2.0-only
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms