Shape devlink Traffic Rates with Nodes and Port Limits
One noisy virtual function is eating the uplink, and tc on the host cannot touch it. devlink port function rate lets you inspect rate objects, create a named parent node, attach a leaf port to it, and apply shared and maximum transmit rates. The examples use the devlink-rate(8) interface from iproute2 6.1.0, installed here as package version 6.1.0-1ubuntu6.4. Allow about fifteen minutes, plus time to confirm the device and port identifiers with whoever owns the network configuration.
The route
Jump straight to the step you need, or tick off Done means at the end.
- Scope: these commands are for hardware and drivers that expose devlink rate objects. They do not shape an arbitrary Linux network interface.
- You need: the
devlinkcommand and a device whose driver supports this feature. - Privileges: reading state is normally unprivileged on a suitably configured host. Creating, changing or deleting objects may need
sudoand can affect live traffic.
1. Check the command and the current objects
Start with the installed binary and its built-in usage text. This is a read-only check:
$ command -v devlink
/usr/sbin/devlink
$ devlink -V
devlink utility, iproute2-6.1.0
$ devlink port function rate help
Usage: devlink port function rate help
devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]
devlink port function rate add DEV/NODE_NAME
[ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]
devlink port function rate del DEV/NODE_NAME
devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }
[ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]
List everything before choosing an identifier:
$ devlink port function rate show
pci/0000:03:00.0/1 type leaf parent some_group
pci/0000:03:00.0/2 type leaf tx_share 12Mbit
pci/0000:03:00.0/some_group type node tx_share 1Gbps tx_max 5Gbps
Your output is host-specific. Two object types matter:
- Leaf: belongs to a devlink port and is normally supplied by the driver.
- Node: a user-created group. Its name must not be a decimal number, because that would collide with how a leaf port is addressed.
If the command prints nothing, or JSON output is {"rate":{}}, stop and identify a supported device rather than guessing a path.
Checkpoint
Copy one real device path, such as pci/0000:03:00.0, and one real leaf port index from your own output. Replace DEV_PATH and PORT_INDEX below; do not paste the illustrative values unchanged.
2. Read one object in a script-friendly format
The ordinary display uses SI units such as Mbit and Gbps. Add -i when IEC units are easier to compare. Add -j for JSON; JSON rate values are always bytes per second, whatever unit the ordinary output uses.
$ devlink -j port function rate show DEV_PATH/PORT_INDEX
{
"rate": {
"DEV_PATH/PORT_INDEX": {
"type": "leaf",
"tx_share": 1500000
}
}
}
$ devlink -i port function rate show DEV_PATH/PORT_INDEX
DEV_PATH/PORT_INDEX type leaf tx_share 11718Kibit
These show the output shapes from the manual. Exact values, indentation and fields depend on the driver and current configuration. A zero rate means unlimited, so unlimited values and an unset parent are left out of the display. For automation, parse the JSON rather than matching the unit suffix in human-readable output.
3. Create an empty parent node
Creating a node changes device rate configuration. Confirm the name, limits and maintenance window first. This creates a node with no limits, which is handy as a grouping point:
$ sudo devlink port function rate add DEV_PATH/test_group
$ devlink port function rate show DEV_PATH/test_group
DEV_PATH/test_group type node
Use a name that means something on this device and is not only digits. The node belongs to the devlink device named by DEV_PATH; it is not a Linux directory, or a persistent object in a general-purpose configuration file.
Checkpoint
The new object should report type node. If the add fails, do not repeat it blindly. Check whether the node already exists, whether the driver supports rate management, and whether the name is a forbidden numeric-only value.
4. Set a group limit and attach a leaf
Values are floating-point or integer amounts followed by a bits or bytes per second unit. A bare number means bits per second, so explicit units are easier to review.
- SI bits:
kbit,mbitandgbit. - SI bytes:
kbps,mbpsandgbps. - IEC forms:
kibit,mibitand so on.
$ sudo devlink port function rate set DEV_PATH/test_group \
tx_share 100mbit tx_max 500mbit
$ sudo devlink port function rate set DEV_PATH/PORT_INDEX \
tx_share 20mbit tx_max 200mbit parent test_group
$ devlink port function rate show DEV_PATH/test_group
DEV_PATH/test_group type node tx_share 100Mbit tx_max 500Mbit
$ devlink port function rate show DEV_PATH/PORT_INDEX
DEV_PATH/PORT_INDEX type leaf parent test_group tx_share 20Mbit tx_max 200Mbit
tx_shareis the minimum transmit rate shared by members of the same group.tx_maxis the maximum transmit rate for that object.- Enforcement is driver-dependent. The parent node's limits apply to its children, but exactly how is up to the driver. A successful command means the driver accepted the setting; it does not prove a workload is currently reaching or being held to that rate.
Set the parent in the same command as the leaf rates when you want one reviewed change. To change only one field, omit the others. When an argument is given more than once, the last occurrence wins, which is a good reason to avoid generated command lines with duplicate fields.
5. Verify the live state before testing traffic
Inspect both objects, then use JSON if a monitoring script will record the result:
$ devlink port function rate show
$ devlink -jp port function rate show DEV_PATH/PORT_INDEX
{
"rate": {
"DEV_PATH/PORT_INDEX": {
"type": "leaf",
"parent": "test_group",
"tx_share": 2500000,
"tx_max": 25000000
}
}
}
JSON values are bytes per second: 20 Mbit is 2,500,000 bytes per second and 200 Mbit is 25,000,000 bytes per second. Treat the displayed result as the authoritative check of what the driver stored. Test traffic only after confirming the selected port serves the intended function.
6. Undo the test without leaving a child behind
Removing a parent that still has a child is rejected. Detach the leaf first, then remove the node. These commands change state and can alter traffic behaviour immediately:
$ sudo devlink port function rate set DEV_PATH/PORT_INDEX \
tx_share 0 tx_max 0 noparent
$ devlink port function rate show DEV_PATH/PORT_INDEX
DEV_PATH/PORT_INDEX type leaf
$ sudo devlink port function rate del DEV_PATH/test_group
Zero means unlimited, and noparent removes the group relationship. If the leaf had a limit before this test, record it first and restore those values instead of assuming zero is the right rollback. Re-run devlink port function rate show and confirm the node no longer appears.
Recovery
If deletion fails, confirm the node name and check for another child still attached to it.
Common traps
- Wrong address: leaf objects use
DEV/PORT_INDEX, while nodes useDEV/NODE_NAME. Copy the complete identifier fromshow. - Unexpected units: human output uses SI units unless
-iis selected; JSON is bytes per second. Convert before comparing numbers. - Missing parent:
parent NODE_NAMEmust name an existing node on the same device. Usenoparentto detach instead. - Failed deletion: a node with children cannot be deleted. Detach every child explicitly, then retry.
- No visible effect: rate enforcement is part of the driver's implementation. Confirm the stored configuration, the correct function and the driver documentation before blaming the command.
Done means
- Real target: you identified a rate-capable devlink device and copied its leaf identifier.
- Baseline first: you checked the current state before making changes.
- Explicit and verified: every node, parent relationship and rate limit used explicit units and was checked with
showor JSON. - Clean teardown: you detached test leaves before deleting their parent node, or recorded what is needed to restore it.
- Driver decides: you understand that the driver, not
devlinkalone, determines how limits affect live traffic.