From: Pablo Neira Ayuso Date: Tue, 8 Jul 2025 22:32:13 +0000 (+0200) Subject: src: convert set to list expression X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=01fdd7c7f445337c460738aa872cbdaabb5316ea;p=thirdparty%2Fnftables.git src: convert set to list expression The following definition: define xyz = { "dummy0", "dummy1" } is represented as a set expression to ease integration with sets. However, this definition can be used in chains and flowtables to specify the devices, for instance: table netdev x { chain y { type filter hook ingress devices = $xyz priority 0; policy drop; } } in this context, $xyz defines a _list_ of devices, not a set. Transform the set to list expression from the evaluation step for chains and flowtables. This patch also handles: define xyz = { "dummy0", $abc } where $abc is also transformed to a list expression in the context of chains and flowtables. Signed-off-by: Pablo Neira Ayuso --- diff --git a/src/evaluate.c b/src/evaluate.c index f4f72ee4..fb6c4e06 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -5393,9 +5393,54 @@ static bool evaluate_expr_variable(struct eval_ctx *ctx, struct expr **exprp) return true; } -static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr) +static struct expr *expr_set_to_list(struct eval_ctx *ctx, struct expr *dev_expr) { struct expr *expr, *next, *key; + struct location loc; + LIST_HEAD(tmp); + + list_for_each_entry_safe(expr, next, &dev_expr->expressions, list) { + list_del(&expr->list); + + switch (expr->etype) { + case EXPR_VARIABLE: + expr_set_context(&ctx->ectx, &ifname_type, + IFNAMSIZ * BITS_PER_BYTE); + if (!evaluate_expr_variable(ctx, &expr)) + return false; + + if (expr->etype == EXPR_SET) { + expr = expr_set_to_list(ctx, expr); + list_splice_init(&expr->expressions, &tmp); + expr_free(expr); + continue; + } + break; + case EXPR_SET_ELEM: + key = expr_clone(expr->key); + expr_free(expr); + expr = key; + break; + case EXPR_VALUE: + break; + default: + break; + } + + list_add(&expr->list, &tmp); + } + + loc = dev_expr->location; + expr_free(dev_expr); + dev_expr = compound_expr_alloc(&loc, EXPR_LIST); + list_splice_init(&tmp, &dev_expr->expressions); + + return dev_expr; +} + +static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr) +{ + struct expr *expr, *next; LIST_HEAD(tmp); if ((*dev_expr)->etype == EXPR_VARIABLE) { @@ -5405,9 +5450,10 @@ static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr) return false; } - if ((*dev_expr)->etype != EXPR_SET && - (*dev_expr)->etype != EXPR_LIST) - return true; + if ((*dev_expr)->etype == EXPR_SET) + *dev_expr = expr_set_to_list(ctx, *dev_expr); + + assert((*dev_expr)->etype == EXPR_LIST); list_for_each_entry_safe(expr, next, &(*dev_expr)->expressions, list) { list_del(&expr->list); @@ -5418,11 +5464,13 @@ static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr) IFNAMSIZ * BITS_PER_BYTE); if (!evaluate_expr_variable(ctx, &expr)) return false; - break; - case EXPR_SET_ELEM: - key = expr_clone(expr->key); - expr_free(expr); - expr = key; + + if (expr->etype == EXPR_SET) { + expr = expr_set_to_list(ctx, expr); + list_splice_init(&expr->expressions, &tmp); + expr_free(expr); + continue; + } break; case EXPR_VALUE: break; diff --git a/src/mnl.c b/src/mnl.c index 8a8dc4d6..cc20908f 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -757,7 +757,6 @@ static struct nft_dev *nft_dev_array(const struct expr *dev_expr, int *num_devs) struct expr *expr; switch (dev_expr->etype) { - case EXPR_SET: case EXPR_LIST: list_for_each_entry(expr, &dev_expr->expressions, list) len++;