]>
Commit | Line | Data |
---|---|---|
e90e115a HH |
1 | /* |
2 | * Copyright (c) 2020 Intel Corporation. | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "dpif-netdev.h" | |
19 | #include "dpif-netdev-lookup.h" | |
20 | #include "dpif-netdev-private.h" | |
21 | #include "openvswitch/vlog.h" | |
22 | ||
23 | VLOG_DEFINE_THIS_MODULE(dpif_lookup_autovalidator); | |
24 | ||
25 | /* This file implements an automated validator for subtable search | |
26 | * implementations. It compares the results of the generic scalar search result | |
27 | * with ISA optimized implementations. | |
28 | * | |
29 | * Note the goal is *NOT* to test the *specialized* versions of subtables, as | |
30 | * the compiler performs the specialization - and we rely on the correctness of | |
31 | * the compiler to not break those specialized variants. | |
32 | * | |
33 | * The goal is to ensure identical results of the different implementations, | |
34 | * despite that the implementations may have different methods to get those | |
35 | * results. | |
36 | * | |
37 | * Example: AVX-512 ISA uses different instructions and algorithm to the scalar | |
38 | * implementation, however the results (rules[] output) must be the same. | |
39 | */ | |
40 | ||
41 | dpcls_subtable_lookup_func | |
42 | dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED, | |
43 | uint32_t u1 OVS_UNUSED); | |
44 | ||
45 | static uint32_t | |
46 | dpcls_subtable_autovalidator(struct dpcls_subtable *subtable, | |
47 | uint32_t keys_map, | |
48 | const struct netdev_flow_key *keys[], | |
49 | struct dpcls_rule **rules_good) | |
50 | { | |
51 | const uint32_t u0_bit_count = subtable->mf_bits_set_unit0; | |
52 | const uint32_t u1_bit_count = subtable->mf_bits_set_unit1; | |
53 | ||
54 | /* Scalar generic - the "known correct" version. */ | |
55 | dpcls_subtable_lookup_func lookup_good; | |
56 | lookup_good = dpcls_subtable_generic_probe(u0_bit_count, u1_bit_count); | |
57 | ||
58 | /* Run actual scalar implementation to get known good results. */ | |
59 | uint32_t matches_good = lookup_good(subtable, keys_map, keys, rules_good); | |
60 | ||
61 | struct dpcls_subtable_lookup_info_t *lookup_funcs; | |
62 | int32_t lookup_func_count = dpcls_subtable_lookup_info_get(&lookup_funcs); | |
63 | if (lookup_func_count < 0) { | |
64 | VLOG_ERR("failed to get lookup subtable function implementations\n"); | |
65 | return 0; | |
66 | } | |
67 | ||
68 | /* Ensure the autovalidator is the 0th item in the lookup_funcs array. */ | |
69 | ovs_assert(lookup_funcs[0].probe(0, 0) == dpcls_subtable_autovalidator); | |
70 | ||
71 | /* Now compare all other implementations against known good results. | |
72 | * Note we start iterating from array[1], as 0 is the autotester itself. | |
73 | */ | |
74 | for (int i = 1; i < lookup_func_count; i++) { | |
75 | dpcls_subtable_lookup_func lookup_func; | |
76 | lookup_func = lookup_funcs[i].probe(u0_bit_count, | |
77 | u1_bit_count); | |
78 | ||
79 | /* If its probe returns a function, then test it. */ | |
80 | if (lookup_func) { | |
81 | struct dpcls_rule *rules_test[NETDEV_MAX_BURST]; | |
82 | size_t rules_size = sizeof(struct dpcls_rule *) * NETDEV_MAX_BURST; | |
83 | memset(rules_test, 0, rules_size); | |
84 | uint32_t matches_test = lookup_func(subtable, keys_map, keys, | |
85 | rules_test); | |
86 | ||
87 | /* Ensure same packets matched against subtable. */ | |
88 | if (matches_good != matches_test) { | |
89 | VLOG_ERR("matches_good 0x%x != matches_test 0x%x in func %s\n", | |
90 | matches_good, matches_test, lookup_funcs[i].name); | |
91 | } | |
92 | ||
93 | /* Ensure rules matched are the same for scalar / others. */ | |
94 | int j; | |
95 | ULLONG_FOR_EACH_1 (j, matches_test) { | |
96 | ovs_assert(rules_good[j] == rules_test[j]); | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | return matches_good; | |
102 | } | |
103 | ||
104 | dpcls_subtable_lookup_func | |
105 | dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED, | |
106 | uint32_t u1 OVS_UNUSED) | |
107 | { | |
108 | /* Always return the same validator tester, it works for all subtables. */ | |
109 | return dpcls_subtable_autovalidator; | |
110 | } |