get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2221012,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2221012/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20260408170613.587902-10-aconole@redhat.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/1.1/projects/47/?format=api",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "git@github.com:openvswitch/ovs.git",
        "webscm_url": "https://github.com/openvswitch/ovs"
    },
    "msgid": "<20260408170613.587902-10-aconole@redhat.com>",
    "date": "2026-04-08T17:06:05",
    "name": "[ovs-dev,RFC,09/12] ct-offload: Add configuration infrastructure.",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "3335ef66cadad6c3d41be316688f9285b9e87bf3",
    "submitter": {
        "id": 67184,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/67184/?format=api",
        "name": "Aaron Conole",
        "email": "aconole@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20260408170613.587902-10-aconole@redhat.com/mbox/",
    "series": [
        {
            "id": 499163,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/499163/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=499163",
            "date": "2026-04-08T17:05:56",
            "name": "ct-offload: Introduce a conntrack offload infrastructure.",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/499163/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2221012/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/2221012/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=GHXK7E8W;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.136; helo=smtp3.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)",
            "smtp3.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=GHXK7E8W",
            "smtp3.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com"
        ],
        "Received": [
            "from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])\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 4frTy96Y3Xz1xv0\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 03:07:13 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp3.osuosl.org (Postfix) with ESMTP id EFEE261003;\n\tWed,  8 Apr 2026 17:07:11 +0000 (UTC)",
            "from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id Q8Esbd4qdxLg; Wed,  8 Apr 2026 17:07:10 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp3.osuosl.org (Postfix) with ESMTPS id 3AD1E6102C;\n\tWed,  8 Apr 2026 17:07:07 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 14056C0905;\n\tWed,  8 Apr 2026 17:07:07 +0000 (UTC)",
            "from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 04B91C0549\n for <dev@openvswitch.org>; Wed,  8 Apr 2026 17:07:06 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id 931A960FD2\n for <dev@openvswitch.org>; Wed,  8 Apr 2026 17:06:42 +0000 (UTC)",
            "from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id FTmL9dZI9vva for <dev@openvswitch.org>;\n Wed,  8 Apr 2026 17:06:41 +0000 (UTC)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 80E8C60FBD\n for <dev@openvswitch.org>; Wed,  8 Apr 2026 17:06:41 +0000 (UTC)",
            "from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-167-kcvqMyxoPbqIJ9IDm9A7PQ-1; Wed,\n 08 Apr 2026 13:06:37 -0400",
            "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 3841918005B3; Wed,  8 Apr 2026 17:06:36 +0000 (UTC)",
            "from RHTRH0061144.redhat.com (unknown [10.22.89.172])\n by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 227A0300019F; Wed,  8 Apr 2026 17:06:33 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavis at osuosl.org",
            "amavis at osuosl.org"
        ],
        "X-Comment": "SPF check N/A for local connections -\n client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ",
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 smtp3.osuosl.org 3AD1E6102C",
            "OpenDKIM Filter v2.11.0 smtp3.osuosl.org 80E8C60FBD"
        ],
        "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=aconole@redhat.com;\n receiver=<UNKNOWN>",
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp3.osuosl.org 80E8C60FBD",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1775668000;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=jsWCh3LR/TCzmOEC16eVc11EX+zB5Vaq6TZEiFxm7j8=;\n b=GHXK7E8W+z9C9o17W6jLBnB2Tm0wTWvEbvGCQbBKTo4ZzDj2aqVgJD166nfbT1Dl9hqaM3\n bOeluRvUEIuqSFHsWYjMyKlU69zJ+Xz60FlKpT/tZASRfkQbDvoCQ8yfGNeSuiwr2/VkSB\n L9/c8hvb3ZXtQxCDNedMt53JVyoMH5k=",
        "X-MC-Unique": "kcvqMyxoPbqIJ9IDm9A7PQ-1",
        "X-Mimecast-MFC-AGG-ID": "kcvqMyxoPbqIJ9IDm9A7PQ_1775667996",
        "To": "dev@openvswitch.org",
        "Date": "Wed,  8 Apr 2026 13:06:05 -0400",
        "Message-ID": "<20260408170613.587902-10-aconole@redhat.com>",
        "In-Reply-To": "<20260408170613.587902-1-aconole@redhat.com>",
        "References": "<20260408170613.587902-1-aconole@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "9zBmJQMF-J3SPh-q8Z0GGp15PS80NF2Ypa40bkLUH9Y_1775667996",
        "X-Mimecast-Originator": "redhat.com",
        "Subject": "[ovs-dev] [RFC 09/12] ct-offload: Add configuration infrastructure.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "From": "Aaron Conole via dev <ovs-dev@openvswitch.org>",
        "Reply-To": "Aaron Conole <aconole@redhat.com>",
        "Cc": "Eli Britstein <elibr@nvidia.com>, Florian Westphal <fwestpha@redhat.com>,\n Flavio Leitner <fbl@redhat.com>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "This allows configuring hardware offload on/off.  The ct_sweep\nexpiration is always trying to fill the ops batch anyway, so it\ndoesn't need an actual check for enabled / disabled.  Wrapping that\ncode in a check may also be harmful in the event that offload is\ndisabled with offloaded connections.\n\nSigned-off-by: Aaron Conole <aconole@redhat.com>\n---\n lib/conntrack.c    | 25 +++++++++++++----------\n lib/ct-offload.c   | 51 +++++++++++++++++++++++++++++++++++++++++++++-\n lib/ct-offload.h   |  8 ++++++++\n lib/dpif-offload.c | 13 ++++++++++++\n lib/dpif-offload.h |  1 +\n vswitchd/bridge.c  |  4 ++++\n 6 files changed, 90 insertions(+), 12 deletions(-)",
    "diff": "diff --git a/lib/conntrack.c b/lib/conntrack.c\nindex 9872d7af51..e59630aa2b 100644\n--- a/lib/conntrack.c\n+++ b/lib/conntrack.c\n@@ -534,12 +534,14 @@ conn_clean(struct conntrack *ct, struct conn *conn)\n         atomic_count_dec(&zl->czl.count);\n     }\n \n-    struct ct_offload_ctx offload_ctx = {\n-        .conn           = conn,\n-        .netdev_in      = NULL,\n-        .input_port_id  = ODPP_NONE,\n-    };\n-    ct_offload_conn_del(&offload_ctx);\n+    if (ct_offload_enabled()) {\n+        struct ct_offload_ctx offload_ctx = {\n+            .conn           = conn,\n+            .netdev_in      = NULL,\n+            .input_port_id  = ODPP_NONE,\n+        };\n+        ct_offload_conn_del(&offload_ctx);\n+    }\n \n     ovsrcu_postpone(delete_conn, conn);\n     atomic_count_dec(&ct->n_conn);\n@@ -1405,7 +1407,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,\n         }\n         ovs_mutex_unlock(&ct->ct_lock);\n \n-        if (conn) {\n+        if (conn && ct_offload_enabled()) {\n             struct ct_offload_ctx offload_ctx = {\n                 .conn           = conn,\n                 .netdev_in      = NULL,\n@@ -1417,6 +1419,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,\n \n     if (!create_new_conn && conn && ctx->reply &&\n         (pkt->md.ct_state & CS_ESTABLISHED) &&\n+        ct_offload_enabled() &&\n         ct_offload_conn_is_offloaded(conn) &&\n         !ct_offload_conn_is_established(conn)) {\n         /* Notify offload providers that the connection is established.\n@@ -1581,7 +1584,6 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,\n     size_t cleaned = 0;\n     size_t count = 0;\n \n-\n     ct_offload_op_batch_init(&batch);\n \n     RCULIST_FOR_EACH (conn, node, list) {\n@@ -1595,7 +1597,6 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,\n                     .netdev_in      = NULL,\n                     .input_port_id  = ODPP_NONE,\n                 };\n-\n                 ct_offload_op_batch_add(&batch, CT_OFFLOAD_OP_UPD,\n                                         &offload_ctx);\n             }\n@@ -1603,12 +1604,14 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,\n         count++;\n     }\n \n-    /* Run the batch. */\n+    /* Run the batch: providers that can supply a hw last-used timestamp\n+     * return error==0, allowing us to extend the expiration.  A non-zero\n+     * error (typically ENODATA) means the connection has no hw activity\n+     * and should be expired normally. */\n     ct_offload_op_batch_submit(&batch);\n \n     CT_OFFLOAD_BATCH_OP_FOR_EACH (idx, op, &batch) {\n         struct conn *c = CONST_CAST(struct conn *, op->ctx.conn);\n-\n         if (op->error) {\n             conn_clean(ct, c);\n             cleaned++;\ndiff --git a/lib/ct-offload.c b/lib/ct-offload.c\nindex 618bd655d0..b777801ab9 100644\n--- a/lib/ct-offload.c\n+++ b/lib/ct-offload.c\n@@ -20,8 +20,10 @@\n #include \"conntrack.h\"\n #include \"conntrack-private.h\"\n #include \"ct-offload.h\"\n+#include \"dpif-offload.h\"\n #include \"ovs-thread.h\"\n #include \"util.h\"\n+#include \"vswitch-idl.h\"\n \n #include \"openvswitch/list.h\"\n #include \"openvswitch/vlog.h\"\n@@ -51,6 +53,12 @@ static struct ovs_list  ct_offload_classes\n     OVS_GUARDED_BY(ct_offload_mutex)\n     = OVS_LIST_INITIALIZER(&ct_offload_classes);\n \n+/* Built-in CT offload provider classes.  Only those whose name matches a\n+ * registered dpif offload class will be activated by ct_offload_module_init().\n+ */\n+static const struct ct_offload_class *base_ct_offload_classes[] = {\n+};\n+\n \n /* ct_offload_register() - register a CT offload provider class.\n  *\n@@ -140,11 +148,52 @@ ct_offload_alloc_private_slot(void)\n \n /* ct_offload_module_init() - register built-in CT offload providers.\n  *\n- * Must be called once before any connections are created. */\n+ * Only registers providers whose name matches a currently-registered dpif\n+ * offload class, so CT offload is automatically tied to the active hardware\n+ * offload provider.  Safe to call multiple times; subsequent calls are\n+ * no-ops (duplicate registration is detected and skipped). */\n void\n ct_offload_module_init(void)\n {\n     ct_offload_alloc_private_slot();\n+\n+    for (int i = 0; i < ARRAY_SIZE(base_ct_offload_classes); i++) {\n+        const struct ct_offload_class *class = base_ct_offload_classes[i];\n+\n+        if (dpif_offload_class_is_registered(class->name)) {\n+            ct_offload_register(class);\n+        }\n+    }\n+}\n+\n+/* ct_offload_enabled() - returns true when hardware offload is active.\n+ *\n+ * Delegates to dpif_offload_enabled() so CT offload shares the same global\n+ * enable/disable knob as datapath hardware offload. */\n+bool\n+ct_offload_enabled(void)\n+{\n+    return dpif_offload_enabled();\n+}\n+\n+/* ct_offload_set_global_cfg() - configure CT offload from OVSDB.\n+ *\n+ * Must be called alongside dpif_offload_set_global_cfg() so that CT offload\n+ * providers are registered once hardware offload has been enabled and the\n+ * appropriate dpif offload classes are known. */\n+void\n+ct_offload_set_global_cfg(const struct ovsrec_open_vswitch *cfg OVS_UNUSED)\n+{\n+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;\n+\n+    if (!dpif_offload_enabled()) {\n+        return;\n+    }\n+\n+    if (ovsthread_once_start(&once)) {\n+        ct_offload_module_init();\n+        ovsthread_once_done(&once);\n+    }\n }\n \n /* ct_offload_conn_add_() - notify all eligible providers of a new connection.\ndiff --git a/lib/ct-offload.h b/lib/ct-offload.h\nindex fcb3170fa1..fe4ecd33b8 100644\n--- a/lib/ct-offload.h\n+++ b/lib/ct-offload.h\n@@ -21,6 +21,7 @@\n \n struct conn;\n struct netdev;\n+struct ovsrec_open_vswitch;\n \n /* Context for offload as part of the callbacks that all connection\n  * offload APIs receive.\n@@ -91,6 +92,13 @@ void ct_offload_unregister(const struct ct_offload_class *);\n void ct_offload_alloc_private_slot(void);\n /* Module initialization (register built-in providers). */\n void ct_offload_module_init(void);\n+/* Global configuration: call alongside dpif_offload_set_global_cfg() to\n+ * enable CT offload when hardware offload is active. */\n+void ct_offload_set_global_cfg(const struct ovsrec_open_vswitch *);\n+\n+/* Returns true when CT offload is enabled (delegates to dpif_offload_enabled).\n+ */\n+bool ct_offload_enabled(void);\n \n /* Per-connection offload API that dispatches to all registered providers. */\n int       ct_offload_conn_add(const struct ct_offload_ctx *);\ndiff --git a/lib/dpif-offload.c b/lib/dpif-offload.c\nindex bb2feced9e..30cc4fd271 100644\n--- a/lib/dpif-offload.c\n+++ b/lib/dpif-offload.c\n@@ -516,6 +516,19 @@ dpif_offload_enabled(void)\n     return enabled;\n }\n \n+/* dpif_offload_class_is_registered() - returns true if a dpif offload class\n+ * with the given name has been successfully registered. */\n+bool\n+dpif_offload_class_is_registered(const char *name)\n+{\n+    bool found;\n+\n+    ovs_mutex_lock(&dpif_offload_mutex);\n+    found = shash_find(&dpif_offload_classes, name) != NULL;\n+    ovs_mutex_unlock(&dpif_offload_mutex);\n+    return found;\n+}\n+\n bool\n dpif_offload_rebalance_policy_enabled(void)\n {\ndiff --git a/lib/dpif-offload.h b/lib/dpif-offload.h\nindex 7fad3ebee3..d95e4b9463 100644\n--- a/lib/dpif-offload.h\n+++ b/lib/dpif-offload.h\n@@ -45,6 +45,7 @@ enum dpif_offload_impl_type {\n void dpif_offload_set_global_cfg(const struct ovsrec_open_vswitch *);\n bool dpif_offload_enabled(void);\n bool dpif_offload_rebalance_policy_enabled(void);\n+bool dpif_offload_class_is_registered(const char *name);\n \n \f\n /* Per dpif specific functions. */\ndiff --git a/vswitchd/bridge.c b/vswitchd/bridge.c\nindex 7a68e19ac3..91ffe76648 100644\n--- a/vswitchd/bridge.c\n+++ b/vswitchd/bridge.c\n@@ -28,6 +28,7 @@\n #include \"daemon.h\"\n #include \"dirs.h\"\n #include \"dpif.h\"\n+#include \"ct-offload.h\"\n #include \"dpif-offload.h\"\n #include \"dpdk.h\"\n #include \"hash.h\"\n@@ -543,6 +544,8 @@ bridge_init(const char *remote)\n void\n bridge_exit(bool delete_datapath)\n {\n+    ct_offload_flush();\n+\n     if_notifier_manual_set_cb(NULL);\n     if_notifier_destroy(ifnotifier);\n     seq_destroy(ifaces_changed);\n@@ -3396,6 +3399,7 @@ bridge_run(void)\n \n     if (cfg && ovsdb_idl_get_seqno(idl) != idl_seqno) {\n         dpif_offload_set_global_cfg(cfg);\n+        ct_offload_set_global_cfg(cfg);\n     }\n \n     if (cfg) {\n",
    "prefixes": [
        "ovs-dev",
        "RFC",
        "09/12"
    ]
}