summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2021-06-15 14:57:08 +0200
committerFlorian Westphal <fw@strlen.de>2021-06-21 14:44:58 +0200
commit6cf0f2c17bfb96c05dd0c03e0b91a75d732917cf (patch)
treeabb34028a9da0d2de41f26f1d40a61657022233c
parent3486127e52426d1861a78b44f10e5997c3a69ff2 (diff)
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 <fw@strlen.de>
-rw-r--r--doc/statements.txt4
-rw-r--r--src/evaluate.c13
-rw-r--r--src/netlink_delinearize.c48
-rw-r--r--src/netlink_linearize.c28
-rw-r--r--src/parser_bison.y16
-rw-r--r--src/statement.c9
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 <stmt> queue_stmt queue_stmt_alloc queue_stmt_compat
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc queue_stmt_compat
-%type <expr> queue_stmt_expr_simple
-%destructor { expr_free($$); } queue_stmt_expr_simple
+%type <expr> queue_stmt_expr_simple queue_stmt_expr
+%destructor { expr_free($$); } queue_stmt_expr_simple queue_stmt_expr
%type <val> queue_stmt_flags queue_stmt_flag
%type <stmt> 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");
}