diff mbox series

[ovs-dev,RFC,07/12] ct-offload: Add a mark for offloaded connections.

Message ID 20260408170613.587902-8-aconole@redhat.com
State New
Headers show
Series ct-offload: Introduce a conntrack offload infrastructure. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Aaron Conole April 8, 2026, 5:06 p.m. UTC
This helps future work to determine whether a connection
needs to be cleaned up during offload sweeping, and whether
to notify offload providers about established connections.

Additionally, update the TCP sequence check to skip verifying
sequence numbers for offloaded connections.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 lib/conntrack-tcp.c |  8 +++--
 lib/ct-offload.c    | 81 +++++++++++++++++++++++++++++++++++++++++++--
 lib/ct-offload.h    |  8 +++++
 3 files changed, 92 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c
index 696fd5c109..1e71b40d40 100644
--- a/lib/conntrack-tcp.c
+++ b/lib/conntrack-tcp.c
@@ -39,6 +39,7 @@ 
 
 #include <config.h>
 
+#include "ct-offload.h"
 #include "conntrack-private.h"
 #include "conntrack-tcp.h"
 #include "conntrack-tp.h"
@@ -133,9 +134,10 @@  tcp_get_wscale(const struct tcp_header *tcp)
 }
 
 static bool
-tcp_bypass_seq_chk(struct conntrack *ct)
+tcp_bypass_seq_chk(struct conntrack *ct, struct conn *conn)
 {
-    if (!conntrack_get_tcp_seq_chk(ct)) {
+    if (!conntrack_get_tcp_seq_chk(ct) ||
+        ct_offload_conn_is_offloaded(conn)) {
         COVERAGE_INC(conntrack_tcp_seq_chk_bypass);
         return true;
     }
@@ -286,7 +288,7 @@  tcp_conn_update(struct conntrack *ct, struct conn *conn_,
         /* Acking not more than one window forward */
         && ((tcp_flags & TCP_RST) == 0 || orig_seq == src->seqlo
             || (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo)))
-        || tcp_bypass_seq_chk(ct)) {
+        || tcp_bypass_seq_chk(ct, conn_)) {
         /* Require an exact/+1 sequence match on resets when possible */
 
         /* update max window */
diff --git a/lib/ct-offload.c b/lib/ct-offload.c
index 97c922dde1..618bd655d0 100644
--- a/lib/ct-offload.c
+++ b/lib/ct-offload.c
@@ -17,6 +17,8 @@ 
 #include <config.h>
 #include <errno.h>
 
+#include "conntrack.h"
+#include "conntrack-private.h"
 #include "ct-offload.h"
 #include "ovs-thread.h"
 #include "util.h"
@@ -26,6 +28,15 @@ 
 
 VLOG_DEFINE_THIS_MODULE(ct_offload);
 
+/* Private data slot used to mark connections that have been successfully
+ * offloaded.  Allocated once at module init; no destructor needed because
+ * the stored value is a plain integer cast to pointer, not heap data. */
+static ct_private_id_t ct_offload_private_id = CT_PRIVATE_ID_INVALID;
+
+#define CT_OFFLOAD_STATE_NONE  ((void *) 0)
+#define CT_OFFLOAD_STATE_ADDED ((void *) 1)
+#define CT_OFFLOAD_STATE_EST   ((void *) 2)
+
 /* Node in the registered-provider list. */
 struct ct_offload_class_node {
     const struct ct_offload_class *class;
@@ -111,14 +122,29 @@  out:
     ovs_mutex_unlock(&ct_offload_mutex);
 }
 
+void
+ct_offload_alloc_private_slot(void)
+{
+    static struct ovsthread_once once_enable = OVSTHREAD_ONCE_INITIALIZER;
+
+    if (ovsthread_once_start(&once_enable)) {
+        /* Allocate the per-connection private slot. */
+        ct_offload_private_id = conn_private_id_alloc(NULL);
+        if (ct_offload_private_id == CT_PRIVATE_ID_INVALID) {
+            VLOG_ERR("failed to allocate ct offload private id: "
+                     "is-offloaded tracking disabled");
+        }
+        ovsthread_once_done(&once_enable);
+    }
+}
+
 /* ct_offload_module_init() - register built-in CT offload providers.
  *
  * Must be called once before any connections are created. */
 void
 ct_offload_module_init(void)
 {
-    /* No built-in providers yet; third parties call ct_offload_register()
-     * directly from their own module-init routines. */
+    ct_offload_alloc_private_slot();
 }
 
 /* ct_offload_conn_add_() - notify all eligible providers of a new connection.
@@ -157,6 +183,11 @@  ct_offload_conn_add_(const struct ct_offload_ctx *ctx, bool batched)
         }
     }
 
+    if (!ret && ct_offload_private_id != CT_PRIVATE_ID_INVALID) {
+        conn_private_set(CONST_CAST(struct conn *, ctx->conn),
+                         ct_offload_private_id, CT_OFFLOAD_STATE_ADDED);
+    }
+
     return ret;
 }
 
@@ -195,6 +226,11 @@  ct_offload_conn_del_(const struct ct_offload_ctx *ctx, bool batched)
             class->conn_del(ctx);
         }
     }
+
+    if (ct_offload_private_id != CT_PRIVATE_ID_INVALID) {
+        conn_private_set(CONST_CAST(struct conn *, ctx->conn),
+                         ct_offload_private_id, CT_OFFLOAD_STATE_NONE);
+    }
 }
 
 void
@@ -208,8 +244,19 @@  ct_offload_conn_del(const struct ct_offload_ctx *ctx)
 static int
 ct_offload_conn_established_(const struct ct_offload_ctx *ctx, bool batched)
 {
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(600, 600);
     struct ct_offload_class_node *node;
 
+    if (ct_offload_private_id == CT_PRIVATE_ID_INVALID) {
+        VLOG_WARN_RL(&rl, "ct_offload id not allocted: always sending est.");
+        return EAGAIN;
+    }
+
+    if (conn_private_get(ctx->conn, ct_offload_private_id) !=
+        CT_OFFLOAD_STATE_ADDED) {
+        return EALREADY;
+    }
+
     LIST_FOR_EACH (node, list_node, &ct_offload_classes) {
         const struct ct_offload_class *class = node->class;
 
@@ -225,6 +272,8 @@  ct_offload_conn_established_(const struct ct_offload_ctx *ctx, bool batched)
         }
     }
 
+    conn_private_set(CONST_CAST(struct conn *, ctx->conn),
+                     ct_offload_private_id, CT_OFFLOAD_STATE_EST);
     return 0;
 }
 
@@ -453,6 +502,34 @@  ct_offload_op_batch_submit(struct ct_offload_op_batch *batch)
     ovs_mutex_unlock(&ct_offload_mutex);
 }
 
+/* ct_offload_conn_is_offloaded() - return true if conn is currently offloaded.
+ *
+ * Reads the private slot set by ct_offload_conn_add() on success and cleared
+ * by ct_offload_conn_del().  Returns false when the private slot could not be
+ * allocated at init time. */
+bool
+ct_offload_conn_is_offloaded(const struct conn *conn)
+{
+    if (ct_offload_private_id == CT_PRIVATE_ID_INVALID) {
+        return false;
+    }
+    return conn_private_get(conn, ct_offload_private_id) !=
+        CT_OFFLOAD_STATE_NONE;
+}
+
+/* ct_offload_conn_is_established() - return true if conn transitioned to
+ * established state.  Returns false when the private slot could not be
+ * allocated at init time. */
+bool
+ct_offload_conn_is_established(const struct conn *conn)
+{
+    if (ct_offload_private_id == CT_PRIVATE_ID_INVALID) {
+        return false;
+    }
+    return conn_private_get(conn, ct_offload_private_id) ==
+        CT_OFFLOAD_STATE_EST;
+}
+
 /* ct_offload_op_batch_destroy() - release memory held by the batch.
  *
  * The batch may be re-initialised with ct_offload_op_batch_init() after
diff --git a/lib/ct-offload.h b/lib/ct-offload.h
index 36871d12cb..fcb3170fa1 100644
--- a/lib/ct-offload.h
+++ b/lib/ct-offload.h
@@ -87,6 +87,8 @@  struct ct_offload_class {
 int  ct_offload_register(const struct ct_offload_class *);
 void ct_offload_unregister(const struct ct_offload_class *);
 
+/* Allocate private slot id. */
+void ct_offload_alloc_private_slot(void);
 /* Module initialization (register built-in providers). */
 void ct_offload_module_init(void);
 
@@ -98,6 +100,12 @@  void      ct_offload_conn_established(const struct ct_offload_ctx *);
 bool      ct_offload_can_offload(const struct ct_offload_ctx *);
 void      ct_offload_flush(void);
 
+/* Returns true if 'conn' has been successfully offloaded to hardware.
+ * Set by ct_offload_conn_add(); cleared by ct_offload_conn_del(). */
+bool      ct_offload_conn_is_offloaded(const struct conn *);
+/* Returns true if 'conn' has been transitioned to established state. */
+bool      ct_offload_conn_is_established(const struct conn *);
+
 /* Batch offload API.
  *
  * The default implementation dispatches each operation individually using the