]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: revisit anonymous set with single element optimization
authorPablo Neira Ayuso <pablo@netfilter.org>
Sat, 2 Sep 2023 08:37:39 +0000 (10:37 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 2 Sep 2023 19:13:14 +0000 (21:13 +0200)
This patch reworks it to perform this optimization from the evaluation
step of the relational expression. Hence, when optimizing for protocol
flags, use OP_EQ instead of OP_IMPLICIT, that is:

tcp flags { syn }

becomes (to represent an exact match):

tcp flags == syn

given OP_IMPLICIT and OP_EQ are not equivalent for flags.

01167c393a12 ("evaluate: do not remove anonymous set with protocol flags
and single element") disabled this optimization, which is enabled again
after this patch.

Fixes: 01167c393a12 ("evaluate: do not remove anonymous set with protocol flags and single element")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c

index a7725f4e4c96cda0d9c872e42fa0feb4fe694259..ab3ec98739e99e67dba37e021a1c064ee7555c12 100644 (file)
@@ -1815,26 +1815,6 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
        if (ctx->set) {
                if (ctx->set->flags & NFT_SET_CONCAT)
                        set->set_flags |= NFT_SET_CONCAT;
-       } else if (set->size == 1) {
-               i = list_first_entry(&set->expressions, struct expr, list);
-               if (i->etype == EXPR_SET_ELEM &&
-                   (!i->dtype->basetype ||
-                    i->dtype->basetype->type != TYPE_BITMASK ||
-                    i->dtype->type == TYPE_CT_STATE) &&
-                   list_empty(&i->stmt_list)) {
-
-                       switch (i->key->etype) {
-                       case EXPR_PREFIX:
-                       case EXPR_RANGE:
-                       case EXPR_VALUE:
-                               *expr = i->key;
-                               i->key = NULL;
-                               expr_free(set);
-                               return 0;
-                       default:
-                               break;
-                       }
-               }
        }
 
        set->set_flags |= NFT_SET_CONSTANT;
@@ -2355,6 +2335,35 @@ static bool range_needs_swap(const struct expr *range)
        return mpz_cmp(left->value, right->value) > 0;
 }
 
+static void optimize_singleton_set(struct expr *rel, struct expr **expr)
+{
+       struct expr *set = rel->right, *i;
+
+       i = list_first_entry(&set->expressions, struct expr, list);
+       if (i->etype == EXPR_SET_ELEM &&
+           list_empty(&i->stmt_list)) {
+
+               switch (i->key->etype) {
+               case EXPR_PREFIX:
+               case EXPR_RANGE:
+               case EXPR_VALUE:
+                       rel->right = *expr = i->key;
+                       i->key = NULL;
+                       expr_free(set);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (rel->op == OP_IMPLICIT &&
+           rel->right->dtype->basetype &&
+           rel->right->dtype->basetype->type == TYPE_BITMASK &&
+           rel->right->dtype->type != TYPE_CT_STATE) {
+               rel->op = OP_EQ;
+       }
+}
+
 static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
 {
        struct expr *rel = *expr, *left, *right;
@@ -2434,6 +2443,17 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                return expr_binary_error(ctx->msgs, right, left,
                                         "Cannot be used with right hand side constant value");
 
+       switch (rel->op) {
+       case OP_EQ:
+       case OP_IMPLICIT:
+       case OP_NEQ:
+               if (right->etype == EXPR_SET && right->size == 1)
+                       optimize_singleton_set(rel, &right);
+               break;
+       default:
+               break;
+       }
+
        switch (rel->op) {
        case OP_EQ:
        case OP_IMPLICIT: