nftables/SOURCES/0274-expression-propagate-key-datatype-for-anonymous-sets.patch
2026-08-26 08:03:54 -04:00

179 lines
6.0 KiB
Diff

From f1fd3a56922f88551c2a2c94654aa5175f6d410c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Jul 2026 11:30:58 +0200
Subject: [PATCH] expression: propagate key datatype for anonymous sets
JIRA: https://issues.redhat.com/browse/RHEL-190549
Upstream Status: nftables commit 3d6ad54dbc74449e171823cdaf9d43cd41721b8d
commit 3d6ad54dbc74449e171823cdaf9d43cd41721b8d
Author: Florian Westphal <fw@strlen.de>
Date: Thu Feb 27 15:52:08 2025 +0100
expression: propagate key datatype for anonymous sets
set s {
typeof tcp option mptcp subtype
elements = { mp-join, dss }
}
is listed correctly. The set key provides the 'mptcpopt_subtype'
information and listing can print all elements with symbolic names.
In anon set case this doesn't work:
tcp option mptcp subtype { mp-join, dss }
is printed as "... subtype { 1, 2}" because the anon set only provides
plain integer type.
This change propagates the datatype to the individual members of the
anon set.
After this change, multiple existing data types such as TYPE_ICMP_TYPE
could theoretically be replaced by integer-type aliases.
However, those datatypes are already exposed to userspace via the
'set type' keyword. Thus removing them will break set definitions that
use them.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/expression.c | 35 +++++++++++++++++++++++++++++++++++
tests/py/any/tcpopt.t | 2 +-
tests/py/any/tcpopt.t.json | 11 ++++++++---
tests/py/any/tcpopt.t.payload | 10 +++++-----
4 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/src/expression.c b/src/expression.c
index 09449da..4fd0a91 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1365,6 +1365,32 @@ static void set_ref_expr_destroy(struct expr *expr)
set_free(expr->set);
}
+static void set_ref_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ const struct set *s = expr->set;
+
+ /* normal sets already have a precise datatype that is given in
+ * the set definition via type foo.
+ *
+ * Anon sets do not have this, and need to rely on type info
+ * generated at rule creation time.
+ *
+ * For most cases, the type info is correct.
+ * In some cases however, the kernel only stores TYPE_INTEGER.
+ *
+ * This happens with expressions that only use an integer alias
+ * type, e.g. the mptcpopt_subtype datatype.
+ *
+ * In this case nft will print the elements as numerical values
+ * because the base type lacks the ->sym_tbl information of the
+ * subtypes.
+ */
+ if (s->init && set_is_anonymous(s->flags))
+ expr_set_type(s->init, dtype, byteorder);
+}
+
static const struct expr_ops set_ref_expr_ops = {
.type = EXPR_SET_REF,
.name = "set reference",
@@ -1372,6 +1398,7 @@ static const struct expr_ops set_ref_expr_ops = {
.json = set_ref_expr_json,
.clone = set_ref_expr_clone,
.destroy = set_ref_expr_destroy,
+ .set_type = set_ref_expr_set_type,
};
struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
@@ -1431,6 +1458,13 @@ static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
__set_elem_expr_clone(new, expr);
}
+static void set_elem_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ expr_set_type(expr->key, dtype, byteorder);
+}
+
static const struct expr_ops set_elem_expr_ops = {
.type = EXPR_SET_ELEM,
.name = "set element",
@@ -1438,6 +1472,7 @@ static const struct expr_ops set_elem_expr_ops = {
.print = set_elem_expr_print,
.json = set_elem_expr_json,
.destroy = set_elem_expr_destroy,
+ .set_type = set_elem_expr_set_type,
};
struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index a2fcdb3..79699e2 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -53,7 +53,7 @@ tcp option mptcp exists;ok
tcp option mptcp subtype mp-capable;ok
tcp option mptcp subtype 1;ok;tcp option mptcp subtype mp-join
-tcp option mptcp subtype { 0, 2};ok
+tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst };ok
reset tcp option mptcp;ok
reset tcp option 2;ok;reset tcp option maxseg
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index bf10c55..fb0662a 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -565,7 +565,7 @@
}
]
-# tcp option mptcp subtype { 0, 2}
+# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst }
[
{
"match": {
@@ -578,8 +578,13 @@
"op": "==",
"right": {
"set": [
- 0,
- 2
+ "mp-capable",
+ "mp-join",
+ "remove-addr",
+ "mp-prio",
+ "mp-fail",
+ "mp-fastclose",
+ "mp-tcprst"
]
}
}
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index e3cf500..af8c431 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -180,11 +180,11 @@ inet
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
-# tcp option mptcp subtype { 0, 2}
-__set%d test-inet 3 size 2
-__set%d test-inet 0
- element 00000000 : 0 [end] element 00000020 : 0 [end]
-inet
+# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst }
+__set%d test-ip4 3 size 7
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000010 : 0 [end] element 00000040 : 0 [end] element 00000050 : 0 [end] element 00000060 : 0 [end] element 00000070 : 0 [end] element 00000080 : 0 [end]
+ip test-ip4 input
[ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]