netlink

package module
v1.11.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: MIT Imports: 22 Imported by: 368

README

Package netlink provides low-level access to Linux netlink sockets (AF_NETLINK). MIT Licensed.

For more information about how netlink works, check out my blog series on Linux, Netlink, and Go.

If you have any questions or you'd like some guidance, please join us on Gophers Slack in the #networking channel!

Stability

See the CHANGELOG file for a description of changes between releases.

This package has a stable v1 API and any future breaking changes will prompt the release of a new major version. Features and bug fixes will continue to occur in the v1.x.x series.

This package only supports the two most recent major versions of Go, mirroring Go's own release policy. Older versions of Go may lack critical features and bug fixes which are necessary for this package to function correctly.

Design

A number of netlink packages are already available for Go, but I wasn't able to find one that aligned with what I wanted in a netlink package:

  • Straightforward, idiomatic API
  • Well tested
  • Well documented
  • Doesn't use package/global variables or state
  • Doesn't necessarily need root to work

My goal for this package is to use it as a building block for the creation of other netlink family packages.

Ecosystem

Over time, an ecosystem of Go packages has developed around package netlink. Many of these packages provide building blocks for further interactions with various netlink families, such as NETLINK_GENERIC or NETLINK_ROUTE.

To have your package included in this diagram, please send a pull request!

flowchart LR
    netlink["github.com/mdlayher/netlink"]
    click netlink "https://github.com/mdlayher/netlink"

    subgraph "NETLINK_CONNECTOR"
        direction LR

        garlic["github.com/fearful-symmetry/garlic"]
        click garlic "https://github.com/fearful-symmetry/garlic"
    end

    subgraph "NETLINK_CRYPTO"
        direction LR

        cryptonl["github.com/mdlayher/cryptonl"]
        click cryptonl "https://github.com/mdlayher/cryptonl"
    end

    subgraph "NETLINK_GENERIC"
        direction LR

        genetlink["github.com/mdlayher/genetlink"]
        click genetlink "https://github.com/mdlayher/genetlink"

        devlink["github.com/mdlayher/devlink"]
        click devlink "https://github.com/mdlayher/devlink"

        ethtool["github.com/mdlayher/ethtool"]
        click ethtool "https://github.com/mdlayher/ethtool"

        go-openvswitch["github.com/digitalocean/go-openvswitch"]
        click go-openvswitch "https://github.com/digitalocean/go-openvswitch"

        ipvs["github.com/cloudflare/ipvs"]
        click ipvs "https://github.com/cloudflare/ipvs"

        l2tp["github.com/axatrax/l2tp"]
        click l2tp "https://github.com/axatrax/l2tp"

        nbd["github.com/Merovius/nbd"]
        click nbd "https://github.com/Merovius/nbd"

        quota["github.com/mdlayher/quota"]
        click quota "https://github.com/mdlayher/quota"

        router7["github.com/rtr7/router7"]
        click router7 "https://github.com/rtr7/router7"

        taskstats["github.com/mdlayher/taskstats"]
        click taskstats "https://github.com/mdlayher/taskstats"

        u-bmc["github.com/u-root/u-bmc"]
        click u-bmc "https://github.com/u-root/u-bmc"

        wgctrl["golang.zx2c4.com/wireguard/wgctrl"]
        click wgctrl "https://golang.zx2c4.com/wireguard/wgctrl"

        wifi["github.com/mdlayher/wifi"]
        click wifi "https://github.com/mdlayher/wifi"

        devlink & ethtool & go-openvswitch & ipvs --> genetlink
        l2tp & nbd & quota & router7 & taskstats --> genetlink
        u-bmc & wgctrl & wifi --> genetlink
    end

    subgraph "NETLINK_KOBJECT_UEVENT"
        direction LR

        kobject["github.com/mdlayher/kobject"]
        click kobject "https://github.com/mdlayher/kobject"
    end

    subgraph "NETLINK_NETFILTER"
        direction LR

        go-conntrack["github.com/florianl/go-conntrack"]
        click go-conntrack "https://github.com/florianl/go-conntrack"

        go-nflog["github.com/florianl/go-nflog"]
        click go-nflog "https://github.com/florianl/go-nflog"

        go-nfqueue["github.com/florianl/go-nfqueue"]
        click go-nfqueue "https://github.com/florianl/go-nfqueue"

        netfilter["github.com/ti-mo/netfilter"]
        click netfilter "https://github.com/ti-mo/netfilter"

        nftables["github.com/google/nftables"]
        click nftables "https://github.com/google/nftables"

        conntrack["github.com/ti-mo/conntrack"]
        click conntrack "https://github.com/ti-mo/conntrack"

        conntrack --> netfilter
    end

    subgraph "NETLINK_ROUTE"
        direction LR

        go-tc["github.com/florianl/go-tc"]
        click go-tc "https://github.com/florianl/go-tc"

        qdisc["github.com/ema/qdisc"]
        click qdisc "https://github.com/ema/qdisc"

        rtnetlink["github.com/jsimonetti/rtnetlink"]
        click rtnetlink "https://github.com/jsimonetti/rtnetlink"

        rtnl["gitlab.com/mergetb/tech/rtnl"]
        click rtnl "https://gitlab.com/mergetb/tech/rtnl"
    end

    subgraph "NETLINK_W1"
        direction LR

        go-onewire["github.com/SpComb/go-onewire"]
        click go-onewire "https://github.com/SpComb/go-onewire"
    end

    subgraph "NETLINK_SOCK_DIAG"
        direction LR

        go-diag["github.com/florianl/go-diag"]
        click go-diag "https://github.com/florianl/go-diag"
    end

    NETLINK_CONNECTOR --> netlink
    NETLINK_CRYPTO --> netlink
    NETLINK_GENERIC --> netlink
    NETLINK_KOBJECT_UEVENT --> netlink
    NETLINK_NETFILTER --> netlink
    NETLINK_ROUTE --> netlink
    NETLINK_SOCK_DIAG --> netlink
    NETLINK_W1 --> netlink

