summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--acinclude.m416
-rw-r--r--configure.ac1
-rw-r--r--lib/automake.mk3
-rw-r--r--lib/dpif-netdev-lookup-autovalidator.c110
-rw-r--r--lib/dpif-netdev-lookup-generic.c9
-rw-r--r--lib/dpif-netdev-lookup.c104
-rw-r--r--lib/dpif-netdev-lookup.h75
-rw-r--r--lib/dpif-netdev-private.h15
-rw-r--r--lib/dpif-netdev.c13
9 files changed, 322 insertions, 24 deletions
diff --git a/acinclude.m4 b/acinclude.m4
index 863a04349..0f1986184 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -14,6 +14,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+dnl Set OVS DPCLS Autovalidator as default subtable search at compile time?
+dnl This enables automatically running all unit tests with all DPCLS
+dnl implementations.
+AC_DEFUN([OVS_CHECK_DPCLS_AUTOVALIDATOR], [
+ AC_ARG_ENABLE([autovalidator],
+ [AC_HELP_STRING([--enable-autovalidator], [Enable DPCLS autovalidator as default subtable search implementation.])],
+ [autovalidator=yes],[autovalidator=no])
+ AC_MSG_CHECKING([whether DPCLS Autovalidator is default implementation])
+ if test "$autovalidator" != yes; then
+ AC_MSG_RESULT([no])
+ else
+ OVS_CFLAGS="$OVS_CFLAGS -DDPCLS_AUTOVALIDATOR_DEFAULT"
+ AC_MSG_RESULT([yes])
+ fi
+])
+
dnl OVS_ENABLE_WERROR
AC_DEFUN([OVS_ENABLE_WERROR],
[AC_ARG_ENABLE(
diff --git a/configure.ac b/configure.ac
index 5ce510c20..4a6995ea8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,6 +181,7 @@ OVS_CONDITIONAL_CC_OPTION([-Wno-unused-parameter], [HAVE_WNO_UNUSED_PARAMETER])
OVS_ENABLE_WERROR
OVS_ENABLE_SPARSE
OVS_CTAGS_IDENTIFIERS
+OVS_CHECK_DPCLS_AUTOVALIDATOR
AC_ARG_VAR(KARCH, [Kernel Architecture String])
AC_SUBST(KARCH)
diff --git a/lib/automake.mk b/lib/automake.mk
index 86940ccd2..1fc1a209e 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -81,6 +81,9 @@ lib_libopenvswitch_la_SOURCES = \
lib/dp-packet.h \
lib/dp-packet.c \
lib/dpdk.h \
+ lib/dpif-netdev-lookup.h \
+ lib/dpif-netdev-lookup.c \
+ lib/dpif-netdev-lookup-autovalidator.c \
lib/dpif-netdev-lookup-generic.c \
lib/dpif-netdev.c \
lib/dpif-netdev.h \
diff --git a/lib/dpif-netdev-lookup-autovalidator.c b/lib/dpif-netdev-lookup-autovalidator.c
new file mode 100644
index 000000000..97b59fdd0
--- /dev/null
+++ b/lib/dpif-netdev-lookup-autovalidator.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020 Intel Corporation.
+ *
+ * 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 "dpif-netdev.h"
+#include "dpif-netdev-lookup.h"
+#include "dpif-netdev-private.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(dpif_lookup_autovalidator);
+
+/* This file implements an automated validator for subtable search
+ * implementations. It compares the results of the generic scalar search result
+ * with ISA optimized implementations.
+ *
+ * Note the goal is *NOT* to test the *specialized* versions of subtables, as
+ * the compiler performs the specialization - and we rely on the correctness of
+ * the compiler to not break those specialized variants.
+ *
+ * The goal is to ensure identical results of the different implementations,
+ * despite that the implementations may have different methods to get those
+ * results.
+ *
+ * Example: AVX-512 ISA uses different instructions and algorithm to the scalar
+ * implementation, however the results (rules[] output) must be the same.
+ */
+
+dpcls_subtable_lookup_func
+dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED,
+ uint32_t u1 OVS_UNUSED);
+
+static uint32_t
+dpcls_subtable_autovalidator(struct dpcls_subtable *subtable,
+ uint32_t keys_map,
+ const struct netdev_flow_key *keys[],
+ struct dpcls_rule **rules_good)
+{
+ const uint32_t u0_bit_count = subtable->mf_bits_set_unit0;
+ const uint32_t u1_bit_count = subtable->mf_bits_set_unit1;
+
+ /* Scalar generic - the "known correct" version. */
+ dpcls_subtable_lookup_func lookup_good;
+ lookup_good = dpcls_subtable_generic_probe(u0_bit_count, u1_bit_count);
+
+ /* Run actual scalar implementation to get known good results. */
+ uint32_t matches_good = lookup_good(subtable, keys_map, keys, rules_good);
+
+ struct dpcls_subtable_lookup_info_t *lookup_funcs;
+ int32_t lookup_func_count = dpcls_subtable_lookup_info_get(&lookup_funcs);
+ if (lookup_func_count < 0) {
+ VLOG_ERR("failed to get lookup subtable function implementations\n");
+ return 0;
+ }
+
+ /* Ensure the autovalidator is the 0th item in the lookup_funcs array. */
+ ovs_assert(lookup_funcs[0].probe(0, 0) == dpcls_subtable_autovalidator);
+
+ /* Now compare all other implementations against known good results.
+ * Note we start iterating from array[1], as 0 is the autotester itself.
+ */
+ for (int i = 1; i < lookup_func_count; i++) {
+ dpcls_subtable_lookup_func lookup_func;
+ lookup_func = lookup_funcs[i].probe(u0_bit_count,
+ u1_bit_count);
+
+ /* If its probe returns a function, then test it. */
+ if (lookup_func) {
+ struct dpcls_rule *rules_test[NETDEV_MAX_BURST];
+ size_t rules_size = sizeof(struct dpcls_rule *) * NETDEV_MAX_BURST;
+ memset(rules_test, 0, rules_size);
+ uint32_t matches_test = lookup_func(subtable, keys_map, keys,
+ rules_test);
+
+ /* Ensure same packets matched against subtable. */
+ if (matches_good != matches_test) {
+ VLOG_ERR("matches_good 0x%x != matches_test 0x%x in func %s\n",
+ matches_good, matches_test, lookup_funcs[i].name);
+ }
+
+ /* Ensure rules matched are the same for scalar / others. */
+ int j;
+ ULLONG_FOR_EACH_1 (j, matches_test) {
+ ovs_assert(rules_good[j] == rules_test[j]);
+ }
+ }
+ }
+
+ return matches_good;
+}
+
+dpcls_subtable_lookup_func
+dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED,
+ uint32_t u1 OVS_UNUSED)
+{
+ /* Always return the same validator tester, it works for all subtables. */
+ return dpcls_subtable_autovalidator;
+}
diff --git a/lib/dpif-netdev-lookup-generic.c b/lib/dpif-netdev-lookup-generic.c
index 89c8be0fa..b1a0cfc36 100644
--- a/lib/dpif-netdev-lookup-generic.c
+++ b/lib/dpif-netdev-lookup-generic.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Nicira, Inc.
- * Copyright (c) 2019 Intel Corporation.
+ * Copyright (c) 2019, 2020 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
#include <config.h>
#include "dpif-netdev.h"
#include "dpif-netdev-private.h"
+#include "dpif-netdev-lookup.h"
#include "bitmap.h"
#include "cmap.h"
@@ -254,7 +255,7 @@ lookup_generic_impl(struct dpcls_subtable *subtable,
}
/* Generic lookup function that uses runtime provided mf bits for iterating. */
-uint32_t
+static uint32_t
dpcls_subtable_lookup_generic(struct dpcls_subtable *subtable,
uint32_t keys_map,
const struct netdev_flow_key *keys[],
@@ -310,6 +311,10 @@ dpcls_subtable_generic_probe(uint32_t u0_bits, uint32_t u1_bits)
if (f) {
VLOG_DBG("Subtable using Generic Optimized for u0 %d, u1 %d\n",
u0_bits, u1_bits);
+ } else {
+ /* Always return the generic function. */
+ f = dpcls_subtable_lookup_generic;
}
+
return f;
}
diff --git a/lib/dpif-netdev-lookup.c b/lib/dpif-netdev-lookup.c
new file mode 100644
index 000000000..530187e9c
--- /dev/null
+++ b/lib/dpif-netdev-lookup.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Intel Corporation.
+ *
+ * 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 <errno.h>
+#include "dpif-netdev-lookup.h"
+
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(dpif_netdev_lookup);
+
+/* Actual list of implementations goes here */
+static struct dpcls_subtable_lookup_info_t subtable_lookups[] = {
+ /* The autovalidator implementation will not be used by default, it must
+ * be enabled at compile time to be the default lookup implementation. The
+ * user may enable it at runtime using the normal "prio-set" command if
+ * desired. The compile time default switch is here to enable all unit
+ * tests to transparently run with the autovalidator.
+ */
+#ifdef DPCLS_AUTOVALIDATOR_DEFAULT
+ { .prio = 255,
+#else
+ { .prio = 0,
+#endif
+ .probe = dpcls_subtable_autovalidator_probe,
+ .name = "autovalidator", },
+
+ /* The default scalar C code implementation. */
+ { .prio = 1,
+ .probe = dpcls_subtable_generic_probe,
+ .name = "generic", },
+};
+
+int32_t
+dpcls_subtable_lookup_info_get(struct dpcls_subtable_lookup_info_t **out_ptr)
+{
+ if (out_ptr == NULL) {
+ return -1;
+ }
+
+ *out_ptr = subtable_lookups;
+ return ARRAY_SIZE(subtable_lookups);
+}
+
+/* sets the priority of the lookup function with "name". */
+int32_t
+dpcls_subtable_set_prio(const char *name, uint8_t priority)
+{
+ for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
+ if (strcmp(name, subtable_lookups[i].name) == 0) {
+ subtable_lookups[i].prio = priority;
+ VLOG_INFO("Subtable function '%s' set priority to %d\n",
+ name, priority);
+ return 0;
+ }
+ }
+ VLOG_WARN("Subtable function '%s' not found, failed to set priority\n",
+ name);
+ return -EINVAL;
+}
+
+dpcls_subtable_lookup_func
+dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count)
+{
+ /* Iter over each subtable impl, and get highest priority one. */
+ int32_t prio = -1;
+ const char *name = NULL;
+ dpcls_subtable_lookup_func best_func = NULL;
+
+ for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
+ int32_t probed_prio = subtable_lookups[i].prio;
+ if (probed_prio > prio) {
+ dpcls_subtable_lookup_func probed_func;
+ probed_func = subtable_lookups[i].probe(u0_bit_count,
+ u1_bit_count);
+ if (probed_func) {
+ best_func = probed_func;
+ prio = probed_prio;
+ name = subtable_lookups[i].name;
+ }
+ }
+ }
+
+ VLOG_DBG("Subtable lookup function '%s' with units (%d,%d), priority %d\n",
+ name, u0_bit_count, u1_bit_count, prio);
+
+ /* Programming error - we must always return a valid func ptr. */
+ ovs_assert(best_func != NULL);
+
+ return best_func;
+}
diff --git a/lib/dpif-netdev-lookup.h b/lib/dpif-netdev-lookup.h
new file mode 100644
index 000000000..61f44b9e8
--- /dev/null
+++ b/lib/dpif-netdev-lookup.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020 Intel Corporation.
+ *
+ * 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 DPIF_NETDEV_LOOKUP_H
+#define DPIF_NETDEV_LOOKUP_H 1
+
+#include <config.h>
+#include "dpif-netdev.h"
+#include "dpif-netdev-private.h"
+
+/* Function to perform a probe for the subtable bit fingerprint.
+ * Returns NULL if not valid, or a valid function pointer to call for this
+ * subtable on success.
+ */
+typedef
+dpcls_subtable_lookup_func (*dpcls_subtable_probe_func)(uint32_t u0_bit_count,
+ uint32_t u1_bit_count);
+
+/* Prototypes for subtable implementations */
+dpcls_subtable_lookup_func
+dpcls_subtable_autovalidator_probe(uint32_t u0_bit_count,
+ uint32_t u1_bit_count);
+
+/* Probe function to select a specialized version of the generic lookup
+ * implementation. This provides performance benefit due to compile-time
+ * optimizations such as loop-unrolling. These are enabled by the compile-time
+ * constants in the specific function implementations.
+ */
+dpcls_subtable_lookup_func
+dpcls_subtable_generic_probe(uint32_t u0_bit_count, uint32_t u1_bit_count);
+
+
+/* Subtable registration and iteration helpers */
+struct dpcls_subtable_lookup_info_t {
+ /* higher priority gets used over lower values. This allows deployments
+ * to select the best implementation for the use-case.
+ */
+ uint8_t prio;
+
+ /* Probe function: tests if the (u0,u1) combo is supported. If not
+ * supported, this function returns NULL. If supported, a function pointer
+ * is returned which when called will perform the lookup on the subtable.
+ */
+ dpcls_subtable_probe_func probe;
+
+ /* Human readable name, used in setting subtable priority commands */
+ const char *name;
+};
+
+int32_t dpcls_subtable_set_prio(const char *name, uint8_t priority);
+
+dpcls_subtable_lookup_func
+dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count);
+
+/* Retrieve the array of lookup implementations for iteration.
+ * On error, returns a negative number.
+ * On success, returns the size of the arrays pointed to by the out parameter.
+ */
+int32_t
+dpcls_subtable_lookup_info_get(struct dpcls_subtable_lookup_info_t **out_ptr);
+
+#endif /* dpif-netdev-lookup.h */
diff --git a/lib/dpif-netdev-private.h b/lib/dpif-netdev-private.h
index 68c33a0f9..bdc150d45 100644
--- a/lib/dpif-netdev-private.h
+++ b/lib/dpif-netdev-private.h
@@ -60,21 +60,6 @@ uint32_t (*dpcls_subtable_lookup_func)(struct dpcls_subtable *subtable,
const struct netdev_flow_key *keys[],
struct dpcls_rule **rules);
-/* Prototype for generic lookup func, using generic scalar code path. */
-uint32_t
-dpcls_subtable_lookup_generic(struct dpcls_subtable *subtable,
- uint32_t keys_map,
- const struct netdev_flow_key *keys[],
- struct dpcls_rule **rules);
-
-/* Probe function to select a specialized version of the generic lookup
- * implementation. This provides performance benefit due to compile-time
- * optimizations such as loop-unrolling. These are enabled by the compile-time
- * constants in the specific function implementations.
- */
-dpcls_subtable_lookup_func
-dpcls_subtable_generic_probe(uint32_t u0_bit_count, uint32_t u1_bit_count);
-
/* A set of rules that all have the same fields wildcarded. */
struct dpcls_subtable {
/* The fields are only used by writers. */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 629a0cb53..e023ece6f 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -42,6 +42,7 @@
#include "csum.h"
#include "dp-packet.h"
#include "dpif.h"
+#include "dpif-netdev-lookup.h"
#include "dpif-netdev-perf.h"
#include "dpif-provider.h"
#include "dummy.h"
@@ -8428,13 +8429,11 @@ dpcls_create_subtable(struct dpcls *cls, const struct netdev_flow_key *mask)
subtable->mf_masks = xmalloc(sizeof(uint64_t) * (unit0 + unit1));
netdev_flow_key_gen_masks(mask, subtable->mf_masks, unit0, unit1);
- /* Probe for a specialized generic lookup function. */
- subtable->lookup_func = dpcls_subtable_generic_probe(unit0, unit1);
-
- /* If not set, assign generic lookup. Generic works for any miniflow. */
- if (!subtable->lookup_func) {
- subtable->lookup_func = dpcls_subtable_lookup_generic;
- }
+ /* Get the preferred subtable search function for this (u0,u1) subtable.
+ * The function is guaranteed to always return a valid implementation, and
+ * possibly an ISA optimized, and/or specialized implementation.
+ */
+ subtable->lookup_func = dpcls_subtable_get_best_impl(unit0, unit1);
cmap_insert(&cls->subtables_map, &subtable->cmap_node, mask->hash);
/* Add the new subtable at the end of the pvector (with no hits yet) */