An error returned by a Linx.Netfilter operation.
Built from a failed netlink request or a rejected batch (NLMSG_ERROR
reply from the kernel). The shape mirrors Linx.Mount.Error /
Linx.User.Error / Linx.Sysctl.Error for :operation, :errno,
:code, and :message, plus netfilter-specific context fields
that are populated when the kernel surfaces them:
:operation— what we were trying to do, as an atom. Covers every public verb and every wire-level stage:- Public-API stages:
:open,:close,:get_gen,:push,:pull,:diff,:subscribe,:log_listen. - Wire-level batch stages:
:batch_begin,:batch_end,:newtable,:newchain,:newrule,:newset,:newsetelem,:newobj,:newflowtable,:delgen. - Namespace-acquisition stages (when opening a socket in
another netns):
:open_ns,:setns,:unshare,:thread.
- Public-API stages:
:errno— the POSIX errno as an atom (:enoent,:eperm,:eacces,:einval,:erestart,:eopnotsupp, …).:code— the matching positive errno integer, ornilif we don't have a mapping for this atom. Symmetric with the other Linx error structs.:message— kernel's extended-ack message (NLMSGERR_ATTR_MSG), a human-readable string explaining what was wrong with the offending message.nilwhen the kernel didn't include one.:subsys—:nftables|:ctnetlink|:queue|:ulog|nil. Which nfnetlink sub-subsystem the failure was for.:msg_type— the low-byte nfnetlink message type that failed, when the error came from a specific inner message (e.g.0x06for NFT_MSG_NEWRULE).nilfor non-batch failures.:batch_seq— sequence number of the offending inner message within the batch.nilfor non-batch failures.:attr_offset— byte offset into the offending message at which the kernel detected the problem (from NLMSGERR_ATTR_OFFS, kernel ≥ 4.12).nilwhen not provided.:ruleset_gen— the ruleset generation at which the error occurred. Useful forERESTART(BATCH_GENID mismatch) diagnostics.nilwhen not relevant.
Pattern-match on :errno and :operation to handle specific
failures:
case Linx.Netfilter.push(nfnl, ruleset) do
:ok ->
:ok
{:error, %Linx.Netfilter.Error{errno: :eacces}} ->
# No CAP_NET_ADMIN; can't mutate the kernel's nftables.
:no_perm
{:error, %Linx.Netfilter.Error{errno: :erestart, ruleset_gen: gen}} ->
# BATCH_GENID mismatch — another writer committed between
# our pull and our push. Re-pull, recompute, retry.
{:concurrent_modification, gen}
{:error, %Linx.Netfilter.Error{errno: :eopnotsupp, msg_type: t}} ->
# The kernel doesn't support this op on this entity —
# typically an in-place modification that requires
# delete+recreate.
{:not_supported, t}
endImplements Exception, so an error can be raised or rendered
with Exception.message/1.
Caller-side input mistakes (invalid Ruleset shape, bad opts) come
back as tagged tuples ({:error, {:bad_chain, _}},
{:error, {:bad_rule, _}}, {:error, {:bad_set_element, _}},
{:error, {:tag_required, _}}) — distinct from kernel rejections,
matching the convention every other Linx subsystem uses.
Summary
Functions
Builds a %Linx.Netfilter.Error{} from a posix-atom errno and the
operation we attempted.
Types
@type operation() ::
:open
| :close
| :get_gen
| :push
| :pull
| :diff
| :subscribe
| :log_listen
| :batch_begin
| :batch_end
| :newtable
| :newchain
| :newrule
| :newset
| :newsetelem
| :newobj
| :newflowtable
| :delgen
| :open_ns
| :setns
| :unshare
| :thread
@type subsys() :: :nftables | :ctnetlink | :queue | :ulog | nil
@type t() :: %Linx.Netfilter.Error{ __exception__: true, attr_offset: non_neg_integer() | nil, batch_seq: non_neg_integer() | nil, code: pos_integer() | nil, errno: atom(), message: String.t() | nil, msg_type: 0..255 | nil, operation: operation(), ruleset_gen: non_neg_integer() | nil, subsys: subsys() }
Functions
Builds a %Linx.Netfilter.Error{} from a posix-atom errno and the
operation we attempted.
Optional opts populate the netfilter-specific context fields when
the caller has them (typically populated from decoded NLMSG_ERROR
attributes by the request engine).