Documentation

Overview

Package netlink provides low-level access to Linux netlink sockets (AF_NETLINK).

If you have any questions or you'd like some guidance, please join us on Gophers Slack (https://invite.slack.golangbridge.org) in the #networking channel!

Network namespaces

This package is aware of Linux network namespaces, and can enter different network namespaces either implicitly or explicitly, depending on configuration. The Config structure passed to Dial to create a Conn controls these behaviors. See the documentation of Config.NetNS for details.

Debugging

This package supports rudimentary netlink connection debugging support. To enable this, run your binary with the NLDEBUG environment variable set. Debugging information will be output to stderr with a prefix of "nl:".

To use the debugging defaults, use:

$ NLDEBUG=1 ./nlctl

To configure individual aspects of the debugger, pass key/value options such as:

$ NLDEBUG=level=1 ./nlctl

$ NLDEBUG=level=1,format=mnl ./nlctl

Available key/value debugger options include:

level=N: specify the debugging level (only "1" is currently supported)
format=mnl: specify the same format used by libmnl (nft --debug=all)

Index

Examples

Constants

View Source
const (
	Nested       uint16 = 0x8000
	NetByteOrder uint16 = 0x4000
)

Flags which may apply to netlink attribute types when communicating with certain netlink families.

Variables

This section is empty.

Functions

func IsNotExist deprecated

func IsNotExist(err error) bool

IsNotExist determines if an error is produced as the result of querying some file, object, resource, etc. which does not exist.

Deprecated: use errors.Unwrap and/or `errors.Is(err, os.Permission)` in Go 1.13+.

func MarshalAttributes

func MarshalAttributes(attrs []Attribute) ([]byte, error)

MarshalAttributes packs a slice of Attributes into a single byte slice. In most cases, the Length field of each Attribute should be set to 0, so it can be calculated and populated automatically for each Attribute.

It is recommend to use the AttributeEncoder type where possible instead of calling MarshalAttributes and using package nlenc functions directly.

func Validate

func Validate(request Message, replies []Message) error

Validate validates one or more reply Messages against a request Message, ensuring that they contain matching sequence numbers and PIDs.

Types

type Attribute

type Attribute struct {
	// Length of an Attribute, including this field and Type.
	Length uint16

	// The type of this Attribute, typically matched to a constant. Note that
	// flags such as Nested and NetByteOrder must be handled manually when
	// working with Attribute structures directly.
	Type uint16

	// An arbitrary payload which is specified by Type.
	Data []byte
}

An Attribute is a netlink attribute. Attributes are packed and unpacked to and from the Data field of Message for some netlink families.

func UnmarshalAttributes

func UnmarshalAttributes(b []byte) ([]Attribute, error)

