From 6cf0f2c17bfb96c05dd0c03e0b91a75d732917cf Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 15 Jun 2021 14:57:08 +0200 Subject: src: queue: allow use of arbitrary queue expressions back in 2016 Liping Zhang added support to kernel and libnftnl to specify a source register containing the queue number to use. This was never added to nft itself, so allow this. On linearization side, check if attached expression is a range. If its not, allocate a new register and set NFTNL_EXPR_QUEUE_SREG_QNUM attribute after generating the lowlevel expressions for the kernel. On delinarization we need to check for presence of NFTNL_EXPR_QUEUE_SREG_QNUM and decode the expression(s) when present. Also need to do postprocessing for STMT_QUEUE so that the protocol context is set correctly, without this only raw payload expressions will be shown (@nh,32,...) instead of 'ip ...'. Next patch adds test cases. Signed-off-by: Florian Westphal --- doc/statements.txt | 4 ++++ src/evaluate.c | 13 +++++++------ src/netlink_delinearize.c | 48 +++++++++++++++++++++++++++++++++++++---------- src/netlink_linearize.c | 28 ++++++++++++++++++++++----- src/parser_bison.y | 16 ++++++++++++++-- src/statement.c | 9 +++++++-- 6 files changed, 93 insertions(+), 25 deletions(-) diff --git a/doc/statements.txt b/doc/statements.txt index 602a5b20..c2a61659 100644 --- a/doc/statements.txt +++ b/doc/statements.txt @@ -591,11 +591,15 @@ for details. ____ *queue* [*flags* 'QUEUE_FLAGS'] [*num* 'queue_number'] *queue* [*flags* 'QUEUE_FLAGS'] [*num* 'queue_number_from' - 'queue_number_to'] +*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'QUEUE_EXPRESSION' ] 'QUEUE_FLAGS' := 'QUEUE_FLAG' [*,* 'QUEUE_FLAGS'] 'QUEUE_FLAG' := *bypass* | *fanout* +'QUEUE_EXPRESSION' := *numgen* | *hash* | *symhash* ____ +QUEUE_EXPRESSION can be used to compute a queue number +at run-time with the hash or numgen expressions. .queue statement values [options="header"] diff --git a/src/evaluate.c b/src/evaluate.c index c24fee4c..4f19dc43 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1019,7 +1019,6 @@ static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr) if (mpz_cmp(left->value, right->value) >= 0) return expr_error(ctx->msgs, range, "Range has zero or negative size"); - datatype_set(range, left->dtype); range->flags |= EXPR_F_CONSTANT; return 0; @@ -3446,14 +3445,16 @@ static int stmt_evaluate_queue(struct eval_ctx *ctx, struct stmt *stmt) BYTEORDER_HOST_ENDIAN, &stmt->queue.queue) < 0) return -1; - if (!expr_is_constant(stmt->queue.queue)) - return expr_error(ctx->msgs, stmt->queue.queue, - "queue number is not constant"); - if (stmt->queue.queue->etype != EXPR_RANGE && - (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)) + + if ((stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT) && + stmt->queue.queue->etype != EXPR_RANGE) return expr_error(ctx->msgs, stmt->queue.queue, "fanout requires a range to be " "specified"); + + if (ctx->ectx.maxval > USHRT_MAX) + return expr_error(ctx->msgs, stmt->queue.queue, + "queue expression max value exceeds %u", USHRT_MAX); } stmt->flags |= STMT_F_TERMINAL; return 0; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 58497809..6a6f7747 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1467,19 +1467,32 @@ static void netlink_parse_queue(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) { - uint16_t num, total, flags; - struct expr *expr, *high; + struct expr *expr; + uint16_t flags; - num = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_NUM); - total = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_TOTAL); + if (nftnl_expr_is_set(nle, NFTNL_EXPR_QUEUE_SREG_QNUM)) { + enum nft_registers reg = netlink_parse_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM); - expr = constant_expr_alloc(loc, &integer_type, - BYTEORDER_HOST_ENDIAN, 16, &num); - if (total > 1) { - total += num - 1; - high = constant_expr_alloc(loc, &integer_type, + expr = netlink_get_register(ctx, loc, reg); + if (!expr) { + netlink_error(ctx, loc, "queue statement has no sreg expression"); + return; + } + } else { + uint16_t total = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_TOTAL); + uint16_t num = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_NUM); + + expr = constant_expr_alloc(loc, &integer_type, + BYTEORDER_HOST_ENDIAN, 16, &num); + + if (total > 1) { + struct expr *high; + + total += num - 1; + high = constant_expr_alloc(loc, &integer_type, BYTEORDER_HOST_ENDIAN, 16, &total); - expr = range_expr_alloc(loc, expr, high); + expr = range_expr_alloc(loc, expr, high); + } } flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS); @@ -2852,6 +2865,18 @@ static void stmt_payload_postprocess(struct rule_pp_ctx *ctx) expr_postprocess(ctx, &stmt->payload.val); } +static void stmt_queue_postprocess(struct rule_pp_ctx *ctx) +{ + struct stmt *stmt = ctx->stmt; + struct expr *e = stmt->queue.queue; + + if (e == NULL || e->etype == EXPR_VALUE || + e->etype == EXPR_RANGE) + return; + + expr_postprocess(ctx, &stmt->queue.queue); +} + /* * We can only remove payload dependencies if they occur without * a statement with side effects in between. @@ -2956,6 +2981,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r case STMT_OBJREF: expr_postprocess(&rctx, &stmt->objref.expr); break; + case STMT_QUEUE: + stmt_queue_postprocess(&rctx); + break; default: break; } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 7b35aae1..b1f3feee 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1334,21 +1334,39 @@ static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx, static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { + enum nft_registers sreg = 0; struct nftnl_expr *nle; uint16_t total_queues; + struct expr *expr; mpz_t low, high; mpz_init2(low, 16); mpz_init2(high, 16); - if (stmt->queue.queue != NULL) { - range_expr_value_low(low, stmt->queue.queue); - range_expr_value_high(high, stmt->queue.queue); + + expr = stmt->queue.queue; + + if (expr) { + if (expr->etype == EXPR_RANGE || expr->etype == EXPR_VALUE) { + range_expr_value_low(low, stmt->queue.queue); + range_expr_value_high(high, stmt->queue.queue); + } else { + sreg = get_register(ctx, expr); + netlink_gen_expr(ctx, expr, sreg); + release_register(ctx, expr); + } } + total_queues = mpz_get_uint16(high) - mpz_get_uint16(low) + 1; nle = alloc_nft_expr("queue"); - nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low)); - nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues); + + if (sreg) { + netlink_put_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM, sreg); + } else { + nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low)); + nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues); + } + if (stmt->queue.flags) nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_FLAGS, stmt->queue.flags); diff --git a/src/parser_bison.y b/src/parser_bison.y index 277918ef..cb3e80e3 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -705,8 +705,8 @@ int nft_lex(void *, void *, void *); %type queue_stmt queue_stmt_alloc queue_stmt_compat %destructor { stmt_free($$); } queue_stmt queue_stmt_alloc queue_stmt_compat -%type queue_stmt_expr_simple -%destructor { expr_free($$); } queue_stmt_expr_simple +%type queue_stmt_expr_simple queue_stmt_expr +%destructor { expr_free($$); } queue_stmt_expr_simple queue_stmt_expr %type queue_stmt_flags queue_stmt_flag %type dup_stmt %destructor { stmt_free($$); } dup_stmt @@ -3739,6 +3739,14 @@ nf_nat_flag : RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM; } ; queue_stmt : queue_stmt_compat close_scope_queue + | QUEUE TO queue_stmt_expr close_scope_queue + { + $$ = queue_stmt_alloc(&@$, $3, 0); + } + | QUEUE FLAGS queue_stmt_flags TO queue_stmt_expr close_scope_queue + { + $$ = queue_stmt_alloc(&@$, $5, $3); + } | QUEUE FLAGS queue_stmt_flags QUEUENUM queue_stmt_expr_simple close_scope_queue { $$ = queue_stmt_alloc(&@$, $5, $3); @@ -3777,6 +3785,10 @@ queue_stmt_expr_simple : integer_expr | range_rhs_expr ; +queue_stmt_expr : numgen_expr + | hash_expr + ; + queue_stmt_flags : queue_stmt_flag | queue_stmt_flags COMMA queue_stmt_flag { diff --git a/src/statement.c b/src/statement.c index 9eb49339..dfd27510 100644 --- a/src/statement.c +++ b/src/statement.c @@ -507,8 +507,13 @@ static void queue_stmt_print(const struct stmt *stmt, struct output_ctx *octx) nft_print(octx, "%sfanout", delim); if (e) { - nft_print(octx, " num "); - expr_print(stmt->queue.queue, octx); + if (e->etype == EXPR_VALUE || e->etype == EXPR_RANGE) { + nft_print(octx, " num "); + expr_print(stmt->queue.queue, octx); + } else { + nft_print(octx, " to "); + expr_print(stmt->queue.queue, octx); + } } else { nft_print(octx, " num 0"); } -- cgit v1.2.3