summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/optimize.c44
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft5
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat13
3 files changed, 61 insertions, 1 deletions
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