MQPRIO(8)

๐Ÿ“ฆ
version 7.3.0 ยท 2 versions
  • 7.3.0 ยท alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking (latest)
  • 6.1.0 ยท debian bookworm, ubuntu jammy, ubuntu noble
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŽ€ NAME ๐ŸŽ€

okay so MQPRIO is the Multiqueue Priority Qdisc (Offloaded Hardware QOS) and it's giving main character energy ๐Ÿ’–

โœจ SYNOPSIS โœจ

tc qdisc ... dev dev ( parent classid | root) [ handle major: ] mqprio
        [ num_tc tcs ] [ map P0 P1 P2... ] [ queues count1@offset1
count2@offset2 ... ]
        [ hw 1|0 ] [ mode dcb|channel ] [ shaper dcb|bw_rlimit ]
        [ min_rate min_rate1 min_rate2 ... ] [ max_rate max_rate1
max_rate2 ... ]
        [ fp FP0 FP1 FP2 ... ]

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

bestie, the MQPRIO qdisc is a simple queuing discipline, and I'm obsessed. It lets you map traffic flows onto hardware queue ranges using priorities, plus a configurable priority-to-traffic-class map ๐Ÿงš. A traffic class here is a set of contiguous qdisc classes that map 1:1 onto a set of hardware exposed queues.

By default the qdisc gives you a pfifo qdisc (a packet limited first in, first out queue) for every TX queue the lower layer device exposes. You can add other queuing disciplines later if you want. Packets get enqueued using the map parameter and get hashed across the queues described by the offset and count. Honestly the driver usually configures all of this for you so it matches the hardware QOS structures ๐Ÿ’….

Channel mode is the full-send option ๐Ÿ”ฅ. It offloads the mqprio options, the traffic classes, the queue configurations and the QOS attributes to the hardware. Hardware that supports it can steer traffic flows into the traffic classes this qdisc provides. Hardware based QOS gets configured with the shaper parameter, and bw_rlimit lets you set minimum and maximum bandwidth rates for each traffic class. You can also add more qdiscs to the classes of MQPRIO if you want something extra complex ๐ŸŒˆ.

๐ŸŒธ ALGORITHM ๐ŸŒธ

When you create it with tc qdisc add, eight traffic classes get made automatically. Priorities 0..7 map to traffic classes 0..7, and any priority greater than 7 goes to traffic class 0. This needs base driver support, so the creation will fail on devices that don't support hardware QOS schemes ๐Ÿ’€.

You can override these defaults with the qdisc parameters. If you pass the hw 0 flag, software runs without hardware coordination ๐Ÿซถ.

If hardware coordination is in use and you hand it arguments the hardware can't support, you'll get an error. For most people the hardware defaults work reasonably well, so don't stress ๐Ÿ“.

Here's a specific example: loads of Ethernet cards support the 802.1Q link strict priority transmission selection algorithm (TSA). MQPRIO-enabled hardware, paired with the classification methods below, can give you hardware offloaded support for this TSA โœจ.

๐Ÿงš CLASSIFICATION ๐Ÿงš

There are multiple ways to set the SKB priority, and MQPRIO uses that priority to pick which traffic class the packet gets enqueued into. iykyk ๐Ÿ™ˆ.

๐Ÿ‘‘ From user space

A process with sufficient privileges can encode the destination class directly with SO_PRIORITY. Check out socket(7) for the details ๐Ÿ’œ.

๐Ÿ”ฅ With iptables/nftables

You can make an iptables/nftables rule that matches traffic flows and sets the priority. iptables(8) ๐Ÿ’–

๐ŸŒˆ With net_prio cgroups

The net_prio cgroup can set the priority of all sockets belonging to an application. See the kernel and cgroup documentation for the deets ๐Ÿฆ‹.

๐ŸŽ€ QDISC PARAMETERS ๐ŸŽ€

  • num_tc โ€” how many traffic classes you want. You can have up to 16 classes. You cannot have more classes than queues ๐Ÿซง
  • map โ€” the priority to traffic class map. It maps priorities 0..15 to whichever traffic class you pick ๐Ÿ—บ๏ธ
  • queues โ€” the count and offset of the queue range for each traffic class, written as count@offset. Queue ranges for different traffic classes cannot overlap, and each one has to be a contiguous range of queues ๐Ÿšซ
  • hw โ€” set to 1 to support hardware offload, or 0 to configure your user specified values in software only. The default is 1 ๐Ÿ”ฅ
  • mode โ€” set to channel for the full set of mqprio options. Use dcb if you only want to offload the TC values and use the hardware QOS defaults. This is only supported with hw set to 1 โœจ
  • shaper โ€” use bw_rlimit to set bandwidth rate limits for a traffic class. Use dcb for the hardware QOS defaults. Supported with hw set to 1 only ๐Ÿ’…
  • min_rate โ€” the minimum bandwidth rate limit for a traffic class. Only supported when shaper is set to bw_rlimit ๐ŸŒธ
  • max_rate โ€” the maximum bandwidth rate limit for a traffic class. Only supported when shaper is set to bw_rlimit ๐ŸŒธ
  • fp โ€” picks whether each traffic class is express (delivers packets via the eMAC) or preemptible (delivers packets via the pMAC). This follows IEEE 802.1Q-2018 clause 6.7.2 Frame preemption ๐Ÿฆ‹. It's an array with one element per traffic class, and each value is E (express) or P (preemptible).

Multiple priorities that map to the same traffic class, and multiple TXQs that map to the same traffic class, must have the same FP attributes. To read FP as a per-priority attribute, use the map argument for translation. To read FP as a per-TXQ attribute, use the queues argument for translation ๐Ÿง .

