/src/openvswitch/lib/dpif-netdev-lookup-autovalidator.c
Line | Count | Source (jump to first uncovered line) |
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 "openvswitch/vlog.h" |
21 | | |
22 | | VLOG_DEFINE_THIS_MODULE(dpif_lookup_autovalidator); |
23 | | |
24 | | /* This file implements an automated validator for subtable search |
25 | | * implementations. It compares the results of the generic scalar search result |
26 | | * with ISA optimized implementations. |
27 | | * |
28 | | * Note the goal is *NOT* to test the *specialized* versions of subtables, as |
29 | | * the compiler performs the specialization - and we rely on the correctness of |
30 | | * the compiler to not break those specialized variants. |
31 | | * |
32 | | * The goal is to ensure identical results of the different implementations, |
33 | | * despite that the implementations may have different methods to get those |
34 | | * results. |
35 | | * |
36 | | * Example: AVX-512 ISA uses different instructions and algorithm to the scalar |
37 | | * implementation, however the results (rules[] output) must be the same. |
38 | | */ |
39 | | |
40 | | dpcls_subtable_lookup_func |
41 | | dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED, |
42 | | uint32_t u1 OVS_UNUSED); |
43 | | |
44 | | static uint32_t |
45 | | dpcls_subtable_autovalidator(struct dpcls_subtable *subtable, |
46 | | uint32_t keys_map, |
47 | | const struct netdev_flow_key *keys[], |
48 | | struct dpcls_rule **rules_good) |
49 | 0 | { |
50 | 0 | const uint32_t u0_bit_count = subtable->mf_bits_set_unit0; |
51 | 0 | const uint32_t u1_bit_count = subtable->mf_bits_set_unit1; |
52 | | |
53 | | /* Scalar generic - the "known correct" version. */ |
54 | 0 | dpcls_subtable_lookup_func lookup_good; |
55 | 0 | lookup_good = dpcls_subtable_generic_probe(u0_bit_count, u1_bit_count); |
56 | | |
57 | | /* Run actual scalar implementation to get known good results. */ |
58 | 0 | uint32_t matches_good = lookup_good(subtable, keys_map, keys, rules_good); |
59 | |
|
60 | 0 | struct dpcls_subtable_lookup_info_t *lookup_funcs; |
61 | 0 | int32_t lookup_func_count = dpcls_subtable_lookup_info_get(&lookup_funcs); |
62 | 0 | if (lookup_func_count < 0) { |
63 | 0 | VLOG_ERR("failed to get lookup subtable function implementations\n"); |
64 | 0 | return 0; |
65 | 0 | } |
66 | | |
67 | | /* Ensure the autovalidator is the 0th item in the lookup_funcs array. */ |
68 | 0 | ovs_assert(lookup_funcs[0].probe(0, 0) == dpcls_subtable_autovalidator); |
69 | | |
70 | | /* Now compare all other implementations against known good results. |
71 | | * Note we start iterating from array[1], as 0 is the autotester itself. |
72 | | */ |
73 | 0 | for (int i = 1; i < lookup_func_count; i++) { |
74 | 0 | dpcls_subtable_lookup_func lookup_func; |
75 | 0 | lookup_func = lookup_funcs[i].probe(u0_bit_count, |
76 | 0 | u1_bit_count); |
77 | | |
78 | | /* If its probe returns a function, then test it. */ |
79 | 0 | if (lookup_func) { |
80 | 0 | struct dpcls_rule *rules_test[NETDEV_MAX_BURST]; |
81 | 0 | size_t rules_size = sizeof(struct dpcls_rule *) * NETDEV_MAX_BURST; |
82 | 0 | memset(rules_test, 0, rules_size); |
83 | 0 | uint32_t matches_test = lookup_func(subtable, keys_map, keys, |
84 | 0 | rules_test); |
85 | | |
86 | | /* Ensure same packets matched against subtable. */ |
87 | 0 | if (matches_good != matches_test) { |
88 | 0 | VLOG_ERR("matches_good 0x%x != matches_test 0x%x in func %s\n", |
89 | 0 | matches_good, matches_test, lookup_funcs[i].name); |
90 | 0 | } |
91 | | |
92 | | /* Ensure rules matched are the same for scalar / others. */ |
93 | 0 | int j; |
94 | 0 | ULLONG_FOR_EACH_1 (j, matches_test) { |
95 | 0 | ovs_assert(rules_good[j] == rules_test[j]); |
96 | 0 | } |
97 | 0 | } |
98 | 0 | } |
99 | |
|
100 | 0 | return matches_good; |
101 | 0 | } |
102 | | |
103 | | dpcls_subtable_lookup_func |
104 | | dpcls_subtable_autovalidator_probe(uint32_t u0 OVS_UNUSED, |
105 | | uint32_t u1 OVS_UNUSED) |
106 | 0 | { |
107 | | /* Always return the same validator tester, it works for all subtables. */ |
108 | 0 | return dpcls_subtable_autovalidator; |
109 | 0 | } |