* [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal
@ 2026-02-05 2:41 Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 01/20] src: normalize set element with EXPR_MAPPING Pablo Neira Ayuso
` (20 more replies)
0 siblings, 21 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Hi,
This is v2 of the update to prepare for the removal of EXPR_SET_ELEM.
This series is slightly larger than v1, including more preparation work.
No functional changes are intended. No memory footprint reduction at
this stage. This slightly increases LoC because of the patches that add
assertions on EXPR_SET_ELEM.
This is passing tests/shell.
Apologies for this large series...
Pablo Neira Ayuso (20):
src: normalize set element with EXPR_MAPPING
src: allocate EXPR_SET_ELEM for EXPR_SET in embedded set declaration in sets
src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list
evaluate: simplify sets as set elems evaluation
evaluate: clean up expr_evaluate_set()
segtree: rename set_elem_add() to set_elem_expr_add()
src: move flags from EXPR_SET_ELEM to key
src: remove EXPR_SET_ELEM in range_expr_value_{low,high}()
src: use key location to prepare removal of EXPR_SET_ELEM
intervals: remove interval_expr_key()
src: move __set_expr_add() to src/intervals.c
segtree: remove EXPR_VALUE from expr_value()
segtree: more assert on EXPR_SET_ELEM
segtree: remove dead code in set_expr_add_splice()
segtree: disentangle concat_range_aggregate()
segtree: replace default case by specific types in get_set_intervals()
segtree: consolidate calls to expr_value() to fetch the element key
segtree: use set->key->byteorder instead of expr->byteorder
evaluate: remove check for constant expression in set/map statement
evaluate: skip EXPR_SET_ELEM in error path of set statements
include/expression.h | 5 +-
src/datatype.c | 1 +
src/evaluate.c | 151 +++++++++----------
src/expression.c | 58 +++++---
src/intervals.c | 300 ++++++++++++++++++++------------------
src/json.c | 42 +++++-
src/mergesort.c | 8 +-
src/monitor.c | 2 +-
src/netlink.c | 105 ++++++-------
src/netlink_delinearize.c | 18 ++-
src/optimize.c | 52 ++++---
src/parser_bison.y | 12 +-
src/parser_json.c | 14 +-
src/segtree.c | 230 ++++++++++++++++-------------
14 files changed, 559 insertions(+), 439 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH nft 01/20] src: normalize set element with EXPR_MAPPING
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 02/20] src: allocate EXPR_SET_ELEM for EXPR_SET in embedded set declaration in sets Pablo Neira Ayuso
` (19 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
EXPR_SET_ELEM provides the timeout, expiration, comment and list of
statements, this is a shim expression.
Currently, expr_set(x)->expressions can have either:
- EXPR_SET_ELEM
EXPR_SET_ELEM -> EXPR_VALUE
- EXPR_MAPPING, which contains EXPR_SET_ELEM in the lhs.
EXPR_SET_ELEM -> EXPR_VALUE
/
EXPR_MAPPING |
\
EXPR_VALUE
This patch normalizes the expression for mappings:
EXPR_VALUE
/
EXPR_SET_ELEM -> EXPR_MAPPING |
\
EXPR_VALUE
The previous representation makes it natural for expr_print() to print the
timeout, expiration, statements and comments.
1.1.1.1 counter packets 1 bytes 564 : 0x00000001,
This patch adds an exception for expr_mapping_print() to stick to the
existing representation.
The JSON representation provides this set element information too in the
lhs, which is does not really belong there because it is exposing
transparently the syntax tree for set elements. A workaround to retain
compatibility is included in this patch.
The end goal is to replace EXPR_SET_ELEM by a smaller shim object, to
further reduce memory consumption in set elements in userspace.
This is preparation work that is required to reduce memory footprint
with sets and maps.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/expression.h | 4 +-
src/datatype.c | 1 +
src/evaluate.c | 68 ++++++++++++---------
src/expression.c | 27 +++++++--
src/intervals.c | 124 ++++++++++++++++++++++----------------
src/json.c | 32 ++++++++--
src/netlink.c | 95 +++++++++++++++--------------
src/netlink_delinearize.c | 9 ++-
src/optimize.c | 49 ++++++++-------
src/parser_bison.y | 10 ++-
src/parser_json.c | 14 +++--
src/segtree.c | 31 +++++-----
12 files changed, 281 insertions(+), 183 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index a960f8cb8b08..bce75d29ee2c 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -563,7 +563,9 @@ extern struct expr *set_elem_expr_alloc(const struct location *loc,
struct expr *set_elem_catchall_expr_alloc(const struct location *loc);
#define expr_type_catchall(__expr) \
- ((__expr)->etype == EXPR_SET_ELEM_CATCHALL)
+ ((__expr)->etype == EXPR_SET_ELEM_CATCHALL || \
+ ((__expr)->etype == EXPR_MAPPING && \
+ (__expr)->left->etype == EXPR_SET_ELEM_CATCHALL))
extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
diff --git a/src/datatype.c b/src/datatype.c
index 189738513bf8..4dbca16ec89a 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -1525,6 +1525,7 @@ const struct datatype boolean_type = {
.name = "boolean",
.desc = "boolean type",
.size = 1,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
.parse = boolean_type_parse,
.basetype = &integer_type,
.sym_tbl = &boolean_tbl,
diff --git a/src/evaluate.c b/src/evaluate.c
index 7e6ef3c724c1..13e0c6916ac7 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1943,6 +1943,9 @@ static bool elem_key_compatible(const struct expr *set_key,
if (expr_type_catchall(elem_key))
return true;
+ if (elem_key->etype == EXPR_MAPPING)
+ return datatype_compatible(set_key->dtype, elem_key->left->dtype);
+
return datatype_compatible(set_key->dtype, elem_key->dtype);
}
@@ -2016,14 +2019,6 @@ static int expr_evaluate_set_elem_catchall(struct eval_ctx *ctx, struct expr **e
return 0;
}
-static const struct expr *expr_set_elem(const struct expr *expr)
-{
- if (expr->etype == EXPR_MAPPING)
- return expr->left;
-
- return expr;
-}
-
static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
struct expr *init)
{
@@ -2075,18 +2070,19 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
const struct expr *elem;
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
+ /* recursive EXPR_SET are merged here. */
if (list_member_evaluate(ctx, &i) < 0)
return -1;
- if (i->etype == EXPR_MAPPING &&
- i->left->etype == EXPR_SET_ELEM &&
- i->left->key->etype == EXPR_SET) {
+ if (i->key->etype == EXPR_MAPPING &&
+ i->key->left->etype == EXPR_SET) {
struct expr *new, *j;
- list_for_each_entry(j, &expr_set(i->left->key)->expressions, list) {
+ list_for_each_entry(j, &expr_set(i->key->left)->expressions, list) {
new = mapping_expr_alloc(&i->location,
- expr_get(j),
- expr_get(i->right));
+ expr_get(j->key),
+ expr_get(i->key->right));
+ new = set_elem_expr_alloc(&i->location, new);
list_add_tail(&new->list, &expr_set(set)->expressions);
expr_set(set)->size++;
}
@@ -2095,7 +2091,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
continue;
}
- elem = expr_set_elem(i);
+ elem = i;
if (elem->etype == EXPR_SET_ELEM &&
elem->key->etype == EXPR_SET_REF)
@@ -2110,7 +2106,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
list_replace(&i->list, &new->list);
expr_free(i);
i = new;
- elem = expr_set_elem(i);
+ elem = i;
}
if (!expr_is_constant(i))
@@ -2126,7 +2122,9 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
expr_free(i);
} else if (!expr_is_singleton(i)) {
expr_set(set)->set_flags |= NFT_SET_INTERVAL;
- if (elem->key->etype == EXPR_CONCAT)
+ if ((elem->key->etype == EXPR_MAPPING &&
+ elem->key->left->etype == EXPR_CONCAT) ||
+ elem->key->etype == EXPR_CONCAT)
expr_set(set)->set_flags |= NFT_SET_CONCAT;
}
}
@@ -2197,10 +2195,12 @@ static int mapping_expr_expand(struct eval_ctx *ctx)
return 0;
list_for_each_entry(i, &expr_set(ctx->set->init)->expressions, list) {
- if (i->etype != EXPR_MAPPING)
+ assert(i->etype == EXPR_SET_ELEM);
+
+ if (i->key->etype != EXPR_MAPPING)
return expr_error(ctx->msgs, i,
"expected mapping, not %s", expr_name(i));
- __mapping_expr_expand(i);
+ __mapping_expr_expand(i->key);
}
return 0;
@@ -2389,6 +2389,7 @@ static bool elem_data_compatible(const struct expr *set_data,
static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
{
+ const struct expr *key = ctx->ectx.key;
struct expr *mapping = *expr;
struct set *set = ctx->set;
uint32_t datalen;
@@ -2400,6 +2401,8 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
return set_error(ctx, set, "set is not a map");
expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ ctx->ectx.key = key;
+
if (expr_evaluate(ctx, &mapping->left) < 0)
return -1;
if (!expr_is_constant(mapping->left))
@@ -2702,11 +2705,15 @@ static int __binop_transfer(struct eval_ctx *ctx,
break;
case EXPR_SET:
list_for_each_entry(i, &expr_set(*right)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
err = binop_can_transfer(ctx, left, i);
if (err <= 0)
return err;
}
list_for_each_entry_safe(i, next, &expr_set(*right)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
list_del(&i->list);
err = binop_transfer_one(ctx, left, &i);
list_add_tail(&i->list, &next->list);
@@ -4475,8 +4482,10 @@ static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt)
switch (stmt->nat.addr->mappings->etype) {
case EXPR_SET:
list_for_each_entry(i, &expr_set(stmt->nat.addr->mappings)->expressions, list) {
- if (i->etype == EXPR_MAPPING &&
- i->right->etype == EXPR_CONCAT) {
+ assert(i->etype == EXPR_SET_ELEM);
+
+ if (i->key->etype == EXPR_MAPPING &&
+ i->key->right->etype == EXPR_CONCAT) {
stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
return true;
}
@@ -5315,16 +5324,17 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
if (set_is_anonymous(set->flags) && set->key->etype == EXPR_CONCAT) {
- struct expr *i;
+ struct expr *i, *key;
list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
- if ((i->etype == EXPR_SET_ELEM &&
- i->key->etype != EXPR_CONCAT &&
- i->key->etype != EXPR_SET_ELEM_CATCHALL) ||
- (i->etype == EXPR_MAPPING &&
- i->left->etype == EXPR_SET_ELEM &&
- i->left->key->etype != EXPR_CONCAT &&
- i->left->key->etype != EXPR_SET_ELEM_CATCHALL))
+ assert (i->etype == EXPR_SET_ELEM);
+
+ key = i->key;
+ if (key->etype == EXPR_MAPPING)
+ key = key->left;
+
+ if (key->etype != EXPR_CONCAT &&
+ key->etype != EXPR_SET_ELEM_CATCHALL)
return expr_error(ctx->msgs, i, "expression is not a concatenation");
}
}
diff --git a/src/expression.c b/src/expression.c
index e036c4bb6996..5aac7165319f 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1515,14 +1515,16 @@ struct expr *mapping_expr_alloc(const struct location *loc,
static bool __set_expr_is_vmap(const struct expr *mappings)
{
- const struct expr *mapping;
+ const struct expr *elem;
if (list_empty(&expr_set(mappings)->expressions))
return false;
- mapping = list_first_entry(&expr_set(mappings)->expressions, struct expr, list);
- if (mapping->etype == EXPR_MAPPING &&
- mapping->right->etype == EXPR_VERDICT)
+ elem = list_first_entry(&expr_set(mappings)->expressions, struct expr, list);
+ assert(elem->etype == EXPR_SET_ELEM);
+
+ if (elem->key->etype == EXPR_MAPPING &&
+ elem->key->right->etype == EXPR_VERDICT)
return true;
return false;
@@ -1653,7 +1655,17 @@ static void set_elem_expr_print(const struct expr *expr,
{
struct stmt *stmt;
- expr_print(expr->key, octx);
+ /* The mapping output needs to print lhs first, then timeout, expires,
+ * comment and list of statements and finally rhs.
+ *
+ * Because EXPR_SET_ELEM always comes before EXPR_MAPPING, add this
+ * special handling to print the output accordingly.
+ */
+ if (expr->key->etype == EXPR_MAPPING)
+ expr_print(expr->key->left, octx);
+ else
+ expr_print(expr->key, octx);
+
list_for_each_entry(stmt, &expr->stmt_list, list) {
nft_print(octx, " ");
stmt_print(stmt, octx);
@@ -1673,6 +1685,11 @@ static void set_elem_expr_print(const struct expr *expr,
}
if (expr->comment)
nft_print(octx, " comment \"%s\"", expr->comment);
+
+ if (expr->key->etype == EXPR_MAPPING) {
+ nft_print(octx, " : ");
+ expr_print(expr->key->right, octx);
+ }
}
static void set_elem_expr_destroy(struct expr *expr)
diff --git a/src/intervals.c b/src/intervals.c
index 29e8fab8172a..9ab2cc20533a 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -15,65 +15,73 @@
static void set_to_range(struct expr *init);
-static void setelem_expr_to_range(struct expr *expr)
+static void __setelem_expr_to_range(struct expr **exprp)
{
- struct expr *key;
+ struct expr *key, *expr = *exprp;
mpz_t rop;
- assert(expr->etype == EXPR_SET_ELEM);
-
- switch (expr->key->etype) {
+ switch (expr->etype) {
case EXPR_SET_ELEM_CATCHALL:
case EXPR_RANGE_VALUE:
break;
case EXPR_RANGE:
key = constant_range_expr_alloc(&expr->location,
- expr->key->dtype,
- expr->key->byteorder,
- expr->key->len,
- expr->key->left->value,
- expr->key->right->value);
- expr_free(expr->key);
- expr->key = key;
+ expr->dtype,
+ expr->byteorder,
+ expr->len,
+ expr->left->value,
+ expr->right->value);
+ expr_free(*exprp);
+ *exprp = key;
break;
case EXPR_PREFIX:
- if (expr->key->prefix->etype != EXPR_VALUE)
- BUG("Prefix for unexpected type %d", expr->key->prefix->etype);
+ if (expr->prefix->etype != EXPR_VALUE)
+ BUG("Prefix for unexpected type %d", expr->prefix->etype);
mpz_init(rop);
- mpz_bitmask(rop, expr->key->len - expr->key->prefix_len);
+ mpz_bitmask(rop, expr->len - expr->prefix_len);
if (expr_basetype(expr)->type == TYPE_STRING)
- mpz_switch_byteorder(expr->key->prefix->value, expr->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(expr->prefix->value, expr->len / BITS_PER_BYTE);
- mpz_ior(rop, rop, expr->key->prefix->value);
+ mpz_ior(rop, rop, expr->prefix->value);
key = constant_range_expr_alloc(&expr->location,
- expr->key->dtype,
- expr->key->byteorder,
- expr->key->len,
- expr->key->prefix->value,
+ expr->dtype,
+ expr->byteorder,
+ expr->len,
+ expr->prefix->value,
rop);
mpz_clear(rop);
- expr_free(expr->key);
- expr->key = key;
+ expr_free(*exprp);
+ *exprp = key;
break;
case EXPR_VALUE:
if (expr_basetype(expr)->type == TYPE_STRING)
- mpz_switch_byteorder(expr->key->value, expr->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
key = constant_range_expr_alloc(&expr->location,
- expr->key->dtype,
- expr->key->byteorder,
- expr->key->len,
- expr->key->value,
- expr->key->value);
- expr_free(expr->key);
- expr->key = key;
+ expr->dtype,
+ expr->byteorder,
+ expr->len,
+ expr->value,
+ expr->value);
+ expr_free(*exprp);
+ *exprp = key;
break;
default:
BUG("unhandled key type %s", expr_name(expr->key));
}
}
+static void setelem_expr_to_range(struct expr *expr)
+{
+ assert(expr->etype == EXPR_SET_ELEM);
+
+ if (expr->key->etype == EXPR_MAPPING)
+ __setelem_expr_to_range(&expr->key->left);
+ else
+ __setelem_expr_to_range(&expr->key);
+}
+
struct set_automerge_ctx {
struct set *set;
struct expr *init;
@@ -219,9 +227,6 @@ static struct expr *interval_expr_key(struct expr *i)
struct expr *elem;
switch (i->etype) {
- case EXPR_MAPPING:
- elem = i->left;
- break;
case EXPR_SET_ELEM:
elem = i;
break;
@@ -411,9 +416,17 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
i = interval_expr_key(elem);
if (expr_type_catchall(i->key)) {
+ uint32_t len;
+
/* Assume max value to simplify handling. */
- mpz_bitmask(range.low, i->len);
- mpz_bitmask(range.high, i->len);
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ len = i->key->len;
+ else if (i->key->etype == EXPR_MAPPING &&
+ i->key->left->etype == EXPR_SET_ELEM_CATCHALL)
+ len = i->key->left->len;
+
+ mpz_bitmask(range.low, len);
+ mpz_bitmask(range.high, len);
} else {
range_expr_value_low(range.low, i);
range_expr_value_high(range.high, i);
@@ -677,6 +690,20 @@ static bool segtree_needs_first_segment(const struct set *set,
return false;
}
+static bool range_low_is_non_zero(const struct expr *expr)
+{
+ switch (expr->etype) {
+ case EXPR_RANGE_VALUE:
+ return mpz_cmp_ui(expr->range.low, 0);
+ case EXPR_MAPPING:
+ return range_low_is_non_zero(expr->left);
+ default:
+ BUG("unexpected expression %s\n", expr_name(expr));
+ break;
+ }
+ return false;
+}
+
int set_to_intervals(const struct set *set, struct expr *init, bool add)
{
struct expr *i, *n, *prev = NULL, *elem, *root, *expr;
@@ -693,7 +720,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
break;
if (segtree_needs_first_segment(set, init, add) &&
- mpz_cmp_ui(elem->key->range.low, 0)) {
+ range_low_is_non_zero(elem->key)) {
mpz_init2(p, set->key->len);
mpz_set_ui(p, 0);
expr = constant_range_expr_alloc(&internal_location,
@@ -703,11 +730,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
mpz_clear(p);
root = set_elem_expr_alloc(&internal_location, expr);
- if (i->etype == EXPR_MAPPING) {
- root = mapping_expr_alloc(&internal_location,
- root,
- expr_get(i->right));
- }
+
root->flags |= EXPR_F_INTERVAL_END;
list_add(&root->list, &intervals);
break;
@@ -749,12 +772,11 @@ static struct expr *setelem_key(struct expr *expr)
struct expr *key;
switch (expr->etype) {
- case EXPR_MAPPING:
- key = expr->left->key;
- break;
case EXPR_SET_ELEM:
- key = expr->key;
- break;
+ if (expr->key->etype == EXPR_MAPPING)
+ return expr->key->left;
+
+ return expr->key;
default:
BUG("unhandled expression type %d", expr->etype);
return NULL;
@@ -801,13 +823,13 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
BYTEORDER_BIG_ENDIAN, set->key->len, NULL);
mpz_set(low->value, key->range.low);
+ if (elem->key->etype == EXPR_MAPPING)
+ low = mapping_expr_alloc(&elem->location,
+ low, expr_get(elem->key->right));
+
low = set_elem_expr_alloc(&key->location, low);
set_elem_expr_copy(low, interval_expr_key(elem));
- if (elem->etype == EXPR_MAPPING)
- low = mapping_expr_alloc(&elem->location,
- low, expr_get(elem->right));
-
list_add_tail(&low->list, intervals);
if (adjacent)
diff --git a/src/json.c b/src/json.c
index 9fb6d715a53d..937a82dc19e9 100644
--- a/src/json.c
+++ b/src/json.c
@@ -783,18 +783,19 @@ json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx)
}
}
-json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
+static json_t *__set_elem_expr_json(const struct expr *expr,
+ const struct expr *val,
+ struct output_ctx *octx)
{
- json_t *root = expr_print_json(expr->key, octx);
+ json_t *root = expr_print_json(val, octx);
struct stmt *stmt;
json_t *tmp;
- if (!root)
- return NULL;
-
/* these element attributes require formal set elem syntax */
if (expr->timeout || expr->expiration || expr->comment ||
!list_empty(&expr->stmt_list)) {
+ assert(expr->etype == EXPR_SET_ELEM);
+
root = nft_json_pack("{s:o}", "val", root);
if (expr->timeout) {
@@ -823,6 +824,27 @@ json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
return root;
}
+json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *left, *right;
+
+ assert(expr->etype == EXPR_SET_ELEM);
+
+ /* Special handling to retain backwards compatibility: json exposes
+ * EXPR_MAPPING { left: EXPR_SET_ELEM, right: EXPR_{VALUE,CONCAT,SYMBOL}.
+ * Revisit this at some point to accept the following input:
+ * EXPR_SET_ELEM -> EXPR_MAPPING { left, right }
+ */
+ if (expr->key->etype == EXPR_MAPPING) {
+ left = __set_elem_expr_json(expr, expr->key->left, octx);
+ right = expr_print_json(expr->key->right, octx);
+
+ return nft_json_pack("[o, o]", left, right);
+ }
+
+ return __set_elem_expr_json(expr, expr->key, octx);
+}
+
json_t *prefix_expr_json(const struct expr *expr, struct output_ctx *octx)
{
json_t *root = expr_print_json(expr->prefix, octx);
diff --git a/src/netlink.c b/src/netlink.c
index ad19f8b7dc39..3a28978547c3 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -103,7 +103,7 @@ static void __netlink_gen_data(const struct expr *expr,
struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
const struct expr *expr)
{
- const struct expr *elem, *data;
+ const struct expr *data, *elem;
struct nftnl_set_elem *nlse;
struct nft_data_linearize nld;
struct nftnl_udata_buf *udbuf = NULL;
@@ -116,18 +116,20 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
if (nlse == NULL)
memory_allocation_error();
+ if (expr->etype != EXPR_SET_ELEM)
+ BUG("Unexpected expression type: got %d\n", expr->etype);
+
data = NULL;
- if (expr->etype == EXPR_MAPPING) {
- elem = expr->left;
- if (!(expr->flags & EXPR_F_INTERVAL_END))
- data = expr->right;
+ if (expr->key->etype == EXPR_MAPPING) {
+ if (!(expr->key->flags & EXPR_F_INTERVAL_END))
+ data = expr->key->right;
+
+ key = expr->key->left;
} else {
- elem = expr;
+ key = expr->key;
}
- if (elem->etype != EXPR_SET_ELEM)
- BUG("Unexpected expression type: got %d", elem->etype);
- key = elem->key;
+ elem = expr;
switch (key->etype) {
case EXPR_SET_ELEM_CATCHALL:
@@ -627,6 +629,8 @@ static void netlink_gen_key(const struct expr *expr,
return netlink_gen_range(expr, data);
case EXPR_PREFIX:
return netlink_gen_prefix(expr, data);
+ case EXPR_MAPPING:
+ return netlink_gen_key(expr->left, data);
default:
BUG("invalid data expression type %s", expr_name(expr));
}
@@ -1599,41 +1603,6 @@ key_end:
return 0;
}
- expr = set_elem_expr_alloc(&netlink_location, key);
- expr->flags |= EXPR_F_KERNEL;
-
- if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) {
- expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
- if (expr->timeout == 0)
- expr->timeout = NFT_NEVER_TIMEOUT;
- }
-
- if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
- expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION);
- if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) {
- set_elem_parse_udata(nlse, expr);
- if (expr->comment)
- set->elem_has_comment = true;
- }
- if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) {
- const struct nftnl_expr *nle;
- struct stmt *stmt;
-
- nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
- stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
- list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list);
- } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) {
- nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions,
- &setelem_parse_ctx);
- }
- list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
-
- if (flags & NFT_SET_ELEM_INTERVAL_END) {
- expr->flags |= EXPR_F_INTERVAL_END;
- if (mpz_cmp_ui(set->key->value, 0) == 0)
- set->root = true;
- }
-
if (set_is_datamap(set->flags)) {
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) {
nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA,
@@ -1664,7 +1633,7 @@ key_end:
if (data->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
- expr = mapping_expr_alloc(&netlink_location, expr, data);
+ key = mapping_expr_alloc(&netlink_location, key, data);
}
if (set_is_objmap(set->flags)) {
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_OBJREF)) {
@@ -1678,9 +1647,43 @@ key_end:
data->dtype = &string_type;
data->byteorder = BYTEORDER_HOST_ENDIAN;
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
- expr = mapping_expr_alloc(&netlink_location, expr, data);
+ key = mapping_expr_alloc(&netlink_location, key, data);
}
out:
+ expr = set_elem_expr_alloc(&netlink_location, key);
+ expr->flags |= EXPR_F_KERNEL;
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) {
+ expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
+ if (expr->timeout == 0)
+ expr->timeout = NFT_NEVER_TIMEOUT;
+ }
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
+ expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) {
+ set_elem_parse_udata(nlse, expr);
+ if (expr->comment)
+ set->elem_has_comment = true;
+ }
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) {
+ const struct nftnl_expr *nle;
+ struct stmt *stmt;
+
+ nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
+ stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
+ list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list);
+ } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) {
+ nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions,
+ &setelem_parse_ctx);
+ }
+ list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
+
+ if (flags & NFT_SET_ELEM_INTERVAL_END) {
+ expr->flags |= EXPR_F_INTERVAL_END;
+ if (mpz_cmp_ui(set->key->value, 0) == 0)
+ set->root = true;
+ }
set_expr_add(set->init, expr);
if (!(flags & NFT_SET_ELEM_INTERVAL_END) &&
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 9561e298aebb..fc359d6d9294 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2493,6 +2493,8 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
break;
list_for_each_entry(i, &expr_set(right->set->init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
switch (i->key->etype) {
case EXPR_VALUE:
binop_adjust_one(binop, i->key, shift);
@@ -2501,8 +2503,11 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
binop_adjust_one(binop, i->key->left, shift);
binop_adjust_one(binop, i->key->right, shift);
break;
- case EXPR_SET_ELEM:
- binop_adjust(binop, i->key->key, shift);
+ case EXPR_MAPPING:
+ if (i->key->left->etype == EXPR_RANGE)
+ binop_adjust(binop, i->key->left, shift);
+ else
+ binop_adjust_one(binop, i->key->left, shift);
break;
default:
BUG("unknown expression type %s",
diff --git a/src/optimize.c b/src/optimize.c
index 17084a84d465..3e6e24cf7b90 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -756,29 +756,31 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
switch (expr->etype) {
case EXPR_LIST:
list_for_each_entry(item, &expr_list(expr)->expressions, list) {
- elem = set_elem_expr_alloc(&internal_location, expr_get(item));
+ mapping = mapping_expr_alloc(&internal_location, expr_get(item),
+ expr_get(verdict->expr));
+
+ elem = set_elem_expr_alloc(&internal_location, mapping);
if (counter) {
counter_elem = counter_stmt_alloc(&counter->location);
list_add_tail(&counter_elem->list, &elem->stmt_list);
}
- mapping = mapping_expr_alloc(&internal_location, elem,
- expr_get(verdict->expr));
- set_expr_add(set, mapping);
+ set_expr_add(set, elem);
}
stmt_free(counter);
break;
case EXPR_SET:
list_for_each_entry(item, &expr_set(expr)->expressions, list) {
- elem = set_elem_expr_alloc(&internal_location, expr_get(item->key));
+ mapping = mapping_expr_alloc(&internal_location, expr_get(item->key),
+ expr_get(verdict->expr));
+
+ elem = set_elem_expr_alloc(&internal_location, mapping);
if (counter) {
counter_elem = counter_stmt_alloc(&counter->location);
list_add_tail(&counter_elem->list, &elem->stmt_list);
}
- mapping = mapping_expr_alloc(&internal_location, elem,
- expr_get(verdict->expr));
- set_expr_add(set, mapping);
+ set_expr_add(set, elem);
}
stmt_free(counter);
break;
@@ -789,13 +791,14 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
case EXPR_VALUE:
case EXPR_SYMBOL:
case EXPR_CONCAT:
- elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
+ mapping = mapping_expr_alloc(&internal_location, expr_get(expr),
+ expr_get(verdict->expr));
+
+ elem = set_elem_expr_alloc(&internal_location, mapping);
if (counter)
list_add_tail(&counter->list, &elem->stmt_list);
- mapping = mapping_expr_alloc(&internal_location, elem,
- expr_get(verdict->expr));
- set_expr_add(set, mapping);
+ set_expr_add(set, elem);
break;
default:
assert(0);
@@ -895,15 +898,17 @@ static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
list_for_each_entry_safe(concat, next, &concat_list, list) {
list_del(&concat->list);
- elem = set_elem_expr_alloc(&internal_location, concat);
+
+ mapping = mapping_expr_alloc(&internal_location, concat,
+ expr_get(verdict->expr));
+
+ elem = set_elem_expr_alloc(&internal_location, mapping);
if (counter) {
counter_elem = counter_stmt_alloc(&counter->location);
list_add_tail(&counter_elem->list, &elem->stmt_list);
}
- mapping = mapping_expr_alloc(&internal_location, elem,
- expr_get(verdict->expr));
- set_expr_add(set, mapping);
+ set_expr_add(set, elem);
}
stmt_free(counter);
}
@@ -1064,9 +1069,9 @@ static void merge_nat(const struct optimize_ctx *ctx,
nat_stmt = ctx->stmt_matrix[i][k];
nat_expr = stmt_nat_expr(nat_stmt);
- elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
- mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
- set_expr_add(set, mapping);
+ mapping = mapping_expr_alloc(&internal_location, expr_get(expr), nat_expr);
+ elem = set_elem_expr_alloc(&internal_location, mapping);
+ set_expr_add(set, elem);
}
stmt = ctx->stmt_matrix[from][merge->stmt[0]];
@@ -1121,9 +1126,9 @@ static void merge_concat_nat(const struct optimize_ctx *ctx,
nat_stmt = ctx->stmt_matrix[i][k];
nat_expr = stmt_nat_expr(nat_stmt);
- elem = set_elem_expr_alloc(&internal_location, concat);
- mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
- set_expr_add(set, mapping);
+ mapping = mapping_expr_alloc(&internal_location, concat, nat_expr);
+ elem = set_elem_expr_alloc(&internal_location, mapping);
+ set_expr_add(set, elem);
}
concat = concat_expr_alloc(&internal_location);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 74c3d25db4ff..361f43d95104 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -3374,7 +3374,10 @@ verdict_map_list_expr : verdict_map_list_member_expr
verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline
{
- $$ = mapping_expr_alloc(&@2, $2, $4);
+ struct expr *expr = $2;
+
+ expr->key = mapping_expr_alloc(&@2, $2->key, $4);
+ $$ = expr;
}
;
@@ -4561,7 +4564,10 @@ set_list_member_expr : opt_newline set_expr opt_newline
}
| opt_newline set_elem_expr COLON set_rhs_expr opt_newline
{
- $$ = mapping_expr_alloc(&@2, $2, $4);
+ struct expr *expr = $2;
+
+ expr->key = mapping_expr_alloc(&@2, $2->key, $4);
+ $$ = expr;
}
;
diff --git a/src/parser_json.c b/src/parser_json.c
index 67e4f2c0f1b9..f444b8a0f52f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1480,7 +1480,7 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx,
}
json_array_foreach(root, index, value) {
- struct expr *expr;
+ struct expr *expr, *elem;
json_t *jleft, *jright;
if (!json_unpack(value, "[o, o!]", &jleft, &jright)) {
@@ -1492,8 +1492,13 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx,
expr_free(set_expr);
return NULL;
}
- if (expr->etype != EXPR_SET_ELEM)
- expr = set_elem_expr_alloc(int_loc, expr);
+
+ if (expr->etype != EXPR_SET_ELEM) {
+ elem = set_elem_expr_alloc(int_loc, expr);
+ } else {
+ elem = expr;
+ expr = expr->key;
+ }
expr2 = json_parse_set_rhs_expr(ctx, jright);
if (!expr2) {
@@ -1503,7 +1508,8 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx,
return NULL;
}
expr2 = mapping_expr_alloc(int_loc, expr, expr2);
- expr = expr2;
+ elem->key = expr2;
+ expr = elem;
} else {
expr = json_parse_rhs_expr(ctx, value);
diff --git a/src/segtree.c b/src/segtree.c
index b9d6891e4b8f..6d96b4f8a0a9 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -113,9 +113,10 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
static struct expr *expr_value(struct expr *expr)
{
switch (expr->etype) {
- case EXPR_MAPPING:
- return expr->left->key;
case EXPR_SET_ELEM:
+ if (expr->key->etype == EXPR_MAPPING)
+ return expr->key->left;
+
return expr->key;
case EXPR_VALUE:
return expr;
@@ -167,17 +168,16 @@ out:
static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
{
- struct expr *elem = set_elem_expr_alloc(&low->location, expr);
-
- if (low->etype == EXPR_MAPPING) {
- interval_expr_copy(elem, low->left);
+ struct expr *elem;
- elem = mapping_expr_alloc(&low->location, elem,
- expr_clone(low->right));
- } else {
- interval_expr_copy(elem, low);
+ if (low->key->etype == EXPR_MAPPING) {
+ expr = mapping_expr_alloc(&low->location, expr,
+ expr_clone(low->key->right));
}
+
+ elem = set_elem_expr_alloc(&low->location, expr);
elem->flags |= EXPR_F_KERNEL;
+ interval_expr_copy(elem, low);
return elem;
}
@@ -237,6 +237,8 @@ int get_set_decompose(struct set *cache_set, struct set *set)
new_init = set_expr_alloc(&internal_location, set);
list_for_each_entry_safe(i, next, &expr_set(set->init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
if (i->flags & EXPR_F_INTERVAL_END && left) {
list_del(&left->list);
list_del(&i->list);
@@ -573,13 +575,10 @@ void interval_map_decompose(struct expr *set)
/* Sort elements */
n = 0;
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
- key = NULL;
- if (i->etype == EXPR_SET_ELEM)
- key = i->key;
- else if (i->etype == EXPR_MAPPING)
- key = i->left->key;
+ assert(i->etype == EXPR_SET_ELEM);
- if (key && expr_type_catchall(key)) {
+ key = i->key;
+ if (expr_type_catchall(key)) {
list_del(&i->list);
catchall = i;
continue;
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 02/20] src: allocate EXPR_SET_ELEM for EXPR_SET in embedded set declaration in sets
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 01/20] src: normalize set element with EXPR_MAPPING Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 03/20] src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list Pablo Neira Ayuso
` (18 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Normalize the representation so the expressions list in EXPR_SET always
contains EXPR_SET_ELEM. Add assert() to validate this.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 3 ++-
src/parser_bison.y | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 13e0c6916ac7..e6689adf0880 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2070,7 +2070,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
const struct expr *elem;
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
- /* recursive EXPR_SET are merged here. */
+ assert(i->etype == EXPR_SET_ELEM);
+
if (list_member_evaluate(ctx, &i) < 0)
return -1;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 361f43d95104..6c0e29c82065 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4556,7 +4556,7 @@ set_list_expr : set_list_member_expr
set_list_member_expr : opt_newline set_expr opt_newline
{
- $$ = $2;
+ $$ = set_elem_expr_alloc(&@$, $2);
}
| opt_newline set_elem_expr opt_newline
{
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 03/20] src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 01/20] src: normalize set element with EXPR_MAPPING Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 02/20] src: allocate EXPR_SET_ELEM for EXPR_SET in embedded set declaration in sets Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 04/20] evaluate: simplify sets as set elems evaluation Pablo Neira Ayuso
` (17 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Add assert() to validate that expression lists contain EXPR_SET_ELEM.
This allows to detect potential subtle bugs when dereferencing struct
expr.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 23 +++++++++--------------
src/expression.c | 16 ++++++++++++----
src/intervals.c | 14 ++++++++++++++
src/json.c | 10 ++++++++--
src/netlink.c | 2 ++
src/netlink_delinearize.c | 9 ++++++---
src/optimize.c | 3 +++
src/segtree.c | 6 ++++++
8 files changed, 60 insertions(+), 23 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index e6689adf0880..f0a82a2c46eb 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2080,6 +2080,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
struct expr *new, *j;
list_for_each_entry(j, &expr_set(i->key->left)->expressions, list) {
+ assert(j->etype == EXPR_SET_ELEM);
+
new = mapping_expr_alloc(&i->location,
expr_get(j->key),
expr_get(i->key->right));
@@ -2781,9 +2783,9 @@ static void optimize_singleton_set(struct expr *rel, struct expr **expr)
struct expr *set = rel->right, *i;
i = list_first_entry(&expr_set(set)->expressions, struct expr, list);
- if (i->etype == EXPR_SET_ELEM &&
- list_empty(&i->stmt_list)) {
+ assert (i->etype == EXPR_SET_ELEM);
+ if (list_empty(&i->stmt_list)) {
switch (i->key->etype) {
case EXPR_PREFIX:
case EXPR_RANGE:
@@ -5488,19 +5490,12 @@ static struct expr *expr_set_to_list(struct eval_ctx *ctx, struct expr *dev_expr
LIST_HEAD(tmp);
list_for_each_entry_safe(expr, next, &expr_set(dev_expr)->expressions, list) {
- list_del(&expr->list);
-
- switch (expr->etype) {
- case EXPR_SET_ELEM:
- key = expr_clone(expr->key);
- expr_free(expr);
- expr = key;
- break;
- default:
- BUG("invalid expression type %s", expr_name(expr));
- break;
- }
+ assert(expr->etype == EXPR_SET_ELEM);
+ list_del(&expr->list);
+ key = expr_clone(expr->key);
+ expr_free(expr);
+ expr = key;
list_add(&expr->list, &tmp);
}
diff --git a/src/expression.c b/src/expression.c
index 5aac7165319f..f356cf117307 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -946,8 +946,9 @@ void relational_expr_pctx_update(struct proto_ctx *ctx,
ops->pctx_update(ctx, &expr->location, left, right);
else if (right->etype == EXPR_SET) {
list_for_each_entry(i, &expr_set(right)->expressions, list) {
- if (i->etype == EXPR_SET_ELEM &&
- i->key->etype == EXPR_VALUE)
+ assert(i->etype == EXPR_SET_ELEM);
+
+ if (i->key->etype == EXPR_VALUE)
ops->pctx_update(ctx, &expr->location, left, i->key);
}
} else if (ops == &meta_expr_ops &&
@@ -1384,6 +1385,8 @@ static void set_expr_print(const struct expr *expr, struct output_ctx *octx)
nft_print(octx, "{ ");
list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
nft_print(octx, "%s", d);
expr_print(i, octx);
count++;
@@ -1406,8 +1409,10 @@ static void set_expr_destroy(struct expr *expr)
{
struct expr *i, *next;
- list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list)
+ list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
expr_free(i);
+ }
}
static void set_expr_set_type(const struct expr *expr,
@@ -1416,8 +1421,11 @@ static void set_expr_set_type(const struct expr *expr,
{
struct expr *i;
- list_for_each_entry(i, &expr_set(expr)->expressions, list)
+ list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
expr_set_type(i, dtype, byteorder);
+ }
}
static const struct expr_ops set_expr_ops = {
diff --git a/src/intervals.c b/src/intervals.c
index 9ab2cc20533a..ec4435e08690 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -183,6 +183,8 @@ static void setelem_automerge(struct set_automerge_ctx *ctx)
mpz_init(rop);
list_for_each_entry_safe(i, next, &expr_set(ctx->init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
if (expr_type_catchall(i->key))
continue;
@@ -243,6 +245,8 @@ static void set_to_range(struct expr *init)
struct expr *i, *elem;
list_for_each_entry(i, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
elem = interval_expr_key(i);
setelem_expr_to_range(elem);
}
@@ -274,6 +278,8 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
setelem_automerge(&ctx);
list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
if (i->flags & EXPR_F_KERNEL) {
list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
} else if (existing_set) {
@@ -413,6 +419,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
mpz_init(rop);
list_for_each_entry_safe(elem, next, &expr_set(elems)->expressions, list) {
+ assert(elem->etype == EXPR_SET_ELEM);
+
i = interval_expr_key(elem);
if (expr_type_catchall(i->key)) {
@@ -585,6 +593,8 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
mpz_init(rop);
list_for_each_entry_safe(elem, next, &expr_set(init)->expressions, list) {
+ assert(elem->etype == EXPR_SET_ELEM);
+
i = interval_expr_key(elem);
if (expr_type_catchall(i->key))
@@ -654,6 +664,8 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
err = setelem_overlap(msgs, set, init);
list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
if (i->flags & EXPR_F_KERNEL)
list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
else if (existing_set) {
@@ -711,6 +723,8 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
mpz_t p;
list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
elem = interval_expr_key(i);
if (expr_type_catchall(elem->key))
diff --git a/src/json.c b/src/json.c
index 937a82dc19e9..3c369fb916d0 100644
--- a/src/json.c
+++ b/src/json.c
@@ -232,8 +232,11 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
json_t *array = json_array();
const struct expr *i;
- list_for_each_entry(i, &expr_set(set->init)->expressions, list)
+ list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
json_array_append_new(array, expr_print_json(i, octx));
+ }
json_object_set_new(root, "elem", array);
}
@@ -768,8 +771,11 @@ json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx)
json_t *array = json_array();
const struct expr *i;
- list_for_each_entry(i, &expr_set(expr)->expressions, list)
+ list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
json_array_append_new(array, expr_print_json(i, octx));
+ }
return nft_json_pack("{s:o}", "set", array);
}
diff --git a/src/netlink.c b/src/netlink.c
index 3a28978547c3..34c667995489 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1309,6 +1309,8 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
const struct expr *expr;
list_for_each_entry(expr, &expr_set(set)->expressions, list) {
+ assert(expr->etype == EXPR_SET_ELEM);
+
nlse = alloc_nftnl_setelem(set, expr);
nftnl_set_elem_add(nls, nlse);
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index fc359d6d9294..81763206f136 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2206,9 +2206,9 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
struct expr *elem;
elem = list_first_entry(&expr_set(set->init)->expressions, struct expr, list);
+ assert(elem->etype == EXPR_SET_ELEM);
- if (elem->etype == EXPR_SET_ELEM &&
- elem->key->etype == EXPR_VALUE)
+ if (elem->key->etype == EXPR_VALUE)
payload_icmp_check(ctx, payload, elem->key);
}
}
@@ -2883,8 +2883,11 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_postprocess(ctx, &expr->right);
break;
case EXPR_SET:
- list_for_each_entry(i, &expr_set(expr)->expressions, list)
+ list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
expr_postprocess(ctx, &i);
+ }
break;
case EXPR_CONCAT:
expr_postprocess_concat(ctx, exprp);
diff --git a/src/optimize.c b/src/optimize.c
index 3e6e24cf7b90..a2bd3aab72d0 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -594,6 +594,7 @@ static void merge_vmap(const struct optimize_ctx *ctx,
mappings = stmt_b->expr->mappings;
list_for_each_entry(expr, &expr_set(mappings)->expressions, list) {
+ assert(expr->etype == EXPR_SET_ELEM);
mapping = expr_clone(expr);
set_expr_add(stmt_a->expr->mappings, mapping);
}
@@ -660,6 +661,7 @@ static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i,
switch (stmt_a->expr->right->etype) {
case EXPR_SET:
list_for_each_entry(expr, &expr_set(stmt_a->expr->right)->expressions, list) {
+ assert(expr->etype == EXPR_SET_ELEM);
concat_clone = expr_clone(concat);
clone = expr_clone(expr->key);
concat_expr_add(concat_clone, clone);
@@ -771,6 +773,7 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
break;
case EXPR_SET:
list_for_each_entry(item, &expr_set(expr)->expressions, list) {
+ assert(item->etype == EXPR_SET_ELEM);
mapping = mapping_expr_alloc(&internal_location, expr_get(item->key),
expr_get(verdict->expr));
diff --git a/src/segtree.c b/src/segtree.c
index 6d96b4f8a0a9..90e4a616edf0 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -80,6 +80,8 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
new_init = set_expr_alloc(&internal_location, NULL);
list_for_each_entry(i, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
switch (i->key->etype) {
case EXPR_VALUE:
set_elem_add(set, new_init, i->key->value,
@@ -137,6 +139,8 @@ static struct expr *get_set_interval_find(const struct set *cache_set,
mpz_init2(val, set->key->len);
list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
key = expr_value(i);
switch (key->etype) {
case EXPR_VALUE:
@@ -357,6 +361,8 @@ void concat_range_aggregate(struct expr *set)
mpz_t range, p;
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
+
if (!start) {
start = i;
continue;
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 04/20] evaluate: simplify sets as set elems evaluation
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (2 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 03/20] src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 05/20] evaluate: clean up expr_evaluate_set() Pablo Neira Ayuso
` (16 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
After normalizing set element representation for EXPR_MAPPING, it is
possible to simplify:
a6b75b837f5e ("evaluate: set: Allow for set elems to be sets")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index f0a82a2c46eb..556664d640a3 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2101,27 +2101,17 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx->msgs, i,
"Set reference cannot be part of another set");
- if (elem->etype == EXPR_SET_ELEM &&
- elem->key->etype == EXPR_SET) {
- struct expr *new = expr_get(elem->key);
-
- expr_set(set)->set_flags |= expr_set(elem->key)->set_flags;
- list_replace(&i->list, &new->list);
- expr_free(i);
- i = new;
- elem = i;
- }
-
if (!expr_is_constant(i))
return expr_error(ctx->msgs, i,
"Set member is not constant");
- if (i->etype == EXPR_SET) {
+ if (i->etype == EXPR_SET_ELEM &&
+ i->key->etype == EXPR_SET) {
/* Merge recursive set definitions */
- list_splice_tail_init(&expr_set(i)->expressions, &i->list);
+ list_splice_tail_init(&expr_set(i->key)->expressions, &i->list);
list_del(&i->list);
- expr_set(set)->size += expr_set(i)->size - 1;
- expr_set(set)->set_flags |= expr_set(i)->set_flags;
+ expr_set(set)->size += expr_set(i->key)->size - 1;
+ expr_set(set)->set_flags |= expr_set(i->key)->set_flags;
expr_free(i);
} else if (!expr_is_singleton(i)) {
expr_set(set)->set_flags |= NFT_SET_INTERVAL;
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 05/20] evaluate: clean up expr_evaluate_set()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (3 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 04/20] evaluate: simplify sets as set elems evaluation Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 06/20] segtree: rename set_elem_add() to set_elem_expr_add() Pablo Neira Ayuso
` (15 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Remove redundant check for elem->etype == EXPR_SET_ELEM, assert()
already validates this at the beginning of the loop.
Remove redundant pointer to set element, use iterator index instead.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 556664d640a3..7caa161bbe23 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2067,7 +2067,6 @@ static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr)
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
- const struct expr *elem;
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
@@ -2094,10 +2093,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
continue;
}
- elem = i;
-
- if (elem->etype == EXPR_SET_ELEM &&
- elem->key->etype == EXPR_SET_REF)
+ if (i->key->etype == EXPR_SET_REF)
return expr_error(ctx->msgs, i,
"Set reference cannot be part of another set");
@@ -2105,8 +2101,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx->msgs, i,
"Set member is not constant");
- if (i->etype == EXPR_SET_ELEM &&
- i->key->etype == EXPR_SET) {
+ if (i->key->etype == EXPR_SET) {
/* Merge recursive set definitions */
list_splice_tail_init(&expr_set(i->key)->expressions, &i->list);
list_del(&i->list);
@@ -2115,9 +2110,9 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
expr_free(i);
} else if (!expr_is_singleton(i)) {
expr_set(set)->set_flags |= NFT_SET_INTERVAL;
- if ((elem->key->etype == EXPR_MAPPING &&
- elem->key->left->etype == EXPR_CONCAT) ||
- elem->key->etype == EXPR_CONCAT)
+ if ((i->key->etype == EXPR_MAPPING &&
+ i->key->left->etype == EXPR_CONCAT) ||
+ i->key->etype == EXPR_CONCAT)
expr_set(set)->set_flags |= NFT_SET_CONCAT;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 06/20] segtree: rename set_elem_add() to set_elem_expr_add()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (4 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 05/20] evaluate: clean up expr_evaluate_set() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 07/20] src: move flags from EXPR_SET_ELEM to key Pablo Neira Ayuso
` (14 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Just a clean up, to prepare for the introduction of struct set_elem
that will provide a set_elem_add() function again.
Rename it now to leave room for such future change.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 90e4a616edf0..bf543b9b91ab 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -53,8 +53,8 @@ static void interval_expr_copy(struct expr *dst, struct expr *src)
list_splice_init(&src->stmt_list, &dst->stmt_list);
}
-static void set_elem_add(const struct set *set, struct expr *init, mpz_t value,
- uint32_t flags, enum byteorder byteorder)
+static void set_elem_expr_add(const struct set *set, struct expr *init,
+ mpz_t value, uint32_t flags, enum byteorder byteorder)
{
struct expr *expr;
@@ -84,8 +84,8 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
switch (i->key->etype) {
case EXPR_VALUE:
- set_elem_add(set, new_init, i->key->value,
- i->flags, byteorder);
+ set_elem_expr_add(set, new_init, i->key->value,
+ i->flags, byteorder);
break;
case EXPR_CONCAT:
set_expr_add(new_init, expr_clone(i));
@@ -97,11 +97,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
break;
default:
range_expr_value_low(low, i);
- set_elem_add(set, new_init, low, 0, i->byteorder);
+ set_elem_expr_add(set, new_init, low, 0, i->byteorder);
range_expr_value_high(high, i);
mpz_add_ui(high, high, 1);
- set_elem_add(set, new_init, high,
- EXPR_F_INTERVAL_END, i->byteorder);
+ set_elem_expr_add(set, new_init, high,
+ EXPR_F_INTERVAL_END, i->byteorder);
break;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 07/20] src: move flags from EXPR_SET_ELEM to key
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (5 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 06/20] segtree: rename set_elem_add() to set_elem_expr_add() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 08/20] src: remove EXPR_SET_ELEM in range_expr_value_{low,high}() Pablo Neira Ayuso
` (13 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
This is to prepare to replace EXPR_SET_ELEM by struct set_elem.
Check that expr->flags for EXPR_SET_ELEM are zero from
set_elem_expr_destroy() to validate that there are no more users.
Only EXPR_F_KERNEL is taken in interval.c when converting to constant,
prefix and range in __setelem_expr_to_range().
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 13 +++++----
src/expression.c | 2 ++
src/intervals.c | 69 +++++++++++++++++++++++++-----------------------
src/monitor.c | 2 +-
src/netlink.c | 12 ++++-----
src/segtree.c | 26 +++++++++---------
6 files changed, 64 insertions(+), 60 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 7caa161bbe23..3b6008149801 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1896,7 +1896,7 @@ static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem)
struct stmt *set_stmt, *elem_stmt;
if (num_set_exprs > 0 && num_elem_exprs != num_set_exprs) {
- return expr_error(ctx->msgs, elem,
+ return expr_error(ctx->msgs, elem->key,
"number of statements mismatch, set expects %d "
"but element has %d", num_set_exprs,
num_elem_exprs);
@@ -1992,14 +1992,13 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
}
if (ctx->set && !elem_key_compatible(ctx->set->key, elem->key))
- return expr_error(ctx->msgs, elem,
+ return expr_error(ctx->msgs, elem->key,
"Element mismatches %s definition, expected %s, not '%s'",
set_is_map(ctx->set->flags) ? "map" : "set",
ctx->set->key->dtype->desc, elem->key->dtype->desc);
datatype_set(elem, elem->key->dtype);
elem->len = elem->key->len;
- elem->flags = elem->key->flags;
return 0;
@@ -2094,11 +2093,11 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
}
if (i->key->etype == EXPR_SET_REF)
- return expr_error(ctx->msgs, i,
+ return expr_error(ctx->msgs, i->key,
"Set reference cannot be part of another set");
- if (!expr_is_constant(i))
- return expr_error(ctx->msgs, i,
+ if (!expr_is_constant(i->key))
+ return expr_error(ctx->msgs, i->key,
"Set member is not constant");
if (i->key->etype == EXPR_SET) {
@@ -2108,7 +2107,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
expr_set(set)->size += expr_set(i->key)->size - 1;
expr_set(set)->set_flags |= expr_set(i->key)->set_flags;
expr_free(i);
- } else if (!expr_is_singleton(i)) {
+ } else if (!expr_is_singleton(i->key)) {
expr_set(set)->set_flags |= NFT_SET_INTERVAL;
if ((i->key->etype == EXPR_MAPPING &&
i->key->left->etype == EXPR_CONCAT) ||
diff --git a/src/expression.c b/src/expression.c
index f356cf117307..fac4901d8ecc 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1704,6 +1704,8 @@ static void set_elem_expr_destroy(struct expr *expr)
{
struct stmt *stmt, *next;
+ assert(expr->flags == 0);
+
free_const(expr->comment);
expr_free(expr->key);
list_for_each_entry_safe(stmt, next, &expr->stmt_list, list)
diff --git a/src/intervals.c b/src/intervals.c
index ec4435e08690..0a1e8fc79ecd 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -31,6 +31,7 @@ static void __setelem_expr_to_range(struct expr **exprp)
expr->len,
expr->left->value,
expr->right->value);
+ key->flags |= expr->flags & EXPR_F_KERNEL;
expr_free(*exprp);
*exprp = key;
break;
@@ -50,6 +51,7 @@ static void __setelem_expr_to_range(struct expr **exprp)
expr->len,
expr->prefix->value,
rop);
+ key->flags |= expr->flags & EXPR_F_KERNEL;
mpz_clear(rop);
expr_free(*exprp);
*exprp = key;
@@ -64,6 +66,7 @@ static void __setelem_expr_to_range(struct expr **exprp)
expr->len,
expr->value,
expr->value);
+ key->flags |= expr->flags & EXPR_F_KERNEL;
expr_free(*exprp);
*exprp = key;
break;
@@ -102,7 +105,7 @@ static void purge_elem(struct set_automerge_ctx *ctx, struct expr *i)
static void remove_overlapping_range(struct set_automerge_ctx *ctx,
struct expr *prev, struct expr *i)
{
- if (i->flags & EXPR_F_KERNEL) {
+ if (i->key->flags & EXPR_F_KERNEL) {
i->location = prev->location;
purge_elem(ctx, i);
return;
@@ -121,13 +124,13 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
struct expr *prev, struct expr *i,
struct range *prev_range, struct range *range)
{
- if (prev->flags & EXPR_F_KERNEL) {
+ if (prev->key->flags & EXPR_F_KERNEL) {
prev->location = i->location;
purge_elem(ctx, prev);
mpz_set(i->key->range.low, prev->key->range.low);
mpz_set(prev_range->high, range->high);
return true;
- } else if (i->flags & EXPR_F_KERNEL) {
+ } else if (i->key->flags & EXPR_F_KERNEL) {
i->location = prev->location;
purge_elem(ctx, i);
mpz_set(prev->key->range.high, i->key->range.high);
@@ -280,7 +283,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
- if (i->flags & EXPR_F_KERNEL) {
+ if (i->key->flags & EXPR_F_KERNEL) {
list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
} else if (existing_set) {
if (debug_mask & NFT_DEBUG_SEGTREE) {
@@ -288,7 +291,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
i->key->range.low, i->key->range.high);
}
clone = expr_clone(i);
- clone->flags |= EXPR_F_KERNEL;
+ clone->key->flags |= EXPR_F_KERNEL;
__set_expr_add(existing_set->init, clone);
}
}
@@ -310,7 +313,7 @@ static void remove_elem(struct expr *prev, struct set *set, struct expr *purge)
{
struct expr *clone;
- if (prev->flags & EXPR_F_KERNEL) {
+ if (prev->key->flags & EXPR_F_KERNEL) {
clone = expr_clone(prev);
list_move_tail(&clone->list, &expr_set(purge)->expressions);
}
@@ -318,7 +321,7 @@ static void remove_elem(struct expr *prev, struct set *set, struct expr *purge)
static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i)
{
- prev->flags &= ~EXPR_F_KERNEL;
+ prev->key->flags &= ~EXPR_F_KERNEL;
mpz_set(prev->key->range.low, i->key->range.high);
mpz_add_ui(prev->key->range.low, prev->key->range.low, 1);
list_move(&prev->list, &expr_set(set->existing_set->init)->expressions);
@@ -337,7 +340,7 @@ static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i)
{
- prev->flags &= ~EXPR_F_KERNEL;
+ prev->key->flags &= ~EXPR_F_KERNEL;
mpz_set(prev->key->range.high, i->key->range.low);
mpz_sub_ui(prev->key->range.high, prev->key->range.high, 1);
list_move(&prev->list, &expr_set(set->existing_set->init)->expressions);
@@ -361,12 +364,12 @@ static void split_range(struct set *set, struct expr *prev, struct expr *i,
prev->location = i->location;
- if (prev->flags & EXPR_F_KERNEL) {
+ if (prev->key->flags & EXPR_F_KERNEL) {
clone = expr_clone(prev);
list_move_tail(&clone->list, &expr_set(purge)->expressions);
}
- prev->flags &= ~EXPR_F_KERNEL;
+ prev->key->flags &= ~EXPR_F_KERNEL;
clone = expr_clone(prev);
mpz_set(clone->key->range.low, i->key->range.high);
mpz_add_ui(clone->key->range.low, i->key->range.high, 1);
@@ -386,15 +389,15 @@ static int setelem_adjust(struct set *set, struct expr *purge,
{
if (mpz_cmp(prev_range->low, range->low) == 0 &&
mpz_cmp(prev_range->high, range->high) > 0) {
- if (i->flags & EXPR_F_REMOVE)
+ if (i->key->flags & EXPR_F_REMOVE)
adjust_elem_left(set, prev, i, purge);
} else if (mpz_cmp(prev_range->low, range->low) < 0 &&
mpz_cmp(prev_range->high, range->high) == 0) {
- if (i->flags & EXPR_F_REMOVE)
+ if (i->key->flags & EXPR_F_REMOVE)
adjust_elem_right(set, prev, i, purge);
} else if (mpz_cmp(prev_range->low, range->low) < 0 &&
mpz_cmp(prev_range->high, range->high) > 0) {
- if (i->flags & EXPR_F_REMOVE)
+ if (i->key->flags & EXPR_F_REMOVE)
split_range(set, prev, i, purge);
} else {
return -1;
@@ -440,13 +443,13 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
range_expr_value_high(range.high, i);
}
- if (!prev && elem->flags & EXPR_F_REMOVE) {
+ if (!prev && elem->key->flags & EXPR_F_REMOVE) {
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
}
- if (!(elem->flags & EXPR_F_REMOVE)) {
+ if (!(elem->key->flags & EXPR_F_REMOVE)) {
prev = elem;
mpz_set(prev_range.low, range.low);
mpz_set(prev_range.high, range.high);
@@ -455,8 +458,8 @@ 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 (elem->flags & EXPR_F_REMOVE) {
- if (prev->flags & EXPR_F_KERNEL) {
+ if (elem->key->flags & EXPR_F_REMOVE) {
+ if (prev->key->flags & EXPR_F_KERNEL) {
prev->location = elem->location;
list_move_tail(&prev->list, &expr_set(purge)->expressions);
}
@@ -470,7 +473,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
err = -1;
goto err;
}
- } else if (elem->flags & EXPR_F_REMOVE) {
+ } else if (elem->key->flags & EXPR_F_REMOVE) {
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
@@ -506,7 +509,7 @@ static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set,
struct expr *init, struct set *existing_set,
unsigned int debug_mask)
{
- i->flags |= EXPR_F_REMOVE;
+ i->key->flags |= EXPR_F_REMOVE;
list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
list_expr_sort(&expr_set(existing_set->init)->expressions);
@@ -546,10 +549,10 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
add = set_expr_alloc(&internal_location, set);
list_for_each_entry(i, &expr_set(existing_set->init)->expressions, list) {
- if (!(i->flags & EXPR_F_KERNEL)) {
+ if (!(i->key->flags & EXPR_F_KERNEL)) {
clone = expr_clone(i);
__set_expr_add(add, clone);
- i->flags |= EXPR_F_KERNEL;
+ i->key->flags |= EXPR_F_KERNEL;
}
}
@@ -616,9 +619,9 @@ static int setelem_overlap(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 (prev->flags & EXPR_F_KERNEL)
+ if (prev->key->flags & EXPR_F_KERNEL)
expr_error(msgs, i, "interval overlaps with an existing one");
- else if (elem->flags & EXPR_F_KERNEL)
+ else if (elem->key->flags & EXPR_F_KERNEL)
expr_error(msgs, prev, "interval overlaps with an existing one");
else
expr_binary_error(msgs, i, prev,
@@ -626,9 +629,9 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
err = -1;
goto err_out;
} else if (mpz_cmp(range.low, prev_range.high) <= 0) {
- if (prev->flags & EXPR_F_KERNEL)
+ if (prev->key->flags & EXPR_F_KERNEL)
expr_error(msgs, i, "interval overlaps with an existing one");
- else if (elem->flags & EXPR_F_KERNEL)
+ else if (elem->key->flags & EXPR_F_KERNEL)
expr_error(msgs, prev, "interval overlaps with an existing one");
else
expr_binary_error(msgs, i, prev,
@@ -666,11 +669,11 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
- if (i->flags & EXPR_F_KERNEL)
+ if (i->key->flags & EXPR_F_KERNEL)
list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
else if (existing_set) {
clone = expr_clone(i);
- clone->flags |= EXPR_F_KERNEL;
+ clone->key->flags |= EXPR_F_KERNEL;
__set_expr_add(existing_set->init, clone);
}
}
@@ -745,7 +748,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
root = set_elem_expr_alloc(&internal_location, expr);
- root->flags |= EXPR_F_INTERVAL_END;
+ root->key->flags |= EXPR_F_INTERVAL_END;
list_add(&root->list, &intervals);
break;
}
@@ -821,7 +824,7 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
assert(!next_key || next_key->etype == EXPR_RANGE_VALUE);
/* skip end element for adjacents intervals in anonymous sets. */
- if (!(elem->flags & EXPR_F_INTERVAL_END) && next_key) {
+ if (!(elem->key->flags & EXPR_F_INTERVAL_END) && next_key) {
mpz_t p;
mpz_init2(p, set->key->len);
@@ -848,11 +851,11 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
if (adjacent)
return 0;
- else if (!mpz_cmp_ui(key->value, 0) && elem->flags & EXPR_F_INTERVAL_END) {
- low->flags |= EXPR_F_INTERVAL_END;
+ else if (!mpz_cmp_ui(key->value, 0) && elem->key->flags & EXPR_F_INTERVAL_END) {
+ low->key->flags |= EXPR_F_INTERVAL_END;
return 0;
} else if (mpz_scan0(key->range.high, 0) == set->key->len) {
- low->flags |= EXPR_F_INTERVAL_OPEN;
+ low->key->flags |= EXPR_F_INTERVAL_OPEN;
return 0;
}
@@ -865,7 +868,7 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
high = set_elem_expr_alloc(&key->location, high);
- high->flags |= EXPR_F_INTERVAL_END;
+ high->key->flags |= EXPR_F_INTERVAL_END;
list_add_tail(&high->list, intervals);
return 0;
diff --git a/src/monitor.c b/src/monitor.c
index 6532c9c50f8d..e5803e32a467 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -380,7 +380,7 @@ static bool set_elem_is_open_interval(struct expr *elem)
{
switch (elem->etype) {
case EXPR_SET_ELEM:
- return elem->flags & EXPR_F_INTERVAL_OPEN;
+ return elem->key->flags & EXPR_F_INTERVAL_OPEN;
case EXPR_MAPPING:
return set_elem_is_open_interval(elem->left);
default:
diff --git a/src/netlink.c b/src/netlink.c
index 34c667995489..5e59cb7b2d8f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -186,7 +186,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
netlink_gen_stmt_stateful(stmt));
}
}
- if (elem->comment || expr->flags & EXPR_F_INTERVAL_OPEN) {
+ if (elem->comment || expr->key->flags & EXPR_F_INTERVAL_OPEN) {
udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udbuf)
memory_allocation_error();
@@ -196,7 +196,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
elem->comment))
memory_allocation_error();
}
- if (expr->flags & EXPR_F_INTERVAL_OPEN) {
+ if (expr->key->flags & EXPR_F_INTERVAL_OPEN) {
if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_ELEM_FLAGS,
NFTNL_SET_ELEM_F_INTERVAL_OPEN))
memory_allocation_error();
@@ -239,7 +239,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
nld.value, nld.len);
}
- if (expr->flags & EXPR_F_INTERVAL_END)
+ if (expr->key->flags & EXPR_F_INTERVAL_END)
flags |= NFT_SET_ELEM_INTERVAL_END;
if (key->etype == EXPR_SET_ELEM_CATCHALL)
flags |= NFT_SET_ELEM_CATCHALL;
@@ -1556,7 +1556,7 @@ static void set_elem_parse_udata(struct nftnl_set_elem *nlse,
elem_flags =
nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_ELEM_FLAGS]);
if (elem_flags & NFTNL_SET_ELEM_F_INTERVAL_OPEN)
- expr->flags |= EXPR_F_INTERVAL_OPEN;
+ expr->key->flags |= EXPR_F_INTERVAL_OPEN;
}
}
@@ -1653,7 +1653,7 @@ key_end:
}
out:
expr = set_elem_expr_alloc(&netlink_location, key);
- expr->flags |= EXPR_F_KERNEL;
+ expr->key->flags |= EXPR_F_KERNEL;
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) {
expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
@@ -1682,7 +1682,7 @@ out:
list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
if (flags & NFT_SET_ELEM_INTERVAL_END) {
- expr->flags |= EXPR_F_INTERVAL_END;
+ expr->key->flags |= EXPR_F_INTERVAL_END;
if (mpz_cmp_ui(set->key->value, 0) == 0)
set->root = true;
}
diff --git a/src/segtree.c b/src/segtree.c
index bf543b9b91ab..37bdcb5867cf 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -62,7 +62,7 @@ static void set_elem_expr_add(const struct set *set, struct expr *init,
byteorder, set->key->len, NULL);
mpz_set(expr->value, value);
expr = set_elem_expr_alloc(&internal_location, expr);
- expr->flags = flags;
+ expr->key->flags = flags;
set_expr_add(init, expr);
}
@@ -85,11 +85,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
switch (i->key->etype) {
case EXPR_VALUE:
set_elem_expr_add(set, new_init, i->key->value,
- i->flags, byteorder);
+ i->key->flags, byteorder);
break;
case EXPR_CONCAT:
set_expr_add(new_init, expr_clone(i));
- i->flags |= EXPR_F_INTERVAL_END;
+ i->key->flags |= EXPR_F_INTERVAL_END;
set_expr_add(new_init, expr_clone(i));
break;
case EXPR_SET_ELEM_CATCHALL:
@@ -180,7 +180,7 @@ static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
}
elem = set_elem_expr_alloc(&low->location, expr);
- elem->flags |= EXPR_F_KERNEL;
+ elem->key->flags |= EXPR_F_KERNEL;
interval_expr_copy(elem, low);
return elem;
@@ -243,7 +243,7 @@ int get_set_decompose(struct set *cache_set, struct set *set)
list_for_each_entry_safe(i, next, &expr_set(set->init)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
- if (i->flags & EXPR_F_INTERVAL_END && left) {
+ if (i->key->flags & EXPR_F_INTERVAL_END && left) {
list_del(&left->list);
list_del(&i->list);
mpz_sub_ui(i->key->value, i->key->value, 1);
@@ -314,9 +314,9 @@ static int expr_value_cmp(const void *p1, const void *p2)
ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value);
if (ret == 0) {
- if (e1->flags & EXPR_F_INTERVAL_END)
+ if (e1->key->flags & EXPR_F_INTERVAL_END)
return -1;
- else if (e2->flags & EXPR_F_INTERVAL_END)
+ else if (e2->key->flags & EXPR_F_INTERVAL_END)
return 1;
}
@@ -546,7 +546,7 @@ add_interval(struct expr *set, struct expr *low, struct expr *i)
if (expr_basetype(low)->type == TYPE_STRING)
mpz_switch_byteorder(expr_value(low)->value,
expr_value(low)->len / BITS_PER_BYTE);
- low->flags |= EXPR_F_KERNEL;
+ low->key->flags |= EXPR_F_KERNEL;
expr = expr_get(low);
} else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
@@ -601,11 +601,11 @@ void interval_map_decompose(struct expr *set)
for (m = 0; m < size; m++) {
i = elements[m];
- if (i->flags & EXPR_F_INTERVAL_END)
+ if (i->key->flags & EXPR_F_INTERVAL_END)
interval = false;
else if (interval) {
end = expr_clone(i);
- end->flags |= EXPR_F_INTERVAL_END;
+ end->key->flags |= EXPR_F_INTERVAL_END;
ranges[n++] = end;
} else
interval = true;
@@ -618,7 +618,7 @@ void interval_map_decompose(struct expr *set)
i = ranges[n];
if (low == NULL) {
- if (i->flags & EXPR_F_INTERVAL_END) {
+ if (i->key->flags & EXPR_F_INTERVAL_END) {
/*
* End of interval mark
*/
@@ -635,7 +635,7 @@ void interval_map_decompose(struct expr *set)
add_interval(set, low, i);
- if (i->flags & EXPR_F_INTERVAL_END) {
+ if (i->key->flags & EXPR_F_INTERVAL_END) {
expr_free(low);
low = NULL;
}
@@ -660,7 +660,7 @@ void interval_map_decompose(struct expr *set)
out:
if (catchall) {
- catchall->flags |= EXPR_F_KERNEL;
+ catchall->key->flags |= EXPR_F_KERNEL;
set_expr_add(set, catchall);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 08/20] src: remove EXPR_SET_ELEM in range_expr_value_{low,high}()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (6 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 07/20] src: move flags from EXPR_SET_ELEM to key Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 09/20] src: use key location to prepare removal of EXPR_SET_ELEM Pablo Neira Ayuso
` (12 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Call range_expr_value_{low,high}() with the key instead to skip one
level of indirection.
This is to prepare for the future removal of EXPR_SET_ELEM.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/expression.c | 4 ----
src/intervals.c | 12 ++++++------
src/segtree.c | 8 ++++----
3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/src/expression.c b/src/expression.c
index fac4901d8ecc..415d678ba2e3 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1799,8 +1799,6 @@ void range_expr_value_low(mpz_t rop, const struct expr *expr)
return range_expr_value_low(rop, expr->left);
case EXPR_MAPPING:
return range_expr_value_low(rop, expr->left);
- case EXPR_SET_ELEM:
- return range_expr_value_low(rop, expr->key);
default:
BUG("invalid range expression type %s", expr_name(expr));
}
@@ -1826,8 +1824,6 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
return range_expr_value_high(rop, expr->right);
case EXPR_MAPPING:
return range_expr_value_high(rop, expr->left);
- case EXPR_SET_ELEM:
- return range_expr_value_high(rop, expr->key);
default:
BUG("invalid range expression type %s", expr_name(expr));
}
diff --git a/src/intervals.c b/src/intervals.c
index 0a1e8fc79ecd..4f15095c4bb4 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -191,8 +191,8 @@ static void setelem_automerge(struct set_automerge_ctx *ctx)
if (expr_type_catchall(i->key))
continue;
- range_expr_value_low(range.low, i);
- range_expr_value_high(range.high, i);
+ range_expr_value_low(range.low, i->key);
+ range_expr_value_high(range.high, i->key);
if (!prev) {
set_prev_elem(&prev, i, &prev_range, &range);
@@ -439,8 +439,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
mpz_bitmask(range.low, len);
mpz_bitmask(range.high, len);
} else {
- range_expr_value_low(range.low, i);
- range_expr_value_high(range.high, i);
+ range_expr_value_low(range.low, i->key);
+ range_expr_value_high(range.high, i->key);
}
if (!prev && elem->key->flags & EXPR_F_REMOVE) {
@@ -603,8 +603,8 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
if (expr_type_catchall(i->key))
continue;
- range_expr_value_low(range.low, i);
- range_expr_value_high(range.high, i);
+ range_expr_value_low(range.low, i->key);
+ range_expr_value_high(range.high, i->key);
if (!prev) {
prev = elem;
diff --git a/src/segtree.c b/src/segtree.c
index 37bdcb5867cf..5e03122ebfb7 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -96,9 +96,9 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
set_expr_add(new_init, expr_clone(i));
break;
default:
- range_expr_value_low(low, i);
+ range_expr_value_low(low, i->key);
set_elem_expr_add(set, new_init, low, 0, i->byteorder);
- range_expr_value_high(high, i);
+ range_expr_value_high(high, i->key);
mpz_add_ui(high, high, 1);
set_elem_expr_add(set, new_init, high,
EXPR_F_INTERVAL_END, i->byteorder);
@@ -150,11 +150,11 @@ static struct expr *get_set_interval_find(const struct set *cache_set,
/* fall-through */
case EXPR_PREFIX:
case EXPR_RANGE:
- range_expr_value_low(val, i);
+ range_expr_value_low(val, i->key);
if (left && mpz_cmp(expr_value(left)->value, val))
break;
- range_expr_value_high(val, i);
+ range_expr_value_high(val, i->key);
if (right && mpz_cmp(expr_value(right)->value, val))
break;
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 09/20] src: use key location to prepare removal of EXPR_SET_ELEM
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (7 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 08/20] src: remove EXPR_SET_ELEM in range_expr_value_{low,high}() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 10/20] intervals: remove interval_expr_key() Pablo Neira Ayuso
` (11 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Again, to prepare for the removal of EXPR_SET_ELEM, use the key
location instead.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/intervals.c | 32 ++++++++++++++++----------------
src/mergesort.c | 8 ++++----
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index 4f15095c4bb4..bf0c5573ee1d 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -106,7 +106,7 @@ static void remove_overlapping_range(struct set_automerge_ctx *ctx,
struct expr *prev, struct expr *i)
{
if (i->key->flags & EXPR_F_KERNEL) {
- i->location = prev->location;
+ i->key->location = prev->key->location;
purge_elem(ctx, i);
return;
}
@@ -125,13 +125,13 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
struct range *prev_range, struct range *range)
{
if (prev->key->flags & EXPR_F_KERNEL) {
- prev->location = i->location;
+ prev->key->location = i->key->location;
purge_elem(ctx, prev);
mpz_set(i->key->range.low, prev->key->range.low);
mpz_set(prev_range->high, range->high);
return true;
} else if (i->key->flags & EXPR_F_KERNEL) {
- i->location = prev->location;
+ i->key->location = prev->key->location;
purge_elem(ctx, i);
mpz_set(prev->key->range.high, i->key->range.high);
mpz_set(prev_range->high, range->high);
@@ -330,7 +330,7 @@ static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *
static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
struct expr *purge)
{
- prev->location = i->location;
+ prev->key->location = i->key->location;
remove_elem(prev, set, purge);
__adjust_elem_left(set, prev, i);
@@ -349,7 +349,7 @@ static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr
static void adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
struct expr *purge)
{
- prev->location = i->location;
+ prev->key->location = i->key->location;
remove_elem(prev, set, purge);
__adjust_elem_right(set, prev, i);
@@ -362,7 +362,7 @@ static void split_range(struct set *set, struct expr *prev, struct expr *i,
{
struct expr *clone;
- prev->location = i->location;
+ prev->key->location = i->key->location;
if (prev->key->flags & EXPR_F_KERNEL) {
clone = expr_clone(prev);
@@ -444,7 +444,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
}
if (!prev && elem->key->flags & EXPR_F_REMOVE) {
- expr_error(msgs, i, "element does not exist");
+ expr_error(msgs, i->key, "element does not exist");
err = -1;
goto err;
}
@@ -460,7 +460,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
mpz_cmp(prev_range.high, range.high) == 0) {
if (elem->key->flags & EXPR_F_REMOVE) {
if (prev->key->flags & EXPR_F_KERNEL) {
- prev->location = elem->location;
+ prev->key->location = elem->key->location;
list_move_tail(&prev->list, &expr_set(purge)->expressions);
}
@@ -469,12 +469,12 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
}
} else if (set->automerge) {
if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
- expr_error(msgs, i, "element does not exist");
+ expr_error(msgs, i->key, "element does not exist");
err = -1;
goto err;
}
} else if (elem->key->flags & EXPR_F_REMOVE) {
- expr_error(msgs, i, "element does not exist");
+ expr_error(msgs, i->key, "element does not exist");
err = -1;
goto err;
}
@@ -620,21 +620,21 @@ static int setelem_overlap(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 (prev->key->flags & EXPR_F_KERNEL)
- expr_error(msgs, i, "interval overlaps with an existing one");
+ expr_error(msgs, i->key, "interval overlaps with an existing one");
else if (elem->key->flags & EXPR_F_KERNEL)
- expr_error(msgs, prev, "interval overlaps with an existing one");
+ expr_error(msgs, prev->key, "interval overlaps with an existing one");
else
- expr_binary_error(msgs, i, prev,
+ expr_binary_error(msgs, i->key, prev->key,
"conflicting intervals specified");
err = -1;
goto err_out;
} else if (mpz_cmp(range.low, prev_range.high) <= 0) {
if (prev->key->flags & EXPR_F_KERNEL)
- expr_error(msgs, i, "interval overlaps with an existing one");
+ expr_error(msgs, i->key, "interval overlaps with an existing one");
else if (elem->key->flags & EXPR_F_KERNEL)
- expr_error(msgs, prev, "interval overlaps with an existing one");
+ expr_error(msgs, prev->key, "interval overlaps with an existing one");
else
- expr_binary_error(msgs, i, prev,
+ expr_binary_error(msgs, i->key, prev->key,
"conflicting intervals specified");
err = -1;
goto err_out;
diff --git a/src/mergesort.c b/src/mergesort.c
index 7b318423a572..2e8ddd22f813 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -30,8 +30,6 @@ static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
static mpz_srcptr expr_msort_value(const struct expr *expr, mpz_t value)
{
switch (expr->etype) {
- case EXPR_SET_ELEM:
- return expr_msort_value(expr->key, value);
case EXPR_BINOP:
case EXPR_MAPPING:
case EXPR_RANGE:
@@ -68,10 +66,12 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
mpz_t value2_tmp;
int ret;
+ assert(e1->etype == EXPR_SET_ELEM && e2->etype == EXPR_SET_ELEM);
+
mpz_init(value1_tmp);
mpz_init(value2_tmp);
- value1 = expr_msort_value(e1, value1_tmp);
- value2 = expr_msort_value(e2, value2_tmp);
+ value1 = expr_msort_value(e1->key, value1_tmp);
+ value2 = expr_msort_value(e2->key, value2_tmp);
ret = mpz_cmp(value1, value2);
mpz_clear(value1_tmp);
mpz_clear(value2_tmp);
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 10/20] intervals: remove interval_expr_key()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (8 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 09/20] src: use key location to prepare removal of EXPR_SET_ELEM Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 11/20] src: move __set_expr_add() to src/intervals.c Pablo Neira Ayuso
` (10 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Since ("src: normalize set element with EXPR_MAPPING"), this became an
empty shim function, remove it.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/intervals.c | 72 +++++++++++++++++--------------------------------
1 file changed, 24 insertions(+), 48 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index bf0c5573ee1d..743e034519b5 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -227,31 +227,14 @@ static void setelem_automerge(struct set_automerge_ctx *ctx)
mpz_clear(rop);
}
-static struct expr *interval_expr_key(struct expr *i)
-{
- struct expr *elem;
-
- switch (i->etype) {
- case EXPR_SET_ELEM:
- elem = i;
- break;
- default:
- BUG("unhandled expression type %d", i->etype);
- return NULL;
- }
-
- return elem;
-}
-
static void set_to_range(struct expr *init)
{
- struct expr *i, *elem;
+ struct expr *i;
list_for_each_entry(i, &expr_set(init)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
- elem = interval_expr_key(i);
- setelem_expr_to_range(elem);
+ setelem_expr_to_range(i);
}
}
@@ -410,7 +393,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, *elem, *prev = NULL;
+ struct expr *i, *next, *prev = NULL;
struct range range, prev_range;
int err = 0;
mpz_t rop;
@@ -421,10 +404,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
mpz_init(range.high);
mpz_init(rop);
- list_for_each_entry_safe(elem, next, &expr_set(elems)->expressions, list) {
- assert(elem->etype == EXPR_SET_ELEM);
-
- i = interval_expr_key(elem);
+ list_for_each_entry_safe(i, next, &expr_set(elems)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
if (expr_type_catchall(i->key)) {
uint32_t len;
@@ -443,14 +424,14 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
range_expr_value_high(range.high, i->key);
}
- if (!prev && elem->key->flags & EXPR_F_REMOVE) {
+ if (!prev && i->key->flags & EXPR_F_REMOVE) {
expr_error(msgs, i->key, "element does not exist");
err = -1;
goto err;
}
- if (!(elem->key->flags & EXPR_F_REMOVE)) {
- prev = elem;
+ if (!(i->key->flags & EXPR_F_REMOVE)) {
+ prev = i;
mpz_set(prev_range.low, range.low);
mpz_set(prev_range.high, range.high);
continue;
@@ -458,14 +439,14 @@ 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 (elem->key->flags & EXPR_F_REMOVE) {
+ if (i->key->flags & EXPR_F_REMOVE) {
if (prev->key->flags & EXPR_F_KERNEL) {
- prev->key->location = elem->key->location;
+ prev->key->location = i->key->location;
list_move_tail(&prev->list, &expr_set(purge)->expressions);
}
- list_del(&elem->list);
- expr_free(elem);
+ list_del(&i->list);
+ expr_free(i);
}
} else if (set->automerge) {
if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
@@ -473,7 +454,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
err = -1;
goto err;
}
- } else if (elem->key->flags & EXPR_F_REMOVE) {
+ } else if (i->key->flags & EXPR_F_REMOVE) {
expr_error(msgs, i->key, "element does not exist");
err = -1;
goto err;
@@ -584,7 +565,7 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
static int setelem_overlap(struct list_head *msgs, struct set *set,
struct expr *init)
{
- struct expr *i, *next, *elem, *prev = NULL;
+ struct expr *i, *next, *prev = NULL;
struct range range, prev_range;
int err = 0;
mpz_t rop;
@@ -595,10 +576,8 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
mpz_init(range.high);
mpz_init(rop);
- list_for_each_entry_safe(elem, next, &expr_set(init)->expressions, list) {
- assert(elem->etype == EXPR_SET_ELEM);
-
- i = interval_expr_key(elem);
+ list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) {
+ assert(i->etype == EXPR_SET_ELEM);
if (expr_type_catchall(i->key))
continue;
@@ -607,7 +586,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
range_expr_value_high(range.high, i->key);
if (!prev) {
- prev = elem;
+ prev = i;
mpz_set(prev_range.low, range.low);
mpz_set(prev_range.high, range.high);
continue;
@@ -621,7 +600,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
mpz_cmp(prev_range.high, range.high) >= 0) {
if (prev->key->flags & EXPR_F_KERNEL)
expr_error(msgs, i->key, "interval overlaps with an existing one");
- else if (elem->key->flags & EXPR_F_KERNEL)
+ else if (i->key->flags & EXPR_F_KERNEL)
expr_error(msgs, prev->key, "interval overlaps with an existing one");
else
expr_binary_error(msgs, i->key, prev->key,
@@ -631,7 +610,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
} else if (mpz_cmp(range.low, prev_range.high) <= 0) {
if (prev->key->flags & EXPR_F_KERNEL)
expr_error(msgs, i->key, "interval overlaps with an existing one");
- else if (elem->key->flags & EXPR_F_KERNEL)
+ else if (i->key->flags & EXPR_F_KERNEL)
expr_error(msgs, prev->key, "interval overlaps with an existing one");
else
expr_binary_error(msgs, i->key, prev->key,
@@ -640,7 +619,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
goto err_out;
}
next:
- prev = elem;
+ prev = i;
mpz_set(prev_range.low, range.low);
mpz_set(prev_range.high, range.high);
}
@@ -721,23 +700,20 @@ static bool range_low_is_non_zero(const struct expr *expr)
int set_to_intervals(const struct set *set, struct expr *init, bool add)
{
- struct expr *i, *n, *prev = NULL, *elem, *root, *expr;
+ struct expr *i, *n, *prev = NULL, *root, *expr;
LIST_HEAD(intervals);
mpz_t p;
list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
- assert(i->etype == EXPR_SET_ELEM);
- elem = interval_expr_key(i);
-
- if (expr_type_catchall(elem->key))
+ if (expr_type_catchall(i->key))
continue;
if (prev)
break;
if (segtree_needs_first_segment(set, init, add) &&
- range_low_is_non_zero(elem->key)) {
+ range_low_is_non_zero(i->key)) {
mpz_init2(p, set->key->len);
mpz_set_ui(p, 0);
expr = constant_range_expr_alloc(&internal_location,
@@ -845,7 +821,7 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
low, expr_get(elem->key->right));
low = set_elem_expr_alloc(&key->location, low);
- set_elem_expr_copy(low, interval_expr_key(elem));
+ set_elem_expr_copy(low, elem);
list_add_tail(&low->list, intervals);
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 11/20] src: move __set_expr_add() to src/intervals.c
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (9 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 10/20] intervals: remove interval_expr_key() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 12/20] segtree: remove EXPR_VALUE from expr_value() Pablo Neira Ayuso
` (9 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Where this is only used.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/expression.h | 1 -
src/expression.c | 5 -----
src/intervals.c | 5 +++++
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index bce75d29ee2c..7abff4ba72ab 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -537,7 +537,6 @@ struct expr *list_expr_to_binop(struct expr *expr);
extern struct expr *set_expr_alloc(const struct location *loc,
const struct set *set);
-void __set_expr_add(struct expr *set, struct expr *elem);
void set_expr_add(struct expr *set, struct expr *elem);
void set_expr_remove(struct expr *expr, struct expr *item);
diff --git a/src/expression.c b/src/expression.c
index 415d678ba2e3..23ff42ac9331 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1454,11 +1454,6 @@ struct expr *set_expr_alloc(const struct location *loc, const struct set *set)
return set_expr;
}
-void __set_expr_add(struct expr *set, struct expr *elem)
-{
- list_add_tail(&elem->list, &expr_set(set)->expressions);
-}
-
void set_expr_add(struct expr *set, struct expr *elem)
{
struct expr_set *expr_set = expr_set(set);
diff --git a/src/intervals.c b/src/intervals.c
index 743e034519b5..c9e278b2a895 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -13,6 +13,11 @@
#include <intervals.h>
#include <rule.h>
+static void __set_expr_add(struct expr *set, struct expr *elem)
+{
+ list_add_tail(&elem->list, &expr_set(set)->expressions);
+}
+
static void set_to_range(struct expr *init);
static void __setelem_expr_to_range(struct expr **exprp)
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 12/20] segtree: remove EXPR_VALUE from expr_value()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (10 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 11/20] src: move __set_expr_add() to src/intervals.c Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 13/20] segtree: more assert on EXPR_SET_ELEM Pablo Neira Ayuso
` (8 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Rework the following commit:
7e6be917987c ("segtree: fix decomposition of unclosed intervals containing address prefixes")
this allows to add an assert(expr->etype == EXPR_SET_ELEM), in order to
normalize the input.
The closed flag tells us if this interval is represented with two
element or only one (as an open interval).
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 5e03122ebfb7..95cab41668f0 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -114,17 +114,12 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
static struct expr *expr_value(struct expr *expr)
{
- switch (expr->etype) {
- case EXPR_SET_ELEM:
- if (expr->key->etype == EXPR_MAPPING)
- return expr->key->left;
+ assert(expr->etype == EXPR_SET_ELEM);
- return expr->key;
- case EXPR_VALUE:
- return expr;
- default:
- BUG("invalid expression type %s", expr_name(expr));
- }
+ if (expr->key->etype == EXPR_MAPPING)
+ return expr->key->left;
+
+ return expr->key;
}
static struct expr *get_set_interval_find(const struct set *cache_set,
@@ -528,7 +523,7 @@ static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t ra
}
static void
-add_interval(struct expr *set, struct expr *low, struct expr *i)
+add_interval(struct expr *set, struct expr *low, struct expr *i, bool closed)
{
struct expr *expr;
mpz_t range, p;
@@ -537,7 +532,7 @@ add_interval(struct expr *set, struct expr *low, struct expr *i)
mpz_init(p);
mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
- if (i->etype != EXPR_VALUE)
+ if (closed)
mpz_sub_ui(range, range, 1);
mpz_and(p, expr_value(low)->value, range);
@@ -633,7 +628,7 @@ void interval_map_decompose(struct expr *set)
}
}
- add_interval(set, low, i);
+ add_interval(set, low, i, true);
if (i->key->flags & EXPR_F_INTERVAL_END) {
expr_free(low);
@@ -648,11 +643,12 @@ void interval_map_decompose(struct expr *set)
i = constant_expr_alloc(&low->location, low->dtype,
low->byteorder, expr_value(low)->len, NULL);
mpz_bitmask(i->value, i->len);
+ i = set_elem_expr_alloc(&low->location, i);
- if (!mpz_cmp(i->value, expr_value(low)->value)) {
+ if (!mpz_cmp(i->key->value, expr_value(low)->value)) {
set_expr_add(set, low);
} else {
- add_interval(set, low, i);
+ add_interval(set, low, i, false);
expr_free(low);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 13/20] segtree: more assert on EXPR_SET_ELEM
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (11 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 12/20] segtree: remove EXPR_VALUE from expr_value() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 14/20] segtree: remove dead code in set_expr_add_splice() Pablo Neira Ayuso
` (7 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
More EXPR_SET_ELEM validation, for correctness, to prepare the removal
of this expression.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/expression.c | 4 ++++
src/segtree.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/src/expression.c b/src/expression.c
index 23ff42ac9331..39221ba83fd0 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1458,12 +1458,16 @@ void set_expr_add(struct expr *set, struct expr *elem)
{
struct expr_set *expr_set = expr_set(set);
+ assert(elem->etype == EXPR_SET_ELEM);
+
list_add_tail(&elem->list, &expr_set->expressions);
expr_set->size++;
}
void set_expr_remove(struct expr *set, struct expr *expr)
{
+ assert(expr->etype == EXPR_SET_ELEM);
+
expr_set(set)->size--;
list_del(&expr->list);
}
diff --git a/src/segtree.c b/src/segtree.c
index 95cab41668f0..0ff1577b75b9 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -43,6 +43,9 @@ static enum byteorder get_key_byteorder(const struct expr *e)
static void interval_expr_copy(struct expr *dst, struct expr *src)
{
+ assert(dst->etype == EXPR_SET_ELEM);
+ assert(src->etype == EXPR_SET_ELEM);
+
if (src->comment)
dst->comment = xstrdup(src->comment);
if (src->timeout)
@@ -131,6 +134,9 @@ static struct expr *get_set_interval_find(const struct set *cache_set,
struct expr *i, *key;
mpz_t val;
+ assert(left->etype == EXPR_SET_ELEM);
+ assert(!right || right->etype == EXPR_SET_ELEM);
+
mpz_init2(val, set->key->len);
list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
@@ -169,6 +175,8 @@ static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
{
struct expr *elem;
+ assert(low->etype == EXPR_SET_ELEM);
+
if (low->key->etype == EXPR_MAPPING) {
expr = mapping_expr_alloc(&low->location, expr,
expr_clone(low->key->right));
@@ -188,6 +196,8 @@ static struct expr *expr_to_set_elem(struct expr *e)
char data[len + 1];
struct expr *expr;
+ assert(e->etype == EXPR_SET_ELEM);
+
if (expr_basetype(expr_value(e))->type != TYPE_STRING)
return expr_clone(e);
@@ -210,6 +220,9 @@ static void set_expr_add_splice(struct expr *compound, struct expr *expr, struct
{
struct expr *elem;
+ assert(expr->etype == EXPR_SET_ELEM);
+ assert(orig->etype == EXPR_SET_ELEM);
+
switch (expr->etype) {
case EXPR_SET_ELEM:
list_splice_init(&orig->stmt_list, &expr->stmt_list);
@@ -304,6 +317,9 @@ static int expr_value_cmp(const void *p1, const void *p2)
struct expr *e2 = *(void * const *)p2;
int ret;
+ assert(e1->etype == EXPR_SET_ELEM);
+ assert(e2->etype == EXPR_SET_ELEM);
+
if (expr_value(e1)->etype == EXPR_CONCAT)
return -1;
@@ -468,6 +484,9 @@ static struct expr *interval_to_prefix(struct expr *low, struct expr *i, const m
unsigned int prefix_len;
struct expr *prefix;
+ assert(low->etype == EXPR_SET_ELEM);
+ assert(i->etype == EXPR_SET_ELEM);
+
prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
prefix = prefix_expr_alloc(&low->location,
expr_clone(expr_value(low)),
@@ -484,6 +503,9 @@ static struct expr *interval_to_string(struct expr *low, struct expr *i, const m
char data[len + 2];
struct expr *expr;
+ assert(low->etype == EXPR_SET_ELEM);
+ assert(i->etype == EXPR_SET_ELEM);
+
prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
if (prefix_len > i->len || prefix_len % BITS_PER_BYTE)
@@ -508,6 +530,9 @@ static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t ra
{
struct expr *tmp;
+ assert(low->etype == EXPR_SET_ELEM);
+ assert(i->etype == EXPR_SET_ELEM);
+
tmp = constant_expr_alloc(&low->location, low->dtype,
low->byteorder, expr_value(low)->len,
NULL);
@@ -528,6 +553,9 @@ add_interval(struct expr *set, struct expr *low, struct expr *i, bool closed)
struct expr *expr;
mpz_t range, p;
+ assert(low->etype == EXPR_SET_ELEM);
+ assert(i->etype == EXPR_SET_ELEM);
+
mpz_init(range);
mpz_init(p);
@@ -596,6 +624,8 @@ void interval_map_decompose(struct expr *set)
for (m = 0; m < size; m++) {
i = elements[m];
+ assert(i->etype == EXPR_SET_ELEM);
+
if (i->key->flags & EXPR_F_INTERVAL_END)
interval = false;
else if (interval) {
@@ -612,6 +642,8 @@ void interval_map_decompose(struct expr *set)
for (n = 0; n < size; n++) {
i = ranges[n];
+ assert(i->etype == EXPR_SET_ELEM);
+
if (low == NULL) {
if (i->key->flags & EXPR_F_INTERVAL_END) {
/*
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 14/20] segtree: remove dead code in set_expr_add_splice()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (12 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 13/20] segtree: more assert on EXPR_SET_ELEM Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 15/20] segtree: disentangle concat_range_aggregate() Pablo Neira Ayuso
` (6 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
If get_set_interval_find() always returns EXPR_SET_ELEM, then,
set_expr_add_splice() always takes EXPR_SET_ELEM.
This reworks:
2b164aec4295 ("src: fix reset element support for interval set type")
which does _not_ seem to have a tests/shell unit.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 0ff1577b75b9..69d6f513c55d 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -218,26 +218,11 @@ static struct expr *expr_to_set_elem(struct expr *e)
static void set_expr_add_splice(struct expr *compound, struct expr *expr, struct expr *orig)
{
- struct expr *elem;
-
assert(expr->etype == EXPR_SET_ELEM);
assert(orig->etype == EXPR_SET_ELEM);
- switch (expr->etype) {
- case EXPR_SET_ELEM:
- list_splice_init(&orig->stmt_list, &expr->stmt_list);
- set_expr_add(compound, expr);
- break;
- case EXPR_MAPPING:
- list_splice_init(&orig->left->stmt_list, &expr->left->stmt_list);
- set_expr_add(compound, expr);
- break;
- default:
- elem = set_elem_expr_alloc(&orig->location, expr);
- list_splice_init(&orig->stmt_list, &elem->stmt_list);
- set_expr_add(compound, elem);
- break;
- }
+ list_splice_init(&orig->stmt_list, &expr->stmt_list);
+ set_expr_add(compound, expr);
}
int get_set_decompose(struct set *cache_set, struct set *set)
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 15/20] segtree: disentangle concat_range_aggregate()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (13 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 14/20] segtree: remove dead code in set_expr_add_splice() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 16/20] segtree: replace default case by specific types in get_set_intervals() Pablo Neira Ayuso
` (5 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Consolidate calls to expr_value() in concat_range_aggregate() to
simplify this code.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 69d6f513c55d..06f8be92ccfa 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -351,7 +351,7 @@ static int range_mask_len(const mpz_t start, const mpz_t end, unsigned int len)
*/
void concat_range_aggregate(struct expr *set)
{
- struct expr *i, *start = NULL, *end, *r1, *r2, *next, *r1_next, *tmp;
+ struct expr *i, *start, *end, *prev = NULL, *r1, *r2, *next, *r1_next, *tmp;
struct list_head *r2_next;
int prefix_len, free_r1;
mpz_t range, p;
@@ -359,21 +359,22 @@ void concat_range_aggregate(struct expr *set)
list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
assert(i->etype == EXPR_SET_ELEM);
- if (!start) {
- start = i;
+ if (!prev) {
+ prev = i;
continue;
}
- end = i;
+ start = expr_value(prev);
+ end = expr_value(i);
/* Walk over r1 (start expression) and r2 (end) in parallel,
* form ranges between corresponding r1 and r2 expressions,
* store them by replacing r2 expressions, and free r1
* expressions.
*/
- r2 = list_first_entry(&expr_concat(expr_value(end))->expressions,
+ r2 = list_first_entry(&expr_concat(end)->expressions,
struct expr, list);
list_for_each_entry_safe(r1, r1_next,
- &expr_concat(expr_value(start))->expressions,
+ &expr_concat(start)->expressions,
list) {
bool string_type = false;
@@ -452,15 +453,15 @@ next:
mpz_clear(range);
r2 = list_entry(r2_next, typeof(*r2), list);
- concat_expr_remove(expr_value(start), r1);
+ concat_expr_remove(start, r1);
if (free_r1)
expr_free(r1);
}
- set_expr_remove(set, start);
- expr_free(start);
- start = NULL;
+ set_expr_remove(set, prev);
+ expr_free(prev);
+ prev = NULL;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 16/20] segtree: replace default case by specific types in get_set_intervals()
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (14 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 15/20] segtree: disentangle concat_range_aggregate() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 17/20] segtree: consolidate calls to expr_value() to fetch the element key Pablo Neira Ayuso
` (4 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Use specific types, so default case can be left for catching bugs.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/segtree.c b/src/segtree.c
index 06f8be92ccfa..7fed4df6e178 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -98,7 +98,10 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
case EXPR_SET_ELEM_CATCHALL:
set_expr_add(new_init, expr_clone(i));
break;
- default:
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ case EXPR_RANGE_VALUE:
+ case EXPR_MAPPING:
range_expr_value_low(low, i->key);
set_elem_expr_add(set, new_init, low, 0, i->byteorder);
range_expr_value_high(high, i->key);
@@ -106,6 +109,9 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
set_elem_expr_add(set, new_init, high,
EXPR_F_INTERVAL_END, i->byteorder);
break;
+ default:
+ BUG("unexpected expression %s", expr_name(i->key));
+ break;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 17/20] segtree: consolidate calls to expr_value() to fetch the element key
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (15 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 16/20] segtree: replace default case by specific types in get_set_intervals() Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 18/20] segtree: use set->key->byteorder instead of expr->byteorder Pablo Neira Ayuso
` (3 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Consolidate calls to expr_value() so the key is fetched only once.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 51 ++++++++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 21 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 7fed4df6e178..fde9473dd366 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -198,16 +198,17 @@ static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
static struct expr *expr_to_set_elem(struct expr *e)
{
unsigned int len = div_round_up(e->len, BITS_PER_BYTE);
+ struct expr *expr, *key;
unsigned int str_len;
char data[len + 1];
- struct expr *expr;
assert(e->etype == EXPR_SET_ELEM);
- if (expr_basetype(expr_value(e))->type != TYPE_STRING)
+ key = expr_value(e);
+ if (expr_basetype(key)->type != TYPE_STRING)
return expr_clone(e);
- mpz_export_data(data, expr_value(e)->value, BYTEORDER_BIG_ENDIAN, len);
+ mpz_export_data(data, key->value, BYTEORDER_BIG_ENDIAN, len);
str_len = strnlen(data, len);
if (str_len >= len || str_len == 0)
@@ -306,15 +307,18 @@ static int expr_value_cmp(const void *p1, const void *p2)
{
struct expr *e1 = *(void * const *)p1;
struct expr *e2 = *(void * const *)p2;
+ struct expr *key_e1, *key_e2;
int ret;
assert(e1->etype == EXPR_SET_ELEM);
assert(e2->etype == EXPR_SET_ELEM);
- if (expr_value(e1)->etype == EXPR_CONCAT)
+ key_e1 = expr_value(e1);
+ if (key_e1->etype == EXPR_CONCAT)
return -1;
- ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value);
+ key_e2 = expr_value(e2);
+ ret = mpz_cmp(key_e1->value, key_e2->value);
if (ret == 0) {
if (e1->key->flags & EXPR_F_INTERVAL_END)
return -1;
@@ -475,15 +479,17 @@ static struct expr *interval_to_prefix(struct expr *low, struct expr *i, const m
{
unsigned int prefix_len;
struct expr *prefix;
+ struct expr *key;
assert(low->etype == EXPR_SET_ELEM);
assert(i->etype == EXPR_SET_ELEM);
- prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+ key = expr_value(i);
+ prefix_len = key->len - mpz_scan0(range, 0);
prefix = prefix_expr_alloc(&low->location,
expr_clone(expr_value(low)),
prefix_len);
- prefix->len = expr_value(i)->len;
+ prefix->len = key->len;
return __expr_to_set_elem(low, prefix);
}
@@ -494,11 +500,13 @@ static struct expr *interval_to_string(struct expr *low, struct expr *i, const m
unsigned int prefix_len, str_len;
char data[len + 2];
struct expr *expr;
+ struct expr *key;
assert(low->etype == EXPR_SET_ELEM);
assert(i->etype == EXPR_SET_ELEM);
- prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+ key = expr_value(i);
+ prefix_len = key->len - mpz_scan0(range, 0);
if (prefix_len > i->len || prefix_len % BITS_PER_BYTE)
return interval_to_prefix(low, i, range);
@@ -520,21 +528,20 @@ static struct expr *interval_to_string(struct expr *low, struct expr *i, const m
static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t range)
{
- struct expr *tmp;
+ struct expr *tmp, *key;
assert(low->etype == EXPR_SET_ELEM);
assert(i->etype == EXPR_SET_ELEM);
+ key = expr_value(low);
tmp = constant_expr_alloc(&low->location, low->dtype,
- low->byteorder, expr_value(low)->len,
+ low->byteorder, key->len,
NULL);
- mpz_add(range, range, expr_value(low)->value);
+ mpz_add(range, range, key->value);
mpz_set(tmp->value, range);
- tmp = range_expr_alloc(&low->location,
- expr_clone(expr_value(low)),
- tmp);
+ tmp = range_expr_alloc(&low->location, expr_clone(key), tmp);
return __expr_to_set_elem(low, tmp);
}
@@ -542,7 +549,7 @@ static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t ra
static void
add_interval(struct expr *set, struct expr *low, struct expr *i, bool closed)
{
- struct expr *expr;
+ struct expr *expr, *key;
mpz_t range, p;
assert(low->etype == EXPR_SET_ELEM);
@@ -551,16 +558,17 @@ add_interval(struct expr *set, struct expr *low, struct expr *i, bool closed)
mpz_init(range);
mpz_init(p);
- mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
+ key = expr_value(low);
+ mpz_sub(range, expr_value(i)->value, key->value);
if (closed)
mpz_sub_ui(range, range, 1);
- mpz_and(p, expr_value(low)->value, range);
+ mpz_and(p, key->value, range);
if (!mpz_cmp_ui(range, 0)) {
if (expr_basetype(low)->type == TYPE_STRING)
- mpz_switch_byteorder(expr_value(low)->value,
- expr_value(low)->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(key->value,
+ key->len / BITS_PER_BYTE);
low->key->flags |= EXPR_F_KERNEL;
expr = expr_get(low);
} else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
@@ -664,12 +672,13 @@ void interval_map_decompose(struct expr *set)
if (!low) /* no unclosed interval at end */
goto out;
+ key = expr_value(low);
i = constant_expr_alloc(&low->location, low->dtype,
- low->byteorder, expr_value(low)->len, NULL);
+ low->byteorder, key->len, NULL);
mpz_bitmask(i->value, i->len);
i = set_elem_expr_alloc(&low->location, i);
- if (!mpz_cmp(i->key->value, expr_value(low)->value)) {
+ if (!mpz_cmp(i->key->value, key->value)) {
set_expr_add(set, low);
} else {
add_interval(set, low, i, false);
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 18/20] segtree: use set->key->byteorder instead of expr->byteorder
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (16 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 17/20] segtree: consolidate calls to expr_value() to fetch the element key Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 19/20] evaluate: remove check for constant expression in set/map statement Pablo Neira Ayuso
` (2 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
For consistency, use the set key byteorder in get_set_intervals().
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/segtree.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index fde9473dd366..bfea2f64ed81 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -103,11 +103,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
case EXPR_RANGE_VALUE:
case EXPR_MAPPING:
range_expr_value_low(low, i->key);
- set_elem_expr_add(set, new_init, low, 0, i->byteorder);
+ set_elem_expr_add(set, new_init, low, 0, byteorder);
range_expr_value_high(high, i->key);
mpz_add_ui(high, high, 1);
set_elem_expr_add(set, new_init, high,
- EXPR_F_INTERVAL_END, i->byteorder);
+ EXPR_F_INTERVAL_END, byteorder);
break;
default:
BUG("unexpected expression %s", expr_name(i->key));
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 19/20] evaluate: remove check for constant expression in set/map statement
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (17 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 18/20] segtree: use set->key->byteorder instead of expr->byteorder Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 20/20] evaluate: skip EXPR_SET_ELEM in error path of set statements Pablo Neira Ayuso
2026-02-05 10:37 ` [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Florian Westphal
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
a8260c056a69 ("tests: add dynmap datapath add/delete test case") proves
this is indeed supported, remove these checks.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 3b6008149801..ea6013f6a24e 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4847,9 +4847,6 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
stmt->set.set->set->key->byteorder,
&stmt->set.key->key) < 0)
return -1;
- if (expr_is_constant(stmt->set.key))
- return expr_error(ctx->msgs, stmt->set.key,
- "Key expression can not be constant");
if (stmt->set.key->comment != NULL)
return expr_error(ctx->msgs, stmt->set.key,
"Key expression comments are not supported");
@@ -4891,9 +4888,6 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
stmt->map.set->set->key->byteorder,
&stmt->map.key->key) < 0)
return -1;
- if (expr_is_constant(stmt->map.key))
- return expr_error(ctx->msgs, stmt->map.key,
- "Key expression can not be constant");
if (stmt->map.key->comment != NULL)
return expr_error(ctx->msgs, stmt->map.key,
"Key expression comments are not supported");
@@ -4904,9 +4898,6 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
stmt->map.set->set->data->byteorder,
&stmt->map.data->key) < 0)
return -1;
- if (expr_is_constant(stmt->map.data))
- return expr_error(ctx->msgs, stmt->map.data,
- "Data expression can not be constant");
if (stmt->map.data->comment != NULL)
return expr_error(ctx->msgs, stmt->map.data,
"Data expression comments are not supported");
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH nft 20/20] evaluate: skip EXPR_SET_ELEM in error path of set statements
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (18 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 19/20] evaluate: remove check for constant expression in set/map statement Pablo Neira Ayuso
@ 2026-02-05 2:41 ` Pablo Neira Ayuso
2026-02-05 10:37 ` [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Florian Westphal
20 siblings, 0 replies; 22+ messages in thread
From: Pablo Neira Ayuso @ 2026-02-05 2:41 UTC (permalink / raw)
To: netfilter-devel
Use the key value directly, skip EXPR_SET_ELEM indirection.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index ea6013f6a24e..482708ae6191 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3673,28 +3673,28 @@ static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &stmt->meter.key) < 0)
return -1;
- if (expr_is_constant(stmt->meter.key))
- return expr_error(ctx->msgs, stmt->meter.key,
+ if (expr_is_constant(stmt->meter.key->key))
+ return expr_error(ctx->msgs, stmt->meter.key->key,
"Meter key expression can not be constant");
if (stmt->meter.key->comment)
- return expr_error(ctx->msgs, stmt->meter.key,
+ return expr_error(ctx->msgs, stmt->meter.key->key,
"Meter key expression can not contain comments");
/* Declare an empty set */
key = stmt->meter.key;
if (existing_set) {
if ((existing_set->flags & NFT_SET_TIMEOUT) && !key->timeout)
- return expr_error(ctx->msgs, stmt->meter.key,
+ return expr_error(ctx->msgs, stmt->meter.key->key,
"existing set '%s' has timeout flag",
stmt->meter.name);
if ((existing_set->flags & NFT_SET_TIMEOUT) == 0 && key->timeout)
- return expr_error(ctx->msgs, stmt->meter.key,
+ return expr_error(ctx->msgs, stmt->meter.key->key,
"existing set '%s' lacks timeout flag",
stmt->meter.name);
if (stmt->meter.size > 0 && existing_set->desc.size != stmt->meter.size)
- return expr_error(ctx->msgs, stmt->meter.key,
+ return expr_error(ctx->msgs, stmt->meter.key->key,
"existing set '%s' has size %u, meter has %u",
stmt->meter.name, existing_set->desc.size,
stmt->meter.size);
@@ -4848,7 +4848,7 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
&stmt->set.key->key) < 0)
return -1;
if (stmt->set.key->comment != NULL)
- return expr_error(ctx->msgs, stmt->set.key,
+ return expr_error(ctx->msgs, stmt->set.key->key,
"Key expression comments are not supported");
list_for_each_entry(this, &stmt->set.stmt_list, list) {
if (stmt_evaluate_stateful(ctx, this, "set") < 0)
@@ -4889,7 +4889,7 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
&stmt->map.key->key) < 0)
return -1;
if (stmt->map.key->comment != NULL)
- return expr_error(ctx->msgs, stmt->map.key,
+ return expr_error(ctx->msgs, stmt->map.key->key,
"Key expression comments are not supported");
if (stmt_evaluate_arg(ctx, stmt,
--
2.47.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
` (19 preceding siblings ...)
2026-02-05 2:41 ` [PATCH nft 20/20] evaluate: skip EXPR_SET_ELEM in error path of set statements Pablo Neira Ayuso
@ 2026-02-05 10:37 ` Florian Westphal
20 siblings, 0 replies; 22+ messages in thread
From: Florian Westphal @ 2026-02-05 10:37 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> This is v2 of the update to prepare for the removal of EXPR_SET_ELEM.
> This series is slightly larger than v1, including more preparation work.
> No functional changes are intended. No memory footprint reduction at
> this stage. This slightly increases LoC because of the patches that add
> assertions on EXPR_SET_ELEM.
>
> This is passing tests/shell.
>
> Apologies for this large series...
Thanks for the quick resend. I have no comments, if you are happy with
it feel free to push this out.
I also checked this with both nf and nf-next and did not see any errors
running shell tests.
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-02-05 10:37 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-05 2:41 [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 01/20] src: normalize set element with EXPR_MAPPING Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 02/20] src: allocate EXPR_SET_ELEM for EXPR_SET in embedded set declaration in sets Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 03/20] src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 04/20] evaluate: simplify sets as set elems evaluation Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 05/20] evaluate: clean up expr_evaluate_set() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 06/20] segtree: rename set_elem_add() to set_elem_expr_add() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 07/20] src: move flags from EXPR_SET_ELEM to key Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 08/20] src: remove EXPR_SET_ELEM in range_expr_value_{low,high}() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 09/20] src: use key location to prepare removal of EXPR_SET_ELEM Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 10/20] intervals: remove interval_expr_key() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 11/20] src: move __set_expr_add() to src/intervals.c Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 12/20] segtree: remove EXPR_VALUE from expr_value() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 13/20] segtree: more assert on EXPR_SET_ELEM Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 14/20] segtree: remove dead code in set_expr_add_splice() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 15/20] segtree: disentangle concat_range_aggregate() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 16/20] segtree: replace default case by specific types in get_set_intervals() Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 17/20] segtree: consolidate calls to expr_value() to fetch the element key Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 18/20] segtree: use set->key->byteorder instead of expr->byteorder Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 19/20] evaluate: remove check for constant expression in set/map statement Pablo Neira Ayuso
2026-02-05 2:41 ` [PATCH nft 20/20] evaluate: skip EXPR_SET_ELEM in error path of set statements Pablo Neira Ayuso
2026-02-05 10:37 ` [PATCH nft,v2 00/20] prepare for EXPR_SET_ELEM removal Florian Westphal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox