From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH nftables 2/4] optimize: merge verdict maps with same lookup key
Date: Wed, 26 Jan 2022 23:33:12 +0100 [thread overview]
Message-ID: <20220126223314.297735-3-pablo@netfilter.org> (raw)
In-Reply-To: <20220126223314.297735-1-pablo@netfilter.org>
Merge two consecutive verdict maps with the same lookup key.
For instance, merge the following:
table inet x {
chain filter_in_tcp {
tcp dport vmap {
80 : accept,
81 : accept,
443 : accept,
931 : accept,
5001 : accept,
5201 : accept,
}
tcp dport vmap {
6800-6999 : accept,
33434-33499 : accept,
}
}
}
into:
table inet x {
chain filter_in_tcp {
tcp dport vmap {
80 : accept,
81 : accept,
443 : accept,
931 : accept,
5001 : accept,
5201 : accept,
6800-6999 : accept,
33434-33499 : accept,
}
}
}
This patch updates statement comparison routine to inspect the verdict
expression type to detect possible merger.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/optimize.c | 105 ++++++++++++++++--
.../optimizations/dumps/merge_vmaps.nft | 12 ++
.../shell/testcases/optimizations/merge_vmaps | 25 +++++
3 files changed, 130 insertions(+), 12 deletions(-)
create mode 100644 tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
create mode 100755 tests/shell/testcases/optimizations/merge_vmaps
diff --git a/src/optimize.c b/src/optimize.c
index c52966a86e2c..9a93e3b8d296 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -101,6 +101,15 @@ static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
case STMT_NOTRACK:
break;
case STMT_VERDICT:
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+
+ if (expr_a->etype != expr_b->etype)
+ return false;
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
break;
case STMT_LIMIT:
if (stmt_a->limit.rate != stmt_b->limit.rate ||
@@ -139,14 +148,8 @@ static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
return true;
}
-static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+static bool expr_verdict_eq(const struct expr *expr_a, const struct expr *expr_b)
{
- struct expr *expr_a, *expr_b;
-
- assert (stmt_a->ops->type == STMT_VERDICT);
-
- expr_a = stmt_a->expr;
- expr_b = stmt_b->expr;
if (expr_a->verdict != expr_b->verdict)
return false;
if (expr_a->chain && expr_b->chain) {
@@ -162,6 +165,25 @@ static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b
return true;
}
+static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *expr_a, *expr_b;
+
+ assert (stmt_a->ops->type == STMT_VERDICT);
+
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+ if (expr_a->etype == EXPR_VERDICT &&
+ expr_b->etype == EXPR_VERDICT)
+ return expr_verdict_eq(expr_a, expr_b);
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
+
+ return false;
+}
+
static bool stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
{
if (!stmt_a && !stmt_b)
@@ -194,6 +216,10 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
if (stmt_type_find(ctx, stmt))
continue;
+ if (stmt->ops->type == STMT_VERDICT &&
+ stmt->expr->etype == EXPR_MAP)
+ continue;
+
/* No refcounter available in statement objects, clone it to
* to store in the array of selectors.
*/
@@ -273,16 +299,15 @@ struct merge {
uint32_t num_stmts;
};
-static void merge_stmts(const struct optimize_ctx *ctx,
- uint32_t from, uint32_t to, const struct merge *merge)
+static void merge_expr_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
{
- struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
struct expr *expr_a, *expr_b, *set, *elem;
struct stmt *stmt_b;
uint32_t i;
- assert (stmt_a->ops->type == STMT_EXPRESSION);
-
set = set_expr_alloc(&internal_location, NULL);
set->set_flags |= NFT_SET_ANONYMOUS;
@@ -301,6 +326,62 @@ static void merge_stmts(const struct optimize_ctx *ctx,
stmt_a->expr->right = set;
}
+static void merge_vmap(const struct optimize_ctx *ctx,
+ struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *mappings, *mapping, *expr;
+
+ mappings = stmt_b->expr->mappings;
+ list_for_each_entry(expr, &mappings->expressions, list) {
+ mapping = expr_clone(expr);
+ compound_expr_add(stmt_a->expr->mappings, mapping);
+ }
+}
+
+static void merge_verdict_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
+{
+ struct stmt *stmt_b;
+ uint32_t i;
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ switch (stmt_b->ops->type) {
+ case STMT_VERDICT:
+ switch (stmt_b->expr->etype) {
+ case EXPR_MAP:
+ merge_vmap(ctx, stmt_a, stmt_b);
+ break;
+ default:
+ assert(1);
+ }
+ break;
+ default:
+ assert(1);
+ break;
+ }
+ }
+}
+
+static void merge_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to, const struct merge *merge)
+{
+ struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
+
+ switch (stmt_a->ops->type) {
+ case STMT_EXPRESSION:
+ merge_expr_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ case STMT_VERDICT:
+ merge_verdict_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ default:
+ assert(1);
+ }
+}
+
static void merge_concat_stmts(const struct optimize_ctx *ctx,
uint32_t from, uint32_t to,
const struct merge *merge)
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
new file mode 100644
index 000000000000..c1c9743b9f8c
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
@@ -0,0 +1,12 @@
+table ip x {
+ chain filter_in_tcp {
+ }
+
+ chain filter_in_udp {
+ }
+
+ chain y {
+ tcp dport vmap { 80 : accept, 81 : accept, 443 : accept, 8000-8100 : accept, 24000-25000 : accept }
+ meta l4proto vmap { tcp : goto filter_in_tcp, udp : goto filter_in_udp }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/merge_vmaps b/tests/shell/testcases/optimizations/merge_vmaps
new file mode 100755
index 000000000000..7b7a2723be4b
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_vmaps
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain filter_in_tcp {
+ }
+ chain filter_in_udp {
+ }
+ chain y {
+ tcp dport vmap {
+ 80 : accept,
+ 81 : accept,
+ 443 : accept,
+ }
+ tcp dport vmap {
+ 8000-8100 : accept,
+ 24000-25000 : accept,
+ }
+ meta l4proto tcp goto filter_in_tcp
+ meta l4proto udp goto filter_in_udp
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
--
2.30.2
next prev parent reply other threads:[~2022-01-26 22:33 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-26 22:33 [PATCH nftables 0/4] optimization updates Pablo Neira Ayuso
2022-01-26 22:33 ` [PATCH nftables 1/4] optimize: add __expr_cmp() Pablo Neira Ayuso
2022-01-26 22:33 ` Pablo Neira Ayuso [this message]
2022-01-26 22:33 ` [PATCH nftables 3/4] optimize: check for payload base and offset when searching for mergers Pablo Neira Ayuso
2022-01-26 22:33 ` [PATCH nftables 4/4] optimize: do not merge raw payload expressions Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220126223314.297735-3-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.