/* * 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 #include "dpif-netdev.h" #include "dpif-netdev-lookup.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; }