Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

netlink-packet-ethtool

Packet types for the ethtool generic netlink family.

Generated from the kernel's own spec

src/constants.rs is generated from Documentation/netlink/specs/ethtool.yaml — the same file the kernel's ethtool_netlink_generated.h comes from — by the ethtool-codegen crate. Generation is a deliberate step with checked-in output, not a build.rs; nothing fetches at build time. See spec/PROVENANCE.md.

566 constants, 74 operations, 62 attribute sets.

Only names and numbers are generated. Everything with semantics is hand-written, because the spec records an attribute's type but not what it means:

shape why a generator cannot handle it
bitset two wire encodings, chosen by a request flag
type-value the attribute's identity is its nla type number
sub-type a binary blob reinterpreted as an array
byte-order one big-endian attribute among host-endian neighbours
uint variable width; 1, 2, 4 or 8 bytes for the same attribute

IRREGULAR_ATTRIBUTES lists the eight attributes with those shapes, and a test asserts it is unchanged — so a future spec adding a shape nothing can decode fails the build rather than silently misparsing.

Drift

tests/generated.rs cross-checks every generated constant against the build host's uapi header:

checked 498 generated constants against .../linux/ethtool_netlink_generated.h

It panics if it cannot find a header, rather than passing vacuously; ETHTOOL_UAPI_HEADER=skip is the explicit opt-out. The first version searched paths that do not exist on this machine, found nothing, and returned Ok — which is worse than no guard at all.

It earned its keep immediately, catching four generator bugs before any protocol code existed:

  1. subset-of never deserialised — the field was spelled with an underscore. A subset borrows its parent's numbering and the kernel emits no enum of its own for it, so the generator invented ETHTOOL_A_STATS_GRP_HIST_HIST_BKT_LOW = 0. The real constant is ..._HIST_BKT_LOW = 7.
  2. Reply numbering is not parallel to request numbering. A bare _SET gets no reply entry — except features-set, the one operation that declares its own.
  3. The spec spells "notification" two ways, notify: and event:. Treating only the first as one shifted every request from cable-test-tdr-act onwards.
  4. Attribute numbering starts at 1, not 0. Zero is reserved for unspec and a set that wants it says so explicitly.

tests/kernel_only.rs does the same for the hand-written constants that live in linux/ethtool.h rather than the spec. It also earned its keep: the first version of kernel_only::stringset had everything from ETH_SS_STATS_STD onward off by one.

Statistics

let request = StatsAttr::request("eth0", StatsAttr::STANDARD_GROUPS);

Verified against an mlx5 ConnectX-6: 29 counters, byte-identical to ethtool -S <dev> --groups eth-phy eth-mac eth-ctrl rmon, names resolved through STRSET_GET.

Three things the wire does that the spec does not say:

A counter is wrapped in its own nest. type-value means each counter sits in its own GRP_STAT holding exactly one attribute, whose nla type is the counter's index:

GRP
  GRP_ID     = 1                      <- eth-mac
  GRP_SS_ID  = 18                     <- ETH_SS_STATS_ETH_MAC
  GRP_STAT   len 12
    kind 0   len 8                    <- counter 0, a u64
  GRP_STAT   len 12
    kind 3   len 8                    <- counter 3; indices are sparse

Miss the wrapper and the counters look like malformed 12-byte children and decode to nothing at all — which is exactly what happened here first.

Histogram buckets are one attribute each, not a list inside one. Reading them as a list descends a level too far and tries to parse a u32 payload as attributes: NLA has invalid length: 0.

Group ids are in no uapi header. enum ethtool_stats_group lives in net/ethtool/stats.c yet crosses the netlink boundary in both directions. The mapping was pinned empirically, by asking for each group and checking the ss-id it replies with:

group id ss-id
eth-phy 0 17 = ETH_SS_STATS_ETH_PHY
eth-mac 1 18 = ETH_SS_STATS_ETH_MAC
eth-ctrl 2 19 = ETH_SS_STATS_ETH_CTRL
rmon 3 20 = ETH_SS_STATS_RMON

StatsAttr::request sidesteps them anyway by selecting groups by name, which the kernel resolves against ETH_SS_STATS_STD. That is what ethtool(8) does.

Nests need NLA_F_NESTED — on requests only

The kernel rejects a request whose nests lack the flag with a bare EINVAL. Replies, confusingly, do not set it, so the parser must not require it. This cost two debugging rounds: once for the statistics header and group selector, again for the inner STRINGSET.

NlaBuffer::kind masks the flag off, which is what lets a nest carry it outbound and still match its bare constant inbound — but it also means the flag is invisible through kind(), and a test asserting it must read the raw type field.

Bitsets

bitset.contains(31);   // works in either encoding
bitset.indices();      // ditto
bitset.names();        // empty for a compact bitset -- it carries no names

Verbose is a bits nest of index/name/value triples. Compact is a size plus value/mask as host-order 32-bit words. Which one arrives is decided by RequestFlags::compact_bitsets, not by the attribute, and the spec lists all five fields side by side with no hint they are alternatives.

nomask distinguishes a list from a change: without it, value says what to set and mask says which bits the request is talking about.

Request flags

RequestFlags::stats is why the previous Rust ethtool binding's pause statistics could never be populated: the kernel omits every optional stats sub-nest unless the request asks. Note this is not needed for STATS_GET, which is the statistics command.

Testing

cargo test --features bolero — round-trip property tests over the generated types. The previous binding emitted its pause Tx counter under the RX_FRAMES attribute id, a one-line slip that no test caught because there were none. attribute_kinds_are_distinct is that test.

Status

STRSET_GET and STATS_GET are implemented and hardware-verified. The remaining 70-odd operations have generated constants but no typed layer yet.

About

Packet types for the ethtool generic netlink family

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages