All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Subject: [PATCH nft,v2 1/3] mergesort: use lhs expression when sorting concatenation
Date: Wed,  5 Aug 2026 18:39:18 +0200	[thread overview]
Message-ID: <20260805163920.238975-1-pablo@netfilter.org> (raw)

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


             reply	other threads:[~2026-08-05 16:39 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05 16:39 Pablo Neira Ayuso [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260805163920.238975-1-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.