{"id":2219288,"url":"http://patchwork.ozlabs.org/api/patches/2219288/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260402184320.14862-3-phil@nwl.cc/","project":{"id":26,"url":"http://patchwork.ozlabs.org/api/projects/26/?format=json","name":"Netfilter Development","link_name":"netfilter-devel","list_id":"netfilter-devel.vger.kernel.org","list_email":"netfilter-devel@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260402184320.14862-3-phil@nwl.cc>","list_archive_url":null,"date":"2026-04-02T18:43:20","name":"[nft,2/2] parser_bison: Accept non-constant binop on LHS of relationals","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"0c66a9ad0d50b5a0f6718f4ad356a15f8cb1b436","submitter":{"id":4285,"url":"http://patchwork.ozlabs.org/api/people/4285/?format=json","name":"Phil Sutter","email":"phil@nwl.cc"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260402184320.14862-3-phil@nwl.cc/mbox/","series":[{"id":498540,"url":"http://patchwork.ozlabs.org/api/series/498540/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=498540","date":"2026-04-02T18:43:20","name":"A bit of non-constant binop follow-up","version":1,"mbox":"http://patchwork.ozlabs.org/series/498540/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2219288/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2219288/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <netfilter-devel+bounces-11593-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","netfilter-devel@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=nwl.cc header.i=@nwl.cc header.a=rsa-sha256\n header.s=mail2022 header.b=kqxXip3c;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-11593-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key)\n header.d=nwl.cc header.i=@nwl.cc header.b=\"kqxXip3c\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=151.80.46.58","smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=nwl.cc","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=nwl.cc","mail.nwl.cc;\n\tiprev=pass (localhost) smtp.remote-ip=::1"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmrNM6dFdz1yGH\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 03 Apr 2026 05:43:47 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id ED9CD300E607\n\tfor <incoming@patchwork.ozlabs.org>; Thu,  2 Apr 2026 18:43:38 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id BA1283E51F8;\n\tThu,  2 Apr 2026 18:43:33 +0000 (UTC)","from orbyte.nwl.cc (orbyte.nwl.cc [151.80.46.58])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F76B3E5EF8\n\tfor <netfilter-devel@vger.kernel.org>; Thu,  2 Apr 2026 18:43:28 +0000 (UTC)","from localhost ([::1] helo=xic)\n\tby orbyte.nwl.cc with esmtp (Exim 4.98.2)\n\t(envelope-from <phil@nwl.cc>)\n\tid 1w8N0n-000000005oc-2tOL;\n\tThu, 02 Apr 2026 20:43:25 +0200"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775155412; cv=none;\n b=oB/0gdgjpcV23fNjhqbcpWwr9pmoe23QBc4Htb94Ra4s+0ff4dsNdurwOQYrhTwhu/9VGiOPj7GP68b0JkXYMv90ZGPTe2DaTEh46ctC7dB0OD2C/aePT4byrRi4YzLfpWh9qPkcwpVeGbeYrWV8cs+4GFqIBZGPhUiwLPEmaNE=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775155412; c=relaxed/simple;\n\tbh=kAJSCh5gSawY5WMlZFkUrBdaAJYwMfYy67VoJFET+GA=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=WZqd2iBeQIw8dhHZy9iRE//vM4oEQRAjy+ijzsglPO480bvbvpf1DWu09qOyzb8a3EYfIjzEn0RBCXV/+kSjzMSf6CnojiKroYFBiiH7A7PGXTOsPi7RRBxh+ZTCF/Pi/VnlPSdkwqPJWSl2VRhoJ6U0YfX8WnQwimgzNIp+1+c=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=nwl.cc;\n spf=pass smtp.mailfrom=nwl.cc;\n dkim=pass (2048-bit key) header.d=nwl.cc header.i=@nwl.cc header.b=kqxXip3c;\n arc=none smtp.client-ip=151.80.46.58","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nwl.cc;\n\ts=mail2022; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=dJxIagA7FBmqVyzAiogHv+Hi5GKyac54W31li0fWnEE=; b=kqxXip3cSkc9GsBXXT0nIUcxlZ\n\t3fTECaVd2fVS7z/xfhnICXnz32SrkSvKRJpQSxJQ6XpVq7C2e58cn8lhk38wM0SeCdMQEyj52pSnb\n\tqxnRQ5dtAsKMyM52P4/LDkM9DOD3+LhJIGvsqTsSrnsnHKIRqSf80zFfbm2Ak2naa1B9CTeBYyqfS\n\tVaY2/2WkufgdAVhEaoqjbkElLxe6vxfqfLBX9vEwTGLZfJgA//Lw0cZ+d1BsVoapFMJMuGryUSjqr\n\tbCNcAtDbwwlX4iKStIWEPzBW60E6e1Hdj9dG3snopMEjElW9mkj8+9tnZNd6gbW3dou88E/HguGuW\n\tXX4cCmUg==;","From":"Phil Sutter <phil@nwl.cc>","To":"Pablo Neira Ayuso <pablo@netfilter.org>","Cc":"netfilter-devel@vger.kernel.org,\n\tDion Bosschieter <dionbosschieter@gmail.com>","Subject":"[nft PATCH 2/2] parser_bison: Accept non-constant binop on LHS of\n relationals","Date":"Thu,  2 Apr 2026 20:43:20 +0200","Message-ID":"<20260402184320.14862-3-phil@nwl.cc>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20260402184320.14862-1-phil@nwl.cc>","References":"<20260402184320.14862-1-phil@nwl.cc>","Precedence":"bulk","X-Mailing-List":"netfilter-devel@vger.kernel.org","List-Id":"<netfilter-devel.vger.kernel.org>","List-Subscribe":"<mailto:netfilter-devel+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:netfilter-devel+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"This reverts commit 14a9968a56f8b35138bab172aa7ce796f5d98e03.\n\nThanks to start conditions, stray \"ecn\" is no longer recognized by flex\nand returned as keyword, so the workaround is not needed anymore. All it\ntakes is to move it into the block for SCANSTATE_IP and SCANSTATE_IP6 in\nscanner.l.\n\nLikewise, keyword_expr no longer has to cover for ECN keyword.\n\nUndoing the commit's workarounds in binop expression parser cases lifts\ntheir restriction which is no longer needed since commit 54bfc38c522ba\n(\"src: allow binop expressions with variable right-hand operands\").\n\nSigned-off-by: Phil Sutter <phil@nwl.cc>\n---\n doc/payload-expression.txt        |  6 ++++\n src/parser_bison.y                | 16 +++++-----\n src/scanner.l                     |  2 +-\n tests/py/arp/arp.t                |  4 +++\n tests/py/arp/arp.t.json           | 51 +++++++++++++++++++++++++++++++\n tests/py/arp/arp.t.payload        | 14 +++++++++\n tests/py/arp/arp.t.payload.netdev | 18 +++++++++++\n 7 files changed, 103 insertions(+), 8 deletions(-)","diff":"diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt\nindex 8b538968c84b5..59be68be5e21b 100644\n--- a/doc/payload-expression.txt\n+++ b/doc/payload-expression.txt\n@@ -87,6 +87,12 @@ IPv4 target address|\n ipv4_addr\n |======================\n \n+.Using arp header expression\n+----------------------------\n+# matching on gratuitous ARP packets\n+arp saddr ip ^ arp daddr ip == 0.0.0.0\n+----------------------------\n+\n IPV4 HEADER EXPRESSION\n ~~~~~~~~~~~~~~~~~~~~~~\n [verse]\ndiff --git a/src/parser_bison.y b/src/parser_bison.y\nindex 5a334bf0c4997..368d1004c0ec4 100644\n--- a/src/parser_bison.y\n+++ b/src/parser_bison.y\n@@ -4466,32 +4466,32 @@ osf_ttl\t\t\t:\t/* empty */\t{ $$ = NF_OSF_TTL_TRUE; }\n \t\t\t;\n \n shift_expr\t\t:\tprimary_expr\n-\t\t\t|\tshift_expr\t\tLSHIFT\t\tprimary_rhs_expr\n+\t\t\t|\tshift_expr\t\tLSHIFT\t\tprimary_expr\n \t\t\t{\n \t\t\t\t$$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);\n \t\t\t}\n-\t\t\t|\tshift_expr\t\tRSHIFT\t\tprimary_rhs_expr\n+\t\t\t|\tshift_expr\t\tRSHIFT\t\tprimary_expr\n \t\t\t{\n \t\t\t\t$$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);\n \t\t\t}\n \t\t\t;\n \n and_expr\t\t:\tshift_expr\n-\t\t\t|\tand_expr\t\tAMPERSAND\tshift_rhs_expr\n+\t\t\t|\tand_expr\t\tAMPERSAND\tshift_expr\n \t\t\t{\n \t\t\t\t$$ = binop_expr_alloc(&@$, OP_AND, $1, $3);\n \t\t\t}\n \t\t\t;\n \n exclusive_or_expr\t:\tand_expr\n-\t\t\t|\texclusive_or_expr\tCARET\t\tand_rhs_expr\n+\t\t\t|\texclusive_or_expr\tCARET\t\tand_expr\n \t\t\t{\n \t\t\t\t$$ = binop_expr_alloc(&@$, OP_XOR, $1, $3);\n \t\t\t}\n \t\t\t;\n \n inclusive_or_expr\t:\texclusive_or_expr\n-\t\t\t|\tinclusive_or_expr\t'|'\t\texclusive_or_rhs_expr\n+\t\t\t|\tinclusive_or_expr\t'|'\t\texclusive_or_expr\n \t\t\t{\n \t\t\t\t$$ = binop_expr_alloc(&@$, OP_OR, $1, $3);\n \t\t\t}\n@@ -5186,6 +5186,10 @@ relational_expr\t\t:\texpr\t/* implicit */\trhs_expr\n \t\t\t{\n \t\t\t\t$$ = relational_expr_alloc(&@2, $2, $1, $3);\n \t\t\t}\n+\t\t\t|\texpr\trelational_op\t'(' rhs_expr ')'\n+\t\t\t{\n+\t\t\t\t$$ = relational_expr_alloc(&@2, $2, $1, $4);\n+\t\t\t}\n \t\t\t|\texpr\trelational_op\tlist_rhs_expr\n \t\t\t{\n \t\t\t\t$$ = relational_expr_alloc(&@2, $2, $1, $3);\n@@ -5287,7 +5291,6 @@ keyword_expr\t\t:\tETHER   close_scope_eth { $$ = symbol_value(&@$, \"ether\"); }\n \t\t\t|\tARP\tclose_scope_arp { $$ = symbol_value(&@$, \"arp\"); }\n \t\t\t|\tDNAT\tclose_scope_nat\t{ $$ = symbol_value(&@$, \"dnat\"); }\n \t\t\t|\tSNAT\tclose_scope_nat\t{ $$ = symbol_value(&@$, \"snat\"); }\n-\t\t\t|\tECN\t\t\t{ $$ = symbol_value(&@$, \"ecn\"); }\n \t\t\t|\tRESET\tclose_scope_reset\t{ $$ = symbol_value(&@$, \"reset\"); }\n \t\t\t|\tDESTROY\tclose_scope_destroy\t{ $$ = symbol_value(&@$, \"destroy\"); }\n \t\t\t|\tORIGINAL\t\t{ $$ = symbol_value(&@$, \"original\"); }\n@@ -5391,7 +5394,6 @@ primary_rhs_expr\t:\tsymbol_expr\t\t{ $$ = $1; }\n \t\t\t\t\t\t\t BYTEORDER_HOST_ENDIAN,\n \t\t\t\t\t\t\t sizeof(data) * BITS_PER_BYTE, &data);\n \t\t\t}\n-\t\t\t|\t'('\tbasic_rhs_expr\t')'\t{ $$ = $2; }\n \t\t\t;\n \n relational_op\t\t:\tEQ\t\t{ $$ = OP_EQ; }\ndiff --git a/src/scanner.l b/src/scanner.l\nindex 1b4eb1cf13a47..912788ee0e55b 100644\n--- a/src/scanner.l\n+++ b/src/scanner.l\n@@ -536,8 +536,8 @@ addrstring\t({macaddr}|{ip4addr}|{ip6addr})\n }\n <SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_TYPE>{\n \t\"dscp\"\t\t\t{ return DSCP; }\n+\t\"ecn\"\t\t\t{ return ECN; }\n }\n-\"ecn\"\t\t\t{ return ECN; }\n <SCANSTATE_EXPR_UDP,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_META,SCANSTATE_TCP,SCANSTATE_SCTP,SCANSTATE_EXPR_SCTP_CHUNK>\"length\"\t\t{ return LENGTH; }\n <SCANSTATE_EXPR_FRAG,SCANSTATE_IP>{\n \t\"frag-off\"\t\t{ return FRAG_OFF; }\ndiff --git a/tests/py/arp/arp.t b/tests/py/arp/arp.t\nindex 222b91cf08457..2c850315c662a 100644\n--- a/tests/py/arp/arp.t\n+++ b/tests/py/arp/arp.t\n@@ -58,3 +58,7 @@ arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee;ok\n arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1;ok;arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee\n \n meta iifname \"invalid\" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566;ok;iifname \"invalid\" arp htype 1 arp ptype ip arp hlen 6 arp plen 4 arp daddr ip 192.168.143.16 arp daddr ether set 11:22:33:44:55:66\n+\n+# gratuitous ARP or not?\n+arp saddr ip ^ arp daddr ip == 0.0.0.0;ok\n+arp saddr ip ^ arp daddr ip != 0.0.0.0;ok\ndiff --git a/tests/py/arp/arp.t.json b/tests/py/arp/arp.t.json\nindex 7ce7609539ba4..ac7ef28d94a2b 100644\n--- a/tests/py/arp/arp.t.json\n+++ b/tests/py/arp/arp.t.json\n@@ -891,3 +891,54 @@\n     }\n ]\n \n+# arp saddr ip ^ arp daddr ip == 0.0.0.0\n+[\n+    {\n+        \"match\": {\n+            \"left\": {\n+                \"^\": [\n+                    {\n+                        \"payload\": {\n+                            \"field\": \"saddr ip\",\n+                            \"protocol\": \"arp\"\n+                        }\n+                    },\n+                    {\n+                        \"payload\": {\n+                            \"field\": \"daddr ip\",\n+                            \"protocol\": \"arp\"\n+                        }\n+                    }\n+                ]\n+            },\n+            \"op\": \"==\",\n+            \"right\": \"0.0.0.0\"\n+        }\n+    }\n+]\n+\n+# arp saddr ip ^ arp daddr ip != 0.0.0.0\n+[\n+    {\n+        \"match\": {\n+            \"left\": {\n+                \"^\": [\n+                    {\n+                        \"payload\": {\n+                            \"field\": \"saddr ip\",\n+                            \"protocol\": \"arp\"\n+                        }\n+                    },\n+                    {\n+                        \"payload\": {\n+                            \"field\": \"daddr ip\",\n+                            \"protocol\": \"arp\"\n+                        }\n+                    }\n+                ]\n+            },\n+            \"op\": \"!=\",\n+            \"right\": \"0.0.0.0\"\n+        }\n+    }\n+]\ndiff --git a/tests/py/arp/arp.t.payload b/tests/py/arp/arp.t.payload\nindex e23c540ca8bc1..649bda9739431 100644\n--- a/tests/py/arp/arp.t.payload\n+++ b/tests/py/arp/arp.t.payload\n@@ -254,3 +254,17 @@ arp\n arp \n   [ payload load 10b @ network header + 14 => reg 1 ]\n   [ cmp eq reg 1 0xc0a80101 0xfeed00c0 0xffee ]\n+\n+# arp saddr ip ^ arp daddr ip == 0.0.0.0\n+arp test-arp input\n+  [ payload load 4b @ network header + 14 => reg 1 ]\n+  [ payload load 4b @ network header + 24 => reg 2 ]\n+  [ bitwise reg 1 = ( reg 1 ^ reg 2 ) ]\n+  [ cmp eq reg 1 0x00000000 ]\n+\n+# arp saddr ip ^ arp daddr ip != 0.0.0.0\n+arp test-arp input\n+  [ payload load 4b @ network header + 14 => reg 1 ]\n+  [ payload load 4b @ network header + 24 => reg 2 ]\n+  [ bitwise reg 1 = ( reg 1 ^ reg 2 ) ]\n+  [ cmp neq reg 1 0x00000000 ]\ndiff --git a/tests/py/arp/arp.t.payload.netdev b/tests/py/arp/arp.t.payload.netdev\nindex ea238978fa73b..044f2712fd827 100644\n--- a/tests/py/arp/arp.t.payload.netdev\n+++ b/tests/py/arp/arp.t.payload.netdev\n@@ -344,3 +344,21 @@ netdev\n   [ cmp eq reg 1 0x0806 ]\n   [ payload load 10b @ network header + 14 => reg 1 ]\n   [ cmp eq reg 1 0xc0a80101 0xfeed00c0 0xffee ]\n+\n+# arp saddr ip ^ arp daddr ip == 0.0.0.0\n+netdev test-netdev ingress\n+  [ meta load protocol => reg 1 ]\n+  [ cmp eq reg 1 0x0806 ]\n+  [ payload load 4b @ network header + 14 => reg 1 ]\n+  [ payload load 4b @ network header + 24 => reg 2 ]\n+  [ bitwise reg 1 = ( reg 1 ^ reg 2 ) ]\n+  [ cmp eq reg 1 0x00000000 ]\n+\n+# arp saddr ip ^ arp daddr ip != 0.0.0.0\n+netdev test-netdev ingress\n+  [ meta load protocol => reg 1 ]\n+  [ cmp eq reg 1 0x0806 ]\n+  [ payload load 4b @ network header + 14 => reg 1 ]\n+  [ payload load 4b @ network header + 24 => reg 2 ]\n+  [ bitwise reg 1 = ( reg 1 ^ reg 2 ) ]\n+  [ cmp neq reg 1 0x00000000 ]\n","prefixes":["nft","2/2"]}