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

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