From 8b4c95dae6c19eb29fb4ad5e931b67097851f0f1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Jan 2022 21:53:26 +0100 Subject: optimize: merge rules with same selectors into a concatenation 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 --- src/optimize.c | 44 +++++++++++++++++++++- .../optimizations/dumps/merge_stmts_concat.nft | 5 +++ .../testcases/optimizations/merge_stmts_concat | 13 +++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft create mode 100755 tests/shell/testcases/optimizations/merge_stmts_concat diff --git a/src/optimize.c b/src/optimize.c index bae36d76..5950e852 100644 --- a/src/optimize.c +++ b/src/optimize.c @@ -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 index 00000000..6dbfff2e --- /dev/null +++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft @@ -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 index 00000000..941e9a5a --- /dev/null +++ b/tests/shell/testcases/optimizations/merge_stmts_concat @@ -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 -- cgit v1.2.3