242 lines
9.3 KiB
Diff
242 lines
9.3 KiB
Diff
From 6fb6d8f15a82b3348184f6950a436becb06931cb Mon Sep 17 00:00:00 2001
|
|
From: Phil Sutter <psutter@redhat.com>
|
|
Date: Wed, 19 May 2021 18:03:43 +0200
|
|
Subject: [PATCH] src: Optimize prefix matches on byte-boundaries
|
|
|
|
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1934926
|
|
Upstream Status: nftables commit 25338cdb6c77a
|
|
Conflicts: There is a hidden dependency on commit ee4391d0ac1e7 ("nat:
|
|
transform range to prefix expression when possible").
|
|
Backport only the single chunk required to keep prefix
|
|
parsing intact to avoid having to backport 9599d9d25a6b3
|
|
("src: NAT support for intervals in maps") as a dependency
|
|
which is clearly oversized for the sake of this purpose.
|
|
|
|
commit 25338cdb6c77aa2f0977afbbb612571c9d325213
|
|
Author: Phil Sutter <phil@nwl.cc>
|
|
Date: Tue Oct 27 17:33:15 2020 +0100
|
|
|
|
src: Optimize prefix matches on byte-boundaries
|
|
|
|
If a prefix expression's length is on a byte-boundary, it is sufficient
|
|
to just reduce the length passed to "cmp" expression. No need for
|
|
explicit bitwise modification of data on LHS. The relevant code is
|
|
already there, used for string prefix matches. There is one exception
|
|
though, namely zero-length prefixes: Kernel doesn't accept zero-length
|
|
"cmp" expressions, so keep them in the old code-path for now.
|
|
|
|
This patch depends upon the previous one to correctly parse odd-sized
|
|
payload matches but has to extend support for non-payload LHS as well.
|
|
In practice, this is needed for "ct" expressions as they allow matching
|
|
against IP address prefixes, too.
|
|
|
|
Signed-off-by: Phil Sutter <phil@nwl.cc>
|
|
---
|
|
src/netlink_delinearize.c | 8 ++++++--
|
|
src/netlink_linearize.c | 4 +++-
|
|
tests/py/ip/ct.t.payload | 4 ----
|
|
tests/py/ip/ip.t.payload | 6 ++----
|
|
tests/py/ip/ip.t.payload.bridge | 6 ++----
|
|
tests/py/ip/ip.t.payload.inet | 6 ++----
|
|
tests/py/ip/ip.t.payload.netdev | 6 ++----
|
|
tests/py/ip6/ip6.t.payload.inet | 5 ++---
|
|
tests/py/ip6/ip6.t.payload.ip6 | 5 ++---
|
|
9 files changed, 21 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
|
|
index 8bdee12..157a473 100644
|
|
--- a/src/netlink_delinearize.c
|
|
+++ b/src/netlink_delinearize.c
|
|
@@ -291,8 +291,9 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
|
|
|
|
if (left->len > right->len &&
|
|
expr_basetype(left) != &string_type) {
|
|
- netlink_error(ctx, loc, "Relational expression size mismatch");
|
|
- goto err_free;
|
|
+ mpz_lshift_ui(right->value, left->len - right->len);
|
|
+ right = prefix_expr_alloc(loc, right, right->len);
|
|
+ right->prefix->len = left->len;
|
|
} else if (left->len > 0 && left->len < right->len) {
|
|
expr_free(left);
|
|
left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
|
|
@@ -2164,6 +2165,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
|
|
expr_postprocess(ctx, &expr->left);
|
|
expr_postprocess(ctx, &expr->right);
|
|
break;
|
|
+ case EXPR_PREFIX:
|
|
+ expr_postprocess(ctx, &expr->prefix);
|
|
+ break;
|
|
case EXPR_SET_ELEM:
|
|
expr_postprocess(ctx, &expr->key);
|
|
break;
|
|
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
|
|
index 606d97a..25be634 100644
|
|
--- a/src/netlink_linearize.c
|
|
+++ b/src/netlink_linearize.c
|
|
@@ -501,7 +501,9 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
|
|
return netlink_gen_flagcmp(ctx, expr, dreg);
|
|
case EXPR_PREFIX:
|
|
sreg = get_register(ctx, expr->left);
|
|
- if (expr_basetype(expr->left)->type != TYPE_STRING) {
|
|
+ if (expr_basetype(expr->left)->type != TYPE_STRING &&
|
|
+ (!expr->right->prefix_len ||
|
|
+ expr->right->prefix_len % BITS_PER_BYTE)) {
|
|
len = div_round_up(expr->right->len, BITS_PER_BYTE);
|
|
netlink_gen_expr(ctx, expr->left, sreg);
|
|
right = netlink_gen_prefix(ctx, expr, sreg);
|
|
diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload
|
|
index d5faed4..a7e08f9 100644
|
|
--- a/tests/py/ip/ct.t.payload
|
|
+++ b/tests/py/ip/ct.t.payload
|
|
@@ -21,25 +21,21 @@ ip test-ip4 output
|
|
# ct original ip saddr 192.168.1.0/24
|
|
ip test-ip4 output
|
|
[ ct load src_ip => reg 1 , dir original ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
[ cmp eq reg 1 0x0001a8c0 ]
|
|
|
|
# ct reply ip saddr 192.168.1.0/24
|
|
ip test-ip4 output
|
|
[ ct load src_ip => reg 1 , dir reply ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
[ cmp eq reg 1 0x0001a8c0 ]
|
|
|
|
# ct original ip daddr 192.168.1.0/24
|
|
ip test-ip4 output
|
|
[ ct load dst_ip => reg 1 , dir original ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
[ cmp eq reg 1 0x0001a8c0 ]
|
|
|
|
# ct reply ip daddr 192.168.1.0/24
|
|
ip test-ip4 output
|
|
[ ct load dst_ip => reg 1 , dir reply ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
[ cmp eq reg 1 0x0001a8c0 ]
|
|
|
|
# ct l3proto ipv4
|
|
diff --git a/tests/py/ip/ip.t.payload b/tests/py/ip/ip.t.payload
|
|
index d627b22..825c0f0 100644
|
|
--- a/tests/py/ip/ip.t.payload
|
|
+++ b/tests/py/ip/ip.t.payload
|
|
@@ -358,14 +358,12 @@ ip test-ip4 input
|
|
|
|
# ip saddr 192.168.2.0/24
|
|
ip test-ip4 input
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp eq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr != 192.168.2.0/24
|
|
ip test-ip4 input
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp neq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
|
|
diff --git a/tests/py/ip/ip.t.payload.bridge b/tests/py/ip/ip.t.payload.bridge
|
|
index 91a4fde..e958a5b 100644
|
|
--- a/tests/py/ip/ip.t.payload.bridge
|
|
+++ b/tests/py/ip/ip.t.payload.bridge
|
|
@@ -466,16 +466,14 @@ bridge test-bridge input
|
|
bridge test-bridge input
|
|
[ meta load protocol => reg 1 ]
|
|
[ cmp eq reg 1 0x00000008 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp eq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr != 192.168.2.0/24
|
|
bridge test-bridge input
|
|
[ meta load protocol => reg 1 ]
|
|
[ cmp eq reg 1 0x00000008 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp neq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
|
|
diff --git a/tests/py/ip/ip.t.payload.inet b/tests/py/ip/ip.t.payload.inet
|
|
index b9cb28a..6501473 100644
|
|
--- a/tests/py/ip/ip.t.payload.inet
|
|
+++ b/tests/py/ip/ip.t.payload.inet
|
|
@@ -466,16 +466,14 @@ inet test-inet input
|
|
inet test-inet input
|
|
[ meta load nfproto => reg 1 ]
|
|
[ cmp eq reg 1 0x00000002 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp eq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr != 192.168.2.0/24
|
|
inet test-inet input
|
|
[ meta load nfproto => reg 1 ]
|
|
[ cmp eq reg 1 0x00000002 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp neq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
|
|
diff --git a/tests/py/ip/ip.t.payload.netdev b/tests/py/ip/ip.t.payload.netdev
|
|
index 588e5ca..58ae358 100644
|
|
--- a/tests/py/ip/ip.t.payload.netdev
|
|
+++ b/tests/py/ip/ip.t.payload.netdev
|
|
@@ -379,16 +379,14 @@ netdev test-netdev ingress
|
|
netdev test-netdev ingress
|
|
[ meta load protocol => reg 1 ]
|
|
[ cmp eq reg 1 0x00000008 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp eq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr != 192.168.2.0/24
|
|
netdev test-netdev ingress
|
|
[ meta load protocol => reg 1 ]
|
|
[ cmp eq reg 1 0x00000008 ]
|
|
- [ payload load 4b @ network header + 12 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
|
+ [ payload load 3b @ network header + 12 => reg 1 ]
|
|
[ cmp neq reg 1 0x0002a8c0 ]
|
|
|
|
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
|
|
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
|
|
index d015c8e..ffc9b9f 100644
|
|
--- a/tests/py/ip6/ip6.t.payload.inet
|
|
+++ b/tests/py/ip6/ip6.t.payload.inet
|
|
@@ -604,9 +604,8 @@ inet test-inet input
|
|
inet test-inet input
|
|
[ meta load nfproto => reg 1 ]
|
|
[ cmp eq reg 1 0x0000000a ]
|
|
- [ payload load 16b @ network header + 8 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
|
|
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
|
|
+ [ payload load 8b @ network header + 8 => reg 1 ]
|
|
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
|
|
|
|
# ip6 saddr ::1 ip6 daddr ::2
|
|
inet test-inet input
|
|
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
|
|
index b2e8363..18b8bcb 100644
|
|
--- a/tests/py/ip6/ip6.t.payload.ip6
|
|
+++ b/tests/py/ip6/ip6.t.payload.ip6
|
|
@@ -452,9 +452,8 @@ ip6 test-ip6 input
|
|
|
|
# ip6 saddr ::/64
|
|
ip6 test-ip6 input
|
|
- [ payload load 16b @ network header + 8 => reg 1 ]
|
|
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
|
|
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
|
|
+ [ payload load 8b @ network header + 8 => reg 1 ]
|
|
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
|
|
|
|
# ip6 saddr ::1 ip6 daddr ::2
|
|
ip6 test-ip6 input
|
|
--
|
|
1.8.3.1
|
|
|