mdlayher/netlink: the low-level Go socket other netlink packages are built on
Package netlink provides low-level access to Linux netlink sockets (AF_NETLINK). MIT Licensed.
At a glance
- What is it?
- The netlink package gives Go programs direct access to Linux AF_NETLINK sockets, with the design goals spelled out as a straightforward idiomatic API, no package or global state, and no need for root in many cases. It is the base layer under an ecosystem of family-specific packages for route, generic, netfilter and more, and it retracts three of its own recent versions for concurrency bugs.
- Who is it for?
- netlink suits a Go developer writing a network tool that needs to talk to the kernel directly, whether that is a route inspector, a link monitor or the foundation of a family-specific package of your own, and who wants an API that does not hide the wire format behind a global stateful client.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it is: the socket, not a client
The package provides low-level access to Linux netlink sockets, AF_NETLINK. That description is precise and it tells you what you are taking on. Netlink is the kernel's own socket protocol, used for routing, link state, neighbour tables, netfilter and a long tail of subsystems, and a low-level library here means you construct and exchange the message structures yourself rather than calling a high level API that has already decided what they mean. The package description is one line, and the documentation is a pointer to the author's blog series on Linux, Netlink, and Go for the background, plus an invitation to the Gophers Slack in the networking channel. The primary language is Go, the licence is MIT, and the last push to the repository was on 2026-10-14.
The design goals, which are mostly things other packages get wrong
The Design section is the most useful part of the README, because it explains what the author was looking for and did not find. A number of netlink packages are already available for Go, but the criteria were a straightforward, idiomatic API, well tested, well documented, a package that does not use package or global variables or state, and one that does not necessarily need root to work. That list is a design review of the existing ecosystem, and two of the items deserve a note. Not using global state matters because a global client in a Go program is a shared mutable object that is awkward to use from two goroutines and impossible to use from two sockets cleanly. And does not necessarily need root matters because most netlink operations are readable by any user, and a library that requires root for a read is a library you cannot use in a monitoring agent running as an unprivileged user. The stated goal for the package is to use it as a building block for the creation of other netlink family packages.
The ecosystem: the mermaid diagram is a map of who depends on whom
The README carries a large mermaid flowchart mapping the netlink family packages, and it is a better description of the project than any paragraph. Each subgraph is a netlink family, and the arrows point from the family-specific packages up to the base layer. NETLINK_CONNECTOR has fearful-symmetry/garlic. NETLINK_CRYPTO has mdlayher/cryptonl. NETLINK_GENERIC is the largest group, with genetlink at the top and devlink, ethtool, go-openvswitch, ipvs, l2tp, nbd, quota, router7, taskstats, u-root/u-bmc, wgctrl and wifi feeding into it. NETLINK_KOBJECT_UEVENT has kobject. NETLINK_NETFILTER has go-conntrack, go-nflog, go-nfqueue, netfilter, nftables and conntrack, with conntrack feeding netfilter. NETLINK_ROUTE has go-tc, qdisc, rtnetlink and rtnl. NETLINK_SOCK_DIAG has go-diag, and NETLINK_W1 has go-onewire. The maintainers ask for a pull request to add a package to the diagram, which tells you the ecosystem is curated rather than accidental.
The stability policy, and the Go version floor
The Stability section is short and specific. This package has a stable v1 API and any future breaking changes will prompt the release of a new major version, and features and bug fixes will continue to occur in the v1.x.x series. The CHANGELOG file is where changes between releases are described. The second policy is about Go itself, and the wording gives the reason. The package only supports the two most recent major versions of Go, mirroring Go's own release policy, and older versions of Go may lack critical features and bug fixes which are necessary for this package to function correctly. The go.mod declares go 1.26.0. That is an unusually tight floor for a library, and it is a direct consequence of the package using newer language and standard library features rather than being a stylistic choice.
Three retracted versions, and what the bugs were
The go.mod contains a retract block naming three versions, and the comments explain each one, which is unusually useful. v1.11.1 is retracted because it contains a bug where netlink.Conn.Receive blocks concurrent calls to netlink.Conn.Send when blocking in recvmsg. v1.11.0 is retracted because netlink.Conn.Receive and netlink.Conn.ReceiveIter reject valid netlink messages whose header length is not aligned. And v1.10.0 is retracted because it contains a critical bug where Receive and ReceiveIter would panic if the received message was unaligned. Two themes run through them, concurrency between Send and Receive on one connection, and message alignment. The retract directive means the Go tool will warn you if you ask for one of these versions, so an existing dependency pinned to v1.11.1 will produce a build message rather than failing silently, which is exactly the behaviour the directive exists to provide.
The file layout shows what the package is actually made of
The top level of the repository is a good index of the concepts involved. There is conn.go with conn_linux.go and conn_others.go, which is the connection type and its platform split, and conn_linux_error_test.go, conn_linux_integration_test.go and conn_others_test.go alongside them. There is message.go for the netlink message structures, attribute.go for the netlink attributes, and align.go with its own test file, which is the alignment logic the retraction comments refer to. There is debug.go with debug_linux.go and debug_others.go, a debugging dump of the wire format. And errors.go for the error handling. The subdirectories are nlenc/ for the netlink encoder, nltest/ for test helpers, and internal/. The examples are example_test.go, example_attributedecoder_test.go and example_attributeencoder_test.go, and there is a fuzz.go with fuzz_test.go, so the parser is fuzz tested.
The dependencies are the minimum a netlink library needs
The require block has four direct dependencies and one indirect. github.com/google/go-cmp is the test comparison library. github.com/mdlayher/socket is the raw socket wrapper that does the actual syscalls, which is a separate project by the same author, so the netlink specifics live in this package and the syscall mechanics live there. golang.org/x/net and golang.org/x/sys are the other two direct dependencies. golang.org/x/sync is indirect. The notable absence is any dependency on a netlink protocol library, which is the point: this package does the transport and the message framing and leaves the meaning of a particular family to the packages above it. The.golangci.yml at the root indicates the project lints itself with golangci-lint, and the CHANGELOG.md and LICENSE.md are at the top level.
Editorial conclusion
netlink suits a Go developer writing a network tool that needs to talk to the kernel directly, whether that is a route inspector, a link monitor or the foundation of a family-specific package of your own, and who wants an API that does not hide the wire format behind a global stateful client. It is the wrong choice for an application that only needs to configure networking, since a higher level tool does that without you implementing the protocol, and a poor fit if you cannot tolerate API surface that tracks the kernel rather than a versioned stable schema. Before adopting it, read the CHANGELOG, because the module retracts v1.10.0, v1.11.0 and v1.11.1 for concurrency and alignment bugs, and note that the package supports only the two most recent major Go versions.
Frequently asked questions
What does the mdlayher/netlink package provide?
It provides low-level access to Linux netlink sockets, AF_NETLINK, in Go. The design goals are a straightforward idiomatic API, being well tested and documented, not using package or global variables or state, and not necessarily needing root to work, with the intent that it serves as a building block for other netlink family packages.
Which netlink families have Go packages built on top of netlink?
The ecosystem diagram in the README maps them. NETLINK_GENERIC has genetlink with devlink, ethtool, go-openvswitch, ipvs, l2tp, nbd, quota, router7, taskstats, u-root/u-bmc, wgctrl and wifi. NETLINK_NETFILTER has go-conntrack, go-nflog, go-nfqueue, netfilter, nftables and conntrack, NETLINK_ROUTE has go-tc, qdisc, rtnetlink and rtnl, and there are packages for connector, crypto, kobject uevent, sock diag and W1.
Is the netlink API stable?
Yes, it has a stable v1 API, and any future breaking changes will prompt the release of a new major version, with features and bug fixes continuing in the v1.x.x series. The CHANGELOG.md file describes the changes between releases. The package only supports the two most recent major versions of Go, mirroring Go's own release policy.
Which versions of mdlayher/netlink are retracted and why?
v1.11.1 is retracted because Conn.Receive blocks concurrent calls to Conn.Send when blocking in recvmsg, v1.11.0 because Receive and ReceiveIter reject valid messages whose header length is not aligned, and v1.10.0 because Receive and ReceiveIter would panic on an unaligned message. The retract directive in go.mod makes the Go tool warn when these versions are requested.
What does mdlayher/netlink depend on?
Four direct dependencies: github.com/google/go-cmp for test comparisons, github.com/mdlayher/socket for the raw socket syscalls, golang.org/x/net for netlink constants, and golang.org/x/sys for the system call layer, with golang.org/x/sync indirect. The go.mod declares go 1.26.0, and the repository is MIT licensed.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mdlayher-netlink)Was this useful?