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

nfnetlink (`NETLINK_NETFILTER`) — the kernel's netfilter-control
interface: nf_tables (the modern firewall), conntrack, NFLOG, NFQUEUE.

This is the second `Linx.Netlink` protocol family (after
`Linx.Netlink.Rtnl`). nfnetlink multiplexes several sub-subsystems
inside one netlink family — identified by the high byte of
`nlmsghdr.type` (`subsys_id`). The map (`include/uapi/linux/netfilter/nfnetlink.h`):

| subsys_id | Name | Linx module |
|---|---|---|
| 1  | CTNETLINK | `Linx.Netfilter.Conntrack` (future) |
| 3  | QUEUE     | `Linx.Netfilter.Queue` (future) |
| 4  | ULOG      | `Linx.Netfilter.Log` (NFLOG) |
| 10 | NFTABLES  | `Linx.Netfilter` core |
| 12 | HOOK      | (deferred) |

Open a socket with `open/1` and pass it to the appropriate higher-level
module (`Linx.Netfilter`, eventually `Linx.Netfilter.{Conntrack,Log,Queue}`).

Codec helpers — `nfgenmsg` header encoding, subsys-id multiplexing on
`nlmsghdr.type`, batched-transaction envelope (`NFNL_MSG_BATCH_BEGIN` /
`NFNL_MSG_BATCH_END`), and the `NFT_MSG_GETGEN` / `NEWGEN` codec — live
in `Linx.Netlink.Nfnl.Codec`. The `batch/2` request engine below
drives nf_tables mutating transactions on top of those primitives.

The NFTABLES sub-subsystem (id 10) is driven by `Linx.Netfilter`;
CTNETLINK / QUEUE / HOOK are future families.

# `batch`

```elixir
@spec batch(
  Linx.Netlink.Socket.t(),
  [Linx.Netlink.Message.t()],
  atom() | 0..255,
  keyword()
) ::
  :ok | {:error, {non_neg_integer(), Linx.Netlink.Error.t()} | term()}
```

Sends a batched nf_tables transaction.

Wraps `inner_messages` between a `NFNL_MSG_BATCH_BEGIN` envelope
targeting `subsys` (default `:nftables`) and a `NFNL_MSG_BATCH_END`,
assigns sequence numbers, ORs `NLM_F_REQUEST | NLM_F_ACK` onto every
inner message, sends the whole batch in one `sendmsg(2)`, and
collects per-message ACK / error responses until every inner
message has been accounted for.

Returns `:ok` if every inner message was accepted, or
`{:error, {batch_seq, %Linx.Netlink.Error{}}}` for the first
inner message the kernel rejected. `batch_seq` is the
1-indexed position of the offending message within
`inner_messages` (the BATCH_BEGIN envelope is position 0; not
returned).

The envelope messages do not themselves get ACKs from the kernel —
BATCH_BEGIN merely opens the transaction, BATCH_END commits it.
Per-inner-message validation errors are returned during the prep
phase; commit-time failures (e.g. BATCH_GENID mismatch)
surface here too, attributed to the inner message that triggered
them.

Each call allocates fresh sequence numbers from the socket's
counter, so concurrent users of the same socket cannot collide.

# `open`

```elixir
@spec open(Linx.Netlink.Socket.netns()) ::
  {:ok, Linx.Netlink.Socket.t()} | {:error, term()}
```

Opens an nfnetlink socket in network namespace `netns`.

See `Linx.Netlink.Socket.open/2` for the `netns` forms (`:host`,
`{:pid, n}`, `{:path, p}`). Close the socket with
`Linx.Netlink.Socket.close/1`.

---

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