From 0a38b9fcf1841e68088f2db39e3c96b3ad3b0369 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 18 Mar 2026 22:17:46 +0100 Subject: [PATCH] src: fix reset element support for interval set type JIRA: https://issues.redhat.com/browse/https://redhat.atlassian.net/browse/RHEL-153461 Upstream Status: nftables commit 2b164aec4295d5f4f6d45aa098279494ab44289b commit 2b164aec4295d5f4f6d45aa098279494ab44289b Author: Florian Westphal Date: Thu Mar 6 14:23:30 2025 +0100 src: fix reset element support for interval set type Running reset command yields on an interval (rbtree) set yields: nft reset element inet filter rbtreeset {1.2.3.4} BUG: unhandled op 8 This is easy to fix, CMD_RESET doesn't add or remove so it should be treated like CMD_GET. Unfortunately, this still doesn't work properly: nft get element inet filter rbset {1.2.3.4} returns: ... elements = { 1.2.3.4 } but its expected that "get" and "reset" also return stateful objects associated with the element. This works for other set types, but for rbtree, the list of statements gets lost during segtree processing. After fix, get/reset returns: elements = { 1.2.3.4 counter packets 10 ... A follow up patch will add a test case. Fixes: 83e0f4402fb7 ("Implement 'reset {set,map,element}' commands") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Phil Sutter --- src/evaluate.c | 1 + src/segtree.c | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 2196e92..711990a 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1729,6 +1729,7 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set, ctx->nft->debug_mask); break; case CMD_GET: + case CMD_RESET: break; default: BUG("unhandled op %d\n", ctx->cmd->op); diff --git a/src/segtree.c b/src/segtree.c index 28172b3..c4029f9 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -206,6 +206,27 @@ static struct expr *expr_to_set_elem(struct expr *e) return __expr_to_set_elem(e, expr); } +static void set_compound_expr_add(struct expr *compound, struct expr *expr, struct expr *orig) +{ + struct expr *elem; + + switch (expr->etype) { + case EXPR_SET_ELEM: + list_splice_init(&orig->stmt_list, &expr->stmt_list); + compound_expr_add(compound, expr); + break; + case EXPR_MAPPING: + list_splice_init(&orig->left->stmt_list, &expr->left->stmt_list); + compound_expr_add(compound, expr); + break; + default: + elem = set_elem_expr_alloc(&orig->location, expr); + list_splice_init(&orig->stmt_list, &elem->stmt_list); + compound_expr_add(compound, elem); + break; + } +} + int get_set_decompose(struct set *cache_set, struct set *set) { struct expr *i, *next, *range; @@ -227,20 +248,23 @@ int get_set_decompose(struct set *cache_set, struct set *set) errno = ENOENT; return -1; } + + set_compound_expr_add(new_init, range, left); + expr_free(left); expr_free(i); - compound_expr_add(new_init, range); left = NULL; } else { if (left) { range = get_set_interval_find(cache_set, left, NULL); + if (range) - compound_expr_add(new_init, range); + set_compound_expr_add(new_init, range, left); else - compound_expr_add(new_init, - expr_to_set_elem(left)); + set_compound_expr_add(new_init, + expr_to_set_elem(left), left); } left = i; } @@ -248,9 +272,9 @@ int get_set_decompose(struct set *cache_set, struct set *set) if (left) { range = get_set_interval_find(cache_set, left, NULL); if (range) - compound_expr_add(new_init, range); + set_compound_expr_add(new_init, range, left); else - compound_expr_add(new_init, expr_to_set_elem(left)); + set_compound_expr_add(new_init, expr_to_set_elem(left), left); } expr_free(set->init);