All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft,v2 1/3] mergesort: use lhs expression when sorting concatenation
@ 2026-08-05 16:39 Pablo Neira Ayuso
  2026-08-05 16:39 ` [PATCH nft 2/3] segtree: basic support for binary operations in concatenated set ranges Pablo Neira Ayuso
  2026-08-05 16:39 ` [PATCH nft 3/3] tests: shell: add flush set after expiration Pablo Neira Ayuso
  0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-05 16:39 UTC (permalink / raw)
  To: netfilter-devel

Otherwise, concatenations using binary operations hit an assertion.

 # cat ruleset.nft
 table inet t {
        chain c {
                tcp flags . tcp dport vmap { syn | ack . 80 : drop, ack . 90 : accept }
        }
 }
 # nft -f ruleset.nft
 # nft list ruleset
 nft: src/mergesort.c:23: concat_expr_msort_value: Assertion `ilen > 0' failed.
 Aborted

Inspect the left-hand size of the expression for the merge sorting.

This patch includes a new tests/shell unit file.

Fixes: 741a06ac15d2 ("mergesort: find base value expression type via recursion")
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1841
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: add tests/shell unit file.

 src/mergesort.c                               |  38 +++-
 .../maps/dumps/vmap_concat_binop.json-nft     | 196 ++++++++++++++++++
 .../maps/dumps/vmap_concat_binop.nft          |  13 ++
 tests/shell/testcases/maps/vmap_concat_binop  |  19 ++
 4 files changed, 262 insertions(+), 4 deletions(-)
 create mode 100644 tests/shell/testcases/maps/dumps/vmap_concat_binop.json-nft
 create mode 100644 tests/shell/testcases/maps/dumps/vmap_concat_binop.nft
 create mode 100755 tests/shell/testcases/maps/vmap_concat_binop

diff --git a/src/mergesort.c b/src/mergesort.c
index 2e8ddd22f813..f4b4d56b579c 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -12,16 +12,46 @@
 #include <gmputil.h>
 #include <list.h>
 
+static mpz_srcptr concat_expr_msort_value_one(const struct expr *expr,
+					      unsigned int *i_len)
+{
+	mpz_srcptr i_value;
+
+	switch (expr->etype) {
+	case EXPR_BINOP:
+	case EXPR_MAPPING:
+	case EXPR_RANGE:
+		i_value = expr->left->value;
+		*i_len = expr->left->len;
+		break;
+	case EXPR_VALUE:
+		i_value = expr->value;
+		*i_len = expr->len;
+		break;
+	case EXPR_RANGE_VALUE:
+		i_value = expr->range.low;
+		*i_len = expr->len;
+		break;
+	default:
+		BUG("Unknown expression %s", expr_name(expr));
+	}
+
+	*i_len = div_round_up(*i_len, BITS_PER_BYTE);
+
+	return i_value;
+}
+
 static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
 {
-	unsigned int len = 0, ilen;
+	unsigned int len = 0, i_len;
 	const struct expr *i;
+	mpz_srcptr i_value;
 	char data[512];
 
 	list_for_each_entry(i, &expr_concat(expr)->expressions, list) {
-		ilen = div_round_up(i->len, BITS_PER_BYTE);
-		mpz_export_data(data + len, i->value, BYTEORDER_BIG_ENDIAN, ilen);
-		len += ilen;
+		i_value = concat_expr_msort_value_one(i, &i_len);
+		mpz_export_data(data + len, i_value, BYTEORDER_BIG_ENDIAN, i_len);
+		len += i_len;
 	}
 
 	mpz_import_data(value, data, BYTEORDER_BIG_ENDIAN, len);
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_binop.json-nft b/tests/shell/testcases/maps/dumps/vmap_concat_binop.json-nft
new file mode 100644
index 000000000000..502648f53dec
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_binop.json-nft
@@ -0,0 +1,196 @@
+{
+  "nftables": [
+    {
+      "metainfo": {
+        "version": "VERSION",
+        "release_name": "RELEASE_NAME",
+        "json_schema_version": 1
+      }
+    },
+    {
+      "table": {
+        "family": "ip",
+        "name": "x",
+        "handle": 0
+      }
+    },
+    {
+      "chain": {
+        "family": "ip",
+        "table": "x",
+        "name": "z",
+        "handle": 0
+      }
+    },
+    {
+      "map": {
+        "family": "ip",
+        "name": "y",
+        "table": "x",
+        "type": {
+          "typeof": {
+            "concat": [
+              {
+                "payload": {
+                  "protocol": "tcp",
+                  "field": "flags"
+                }
+              },
+              {
+                "payload": {
+                  "protocol": "tcp",
+                  "field": "dport"
+                }
+              }
+            ]
+          }
+        },
+        "handle": 0,
+        "map": "verdict",
+        "elem": [
+          [
+            {
+              "concat": [
+                {
+                  "|": [
+                    "syn",
+                    "ack"
+                  ]
+                },
+                80
+              ]
+            },
+            {
+              "accept": null
+            }
+          ],
+          [
+            {
+              "concat": [
+                "rst",
+                100
+              ]
+            },
+            {
+              "drop": null
+            }
+          ],
+          [
+            {
+              "concat": [
+                "ack",
+                90
+              ]
+            },
+            {
+              "drop": null
+            }
+          ]
+        ]
+      }
+    },
+    {
+      "rule": {
+        "family": "ip",
+        "table": "x",
+        "chain": "z",
+        "handle": 0,
+        "expr": [
+          {
+            "vmap": {
+              "key": {
+                "concat": [
+                  {
+                    "payload": {
+                      "protocol": "tcp",
+                      "field": "flags"
+                    }
+                  },
+                  {
+                    "payload": {
+                      "protocol": "tcp",
+                      "field": "dport"
+                    }
+                  }
+                ]
+              },
+              "data": "@y"
+            }
+          }
+        ]
+      }
+    },
+    {
+      "rule": {
+        "family": "ip",
+        "table": "x",
+        "chain": "z",
+        "handle": 0,
+        "expr": [
+          {
+            "vmap": {
+              "key": {
+                "concat": [
+                  {
+                    "payload": {
+                      "protocol": "tcp",
+                      "field": "flags"
+                    }
+                  },
+                  {
+                    "payload": {
+                      "protocol": "tcp",
+                      "field": "dport"
+                    }
+                  }
+                ]
+              },
+              "data": {
+                "set": [
+                  [
+                    {
+                      "concat": [
+                        {
+                          "|": [
+                            "syn",
+                            "ack"
+                          ]
+                        },
+                        80
+                      ]
+                    },
+                    {
+                      "accept": null
+                    }
+                  ],
+                  [
+                    {
+                      "concat": [
+                        "rst",
+                        100
+                      ]
+                    },
+                    {
+                      "drop": null
+                    }
+                  ],
+                  [
+                    {
+                      "concat": [
+                        "ack",
+                        90
+                      ]
+                    },
+                    {
+                      "drop": null
+                    }
+                  ]
+                ]
+              }
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_binop.nft b/tests/shell/testcases/maps/dumps/vmap_concat_binop.nft
new file mode 100644
index 000000000000..92e50a4cbcc1
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_binop.nft
@@ -0,0 +1,13 @@
+table ip x {
+	map y {
+		typeof tcp flags . tcp dport : verdict
+		elements = { syn | ack . 80 : accept,
+			     rst . 100 : drop,
+			     ack . 90 : drop }
+	}
+
+	chain z {
+		tcp flags . tcp dport vmap @y
+		tcp flags . tcp dport vmap { syn | ack . 80 : accept, rst . 100 : drop, ack . 90 : drop }
+	}
+}
diff --git a/tests/shell/testcases/maps/vmap_concat_binop b/tests/shell/testcases/maps/vmap_concat_binop
new file mode 100755
index 000000000000..fc6e9584740b
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_concat_binop
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+        map y {
+                typeof tcp flags . tcp dport : verdict
+                elements = { syn | ack . 80 : accept,
+                             ack . 90 : drop,
+			     rst . 100 : drop }
+        }
+
+        chain z {
+                tcp flags . tcp dport vmap @y
+                tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100 : drop }
+        }
+}"
+
+$NFT -f - <<< $RULESET
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-05 16:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-05 16:39 [PATCH nft,v2 1/3] mergesort: use lhs expression when sorting concatenation Pablo Neira Ayuso
2026-08-05 16:39 ` [PATCH nft 2/3] segtree: basic support for binary operations in concatenated set ranges Pablo Neira Ayuso
2026-08-05 16:39 ` [PATCH nft 3/3] tests: shell: add flush set after expiration Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.