{"id":2221012,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2221012/?format=json","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=json","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=json","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=json","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"]}