]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nf_tables: export set count and backend name to userspace
authorFlorian Westphal <fw@strlen.de>
Tue, 8 Apr 2025 13:55:53 +0000 (15:55 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 28 Apr 2025 22:00:27 +0000 (00:00 +0200)
nf_tables picks a suitable set backend implementation (bitmap, hash,
rbtree..) based on the userspace requirements.

Figuring out the chosen backend requires information about the set flags
and the kernel version.  Export this to userspace so nft can include this
information in '--debug=netlink' output.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c

index 49c944e78463f3039c59848af4b1599125956485..7d6bc19a0153f3f0c522405ddd8482b82a3fc5c0 100644 (file)
@@ -394,6 +394,8 @@ enum nft_set_field_attributes {
  * @NFTA_SET_HANDLE: set handle (NLA_U64)
  * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
  * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
+ * @NFTA_SET_TYPE: set backend type (NLA_STRING)
+ * @NFTA_SET_COUNT: number of set elements (NLA_U32)
  */
 enum nft_set_attributes {
        NFTA_SET_UNSPEC,
@@ -415,6 +417,8 @@ enum nft_set_attributes {
        NFTA_SET_HANDLE,
        NFTA_SET_EXPR,
        NFTA_SET_EXPRESSIONS,
+       NFTA_SET_TYPE,
+       NFTA_SET_COUNT,
        __NFTA_SET_MAX
 };
 #define NFTA_SET_MAX           (__NFTA_SET_MAX - 1)
index a133e1c175ce9c815ca5f19f9ae762928d87d976..b28f6730e26d665bfd1045bb3a65f2c2c49b02fe 100644 (file)
@@ -4569,6 +4569,8 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
        [NFTA_SET_HANDLE]               = { .type = NLA_U64 },
        [NFTA_SET_EXPR]                 = { .type = NLA_NESTED },
        [NFTA_SET_EXPRESSIONS]          = NLA_POLICY_NESTED_ARRAY(nft_expr_policy),
+       [NFTA_SET_TYPE]                 = { .type = NLA_REJECT },
+       [NFTA_SET_COUNT]                = { .type = NLA_REJECT },
 };
 
 static const struct nla_policy nft_concat_policy[NFTA_SET_FIELD_MAX + 1] = {
@@ -4763,6 +4765,27 @@ static u32 nft_set_userspace_size(const struct nft_set_ops *ops, u32 size)
        return size;
 }
 
+static noinline_for_stack int
+nf_tables_fill_set_info(struct sk_buff *skb, const struct nft_set *set)
+{
+       unsigned int nelems;
+       char str[40];
+       int ret;
+
+       ret = snprintf(str, sizeof(str), "%ps", set->ops);
+
+       /* Not expected to happen and harmless: NFTA_SET_TYPE is dumped
+        * to userspace purely for informational/debug purposes.
+        */
+       DEBUG_NET_WARN_ON_ONCE(ret >= sizeof(str));
+
+       if (nla_put_string(skb, NFTA_SET_TYPE, str))
+               return -EMSGSIZE;
+
+       nelems = nft_set_userspace_size(set->ops, atomic_read(&set->nelems));
+       return nla_put_be32(skb, NFTA_SET_COUNT, htonl(nelems));
+}
+
 static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
                              const struct nft_set *set, u16 event, u16 flags)
 {
@@ -4843,6 +4866,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
 
        nla_nest_end(skb, nest);
 
+       if (nf_tables_fill_set_info(skb, set))
+               goto nla_put_failure;
+
        if (set->num_exprs == 1) {
                nest = nla_nest_start_noflag(skb, NFTA_SET_EXPR);
                if (nf_tables_fill_expr_info(skb, set->exprs[0], false) < 0)