]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
optimize: merge rules with same selectors into a concatenation
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 2 Jan 2022 20:53:26 +0000 (21:53 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 15 Jan 2022 17:11:22 +0000 (18:11 +0100)
This patch extends the ruleset optimization infrastructure to collapse
several rules with the same selectors into a concatenation.

Transform:

  meta iifname eth1 ip saddr 1.1.1.1 ip daddr 2.2.2.3 accept
  meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.2.5 accept
  meta iifname eth2 ip saddr 1.1.1.3 ip daddr 2.2.2.6 accept

into:

  meta iifname . ip saddr . ip daddr { eth1 . 1.1.1.1 . 2.2.2.6, eth1 . 1.1.1.2 . 2.2.2.5 , eth1 . 1.1.1.3 . 2.2.2.6 } accept

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/optimize.c
tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft [new file with mode: 0644]
tests/shell/testcases/optimizations/merge_stmts_concat [new file with mode: 0755]

index bae36d763656d5ea748a76789844c8140de7838d..5950e8528158c67473c03a662121b0adce22d065 100644 (file)
@@ -271,6 +271,48 @@ static void merge_stmts(const struct optimize_ctx *ctx,
        stmt_a->expr->right = set;
 }
 
+static void merge_concat_stmts(const struct optimize_ctx *ctx,
+                              uint32_t from, uint32_t to,
+                              const struct merge *merge)
+{
+       struct expr *concat, *elem, *set;
+       struct stmt *stmt, *stmt_a;
+       uint32_t i, k;
+
+       stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+       /* build concatenation of selectors, eg. ifname . ip daddr . tcp dport */
+       concat = concat_expr_alloc(&internal_location);
+
+       for (k = 0; k < merge->num_stmts; k++) {
+               stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+               compound_expr_add(concat, expr_get(stmt_a->expr->left));
+       }
+       expr_free(stmt->expr->left);
+       stmt->expr->left = concat;
+
+       /* build set data contenation, eg. { eth0 . 1.1.1.1 . 22 } */
+       set = set_expr_alloc(&internal_location, NULL);
+       set->set_flags |= NFT_SET_ANONYMOUS;
+
+       for (i = from; i <= to; i++) {
+               concat = concat_expr_alloc(&internal_location);
+               for (k = 0; k < merge->num_stmts; k++) {
+                       stmt_a = ctx->stmt_matrix[i][merge->stmt[k]];
+                       compound_expr_add(concat, expr_get(stmt_a->expr->right));
+               }
+               elem = set_elem_expr_alloc(&internal_location, concat);
+               compound_expr_add(set, elem);
+       }
+       expr_free(stmt->expr->right);
+       stmt->expr->right = set;
+
+       for (k = 1; k < merge->num_stmts; k++) {
+               stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+               list_del(&stmt_a->list);
+               stmt_free(stmt_a);
+       }
+}
+
 static void rule_optimize_print(struct output_ctx *octx,
                                const struct rule *rule)
 {
@@ -312,7 +354,7 @@ static void merge_rules(const struct optimize_ctx *ctx,
        uint32_t i;
 
        if (merge->num_stmts > 1) {
-               return;
+               merge_concat_stmts(ctx, from, to, merge);
        } else {
                merge_stmts(ctx, from, to, merge);
        }
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
new file mode 100644 (file)
index 0000000..6dbfff2
--- /dev/null
@@ -0,0 +1,5 @@
+table ip x {
+       chain y {
+               iifname . ip saddr . ip daddr { "eth1" . 1.1.1.1 . 2.2.2.3, "eth1" . 1.1.1.2 . 2.2.2.4, "eth2" . 1.1.1.3 . 2.2.2.5 } accept
+       }
+}
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat b/tests/shell/testcases/optimizations/merge_stmts_concat
new file mode 100755 (executable)
index 0000000..941e9a5
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+       chain y {
+               meta iifname eth1 ip saddr 1.1.1.1 ip daddr 2.2.2.3 accept
+               meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.2.4 accept
+               meta iifname eth2 ip saddr 1.1.1.3 ip daddr 2.2.2.5 accept
+       }
+}"
+
+$NFT -o -f - <<< $RULESET