Traffic classes are express by default. This argument is only supported with hw set to 1. Preemptible traffic classes are only accepted if the device has a MAC Merge layer that you can configure through ethtool(8) ๐Ÿซถ.

๐Ÿ’– SEE ALSO ๐Ÿ’–

ethtool(8)

๐ŸŒˆ EXAMPLE ๐ŸŒˆ

This first one attaches priorities to 4 traffic classes (num_tc 4), then pairs those traffic classes with 4 hardware queues using mqprio, with hardware coordination (hw 1, or you can leave it out since 1 is the default value). Traffic class 0 (tc0) maps to hardware queue 0 (q0), tc1 maps to q1, tc2 maps to q2, and tc3 maps to q3 ๐Ÿ“.

# tc qdisc add dev eth0 root mqprio               num_tc 4               map 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3               queues 1@0 1@1 1@2 1@3               hw 1

The next one attaches priorities to 3 traffic classes (num_tc 3) and pairs them with 4 queues without hardware coordination (hw 0). Traffic class 0 (tc0) maps to hardware queue 0 (q0), tc1 maps to q1, and tc2 maps to both q2 and q3, where the queue selection between those two is kinda random ๐ŸŽฒ.

# tc qdisc add dev eth0 root mqprio               num_tc 3               map 0 0 0 0 1 1 1 1 2 2 2 2 2 2 2 2               queues 1@0 1@1 2@2               hw 0

In both examples, priority values 0 to 3 (prio0-3) map to tc0, prio4-7 map to tc1, and prio8-11 map to tc2 (that's the map attribute doing its thing โœจ). The last four priority values (prio12-15) get mapped differently in each example. In the first one they go to tc3, and in the second one they go to tc2 ๐Ÿ™ˆ. Here's how the two examples compare:

โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚Prioโ”‚ tc โ”‚ queue โ”‚  โ”‚Prioโ”‚ tc โ”‚  queue โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  0 โ”‚  0 โ”‚     0 โ”‚  โ”‚  0 โ”‚  0 โ”‚      0 โ”‚
โ”‚  1 โ”‚  0 โ”‚     0 โ”‚  โ”‚  1 โ”‚  0 โ”‚      0 โ”‚
โ”‚  2 โ”‚  0 โ”‚     0 โ”‚  โ”‚  2 โ”‚  0 โ”‚      0 โ”‚
โ”‚  3 โ”‚  0 โ”‚     0 โ”‚  โ”‚  3 โ”‚  0 โ”‚      0 โ”‚
โ”‚  4 โ”‚  1 โ”‚     1 โ”‚  โ”‚  4 โ”‚  1 โ”‚      1 โ”‚
โ”‚  5 โ”‚  1 โ”‚     1 โ”‚  โ”‚  5 โ”‚  1 โ”‚      1 โ”‚
โ”‚  6 โ”‚  1 โ”‚     1 โ”‚  โ”‚  6 โ”‚  1 โ”‚      1 โ”‚
โ”‚  7 โ”‚  1 โ”‚     1 โ”‚  โ”‚  7 โ”‚  1 โ”‚      1 โ”‚
โ”‚  8 โ”‚  2 โ”‚     2 โ”‚  โ”‚  8 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚  9 โ”‚  2 โ”‚     2 โ”‚  โ”‚  9 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 10 โ”‚  2 โ”‚     2 โ”‚  โ”‚ 10 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 11 โ”‚  2 โ”‚     2 โ”‚  โ”‚ 11 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 12 โ”‚  3 โ”‚     3 โ”‚  โ”‚ 12 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 13 โ”‚  3 โ”‚     3 โ”‚  โ”‚ 13 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 14 โ”‚  3 โ”‚     3 โ”‚  โ”‚ 14 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ”‚ 15 โ”‚  3 โ”‚     3 โ”‚  โ”‚ 15 โ”‚  2 โ”‚ 2 or 3 โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
      example1             example2

Here's another queue mapping for you. This one has 5 traffic classes and 8 hardware queues ๐Ÿซง.

# tc qdisc add dev eth0 root mqprio               num_tc 5               map 0 0 0 1 1 1 1 2 2 3 3 4 4 4 4 4               queues 1@0 2@1 1@3 1@4 3@5

And here's how the values map out for that one:

        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 tc0โ”€โ”€โ”€โ”€โ”คQueue 0โ”‚โ—„โ”€โ”€โ”€โ”€1@0
        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ”Œโ”€โ”คQueue 1โ”‚โ—„โ”€โ”€โ”€โ”€2@1
 tc1โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ””โ”€โ”คQueue 2โ”‚
        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
 tc2โ”€โ”€โ”€โ”€โ”คQueue 3โ”‚โ—„โ”€โ”€โ”€โ”€1@3
        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
 tc3โ”€โ”€โ”€โ”€โ”คQueue 4โ”‚โ—„โ”€โ”€โ”€โ”€1@4
        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ”Œโ”€โ”คQueue 5โ”‚โ—„โ”€โ”€โ”€โ”€3@5
      โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
 tc4โ”€โ”€โ”ผโ”€โ”คQueue 6โ”‚
      โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ””โ”€โ”คQueue 7โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

John Fastabend, <john.r.fastabend@intel.com>


that's a wrap, bestie ๐Ÿซถ๐Ÿ’– this MQPRIO(8) page came from iproute2, dated 24 Sept 2013, and I'm literally obsessed with it ๐Ÿฆ‹โœจ