UnmarshalAttributes unpacks a slice of Attributes from a single byte slice.

It is recommend to use the AttributeDecoder type where possible instead of calling UnmarshalAttributes and using package nlenc functions directly.

type AttributeDecoder

type AttributeDecoder struct {
	// ByteOrder defines a specific byte order to use when processing integer
	// attributes.  ByteOrder should be set immediately after creating the
	// AttributeDecoder: before any attributes are parsed.
	//
	// If not set, the native byte order will be used.
	ByteOrder binary.ByteOrder
	// contains filtered or unexported fields
}

An AttributeDecoder provides a safe, iterator-like, API around attribute decoding.

It is recommend to use an AttributeDecoder where possible instead of calling UnmarshalAttributes and using package nlenc functions directly.

The Err method must be called after the Next method returns false to determine if any errors occurred during iteration.

Example (Decode)

This example demonstrates using a netlink.AttributeDecoder to decode packed netlink attributes in a message payload.

package main

import (
	"fmt"
	"log"

	"github.com/mdlayher/netlink"
)

// decodeNested is a nested structure within decodeOut.
type decodeNested struct {
	A, B uint32
}

// decodeOut is an example structure we will use to unpack netlink attributes.
type decodeOut struct {
	Number uint16
	String string
	Nested decodeNested
}

// decode is an example function used to adapt the ad.Nested method to decode an
// arbitrary structure.
func (n *decodeNested) decode(ad *netlink.AttributeDecoder) error {
	// Iterate over the attributes, checking the type of each attribute and
	// decoding them as appropriate.
	for ad.Next() {
		switch ad.Type() {
		// A and B are both uint32 values, so decode them as such.
		case 1:
			n.A = ad.Uint32()
		case 2:
			n.B = ad.Uint32()
		}
	}

	// No need to call ad.Err directly.
	return nil
}

// This example demonstrates using a netlink.AttributeDecoder to decode packed
// netlink attributes in a message payload.
func main() {
	// Create a netlink.AttributeDecoder using some example attribute bytes
	// that are prepared for this example.
	ad, err := netlink.NewAttributeDecoder(exampleAttributes())
	if err != nil {
		log.Fatalf("failed to create attribute decoder: %v", err)
	}

	// Iterate attributes until completion, checking the type of each and
	// decoding them as appropriate.
	var out decodeOut
	for ad.Next() {
		// Check the type of the current attribute with ad.Type.  Typically you
		// will find netlink attribute types and data values in C headers as
		// constants.
		switch ad.Type() {
		case 1:
			// Number is a uint16.
			out.Number = ad.Uint16()
		case 2:
			// String is a string.
			out.String = ad.String()
		case 3:
			// Nested is a nested structure, so we will use a method on the
			// nested type along with ad.Do to decode it in a concise way.
			ad.Nested(out.Nested.decode)
		}
	}

	// Any errors encountered during decoding (including any errors from
	// decoding the nested attributes) will be returned here.
	if err := ad.Err(); err != nil {
		log.Fatalf("failed to decode attributes: %v", err)
	}

	fmt.Printf(`Number: %d
String: %q
Nested:
   - A: %d
   - B: %d`,
		out.Number, out.String, out.Nested.A, out.Nested.B,
	)
}
Output:
Number: 1
String: "hello world"
Nested:
   - A: 2
   - B: 3

func NewAttributeDecoder

func NewAttributeDecoder(b []byte) (*AttributeDecoder, error)

NewAttributeDecoder creates an AttributeDecoder that unpacks Attributes from b and prepares the decoder for iteration.

func (*AttributeDecoder) Bytes

func (ad *AttributeDecoder) Bytes() []byte

Bytes returns the raw bytes of the current Attribute's data.

func (*AttributeDecoder) Do

func (ad *AttributeDecoder) Do(fn func(b []byte) error)

Do is a general purpose function which allows access to the current data pointed to by the AttributeDecoder.

Do can be used to allow parsing arbitrary data within the context of the decoder. Do is most useful when dealing with nested attributes, attribute arrays, or decoding arbitrary types (such as C structures) which don't fit cleanly into a typical unsigned integer value.

The function fn should not retain any reference to the data b outside of the scope of the function.

func (*AttributeDecoder) Err

func (ad *AttributeDecoder) Err() error

Err returns the first error encountered by the decoder.

func (*AttributeDecoder) Flag

func (ad *AttributeDecoder) Flag() bool

