diff --git a/.gitignore b/.gitignore index 82fbd1f..4aa6694 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ /nftables-1.0.5.tar.bz2 /nftables-1.0.7.tar.xz /nftables-1.0.9.tar.xz +/nftables-1.1.1.tar.xz diff --git a/0001-Add-support-for-table-s-persist-flag.patch b/0001-Add-support-for-table-s-persist-flag.patch deleted file mode 100644 index 3dca01e..0000000 --- a/0001-Add-support-for-table-s-persist-flag.patch +++ /dev/null @@ -1,337 +0,0 @@ -From 450520649ac5ac6f983b40e15e54863aab9d5bd7 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 14 Jun 2024 18:30:55 +0200 -Subject: [PATCH] Add support for table's persist flag - -JIRA: https://issues.redhat.com/browse/RHEL-32122 -Upstream Status: nftables commit 4955ae1a81b73f9a61b7fbf1a73e11544513548e -Conflicts: -- Adjusted to missing commit ffd6b4790a728 - ("src: add free_const() and use it instead of xfree()") - -commit 4955ae1a81b73f9a61b7fbf1a73e11544513548e -Author: Phil Sutter -Date: Fri Dec 15 01:10:39 2023 +0100 - - Add support for table's persist flag - - Bison parser lacked support for passing multiple flags, JSON parser - did not support table flags at all. - - Document also 'owner' flag (and describe their relationship in nft.8. - - Signed-off-by: Phil Sutter - -Signed-off-by: Phil Sutter ---- - doc/libnftables-json.adoc | 11 ++++- - doc/nft.txt | 9 ++++ - include/rule.h | 4 +- - src/parser_bison.y | 35 +++++++++------ - src/parser_json.c | 49 ++++++++++++++++++++- - src/rule.c | 12 +++++ - tests/shell/features/table_flag_persist.nft | 3 ++ - tests/shell/testcases/owner/0002-persist | 36 +++++++++++++++ - 8 files changed, 142 insertions(+), 17 deletions(-) - create mode 100644 tests/shell/features/table_flag_persist.nft - create mode 100755 tests/shell/testcases/owner/0002-persist - -diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc -index 3e6e1db..0e424c2 100644 ---- a/doc/libnftables-json.adoc -+++ b/doc/libnftables-json.adoc -@@ -202,12 +202,19 @@ Rename a chain. The new name is expected in a dedicated property named - - === TABLE - [verse] -+____ - *{ "table": { - "family":* 'STRING'*, - "name":* 'STRING'*, -- "handle":* 'NUMBER' -+ "handle":* 'NUMBER'*, -+ "flags":* 'TABLE_FLAGS' - *}}* - -+'TABLE_FLAGS' := 'TABLE_FLAG' | *[* 'TABLE_FLAG_LIST' *]* -+'TABLE_FLAG_LIST' := 'TABLE_FLAG' [*,* 'TABLE_FLAG_LIST' ] -+'TABLE_FLAG' := *"dormant"* | *"owner"* | *"persist"* -+____ -+ - This object describes a table. - - *family*:: -@@ -217,6 +224,8 @@ This object describes a table. - *handle*:: - The table's handle. In input, it is used only in *delete* command as - alternative to *name*. -+*flags*:: -+ The table's flags. - - === CHAIN - [verse] -diff --git a/doc/nft.txt b/doc/nft.txt -index b08e32f..dba1b60 100644 ---- a/doc/nft.txt -+++ b/doc/nft.txt -@@ -343,8 +343,17 @@ return an error. - |Flag | Description - |dormant | - table is not evaluated any more (base chains are unregistered). -+|owner | -+table is owned by the creating process. -+|persist | -+table shall outlive the owning process. - |================= - -+Creating a table with flag *owner* excludes other processes from manipulating -+it or its contents. By default, it will be removed when the process exits. -+Setting flag *persist* will prevent this and the resulting orphaned table will -+accept a new owner, e.g. a restarting daemon maintaining the table. -+ - .*Add, change, delete a table* - --------------------------------------- - # start nft in interactive mode -diff --git a/include/rule.h b/include/rule.h -index 6236d29..a8bb11f 100644 ---- a/include/rule.h -+++ b/include/rule.h -@@ -130,10 +130,12 @@ struct symbol *symbol_get(const struct scope *scope, const char *identifier); - enum table_flags { - TABLE_F_DORMANT = (1 << 0), - TABLE_F_OWNER = (1 << 1), -+ TABLE_F_PERSIST = (1 << 2), - }; --#define TABLE_FLAGS_MAX 2 -+#define TABLE_FLAGS_MAX 3 - - const char *table_flag_name(uint32_t flag); -+unsigned int parse_table_flag(const char *name); - - /** - * struct table - nftables table -diff --git a/src/parser_bison.y b/src/parser_bison.y -index c517dc3..5ced6e1 100644 ---- a/src/parser_bison.y -+++ b/src/parser_bison.y -@@ -720,6 +720,8 @@ int nft_lex(void *, void *, void *); - %type rule rule_alloc - %destructor { rule_free($$); } rule - -+%type table_flags table_flag -+ - %type set_flag_list set_flag - - %type set_policy_spec -@@ -1874,20 +1876,9 @@ table_block_alloc : /* empty */ - } - ; - --table_options : FLAGS STRING -+table_options : FLAGS table_flags - { -- if (strcmp($2, "dormant") == 0) { -- $0->flags |= TABLE_F_DORMANT; -- xfree($2); -- } else if (strcmp($2, "owner") == 0) { -- $
0->flags |= TABLE_F_OWNER; -- xfree($2); -- } else { -- erec_queue(error(&@2, "unknown table option %s", $2), -- state->msgs); -- xfree($2); -- YYERROR; -- } -+ $
0->flags |= $2; - } - | comment_spec - { -@@ -1899,6 +1890,24 @@ table_options : FLAGS STRING - } - ; - -+table_flags : table_flag -+ | table_flags COMMA table_flag -+ { -+ $$ = $1 | $3; -+ } -+ ; -+table_flag : STRING -+ { -+ $$ = parse_table_flag($1); -+ xfree($1); -+ if ($$ == 0) { -+ erec_queue(error(&@1, "unknown table option %s", $1), -+ state->msgs); -+ YYERROR; -+ } -+ } -+ ; -+ - table_block : /* empty */ { $$ = $
-1; } - | table_block common_block - | table_block stmt_separator -diff --git a/src/parser_json.c b/src/parser_json.c -index 199241a..9e5b656 100644 ---- a/src/parser_json.c -+++ b/src/parser_json.c -@@ -2941,6 +2941,45 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) - return NULL; - } - -+static int json_parse_table_flags(struct json_ctx *ctx, json_t *root, -+ enum table_flags *flags) -+{ -+ json_t *tmp, *tmp2; -+ size_t index; -+ int flag; -+ -+ if (json_unpack(root, "{s:o}", "flags", &tmp)) -+ return 0; -+ -+ if (json_is_string(tmp)) { -+ flag = parse_table_flag(json_string_value(tmp)); -+ if (flag) { -+ *flags = flag; -+ return 0; -+ } -+ json_error(ctx, "Invalid table flag '%s'.", -+ json_string_value(tmp)); -+ return 1; -+ } -+ if (!json_is_array(tmp)) { -+ json_error(ctx, "Unexpected table flags value."); -+ return 1; -+ } -+ json_array_foreach(tmp, index, tmp2) { -+ if (json_is_string(tmp2)) { -+ flag = parse_table_flag(json_string_value(tmp2)); -+ -+ if (flag) { -+ *flags |= flag; -+ continue; -+ } -+ } -+ json_error(ctx, "Invalid table flag at index %zu.", index); -+ return 1; -+ } -+ return 0; -+} -+ - static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, - enum cmd_ops op, enum cmd_obj obj) - { -@@ -2949,6 +2988,7 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, - .table.location = *int_loc, - }; - struct table *table = NULL; -+ enum table_flags flags = 0; - - if (json_unpack_err(ctx, root, "{s:s}", - "family", &family)) -@@ -2959,6 +2999,9 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, - return NULL; - - json_unpack(root, "{s:s}", "comment", &comment); -+ if (json_parse_table_flags(ctx, root, &flags)) -+ return NULL; -+ - } else if (op == CMD_DELETE && - json_unpack(root, "{s:s}", "name", &h.table.name) && - json_unpack(root, "{s:I}", "handle", &h.handle.id)) { -@@ -2972,10 +3015,12 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, - if (h.table.name) - h.table.name = xstrdup(h.table.name); - -- if (comment) { -+ if (comment || flags) { - table = table_alloc(); - handle_merge(&table->handle, &h); -- table->comment = xstrdup(comment); -+ if (comment) -+ table->comment = xstrdup(comment); -+ table->flags = flags; - } - - if (op == CMD_ADD) -diff --git a/src/rule.c b/src/rule.c -index 739b7a5..a0e151d 100644 ---- a/src/rule.c -+++ b/src/rule.c -@@ -1208,6 +1208,7 @@ struct table *table_lookup_fuzzy(const struct handle *h, - static const char *table_flags_name[TABLE_FLAGS_MAX] = { - "dormant", - "owner", -+ "persist", - }; - - const char *table_flag_name(uint32_t flag) -@@ -1218,6 +1219,17 @@ const char *table_flag_name(uint32_t flag) - return table_flags_name[flag]; - } - -+unsigned int parse_table_flag(const char *name) -+{ -+ int i; -+ -+ for (i = 0; i < TABLE_FLAGS_MAX; i++) { -+ if (!strcmp(name, table_flags_name[i])) -+ return 1 << i; -+ } -+ return 0; -+} -+ - static void table_print_flags(const struct table *table, const char **delim, - struct output_ctx *octx) - { -diff --git a/tests/shell/features/table_flag_persist.nft b/tests/shell/features/table_flag_persist.nft -new file mode 100644 -index 0000000..0da3e6d ---- /dev/null -+++ b/tests/shell/features/table_flag_persist.nft -@@ -0,0 +1,3 @@ -+table t { -+ flags persist; -+} -diff --git a/tests/shell/testcases/owner/0002-persist b/tests/shell/testcases/owner/0002-persist -new file mode 100755 -index 0000000..cf4b8f1 ---- /dev/null -+++ b/tests/shell/testcases/owner/0002-persist -@@ -0,0 +1,36 @@ -+#!/bin/bash -+ -+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_table_flag_owner) -+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_table_flag_persist) -+ -+die() { -+ echo "$@" -+ exit 1 -+} -+ -+$NFT -f - < +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] tests: shell: fix spurious dump failure in vmap timeout test + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 95017b8c8f10ada09c2faa7e6bae71b60f38f259 + +commit 95017b8c8f10ada09c2faa7e6bae71b60f38f259 +Author: Florian Westphal +Date: Fri Oct 11 02:32:08 2024 +0200 + + tests: shell: fix spurious dump failure in vmap timeout test + + Blamed commit can update the timeout to 6s, but last line waits + for 5 seconds and expects that to be enough to have all elements vanish. + + Fix the typo to limit update timeout also to 5 seconds and not 6. + This fixes spurious dump failures like this one: + + - elements = { 1.2.3.4 . 22 : jump ssh_input } + + elements = { 1.2.3.4 . 22 : jump ssh_input, + + 10.0.95.144 . 38023 timeout 6s expires 545ms : jump other_input } + + Fixes: db80037c0279 ("tests: shell: extend vmap test with updates") + Signed-off-by: Florian Westphal + +Signed-off-by: Phil Sutter +--- + tests/shell/testcases/maps/vmap_timeout | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/shell/testcases/maps/vmap_timeout b/tests/shell/testcases/maps/vmap_timeout +index 3f0563a..6d73f3c 100755 +--- a/tests/shell/testcases/maps/vmap_timeout ++++ b/tests/shell/testcases/maps/vmap_timeout +@@ -32,7 +32,7 @@ for i in $(seq 1 100) ; do + timeout=$((timeout+1)) + expire=$((RANDOM%timeout)) + utimeout=$((RANDOM%5)) +- utimeout=$((timeout+1)) ++ utimeout=$((utimeout+1)) + + timeout_str="timeout ${timeout}s" + expire_str="" diff --git a/0002-cache-Always-set-NFT_CACHE_TERSE-for-list-cmd-with-t.patch b/0002-cache-Always-set-NFT_CACHE_TERSE-for-list-cmd-with-t.patch deleted file mode 100644 index f20c1c8..0000000 --- a/0002-cache-Always-set-NFT_CACHE_TERSE-for-list-cmd-with-t.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 2ef49849b901184c3d97c98c05ffa6418b50af1e Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Tue, 2 Jul 2024 16:41:22 +0200 -Subject: [PATCH] cache: Always set NFT_CACHE_TERSE for list cmd with --terse - -JIRA: https://issues.redhat.com/browse/RHEL-45633 -Upstream Status: nftables commit cd4e947032a57a585b1a457ce03f546afc7ba033 - -commit cd4e947032a57a585b1a457ce03f546afc7ba033 -Author: Phil Sutter -Date: Thu Feb 8 02:10:48 2024 +0100 - - cache: Always set NFT_CACHE_TERSE for list cmd with --terse - - This fixes at least 'nft -t list table ...' and 'nft -t list set ...'. - - Note how --terse handling for 'list sets/maps' remains in place since - setting NFT_CACHE_TERSE does not fully undo NFT_CACHE_SETELEM: setting - both enables fetching of anonymous sets which is pointless for that - command. - - Reported-by: anton.khazan@gmail.com - Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1735 - Suggested-by: Pablo Neira Ayuso - Signed-off-by: Phil Sutter - -Signed-off-by: Phil Sutter ---- - src/cache.c | 10 +++------- - 1 file changed, 3 insertions(+), 7 deletions(-) - -diff --git a/src/cache.c b/src/cache.c -index 4e89fe1..0ac0f7c 100644 ---- a/src/cache.c -+++ b/src/cache.c -@@ -230,8 +230,6 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd, - } - if (filter->list.table && filter->list.set) - flags |= NFT_CACHE_TABLE | NFT_CACHE_SET | NFT_CACHE_SETELEM; -- else if (nft_output_terse(&nft->output)) -- flags |= NFT_CACHE_FULL | NFT_CACHE_TERSE; - else - flags |= NFT_CACHE_FULL; - break; -@@ -257,17 +255,15 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd, - flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE; - break; - case CMD_OBJ_RULESET: -- if (nft_output_terse(&nft->output)) -- flags |= NFT_CACHE_FULL | NFT_CACHE_TERSE; -- else -- flags |= NFT_CACHE_FULL; -- break; - default: - flags |= NFT_CACHE_FULL; - break; - } - flags |= NFT_CACHE_REFRESH; - -+ if (nft_output_terse(&nft->output)) -+ flags |= NFT_CACHE_TERSE; -+ - return flags; - } - diff --git a/0002-libnftables-json-fix-raw-payload-expression-document.patch b/0002-libnftables-json-fix-raw-payload-expression-document.patch new file mode 100644 index 0000000..f5235b9 --- /dev/null +++ b/0002-libnftables-json-fix-raw-payload-expression-document.patch @@ -0,0 +1,38 @@ +From 08d33851ff012bb14237127553be80dbb00fa07d Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] libnftables-json: fix raw payload expression documentation + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 570320ab9a0752c7749a6c9cc85b34a5e7ab91b5 + +commit 570320ab9a0752c7749a6c9cc85b34a5e7ab91b5 +Author: Eric Long +Date: Thu Oct 17 23:33:17 2024 +0800 + + libnftables-json: fix raw payload expression documentation + + Raw payload expression accesses payload data in bits, not bytes. + + Fixes: 872f373dc50f7 ("doc: Add JSON schema documentation") + Signed-off-by: Eric Long + Signed-off-by: Phil Sutter + +Signed-off-by: Phil Sutter +--- + doc/libnftables-json.adoc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc +index a8a6165..2f29ac0 100644 +--- a/doc/libnftables-json.adoc ++++ b/doc/libnftables-json.adoc +@@ -1182,7 +1182,7 @@ ____ + + Construct a payload expression, i.e. a reference to a certain part of packet + data. The first form creates a raw payload expression to point at a random +-number (*len*) of bytes at a certain offset (*offset*) from a given reference ++number (*len*) of bits at a certain offset (*offset*) from a given reference + point (*base*). The following *base* values are accepted: + + *"ll"*:: diff --git a/0003-src-collapse-set-element-commands-from-parser.patch b/0003-src-collapse-set-element-commands-from-parser.patch new file mode 100644 index 0000000..5703b4a --- /dev/null +++ b/0003-src-collapse-set-element-commands-from-parser.patch @@ -0,0 +1,339 @@ +From 005c220f08964958eae2ca6e40a070b5bc9d6f79 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +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 +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 + 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 + +Signed-off-by: Phil Sutter +--- + 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 + + #include ++#include + #include + #include + #include +@@ -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; + } diff --git a/0004-mnl-rename-to-mnl_seqnum_alloc-to-mnl_seqnum_inc.patch b/0004-mnl-rename-to-mnl_seqnum_alloc-to-mnl_seqnum_inc.patch new file mode 100644 index 0000000..4b0a03f --- /dev/null +++ b/0004-mnl-rename-to-mnl_seqnum_alloc-to-mnl_seqnum_inc.patch @@ -0,0 +1,78 @@ +From c2e328edd47ac3d3ed127b313d35ed05839441db Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] mnl: rename to mnl_seqnum_alloc() to mnl_seqnum_inc() + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit b4ce90d52d564efaced298f6e9c575d6942ecf91 + +commit b4ce90d52d564efaced298f6e9c575d6942ecf91 +Author: Pablo Neira Ayuso +Date: Wed Oct 23 22:15:24 2024 +0200 + + mnl: rename to mnl_seqnum_alloc() to mnl_seqnum_inc() + + rename mnl_seqnum_alloc() to mnl_seqnum_inc(). + + No functional change is intended. + + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/mnl.h | 2 +- + src/libnftables.c | 6 +++--- + src/mnl.c | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/include/mnl.h b/include/mnl.h +index c9502f3..7c465d4 100644 +--- a/include/mnl.h ++++ b/include/mnl.h +@@ -8,7 +8,7 @@ + + struct mnl_socket *nft_mnl_socket_open(void); + +-uint32_t mnl_seqnum_alloc(uint32_t *seqnum); ++uint32_t mnl_seqnum_inc(uint32_t *seqnum); + uint32_t mnl_genid_get(struct netlink_ctx *ctx); + + struct mnl_err { +diff --git a/src/libnftables.c b/src/libnftables.c +index 2834c99..3550961 100644 +--- a/src/libnftables.c ++++ b/src/libnftables.c +@@ -37,9 +37,9 @@ static int nft_netlink(struct nft_ctx *nft, + if (list_empty(cmds)) + goto out; + +- batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_alloc(&seqnum)); ++ batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_inc(&seqnum)); + list_for_each_entry(cmd, cmds, list) { +- ctx.seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum); ++ ctx.seqnum = cmd->seqnum = mnl_seqnum_inc(&seqnum); + ret = do_command(&ctx, cmd); + if (ret < 0) { + netlink_io_error(&ctx, &cmd->location, +@@ -50,7 +50,7 @@ static int nft_netlink(struct nft_ctx *nft, + num_cmds++; + } + if (!nft->check) +- mnl_batch_end(ctx.batch, mnl_seqnum_alloc(&seqnum)); ++ mnl_batch_end(ctx.batch, mnl_seqnum_inc(&seqnum)); + + if (!mnl_batch_ready(ctx.batch)) + goto out; +diff --git a/src/mnl.c b/src/mnl.c +index db53a60..c1691da 100644 +--- a/src/mnl.c ++++ b/src/mnl.c +@@ -70,7 +70,7 @@ struct mnl_socket *nft_mnl_socket_open(void) + return nf_sock; + } + +-uint32_t mnl_seqnum_alloc(unsigned int *seqnum) ++uint32_t mnl_seqnum_inc(unsigned int *seqnum) + { + return (*seqnum)++; + } diff --git a/0005-mnl-update-cmd_add_loc-to-take-struct-nlmsghdr.patch b/0005-mnl-update-cmd_add_loc-to-take-struct-nlmsghdr.patch new file mode 100644 index 0000000..f6ca67e --- /dev/null +++ b/0005-mnl-update-cmd_add_loc-to-take-struct-nlmsghdr.patch @@ -0,0 +1,312 @@ +From ed5989c26e998985a01dcd6c57415d8110c63f64 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] mnl: update cmd_add_loc() to take struct nlmsghdr + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit f7c2b27c9f8356c634f0405347444e03e10e151b + +commit f7c2b27c9f8356c634f0405347444e03e10e151b +Author: Pablo Neira Ayuso +Date: Wed Oct 23 23:07:31 2024 +0200 + + mnl: update cmd_add_loc() to take struct nlmsghdr + + To prepare for a fix for very large sets. + + No functional change is intended. + + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/cmd.h | 2 +- + src/cmd.c | 4 +-- + src/mnl.c | 77 +++++++++++++++++++++++++-------------------------- + 3 files changed, 41 insertions(+), 42 deletions(-) + +diff --git a/include/cmd.h b/include/cmd.h +index 0a8779b..cf7e43b 100644 +--- a/include/cmd.h ++++ b/include/cmd.h +@@ -1,7 +1,7 @@ + #ifndef _NFT_CMD_H_ + #define _NFT_CMD_H_ + +-void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc); ++void cmd_add_loc(struct cmd *cmd, const struct nlmsghdr *nlh, const struct location *loc); + struct mnl_err; + void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd, + struct mnl_err *err); +diff --git a/src/cmd.c b/src/cmd.c +index e010dcb..78a2aa3 100644 +--- a/src/cmd.c ++++ b/src/cmd.c +@@ -17,14 +17,14 @@ + #include + #include + +-void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc) ++void cmd_add_loc(struct cmd *cmd, const struct nlmsghdr *nlh, const struct location *loc) + { + if (cmd->num_attrs >= cmd->attr_array_len) { + cmd->attr_array_len *= 2; + cmd->attr = xrealloc(cmd->attr, sizeof(struct nlerr_loc) * cmd->attr_array_len); + } + +- cmd->attr[cmd->num_attrs].offset = offset; ++ cmd->attr[cmd->num_attrs].offset = nlh->nlmsg_len; + cmd->attr[cmd->num_attrs].location = loc; + cmd->num_attrs++; + } +diff --git a/src/mnl.c b/src/mnl.c +index c1691da..42d1b0d 100644 +--- a/src/mnl.c ++++ b/src/mnl.c +@@ -474,7 +474,7 @@ static int mnl_nft_expr_build_cb(struct nftnl_expr *nle, void *data) + + eloc = nft_expr_loc_find(nle, ctx->lctx); + if (eloc) +- cmd_add_loc(cmd, nlh->nlmsg_len, eloc->loc); ++ cmd_add_loc(cmd, nlh, eloc->loc); + + nest = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM); + nftnl_expr_build_payload(nlh, nle); +@@ -527,9 +527,9 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd, + cmd->handle.family, + NLM_F_CREATE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location); ++ cmd_add_loc(cmd, nlh, &h->table.location); + mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location); ++ cmd_add_loc(cmd, nlh, &h->chain.location); + + if (h->chain_id) + mnl_attr_put_u32(nlh, NFTA_RULE_CHAIN_ID, htonl(h->chain_id)); +@@ -578,11 +578,11 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd) + cmd->handle.family, + NLM_F_REPLACE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location); ++ cmd_add_loc(cmd, nlh, &h->table.location); + mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location); ++ cmd_add_loc(cmd, nlh, &h->chain.location); + mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location); ++ cmd_add_loc(cmd, nlh, &h->handle.location); + mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id)); + + mnl_nft_rule_build_ctx_init(&rule_ctx, nlh, cmd, &lctx); +@@ -621,14 +621,14 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd) + nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY), + 0, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location); ++ cmd_add_loc(cmd, nlh, &h->table.location); + mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name); + if (h->chain.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location); ++ cmd_add_loc(cmd, nlh, &h->chain.location); + mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name); + } + if (h->handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location); ++ cmd_add_loc(cmd, nlh, &h->handle.location); + mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id)); + } + +@@ -792,12 +792,12 @@ static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd) + + dev_array = nft_dev_array(dev_expr, &num_devs); + if (num_devs == 1) { +- cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[0].location); ++ cmd_add_loc(cmd, nlh, dev_array[0].location); + mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, dev_array[0].ifname); + } else { + nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS); + for (i = 0; i < num_devs; i++) { +- cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location); ++ cmd_add_loc(cmd, nlh, dev_array[i].location); + mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname); + mnl_attr_nest_end(nlh, nest_dev); + } +@@ -842,9 +842,9 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd, + cmd->handle.family, + NLM_F_CREATE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.chain.location); + + if (!cmd->chain || !(cmd->chain->flags & CHAIN_F_BINDING)) { + mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name); +@@ -861,7 +861,7 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd, + if (cmd->chain && cmd->chain->policy) { + mpz_export_data(&policy, cmd->chain->policy->value, + BYTEORDER_HOST_ENDIAN, sizeof(int)); +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->policy->location); ++ cmd_add_loc(cmd, nlh, &cmd->chain->policy->location); + mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(policy)); + } + +@@ -873,7 +873,7 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd, + struct nlattr *nest; + + if (cmd->chain->type.str) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->type.loc); ++ cmd_add_loc(cmd, nlh, &cmd->chain->type.loc); + mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, cmd->chain->type.str); + } + +@@ -949,13 +949,13 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd) + cmd->handle.family, + 0, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name); + if (cmd->handle.chain.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.chain.location); + mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name); + } else if (cmd->handle.handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.handle.location); + mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, + htobe64(cmd->handle.handle.id)); + } +@@ -1077,7 +1077,7 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd, + cmd->handle.family, + flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name); + nftnl_table_nlmsg_build_payload(nlh, nlt); + nftnl_table_free(nlt); +@@ -1106,10 +1106,10 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd) + cmd->handle.family, 0, ctx->seqnum); + + if (cmd->handle.table.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name); + } else if (cmd->handle.handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.handle.location); + mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE, + htobe64(cmd->handle.handle.id)); + } +@@ -1325,9 +1325,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd, + h->family, + NLM_F_CREATE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location); ++ cmd_add_loc(cmd, nlh, &h->table.location); + mnl_attr_put_strz(nlh, NFTA_SET_TABLE, h->table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &h->set.location); ++ cmd_add_loc(cmd, nlh, &h->set.location); + mnl_attr_put_strz(nlh, NFTA_SET_NAME, h->set.name); + + nftnl_set_nlmsg_build_payload(nlh, nls); +@@ -1359,13 +1359,13 @@ int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd) + h->family, + 0, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_SET_TABLE, cmd->handle.table.name); + if (h->set.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.set.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.set.location); + mnl_attr_put_strz(nlh, NFTA_SET_NAME, cmd->handle.set.name); + } else if (h->handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.handle.location); + mnl_attr_put_u64(nlh, NFTA_SET_HANDLE, + htobe64(cmd->handle.handle.id)); + } +@@ -1544,9 +1544,9 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd, + NFT_MSG_NEWOBJ, cmd->handle.family, + NLM_F_CREATE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.obj.location); + mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name); + + nftnl_obj_nlmsg_build_payload(nlh, nlo); +@@ -1577,14 +1577,14 @@ int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type) + msg_type, cmd->handle.family, + 0, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name); + + if (cmd->handle.obj.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.obj.location); + mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name); + } else if (cmd->handle.handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.handle.location); + mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE, + htobe64(cmd->handle.handle.id)); + } +@@ -1764,7 +1764,7 @@ next: + list_for_each_entry_from(expr, &set->expressions, list) { + nlse = alloc_nftnl_setelem(set, expr); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &expr->location); ++ cmd_add_loc(cmd, nlh, &expr->location); + nest2 = mnl_attr_nest_start(nlh, ++i); + nftnl_set_elem_nlmsg_build_payload(nlh, nlse); + mnl_attr_nest_end(nlh, nest2); +@@ -2005,7 +2005,7 @@ static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd) + dev_array = nft_dev_array(dev_expr, &num_devs); + nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS); + for (i = 0; i < num_devs; i++) { +- cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location); ++ cmd_add_loc(cmd, nlh, dev_array[i].location); + mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname); + } + +@@ -2037,9 +2037,9 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd, + NFT_MSG_NEWFLOWTABLE, cmd->handle.family, + NLM_F_CREATE | flags, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name); +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.flowtable.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.flowtable.location); + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, cmd->handle.flowtable.name); + + nftnl_flowtable_nlmsg_build_payload(nlh, flo); +@@ -2086,16 +2086,15 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd) + msg_type, cmd->handle.family, + 0, ctx->seqnum); + +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.table.location); + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name); + + if (cmd->handle.flowtable.name) { +- cmd_add_loc(cmd, nlh->nlmsg_len, +- &cmd->handle.flowtable.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.flowtable.location); + mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, + cmd->handle.flowtable.name); + } else if (cmd->handle.handle.id) { +- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location); ++ cmd_add_loc(cmd, nlh, &cmd->handle.handle.location); + mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE, + htobe64(cmd->handle.handle.id)); + } diff --git a/0006-rule-netlink-attribute-offset-is-uint32_t-for-struct.patch b/0006-rule-netlink-attribute-offset-is-uint32_t-for-struct.patch new file mode 100644 index 0000000..a3f5fe1 --- /dev/null +++ b/0006-rule-netlink-attribute-offset-is-uint32_t-for-struct.patch @@ -0,0 +1,58 @@ +From 66dc95d7a3f7c0e4527f4e960f5c397fd3b82af5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] rule: netlink attribute offset is uint32_t for struct + nlerr_loc + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 42b081df747729b0d83b69d2816be4091af56a58 + +commit 42b081df747729b0d83b69d2816be4091af56a58 +Author: Pablo Neira Ayuso +Date: Thu Oct 24 00:08:24 2024 +0200 + + rule: netlink attribute offset is uint32_t for struct nlerr_loc + + The maximum netlink message length (nlh->nlmsg_len) is uint32_t, struct + nlerr_loc stores the offset to the netlink attribute which must be + uint32_t, not uint16_t. + + While at it, remove check for zero netlink attribute offset in + nft_cmd_error() which should not ever happen, likely this check was + there to prevent the uint16_t offset overflow. + + Fixes: f8aec603aa7e ("src: initial extended netlink error reporting") + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/rule.h | 2 +- + src/cmd.c | 2 -- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/include/rule.h b/include/rule.h +index a1628d8..3fcfa44 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -695,7 +695,7 @@ void monitor_free(struct monitor *m); + #define NFT_NLATTR_LOC_MAX 32 + + struct nlerr_loc { +- uint16_t offset; ++ uint32_t offset; + const struct location *location; + }; + +diff --git a/src/cmd.c b/src/cmd.c +index 78a2aa3..0c7a43e 100644 +--- a/src/cmd.c ++++ b/src/cmd.c +@@ -323,8 +323,6 @@ void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd, + uint32_t i; + + for (i = 0; i < cmd->num_attrs; i++) { +- if (!cmd->attr[i].offset) +- break; + if (cmd->attr[i].offset == err->offset) + loc = cmd->attr[i].location; + } diff --git a/0007-src-fix-extended-netlink-error-reporting-with-large-.patch b/0007-src-fix-extended-netlink-error-reporting-with-large-.patch new file mode 100644 index 0000000..2d7a413 --- /dev/null +++ b/0007-src-fix-extended-netlink-error-reporting-with-large-.patch @@ -0,0 +1,193 @@ +From c62c11ee27daf90c74a46353df4936b869624e72 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] src: fix extended netlink error reporting with large set + elements + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 68d2de3ca6c6eb18f5b32f7b4324a85c9c6c358e + +commit 68d2de3ca6c6eb18f5b32f7b4324a85c9c6c358e +Author: Pablo Neira Ayuso +Date: Thu Oct 24 00:24:55 2024 +0200 + + src: fix extended netlink error reporting with large set elements + + Large sets can expand into several netlink messages, use sequence number + and attribute offset to correlate the set element and the location. + + When set element command expands into several netlink messages, + increment sequence number for each netlink message. Update struct cmd to + store the range of netlink messages that result from this command. + + struct nlerr_loc remains in the same size in x86_64. + + # nft -f set-65535.nft + set-65535.nft:65029:22-32: Error: Could not process rule: File exists + create element x y { 1.1.254.253 } + ^^^^^^^^^^^ + + Fixes: f8aec603aa7e ("src: initial extended netlink error reporting") + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/rule.h | 4 +++- + src/cmd.c | 4 +++- + src/libnftables.c | 12 ++++++++---- + src/mnl.c | 9 +++++---- + src/parser_json.c | 4 ++-- + 5 files changed, 21 insertions(+), 12 deletions(-) + +diff --git a/include/rule.h b/include/rule.h +index 3fcfa44..48e148e 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -695,6 +695,7 @@ void monitor_free(struct monitor *m); + #define NFT_NLATTR_LOC_MAX 32 + + struct nlerr_loc { ++ uint32_t seqnum; + uint32_t offset; + const struct location *location; + }; +@@ -717,7 +718,8 @@ struct cmd { + enum cmd_ops op; + enum cmd_obj obj; + struct handle handle; +- uint32_t seqnum; ++ uint32_t seqnum_from; ++ uint32_t seqnum_to; + union { + void *data; + struct expr *expr; +diff --git a/src/cmd.c b/src/cmd.c +index 0c7a43e..eb44b98 100644 +--- a/src/cmd.c ++++ b/src/cmd.c +@@ -24,6 +24,7 @@ void cmd_add_loc(struct cmd *cmd, const struct nlmsghdr *nlh, const struct locat + cmd->attr = xrealloc(cmd->attr, sizeof(struct nlerr_loc) * cmd->attr_array_len); + } + ++ cmd->attr[cmd->num_attrs].seqnum = nlh->nlmsg_seq; + cmd->attr[cmd->num_attrs].offset = nlh->nlmsg_len; + cmd->attr[cmd->num_attrs].location = loc; + cmd->num_attrs++; +@@ -323,7 +324,8 @@ void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd, + uint32_t i; + + for (i = 0; i < cmd->num_attrs; i++) { +- if (cmd->attr[i].offset == err->offset) ++ if (cmd->attr[i].seqnum == err->seqnum && ++ cmd->attr[i].offset == err->offset) + loc = cmd->attr[i].location; + } + +diff --git a/src/libnftables.c b/src/libnftables.c +index 3550961..1df22b3 100644 +--- a/src/libnftables.c ++++ b/src/libnftables.c +@@ -39,7 +39,7 @@ static int nft_netlink(struct nft_ctx *nft, + + batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_inc(&seqnum)); + list_for_each_entry(cmd, cmds, list) { +- ctx.seqnum = cmd->seqnum = mnl_seqnum_inc(&seqnum); ++ ctx.seqnum = cmd->seqnum_from = mnl_seqnum_inc(&seqnum); + ret = do_command(&ctx, cmd); + if (ret < 0) { + netlink_io_error(&ctx, &cmd->location, +@@ -47,6 +47,8 @@ static int nft_netlink(struct nft_ctx *nft, + strerror(errno)); + goto out; + } ++ seqnum = cmd->seqnum_to = ctx.seqnum; ++ mnl_seqnum_inc(&seqnum); + num_cmds++; + } + if (!nft->check) +@@ -80,12 +82,14 @@ static int nft_netlink(struct nft_ctx *nft, + cmd = list_first_entry(cmds, struct cmd, list); + + list_for_each_entry_from(cmd, cmds, list) { +- last_seqnum = cmd->seqnum; +- if (err->seqnum == cmd->seqnum || ++ last_seqnum = cmd->seqnum_to; ++ if ((err->seqnum >= cmd->seqnum_from && ++ err->seqnum <= cmd->seqnum_to) || + err->seqnum == batch_seqnum) { + nft_cmd_error(&ctx, cmd, err); + errno = err->err; +- if (err->seqnum == cmd->seqnum) { ++ if (err->seqnum >= cmd->seqnum_from || ++ err->seqnum <= cmd->seqnum_to) { + mnl_err_list_free(err); + break; + } +diff --git a/src/mnl.c b/src/mnl.c +index 42d1b0d..12a6345 100644 +--- a/src/mnl.c ++++ b/src/mnl.c +@@ -1722,7 +1722,7 @@ static void netlink_dump_setelem_done(struct netlink_ctx *ctx) + static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd, + struct nftnl_batch *batch, + enum nf_tables_msg_types msg_type, +- unsigned int flags, uint32_t seqnum, ++ unsigned int flags, uint32_t *seqnum, + const struct expr *set, + struct netlink_ctx *ctx) + { +@@ -1741,7 +1741,7 @@ static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd, + next: + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), msg_type, + nftnl_set_get_u32(nls, NFTNL_SET_FAMILY), +- flags, seqnum); ++ flags, *seqnum); + + if (nftnl_set_is_set(nls, NFTNL_SET_TABLE)) { + mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE, +@@ -1774,6 +1774,7 @@ next: + if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) { + mnl_attr_nest_end(nlh, nest1); + mnl_nft_batch_continue(batch); ++ mnl_seqnum_inc(seqnum); + goto next; + } + } +@@ -1808,7 +1809,7 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, struct cmd *cmd, + netlink_dump_set(nls, ctx); + + err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, NFT_MSG_NEWSETELEM, +- flags, ctx->seqnum, expr, ctx); ++ flags, &ctx->seqnum, expr, ctx); + nftnl_set_free(nls); + + return err; +@@ -1868,7 +1869,7 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, struct cmd *cmd, + msg_type = NFT_MSG_DESTROYSETELEM; + + err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, msg_type, 0, +- ctx->seqnum, init, ctx); ++ &ctx->seqnum, init, ctx); + nftnl_set_free(nls); + + return err; +diff --git a/src/parser_json.c b/src/parser_json.c +index bbe3b1c..37ec34c 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -4269,13 +4269,13 @@ static json_t *seqnum_to_json(const uint32_t seqnum) + cur = json_cmd_assoc_list; + json_cmd_assoc_list = cur->next; + +- key = cur->cmd->seqnum % CMD_ASSOC_HSIZE; ++ key = cur->cmd->seqnum_from % CMD_ASSOC_HSIZE; + hlist_add_head(&cur->hnode, &json_cmd_assoc_hash[key]); + } + + key = seqnum % CMD_ASSOC_HSIZE; + hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) { +- if (cur->cmd->seqnum == seqnum) ++ if (cur->cmd->seqnum_from == seqnum) + return cur->json; + } + diff --git a/0008-tests-monitor-fix-up-test-case-breakage.patch b/0008-tests-monitor-fix-up-test-case-breakage.patch new file mode 100644 index 0000000..74272ef --- /dev/null +++ b/0008-tests-monitor-fix-up-test-case-breakage.patch @@ -0,0 +1,62 @@ +From 42ba69f76beabde5f22a8616469fb296ac72e16e Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] tests: monitor: fix up test case breakage + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit c416416b03d804663c5f7a738a3e1449eeb28157 + +commit c416416b03d804663c5f7a738a3e1449eeb28157 +Author: Florian Westphal +Date: Tue Oct 29 21:12:19 2024 +0100 + + tests: monitor: fix up test case breakage + + Monitor test fails: + + echo: running tests from file set-simple.t + echo output differs! + -add element ip t portrange { 1024-65535 } + add element ip t portrange { 100-200 } + +add element ip t portrange { 1024-65535 } + +# new generation 510 by process 129009 (nft) + + I also noticed -j mode did not work correctly, add missing json annotations + in set-concat-interval.t while at it. + + Signed-off-by: Florian Westphal + +Signed-off-by: Phil Sutter +--- + tests/monitor/testcases/set-concat-interval.t | 3 +++ + tests/monitor/testcases/set-simple.t | 5 +++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tests/monitor/testcases/set-concat-interval.t b/tests/monitor/testcases/set-concat-interval.t +index 763dc31..75f3828 100644 +--- a/tests/monitor/testcases/set-concat-interval.t ++++ b/tests/monitor/testcases/set-concat-interval.t +@@ -10,3 +10,6 @@ I add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; elem + O add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; } + O add element ip t s { 20-80 . 0x14 : accept } + O add element ip t s { 1-10 . 0xa : drop } ++J {"add": {"map": {"family": "ip", "name": "s", "table": "t", "type": ["integer", "integer"], "handle": 0, "map": "verdict", "flags": ["interval"]}}} ++J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [[{"concat": [{"range": [20, 80]}, 20]}, {"accept": null}]]}}}} ++J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [[{"concat": [{"range": [1, 10]}, 10]}, {"drop": null}]]}}}} +diff --git a/tests/monitor/testcases/set-simple.t b/tests/monitor/testcases/set-simple.t +index 8ca4f32..6853a0e 100644 +--- a/tests/monitor/testcases/set-simple.t ++++ b/tests/monitor/testcases/set-simple.t +@@ -37,9 +37,10 @@ J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem" + # make sure half open before other element works + I add element ip t portrange { 1024-65535 } + I add element ip t portrange { 100-200 } +-O - +-J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}} ++O add element ip t portrange { 100-200 } ++O add element ip t portrange { 1024-65535 } + J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [100, 200]}]}}}} ++J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}} + + # make sure deletion of elements works + I delete element ip t portrange { 0-10 } diff --git a/0009-doc-extend-description-of-fib-expression.patch b/0009-doc-extend-description-of-fib-expression.patch new file mode 100644 index 0000000..b1e2689 --- /dev/null +++ b/0009-doc-extend-description-of-fib-expression.patch @@ -0,0 +1,142 @@ +From 86deb09d9886a9ef9c089a6edc0859419e8b4dfd Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:45 +0100 +Subject: [PATCH] doc: extend description of fib expression + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit be4b61c05a2491aad596aa9243b17b13c937b347 + +commit be4b61c05a2491aad596aa9243b17b13c937b347 +Author: Florian Westphal +Date: Thu Oct 10 15:37:42 2024 +0200 + + doc: extend description of fib expression + + Describe the input keys and the result types. + Mention which input keys are mandatory and which keys are mutually + exclusive. + + Describe which hooks can be used with the various lookup modifiers + and extend the examples with more information on fib expression + capabilities. + + Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1663 + Signed-off-by: Florian Westphal + Reviewed-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + doc/primary-expression.txt | 77 +++++++++++++++++++++++++++++++------- + 1 file changed, 63 insertions(+), 14 deletions(-) + +diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt +index 782494b..c6a33bb 100644 +--- a/doc/primary-expression.txt ++++ b/doc/primary-expression.txt +@@ -310,17 +310,48 @@ table inet x { + FIB EXPRESSIONS + ~~~~~~~~~~~~~~~ + [verse] +-*fib* {*saddr* | *daddr* | *mark* | *iif* | *oif*} [*.* ...] {*oif* | *oifname* | *type*} ++*fib* 'FIB_TUPLE' 'FIB_RESULT' ++'FIB_TUPLE' := { *saddr* | *daddr*} [ *.* { *iif* | *oif* } *.* *mark* ] ++'FIB_RESULT' := { *oif* | *oifname* | *type* } + +-A fib expression queries the fib (forwarding information base) to obtain +-information such as the output interface index a particular address would use. +-The input is a tuple of elements that is used as input to the fib lookup +-functions. + +-.fib expression specific types ++A fib expression queries the fib (forwarding information base) to obtain information ++such as the output interface index. ++ ++The first arguments to the *fib* expression are the input keys to be passed to the fib lookup function. ++One of *saddr* or *daddr* is mandatory, they are also mutually exclusive. ++ ++*mark*, *iif* and *oif* keywords are optional modifiers to influence the search result, see ++the *FIB_TUPLE* keyword table below for a description. ++The *iif* and *oif* tuple keywords are also mutually exclusive. ++ ++The last argument to the *fib* expression is the desired result type. ++ ++*oif* asks to obtain the interface index that would be used to send packets to the packets source ++(*saddr* key) or destination (*daddr* key). If no routing entry is found, the returned interface ++index is 0. ++ ++*oifname* is like *oif*, but it fills the interface name instead. This is useful to check dynamic ++interfaces such as ppp devices. If no entry is found, an empty interface name is returned. ++ ++*type* returns the address type such as unicast or multicast. A complete list of supported ++address types can be shown with *nft* *describe* *fib_addrtype*. ++ ++.FIB_TUPLE keywords + [options="header"] + |================== +-|Keyword| Description| Type ++|flag| Description ++|daddr| Perform a normal route lookup: search fib for route to the *destination address* of the packet. ++|saddr| Perform a reverse route lookup: search the fib for route to the *source address* of the packet. ++|mark | consider the packet mark (nfmark) when querying the fib. ++|iif | if fib lookups provides a route then check its output interface is identical to the packets *input* interface. ++|oif | if fib lookups provides a route then check its output interface is identical to the packets *output* interface. This flag can only be used with the *type* result. ++|======================= ++ ++.FIB_RESULT keywords ++[options="header"] ++|================== ++|Keyword| Description| Result Type + |oif| + Output interface index| + integer (32 bit) +@@ -329,25 +360,43 @@ Output interface name| + string + |type| + Address type | +-fib_addrtype ++fib_addrtype (see *nft* *describe* *fib_addrtype* for a list) + |======================= + +-Use *nft* *describe* *fib_addrtype* to get a list of all address types. ++The *oif* and *oifname* result is only valid in the *prerouting*, *input* and *forward* hooks. ++The *type* can be queried from any one of *prerouting*, *input*, *forward* *output* and *postrouting*. ++ ++For *type*, the presence of the *iif* keyword in the 'FIB_TUPLE' modifiers restrict the available ++hooks to those where the packet is associated with an incoming interface, i.e. *prerouting*, *input* and *forward*. ++Likewise, the *oif* keyword in the 'FIB_TUPLE' modifier list will limit the available hooks to ++*forward*, *output* and *postrouting*. + + .Using fib expressions + ---------------------- + # drop packets without a reverse path + filter prerouting fib saddr . iif oif missing drop + +-In this example, 'saddr . iif' looks up routing information based on the source address and the input interface. +-oif picks the output interface index from the routing information. ++In this example, 'saddr . iif' looks up a route to the *source address* of the packet and restricts matching ++results to the interface that the packet arrived on, then stores the output interface index from the obtained ++fib route result. ++ + If no route was found for the source address/input interface combination, the output interface index is zero. +-In case the input interface is specified as part of the input key, the output interface index is always the same as the input interface index or zero. +-If only 'saddr oif' is given, then oif can be any interface index or zero. ++Hence, this rule will drop all packets that do not have a strict reverse path (hypothetical reply packet ++would be sent via the interface the tested packet arrived on). ++ ++If only 'saddr oif' is used as the input key, then this rule would only drop packets where the fib cannot ++find a route. In most setups this will never drop packets because the default route is returned. + +-# drop packets to address not configured on incoming interface ++# drop packets if the destination ip address is not configured on the incoming interface + filter prerouting fib daddr . iif type != { local, broadcast, multicast } drop + ++This queries the fib based on the current packets' destination address and the incoming interface. ++ ++If the packet is sent to a unicast address that is configured on a different interface, then the packet ++will be dropped as such an address would be classified as 'unicast' type. ++Without the 'iif' modifier, any address configured on the local machine is 'local', and unicast addresses ++not configured on any interface would return the type 'unicast'. ++ + # perform lookup in a specific 'blackhole' table (0xdead, needs ip appropriate ip rule) + filter prerouting meta mark set 0xdead fib daddr . mark type vmap { blackhole : drop, prohibit : jump prohibited, unreachable : drop } + ---------------------- diff --git a/0010-json-collapse-set-element-commands-from-parser.patch b/0010-json-collapse-set-element-commands-from-parser.patch new file mode 100644 index 0000000..ca21fc0 --- /dev/null +++ b/0010-json-collapse-set-element-commands-from-parser.patch @@ -0,0 +1,83 @@ +From 21295af879d5cc6a41bd823e708a97684034ed1e Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:46 +0100 +Subject: [PATCH] json: collapse set element commands from parser + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 193faa5475a5df7d9ac0b1a8fe647196de3e5688 + +commit 193faa5475a5df7d9ac0b1a8fe647196de3e5688 +Author: Pablo Neira Ayuso +Date: Thu Oct 31 21:38:02 2024 +0100 + + json: collapse set element commands from parser + + Update json parser to collapse {add,create} element commands to reduce + memory consumption in the case of large sets defined by one element per + command: + + {"nftables": [{"add": {"element": {"family": "ip", "table": "x", "name": + "y", "elem": [{"set": ["1.1.0.0"]}]}}},...]} + + Add CTX_F_COLLAPSED flag to report that command has been collapsed. + + This patch reduces memory consumption by ~32% this case. + + Fixes: 20f1c60ac8c8 ("src: collapse set element commands from parser") + Reported-by: Eric Garver + Tested-by: Eric Garver + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + src/parser_json.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/parser_json.c b/src/parser_json.c +index 37ec34c..68c0600 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -49,6 +50,7 @@ + #define CTX_F_SES (1 << 6) /* set_elem_expr_stmt */ + #define CTX_F_MAP (1 << 7) /* LHS of map_expr */ + #define CTX_F_CONCAT (1 << 8) /* inside concat_expr */ ++#define CTX_F_COLLAPSED (1 << 9) + + struct json_ctx { + struct nft_ctx *nft; +@@ -3490,6 +3492,15 @@ static struct cmd *json_parse_cmd_add_element(struct json_ctx *ctx, + handle_free(&h); + return NULL; + } ++ ++ if ((op == CMD_CREATE || op == CMD_ADD) && ++ nft_cmd_collapse_elems(op, ctx->cmds, &h, expr)) { ++ handle_free(&h); ++ expr_free(expr); ++ ctx->flags |= CTX_F_COLLAPSED; ++ return NULL; ++ } ++ + return cmd_alloc(op, cmd_obj, &h, int_loc, expr); + } + +@@ -4319,6 +4330,11 @@ static int __json_parse(struct json_ctx *ctx) + cmd = json_parse_cmd(ctx, value); + + if (!cmd) { ++ if (ctx->flags & CTX_F_COLLAPSED) { ++ ctx->flags &= ~CTX_F_COLLAPSED; ++ continue; ++ } ++ + json_error(ctx, "Parsing command array at index %zd failed.", index); + return -1; + } diff --git a/0011-json-Support-typeof-in-set-and-map-types.patch b/0011-json-Support-typeof-in-set-and-map-types.patch new file mode 100644 index 0000000..2345b6a --- /dev/null +++ b/0011-json-Support-typeof-in-set-and-map-types.patch @@ -0,0 +1,526 @@ +From d66b043a46f4b8e48ab96503613d4ea7483899d4 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:46 +0100 +Subject: [PATCH] json: Support typeof in set and map types + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit bb6312484af93a83a9ec8716f3887a43566a775a + +commit bb6312484af93a83a9ec8716f3887a43566a775a +Author: Phil Sutter +Date: Sat Sep 28 00:55:34 2024 +0200 + + json: Support typeof in set and map types + + Implement this as a special "type" property value which is an object + with sole property "typeof". The latter's value is the JSON + representation of the expression in set->key, so for concatenated + typeofs it is a concat expression. + + All this is a bit clumsy right now but it works and it should be + possible to tear it down a bit for more user-friendliness in a + compatible way by either replacing the concat expression by the array it + contains or even the whole "typeof" object - the parser would just + assume any object (or objects in an array) in the "type" property value + are expressions to extract a type from. + + Signed-off-by: Phil Sutter + +Signed-off-by: Phil Sutter +--- + doc/libnftables-json.adoc | 7 ++- + src/json.c | 13 ++++- + src/parser_json.c | 9 +++ + tests/monitor/testcases/map-expr.t | 2 +- + tests/monitor/testcases/set-concat-interval.t | 2 +- + .../maps/dumps/0012map_concat_0.json-nft | 21 +++++-- + .../maps/dumps/0017_map_variable_0.json-nft | 18 +++++- + .../maps/dumps/named_limits.json-nft | 55 ++++++++++++++++--- + .../dumps/typeof_maps_add_delete.json-nft | 9 ++- + .../maps/dumps/typeof_maps_update_0.json-nft | 9 ++- + .../maps/dumps/vmap_timeout.json-nft | 22 ++++++-- + .../packetpath/dumps/set_lookups.json-nft | 42 +++++++++++--- + .../sets/dumps/0048set_counters_0.json-nft | 9 ++- + .../testcases/sets/dumps/inner_0.json-nft | 34 ++++++++++-- + .../set_element_timeout_updates.json-nft | 9 ++- + 15 files changed, 220 insertions(+), 41 deletions(-) + +diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc +index 2f29ac0..244eb41 100644 +--- a/doc/libnftables-json.adoc ++++ b/doc/libnftables-json.adoc +@@ -341,7 +341,7 @@ ____ + "auto-merge":* 'BOOLEAN' + *}}* + +-'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]* ++'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]* | *{ "typeof":* 'EXPRESSION' *}* + 'SET_TYPE_LIST' := 'STRING' [*,* 'SET_TYPE_LIST' ] + 'SET_POLICY' := *"performance"* | *"memory"* + 'SET_FLAG_LIST' := 'SET_FLAG' [*,* 'SET_FLAG_LIST' ] +@@ -381,8 +381,9 @@ that they translate a unique key to a value. + Automatic merging of adjacent/overlapping set elements in interval sets. + + ==== TYPE +-The set type might be a string, such as *"ipv4_addr"* or an array +-consisting of strings (for concatenated types). ++The set type might be a string, such as *"ipv4_addr"*, an array ++consisting of strings (for concatenated types) or a *typeof* object containing ++an expression to extract the type from. + + ==== ELEM + A single set element might be given as string, integer or boolean value for +diff --git a/src/json.c b/src/json.c +index b1531ff..1f609bf 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -96,6 +96,17 @@ static json_t *set_dtype_json(const struct expr *key) + return root; + } + ++static json_t *set_key_dtype_json(const struct set *set, ++ struct output_ctx *octx) ++{ ++ bool use_typeof = set->key_typeof_valid; ++ ++ if (!use_typeof) ++ return set_dtype_json(set->key); ++ ++ return json_pack("{s:o}", "typeof", expr_print_json(set->key, octx)); ++} ++ + static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx) + { + char buf[1024]; +@@ -158,7 +169,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set) + "family", family2str(set->handle.family), + "name", set->handle.set.name, + "table", set->handle.table.name, +- "type", set_dtype_json(set->key), ++ "type", set_key_dtype_json(set, octx), + "handle", set->handle.handle.id); + + if (set->comment) +diff --git a/src/parser_json.c b/src/parser_json.c +index 68c0600..02cfcd6 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -1731,7 +1731,16 @@ static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root) + compound_expr_add(expr, i); + } + return expr; ++ } else if (json_is_object(root)) { ++ const char *key; ++ json_t *val; ++ ++ if (!json_unpack_stmt(ctx, root, &key, &val) && ++ !strcmp(key, "typeof")) { ++ return json_parse_expr(ctx, val); ++ } + } ++ + json_error(ctx, "Invalid set datatype."); + return NULL; + } +diff --git a/tests/monitor/testcases/map-expr.t b/tests/monitor/testcases/map-expr.t +index 8729c0b..d11ad0e 100644 +--- a/tests/monitor/testcases/map-expr.t ++++ b/tests/monitor/testcases/map-expr.t +@@ -3,4 +3,4 @@ I add table ip t + I add map ip t m { typeof meta day . meta hour : verdict; flags interval; counter; } + O - + J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}} +-J {"add": {"map": {"family": "ip", "name": "m", "table": "t", "type": ["day", "hour"], "handle": 0, "map": "verdict", "flags": ["interval"], "stmt": [{"counter": null}]}}} ++J {"add": {"map": {"family": "ip", "name": "m", "table": "t", "type": {"typeof": {"concat": [{"meta": {"key": "day"}}, {"meta": {"key": "hour"}}]}}, "handle": 0, "map": "verdict", "flags": ["interval"], "stmt": [{"counter": null}]}}} +diff --git a/tests/monitor/testcases/set-concat-interval.t b/tests/monitor/testcases/set-concat-interval.t +index 75f3828..3542b82 100644 +--- a/tests/monitor/testcases/set-concat-interval.t ++++ b/tests/monitor/testcases/set-concat-interval.t +@@ -10,6 +10,6 @@ I add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; elem + O add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; } + O add element ip t s { 20-80 . 0x14 : accept } + O add element ip t s { 1-10 . 0xa : drop } +-J {"add": {"map": {"family": "ip", "name": "s", "table": "t", "type": ["integer", "integer"], "handle": 0, "map": "verdict", "flags": ["interval"]}}} ++J {"add": {"map": {"family": "ip", "name": "s", "table": "t", "type": {"typeof": {"concat": [{"payload": {"protocol": "udp", "field": "length"}}, {"payload": {"base": "ih", "offset": 32, "len": 32}}]}}, "handle": 0, "map": "verdict", "flags": ["interval"]}}} + J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [[{"concat": [{"range": [20, 80]}, 20]}, {"accept": null}]]}}}} + J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [[{"concat": [{"range": [1, 10]}, 10]}, {"drop": null}]]}}}} +diff --git a/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft +index 0005223..88bf498 100644 +--- a/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft ++++ b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft +@@ -31,10 +31,23 @@ + "family": "ip", + "name": "w", + "table": "x", +- "type": [ +- "ipv4_addr", +- "mark" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ }, ++ { ++ "meta": { ++ "key": "mark" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "map": "verdict", + "flags": [ +diff --git a/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft b/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft +index 725498c..8eacf61 100644 +--- a/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft ++++ b/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft +@@ -19,7 +19,14 @@ + "family": "ip", + "name": "y", + "table": "x", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "map": "mark", + "elem": [ +@@ -39,7 +46,14 @@ + "family": "ip", + "name": "z", + "table": "x", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "map": "mark", + "elem": [ +diff --git a/tests/shell/testcases/maps/dumps/named_limits.json-nft b/tests/shell/testcases/maps/dumps/named_limits.json-nft +index 7fa1298..3c6845a 100644 +--- a/tests/shell/testcases/maps/dumps/named_limits.json-nft ++++ b/tests/shell/testcases/maps/dumps/named_limits.json-nft +@@ -75,7 +75,14 @@ + "family": "inet", + "name": "tarpit4", + "table": "filter", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "size": 10000, + "flags": [ +@@ -90,7 +97,14 @@ + "family": "inet", + "name": "tarpit6", + "table": "filter", +- "type": "ipv6_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip6", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "size": 10000, + "flags": [ +@@ -105,11 +119,29 @@ + "family": "inet", + "name": "addr4limit", + "table": "filter", +- "type": [ +- "inet_proto", +- "ipv4_addr", +- "inet_service" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "meta": { ++ "key": "l4proto" ++ } ++ }, ++ { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ }, ++ { ++ "payload": { ++ "protocol": "tcp", ++ "field": "sport" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "map": "limit", + "flags": [ +@@ -244,7 +276,14 @@ + "family": "inet", + "name": "saddr6limit", + "table": "filter", +- "type": "ipv6_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip6", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "map": "limit", + "flags": [ +diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft +index b3204a2..effe02d 100644 +--- a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft ++++ b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft +@@ -39,7 +39,14 @@ + "family": "ip", + "name": "dynmark", + "table": "dynset", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "daddr" ++ } ++ } ++ }, + "handle": 0, + "map": "mark", + "size": 64, +diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft +index 1d50477..7315146 100644 +--- a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft ++++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft +@@ -50,7 +50,14 @@ + "family": "ip", + "name": "sticky-set-svc-153CN2XYVUHRQ7UB", + "table": "kube-nfproxy-v4", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "daddr" ++ } ++ } ++ }, + "handle": 0, + "map": "mark", + "size": 65535, +diff --git a/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft +index 1c3aa59..71e9a9e 100644 +--- a/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft ++++ b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft +@@ -87,10 +87,24 @@ + "family": "inet", + "name": "portaddrmap", + "table": "filter", +- "type": [ +- "ipv4_addr", +- "inet_service" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "payload": { ++ "protocol": "ip", ++ "field": "daddr" ++ } ++ }, ++ { ++ "payload": { ++ "protocol": "th", ++ "field": "dport" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "map": "verdict", + "flags": [ +diff --git a/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft +index 24363f9..bcf6914 100644 +--- a/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft ++++ b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft +@@ -60,10 +60,23 @@ + "family": "ip", + "name": "s2", + "table": "t", +- "type": [ +- "ipv4_addr", +- "iface_index" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ }, ++ { ++ "meta": { ++ "key": "iif" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "elem": [ + { +@@ -113,10 +126,23 @@ + "family": "ip", + "name": "nomatch", + "table": "t", +- "type": [ +- "ipv4_addr", +- "iface_index" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ }, ++ { ++ "meta": { ++ "key": "iif" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "elem": [ + { +diff --git a/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft b/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft +index 62a6a17..4be4112 100644 +--- a/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft ++++ b/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft +@@ -31,7 +31,14 @@ + "family": "ip", + "name": "y", + "table": "x", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "elem": [ + { +diff --git a/tests/shell/testcases/sets/dumps/inner_0.json-nft b/tests/shell/testcases/sets/dumps/inner_0.json-nft +index 8d84e1c..e5dc198 100644 +--- a/tests/shell/testcases/sets/dumps/inner_0.json-nft ++++ b/tests/shell/testcases/sets/dumps/inner_0.json-nft +@@ -27,10 +27,26 @@ + "family": "netdev", + "name": "x", + "table": "x", +- "type": [ +- "ipv4_addr", +- "ipv4_addr" +- ], ++ "type": { ++ "typeof": { ++ "concat": [ ++ { ++ "payload": { ++ "tunnel": "vxlan", ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ }, ++ { ++ "payload": { ++ "tunnel": "vxlan", ++ "protocol": "ip", ++ "field": "daddr" ++ } ++ } ++ ] ++ } ++ }, + "handle": 0, + "elem": [ + { +@@ -47,7 +63,15 @@ + "family": "netdev", + "name": "y", + "table": "x", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "tunnel": "vxlan", ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "size": 65535, + "flags": [ +diff --git a/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft b/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft +index aa90829..d92d8d7 100644 +--- a/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft ++++ b/tests/shell/testcases/sets/dumps/set_element_timeout_updates.json-nft +@@ -31,7 +31,14 @@ + "family": "ip", + "name": "s", + "table": "t", +- "type": "ipv4_addr", ++ "type": { ++ "typeof": { ++ "payload": { ++ "protocol": "ip", ++ "field": "saddr" ++ } ++ } ++ }, + "handle": 0, + "flags": [ + "timeout" diff --git a/0012-tests-py-Fix-for-storing-payload-into-missing-file.patch b/0012-tests-py-Fix-for-storing-payload-into-missing-file.patch new file mode 100644 index 0000000..504ae68 --- /dev/null +++ b/0012-tests-py-Fix-for-storing-payload-into-missing-file.patch @@ -0,0 +1,43 @@ +From 6c31db6766df3bdeb1ff6039e651a54850b68aa3 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:46 +0100 +Subject: [PATCH] tests: py: Fix for storing payload into missing file + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit c1c0c54e237c880adaa8172b93d7450e6c617cfc + +commit c1c0c54e237c880adaa8172b93d7450e6c617cfc +Author: Phil Sutter +Date: Wed Oct 2 19:55:49 2024 +0200 + + tests: py: Fix for storing payload into missing file + + When running a test for which no corresponding *.payload file exists, + the *.payload.got file name was incorrectly constructed due to + 'payload_path' variable not being set. + + Fixes: 2cfab7a3e10fc ("tests/py: Write dissenting payload into the right file") + Signed-off-by: Phil Sutter + +Signed-off-by: Phil Sutter +--- + tests/py/nft-test.py | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/tests/py/nft-test.py b/tests/py/nft-test.py +index 00799e2..7acdb77 100755 +--- a/tests/py/nft-test.py ++++ b/tests/py/nft-test.py +@@ -769,10 +769,9 @@ def rule_add(rule, filename, lineno, force_all_family_option, filename_path): + + if rule[1].strip() == "ok": + payload_expected = None +- payload_path = None ++ payload_path = "%s.payload" % filename_path + try: +- payload_log = open("%s.payload" % filename_path) +- payload_path = payload_log.name ++ payload_log = open(payload_path) + payload_expected = payload_find_expected(payload_log, rule[0]) + except: + payload_log = None diff --git a/0013-monitor-Recognize-flowtable-add-del-events.patch b/0013-monitor-Recognize-flowtable-add-del-events.patch new file mode 100644 index 0000000..ee74367 --- /dev/null +++ b/0013-monitor-Recognize-flowtable-add-del-events.patch @@ -0,0 +1,260 @@ +From 8cfbb8c3427f232484bacab3116f6925f3976c7b Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 7 Nov 2024 18:38:46 +0100 +Subject: [PATCH] monitor: Recognize flowtable add/del events + +JIRA: https://issues.redhat.com/browse/RHEL-65346 +Upstream Status: nftables commit 73a8adfc2432ec8337288cc90e7c9f4509139846 + +commit 73a8adfc2432ec8337288cc90e7c9f4509139846 +Author: Phil Sutter +Date: Wed May 15 16:01:20 2024 +0200 + + monitor: Recognize flowtable add/del events + + These were entirely ignored before, add the necessary code analogous to + e.g. objects. + + Signed-off-by: Phil Sutter + +Signed-off-by: Phil Sutter +--- + include/json.h | 10 ++++ + include/netlink.h | 1 + + include/rule.h | 1 + + src/json.c | 6 +++ + src/monitor.c | 61 ++++++++++++++++++++++ + src/parser_json.c | 6 +++ + src/rule.c | 15 ++++++ + tests/monitor/testcases/flowtable-simple.t | 10 ++++ + 8 files changed, 110 insertions(+) + create mode 100644 tests/monitor/testcases/flowtable-simple.t + +diff --git a/include/json.h b/include/json.h +index 39be892..0670b87 100644 +--- a/include/json.h ++++ b/include/json.h +@@ -11,6 +11,7 @@ struct nlmsghdr; + struct rule; + struct set; + struct obj; ++struct flowtable; + struct stmt; + struct symbol_table; + struct table; +@@ -113,6 +114,8 @@ void monitor_print_element_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s); + void monitor_print_obj_json(struct netlink_mon_handler *monh, + const char *cmd, struct obj *o); ++void monitor_print_flowtable_json(struct netlink_mon_handler *monh, ++ const char *cmd, struct flowtable *ft); + void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r); + +@@ -254,6 +257,13 @@ static inline void monitor_print_obj_json(struct netlink_mon_handler *monh, + /* empty */ + } + ++static inline void ++monitor_print_flowtable_json(struct netlink_mon_handler *monh, ++ const char *cmd, struct flowtable *ft) ++{ ++ /* empty */ ++} ++ + static inline void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r) + { +diff --git a/include/netlink.h b/include/netlink.h +index cf7ba36..e9667a2 100644 +--- a/include/netlink.h ++++ b/include/netlink.h +@@ -97,6 +97,7 @@ extern struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh); + extern struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh); + extern struct nftnl_set *netlink_set_alloc(const struct nlmsghdr *nlh); + extern struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh); ++extern struct nftnl_flowtable *netlink_flowtable_alloc(const struct nlmsghdr *nlh); + extern struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh); + + struct nft_data_linearize { +diff --git a/include/rule.h b/include/rule.h +index 48e148e..238be23 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -551,6 +551,7 @@ extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name, + const struct table **table); + + void flowtable_print(const struct flowtable *n, struct output_ctx *octx); ++void flowtable_print_plain(const struct flowtable *ft, struct output_ctx *octx); + + /** + * enum cmd_ops - command operations +diff --git a/src/json.c b/src/json.c +index 1f609bf..64a6888 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -2108,6 +2108,12 @@ void monitor_print_obj_json(struct netlink_mon_handler *monh, + monitor_print_json(monh, cmd, obj_print_json(o)); + } + ++void monitor_print_flowtable_json(struct netlink_mon_handler *monh, ++ const char *cmd, struct flowtable *ft) ++{ ++ monitor_print_json(monh, cmd, flowtable_print_json(ft)); ++} ++ + void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r) + { +diff --git a/src/monitor.c b/src/monitor.c +index 2fc16d6..a787db8 100644 +--- a/src/monitor.c ++++ b/src/monitor.c +@@ -127,6 +127,19 @@ struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh) + return nlo; + } + ++struct nftnl_flowtable *netlink_flowtable_alloc(const struct nlmsghdr *nlh) ++{ ++ struct nftnl_flowtable *nlf; ++ ++ nlf = nftnl_flowtable_alloc(); ++ if (nlf == NULL) ++ memory_allocation_error(); ++ if (nftnl_flowtable_nlmsg_parse(nlh, nlf) < 0) ++ netlink_abi_error(); ++ ++ return nlf; ++} ++ + static uint32_t netlink_msg2nftnl_of(uint32_t type, uint16_t flags) + { + switch (type) { +@@ -542,6 +555,50 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type, + return MNL_CB_OK; + } + ++static int netlink_events_flowtable_cb(const struct nlmsghdr *nlh, int type, ++ struct netlink_mon_handler *monh) ++{ ++ const char *family, *cmd; ++ struct nftnl_flowtable *nlf; ++ struct flowtable *ft; ++ ++ nlf = netlink_flowtable_alloc(nlh); ++ ++ ft = netlink_delinearize_flowtable(monh->ctx, nlf); ++ if (!ft) { ++ nftnl_flowtable_free(nlf); ++ return MNL_CB_ERROR; ++ } ++ family = family2str(ft->handle.family); ++ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags); ++ ++ switch (monh->format) { ++ case NFTNL_OUTPUT_DEFAULT: ++ nft_mon_print(monh, "%s ", cmd); ++ ++ switch (type) { ++ case NFT_MSG_NEWFLOWTABLE: ++ flowtable_print_plain(ft, &monh->ctx->nft->output); ++ break; ++ case NFT_MSG_DELFLOWTABLE: ++ nft_mon_print(monh, "flowtable %s %s %s", family, ++ ft->handle.table.name, ++ ft->handle.flowtable.name); ++ break; ++ } ++ nft_mon_print(monh, "\n"); ++ break; ++ case NFTNL_OUTPUT_JSON: ++ monitor_print_flowtable_json(monh, cmd, ft); ++ if (!nft_output_echo(&monh->ctx->nft->output)) ++ nft_mon_print(monh, "\n"); ++ break; ++ } ++ flowtable_free(ft); ++ nftnl_flowtable_free(nlf); ++ return MNL_CB_OK; ++} ++ + static void rule_map_decompose_cb(struct set *s, void *data) + { + if (!set_is_anonymous(s->flags)) +@@ -962,6 +1019,10 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data) + case NFT_MSG_DELOBJ: + ret = netlink_events_obj_cb(nlh, type, monh); + break; ++ case NFT_MSG_NEWFLOWTABLE: ++ case NFT_MSG_DELFLOWTABLE: ++ ret = netlink_events_flowtable_cb(nlh, type, monh); ++ break; + case NFT_MSG_NEWGEN: + ret = netlink_events_newgen_cb(nlh, type, monh); + break; +diff --git a/src/parser_json.c b/src/parser_json.c +index 02cfcd6..bae2c3c 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -4437,6 +4437,7 @@ static int json_echo_error(struct netlink_mon_handler *monh, + + static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh) + { ++ struct nftnl_flowtable *nlf; + struct nftnl_table *nlt; + struct nftnl_chain *nlc; + struct nftnl_rule *nlr; +@@ -4473,6 +4474,11 @@ static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh) + handle = nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE); + nftnl_obj_free(nlo); + break; ++ case NFT_MSG_NEWFLOWTABLE: ++ nlf = netlink_flowtable_alloc(nlh); ++ handle = nftnl_flowtable_get_u64(nlf, NFTNL_FLOWTABLE_HANDLE); ++ nftnl_flowtable_free(nlf); ++ break; + } + return handle; + } +diff --git a/src/rule.c b/src/rule.c +index 9536e68..151ed53 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -2154,6 +2154,21 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx) + do_flowtable_print(s, &opts, octx); + } + ++void flowtable_print_plain(const struct flowtable *ft, struct output_ctx *octx) ++{ ++ struct print_fmt_options opts = { ++ .tab = "", ++ .nl = " ", ++ .table = ft->handle.table.name, ++ .family = family2str(ft->handle.family), ++ .stmt_separator = "; ", ++ }; ++ ++ flowtable_print_declaration(ft, &opts, octx); ++ nft_print(octx, "}"); ++} ++ ++ + struct flowtable *flowtable_lookup_fuzzy(const char *ft_name, + const struct nft_cache *cache, + const struct table **t) +diff --git a/tests/monitor/testcases/flowtable-simple.t b/tests/monitor/testcases/flowtable-simple.t +new file mode 100644 +index 0000000..df8eccb +--- /dev/null ++++ b/tests/monitor/testcases/flowtable-simple.t +@@ -0,0 +1,10 @@ ++# setup first ++I add table ip t ++I add flowtable ip t ft { hook ingress priority 0; devices = { lo }; } ++O - ++J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}} ++J {"add": {"flowtable": {"family": "ip", "name": "ft", "table": "t", "handle": 0, "hook": "ingress", "prio": 0, "dev": "lo"}}} ++ ++I delete flowtable ip t ft ++O - ++J {"delete": {"flowtable": {"family": "ip", "name": "ft", "table": "t", "handle": 0, "hook": "ingress", "prio": 0, "dev": "lo"}}} diff --git a/gating.yaml b/gating.yaml index 9773aea..e0a3a8f 100644 --- a/gating.yaml +++ b/gating.yaml @@ -1,7 +1,7 @@ -# Gating rhel --- !Policy product_versions: - - rhel-* + - rhel-10 decision_context: osci_compose_gate rules: - - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-gating.functional} +# - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1-gating.functional} diff --git a/nftables.spec b/nftables.spec index fadc76d..a7e8f43 100644 --- a/nftables.spec +++ b/nftables.spec @@ -1,9 +1,6 @@ -%define nft_rpmversion 1.0.9 -%define nft_specrelease 5 - Name: nftables -Version: %{nft_rpmversion} -Release: %{nft_specrelease}%{?dist}%{?buildid}.1 +Version: 1.1.1 +Release: 1%{?dist} # Upstream released a 0.100 version, then 0.4. Need Epoch to get back on track. Epoch: 1 Summary: Netfilter Tables userspace utilities @@ -19,8 +16,19 @@ Source5: nat.nft Source6: nft-test.stderr.expect Source7: run-tests.stderr.expect -Patch1: 0001-Add-support-for-table-s-persist-flag.patch -Patch2: 0002-cache-Always-set-NFT_CACHE_TERSE-for-list-cmd-with-t.patch +Patch1: 0001-tests-shell-fix-spurious-dump-failure-in-vmap-timeou.patch +Patch2: 0002-libnftables-json-fix-raw-payload-expression-document.patch +Patch3: 0003-src-collapse-set-element-commands-from-parser.patch +Patch4: 0004-mnl-rename-to-mnl_seqnum_alloc-to-mnl_seqnum_inc.patch +Patch5: 0005-mnl-update-cmd_add_loc-to-take-struct-nlmsghdr.patch +Patch6: 0006-rule-netlink-attribute-offset-is-uint32_t-for-struct.patch +Patch7: 0007-src-fix-extended-netlink-error-reporting-with-large-.patch +Patch8: 0008-tests-monitor-fix-up-test-case-breakage.patch +Patch9: 0009-doc-extend-description-of-fib-expression.patch +Patch10: 0010-json-collapse-set-element-commands-from-parser.patch +Patch11: 0011-json-Support-typeof-in-set-and-map-types.patch +Patch12: 0012-tests-py-Fix-for-storing-payload-into-missing-file.patch +Patch13: 0013-monitor-Recognize-flowtable-add-del-events.patch BuildRequires: autoconf BuildRequires: automake @@ -31,7 +39,7 @@ BuildRequires: flex BuildRequires: bison BuildRequires: pkgconfig(libmnl) >= 1.0.4 BuildRequires: gmp-devel -BuildRequires: pkgconfig(libnftnl) >= 1.2.6 +BuildRequires: pkgconfig(libnftnl) >= 1.2.8 BuildRequires: systemd BuildRequires: asciidoc BuildRequires: pkgconfig(xtables) >= 1.6.1 @@ -135,6 +143,22 @@ cd py/ %files -n python3-nftables -f %{pyproject_files} %changelog +* Thu Nov 07 2024 Phil Sutter [1.1.1-1.el10] +- monitor: Recognize flowtable add/del events (Phil Sutter) [RHEL-65346] +- tests: py: Fix for storing payload into missing file (Phil Sutter) [RHEL-65346] +- json: Support typeof in set and map types (Phil Sutter) [RHEL-65346] +- json: collapse set element commands from parser (Phil Sutter) [RHEL-65346] +- doc: extend description of fib expression (Phil Sutter) [RHEL-65346] +- tests: monitor: fix up test case breakage (Phil Sutter) [RHEL-65346] +- src: fix extended netlink error reporting with large set elements (Phil Sutter) [RHEL-65346] +- rule: netlink attribute offset is uint32_t for struct nlerr_loc (Phil Sutter) [RHEL-65346] +- mnl: update cmd_add_loc() to take struct nlmsghdr (Phil Sutter) [RHEL-65346] +- mnl: rename to mnl_seqnum_alloc() to mnl_seqnum_inc() (Phil Sutter) [RHEL-65346] +- src: collapse set element commands from parser (Phil Sutter) [RHEL-65346] +- libnftables-json: fix raw payload expression documentation (Phil Sutter) [RHEL-65346] +- tests: shell: fix spurious dump failure in vmap timeout test (Phil Sutter) [RHEL-65346] +- Rebase onto version 1.1.1 (Phil Sutter) [RHEL-65346] + * Tue Oct 29 2024 Troy Dawson - 1:1.0.9-5.1 - Bump release for October 2024 mass rebuild: Resolves: RHEL-64018 diff --git a/sources b/sources index 32558f8..1a90c60 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (nftables-1.0.9.tar.xz) = dc34099658e283d9fd4d06264b593710121074558305ea23ab298c5f6a6b564a826f186241b6e106fbaa4e11160cf77e68bb52b4ce401b28d8d2e403cd4b88e8 +SHA512 (nftables-1.1.1.tar.xz) = 676413d4adadffb15d52c1f8f6432636cab83a7bcda1a18d9f0e6b58819a2c027a49922588c02bd9ad386de930eaa697bfe74c0938b595bf1ee485bfa7cf2e50