get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2224353/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2224353,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2224353/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260417103854.4727-1-fw@strlen.de/",
    "project": {
        "id": 26,
        "url": "http://patchwork.ozlabs.org/api/1.2/projects/26/?format=api",
        "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": "<20260417103854.4727-1-fw@strlen.de>",
    "list_archive_url": null,
    "date": "2026-04-17T10:38:50",
    "name": "[nft] tests: shell: add fwd to/fwd ip to test cases",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "97fdec3470a2d7db46076bc01fd4f82cad50824a",
    "submitter": {
        "id": 1025,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/1025/?format=api",
        "name": "Florian Westphal",
        "email": "fw@strlen.de"
    },
    "delegate": {
        "id": 11902,
        "url": "http://patchwork.ozlabs.org/api/1.2/users/11902/?format=api",
        "username": "strlen",
        "first_name": "Florian",
        "last_name": "Westphal",
        "email": "fw@strlen.de"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260417103854.4727-1-fw@strlen.de/mbox/",
    "series": [
        {
            "id": 500303,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/500303/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=500303",
            "date": "2026-04-17T10:38:50",
            "name": "[nft] tests: shell: add fwd to/fwd ip to test cases",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/500303/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2224353/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2224353/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <netfilter-devel+bounces-11998-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 spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c09:e001:a7::12fc:5321; helo=sto.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-11998-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=91.216.245.30",
            "smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=strlen.de",
            "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=Chamillionaire.breakpoint.cc"
        ],
        "Received": [
            "from sto.lore.kernel.org (sto.lore.kernel.org\n [IPv6:2600:3c09:e001:a7::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fxrwW29h4z1yDF\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 17 Apr 2026 20:39:23 +1000 (AEST)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id CE8F6301FCFF\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 17 Apr 2026 10:39:19 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id C42EC3BA25A;\n\tFri, 17 Apr 2026 10:39:15 +0000 (UTC)",
            "from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc\n [91.216.245.30])\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 96EF23BA237\n\tfor <netfilter-devel@vger.kernel.org>; Fri, 17 Apr 2026 10:39:06 +0000 (UTC)",
            "by Chamillionaire.breakpoint.cc (Postfix, from userid 1003)\n\tid ADF4C606C8; Fri, 17 Apr 2026 12:38:59 +0200 (CEST)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776422353; cv=none;\n b=cO+ZLtMeSgNRROsZt39OkevF+Qhg8sIqIpPBLHH4XCZYPwOGA/MVKBZmTBcuWb7YRRujBw5xMAaSKcciXQvhelREL4nv/AMHMpApky0+kFyaJri7a2EpVgoh07UMcjimxCEaaDMsdviLYyvSsWJtQI+zI2V8iwCeBAzgTf6cBNg=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776422353; c=relaxed/simple;\n\tbh=R7dmQ/gr32LtrGidvVl2x1Tsue9kBQSlwMDPgZKJK6o=;\n\th=From:To:Cc:Subject:Date:Message-ID:MIME-Version;\n b=INehip1N6gv9XjsPjLUEGhePy22f99bCIuPxRYocEmeA8USYv3p2co26nfVgNT9KAcbTkO3lsKI5SSMujc2DviFABi3Hj2EejYSRWsmNOm/DWYcq2uVzjmQalhVwELgrnkyeTIVKeTdS9IWZFggRvrzsFx+W0DUDq6gfEQyy6FA=",
        "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=strlen.de;\n spf=pass smtp.mailfrom=Chamillionaire.breakpoint.cc;\n arc=none smtp.client-ip=91.216.245.30",
        "From": "Florian Westphal <fw@strlen.de>",
        "To": "<netfilter-devel@vger.kernel.org>",
        "Cc": "Florian Westphal <fw@strlen.de>",
        "Subject": "[PATCH nft] tests: shell: add fwd to/fwd ip to test cases",
        "Date": "Fri, 17 Apr 2026 12:38:50 +0200",
        "Message-ID": "<20260417103854.4727-1-fw@strlen.de>",
        "X-Mailer": "git-send-email 2.52.0",
        "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": "Tests 'fwd to <dev>' and 'fwd ip ip <addr> device <dev>' expression in\nboth ingress and egress hooks.\n\n'fwd to' is raw frame forward.\n'fwd ip to' uses 'neigh' layer to update mac address.\n\nAssisted-by: Claude:claude-opus-4-5\nSigned-off-by: Florian Westphal <fw@strlen.de>\n---\n NB: I'm not found of these AI tags, I don't think they\n provide value.  Adding only because kernel asks to do it and\n I'd like to hear your thoughts on what nf userspace should do.\n\n If you see no value, I'll no longer add it for userspace work.\n\n .../testcases/packetpath/dumps/fwd.nodump     |   0\n .../testcases/packetpath/dumps/fwd_ip.nodump  |   0\n tests/shell/testcases/packetpath/fwd          | 168 ++++++++++++++++++\n tests/shell/testcases/packetpath/fwd_ip       | 156 ++++++++++++++++\n 4 files changed, 324 insertions(+)\n create mode 100644 tests/shell/testcases/packetpath/dumps/fwd.nodump\n create mode 100644 tests/shell/testcases/packetpath/dumps/fwd_ip.nodump\n create mode 100755 tests/shell/testcases/packetpath/fwd\n create mode 100755 tests/shell/testcases/packetpath/fwd_ip",
    "diff": "diff --git a/tests/shell/testcases/packetpath/dumps/fwd.nodump b/tests/shell/testcases/packetpath/dumps/fwd.nodump\nnew file mode 100644\nindex 000000000000..e69de29bb2d1\ndiff --git a/tests/shell/testcases/packetpath/dumps/fwd_ip.nodump b/tests/shell/testcases/packetpath/dumps/fwd_ip.nodump\nnew file mode 100644\nindex 000000000000..e69de29bb2d1\ndiff --git a/tests/shell/testcases/packetpath/fwd b/tests/shell/testcases/packetpath/fwd\nnew file mode 100755\nindex 000000000000..2c0c1e38d4ef\n--- /dev/null\n+++ b/tests/shell/testcases/packetpath/fwd\n@@ -0,0 +1,168 @@\n+#!/bin/bash\n+\n+# Test case for nftables fwd expression with bridge\n+# Tests that packets are forwarded to the correct device using \"fwd to\"\n+# Setup: ns1 (sender) -> ns2 (bridge) -> ns3/ns4 (receivers)\n+\n+rnd=$(mktemp -u XXXXXXXX)\n+ns1=\"nft1fwdbr-$rnd\"\n+ns2=\"nft2fwdbr-$rnd\"\n+ns3=\"nft3fwdbr-$rnd\"\n+ns4=\"nft4fwdbr-$rnd\"\n+\n+cleanup() {\n+\tip netns del \"$ns1\" 2>/dev/null\n+\tip netns del \"$ns2\" 2>/dev/null\n+\tip netns del \"$ns3\" 2>/dev/null\n+\tip netns del \"$ns4\" 2>/dev/null\n+}\n+\n+die() {\n+\tlocal n=\"$1\"\n+\n+\tip netns exec \"$n\" $NFT list ruleset\n+\n+\techo \"ns2 (router)\"\n+\tip netns exec \"$ns2\" $NFT list ruleset\n+\texit 1\n+}\n+\n+ping_and_check() {\n+\tip netns exec \"$ns1\" ping -c 1 -W 1 10.0.1.3 >/dev/null\n+\tip netns exec \"$ns1\" ping -c 1 -W 1 10.0.1.4 >/dev/null\n+\n+\t# Check that packets arrived at ns3\n+\tip netns exec \"$ns3\" $NFT \"list counter netdev rxt rxc\" | grep -q 'packets 2 '\n+\tif [ $? -ne 0 ]; then\n+\t\techo \"ERROR: counter not incremented in $ns3\"\n+\t\tdie \"$ns3\"\n+\tfi\n+\n+\tip netns exec \"$ns4\" $NFT \"list counter netdev rxt rxc\" | grep -q 'packets 0 '\n+\tif [ $? -ne 0 ]; then\n+\t\techo \"ERROR: counter incremented in $ns4\"\n+\t\tdie \"$ns4\"\n+\tfi\n+}\n+\n+trap cleanup EXIT\n+\n+set -e\n+\n+# Create network namespaces\n+for n in \"$ns1\" \"$ns2\" \"$ns3\" \"$ns4\"; do\n+\tip netns add \"$n\"\n+\tip -net \"$n\" link set lo up\n+done\n+\n+# Create veth pairs:\n+# ns1(veth0) <-> (veth1)ns2 bridge port\n+# ns3(veth0) <-> (veth3)ns2 bridge port\n+# ns4(veth0) <-> (veth4)ns2 bridge port\n+ip link add veth0 netns \"$ns1\" type veth peer name veth1 netns \"$ns2\"\n+ip link add veth0 netns \"$ns3\" type veth peer name veth3 netns \"$ns2\"\n+ip link add veth0 netns \"$ns4\" type veth peer name veth4 netns \"$ns2\"\n+\n+# Create bridge in ns2\n+ip -net \"$ns2\" link add br0 type bridge\n+\n+# Add veth devices to bridge in ns2\n+ip -net \"$ns2\" link set veth1 master br0\n+ip -net \"$ns2\" link set veth3 master br0\n+ip -net \"$ns2\" link set veth4 master br0\n+\n+# Set up IP addresses\n+ip -net \"$ns1\" addr add 10.0.1.1/24 dev veth0\n+ip -net \"$ns2\" addr add 10.0.1.2/24 dev br0\n+ip -net \"$ns3\" addr add 10.0.1.3/24 dev veth0\n+ip -net \"$ns4\" addr add 10.0.1.4/24 dev veth0\n+\n+# Bring up interfaces\n+ip -net \"$ns1\" link set veth0 up\n+ip -net \"$ns3\" link set veth0 up\n+ip -net \"$ns4\" link set veth0 up\n+\n+ip -net \"$ns2\" link set veth1 up\n+ip -net \"$ns2\" link set veth3 up\n+ip -net \"$ns2\" link set veth4 up\n+ip -net \"$ns2\" link set br0 up\n+\n+# Validate setup:\n+ip netns exec \"$ns1\" ping -q -c 1 10.0.1.3\n+ip netns exec \"$ns1\" ping -q -c 1 10.0.1.4\n+\n+# Add nftables rule in ns2 to forward packets from veth1 to veth4\n+ip netns exec \"$ns2\" $NFT -f /dev/stdin <<\"EOF\"\n+table netdev fwd_bridge_test {\n+\tchain ingress_veth1 {\n+\t\ttype filter hook ingress device veth1 priority 0; policy accept;\n+\n+\t\t# Forward ICMP packets destined for ns4 to veth3 (ns3) instead\n+\t\tip daddr 10.0.1.4 ip protocol icmp counter fwd to \"veth3\"\n+\t}\n+}\n+EOF\n+\n+[ $? -ne 0 ] && exit 1\n+\n+# so ingress hook in ns3 picks up packet for ns4 mac\n+ip -net \"$ns3\" link set veth0 promisc on\n+\n+for n in \"$ns3\" \"$ns4\"; do\n+ip netns exec \"$n\" $NFT -f /dev/stdin <<\"EOF\"\n+table netdev rxt {\n+\tcounter rxc { }\n+\n+\tchain in_veth0 {\n+\t\ttype filter hook ingress device veth0 priority 0; policy accept;\n+\t\tip protocol icmp counter name \"rxc\"\n+\t}\n+}\n+EOF\n+done\n+\n+# Verify normal bridge forwarding still works for non-ICMP traffic\n+# Test that ns3/ns4 are reachable from ns1 without fwd interference.\n+ip netns exec \"$ns1\" arping -c 1 -I veth0 10.0.1.3 >/dev/null\n+ip netns exec \"$ns1\" arping -c 1 -I veth0 10.0.1.4 >/dev/null\n+\n+set +e\n+ping_and_check\n+\n+# again, but use egress hook.\n+ip netns exec \"$ns2\" $NFT -f /dev/stdin <<\"EOF\"\n+flush ruleset\n+table netdev fwd_test {\n+\tchain egress_veth4 {\n+\t\ttype filter hook egress device veth4 priority 0; policy accept;\n+\t\tip protocol icmp counter fwd to \"veth3\"\n+\t}\n+}\n+EOF\n+[ $? -ne 0 ] && exit 1\n+\n+echo \"Egress ruleset loaded\"\n+ip netns exec \"$ns3\" $NFT \"reset counter netdev rxt rxc\"\n+ping_and_check\n+\n+ip netns exec \"$ns3\" $NFT \"reset counter netdev rxt rxc\"\n+ip netns exec \"$ns2\" $NFT -f /dev/stdin <<\"EOF\"\n+flush ruleset\n+table netdev fwd_test {\n+\tchain egress_veth4 {\n+\t\ttype filter hook egress device veth4 priority 0; policy accept;\n+\t\tip protocol icmp counter fwd to \"veth4\"\n+\t}\n+}\n+EOF\n+[ $? -ne 0 ] && exit 1\n+\n+# assert this doesn't crash.\n+ip netns exec \"$ns1\" ping -c 1 -W 1 10.0.1.4\n+\n+set -e\n+ip netns exec \"$ns2\" $NFT list ruleset | grep counter\n+ip netns exec \"$ns3\" $NFT \"list counter netdev rxt rxc\" | grep -q 'packets 0 '\n+ip netns exec \"$ns4\" $NFT \"list counter netdev rxt rxc\" | grep -q 'packets 0 '\n+\n+exit 0\ndiff --git a/tests/shell/testcases/packetpath/fwd_ip b/tests/shell/testcases/packetpath/fwd_ip\nnew file mode 100755\nindex 000000000000..f390ad6060ce\n--- /dev/null\n+++ b/tests/shell/testcases/packetpath/fwd_ip\n@@ -0,0 +1,156 @@\n+#!/bin/bash\n+\n+# Test case for nftables 'fwd to ip' in ingress hook.\n+# both ingress and egress hooks.\n+\n+# ns1 tx to n3, ns4 via ns2 (routing)\n+# if ok:\n+#    add rules to ns2 to fwd ip to ns3\n+#    add ns4 ip to ns3\n+#    send packet to ns3 and ns4 ip address\n+#    check both arrived at ns3\n+#    check no packet arrived at ns4\n+#\n+# Then repeat with ns2 having 'egress' ruleset.\n+\n+rnd=$(mktemp -u XXXXXXXX)\n+ns1=\"nft1in-$rnd\"\t# tx\n+ns2=\"nft2in-$rnd\"\t# fwd (nft rules)\n+ns3=\"nft3in-$rnd\"\t# rx\n+ns4=\"nft4in-$rnd\"\t# rx\n+\n+cleanup() {\n+\tip netns del \"$ns1\" 2>/dev/null\n+\tip netns del \"$ns2\" 2>/dev/null\n+\tip netns del \"$ns3\" 2>/dev/null\n+\tip netns del \"$ns4\" 2>/dev/null\n+}\n+\n+die() {\n+\tlocal n=\"$1\"\n+\n+\tip netns exec \"$n\" $NFT list ruleset\n+\n+\techo \"ns2 (router)\"\n+\tip netns exec \"$ns2\" $NFT list ruleset\n+\texit 1\n+}\n+\n+trap cleanup EXIT\n+\n+ping_and_check() {\n+\tip netns exec \"$ns1\" ping -c 1 -W 1 10.0.3.1 >/dev/null\n+\tip netns exec \"$ns1\" ping -c 1 -W 1 10.0.4.1 >/dev/null\n+\n+\t# Check that packets arrived at ns3\n+\tip netns exec \"$ns3\" $NFT \"list counter inet rxt rxc\" | grep -q 'packets 2 '\n+\tif [ $? -ne 0 ]; then\n+\t\techo \"ERROR: counter not incremented in $ns3\"\n+\t\tdie \"$ns3\"\n+\tfi\n+\n+\tip netns exec \"$ns4\" $NFT \"list counter inet rxt rxc\" | grep -q 'packets 0 '\n+\tif [ $? -ne 0 ]; then\n+\t\techo \"ERROR: counter incremented in $ns4\"\n+\t\tdie \"$ns4\"\n+\tfi\n+}\n+\n+set -e\n+set -x\n+\n+for n in \"$ns1\" \"$ns2\" \"$ns3\" \"$ns4\"; do\n+\tip netns add \"$n\"\n+\tip -net \"$n\" link set lo up\n+done\n+\n+\n+# Create veth pairs: ns1(veth0) <-> (veth1)ns2\n+#                    ns2(veth3) <-> (veth0)ns3\n+#                    ns2(veth4) <-> (veth0)ns4\n+ip link add veth0 netns \"$ns1\" type veth peer name veth1 netns \"$ns2\"\n+ip link add veth3 netns \"$ns2\" type veth peer name veth0 netns \"$ns3\"\n+ip link add veth4 netns \"$ns2\" type veth peer name veth0 netns \"$ns4\"\n+\n+# Set up addresses\n+ip -net \"$ns1\" addr add 10.0.1.1/24 dev veth0\n+\n+ip -net \"$ns2\" addr add 10.0.1.2/24 dev veth1\n+ip -net \"$ns2\" addr add 10.0.3.2/24 dev veth3\n+ip -net \"$ns2\" addr add 10.0.4.2/24 dev veth4\n+\n+ip -net \"$ns3\" addr add 10.0.3.1/24 dev veth0\n+ip -net \"$ns4\" addr add 10.0.4.1/24 dev veth0\n+\n+# Bring up interfaces\n+ip -net \"$ns1\" link set veth0 up\n+\n+ip -net \"$ns2\" link set veth1 up\n+ip -net \"$ns2\" link set veth3 up\n+ip -net \"$ns2\" link set veth4 up\n+\n+ip -net \"$ns3\" link set veth0 up\n+ip -net \"$ns4\" link set veth0 up\n+\n+ip netns exec \"$ns2\" sysctl -q net.ipv4.ip_forward=1\n+\n+ip -net \"$ns1\" route add default via 10.0.1.2\n+\n+ip -net \"$ns3\" route add default via 10.0.3.2 dev veth0\n+ip -net \"$ns4\" route add default via 10.0.4.2 dev veth0\n+\n+# Validate setup:\n+ip netns exec \"$ns1\" ping -q -c 1 10.0.3.1\n+ip netns exec \"$ns1\" ping -q -c 1 10.0.4.1\n+\n+# Add nftables rule in ns2 to forward packets from veth1 to veth3\n+# Packets arriving on veth1 (10.0.1.x) will be forwarded to veth3\n+ip netns exec \"$ns2\" $NFT -f /dev/stdin <<\"EOF\"\n+table netdev fwd_test {\n+\tchain ingress_veth1 {\n+\t\ttype filter hook ingress device veth1 priority 0; policy accept;\n+\t\t# Forward ICMP packets to 10.0.3.1 via neigh\n+\t\tip protocol icmp counter fwd ip to 10.0.3.1 device \"veth3\"\n+\t}\n+}\n+EOF\n+[ $? -ne 0 ] && exit 1\n+\n+for n in \"$ns3\" \"$ns4\"; do\n+ip netns exec \"$n\" $NFT -f /dev/stdin <<\"EOF\"\n+table inet rxt {\n+\tcounter rxc { }\n+\n+\tchain input {\n+\t\ttype filter hook input priority 0; policy accept;\n+\t\tip protocol icmp counter name \"rxc\"\n+\t}\n+}\n+EOF\n+done\n+\n+# duplicate address so stack accepts .4.1 too\n+ip -net \"$ns3\" addr add 10.0.4.1/32 dev veth0\n+\n+set +e\n+ping_and_check\n+\n+# Add nftables rule in ns2 to forward packets from veth1 to veth3\n+# Packets arriving on veth1 (10.0.1.x) will be forwarded to veth3\n+ip netns exec \"$ns2\" $NFT -f /dev/stdin <<\"EOF\"\n+flush ruleset\n+table netdev fwd_test {\n+\tchain egress_veth4 {\n+\t\ttype filter hook egress device veth4 priority 0; policy accept;\n+\t\t# Forward ICMP packets to 10.0.3.1 via neigh\n+\t\tip protocol icmp counter fwd ip to 10.0.3.1 device \"veth3\"\n+\t}\n+}\n+EOF\n+[ $? -ne 0 ] && exit 1\n+\n+echo \"Egress ruleset loaded\"\n+ip netns exec \"$ns3\" $NFT \"reset counter inet rxt rxc\"\n+ping_and_check\n+\n+exit 0\n",
    "prefixes": [
        "nft"
    ]
}