Flag returns a boolean representing the Attribute.

func (*AttributeDecoder) Int8 added in v1.4.0

func (ad *AttributeDecoder) Int8() int8

Int8 returns the Int8 representation of the current Attribute's data.

func (*AttributeDecoder) Int16 added in v1.4.0

func (ad *AttributeDecoder) Int16() int16

Int16 returns the Int16 representation of the current Attribute's data.

func (*AttributeDecoder) Int32 added in v1.4.0

func (ad *AttributeDecoder) Int32() int32

Int32 returns the Int32 representation of the current Attribute's data.

func (*AttributeDecoder) Int64 added in v1.4.0

func (ad *AttributeDecoder) Int64() int64

Int64 returns the Int64 representation of the current Attribute's data.

func (*AttributeDecoder) Len

func (ad *AttributeDecoder) Len() int

Len returns the number of netlink attributes pointed to by the decoder.

func (*AttributeDecoder) Nested

func (ad *AttributeDecoder) Nested(fn func(nad *AttributeDecoder) error)

Nested decodes data into a nested AttributeDecoder to handle nested netlink attributes. When calling Nested, the Err method does not need to be called on the nested AttributeDecoder.

The nested AttributeDecoder nad inherits the same ByteOrder setting as the top-level AttributeDecoder ad.

func (*AttributeDecoder) Next

func (ad *AttributeDecoder) Next() bool

Next advances the decoder to the next netlink attribute. It returns false when no more attributes are present, or an error was encountered.

func (*AttributeDecoder) String

func (ad *AttributeDecoder) String() string

String returns the string representation of the current Attribute's data.

func (*AttributeDecoder) Type

func (ad *AttributeDecoder) Type() uint16

Type returns the Attribute.Type field of the current netlink attribute pointed to by the decoder.

Type masks off the high bits of the netlink attribute type which may contain the Nested and NetByteOrder flags. These can be obtained by calling TypeFlags.

func (*AttributeDecoder) TypeFlags added in v1.1.0

func (ad *AttributeDecoder) TypeFlags() uint16

TypeFlags returns the two high bits of the Attribute.Type field of the current netlink attribute pointed to by the decoder.

These bits of the netlink attribute type are used for the Nested and NetByteOrder flags, available as the Nested and NetByteOrder constants in this package.

func (*AttributeDecoder) Uint8

func (ad *AttributeDecoder) Uint8() uint8

Uint8 returns the uint8 representation of the current Attribute's data.

func (*AttributeDecoder) Uint16

func (ad *AttributeDecoder) Uint16() uint16

Uint16 returns the uint16 representation of the current Attribute's data.

func (*AttributeDecoder) Uint32

func (ad *AttributeDecoder) Uint32() uint32

Uint32 returns the uint32 representation of the current Attribute's data.

func (*AttributeDecoder) Uint64

func (ad *AttributeDecoder) Uint64() uint64

Uint64 returns the uint64 representation of the current Attribute's data.

type AttributeEncoder

type AttributeEncoder struct {
	// ByteOrder defines a specific byte order to use when processing integer
	// attributes.  ByteOrder should be set immediately after creating the
	// AttributeEncoder: before any attributes are encoded.
	//
	// If not set, the native byte order will be used.
	ByteOrder binary.ByteOrder
	// contains filtered or unexported fields
}

An AttributeEncoder provides a safe way to encode attributes.

It is recommended to use an AttributeEncoder where possible instead of calling MarshalAttributes or using package nlenc directly.

Errors from intermediate encoding steps are returned in the call to Encode.

Example (Encode)
package main

import (
	"fmt"
	"log"

	"github.com/mdlayher/netlink"
)

// encodeNested is a nested structure within out.
type encodeNested struct {
	A, B uint32
}

// encodeOut is an example structure we will use to pack netlink attributes.
type encodeOut struct {
	Number uint16
	String string
	Nested encodeNested
}

// encode is an example function used to adapt the ae.Nested method
// to encode an arbitrary structure.
func (n encodeNested) encode(ae *netlink.AttributeEncoder) error {
	// Encode the fields of the nested structure.
	ae.Uint32(1, n.A)
	ae.Uint32(2, n.B)
	return nil
}

