* [PATCH nft 1/4] evaluate: set on expr->len for catchall set elements
2024-07-04 21:34 [PATCH nft 0/4] unbreak element deletion in map with ranges Pablo Neira Ayuso
@ 2024-07-04 21:34 ` Pablo Neira Ayuso
2024-07-04 21:34 ` [PATCH nft 2/4] segtree: set on EXPR_F_KERNEL flag for catchall elements in the cache Pablo Neira Ayuso
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2024-07-04 21:34 UTC (permalink / raw)
To: netfilter-devel
Catchall elements coming from the parser provide expr->len == 0.
However, the existing mergesort implementation requires expr->len to be
set up to the length of the set key to properly sort elements.
In particular, set element deletion leverages such list sorting to find
if elements exists in the set.
Fixes: 419d19688688 ("src: add set element catch-all support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index aa9293a87856..0a31c73e4276 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1877,6 +1877,16 @@ err_missing_flag:
set_is_map(ctx->set->flags) ? "map" : "set", expr_name(key));
}
+static int expr_evaluate_set_elem_catchall(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *elem = *expr;
+
+ if (ctx->set)
+ elem->len = ctx->set->key->len;
+
+ return 0;
+}
+
static const struct expr *expr_set_elem(const struct expr *expr)
{
if (expr->etype == EXPR_MAPPING)
@@ -2996,7 +3006,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_XFRM:
return expr_evaluate_xfrm(ctx, expr);
case EXPR_SET_ELEM_CATCHALL:
- return 0;
+ return expr_evaluate_set_elem_catchall(ctx, expr);
case EXPR_FLAGCMP:
return expr_evaluate_flagcmp(ctx, expr);
default:
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH nft 3/4] intervals: fix element deletions with maps
2024-07-04 21:34 [PATCH nft 0/4] unbreak element deletion in map with ranges Pablo Neira Ayuso
2024-07-04 21:34 ` [PATCH nft 1/4] evaluate: set on expr->len for catchall set elements Pablo Neira Ayuso
2024-07-04 21:34 ` [PATCH nft 2/4] segtree: set on EXPR_F_KERNEL flag for catchall elements in the cache Pablo Neira Ayuso
@ 2024-07-04 21:34 ` Pablo Neira Ayuso
2024-07-04 21:34 ` [PATCH nft 4/4] tests: shell: cover set element deletion in maps Pablo Neira Ayuso
3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2024-07-04 21:34 UTC (permalink / raw)
To: netfilter-devel
Set element deletion in maps (including catchall elements) does not work.
# nft delete element ip x m { \* }
BUG: invalid range expression type catch-all set element
nft: src/expression.c:1472: range_expr_value_low: Assertion `0' failed.
Aborted
Call interval_expr_key() to fetch expr->left in the mapping but use the
expression that represents the mapping because it provides access to the
EXPR_F_REMOVE flags.
Moreover, assume maximum value for catchall expression by means of the
expr->len to reuse the existing code to check if the element to be
deleted really exists.
Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/intervals.c | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index 6c3f36fec02a..ff202be9375b 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -383,7 +383,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
struct expr *purge, struct expr *elems,
unsigned int debug_mask)
{
- struct expr *i, *next, *prev = NULL;
+ struct expr *i, *next, *elem, *prev = NULL;
struct range range, prev_range;
int err = 0;
mpz_t rop;
@@ -394,21 +394,26 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
mpz_init(range.high);
mpz_init(rop);
- list_for_each_entry_safe(i, next, &elems->expressions, list) {
- if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
- continue;
+ list_for_each_entry_safe(elem, next, &elems->expressions, list) {
+ i = interval_expr_key(elem);
- range_expr_value_low(range.low, i);
- range_expr_value_high(range.high, i);
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL) {
+ /* Assume max value to simplify handling. */
+ mpz_bitmask(range.low, i->len);
+ mpz_bitmask(range.high, i->len);
+ } else {
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+ }
- if (!prev && i->flags & EXPR_F_REMOVE) {
+ if (!prev && elem->flags & EXPR_F_REMOVE) {
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
}
- if (!(i->flags & EXPR_F_REMOVE)) {
- prev = i;
+ if (!(elem->flags & EXPR_F_REMOVE)) {
+ prev = elem;
mpz_set(prev_range.low, range.low);
mpz_set(prev_range.high, range.high);
continue;
@@ -416,12 +421,12 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
if (mpz_cmp(prev_range.low, range.low) == 0 &&
mpz_cmp(prev_range.high, range.high) == 0) {
- if (i->flags & EXPR_F_REMOVE) {
+ if (elem->flags & EXPR_F_REMOVE) {
if (prev->flags & EXPR_F_KERNEL)
list_move_tail(&prev->list, &purge->expressions);
- list_del(&i->list);
- expr_free(i);
+ list_del(&elem->list);
+ expr_free(elem);
}
} else if (set->automerge) {
if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
@@ -429,7 +434,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
err = -1;
goto err;
}
- } else if (i->flags & EXPR_F_REMOVE) {
+ } else if (elem->flags & EXPR_F_REMOVE) {
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH nft 4/4] tests: shell: cover set element deletion in maps
2024-07-04 21:34 [PATCH nft 0/4] unbreak element deletion in map with ranges Pablo Neira Ayuso
` (2 preceding siblings ...)
2024-07-04 21:34 ` [PATCH nft 3/4] intervals: fix element deletions with maps Pablo Neira Ayuso
@ 2024-07-04 21:34 ` Pablo Neira Ayuso
3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2024-07-04 21:34 UTC (permalink / raw)
To: netfilter-devel
Extend existing coverage to deal with set element deletion, including
catchall elements too.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
tests/shell/testcases/maps/delete_element | 28 +++++++++++++++
.../testcases/maps/delete_element_catchall | 35 +++++++++++++++++++
.../maps/dumps/delete_elem_catchall.nft | 12 +++++++
.../testcases/maps/dumps/delete_element.nft | 12 +++++++
4 files changed, 87 insertions(+)
create mode 100755 tests/shell/testcases/maps/delete_element
create mode 100755 tests/shell/testcases/maps/delete_element_catchall
create mode 100644 tests/shell/testcases/maps/dumps/delete_elem_catchall.nft
create mode 100644 tests/shell/testcases/maps/dumps/delete_element.nft
diff --git a/tests/shell/testcases/maps/delete_element b/tests/shell/testcases/maps/delete_element
new file mode 100755
index 000000000000..75272f448dbf
--- /dev/null
+++ b/tests/shell/testcases/maps/delete_element
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+RULESET="flush ruleset
+
+table ip x {
+ map m {
+ typeof ct bytes : meta priority
+ flags interval
+ elements = {
+ 0-2048000 : 1:0001,
+ 2048001-4000000 : 1:0002,
+ }
+ }
+
+ chain y {
+ type filter hook output priority 0; policy accept;
+
+ meta priority set ct bytes map @m
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT delete element ip x m { 0-2048000 }
+$NFT add element ip x m { 0-2048000 : 1:0002 }
+$NFT delete element ip x m { 0-2048000 : 1:0002 }
diff --git a/tests/shell/testcases/maps/delete_element_catchall b/tests/shell/testcases/maps/delete_element_catchall
new file mode 100755
index 000000000000..a6a0fc6f3e04
--- /dev/null
+++ b/tests/shell/testcases/maps/delete_element_catchall
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+set -e
+
+RULESET="flush ruleset
+
+table ip x {
+ map m {
+ typeof ct bytes : meta priority
+ flags interval
+ elements = {
+ 0-2048000 : 1:0001,
+ * : 1:0002,
+ }
+ }
+
+ chain y {
+ type filter hook output priority 0; policy accept;
+
+ meta priority set ct bytes map @m
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT delete element ip x m { 0-2048000 }
+$NFT add element ip x m { 0-2048000 : 1:0002 }
+$NFT delete element ip x m { 0-2048000 : 1:0002 }
+
+$NFT 'delete element ip x m { * }'
+$NFT 'add element ip x m { * : 1:0003 }'
+$NFT 'delete element ip x m { * : 1:0003 }'
+$NFT 'add element ip x m { * : 1:0003 }'
diff --git a/tests/shell/testcases/maps/dumps/delete_elem_catchall.nft b/tests/shell/testcases/maps/dumps/delete_elem_catchall.nft
new file mode 100644
index 000000000000..14054f4dc4d5
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/delete_elem_catchall.nft
@@ -0,0 +1,12 @@
+table ip x {
+ map m {
+ typeof ct bytes : meta priority
+ flags interval
+ elements = { * : 1:3 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ meta priority set ct bytes map @m
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/delete_element.nft b/tests/shell/testcases/maps/dumps/delete_element.nft
new file mode 100644
index 000000000000..5275b4dc2a68
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/delete_element.nft
@@ -0,0 +1,12 @@
+table ip x {
+ map m {
+ typeof ct bytes : meta priority
+ flags interval
+ elements = { 2048001-4000000 : 1:2 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ meta priority set ct bytes map @m
+ }
+}
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread