2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

netdev-offload: Add multi-thread API.

Expose functions reporting user configuration of offloading threads, as
well as utility functions for multithreading.

This will only expose the configuration knob to the user, while no
datapath will implement the multiple thread request.

This will allow implementations to use this API for offload thread
management in relevant layers before enabling the actual dataplane
implementation.

The offload thread ID is lazily allocated and can as such be in a
different order than the offload thread start sequence.

The RCU thread will sometime access hardware-offload objects from
a provider for reclamation purposes.  In such case, it will get
a default offload thread ID of 0. Care must be taken that using
this thread ID is safe concurrently with the offload threads.

Signed-off-by: Gaetan Rivet <grive@u256.net>
Reviewed-by: Eli Britstein <elibr@nvidia.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Gaetan Rivet 2021-09-08 11:47:38 +02:00 committed by Ilya Maximets
parent 2eac33c6cc
commit 62c2d8a675
5 changed files with 128 additions and 2 deletions

2
NEWS
View File

@ -7,6 +7,8 @@ Post-v2.16.0
to 'hash', enables hash-based Tx packet steering mode to utilize all the
Tx queues of the interface regardles of the number of PMD threads.
* Removed experimental tag for PMD Auto Load Balance.
* New configuration knob 'other_config:n-offload-threads' to change the
number of HW offloading threads.
- DPDK:
* EAL argument --socket-mem is no longer configured by default upon
start-up. If dpdk-socket-mem and dpdk-alloc-mem are not specified,

View File

@ -84,6 +84,7 @@ struct netdev_flow_api {
struct dpif_flow_stats *);
/* Get the number of flows offloaded to netdev.
* 'n_flows' is an array of counters, one per offload thread.
* Return 0 if successful, otherwise returns a positive errno value. */
int (*flow_get_n_flows)(struct netdev *, uint64_t *n_flows);

View File

