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

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