func main() {
	// Create a netlink.AttributeEncoder that encodes to the same message
	// as that decoded by the netlink.AttributeDecoder example.
	ae := netlink.NewAttributeEncoder()

	o := encodeOut{
		Number: 1,
		String: "hello world",
		Nested: encodeNested{
			A: 2,
			B: 3,
		},
	}

	// Encode the Number attribute as a uint16.
	ae.Uint16(1, o.Number)
	// Encode the String attribute as a string.
	ae.String(2, o.String)
	// Nested is a nested structure, so we will use the encodeNested type's
	// encode method with ae.Nested to encode it in a concise way.
	ae.Nested(3, o.Nested.encode)

	// Any errors encountered during encoding (including any errors from
	// encoding nested attributes) will be returned here.
	b, err := ae.Encode()
	if err != nil {
		log.Fatalf("failed to encode attributes: %v", err)
	}

	// Now decode the attributes again to verify the contents.
	ad, err := netlink.NewAttributeDecoder(b)
	if err != nil {
		log.Fatalf("failed to decode attributes: %v", err)
	}

	// Walk the attributes and print each out.
	for ad.Next() {
		switch ad.Type() {
		case 1:
			fmt.Println("uint16:", ad.Uint16())
		case 2:
			fmt.Println("string:", ad.String())
		case 3:
			fmt.Println("nested:")

			// Nested attributes use their own nested decoder.
			ad.Nested(func(nad *netlink.AttributeDecoder) error {
				for nad.Next() {
					switch nad.Type() {
					case 1:
						fmt.Println("  - A:", nad.Uint32())
					case 2:
						fmt.Println("  - B:", nad.Uint32())
					}
				}
				return nil
			})
		}
	}

}
Output:
uint16: 1
string: hello world
nested:
  - A: 2
  - B: 3

func NewAttributeEncoder

func NewAttributeEncoder() *AttributeEncoder

NewAttributeEncoder creates an AttributeEncoder that encodes Attributes.

func (*AttributeEncoder) Bytes

func (ae *AttributeEncoder) Bytes(typ uint16, b []byte)

Bytes embeds raw byte data into an Attribute specified by typ.

func (*AttributeEncoder) Do

func (ae *AttributeEncoder) Do(typ uint16, fn func() ([]byte, error))

Do is a general purpose function to encode arbitrary data into an attribute specified by typ.

Do is especially helpful in encoding nested attributes, attribute arrays, or encoding arbitrary types (such as C structures) which don't fit cleanly into an unsigned integer value.

func (*AttributeEncoder) Encode

func (ae *AttributeEncoder) Encode() ([]byte, error)

Encode returns the encoded bytes representing the attributes.

func (*AttributeEncoder) Flag

func (ae *AttributeEncoder) Flag(typ uint16, v bool)

Flag encodes a flag into an Attribute specified by typ.

func (*AttributeEncoder) Int8 added in v1.4.0

func (ae *AttributeEncoder) Int8(typ uint16, v int8)

Int8 encodes int8 data into an Attribute specified by typ.

func (*AttributeEncoder) Int16 added in v1.4.0

func (ae *AttributeEncoder) Int16(typ uint16, v int16)

Int16 encodes int16 data into an Attribute specified by typ.

func (*AttributeEncoder) Int32 added in v1.4.0

func (ae *AttributeEncoder) Int32(typ uint16, v int32)

Int32 encodes int32 data into an Attribute specified by typ.

func (*AttributeEncoder) Int64 added in v1.4.0

func (ae *AttributeEncoder) Int64(typ uint16, v int64)

Int64 encodes int64 data into an Attribute specified by typ.

func (*AttributeEncoder) Nested

func (ae *AttributeEncoder) Nested(typ uint16, fn func(nae *AttributeEncoder) error)

Nested embeds data produced by a nested AttributeEncoder and flags that data with the Nested flag. When calling Nested, the Encode method should not be called on the nested AttributeEncoder.

The nested AttributeEncoder nae inherits the same ByteOrder setting as the top-level AttributeEncoder ae.

func (*AttributeEncoder) String

func (ae *AttributeEncoder) String(typ uint16, s string)

String encodes string s as a null-terminated string into an Attribute specified by typ.

func (*AttributeEncoder) Uint8

func (ae *AttributeEncoder) Uint8(typ uint16, v uint8)

Uint8 encodes uint8 data into an Attribute specified by typ.

func (*AttributeEncoder) Uint16

func (ae *AttributeEncoder) Uint16(typ uint16, v uint16)

Uint16 encodes uint16 data into an Attribute specified by typ.

