]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: evaluate: add preliminary binop transfer support for vmaps
authorFlorian Westphal <fw@strlen.de>
Thu, 11 Jan 2018 15:30:23 +0000 (16:30 +0100)
committerFlorian Westphal <fw@strlen.de>
Sat, 17 Mar 2018 00:47:18 +0000 (01:47 +0100)
nftables doesn't support vmap with bit-sized headers, such as flow label or dscp:

nft add rule ip filter input ip dscp vmap \{ 4 : accept, 63 : continue \}
BUG: invalid binary operation 5

Unlike plain "ip dscp { 4, 63 }", we don't have a relational operation in
case of vmap. Binop fixups need to be done when evaluating map statements.

This patch is incomplete. 'ip dscp' works, but this won't:
  nft add rule --debug=netlink ip6 test-ip6 input ip6 dscp vmap { 0x04 : accept, 0x3f : continue }

The generated expressions look sane, however there is disagreement on
the sets key size vs. the sizes of the individual elements in the set.
This is because ip6 dscp spans a byte boundary.

Key set size is still set to one byte (dscp type is 6bits).
However, binop expansion requirements result in 2 byte loads, i.e.
set members will be 2 bytes in size as well.

This can hopefully get addressed in an incremental patch.

Signed-off-by: Florian Westphal <fw@strlen.de>
src/evaluate.c

index 46ac9e43a37a86e6094607fca1d3a296caf3f875..8de5e48d728addb254b15a640acc79316bb7f6f1 100644 (file)
@@ -1242,6 +1242,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
        return 0;
 }
 
+static int binop_transfer(struct eval_ctx *ctx, struct expr **expr);
 static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 {
        struct expr_ctx ectx = ctx->ectx;
@@ -1277,8 +1278,12 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
                ctx->set = mappings->set;
                if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
                        return -1;
-               ctx->set = NULL;
+               expr_set_context(&ctx->ectx, ctx->set->key->dtype, ctx->set->key->len);
+               if (binop_transfer(ctx, expr) < 0)
+                       return -1;
 
+               map = *expr;
+               ctx->set = NULL;
                map->mappings->set->flags |= map->mappings->set->init->set_flags;
                break;
        case EXPR_SYMBOL:
@@ -1408,6 +1413,8 @@ static int binop_can_transfer(struct eval_ctx *ctx,
        switch (right->ops->type) {
        case EXPR_VALUE:
                break;
+       case EXPR_SET_ELEM:
+               return binop_can_transfer(ctx, left, right->key);
        case EXPR_RANGE:
                err = binop_can_transfer(ctx, left, right->left);
                if (err <= 0)
@@ -1442,6 +1449,8 @@ static int binop_transfer_one(struct eval_ctx *ctx,
        switch ((*right)->ops->type) {
        case EXPR_VALUE:
                break;
+       case EXPR_SET_ELEM:
+               return binop_transfer_one(ctx, left, &(*right)->key);
        case EXPR_RANGE:
                err = binop_transfer_one(ctx, left, &(*right)->left);
                if (err < 0)
@@ -1516,6 +1525,7 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
                        switch (i->key->ops->type) {
                        case EXPR_VALUE:
                        case EXPR_RANGE:
+                       case EXPR_SET_ELEM:
                                err = binop_can_transfer(ctx, left, i->key);
                                if (err <= 0)
                                        return err;
@@ -1530,6 +1540,7 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
                        switch (i->key->ops->type) {
                        case EXPR_VALUE:
                        case EXPR_RANGE:
+                       case EXPR_SET_ELEM:
                                if (binop_transfer_one(ctx, left, &i->key) < 0)
                                        return -1;
                                break;