summaryrefslogtreecommitdiffstats
path: root/src/netlink_delinearize.c
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 /src/netlink_delinearize.c
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>
Diffstat (limited to 'src/netlink_delinearize.c')
-rw-r--r--src/netlink_delinearize.c48
1 files changed, 38 insertions, 10 deletions
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;
}