]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: fix reset element support for interval set type
authorFlorian Westphal <fw@strlen.de>
Thu, 6 Mar 2025 13:23:30 +0000 (14:23 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 7 Mar 2025 12:56:47 +0000 (13:56 +0100)
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 <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
src/segtree.c

index c9c56588cee4c04c2410ae4e4766c1d40ff3014e..e27d08ce7ef863b0f68aa7f832c372149861215d 100644 (file)
@@ -1953,6 +1953,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);
index 11cf27c55dcbf9ab18b63c656b0df34eb5c9206a..0d95fc838ef71b70ed08cc704118bc93c09fc389 100644 (file)
@@ -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);