Blame SOURCES/0047-src-Optimize-prefix-matches-on-byte-boundaries.patch

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