Linx.Netlink.Socket (Linx v0.1.0)

Copy Markdown View Source

An AF_NETLINK socket, opened in a chosen network namespace.

A netlink socket is bound for its whole life to the network namespace it was created in. open/2 selects that namespace:

  • :host — the BEAM's own network namespace.
  • {:pid, pid} / {:path, path} — another network namespace. The BEAM cannot setns on a scheduler thread, so Linx.Netlink.Socket.Native does it on a throwaway thread and hands back the fd, which :socket adopts.

protocol is the netlink protocol number — NETLINK_ROUTE, NETLINK_GENERIC, and so on — so one socket type serves every netlink family.

The struct carries an :atomics sequence counter. Netlink echoes a request's sequence number back in its reply; next_seq/1 hands out a fresh one per request so a stale or unsolicited message can't be mistaken for the current reply. The counter is mutable shared state, so a %Socket{} works correctly whether driven synchronously by one process or, later, owned by a connection process.

Close every socket with close/1 when done.

Summary

Functions

Joins a netlink multicast group on socket.

Closes a socket from open/2.

Leaves a multicast group joined via add_membership/2.

Returns the next netlink sequence number for socket.

Opens a netlink socket of protocol in network namespace netns.

Sets the socket receive buffer size (SO_RCVBUF) in bytes.

Types

netns()

@type netns() :: :host | {:pid, pos_integer()} | {:path, binary()}

t()

@type t() :: %Linx.Netlink.Socket{
  netns: netns(),
  protocol: non_neg_integer(),
  seq: :atomics.atomics_ref(),
  socket: :socket.socket()
}

Functions

add_membership(socket, group)

@spec add_membership(t(), pos_integer()) :: :ok | {:error, term()}

Joins a netlink multicast group on socket.

Subsequent reads will receive multicast events for group (a protocol-family-specific group number — NFNLGRP_NFTABLES = 7 for nfnetlink ruleset events, RTNLGRP_LINK = 1 for rtnetlink link events, etc.).

close(socket)

@spec close(t()) :: :ok

Closes a socket from open/2.

drop_membership(socket, group)

@spec drop_membership(t(), pos_integer()) :: :ok | {:error, term()}

Leaves a multicast group joined via add_membership/2.

next_seq(socket)

@spec next_seq(t()) :: pos_integer()

Returns the next netlink sequence number for socket.

Sequence numbers start at 1; 0 is reserved for unsolicited kernel messages, so a reply bearing seq 0 is never an answer to one of our requests.

open(protocol, netns \\ :host)

@spec open(non_neg_integer(), netns()) :: {:ok, t()} | {:error, term()}

Opens a netlink socket of protocol in network namespace netns.

Returns {:ok, socket} or {:error, reason}. Pass the socket to the rest of Linx.Netlink, and close/1 it when done.

set_rcvbuf(socket, bytes)

@spec set_rcvbuf(t(), pos_integer()) :: :ok | {:error, term()}

Sets the socket receive buffer size (SO_RCVBUF) in bytes.

For multicast monitors that may face heavy churn, a larger buffer reduces the chance of ENOBUFS overflow. The kernel silently clamps to its net.core.rmem_max ceiling — use SO_RCVBUFFORCE (requires CAP_NET_ADMIN) to override.