@ -60,6 +60,12 @@ VLOG_DEFINE_THIS_MODULE(netdev_offload);
static bool netdev_flow_api_enabled = false;
#define DEFAULT_OFFLOAD_THREAD_NB 1
#define MAX_OFFLOAD_THREAD_NB 10
static unsigned int offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
DEFINE_EXTERN_PER_THREAD_DATA(netdev_offload_thread_id, OVSTHREAD_ID_UNSET);
/* Protects 'netdev_flow_apis'. */
static struct ovs_mutex netdev_flow_api_provider_mutex = OVS_MUTEX_INITIALIZER;
@ -448,6 +454,64 @@ netdev_is_flow_api_enabled(void)
return netdev_flow_api_enabled;
}
unsigned int
netdev_offload_thread_nb(void)
{
return offload_thread_nb;
}
unsigned int
netdev_offload_ufid_to_thread_id(const ovs_u128 ufid)
{
uint32_t ufid_hash;
if (netdev_offload_thread_nb() == 1) {
return 0;
}
ufid_hash = hash_words64_inline(
(const uint64_t [2]){ ufid.u64.lo,
ufid.u64.hi }, 2, 1);
return ufid_hash % netdev_offload_thread_nb();
}
unsigned int
netdev_offload_thread_init(void)
{
static atomic_count next_id = ATOMIC_COUNT_INIT(0);
bool thread_is_hw_offload;
bool thread_is_rcu;
thread_is_hw_offload = !strncmp(get_subprogram_name(),
"hw_offload", strlen("hw_offload"));
thread_is_rcu = !strncmp(get_subprogram_name(), "urcu", strlen("urcu"));
/* Panic if any other thread besides offload and RCU tries
* to initialize their thread ID. */
ovs_assert(thread_is_hw_offload || thread_is_rcu);
if (*netdev_offload_thread_id_get() == OVSTHREAD_ID_UNSET) {
unsigned int id;
if (thread_is_rcu) {
/* RCU will compete with other threads for shared object access.
* Reclamation functions using a thread ID must be thread-safe.
* For that end, and because RCU must consider all potential shared
* objects anyway, its thread-id can be whichever, so return 0.
*/
id = 0;
} else {
/* Only the actual offload threads have their own ID. */
id = atomic_count_inc(&next_id);
}
/* Panic if any offload thread is getting a spurious ID. */
ovs_assert(id < netdev_offload_thread_nb());
return *netdev_offload_thread_id_get() = id;
} else {
return *netdev_offload_thread_id_get();
}
}
void
netdev_ports_flow_flush(const char *dpif_type)
{
@ -660,7 +724,16 @@ netdev_ports_get_n_flows(const char *dpif_type, odp_port_t port_no,
ovs_rwlock_rdlock(&netdev_hmap_rwlock);
data = netdev_ports_lookup(port_no, dpif_type);
if (data) {
ret = netdev_flow_get_n_flows(data->netdev, n_flows);
uint64_t thread_n_flows[MAX_OFFLOAD_THREAD_NB] = {0};
unsigned int tid;
ret = netdev_flow_get_n_flows(data->netdev, thread_n_flows);
*n_flows = 0;
if (!ret) {
for (tid = 0; tid < netdev_offload_thread_nb(); tid++) {
*n_flows += thread_n_flows[tid];
}
}
}
ovs_rwlock_unlock(&netdev_hmap_rwlock);
return ret;
@ -713,7 +786,22 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config)
if (ovsthread_once_start(&once)) {
netdev_flow_api_enabled = true;
VLOG_INFO("netdev: Flow API Enabled");
offload_thread_nb = smap_get_ullong(ovs_other_config,
"n-offload-threads",
DEFAULT_OFFLOAD_THREAD_NB);
if (offload_thread_nb > MAX_OFFLOAD_THREAD_NB) {
VLOG_WARN("netdev: Invalid number of threads requested: %u",
offload_thread_nb);
offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
}
if (smap_get(ovs_other_config, "n-offload-threads")) {
VLOG_INFO("netdev: Flow API Enabled, using %u thread%s",
offload_thread_nb,
offload_thread_nb > 1 ? "s" : "");
} else {
VLOG_INFO("netdev: Flow API Enabled");
}
#ifdef __linux__
tc_set_policy(smap_get_def(ovs_other_config, "tc-policy",

View File

@ -21,6 +21,7 @@
#include "openvswitch/netdev.h"
#include "openvswitch/types.h"
#include "ovs-rcu.h"
#include "ovs-thread.h"
#include "packets.h"
#include "flow.h"
@ -81,6 +82,24 @@ struct offload_info {
odp_port_t orig_in_port; /* Originating in_port for tnl flows. */
};
DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, netdev_offload_thread_id);
unsigned int netdev_offload_thread_nb(void);
unsigned int netdev_offload_thread_init(void);
unsigned int netdev_offload_ufid_to_thread_id(const ovs_u128 ufid);
static inline unsigned int
netdev_offload_thread_id(void)
{
unsigned int id = *netdev_offload_thread_id_get();
if (OVS_UNLIKELY(id == OVSTHREAD_ID_UNSET)) {
id = netdev_offload_thread_init();
}
return id;
}
int netdev_flow_flush(struct netdev *);
int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump,
bool terse);

View File

@ -247,6 +247,22 @@
</p>
</column>
<column name="other_config" key="n-offload-threads"
type='{"type": "integer", "minInteger": 1, "maxInteger": 10}'>
<p>
Set this value to the number of threads created to manage hardware
offloads.
</p>
<p>
The default value is <code>1</code>. Changing this value requires
restarting the daemon.
</p>
<p>
This is only relevant for userspace datapath and only if
<ref column="other_config" key="hw-offload"/> is enabled.
</p>
</column>
<column name="other_config" key="tc-policy"
type='{"type": "string",
"enum": ["set", ["none", "skip_sw", "skip_hw"]]}'>