@@ -534,12 +534,14 @@ conn_clean(struct conntrack *ct, struct conn *conn)
atomic_count_dec(&zl->czl.count);
}
- struct ct_offload_ctx offload_ctx = {
- .conn = conn,
- .netdev_in = NULL,
- .input_port_id = ODPP_NONE,
- };
- ct_offload_conn_del(&offload_ctx);
+ if (ct_offload_enabled()) {
+ struct ct_offload_ctx offload_ctx = {
+ .conn = conn,
+ .netdev_in = NULL,
+ .input_port_id = ODPP_NONE,
+ };
+ ct_offload_conn_del(&offload_ctx);
+ }
ovsrcu_postpone(delete_conn, conn);
atomic_count_dec(&ct->n_conn);
@@ -1405,7 +1407,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,
}
ovs_mutex_unlock(&ct->ct_lock);
- if (conn) {
+ if (conn && ct_offload_enabled()) {
struct ct_offload_ctx offload_ctx = {
.conn = conn,
.netdev_in = NULL,
@@ -1417,6 +1419,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,
if (!create_new_conn && conn && ctx->reply &&
(pkt->md.ct_state & CS_ESTABLISHED) &&
+ ct_offload_enabled() &&
ct_offload_conn_is_offloaded(conn) &&
!ct_offload_conn_is_established(conn)) {
/* Notify offload providers that the connection is established.
@@ -1581,7 +1584,6 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,
size_t cleaned = 0;
size_t count = 0;
-
ct_offload_op_batch_init(&batch);
RCULIST_FOR_EACH (conn, node, list) {
@@ -1595,7 +1597,6 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,
.netdev_in = NULL,
.input_port_id = ODPP_NONE,
};
-
ct_offload_op_batch_add(&batch, CT_OFFLOAD_OP_UPD,
&offload_ctx);
}
@@ -1603,12 +1604,14 @@ ct_sweep(struct conntrack *ct, struct rculist *list, long long now,
count++;
}
- /* Run the batch. */
+ /* Run the batch: providers that can supply a hw last-used timestamp
+ * return error==0, allowing us to extend the expiration. A non-zero
+ * error (typically ENODATA) means the connection has no hw activity
+ * and should be expired normally. */
ct_offload_op_batch_submit(&batch);
CT_OFFLOAD_BATCH_OP_FOR_EACH (idx, op, &batch) {
struct conn *c = CONST_CAST(struct conn *, op->ctx.conn);
-
if (op->error) {
conn_clean(ct, c);
cleaned++;
@@ -20,8 +20,10 @@
#include "conntrack.h"
#include "conntrack-private.h"
#include "ct-offload.h"
+#include "dpif-offload.h"
#include "ovs-thread.h"
#include "util.h"
+#include "vswitch-idl.h"
#include "openvswitch/list.h"
#include "openvswitch/vlog.h"
@@ -51,6 +53,12 @@ static struct ovs_list ct_offload_classes
OVS_GUARDED_BY(ct_offload_mutex)
= OVS_LIST_INITIALIZER(&ct_offload_classes);
+/* Built-in CT offload provider classes. Only those whose name matches a
+ * registered dpif offload class will be activated by ct_offload_module_init().
+ */
+static const struct ct_offload_class *base_ct_offload_classes[] = {
+};
+
/* ct_offload_register() - register a CT offload provider class.
*
@@ -140,11 +148,52 @@ ct_offload_alloc_private_slot(void)
/* ct_offload_module_init() - register built-in CT offload providers.
*
- * Must be called once before any connections are created. */
+ * Only registers providers whose name matches a currently-registered dpif
+ * offload class, so CT offload is automatically tied to the active hardware
+ * offload provider. Safe to call multiple times; subsequent calls are
+ * no-ops (duplicate registration is detected and skipped). */
void
ct_offload_module_init(void)
{
ct_offload_alloc_private_slot();
+
+ for (int i = 0; i < ARRAY_SIZE(base_ct_offload_classes); i++) {
+ const struct ct_offload_class *class = base_ct_offload_classes[i];
+
+ if (dpif_offload_class_is_registered(class->name)) {
+ ct_offload_register(class);
+ }
+ }
+}
+
+/* ct_offload_enabled() - returns true when hardware offload is active.
+ *
+ * Delegates to dpif_offload_enabled() so CT offload shares the same global
+ * enable/disable knob as datapath hardware offload. */
+bool
+ct_offload_enabled(void)
+{
+ return dpif_offload_enabled();
+}
+
+/* ct_offload_set_global_cfg() - configure CT offload from OVSDB.
+ *
+ * Must be called alongside dpif_offload_set_global_cfg() so that CT offload
+ * providers are registered once hardware offload has been enabled and the
+ * appropriate dpif offload classes are known. */
+void
+ct_offload_set_global_cfg(const struct ovsrec_open_vswitch *cfg OVS_UNUSED)
+{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+ if (!dpif_offload_enabled()) {
+ return;
+ }
+
+ if (ovsthread_once_start(&once)) {
+ ct_offload_module_init();
+ ovsthread_once_done(&once);
+ }
}
/* ct_offload_conn_add_() - notify all eligible providers of a new connection.
@@ -21,6 +21,7 @@
struct conn;
struct netdev;
+struct ovsrec_open_vswitch;
/* Context for offload as part of the callbacks that all connection
* offload APIs receive.
@@ -91,6 +92,13 @@ void ct_offload_unregister(const struct ct_offload_class *);
void ct_offload_alloc_private_slot(void);
/* Module initialization (register built-in providers). */
void ct_offload_module_init(void);
+/* Global configuration: call alongside dpif_offload_set_global_cfg() to
+ * enable CT offload when hardware offload is active. */
+void ct_offload_set_global_cfg(const struct ovsrec_open_vswitch *);
+
+/* Returns true when CT offload is enabled (delegates to dpif_offload_enabled).
+ */
+bool ct_offload_enabled(void);
/* Per-connection offload API that dispatches to all registered providers. */
int ct_offload_conn_add(const struct ct_offload_ctx *);
@@ -516,6 +516,19 @@ dpif_offload_enabled(void)
return enabled;
}
+/* dpif_offload_class_is_registered() - returns true if a dpif offload class
+ * with the given name has been successfully registered. */
+bool
+dpif_offload_class_is_registered(const char *name)
+{
+ bool found;
+
+ ovs_mutex_lock(&dpif_offload_mutex);
+ found = shash_find(&dpif_offload_classes, name) != NULL;
+ ovs_mutex_unlock(&dpif_offload_mutex);
+ return found;
+}
+
bool
dpif_offload_rebalance_policy_enabled(void)
{
@@ -45,6 +45,7 @@ enum dpif_offload_impl_type {
void dpif_offload_set_global_cfg(const struct ovsrec_open_vswitch *);
bool dpif_offload_enabled(void);
bool dpif_offload_rebalance_policy_enabled(void);
+bool dpif_offload_class_is_registered(const char *name);
/* Per dpif specific functions. */
@@ -28,6 +28,7 @@
#include "daemon.h"
#include "dirs.h"
#include "dpif.h"
+#include "ct-offload.h"
#include "dpif-offload.h"
#include "dpdk.h"
#include "hash.h"
@@ -543,6 +544,8 @@ bridge_init(const char *remote)
void
bridge_exit(bool delete_datapath)
{
+ ct_offload_flush();
+
if_notifier_manual_set_cb(NULL);
if_notifier_destroy(ifnotifier);
seq_destroy(ifaces_changed);
@@ -3396,6 +3399,7 @@ bridge_run(void)
if (cfg && ovsdb_idl_get_seqno(idl) != idl_seqno) {
dpif_offload_set_global_cfg(cfg);
+ ct_offload_set_global_cfg(cfg);
}
if (cfg) {
This allows configuring hardware offload on/off. The ct_sweep expiration is always trying to fill the ops batch anyway, so it doesn't need an actual check for enabled / disabled. Wrapping that code in a check may also be harmful in the event that offload is disabled with offloaded connections. Signed-off-by: Aaron Conole <aconole@redhat.com> --- lib/conntrack.c | 25 +++++++++++++---------- lib/ct-offload.c | 51 +++++++++++++++++++++++++++++++++++++++++++++- lib/ct-offload.h | 8 ++++++++ lib/dpif-offload.c | 13 ++++++++++++ lib/dpif-offload.h | 1 + vswitchd/bridge.c | 4 ++++ 6 files changed, 90 insertions(+), 12 deletions(-)