func (*AttributeEncoder) Uint32

func (ae *AttributeEncoder) Uint32(typ uint16, v uint32)

Uint32 encodes uint32 data into an Attribute specified by typ.

func (*AttributeEncoder) Uint64

func (ae *AttributeEncoder) Uint64(typ uint16, v uint64)

Uint64 encodes uint64 data into an Attribute specified by typ.

type Config

type Config struct {
	// Groups is a bitmask which specifies multicast groups. If set to 0,
	// no multicast group subscriptions will be made.
	Groups uint32

	// NetNS specifies the network namespace the Conn will operate in.
	//
	// If set (non-zero), Conn will enter the specified network namespace and
	// an error will occur in Dial if the operation fails.
	//
	// If not set (zero), a best-effort attempt will be made to enter the
	// network namespace of the calling thread: this means that any changes made
	// to the calling thread's network namespace will also be reflected in Conn.
	// If this operation fails (due to lack of permissions or because network
	// namespaces are disabled by kernel configuration), Dial will not return
	// an error, and the Conn will operate in the default network namespace of
	// the process. This enables non-privileged use of Conn in applications
	// which do not require elevated privileges.
	//
	// Entering a network namespace is a privileged operation (root or
	// CAP_SYS_ADMIN are required), and most applications should leave this set
	// to 0.
	NetNS int

	// DisableNSLockThread is a no-op.
	//
	// Deprecated: internal changes have made this option obsolete and it has no
	// effect. Do not use.
	DisableNSLockThread bool

	// PID specifies the port ID used to bind the netlink socket. If set to 0,
	// the kernel will assign a port ID on the caller's behalf.
	//
	// Most callers should leave this field set to 0. This option is intended
	// for advanced use cases where the kernel expects a fixed unicast address
	// destination for netlink messages.
	PID uint32

	// Strict applies a more strict default set of options to the Conn,
	// including:
	//   - ExtendedAcknowledge: true
	//     - provides more useful error messages when supported by the kernel
	//   - GetStrictCheck: true
	//     - more strictly enforces request validation for some families such
	//       as rtnetlink which were historically misused
	//
	// If any of the options specified by Strict cannot be configured due to an
	// outdated kernel or similar, an error will be returned.
	//
	// When possible, setting Strict to true is recommended for applications
	// running on modern Linux kernels.
	Strict bool

	// MessageBufferSize specifies a fixed buffer size for receiving netlink
	// messages. When set, the connection will reuse a single pre-allocated
	// buffer of this size instead of peeking at each message to determine
	// the exact size needed.
	//
	// This is useful for high-throughput applications where the overhead of
	// peeking at each message is undesirable and the maximum message size
	// is known in advance.
	//
	// If set to 0 (the default), the connection will peek at the upcoming
	// message before allocating a buffer for it.
	//
	// Note: this is not the same as the kernel socket receive buffer which
	// can be configured using SetReadBuffer. MessageBufferSize only controls
	// the userspace buffer passed to recvmsg.
	MessageBufferSize int
}

Config contains options for a Conn.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

A Conn is a connection to netlink. A Conn can be used to send and receives messages to and from netlink.

A Conn is safe for concurrent use, but to avoid contention in high-throughput applications, the caller should almost certainly create a pool of Conns and distribute them among workers.

A Conn is capable of manipulating netlink subsystems from within a specific Linux network namespace, but special care must be taken when doing so. See the documentation of Config for details.

Example (Execute)

This example demonstrates using a netlink.Conn to execute requests against netlink.

package main

import (
	"log"

	"github.com/mdlayher/netlink"
)

func main() {
	// Speak to generic netlink using netlink
	const familyGeneric = 16

	c, err := netlink.Dial(familyGeneric, nil)
	if err != nil {
		log.Fatalf("failed to dial netlink: %v", err)
	}
	defer c.Close()

	// Ask netlink to send us an acknowledgement, which will contain
	// a copy of the header we sent to it
	req := netlink.Message{
		Header: netlink.Header{
			// Package netlink will automatically set header fields
			// which are set to zero
			Flags: netlink.Request | netlink.Acknowledge,
		},
	}

	// Perform a request, receive replies, and validate the replies
	msgs, err := c.Execute(req)
	if err != nil {
		log.Fatalf("failed to execute request: %v", err)
	}

	if c := len(msgs); c != 1 {
		log.Fatalf("expected 1 message, but got: %d", c)
	}

	// Decode the copied request header, starting after 4 bytes
	// indicating "success"
	var res netlink.Message
	if err := (&res).UnmarshalBinary(msgs[0].Data[4:]); err != nil {
		log.Fatalf("failed to unmarshal response: %v", err)
	}

	log.Printf("res: %+v", res)
}
Example (ListenMulticast)

