|
|
8ff5ad |
From bd940a4efd2b5897f8a8e58ec7733417b3710e1e Mon Sep 17 00:00:00 2001
|
|
|
8ff5ad |
From: Phil Sutter <psutter@redhat.com>
|
|
|
8ff5ad |
Date: Wed, 8 Dec 2021 13:28:49 +0100
|
|
|
8ff5ad |
Subject: [PATCH] mnl: do not build nftnl_set element list
|
|
|
8ff5ad |
|
|
|
8ff5ad |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2047821
|
|
|
8ff5ad |
Upstream Status: nftables commit b4b234f5a29e8
|
|
|
8ff5ad |
Conflicts: Context change due to missing commit 66746e7dedeb0
|
|
|
8ff5ad |
("src: support for nat with interval concatenation").
|
|
|
8ff5ad |
|
|
|
8ff5ad |
commit b4b234f5a29e819045679acd95820a7457d4d7de
|
|
|
8ff5ad |
Author: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
|
8ff5ad |
Date: Thu Nov 4 12:53:11 2021 +0100
|
|
|
8ff5ad |
|
|
|
8ff5ad |
mnl: do not build nftnl_set element list
|
|
|
8ff5ad |
|
|
|
8ff5ad |
Do not call alloc_setelem_cache() to build the set element list in
|
|
|
8ff5ad |
nftnl_set. Instead, translate one single set element expression to
|
|
|
8ff5ad |
nftnl_set_elem object at a time and use this object to build the netlink
|
|
|
8ff5ad |
header.
|
|
|
8ff5ad |
|
|
|
8ff5ad |
Using a huge test set containing 1.1 million element blocklist, this
|
|
|
8ff5ad |
patch is reducing userspace memory consumption by 40%.
|
|
|
8ff5ad |
|
|
|
8ff5ad |
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
|
8ff5ad |
---
|
|
|
8ff5ad |
include/netlink.h | 2 +
|
|
|
8ff5ad |
src/mnl.c | 112 ++++++++++++++++++++++++++++++++++++----------
|
|
|
8ff5ad |
src/netlink.c | 4 +-
|
|
|
8ff5ad |
3 files changed, 93 insertions(+), 25 deletions(-)
|
|
|
8ff5ad |
|
|
|
8ff5ad |
diff --git a/include/netlink.h b/include/netlink.h
|
|
|
8ff5ad |
index 059092e..3443582 100644
|
|
|
8ff5ad |
--- a/include/netlink.h
|
|
|
8ff5ad |
+++ b/include/netlink.h
|
|
|
8ff5ad |
@@ -56,6 +56,8 @@ struct netlink_ctx {
|
|
|
8ff5ad |
|
|
|
8ff5ad |
extern struct nftnl_expr *alloc_nft_expr(const char *name);
|
|
|
8ff5ad |
extern void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls);
|
|
|
8ff5ad |
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
|
|
|
8ff5ad |
+ const struct expr *expr);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
extern struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh);
|
|
|
8ff5ad |
extern struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh);
|
|
|
8ff5ad |
diff --git a/src/mnl.c b/src/mnl.c
|
|
|
8ff5ad |
index 23341e6..44cf1a4 100644
|
|
|
8ff5ad |
--- a/src/mnl.c
|
|
|
8ff5ad |
+++ b/src/mnl.c
|
|
|
8ff5ad |
@@ -1201,33 +1201,102 @@ static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
|
|
|
8ff5ad |
return MNL_CB_OK;
|
|
|
8ff5ad |
}
|
|
|
8ff5ad |
|
|
|
8ff5ad |
-static int mnl_nft_setelem_batch(struct nftnl_set *nls,
|
|
|
8ff5ad |
+static bool mnl_nft_attr_nest_overflow(struct nlmsghdr *nlh,
|
|
|
8ff5ad |
+ const struct nlattr *from,
|
|
|
8ff5ad |
+ const struct nlattr *to)
|
|
|
8ff5ad |
+{
|
|
|
8ff5ad |
+ int len = (void *)to + to->nla_len - (void *)from;
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ /* The attribute length field is 16 bits long, thus the maximum payload
|
|
|
8ff5ad |
+ * that an attribute can convey is UINT16_MAX. In case of overflow,
|
|
|
8ff5ad |
+ * discard the last attribute that did not fit into the nest.
|
|
|
8ff5ad |
+ */
|
|
|
8ff5ad |
+ if (len > UINT16_MAX) {
|
|
|
8ff5ad |
+ nlh->nlmsg_len -= to->nla_len;
|
|
|
8ff5ad |
+ return true;
|
|
|
8ff5ad |
+ }
|
|
|
8ff5ad |
+ return false;
|
|
|
8ff5ad |
+}
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+static void netlink_dump_setelem(const struct nftnl_set_elem *nlse,
|
|
|
8ff5ad |
+ struct netlink_ctx *ctx)
|
|
|
8ff5ad |
+{
|
|
|
8ff5ad |
+ FILE *fp = ctx->nft->output.output_fp;
|
|
|
8ff5ad |
+ char buf[4096];
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
|
|
|
8ff5ad |
+ return;
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ nftnl_set_elem_snprintf(buf, sizeof(buf), nlse, NFTNL_OUTPUT_DEFAULT, 0);
|
|
|
8ff5ad |
+ fprintf(fp, "\t%s", buf);
|
|
|
8ff5ad |
+}
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+static void netlink_dump_setelem_done(struct netlink_ctx *ctx)
|
|
|
8ff5ad |
+{
|
|
|
8ff5ad |
+ FILE *fp = ctx->nft->output.output_fp;
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
|
|
|
8ff5ad |
+ return;
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ fprintf(fp, "\n");
|
|
|
8ff5ad |
+}
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+static int mnl_nft_setelem_batch(const struct nftnl_set *nls,
|
|
|
8ff5ad |
struct nftnl_batch *batch,
|
|
|
8ff5ad |
enum nf_tables_msg_types cmd,
|
|
|
8ff5ad |
- unsigned int flags, uint32_t seqnum)
|
|
|
8ff5ad |
+ unsigned int flags, uint32_t seqnum,
|
|
|
8ff5ad |
+ const struct expr *set,
|
|
|
8ff5ad |
+ struct netlink_ctx *ctx)
|
|
|
8ff5ad |
{
|
|
|
8ff5ad |
+ struct nlattr *nest1, *nest2;
|
|
|
8ff5ad |
+ struct nftnl_set_elem *nlse;
|
|
|
8ff5ad |
struct nlmsghdr *nlh;
|
|
|
8ff5ad |
- struct nftnl_set_elems_iter *iter;
|
|
|
8ff5ad |
- int ret;
|
|
|
8ff5ad |
-
|
|
|
8ff5ad |
- iter = nftnl_set_elems_iter_create(nls);
|
|
|
8ff5ad |
- if (iter == NULL)
|
|
|
8ff5ad |
- memory_allocation_error();
|
|
|
8ff5ad |
+ struct expr *expr = NULL;
|
|
|
8ff5ad |
+ int i = 0;
|
|
|
8ff5ad |
|
|
|
8ff5ad |
if (cmd == NFT_MSG_NEWSETELEM)
|
|
|
8ff5ad |
flags |= NLM_F_CREATE;
|
|
|
8ff5ad |
|
|
|
8ff5ad |
- while (nftnl_set_elems_iter_cur(iter)) {
|
|
|
8ff5ad |
- nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
|
|
|
8ff5ad |
- nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
|
|
|
8ff5ad |
- flags, seqnum);
|
|
|
8ff5ad |
- ret = nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter);
|
|
|
8ff5ad |
- mnl_nft_batch_continue(batch);
|
|
|
8ff5ad |
- if (ret <= 0)
|
|
|
8ff5ad |
- break;
|
|
|
8ff5ad |
+ if (set)
|
|
|
8ff5ad |
+ expr = list_first_entry(&set->expressions, struct expr, list);
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+next:
|
|
|
8ff5ad |
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
|
|
|
8ff5ad |
+ nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
|
|
|
8ff5ad |
+ flags, seqnum);
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ if (nftnl_set_is_set(nls, NFTNL_SET_TABLE)) {
|
|
|
8ff5ad |
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE,
|
|
|
8ff5ad |
+ nftnl_set_get_str(nls, NFTNL_SET_TABLE));
|
|
|
8ff5ad |
+ }
|
|
|
8ff5ad |
+ if (nftnl_set_is_set(nls, NFTNL_SET_NAME)) {
|
|
|
8ff5ad |
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET,
|
|
|
8ff5ad |
+ nftnl_set_get_str(nls, NFTNL_SET_NAME));
|
|
|
8ff5ad |
}
|
|
|
8ff5ad |
+ if (nftnl_set_is_set(nls, NFTNL_SET_ID)) {
|
|
|
8ff5ad |
+ mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID,
|
|
|
8ff5ad |
+ htonl(nftnl_set_get_u32(nls, NFTNL_SET_ID)));
|
|
|
8ff5ad |
+ }
|
|
|
8ff5ad |
+
|
|
|
8ff5ad |
+ if (!set || list_empty(&set->expressions))
|
|
|
8ff5ad |
+ return 0;
|
|
|
8ff5ad |
|
|
|
8ff5ad |
- nftnl_set_elems_iter_destroy(iter);
|
|
|
8ff5ad |
+ assert(expr);
|
|
|
8ff5ad |
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
|
|
|
8ff5ad |
+ list_for_each_entry_from(expr, &set->expressions, list) {
|
|
|
8ff5ad |
+ nlse = alloc_nftnl_setelem(set, expr);
|
|
|
8ff5ad |
+ nest2 = nftnl_set_elem_nlmsg_build(nlh, nlse, ++i);
|
|
|
8ff5ad |
+ netlink_dump_setelem(nlse, ctx);
|
|
|
8ff5ad |
+ nftnl_set_elem_free(nlse);
|
|
|
8ff5ad |
+ if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) {
|
|
|
8ff5ad |
+ mnl_attr_nest_end(nlh, nest1);
|
|
|
8ff5ad |
+ mnl_nft_batch_continue(batch);
|
|
|
8ff5ad |
+ goto next;
|
|
|
8ff5ad |
+ }
|
|
|
8ff5ad |
+ }
|
|
|
8ff5ad |
+ mnl_attr_nest_end(nlh, nest1);
|
|
|
8ff5ad |
+ mnl_nft_batch_continue(batch);
|
|
|
8ff5ad |
+ netlink_dump_setelem_done(ctx);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
return 0;
|
|
|
8ff5ad |
}
|
|
|
8ff5ad |
@@ -1249,11 +1318,10 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
|
|
|
8ff5ad |
if (h->set_id)
|
|
|
8ff5ad |
nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
- alloc_setelem_cache(expr, nls);
|
|
|
8ff5ad |
netlink_dump_set(nls, ctx);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
- err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM, flags,
|
|
|
8ff5ad |
- ctx->seqnum);
|
|
|
8ff5ad |
+ err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM,
|
|
|
8ff5ad |
+ flags, ctx->seqnum, expr, ctx);
|
|
|
8ff5ad |
nftnl_set_free(nls);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
return err;
|
|
|
8ff5ad |
@@ -1306,12 +1374,10 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
|
8ff5ad |
else if (h->handle.id)
|
|
|
8ff5ad |
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
- if (cmd->expr)
|
|
|
8ff5ad |
- alloc_setelem_cache(cmd->expr, nls);
|
|
|
8ff5ad |
netlink_dump_set(nls, ctx);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_DELSETELEM, 0,
|
|
|
8ff5ad |
- ctx->seqnum);
|
|
|
8ff5ad |
+ ctx->seqnum, cmd->expr, ctx);
|
|
|
8ff5ad |
nftnl_set_free(nls);
|
|
|
8ff5ad |
|
|
|
8ff5ad |
return err;
|
|
|
8ff5ad |
diff --git a/src/netlink.c b/src/netlink.c
|
|
|
8ff5ad |
index 825c2cc..f8c97d0 100644
|
|
|
8ff5ad |
--- a/src/netlink.c
|
|
|
8ff5ad |
+++ b/src/netlink.c
|
|
|
8ff5ad |
@@ -95,8 +95,8 @@ struct nftnl_expr *alloc_nft_expr(const char *name)
|
|
|
8ff5ad |
return nle;
|
|
|
8ff5ad |
}
|
|
|
8ff5ad |
|
|
|
8ff5ad |
-static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
|
|
|
8ff5ad |
- const struct expr *expr)
|
|
|
8ff5ad |
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
|
|
|
8ff5ad |
+ const struct expr *expr)
|
|
|
8ff5ad |
{
|
|
|
8ff5ad |
const struct expr *elem, *data;
|
|
|
8ff5ad |
struct nftnl_set_elem *nlse;
|
|
|
8ff5ad |
--
|
|
|
8ff5ad |
2.31.1
|
|
|
8ff5ad |
|