Converts %Linx.Netfilter.*{} value structs into the
%Linx.Netlink.Message{} shapes that ride inside a
NFNL_MSG_BATCH_BEGIN / NFNL_MSG_BATCH_END envelope.
Each public function returns a single %Message{} (or a list,
for entities that map to multiple wire messages). to_batch/2
walks a full %Ruleset{} and produces the ordered message list
for a :replace-mode push. Linx.Netlink.Nfnl.batch/2 wraps the
envelope and drives the transaction.
Wire format quirks
- Every nftables
NLA_U32/NLA_U64is big-endian on the wire — opposite to rtnetlink.Linx.Netfilter.Wire.u32_be/1/u64_be/1do the conversion. - The
nfgenmsg.familybyte carries the family this message applies to (NFPROTO_INET, etc.);res_idis 0 for most ops, the batch target's subsys id only for BATCH_BEGIN/END. - Attribute IDs are netfilter-namespaced (NFTATABLE, NFTACHAIN, etc.) — the same numeric ID can mean different things in different attribute sets.
References
nft_table.c— kernel-side parser; canonical authority on attribute order and required fields.
Summary
Functions
Builds a NEWCHAIN message for chain within family.
Builds a DELCHAIN message — removes a chain by name.
Builds a DELRULE message — removes a single rule by its
kernel-assigned handle.
Builds a DELSET message — removes a named set by (family, table, name). Returns :enoent from the kernel if missing.
Builds a DELSETELEM message that removes the given elements
from a set by raw element values.
Builds a DELTABLE message for the given table.
Builds a DESTROYTABLE message — silently a no-op if the table
doesn't exist. Used by :replace-mode push to clear pre-existing
state before re-creating it.
Encodes a %Linx.Netfilter.Patch{} into the ordered list of
%Message{}s to send inside a single BATCH transaction.
Builds a GETTABLE request — for fetching one table by
(family, name) from the kernel.
Builds a GETTABLE dump request — returns every table in the
netns. Filtering by family is optional (:unspec returns all
families).
Builds a NEWRULE message for rule inside the (family, table, chain)
scope.
Builds a NEWSET message. Accepts either a %Linx.Netfilter.Set{}
(plain set) or a %Linx.Netfilter.Map{} (typed map, including
vmaps — data_type: :verdict).
Builds a NEWSETELEM message — adds one or more elements to a
named set.
Builds a single-table NEWTABLE message. The result is a
%Message{} ready to drop into a batch.
Builds the ordered message list for a :replace-mode push of
ruleset.
Functions
@spec chain(Linx.Netfilter.Chain.t(), Linx.Netfilter.Table.family(), keyword()) :: Linx.Netlink.Message.t()
Builds a NEWCHAIN message for chain within family.
Required at construction:
NFTA_CHAIN_TABLE(string) — taken fromchain.table.NFTA_CHAIN_NAME(string).
Base-chain attributes (set together when chain is a base chain):
NFTA_CHAIN_HOOK(nested) —NFTA_HOOK_HOOKNUM(u32 BE),NFTA_HOOK_PRIORITY(s32 BE), andNFTA_HOOK_DEV(string) for:ingress/:egress.NFTA_CHAIN_TYPE(string:"filter"|"nat"|"route").NFTA_CHAIN_POLICY(u32 BE, NF_ACCEPT=1 / NF_DROP=0) — only whenchain.policyis set.NFTA_CHAIN_FLAGS(u32 BE) — whenchain.flagsis non-empty.
Regular chains skip the HOOK / TYPE / POLICY attributes entirely.
@spec delete_chain(Linx.Netfilter.Table.family(), String.t(), String.t()) :: Linx.Netlink.Message.t()
Builds a DELCHAIN message — removes a chain by name.
@spec delete_rule( Linx.Netfilter.Table.family(), String.t(), String.t(), pos_integer() ) :: Linx.Netlink.Message.t()
Builds a DELRULE message — removes a single rule by its
kernel-assigned handle.
@spec delete_set(Linx.Netfilter.Table.family(), String.t(), String.t()) :: Linx.Netlink.Message.t()
Builds a DELSET message — removes a named set by (family, table, name). Returns :enoent from the kernel if missing.
@spec delete_set_elements( Linx.Netfilter.Table.family(), String.t(), String.t(), [term()], atom(), atom() | nil ) :: Linx.Netlink.Message.t()
Builds a DELSETELEM message that removes the given elements
from a set by raw element values.
@spec deltable(Linx.Netfilter.Table.family(), String.t()) :: Linx.Netlink.Message.t()
Builds a DELTABLE message for the given table.
Returns :enoent from the kernel if the table doesn't exist —
use destroytable/2 for silent-if-missing semantics (6.3+).
@spec destroytable(Linx.Netfilter.Table.family(), String.t()) :: Linx.Netlink.Message.t()
Builds a DESTROYTABLE message — silently a no-op if the table
doesn't exist. Used by :replace-mode push to clear pre-existing
state before re-creating it.
Requires kernel ≥ 6.3 (where DESTROY* messages were added).
@spec from_patch(Linx.Netfilter.Patch.t()) :: [Linx.Netlink.Message.t()]
Encodes a %Linx.Netfilter.Patch{} into the ordered list of
%Message{}s to send inside a single BATCH transaction.
Sets need their NFTA_SET_ID generated per-batch; this function assigns ids in patch order so element-add ops can later reference them by name (the kernel resolves by name regardless, but libnftnl convention is to also send the id).
@spec gettable(Linx.Netfilter.Table.family(), String.t()) :: Linx.Netlink.Message.t()
Builds a GETTABLE request — for fetching one table by
(family, name) from the kernel.
No NLM_F_DUMP — that's gettable_dump/1 (for listing all
tables in the netns).
@spec gettable_dump(atom()) :: Linx.Netlink.Message.t()
Builds a GETTABLE dump request — returns every table in the
netns. Filtering by family is optional (:unspec returns all
families).
@spec rule( Linx.Netfilter.Rule.t(), Linx.Netfilter.Table.family(), String.t(), String.t(), keyword() ) :: Linx.Netlink.Message.t()
Builds a NEWRULE message for rule inside the (family, table, chain)
scope.
Attribute payload:
NFTA_RULE_TABLE(string).NFTA_RULE_CHAIN(string).NFTA_RULE_EXPRESSIONS(nested list ofNFTA_LIST_ELEMs) — each list element wrapsNFTA_EXPR_NAME(string) plusNFTA_EXPR_DATA(nested, per-expression attribute set).
Comment / tag round-trip via NFTA_RULE_USERDATA.
@spec set( Linx.Netfilter.Set.t() | Linx.Netfilter.Map.t(), Linx.Netfilter.Table.family(), keyword() ) :: Linx.Netlink.Message.t()
Builds a NEWSET message. Accepts either a %Linx.Netfilter.Set{}
(plain set) or a %Linx.Netfilter.Map{} (typed map, including
vmaps — data_type: :verdict).
The encoder auto-derives the NFT_SET_F_MAP flag for maps and
NFT_SET_F_EVAL for :dynamic sets; callers shouldn't include
them in :flags directly (but set_flags_int/1 accepts them
for round-trip purposes).
@spec set_elements( Linx.Netfilter.Set.t() | Linx.Netfilter.Map.t(), Linx.Netfilter.Table.family(), keyword() ) :: Linx.Netlink.Message.t() | nil
Builds a NEWSETELEM message — adds one or more elements to a
named set.
Elements is a list of either:
- raw key terms (for plain sets) —
[{10,0,0,1}, "1.2.3.4", ...]. {key, data}tuples (for maps and vmaps) —[{22, %Verdict{...}}, ...].
The encoder normalises each into the wire form using
key_type / data_type from the parent set.
@spec table( Linx.Netfilter.Table.t(), keyword() ) :: Linx.Netlink.Message.t()
Builds a single-table NEWTABLE message. The result is a
%Message{} ready to drop into a batch.
Default flags: NLM_F_CREATE — creates the table if missing,
updates flags otherwise. Pass excl: true for create-or-fail
(NLM_F_EXCL).
Attribute payload:
NFTA_TABLE_NAME(string)NFTA_TABLE_FLAGS(u32 BE) —:dormant|:owner|:persistflags OR'd viaWire.table_flags_int/1. Omitted when zero (libnftnl convention).NFTA_TABLE_USERDATA(binary) — omitted when nil.
@spec to_batch( Linx.Netfilter.Ruleset.t(), keyword() ) :: [Linx.Netlink.Message.t()]
Builds the ordered message list for a :replace-mode push of
ruleset.
For each table in ruleset, the batch contains:
DESTROYTABLE— silently destroys any existing table by the same(family, name), ensuring fresh state.NEWTABLE— recreate with the desired flags.NEWCHAINfor each chain in the table (in map iteration order; the kernel doesn't care about chain order).NEWRULEfor each rule in each chain, in rule-list order — rule ordering matters at runtime, the kernel preserves the batch order viaNLM_F_APPEND.
Objects and flowtables are not yet emitted. The batch shape supports them by interleaving in step 3.
This list is intended to drop straight into
Linx.Netlink.Nfnl.batch/2; it does not include the
BATCH_BEGIN / BATCH_END envelope (that's batch/2's job).