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 classid 11:3. To mark a packet for that band, set the packet priority to 0x110003 ๐Ÿ”ฅ
  • Filter flowid โ€” a tc filter attached to the qdisc can put the packet in a band using the flowid keyword ๐Ÿ’œ
  • 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 is 0, 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. The quanta argument lists quanta for the individual bandwidth-sharing bands, and the minimum for each quantum is 1. If you don't give quanta, 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 the strict keyword and the bandwidth-sharing bands from quanta. 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 the strict and quanta keywords.
  • 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 ๐Ÿฆ‹

tc(8), tc-prio(8), tc-drr(8)


๐Ÿซถ 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