# `Linx.Netlink.Socket`
[🔗](https://github.com/oshlabs/linx/blob/v0.2.0/lib/linx/netlink/socket.ex#L1)

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.

# `netns`

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

# `t`

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

# `add_membership`

```elixir
@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`

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

Closes a socket from `open/2`.

# `drop_membership`

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

Leaves a multicast group joined via `add_membership/2`.

# `next_seq`

```elixir
@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`

```elixir
@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`

```elixir
@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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