This example demonstrates using a netlink.Conn to listen for multicast group messages generated by the addition and deletion of network interfaces.

package main

import (
	"log"

	"github.com/mdlayher/netlink"
)

func main() {
	const (
		// Speak to route netlink using netlink
		familyRoute = 0

		// Listen for events triggered by addition or deletion of
		// network interfaces
		rtmGroupLink = 0x1
	)

	c, err := netlink.Dial(familyRoute, &netlink.Config{
		// Groups is a bitmask; more than one group can be specified
		// by OR'ing multiple group values together
		Groups: rtmGroupLink,
	})
	if err != nil {
		log.Fatalf("failed to dial netlink: %v", err)
	}
	defer c.Close()

	for {
		// Listen for netlink messages triggered by multicast groups
		msgs, err := c.Receive()
		if err != nil {
			log.Fatalf("failed to receive messages: %v", err)
		}

		log.Printf("msgs: %+v", msgs)
	}
}

func Dial

func Dial(family int, config *Config) (*Conn, error)

Dial dials a connection to netlink, using the specified netlink family. Config specifies optional configuration for Conn. If config is nil, a default configuration will be used.

func NewConn

func NewConn(sock Socket, pid uint32) *Conn

NewConn creates a Conn using the specified Socket and PID for netlink communications.

NewConn is primarily useful for tests. Most applications should use Dial instead.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection and unblocks any pending read operations.

func (*Conn) Execute

func (c *Conn) Execute(m Message) ([]Message, error)

Execute sends a single Message to netlink using Send, receives one or more replies using Receive, and then checks the validity of the replies against the request using Validate.

Execute acquires a lock for the duration of the function call which blocks concurrent calls to Send, SendMessages, and Receive, in order to ensure consistency between netlink request/reply messages.

See the documentation of Send, Receive, and Validate for details about each function.

func (*Conn) JoinGroup

func (c *Conn) JoinGroup(group uint32) error

JoinGroup joins a netlink multicast group by its ID.

func (*Conn) LeaveGroup

func (c *Conn) LeaveGroup(group uint32) error

LeaveGroup leaves a netlink multicast group by its ID.

func (*Conn) PID added in v1.9.0

func (c *Conn) PID() uint32

PID returns the PID associated with the Conn. It is also known as the port ID in netlink terminology. https://docs.kernel.org/userspace-api/netlink/intro.html#nlmsg-pid

func (*Conn) ReadBuffer added in v1.8.0

func (c *Conn) ReadBuffer() (int, error)

ReadBuffer reads the size of the operating system's receive buffer associated with the Conn.

func (*Conn) Receive

func (c *Conn) Receive() ([]Message, error)

Receive receives one or more messages from netlink. Multi-part messages are handled transparently and returned as a single slice of Messages, with the final empty "multi-part done" message removed.

If any of the messages indicate a netlink error, that error will be returned.

func (*Conn) ReceiveIter added in v1.10.0

func (c *Conn) ReceiveIter() iter.Seq2[Message, error]

ReceiveIter returns an iterator which can be used to receive messages from netlink. Just like Receive, multi-part messages are handled transparently and netlink errors are returned as errors from the iterator.

If the iteration is stopped before all messages have been read and the response is multi-part, the remaining messages will be discarded.

func (*Conn) RemoveBPF

func (c *Conn) RemoveBPF() error

RemoveBPF removes a BPF filter from a Conn.

func (*Conn) Send

func (c *Conn) Send(m Message) (Message, error)

Send sends a single Message to netlink. In most cases, a Header's Length, Sequence, and PID fields should be set to 0, so they can be populated automatically before the Message is sent. On success, Send returns a copy of the Message with all parameters populated, for later validation.

If Header.Length is 0, it will be automatically populated using the correct length for the Message, including its payload.

If Header.Sequence is 0, it will be automatically populated using the next sequence number for this connection.

If Header.PID is 0, it will be automatically populated using a PID assigned by netlink.

func (*Conn) SendMessages

func (c *Conn) SendMessages(msgs []Message) ([]Message,