Coverage Report

Created: 2025-08-26 06:20

/src/openvswitch/lib/dpif-netdev-private-dpif.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021 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
19
#include "dpif-netdev-private-dpif.h"
20
#include "dpif-netdev-private-thread.h"
21
22
#include <errno.h>
23
#include <string.h>
24
25
#include "cpu.h"
26
#include "openvswitch/dynamic-string.h"
27
#include "openvswitch/vlog.h"
28
#include "util.h"
29
30
VLOG_DEFINE_THIS_MODULE(dpif_netdev_impl);
31
#define DPIF_NETDEV_IMPL_AVX512_CHECK (__x86_64__ && HAVE_AVX512F \
32
    && HAVE_LD_AVX512_GOOD && __SSE4_2__)
33
34
enum dpif_netdev_impl_info_idx {
35
    DPIF_NETDEV_IMPL_SCALAR,
36
    DPIF_NETDEV_IMPL_AVX512
37
};
38
39
#if DPIF_NETDEV_IMPL_AVX512_CHECK
40
static int32_t
41
dp_netdev_input_outer_avx512_probe(void)
42
{
43
    if (!cpu_has_isa(OVS_CPU_ISA_X86_AVX512F)
44
        || !cpu_has_isa(OVS_CPU_ISA_X86_BMI2)) {
45
        return -ENOTSUP;
46
    }
47
48
    return 0;
49
}
50
#endif
51
52
/* Actual list of implementations goes here. */
53
static struct dpif_netdev_impl_info_t dpif_impls[] = {
54
    /* The default scalar C code implementation. */
55
    [DPIF_NETDEV_IMPL_SCALAR] = { .input_func = dp_netdev_input,
56
      .probe = NULL,
57
      .name = "dpif_scalar", },
58
59
#if DPIF_NETDEV_IMPL_AVX512_CHECK
60
    /* Only available on x86_64 bit builds with SSE 4.2 used for OVS core. */
61
    [DPIF_NETDEV_IMPL_AVX512] = { .input_func = dp_netdev_input_outer_avx512,
62
      .probe = dp_netdev_input_outer_avx512_probe,
63
      .name = "dpif_avx512", },
64
#endif
65
};
66
67
static dp_netdev_input_func default_dpif_func;
68
69
dp_netdev_input_func
70
dp_netdev_impl_get_default(void)
71
0
{
72
    /* For the first call, this will be NULL. Compute the compile time default.
73
     */
74
0
    if (!default_dpif_func) {
75
0
        int dpif_idx = DPIF_NETDEV_IMPL_SCALAR;
76
77
/* Configure-time overriding to run test suite on all implementations. */
78
#if DPIF_NETDEV_IMPL_AVX512_CHECK
79
#ifdef DPIF_AVX512_DEFAULT
80
        dp_netdev_input_func_probe probe;
81
82
        /* Check if the compiled default is compatible. */
83
        probe = dpif_impls[DPIF_NETDEV_IMPL_AVX512].probe;
84
        if (!probe || !probe()) {
85
            dpif_idx = DPIF_NETDEV_IMPL_AVX512;
86
        }
87
#endif
88
#endif
89
90
0
        VLOG_INFO("Default DPIF implementation is %s.\n",
91
0
                  dpif_impls[dpif_idx].name);
92
0
        default_dpif_func = dpif_impls[dpif_idx].input_func;
93
0
    }
94
95
0
    return default_dpif_func;
96
0
}
97
98
void
99
dp_netdev_impl_get(struct ds *reply, struct dp_netdev_pmd_thread **pmd_list,
100
                   size_t n)
101
0
{
102
    /* Add all dpif functions to reply string. */
103
0
    ds_put_cstr(reply, "Available DPIF implementations:\n");
104
105
0
    for (uint32_t i = 0; i < ARRAY_SIZE(dpif_impls); i++) {
106
0
        ds_put_format(reply, "  %s (pmds: ", dpif_impls[i].name);
107
108
0
        for (size_t j = 0; j < n; j++) {
109
0
            struct dp_netdev_pmd_thread *pmd = pmd_list[j];
110
0
            if (pmd->core_id == NON_PMD_CORE_ID) {
111
0
                continue;
112
0
            }
113
114
0
            if (pmd->netdev_input_func == dpif_impls[i].input_func) {
115
0
                ds_put_format(reply, "%u,", pmd->core_id);
116
0
            }
117
0
        }
118
119
0
        ds_chomp(reply, ',');
120
121
0
        if (ds_last(reply) == ' ') {
122
0
            ds_put_cstr(reply, "none");
123
0
        }
124
125
0
        ds_put_cstr(reply, ")\n");
126
0
    }
127
0
}
128
129
/* This function checks all available DPIF implementations, and selects the
130
 * returns the function pointer to the one requested by "name".
131
 */
132
static int32_t
133
dp_netdev_impl_get_by_name(const char *name, dp_netdev_input_func *out_func)
134
0
{
135
0
    ovs_assert(name);
136
0
    ovs_assert(out_func);
137
138
0
    uint32_t i;
139
140
0
    for (i = 0; i < ARRAY_SIZE(dpif_impls); i++) {
141
0
        if (strcmp(dpif_impls[i].name, name) == 0) {
142
            /* Probe function is optional - so check it is set before exec. */
143
0
            if (dpif_impls[i].probe) {
144
0
                int probe_err = dpif_impls[i].probe();
145
0
                if (probe_err) {
146
0
                    *out_func = NULL;
147
0
                    return probe_err;
148
0
                }
149
0
            }
150
0
            *out_func = dpif_impls[i].input_func;
151
0
            return 0;
152
0
        }
153
0
    }
154
155
0
    return -EINVAL;
156
0
}
157
158
int32_t
159
dp_netdev_impl_set_default_by_name(const char *name)
160
0
{
161
0
    dp_netdev_input_func new_default;
162
163
0
    int32_t err = dp_netdev_impl_get_by_name(name, &new_default);
164
165
0
    if (!err) {
166
0
        default_dpif_func = new_default;
167
0
    }
168
169
0
    return err;
170
171
0
}