This commit introduces the initial infrastructure required to allow different implementations for OvS actions. The patch introduces action function pointers which allows user to switch between different action implementations available. This will allow for more performance and flexibility so the user can choose the action implementation to best suite their use case.
Signed-off-by: Emma Finn <emma.f...@intel.com> --- v2: - Removed unused variable warning --- lib/automake.mk | 2 + lib/dpif-netdev.c | 2 + lib/odp-execute-private.c | 84 +++++++++++++++++++++++++++++++++ lib/odp-execute-private.h | 98 +++++++++++++++++++++++++++++++++++++++ lib/odp-execute.c | 39 ++++++++++++++-- lib/odp-execute.h | 4 ++ 6 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 lib/odp-execute-private.c create mode 100644 lib/odp-execute-private.h diff --git a/lib/automake.mk b/lib/automake.mk index 46f869a33..16087031f 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -201,6 +201,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/nx-match.h \ lib/object-collection.c \ lib/object-collection.h \ + lib/odp-execute-private.c \ + lib/odp-execute-private.h \ lib/odp-execute.c \ lib/odp-execute.h \ lib/odp-util.c \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 69d7ec26e..277e0d6c3 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1598,6 +1598,8 @@ create_dpif_netdev(struct dp_netdev *dp) dpif->dp = dp; dpif->last_port_seq = seq_read(dp->port_seq); + odp_execute_init(); + return &dpif->dpif; } diff --git a/lib/odp-execute-private.c b/lib/odp-execute-private.c new file mode 100644 index 000000000..6441c491c --- /dev/null +++ b/lib/odp-execute-private.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021 Intel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "dpdk.h" + +#include "openvswitch/vlog.h" +#include "odp-execute-private.h" +#include "odp-netlink.h" +#include "dp-packet.h" +#include "odp-util.h" + + +int32_t action_autoval_init(struct odp_execute_action_impl *self); +VLOG_DEFINE_THIS_MODULE(odp_execute_private); + +static struct odp_execute_action_impl action_impls[] = { + [ACTION_IMPL_SCALAR] = { + .available = 1, + .name = "scalar", + .probe = NULL, + .init_func = NULL, + }, +}; + +static void +action_impl_copy_funcs(struct odp_execute_action_impl *to, + const struct odp_execute_action_impl *from) +{ + for (uint32_t i = 0; i < __OVS_KEY_ATTR_MAX; i++) { + atomic_uintptr_t *func = (void *) &to->funcs[i]; + atomic_store_relaxed(func, (uintptr_t) from->funcs[i]); + } +} + +void +odp_execute_action_init(void) +{ + /* Call probe on each impl, and cache the result. */ + for (int i = 0; i < ACTION_IMPL_MAX; i++) { + bool avail = true; + if (action_impls[i].probe) { + /* Return zero is success, non-zero means error. */ + avail = (action_impls[i].probe() == 0); + } + VLOG_INFO("Action implementation %s (available: %s)\n", + action_impls[i].name, avail ? "available" : "not available"); + action_impls[i].available = avail; + } + + uint32_t i; + for (i = 0; i < ACTION_IMPL_MAX; i++) { + /* Each impl's function array is initialized to reflect the scalar + * implementation. This simplifies adding optimized implementations, + * as the autovalidator can always compare all actions. + * + * Below copies the scalar functions to all other implementations. + */ + if (i != ACTION_IMPL_SCALAR) { + action_impl_copy_funcs(&action_impls[i], + &action_impls[ACTION_IMPL_SCALAR]); + } + + if (action_impls[i].init_func) { + action_impls[i].init_func(&action_impls[i]); + } + } +} diff --git a/lib/odp-execute-private.h b/lib/odp-execute-private.h new file mode 100644 index 000000000..c2e86bbee --- /dev/null +++ b/lib/odp-execute-private.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 Intel. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ODP_EXTRACT_PRIVATE +#define ODP_EXTRACT_PRIVATE 1 + +#include "odp-execute.h" + +/* For __OVS_KEY_ATTR_MAX. */ +#include "odp-netlink.h" +#include "dp-packet.h" +#include "ovs-atomic.h" + +/* Forward declaration for typedef. */ +struct odp_execute_action_impl; + +/* Typedef for an initialization function that can initialize each + * implementation, checking requirements such as CPU ISA. + */ +typedef int32_t (*odp_execute_action_init_func) + (struct odp_execute_action_impl *self); + +/* Probe function is used to detect if this CPU has the ISA required + * to run the optimized action implementation. + * returns one on successful probe. + * returns negative errno on failure. + */ +typedef int (*odp_execute_action_probe)(void); + +/* Structure represents an implementation of the odp actions. */ +struct odp_execute_action_impl { + /* When set, the CPU ISA required for this implementation is available + * and the implementation can be used. + */ + bool available; + + /* Name of the implementation. */ + const char *name; + + /* Probe function is used to detect if this CPU has the ISA required + * to run the optimized miniflow implementation. It is optional and + * if it is not used, then it must be null. + */ + odp_execute_action_probe probe; + + /* Called to check requirements and if usable, initializes the + * implementation for use. + */ + odp_execute_action_init_func init_func; + + /* An array of callback functions, one for each action. */ + ATOMIC(odp_execute_cb) funcs[__OVS_KEY_ATTR_MAX]; +}; + +/* Order of Actions implementations. */ +enum odp_execute_action_impl_idx { + ACTION_IMPL_SCALAR, + /* See ACTION_IMPL_BEGIN below, for "first to-be-validated" impl. + * Do not change the autovalidator position in this list without updating + * the define below. + */ + + ACTION_IMPL_MAX, +}; + +/* Index to start verifying implementations from. */ +BUILD_ASSERT_DECL(ACTION_IMPL_SCALAR == 0); + +/* Odp execute init handles setting up the state of the actions functions at + * initialization time. It cannot return errors, as it must always succeed in + * initializing the scalar/generic codepath. + */ +void odp_execute_action_init(void); + +/* Update the current active functions to those requested in name. */ +void odp_execute_action_get(struct ds *name); +int32_t odp_execute_action_set(const char *name, + struct odp_execute_action_impl *active); + +/* Init function for the scalar implementation. Calls into the odp-execute.c + * file, and initializes the function pointers for optimized action types. + */ +int32_t odp_action_scalar_init(struct odp_execute_action_impl *self); + +#endif /* ODP_EXTRACT_PRIVATE */ diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 6eeda2a61..49dfa2a74 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -17,6 +17,7 @@ #include <config.h> #include "odp-execute.h" +#include "odp-execute-private.h" #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -830,6 +831,23 @@ requires_datapath_assistance(const struct nlattr *a) return false; } +/* The active function pointers on the datapath. ISA optimized implementations + * are enabled by plugging them into this static arary, which is consulted when + * applying actions on the datapath. + */ +static struct odp_execute_action_impl actions_active_impl; + +void +odp_execute_init(void) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + if (ovsthread_once_start(&once)) { + odp_execute_action_init(); + ovsthread_once_done(&once); + } +} + + /* Executes all of the 'actions_len' bytes of datapath actions in 'actions' on * the packets in 'batch'. If 'steal' is true, possibly modifies and * definitely free the packets in 'batch', otherwise leaves 'batch' unchanged. @@ -855,13 +873,12 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { int type = nl_attr_type(a); bool last_action = (left <= NLA_ALIGN(a->nla_len)); + /* Allow 'dp_execute_action' to steal the packet data if we do + * not need it any more. */ + bool should_steal = steal && last_action; if (requires_datapath_assistance(a)) { if (dp_execute_action) { - /* Allow 'dp_execute_action' to steal the packet data if we do - * not need it any more. */ - bool should_steal = steal && last_action; - dp_execute_action(dp, batch, a, should_steal); if (last_action || dp_packet_batch_is_empty(batch)) { @@ -876,8 +893,20 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, continue; } - switch ((enum ovs_action_attr) type) { + /* If type is set in the active actions implementation, call the + * function-pointer and an continue to the next action. + */ + enum ovs_action_attr attr_type = (enum ovs_action_attr) type; + if (actions_active_impl.funcs[attr_type]) { + actions_active_impl.funcs[attr_type](NULL, batch, a, should_steal); + continue; + } + + /* If the action was not handled by the active function pointers above, + * process them by switching on the type below. + */ + switch (attr_type) { case OVS_ACTION_ATTR_HASH: { const struct ovs_action_hash *hash_act = nl_attr_get(a); diff --git a/lib/odp-execute.h b/lib/odp-execute.h index a3578a575..c4f5303e7 100644 --- a/lib/odp-execute.h +++ b/lib/odp-execute.h @@ -28,6 +28,10 @@ struct dp_packet; struct pkt_metadata; struct dp_packet_batch; + +/* Called once at initialization time. */ +void odp_execute_init(void); + typedef void (*odp_execute_cb)(void *dp, struct dp_packet_batch *batch, const struct nlattr *action, bool should_steal); -- 2.25.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev