get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2217624,
    "url": "http://patchwork.ozlabs.org/api/patches/2217624/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260330090944.1008027-5-lulu@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260330090944.1008027-5-lulu@redhat.com>",
    "list_archive_url": null,
    "date": "2026-03-30T08:58:12",
    "name": "[RFC,v3,4/7] net/filter-redirector: add AF_PACKET capture path",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "c413c88427ab0367b12f2e26c1e6f331725c4729",
    "submitter": {
        "id": 78960,
        "url": "http://patchwork.ozlabs.org/api/people/78960/?format=api",
        "name": "Cindy Lu",
        "email": "lulu@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260330090944.1008027-5-lulu@redhat.com/mbox/",
    "series": [
        {
            "id": 497984,
            "url": "http://patchwork.ozlabs.org/api/series/497984/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=497984",
            "date": "2026-03-30T08:58:09",
            "name": "net/filter: Add AF_PACKET support for vhost-net",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/497984/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2217624/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2217624/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Sw17PCiD;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fklq25TyRz1yGH\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 30 Mar 2026 20:11:10 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1w78eF-0006FO-So; Mon, 30 Mar 2026 05:11:05 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <lulu@redhat.com>) id 1w78dr-00067Y-5d\n for qemu-devel@nongnu.org; Mon, 30 Mar 2026 05:10:39 -0400",
            "from us-smtp-delivery-124.mimecast.com ([170.10.129.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <lulu@redhat.com>) id 1w78dp-0000Pa-4W\n for qemu-devel@nongnu.org; Mon, 30 Mar 2026 05:10:38 -0400",
            "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-433-yRAAiayANlWoY3rpqRISPA-1; Mon,\n 30 Mar 2026 05:10:32 -0400",
            "from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id B4E7719560A1; Mon, 30 Mar 2026 09:10:31 +0000 (UTC)",
            "from S2.redhat.com (unknown [10.72.112.39])\n by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 422DD19560AB; Mon, 30 Mar 2026 09:10:27 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1774861834;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=JCiM3aSs/f1RsAuqeti67op//+DqhHvZTedMuAAYf4w=;\n b=Sw17PCiD+uReuAiseG5SattOGpTvGVcfp9p+swltT+RTg4QuZPKqBjb47kh/5EN7P3vMdV\n FWV2/6gIUrQEuEcU7gOSRLl6egC1ssMLTt+BruIbkaTYLGGg6nO8j7RQE22Q0IJcXkQoJo\n 7nGy4EBng8PVVCoJOOJQaTSHbDvuwTU=",
        "X-MC-Unique": "yRAAiayANlWoY3rpqRISPA-1",
        "X-Mimecast-MFC-AGG-ID": "yRAAiayANlWoY3rpqRISPA_1774861831",
        "From": "Cindy Lu <lulu@redhat.com>",
        "To": "lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com,\n lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org",
        "Subject": "[RFC v3 4/7] net/filter-redirector: add AF_PACKET capture path",
        "Date": "Mon, 30 Mar 2026 16:58:12 +0800",
        "Message-ID": "<20260330090944.1008027-5-lulu@redhat.com>",
        "In-Reply-To": "<20260330090944.1008027-1-lulu@redhat.com>",
        "References": "<20260330090944.1008027-1-lulu@redhat.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.12",
        "Received-SPF": "pass client-ip=170.10.129.124; envelope-from=lulu@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com",
        "X-Spam_score_int": "27",
        "X-Spam_score": "2.7",
        "X-Spam_bar": "++",
        "X-Spam_report": "(2.7 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335,\n RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=1, RCVD_IN_VALIDITY_RPBL_BLOCKED=1,\n SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Wire the capture-side AF_PACKET socket into filter-redirector.\n\nWhen the redirector owns an AF_PACKET capture socket, install a read\nhandler that drains PACKET_OUTGOING frames from the TAP device and forwards\nthem into the existing redirector chardev path. Reuse the normal chardev\npacket framing so downstream code sees the same transport format as it\nalready handles today, and keep redirector statistics updated through the\nsame helper.\n\nAF_PACKET delivers a raw Ethernet frame while the redirector chardev path\ncan carry packets with an empty vnet header wrapper. When the backend has a\nvnet header length, prepend an empty legacy virtio-net header before the\nframe so the captured packet can move through the same chardev transport as\nregular redirector traffic.\n\nHook the fd handler up during setup, status changes and VM state changes so\ncapture is only active when the redirector is enabled and allowed to run in\nthe current VM state.\n\nSigned-off-by: Cindy Lu <lulu@redhat.com>\n---\n net/filter-mirror.c | 121 ++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 121 insertions(+)",
    "diff": "diff --git a/net/filter-mirror.c b/net/filter-mirror.c\nindex d9f6a11d6b..e114ddb7d1 100644\n--- a/net/filter-mirror.c\n+++ b/net/filter-mirror.c\n@@ -43,6 +43,7 @@ DECLARE_INSTANCE_CHECKER(MirrorState, FILTER_REDIRECTOR,\n                          TYPE_FILTER_REDIRECTOR)\n \n #define REDIRECTOR_MAX_LEN NET_BUFSIZE\n+#define REDIRECTOR_AF_PACKET_WRAP_LEN sizeof(struct virtio_net_hdr)\n \n struct MirrorState {\n     NetFilterState parent_obj;\n@@ -181,6 +182,17 @@ static int redirector_chr_can_read(void *opaque)\n     return REDIRECTOR_MAX_LEN;\n }\n \n+static bool filter_redirector_input_active(NetFilterState *nf, bool enable)\n+{\n+    MirrorState *s = FILTER_REDIRECTOR(nf);\n+\n+    if (!enable) {\n+        return false;\n+    }\n+\n+    return runstate_is_running() || s->enable_when_stopped;\n+}\n+\n static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)\n {\n     NetFilterState *nf = opaque;\n@@ -217,6 +229,91 @@ static void redirector_chr_event(void *opaque, QEMUChrEvent event)\n     }\n }\n \n+static int filter_redirector_send_chardev_iov(MirrorState *s,\n+                                              const struct iovec *iov,\n+                                              int iovcnt)\n+{\n+    int ret;\n+\n+    if (!qemu_chr_fe_backend_connected(&s->chr_out)) {\n+        return 0;\n+    }\n+\n+    ret = filter_send(s, iov, iovcnt);\n+    if (ret > 0) {\n+        s->outdev_packets++;\n+        s->outdev_bytes += ret;\n+    }\n+\n+    return ret;\n+}\n+\n+static void filter_redirector_capture_netdev_read(void *opaque)\n+{\n+    NetFilterState *nf = opaque;\n+    MirrorState *s = FILTER_REDIRECTOR(nf);\n+    char vnet_hdr[REDIRECTOR_AF_PACKET_WRAP_LEN] = { 0 };\n+    struct iovec iov[2];\n+    struct sockaddr_ll sll;\n+    socklen_t sll_len;\n+    ssize_t len;\n+    size_t wrap_vnet_hdr_len;\n+    int iovcnt;\n+    int ret;\n+\n+    if (!s->in_netbuf || s->in_netfd < 0) {\n+        return;\n+    }\n+\n+    for (;;) {\n+        sll_len = sizeof(sll);\n+        len = recvfrom(s->in_netfd, s->in_netbuf, REDIRECTOR_MAX_LEN, 0,\n+                       (struct sockaddr *)&sll, &sll_len);\n+        if (len <= 0) {\n+            break;\n+        }\n+\n+        if (sll.sll_pkttype != PACKET_OUTGOING) {\n+            continue;\n+        }\n+\n+        /*\n+         * AF_PACKET gives us a raw Ethernet frame. Wrap it as a regular\n+         * redirector payload by prepending an empty legacy virtio-net header,\n+         * so the downstream chardev path can treat it like a normal packet.\n+         */\n+        wrap_vnet_hdr_len = qemu_get_vnet_hdr_len(nf->netdev) ?\n+                            REDIRECTOR_AF_PACKET_WRAP_LEN : 0;\n+        if (len + wrap_vnet_hdr_len > REDIRECTOR_MAX_LEN) {\n+            error_report(\"filter redirector packet too large after wrap(%zd)\",\n+                         len);\n+            continue;\n+        }\n+\n+        iov[0].iov_base = s->in_netbuf;\n+        iov[0].iov_len = len;\n+        iovcnt = 1;\n+        if (wrap_vnet_hdr_len) {\n+            iov[0].iov_base = vnet_hdr;\n+            iov[0].iov_len = wrap_vnet_hdr_len;\n+            iov[1].iov_base = s->in_netbuf;\n+            iov[1].iov_len = len;\n+            iovcnt = 2;\n+        }\n+\n+        ret = filter_redirector_send_chardev_iov(s, iov, iovcnt);\n+        if (ret < 0) {\n+            error_report(\"filter redirector send failed(%s)\", strerror(-ret));\n+        }\n+    }\n+\n+    if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK &&\n+        errno != EINTR) {\n+        error_report(\"filter redirector read netdev failed(%s)\",\n+                     strerror(errno));\n+    }\n+}\n+\n static ssize_t filter_mirror_receive_iov(NetFilterState *nf,\n                                          NetClientState *sender,\n                                          unsigned flags,\n@@ -353,6 +450,14 @@ static void filter_redirector_vm_state_change(void *opaque, bool running,\n     NetFilterState *nf = opaque;\n     MirrorState *s = FILTER_REDIRECTOR(nf);\n     NetClientState *nc = nf->netdev;\n+    bool active = filter_redirector_input_active(nf, nf->on);\n+\n+    if (s->in_netfd >= 0) {\n+        qemu_set_fd_handler(s->in_netfd,\n+                            active ?\n+                            filter_redirector_capture_netdev_read : NULL,\n+                            NULL, active ? nf : NULL);\n+    }\n \n     if (!running && s->enable_when_stopped && nc->info->read_poll) {\n         nc->info->read_poll(nc, true);\n@@ -448,6 +553,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)\n {\n     MirrorState *s = FILTER_REDIRECTOR(nf);\n     Chardev *chr;\n+    bool active = filter_redirector_input_active(nf, nf->on);\n \n     if (!s->indev && !s->outdev) {\n         error_setg(errp, \"filter redirector needs 'indev' or \"\n@@ -501,6 +607,13 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)\n     s->vmsentry = qemu_add_vm_change_state_handler(\n         filter_redirector_vm_state_change, nf);\n \n+    if (s->in_netfd >= 0) {\n+        qemu_set_fd_handler(s->in_netfd,\n+                            active ?\n+                            filter_redirector_capture_netdev_read : NULL,\n+                            NULL, active ? nf : NULL);\n+    }\n+\n     filter_redirector_maybe_enable_read_poll(nf);\n \n     filter_redirector_refresh_allow_send_when_stopped(nf);\n@@ -509,6 +622,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)\n static void filter_redirector_status_changed(NetFilterState *nf, Error **errp)\n {\n     MirrorState *s = FILTER_REDIRECTOR(nf);\n+    bool active = filter_redirector_input_active(nf, nf->on);\n \n     if (s->indev) {\n         if (nf->on) {\n@@ -521,6 +635,13 @@ static void filter_redirector_status_changed(NetFilterState *nf, Error **errp)\n         }\n     }\n \n+    if (s->in_netfd >= 0) {\n+        qemu_set_fd_handler(s->in_netfd,\n+                            active ?\n+                            filter_redirector_capture_netdev_read : NULL,\n+                            NULL, active ? nf : NULL);\n+    }\n+\n     if (nf->on) {\n         filter_redirector_maybe_enable_read_poll(nf);\n     }\n",
    "prefixes": [
        "RFC",
        "v3",
        "4/7"
    ]
}