netlink-packet-core

Protocol-agnostic NetlinkMessage types for parsing and building Linux netlink packets in Rust

Library
Cargo
v0.9.0
8stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
46/100Fair
Development Activity72
Maintenance44
Community16
Maturity52
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
74/100Good
Architecture78
Code Quality75
Innovation70
Learning Curve60

netlink-packet-core provides the generic NetlinkMessage<T> type and the NetlinkSerializable / NetlinkDeserializable traits that let any Rust crate implement a Linux netlink sub-protocol without reimplementing the shared message header, error, done, and overrun handling. It underpins the wider rust-netlink ecosystem, including netlink-packet-route, netlink-packet-audit, and the asynchronous netlink-proto client.

Rather than shipping protocol-specific logic itself, the crate focuses purely on the parts of the netlink wire format that every sub-protocol shares: the 16-byte header, NLM_F_* flag constants, NLA (netlink attribute) buffer helpers, and byte-order-aware integer parsers/emitters. Downstream crates plug their own message payload type into NetlinkMessage<T> and get consistent serialization, deserialization, and error handling for free.

What You Get

  • A generic NetlinkMessage<T> struct with header and payload fields covering Noop, Done, Overrun, Error, and InnerMessage variants
  • NetlinkSerializable / NetlinkDeserializable traits to plug a custom sub-protocol message type into the shared framing logic
  • NetlinkHeader with the standard length/type/flags/sequence/port fields plus NLM_F_* flag constants
  • NLA (netlink attribute) buffer helpers — Nla, NlaBuffer, NlasIterator, DefaultNla — for TLV-encoded attribute payloads
  • Byte-order-aware integer parse/emit helpers (parse_u32, emit_u32_be, etc.) for building payload codecs

Common Use Cases

  • Implementing a new netlink sub-protocol (rtnetlink, audit, generic netlink) by defining a message type and wiring it into NetlinkMessage<T>
  • Parsing raw netlink socket reads into typed messages before dispatching them to protocol-specific handlers
  • Building an async netlink client (as netlink-proto does) on top of a stable, protocol-independent message envelope
  • Writing low-level Linux network configuration tools that need to construct and send netlink requests by hand

Under The Hood

Architecture netlink-packet-core layers a generic NetlinkMessage<T> (src/message.rs) over a raw byte-level NetlinkBuffer (src/buffer.rs) that exposes fixed-offset getters/setters for the 16-byte netlink header (length, message_type, flags, sequence_number, port_number, defined in src/header.rs). Deserialization flows through the Parseable trait: NetlinkMessage::parse reads the header via NetlinkHeader::parse, then branches on message_type to route NLMSG_ERROR into ErrorBuffer/ErrorMessage (src/error.rs), NLMSG_DONE into DoneBuffer/DoneMessage (src/done.rs), NLMSG_NOOP/NLMSG_OVERRUN into fixed payload variants, and any other type into the caller-supplied I: NetlinkDeserializable implementation. Serialization is the mirror path through Emitable::emit, gated by NetlinkMessage::finalize() which recomputes header.length and header.message_type from the payload before emit. Netlink attribute (NLA/TLV) parsing is a separate concern in src/nla.rs, with NlaBuffer, NlasIterator, and the DefaultNla fallback type, built on the same Parseable/Emitable trait pair so sub-protocol crates like netlink-packet-route can reuse the same attribute-iteration code for their own payload types.

Tech Stack The crate is pure Rust with almost no external dependencies: Cargo.toml declares only paste = “1” (used via #[macro_use] mod macros for the buffer! code-generation macros that create typed getter/setter methods on buffer structs), plus netlink-packet-route as a dev-dependency for the doc examples/tests. It targets edition 2021, has zero unsafe blocks in the reviewed source, and builds without extra std feature flags. CI (.github/workflows/main.yml, clippy-rustfmt.yml, license.yml) runs cargo fmt —all — —check and cargo clippy — -D warnings on nightly, plus an Apache skywalking-eyes SPDX header check enforced by .licenserc.yaml, so every merged commit is clippy-clean and consistently formatted.

Code Quality Six of the twelve source files (buffer, done, error, header, message, nla) carry #[cfg(test)] unit tests exercising round-trip serialize/deserialize behavior — message.rs’s test_done and test_error build a NetlinkMessage, finalize() it, emit to a buffer, and assert the reparsed value equals the original. Error handling is centralized through a single DecodeError type (src/error.rs) with a .context(&str) extension trait (ErrorContext) used consistently at every fallible parse site instead of ad-hoc string formatting. Public types are marked #[non_exhaustive] (NetlinkMessage, NetlinkHeader) to allow adding fields without a semver break, and buffer accessors are generated through repetitive buffer! macro invocations rather than hand-written boilerplate, keeping the getter/setter surface consistent across NetlinkBuffer, ErrorBuffer, and DoneBuffer.

API Design The public API centers on one generic type, NetlinkMessage<T>, with two small integration traits (NetlinkSerializable, NetlinkDeserializable) that a downstream crate implements once to get header framing, error/done/overrun handling, and (de)serialization for free — the lib.rs doc comment walks through a complete ping-pong protocol example end to end. The finalize()-before-serialize() convention is explicit and documented with a # Panic section warning what happens if it’s skipped, a reasonable tradeoff for a crate whose entire purpose is precise wire-format control. The crate re-exports a large, flat set of parse_/emit_ integer helpers (parse_u32_be, emit_i64_le, etc.) directly from the crate root, which is convenient for sub-protocol authors implementing their own payload parsers but does mean the top-level namespace is fairly wide for what is nominally three consumer types.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search