STAB(8)
๐ NAME ๐
okay so the whole page is about tc-stab, which is just "Generic size table manipulations" ๐ It's how you tell the traffic control stuff what packet sizes to pretend they are. Lowkey iconic. โจ
๐ง SYNOPSIS ๐ง
tc qdisc add ... stab
[ mtu BYTES ] [ tsize SLOTS ]
[ mpu BYTES ] [ overhead BYTES ]
[ linklayer { adsl | atm | ethernet } ] ...
๐ธ OPTIONS ๐ธ
bestie, for what BYTES means, go check the UNITS section of tc(8). It's giving homework, but it's important ๐
mtuโ the biggest packet size the size table gets built for. If you don't say it explicitly, it's assumed to be2048๐tsizeโ how many slots the table needs. Defaults to512if you skip it ๐mpuโ the minimum packet size used in the math ๐ซถoverheadโ extra per-packet size added in the math. It can be negative, which is a whole mood ๐linklayerโ the link layer you're on. This one's required, no skipping ๐ฅ
๐ DESCRIPTION ๐
okay so size tables let you mess with packet sizes as the whole scheduler framework sees them. The real packet doesn't change size at all, just the number the scheduler uses. โจ The adjusted size only gets calculated once, when a qdisc enqueues the packet. The initial root enqueue sets it to the real packet's size. ๐ฆ
Every qdisc can have its own size table, but the adjusted size lives in one area that's shared by the whole qdisc hierarchy on the interface. So if you have a setup like that, the last qdisc with a stab in the chain wins ๐ For example, picture HFSC with a simple pfifo hanging off one of its leaf classes. If that pfifo has a stab defined, it overrides the lengths HFSC calculated during its enqueue. Then whenever HFSC dequeues a packet, it uses a potentially invalid size in its calculations. ๐ Normal setups usually only put a stab on the root qdisc, but overriding gives you extra flexibility for less usual setups ๐
The initial size table gets calculated by the tc tool using the mtu and tsize params. Each slot's size is set to the smallest power of 2 value, so the whole mtu is covered. Neither tsize nor mtu has to be a power of 2, so the table will usually support more than mtu needs ๐
For example, with mtu = 1500 and tsize = 128, you get a table with 128 slots. Slot 0 corresponds to sizes 0-16, slot 1 to 17 - 32, ..., and slot 127 to 2033 - 2048. What each slot holds depends on the linklayer parameter ๐ง
Stab calculation is also safe for an unusual case where a size assigned to a slot would be bigger than 2^16-1. You'll lose some accuracy though, so heads up ๐
During the kernel part of packet size adjustment, overhead gets added to the original size, and then the slot is calculated. If that would overflow, more than 1 slot gets used to get the final size. This affects accuracy, but it's only a guard for unusual situations ๐ก๏ธ
Right now there are two methods for the values stored in the size table: ethernet and atm (adsl) ๐
ethernetโ basically a 1-1 mapping. Using our example from above (ignoringmpufor a sec), slot 0 holds 8, slot 1 holds 16, and so on, up to slot 127 with 2048. Note thatmpu > 0must be specified, and any slot that would get less thanmpugetsmpuinstead. If you don't specifympu, the size table won't be created at all, since it wouldn't make a difference.overheadstill gets respected in the calculations though โจatm,adslโ ATM linklayer uses 53 byte cells, and each cell gives 48 bytes for payload. All cells have to be fully used, so the last one gets padded if/as needed ๐ซถ
When the size table is calculated, the adjusted size that fits into the lowest number of cells gets assigned to a slot. For example, a 100 byte packet needs three 48-byte payloads, so the final size needs 3 ATM cells, which is 159 bytes ๐
For ATM size tables, 16 bytes sized slots are perfectly enough. But the default mtu and tsize values make 4 bytes sized slots ๐ค
๐ฆ TYPICAL OVERHEADS ๐ฆ
these values are typical for different adsl scenarios (based on [1] and [2]) ๐
โจ LLC based โจ
- PPPoA - 14 (PPP - 2, ATM - 12)
- PPPoE - 40+ (PPPoE - 8, ATM - 18, ethernet 14, possibly FCS - 4+padding)
- Bridged - 32 (ATM - 18, ethernet 14, possibly FCS - 4+padding)
- IPoA - 16 (ATM - 16)
๐ท VC Mux based ๐ท
- PPPoA - 10 (PPP - 2, ATM - 8)
- PPPoE - 32+ (PPPoE - 8, ATM - 10, ethernet 14, possibly FCS - 4+padding)
- Bridged - 24+ (ATM - 10, ethernet 14, possibly FCS - 4+padding)
- IPoA - 8 (ATM - 8)
there are a few important things about the overheads above, so pay attention ๐
- IPoA in the LLC case needs SNAP instead of LLC-NLPID (see rfc2684), which is why it actually takes more space than PPPoA ๐
- In rare cases, FCS might be preserved on protocols that include Ethernet frames (Bridged and PPPoE). In that situation, any Ethernet specific padding guaranteeing a 64 bytes long frame size has to be included too (see RFC2684). In other words, it also guarantees that any packet you send takes minimum 2 atm cells. So set
mpuaccordingly for that ๐ - When the size table gets consulted and you're shaping traffic for the sake of another modem/router, an Ethernet header (without padding) is already added to the initial packet's length. You should compensate by subtracting 14 from the overheads above in this case. If you're shaping directly on the router (like with a speedtouch usb modem) using the ppp daemon, you're on a raw ip interface without an underlying layer2, so nothing gets added ๐ง
For more thorough explanations, check out [1] and [2] ๐
๐ ETHERNET CARDS CONSIDERATIONS ๐
it's often forgotten that modern network cards (even the cheap ones on desktop motherboards) and/or their drivers often support different offloading mechanisms ๐ For traffic shaping, tso and gso might cause undesirable effects, since massive TCP segments get considered during shaping (including stab calculations). For slow uplink interfaces, it's good to use ethtool to turn off offloading features ๐ฅ
๐ SEE ALSO ๐
tc(8), tc-hfsc(7), tc-hfsc(8), [1] http://ace-host.stuart.id.au/russell/files/tc/tc-atm/ [2] http://www.faqs.org/rfcs/rfc2684.html
please send bugreports and patches to: <netdev@vger.kernel.org> ๐
๐ AUTHOR ๐
manpage created by Michal Soltys (soltys@ziu.info) ๐ซถ
okay that's the whole STAB(8) page, bestie ๐ it's from iproute2, last updated 31 October 2011, and it's a certified main character of the traffic control world ๐ฆโจ
๐ฆ 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