@@ -37,18 +37,21 @@ enum dpif_netdev_impl_info_idx {
static struct dpif_netdev_impl_info_t dpif_impls[] = {
/* The default scalar C code implementation. */
[DPIF_NETDEV_IMPL_SCALAR] = { .input_func = dp_netdev_input,
+ .recirc_func = dp_netdev_recirculate,
.probe = NULL,
.name = "dpif_scalar", },
#if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && __SSE4_2__)
/* Only available on x86_64 bit builds with SSE 4.2 used for OVS core. */
[DPIF_NETDEV_IMPL_AVX512] = { .input_func = dp_netdev_input_avx512,
+ .recirc_func = dp_netdev_input_avx512_recirc,
.probe = dp_netdev_input_avx512_probe,
.name = "dpif_avx512", },
#endif
};
static dp_netdev_input_func default_dpif_func;
+static dp_netdev_recirc_func default_dpif_recirc_func;
dp_netdev_input_func
dp_netdev_impl_get_default(void)
@@ -79,6 +82,35 @@ dp_netdev_impl_get_default(void)
return default_dpif_func;
}
+dp_netdev_recirc_func
+dp_netdev_recirc_impl_get_default(void)
+{
+ /* For the first call, this will be NULL. Compute the compile time default.
+ */
+ if (!default_dpif_recirc_func) {
+ int dpif_idx = DPIF_NETDEV_IMPL_SCALAR;
+
+/* Configure-time overriding to run test suite on all implementations. */
+#if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && __SSE4_2__)
+#ifdef DPIF_AVX512_DEFAULT
+ dp_netdev_input_func_probe probe;
+
+ /* Check if the compiled default is compatible. */
+ probe = dpif_impls[DPIF_NETDEV_IMPL_AVX512].probe;
+ if (!probe || !probe()) {
+ dpif_idx = DPIF_NETDEV_IMPL_AVX512;
+ }
+#endif
+#endif
+
+ VLOG_INFO("Default re-circulate DPIF implementation is %s.\n",
+ dpif_impls[dpif_idx].name);
+ default_dpif_recirc_func = dpif_impls[dpif_idx].recirc_func;
+ }
+
+ return default_dpif_recirc_func;
+}
+
void
dp_netdev_impl_get(struct ds *reply, struct dp_netdev_pmd_thread **pmd_list,
size_t n)
@@ -114,10 +146,12 @@ dp_netdev_impl_get(struct ds *reply, struct dp_netdev_pmd_thread **pmd_list,
* returns the function pointer to the one requested by "name".
*/
static int32_t
-dp_netdev_impl_get_by_name(const char *name, dp_netdev_input_func *out_func)
+dp_netdev_impl_get_by_name(const char *name, dp_netdev_input_func *dpif_func,
+ dp_netdev_recirc_func *dpif_recirc_func)
{
ovs_assert(name);
- ovs_assert(out_func);
+ ovs_assert(dpif_func);
+ ovs_assert(dpif_recirc_func);
uint32_t i;
@@ -127,11 +161,13 @@ dp_netdev_impl_get_by_name(const char *name, dp_netdev_input_func *out_func)
if (dpif_impls[i].probe) {
int probe_err = dpif_impls[i].probe();
if (probe_err) {
- *out_func = NULL;
+ *dpif_func = NULL;
+ *dpif_recirc_func = NULL;
return probe_err;
}
}
- *out_func = dpif_impls[i].input_func;
+ *dpif_func = dpif_impls[i].input_func;
+ *dpif_recirc_func = dpif_impls[i].recirc_func;
return 0;
}
}
@@ -142,12 +178,15 @@ dp_netdev_impl_get_by_name(const char *name, dp_netdev_input_func *out_func)
int32_t
dp_netdev_impl_set_default_by_name(const char *name)
{
- dp_netdev_input_func new_default;
+ dp_netdev_input_func new_dpif_default;
+ dp_netdev_recirc_func new_dpif_recirc_default;
- int32_t err = dp_netdev_impl_get_by_name(name, &new_default);
+ int32_t err = dp_netdev_impl_get_by_name(name, &new_dpif_default,
+ &new_dpif_recirc_default);
if (!err) {
- default_dpif_func = new_default;
+ default_dpif_func = new_dpif_default;
+ default_dpif_recirc_func = new_dpif_recirc_default;
}
return err;
@@ -36,6 +36,12 @@ typedef int32_t (*dp_netdev_input_func)(struct dp_netdev_pmd_thread *pmd,
struct dp_packet_batch *packets,
odp_port_t port_no);
+/* Typedef for DPIF re-circulate functions.
+ * Returns whether all packets were processed successfully.
+ */
+typedef int32_t (*dp_netdev_recirc_func)(struct dp_netdev_pmd_thread *pmd,
+ struct dp_packet_batch *packets);
+
/* Probe a DPIF implementation. This allows the implementation to validate CPU
* ISA availability. Returns -ENOTSUP if not available, returns 0 if valid to
* use.
@@ -46,6 +52,10 @@ typedef int32_t (*dp_netdev_input_func_probe)(void);
struct dpif_netdev_impl_info_t {
/* Function pointer to execute to have this DPIF implementation run. */
dp_netdev_input_func input_func;
+
+ /* Function pointer to execute recirc DPIF implementation. */
+ dp_netdev_recirc_func recirc_func;
+
/* Function pointer to execute to check the CPU ISA is available to run. If
* not necessary, it must be set to NULL which implies that it is always
* valid to use. */
@@ -63,6 +73,10 @@ dp_netdev_impl_get(struct ds *reply, struct dp_netdev_pmd_thread **pmd_list,
* overridden at runtime. */
dp_netdev_input_func dp_netdev_impl_get_default(void);
+/* Returns the default recirculate DPIF which is first ./configure selected,
+ * but can be overridden at runtime. */
+dp_netdev_recirc_func dp_netdev_recirc_impl_get_default(void);
+
/* Overrides the default DPIF with the user set DPIF. */
int32_t dp_netdev_impl_set_default_by_name(const char *name);
@@ -124,6 +124,9 @@ struct dp_netdev_pmd_thread {
/* Function pointer to call for dp_netdev_input() functionality. */
ATOMIC(dp_netdev_input_func) netdev_input_func;
+ /* Function pointer to call for dp_netdev_recirculate() functionality. */
+ ATOMIC(dp_netdev_recirc_func) netdev_input_recirc_func;
+
/* Pointer for per-DPIF implementation scratch space. */
void *netdev_input_func_userdata;
@@ -1165,6 +1165,10 @@ dpif_netdev_impl_set(struct unixctl_conn *conn, int argc OVS_UNUSED,
* default. */
atomic_store_relaxed(&pmd->netdev_input_func,
dp_netdev_impl_get_default());
+ /* Initialize recirc DPIF function pointer to the newly configured
+ * default. */
+ atomic_store_relaxed(&pmd->netdev_input_recirc_func,
+ dp_netdev_recirc_impl_get_default());
};
free(pmd_list);
@@ -7455,6 +7459,14 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct dp_netdev *dp,
/* Initialize DPIF function pointer to the default configured version. */
atomic_init(&pmd->netdev_input_func, dp_netdev_impl_get_default());
+ /* Initialize recirculate DPIF function pointer to the default configured
+ * version. */
+ dp_netdev_recirc_func default_dpif_recirc_func =
+ dp_netdev_recirc_impl_get_default();
+ atomic_uintptr_t *pmd_recirc_func =
+ (void *) &pmd->netdev_input_recirc_func;
+ atomic_init(pmd_recirc_func, (uintptr_t) default_dpif_recirc_func);
+
/* Init default miniflow_extract function */
atomic_init(&pmd->miniflow_extract_opt, dp_mfex_impl_get_default());
@@ -8799,7 +8811,10 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
}
(*depth)++;
- dp_netdev_recirculate(pmd, packets_);
+ int ret = pmd->netdev_input_recirc_func(pmd, packets_);
+ if (ret) {
+ dp_netdev_recirculate(pmd, packets_);
+ }
(*depth)--;
return;
}
@@ -8871,7 +8886,10 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
}
(*depth)++;
- dp_netdev_recirculate(pmd, packets_);
+ int ret = pmd->netdev_input_recirc_func(pmd, packets_);
+ if (ret) {
+ dp_netdev_recirculate(pmd, packets_);
+ }
(*depth)--;
return;