Blame SOURCES/0035-netlink_delinearize-Refactor-meta_may_dependency_kil.patch

bacbc8
From 0709a45a89405ad4c564b3a8071fffb79da58612 Mon Sep 17 00:00:00 2001
bacbc8
From: Phil Sutter <phil@nwl.cc>
bacbc8
Date: Thu, 21 Jun 2018 14:01:13 +0200
bacbc8
Subject: [PATCH] netlink_delinearize: Refactor meta_may_dependency_kill()
bacbc8
bacbc8
The original intent was to fix a bug: The following rule in inet table:
bacbc8
bacbc8
| meta nfproto ipv4 icmpv6 type echo-reply
bacbc8
bacbc8
Was added correctly but when printing the meta match was falsely
bacbc8
removed. The fix is to deny dependency killing if RHS family of nfproto
bacbc8
match doesn't match RHS family of l4proto match. Adding this to the
bacbc8
already large conditional led to even more unreadable code, therefore
bacbc8
this patch tries to clean that up (and also removes the partial code
bacbc8
duplication.
bacbc8
bacbc8
Signed-off-by: Phil Sutter <phil@nwl.cc>
bacbc8
Signed-off-by: Florian Westphal <fw@strlen.de>
bacbc8
(cherry picked from commit 056aaa3e6dc65aced5e552233ac3e7f89fb81f86)
bacbc8
Signed-off-by: Phil Sutter <psutter@redhat.com>
bacbc8
---
bacbc8
 src/netlink_delinearize.c        |  83 +++++++++++-----------
bacbc8
 tests/py/inet/icmp.t             |  18 +++++
bacbc8
 tests/py/inet/icmp.t.json        | 114 +++++++++++++++++++++++++++++++
bacbc8
 tests/py/inet/icmp.t.json.output |  30 ++++++++
bacbc8
 tests/py/inet/icmp.t.payload     |  54 +++++++++++++++
bacbc8
 5 files changed, 259 insertions(+), 40 deletions(-)
bacbc8
 create mode 100644 tests/py/inet/icmp.t
bacbc8
 create mode 100644 tests/py/inet/icmp.t.json
bacbc8
 create mode 100644 tests/py/inet/icmp.t.json.output
bacbc8
 create mode 100644 tests/py/inet/icmp.t.payload
bacbc8
bacbc8
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
bacbc8
index bf990e9e979d5..0f4f62f34256c 100644
bacbc8
--- a/src/netlink_delinearize.c
bacbc8
+++ b/src/netlink_delinearize.c
bacbc8
@@ -1525,61 +1525,64 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
bacbc8
 				     const struct expr *expr)
bacbc8
 {
bacbc8
 	struct expr *dep = ctx->pdep->expr;
bacbc8
+	uint16_t l3proto;
bacbc8
+	uint8_t l4proto;
bacbc8
 
bacbc8
 	if (ctx->pbase != PROTO_BASE_NETWORK_HDR)
bacbc8
 		return true;
bacbc8
 
bacbc8
 	switch (family) {
bacbc8
 	case NFPROTO_INET:
bacbc8
-		switch (dep->left->ops->type) {
bacbc8
-		case EXPR_META:
bacbc8
-			if (dep->left->meta.key == NFT_META_NFPROTO &&
bacbc8
-			    (mpz_get_uint16(dep->right->value) == NFPROTO_IPV4 ||
bacbc8
-			     mpz_get_uint16(dep->right->value) == NFPROTO_IPV6) &&
bacbc8
-			    expr->left->meta.key == NFT_META_L4PROTO &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
bacbc8
-				return false;
bacbc8
-			break;
bacbc8
-		case EXPR_PAYLOAD:
bacbc8
-			if (dep->left->payload.base == PROTO_BASE_LL_HDR &&
bacbc8
-			    (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
bacbc8
-			     mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
bacbc8
-			    expr->left->meta.key == NFT_META_L4PROTO &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
bacbc8
-				return false;
bacbc8
-			break;
bacbc8
-		default:
bacbc8
-			break;
bacbc8
-		}
bacbc8
-		break;
bacbc8
 	case NFPROTO_NETDEV:
bacbc8
 	case NFPROTO_BRIDGE:
bacbc8
-		switch (dep->left->ops->type) {
bacbc8
-		case EXPR_META:
bacbc8
-			if (dep->left->meta.key == NFT_META_PROTOCOL &&
bacbc8
-			    (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
bacbc8
-			     mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
bacbc8
-			    expr->left->meta.key == NFT_META_L4PROTO &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
bacbc8
-				return false;
bacbc8
+		break;
bacbc8
+	default:
bacbc8
+		return true;
bacbc8
+	}
bacbc8
+
bacbc8
+	if (expr->left->meta.key != NFT_META_L4PROTO)
bacbc8
+		return true;
bacbc8
+
bacbc8
+	l3proto = mpz_get_uint16(dep->right->value);
bacbc8
+
bacbc8
+	switch (dep->left->ops->type) {
bacbc8
+	case EXPR_META:
bacbc8
+		if (dep->left->meta.key != NFT_META_NFPROTO)
bacbc8
+			return true;
bacbc8
+		break;
bacbc8
+	case EXPR_PAYLOAD:
bacbc8
+		if (dep->left->payload.base != PROTO_BASE_LL_HDR)
bacbc8
+			return true;
bacbc8
+
bacbc8
+		switch(l3proto) {
bacbc8
+		case ETH_P_IP:
bacbc8
+			l3proto = NFPROTO_IPV4;
bacbc8
 			break;
bacbc8
-		case EXPR_PAYLOAD:
bacbc8
-			if (dep->left->payload.base == PROTO_BASE_LL_HDR &&
bacbc8
-			    (mpz_get_uint16(dep->right->value) == ETH_P_IP ||
bacbc8
-			     mpz_get_uint16(dep->right->value) == ETH_P_IPV6) &&
bacbc8
-			    expr->left->meta.key == NFT_META_L4PROTO &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMP &&
bacbc8
-			    mpz_get_uint8(expr->right->value) != IPPROTO_ICMPV6)
bacbc8
-				return false;
bacbc8
+		case ETH_P_IPV6:
bacbc8
+			l3proto = NFPROTO_IPV6;
bacbc8
 			break;
bacbc8
 		default:
bacbc8
 			break;
bacbc8
 		}
bacbc8
 		break;
bacbc8
+	default:
bacbc8
+		break;
bacbc8
+	}
bacbc8
+
bacbc8
+	l4proto = mpz_get_uint8(expr->right->value);
bacbc8
+
bacbc8
+	switch (l4proto) {
bacbc8
+	case IPPROTO_ICMP:
bacbc8
+	case IPPROTO_ICMPV6:
bacbc8
+		break;
bacbc8
+	default:
bacbc8
+		return false;
bacbc8
 	}
bacbc8
+
bacbc8
+	if ((l3proto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
bacbc8
+	    (l3proto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
bacbc8
+		return false;
bacbc8
+
bacbc8
 	return true;
bacbc8
 }
bacbc8
 
bacbc8
diff --git a/tests/py/inet/icmp.t b/tests/py/inet/icmp.t
bacbc8
new file mode 100644
bacbc8
index 0000000000000..9014f846729c7
bacbc8
--- /dev/null
bacbc8
+++ b/tests/py/inet/icmp.t
bacbc8
@@ -0,0 +1,18 @@
bacbc8
+:output;type filter hook output priority 0
bacbc8
+
bacbc8
+*inet;test-inet;output
bacbc8
+
bacbc8
+# without nfproto specified, these should add an implicit dependency on
bacbc8
+# the likely l3 proto (i.e., IPv6 for icmpv6 and IPv4 for icmp)
bacbc8
+
bacbc8
+icmp type echo-request;ok
bacbc8
+icmpv6 type echo-request;ok
bacbc8
+
bacbc8
+# make sure only those nfproto matches are dropped if
bacbc8
+# the next statement would add it as a dependency anyway
bacbc8
+
bacbc8
+meta nfproto ipv4 icmp type echo-request;ok;icmp type echo-request
bacbc8
+meta nfproto ipv4 icmpv6 type echo-request;ok
bacbc8
+
bacbc8
+meta nfproto ipv6 icmp type echo-request;ok
bacbc8
+meta nfproto ipv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
bacbc8
diff --git a/tests/py/inet/icmp.t.json b/tests/py/inet/icmp.t.json
bacbc8
new file mode 100644
bacbc8
index 0000000000000..c4517605a7186
bacbc8
--- /dev/null
bacbc8
+++ b/tests/py/inet/icmp.t.json
bacbc8
@@ -0,0 +1,114 @@
bacbc8
+# icmp type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmp"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# icmpv6 type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmpv6"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# meta nfproto ipv4 icmp type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": { "meta": "nfproto" },
bacbc8
+            "right": "ipv4"
bacbc8
+        }
bacbc8
+    },
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmp"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# meta nfproto ipv4 icmpv6 type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": { "meta": "nfproto" },
bacbc8
+            "right": "ipv4"
bacbc8
+        }
bacbc8
+    },
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmpv6"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# meta nfproto ipv6 icmp type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": { "meta": "nfproto" },
bacbc8
+            "right": "ipv6"
bacbc8
+        }
bacbc8
+    },
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmp"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# meta nfproto ipv6 icmpv6 type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": { "meta": "nfproto" },
bacbc8
+            "right": "ipv6"
bacbc8
+        }
bacbc8
+    },
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmpv6"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
diff --git a/tests/py/inet/icmp.t.json.output b/tests/py/inet/icmp.t.json.output
bacbc8
new file mode 100644
bacbc8
index 0000000000000..2282900d58e98
bacbc8
--- /dev/null
bacbc8
+++ b/tests/py/inet/icmp.t.json.output
bacbc8
@@ -0,0 +1,30 @@
bacbc8
+# meta nfproto ipv4 icmp type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmp"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
+# meta nfproto ipv6 icmpv6 type echo-request
bacbc8
+[
bacbc8
+    {
bacbc8
+        "match": {
bacbc8
+            "left": {
bacbc8
+                "payload": {
bacbc8
+                    "field": "type",
bacbc8
+                    "name": "icmpv6"
bacbc8
+                }
bacbc8
+            },
bacbc8
+            "right": "echo-request"
bacbc8
+        }
bacbc8
+    }
bacbc8
+]
bacbc8
+
bacbc8
diff --git a/tests/py/inet/icmp.t.payload b/tests/py/inet/icmp.t.payload
bacbc8
new file mode 100644
bacbc8
index 0000000000000..f98cfc39abed4
bacbc8
--- /dev/null
bacbc8
+++ b/tests/py/inet/icmp.t.payload
bacbc8
@@ -0,0 +1,54 @@
bacbc8
+# icmp type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000002 ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000001 ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000008 ]
bacbc8
+
bacbc8
+# icmpv6 type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000000a ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000003a ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000080 ]
bacbc8
+
bacbc8
+# meta nfproto ipv4 icmp type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000002 ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000001 ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000008 ]
bacbc8
+
bacbc8
+# meta nfproto ipv4 icmpv6 type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000002 ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000003a ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000080 ]
bacbc8
+
bacbc8
+# meta nfproto ipv6 icmp type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000000a ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000001 ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000008 ]
bacbc8
+
bacbc8
+# meta nfproto ipv6 icmpv6 type echo-request
bacbc8
+inet test-inet output 
bacbc8
+  [ meta load nfproto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000000a ]
bacbc8
+  [ meta load l4proto => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x0000003a ]
bacbc8
+  [ payload load 1b @ transport header + 0 => reg 1 ]
bacbc8
+  [ cmp eq reg 1 0x00000080 ]
bacbc8
+
bacbc8
-- 
bacbc8
2.21.0
bacbc8