340 lines
9.4 KiB
Diff
340 lines
9.4 KiB
Diff
|
From 005c220f08964958eae2ca6e40a070b5bc9d6f79 Mon Sep 17 00:00:00 2001
|
||
|
From: Phil Sutter <psutter@redhat.com>
|
||
|
Date: Thu, 7 Nov 2024 18:38:45 +0100
|
||
|
Subject: [PATCH] src: collapse set element commands from parser
|
||
|
|
||
|
JIRA: https://issues.redhat.com/browse/RHEL-65346
|
||
|
Upstream Status: nftables commit 20f1c60ac8c88be3bdf3096083b24ada06570a77
|
||
|
|
||
|
commit 20f1c60ac8c88be3bdf3096083b24ada06570a77
|
||
|
Author: Pablo Neira Ayuso <pablo@netfilter.org>
|
||
|
Date: Wed Oct 23 11:43:58 2024 +0200
|
||
|
|
||
|
src: collapse set element commands from parser
|
||
|
|
||
|
498a5f0c219d ("rule: collapse set element commands") does not help to
|
||
|
reduce memory consumption in the case of large sets defined by one
|
||
|
element per line:
|
||
|
|
||
|
add element ip x y { 1.1.1.1 }
|
||
|
add element ip x y { 1.1.1.2 }
|
||
|
...
|
||
|
|
||
|
This patch reduces memory consumption by ~75%, set elements are
|
||
|
collapsed into an existing cmd object wherever possible to reduce the
|
||
|
number of cmd objects.
|
||
|
|
||
|
This patch also adds a special case for variables for sets similar to:
|
||
|
|
||
|
be055af5c58d ("cmd: skip variable set elements when collapsing commands")
|
||
|
|
||
|
This patch requires this small kernel fix:
|
||
|
|
||
|
commit b53c116642502b0c85ecef78bff4f826a7dd4145
|
||
|
Author: Pablo Neira Ayuso <pablo@netfilter.org>
|
||
|
Date: Fri May 20 00:02:06 2022 +0200
|
||
|
|
||
|
netfilter: nf_tables: set element extended ACK reporting support
|
||
|
|
||
|
which is already included in recent -stable kernels:
|
||
|
|
||
|
# cat ruleset.nft
|
||
|
add table ip x
|
||
|
add chain ip x y
|
||
|
add set ip x y { type ipv4_addr; }
|
||
|
create element ip x y { 1.1.1.1 }
|
||
|
create element ip x y { 1.1.1.1 }
|
||
|
|
||
|
# nft -f ruleset.nft
|
||
|
ruleset.nft:5:25-31: Error: Could not process rule: File exists
|
||
|
create element ip x y { 1.1.1.1 }
|
||
|
^^^^^^^
|
||
|
|
||
|
since there is no need to relate commands via sequence number anymore,
|
||
|
this allows also removes the uncollapse step.
|
||
|
|
||
|
Fixes: 498a5f0c219d ("rule: collapse set element commands")
|
||
|
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||
|
|
||
|
Signed-off-by: Phil Sutter <psutter@redhat.com>
|
||
|
---
|
||
|
include/cmd.h | 7 +--
|
||
|
include/expression.h | 1 -
|
||
|
include/list.h | 11 +++++
|
||
|
include/rule.h | 1 -
|
||
|
src/cmd.c | 105 +++++++++++--------------------------------
|
||
|
src/libnftables.c | 7 ---
|
||
|
src/parser_bison.y | 13 ++++++
|
||
|
src/rule.c | 1 -
|
||
|
8 files changed, 54 insertions(+), 92 deletions(-)
|
||
|
|
||
|
diff --git a/include/cmd.h b/include/cmd.h
|
||
|
index 92a4152..0a8779b 100644
|
||
|
--- a/include/cmd.h
|
||
|
+++ b/include/cmd.h
|
||
|
@@ -2,12 +2,13 @@
|
||
|
#define _NFT_CMD_H_
|
||
|
|
||
|
void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc);
|
||
|
+struct mnl_err;
|
||
|
void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
|
||
|
struct mnl_err *err);
|
||
|
|
||
|
+bool nft_cmd_collapse_elems(enum cmd_ops op, struct list_head *cmds,
|
||
|
+ struct handle *handle, struct expr *init);
|
||
|
+
|
||
|
void nft_cmd_expand(struct cmd *cmd);
|
||
|
-void nft_cmd_post_expand(struct cmd *cmd);
|
||
|
-bool nft_cmd_collapse(struct list_head *cmds);
|
||
|
-void nft_cmd_uncollapse(struct list_head *cmds);
|
||
|
|
||
|
#endif
|
||
|
diff --git a/include/expression.h b/include/expression.h
|
||
|
index 8982110..da2f693 100644
|
||
|
--- a/include/expression.h
|
||
|
+++ b/include/expression.h
|
||
|
@@ -255,7 +255,6 @@ struct expr {
|
||
|
enum expr_types etype:8;
|
||
|
enum ops op:8;
|
||
|
unsigned int len;
|
||
|
- struct cmd *cmd;
|
||
|
|
||
|
union {
|
||
|
struct {
|
||
|
diff --git a/include/list.h b/include/list.h
|
||
|
index 857921e..37fbe3e 100644
|
||
|
--- a/include/list.h
|
||
|
+++ b/include/list.h
|
||
|
@@ -348,6 +348,17 @@ static inline void list_splice_tail_init(struct list_head *list,
|
||
|
#define list_first_entry(ptr, type, member) \
|
||
|
list_entry((ptr)->next, type, member)
|
||
|
|
||
|
+/**
|
||
|
+ * list_last_entry - get the last element from a list
|
||
|
+ * @ptr: the list head to take the element from.
|
||
|
+ * @type: the type of the struct this is embedded in.
|
||
|
+ * @member: the name of the list_head within the struct.
|
||
|
+ *
|
||
|
+ * Note, that list is expected to be not empty.
|
||
|
+ */
|
||
|
+#define list_last_entry(ptr, type, member) \
|
||
|
+ list_entry((ptr)->prev, type, member)
|
||
|
+
|
||
|
/**
|
||
|
* list_next_entry - get the next element in list
|
||
|
* @pos: the type * to cursor
|
||
|
diff --git a/include/rule.h b/include/rule.h
|
||
|
index 5b3e12b..a1628d8 100644
|
||
|
--- a/include/rule.h
|
||
|
+++ b/include/rule.h
|
||
|
@@ -718,7 +718,6 @@ struct cmd {
|
||
|
enum cmd_obj obj;
|
||
|
struct handle handle;
|
||
|
uint32_t seqnum;
|
||
|
- struct list_head collapse_list;
|
||
|
union {
|
||
|
void *data;
|
||
|
struct expr *expr;
|
||
|
diff --git a/src/cmd.c b/src/cmd.c
|
||
|
index 9a572b5..e010dcb 100644
|
||
|
--- a/src/cmd.c
|
||
|
+++ b/src/cmd.c
|
||
|
@@ -378,6 +378,32 @@ static void nft_cmd_expand_chain(struct chain *chain, struct list_head *new_cmds
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+bool nft_cmd_collapse_elems(enum cmd_ops op, struct list_head *cmds,
|
||
|
+ struct handle *handle, struct expr *init)
|
||
|
+{
|
||
|
+ struct cmd *last_cmd;
|
||
|
+
|
||
|
+ if (list_empty(cmds))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ if (init->etype == EXPR_VARIABLE)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ last_cmd = list_last_entry(cmds, struct cmd, list);
|
||
|
+ if (last_cmd->op != op ||
|
||
|
+ last_cmd->obj != CMD_OBJ_ELEMENTS ||
|
||
|
+ last_cmd->expr->etype == EXPR_VARIABLE ||
|
||
|
+ last_cmd->handle.family != handle->family ||
|
||
|
+ strcmp(last_cmd->handle.table.name, handle->table.name) ||
|
||
|
+ strcmp(last_cmd->handle.set.name, handle->set.name))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ list_splice_tail_init(&init->expressions, &last_cmd->expr->expressions);
|
||
|
+ last_cmd->expr->size += init->size;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
void nft_cmd_expand(struct cmd *cmd)
|
||
|
{
|
||
|
struct list_head new_cmds;
|
||
|
@@ -459,82 +485,3 @@ void nft_cmd_expand(struct cmd *cmd)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
-bool nft_cmd_collapse(struct list_head *cmds)
|
||
|
-{
|
||
|
- struct cmd *cmd, *next, *elems = NULL;
|
||
|
- struct expr *expr, *enext;
|
||
|
- bool collapse = false;
|
||
|
-
|
||
|
- list_for_each_entry_safe(cmd, next, cmds, list) {
|
||
|
- if (cmd->op != CMD_ADD &&
|
||
|
- cmd->op != CMD_CREATE) {
|
||
|
- elems = NULL;
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- if (cmd->obj != CMD_OBJ_ELEMENTS) {
|
||
|
- elems = NULL;
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- if (cmd->expr->etype == EXPR_VARIABLE)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (!elems) {
|
||
|
- elems = cmd;
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- if (cmd->op != elems->op) {
|
||
|
- elems = cmd;
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- if (elems->handle.family != cmd->handle.family ||
|
||
|
- strcmp(elems->handle.table.name, cmd->handle.table.name) ||
|
||
|
- strcmp(elems->handle.set.name, cmd->handle.set.name)) {
|
||
|
- elems = cmd;
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- collapse = true;
|
||
|
- list_for_each_entry_safe(expr, enext, &cmd->expr->expressions, list) {
|
||
|
- expr->cmd = cmd;
|
||
|
- list_move_tail(&expr->list, &elems->expr->expressions);
|
||
|
- }
|
||
|
- elems->expr->size += cmd->expr->size;
|
||
|
- list_move_tail(&cmd->list, &elems->collapse_list);
|
||
|
- }
|
||
|
-
|
||
|
- return collapse;
|
||
|
-}
|
||
|
-
|
||
|
-void nft_cmd_uncollapse(struct list_head *cmds)
|
||
|
-{
|
||
|
- struct cmd *cmd, *cmd_next, *collapse_cmd, *collapse_cmd_next;
|
||
|
- struct expr *expr, *next;
|
||
|
-
|
||
|
- list_for_each_entry_safe(cmd, cmd_next, cmds, list) {
|
||
|
- if (list_empty(&cmd->collapse_list))
|
||
|
- continue;
|
||
|
-
|
||
|
- assert(cmd->obj == CMD_OBJ_ELEMENTS);
|
||
|
-
|
||
|
- list_for_each_entry_safe(expr, next, &cmd->expr->expressions, list) {
|
||
|
- if (!expr->cmd)
|
||
|
- continue;
|
||
|
-
|
||
|
- list_move_tail(&expr->list, &expr->cmd->expr->expressions);
|
||
|
- cmd->expr->size--;
|
||
|
- expr->cmd = NULL;
|
||
|
- }
|
||
|
-
|
||
|
- list_for_each_entry_safe(collapse_cmd, collapse_cmd_next, &cmd->collapse_list, list) {
|
||
|
- if (cmd->elem.set)
|
||
|
- collapse_cmd->elem.set = set_get(cmd->elem.set);
|
||
|
-
|
||
|
- list_add(&collapse_cmd->list, &cmd->list);
|
||
|
- }
|
||
|
- }
|
||
|
-}
|
||
|
diff --git a/src/libnftables.c b/src/libnftables.c
|
||
|
index 2ae2150..2834c99 100644
|
||
|
--- a/src/libnftables.c
|
||
|
+++ b/src/libnftables.c
|
||
|
@@ -513,7 +513,6 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
|
||
|
{
|
||
|
struct nft_cache_filter *filter;
|
||
|
struct cmd *cmd, *next;
|
||
|
- bool collapsed = false;
|
||
|
unsigned int flags;
|
||
|
int err = 0;
|
||
|
|
||
|
@@ -529,9 +528,6 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
|
||
|
|
||
|
nft_cache_filter_fini(filter);
|
||
|
|
||
|
- if (nft_cmd_collapse(cmds))
|
||
|
- collapsed = true;
|
||
|
-
|
||
|
list_for_each_entry(cmd, cmds, list) {
|
||
|
if (cmd->op != CMD_ADD &&
|
||
|
cmd->op != CMD_CREATE)
|
||
|
@@ -553,9 +549,6 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (collapsed)
|
||
|
- nft_cmd_uncollapse(cmds);
|
||
|
-
|
||
|
if (err < 0 || nft->state->nerrs)
|
||
|
return -1;
|
||
|
|
||
|
diff --git a/src/parser_bison.y b/src/parser_bison.y
|
||
|
index e2936d1..602fc60 100644
|
||
|
--- a/src/parser_bison.y
|
||
|
+++ b/src/parser_bison.y
|
||
|
@@ -35,6 +35,7 @@
|
||
|
#include <libnftnl/udata.h>
|
||
|
|
||
|
#include <rule.h>
|
||
|
+#include <cmd.h>
|
||
|
#include <statement.h>
|
||
|
#include <expression.h>
|
||
|
#include <headers.h>
|
||
|
@@ -1219,6 +1220,12 @@ add_cmd : TABLE table_spec
|
||
|
}
|
||
|
| ELEMENT set_spec set_block_expr
|
||
|
{
|
||
|
+ if (nft_cmd_collapse_elems(CMD_ADD, state->cmds, &$2, $3)) {
|
||
|
+ handle_free(&$2);
|
||
|
+ expr_free($3);
|
||
|
+ $$ = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
|
||
|
}
|
||
|
| FLOWTABLE flowtable_spec flowtable_block_alloc
|
||
|
@@ -1336,6 +1343,12 @@ create_cmd : TABLE table_spec
|
||
|
}
|
||
|
| ELEMENT set_spec set_block_expr
|
||
|
{
|
||
|
+ if (nft_cmd_collapse_elems(CMD_CREATE, state->cmds, &$2, $3)) {
|
||
|
+ handle_free(&$2);
|
||
|
+ expr_free($3);
|
||
|
+ $$ = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
|
||
|
}
|
||
|
| FLOWTABLE flowtable_spec flowtable_block_alloc
|
||
|
diff --git a/src/rule.c b/src/rule.c
|
||
|
index 9bc160e..9536e68 100644
|
||
|
--- a/src/rule.c
|
||
|
+++ b/src/rule.c
|
||
|
@@ -1332,7 +1332,6 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
|
||
|
cmd->attr = xzalloc_array(NFT_NLATTR_LOC_MAX,
|
||
|
sizeof(struct nlerr_loc));
|
||
|
cmd->attr_array_len = NFT_NLATTR_LOC_MAX;
|
||
|
- init_list_head(&cmd->collapse_list);
|
||
|
|
||
|
return cmd;
|
||
|
}
|