]> git.proxmox.com Git - ovs.git/blame - lib/dpdk.c
ovsdb: Prevent OVSDB server from replicating itself.
[ovs.git] / lib / dpdk.c
CommitLineData
01961bbd
DDP
1/*
2 * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
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 "dpdk.h"
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <getopt.h>
23
24#include <rte_memzone.h>
a0cbc627
CL
25#ifdef DPDK_PDUMP
26#include <rte_mempool.h>
27#include <rte_pdump.h>
28#endif
01961bbd
DDP
29
30#include "dirs.h"
a0cbc627 31#include "fatal-signal.h"
01961bbd
DDP
32#include "netdev-dpdk.h"
33#include "openvswitch/dynamic-string.h"
34#include "openvswitch/vlog.h"
35#include "smap.h"
36
37VLOG_DEFINE_THIS_MODULE(dpdk);
38
39static char *vhost_sock_dir = NULL; /* Location of vhost-user sockets */
40
41static int
6c4f08e2 42process_vhost_flags(char *flag, const char *default_val, int size,
01961bbd
DDP
43 const struct smap *ovs_other_config,
44 char **new_val)
45{
46 const char *val;
47 int changed = 0;
48
49 val = smap_get(ovs_other_config, flag);
50
51 /* Process the vhost-sock-dir flag if it is provided, otherwise resort to
52 * default value.
53 */
54 if (val && (strlen(val) <= size)) {
55 changed = 1;
56 *new_val = xstrdup(val);
57 VLOG_INFO("User-provided %s in use: %s", flag, *new_val);
58 } else {
59 VLOG_INFO("No %s provided - defaulting to %s", flag, default_val);
6c4f08e2 60 *new_val = xstrdup(default_val);
01961bbd
DDP
61 }
62
63 return changed;
64}
65
66static char **
67grow_argv(char ***argv, size_t cur_siz, size_t grow_by)
68{
69 return xrealloc(*argv, sizeof(char *) * (cur_siz + grow_by));
70}
71
72static void
73dpdk_option_extend(char ***argv, int argc, const char *option,
74 const char *value)
75{
76 char **newargv = grow_argv(argv, argc, 2);
77 *argv = newargv;
78 newargv[argc] = xstrdup(option);
79 newargv[argc+1] = xstrdup(value);
80}
81
82static char **
83move_argv(char ***argv, size_t cur_size, char **src_argv, size_t src_argc)
84{
85 char **newargv = grow_argv(argv, cur_size, src_argc);
86 while (src_argc--) {
87 newargv[cur_size+src_argc] = src_argv[src_argc];
88 src_argv[src_argc] = NULL;
89 }
90 return newargv;
91}
92
93static int
94extra_dpdk_args(const char *ovs_extra_config, char ***argv, int argc)
95{
96 int ret = argc;
97 char *release_tok = xstrdup(ovs_extra_config);
98 char *tok, *endptr = NULL;
99
100 for (tok = strtok_r(release_tok, " ", &endptr); tok != NULL;
101 tok = strtok_r(NULL, " ", &endptr)) {
102 char **newarg = grow_argv(argv, ret, 1);
103 *argv = newarg;
104 newarg[ret++] = xstrdup(tok);
105 }
106 free(release_tok);
107 return ret;
108}
109
110static bool
111argv_contains(char **argv_haystack, const size_t argc_haystack,
112 const char *needle)
113{
114 for (size_t i = 0; i < argc_haystack; ++i) {
115 if (!strcmp(argv_haystack[i], needle))
116 return true;
117 }
118 return false;
119}
120
121static int
122construct_dpdk_options(const struct smap *ovs_other_config,
123 char ***argv, const int initial_size,
124 char **extra_args, const size_t extra_argc)
125{
126 struct dpdk_options_map {
127 const char *ovs_configuration;
128 const char *dpdk_option;
129 bool default_enabled;
130 const char *default_value;
131 } opts[] = {
132 {"dpdk-lcore-mask", "-c", false, NULL},
133 {"dpdk-hugepage-dir", "--huge-dir", false, NULL},
134 };
135
136 int i, ret = initial_size;
137
138 /*First, construct from the flat-options (non-mutex)*/
139 for (i = 0; i < ARRAY_SIZE(opts); ++i) {
140 const char *lookup = smap_get(ovs_other_config,
141 opts[i].ovs_configuration);
142 if (!lookup && opts[i].default_enabled) {
143 lookup = opts[i].default_value;
144 }
145
146 if (lookup) {
147 if (!argv_contains(extra_args, extra_argc, opts[i].dpdk_option)) {
148 dpdk_option_extend(argv, ret, opts[i].dpdk_option, lookup);
149 ret += 2;
150 } else {
151 VLOG_WARN("Ignoring database defined option '%s' due to "
152 "dpdk_extras config", opts[i].dpdk_option);
153 }
154 }
155 }
156
157 return ret;
158}
159
160#define MAX_DPDK_EXCL_OPTS 10
161
162static int
163construct_dpdk_mutex_options(const struct smap *ovs_other_config,
164 char ***argv, const int initial_size,
165 char **extra_args, const size_t extra_argc)
166{
167 struct dpdk_exclusive_options_map {
168 const char *category;
169 const char *ovs_dpdk_options[MAX_DPDK_EXCL_OPTS];
170 const char *eal_dpdk_options[MAX_DPDK_EXCL_OPTS];
171 const char *default_value;
172 int default_option;
173 } excl_opts[] = {
174 {"memory type",
175 {"dpdk-alloc-mem", "dpdk-socket-mem", NULL,},
176 {"-m", "--socket-mem", NULL,},
177 "1024,0", 1
178 },
179 };
180
181 int i, ret = initial_size;
182 for (i = 0; i < ARRAY_SIZE(excl_opts); ++i) {
183 int found_opts = 0, scan, found_pos = -1;
184 const char *found_value;
185 struct dpdk_exclusive_options_map *popt = &excl_opts[i];
186
187 for (scan = 0; scan < MAX_DPDK_EXCL_OPTS
188 && popt->ovs_dpdk_options[scan]; ++scan) {
189 const char *lookup = smap_get(ovs_other_config,
190 popt->ovs_dpdk_options[scan]);
191 if (lookup && strlen(lookup)) {
192 found_opts++;
193 found_pos = scan;
194 found_value = lookup;
195 }
196 }
197
198 if (!found_opts) {
199 if (popt->default_option) {
200 found_pos = popt->default_option;
201 found_value = popt->default_value;
202 } else {
203 continue;
204 }
205 }
206
207 if (found_opts > 1) {
208 VLOG_ERR("Multiple defined options for %s. Please check your"
209 " database settings and reconfigure if necessary.",
210 popt->category);
211 }
212
213 if (!argv_contains(extra_args, extra_argc,
214 popt->eal_dpdk_options[found_pos])) {
215 dpdk_option_extend(argv, ret, popt->eal_dpdk_options[found_pos],
216 found_value);
217 ret += 2;
218 } else {
219 VLOG_WARN("Ignoring database defined option '%s' due to "
220 "dpdk_extras config", popt->eal_dpdk_options[found_pos]);
221 }
222 }
223
224 return ret;
225}
226
227static int
228get_dpdk_args(const struct smap *ovs_other_config, char ***argv,
229 int argc)
230{
231 const char *extra_configuration;
232 char **extra_args = NULL;
233 int i;
234 size_t extra_argc = 0;
235
236 extra_configuration = smap_get(ovs_other_config, "dpdk-extra");
237 if (extra_configuration) {
238 extra_argc = extra_dpdk_args(extra_configuration, &extra_args, 0);
239 }
240
241 i = construct_dpdk_options(ovs_other_config, argv, argc, extra_args,
242 extra_argc);
243 i = construct_dpdk_mutex_options(ovs_other_config, argv, i, extra_args,
244 extra_argc);
245
246 if (extra_configuration) {
247 *argv = move_argv(argv, i, extra_args, extra_argc);
248 }
249
250 return i + extra_argc;
251}
252
01961bbd 253static void
71e2a07a 254argv_release(char **dpdk_argv, char **dpdk_argv_release, size_t dpdk_argc)
01961bbd
DDP
255{
256 int result;
257 for (result = 0; result < dpdk_argc; ++result) {
fe11b9e0 258 free(dpdk_argv_release[result]);
01961bbd
DDP
259 }
260
fe11b9e0 261 free(dpdk_argv_release);
01961bbd
DDP
262 free(dpdk_argv);
263}
264
265static void
266dpdk_init__(const struct smap *ovs_other_config)
267{
71e2a07a 268 char **argv = NULL, **argv_to_release = NULL;
01961bbd
DDP
269 int result;
270 int argc, argc_tmp;
271 bool auto_determine = true;
272 int err = 0;
273 cpu_set_t cpuset;
274 char *sock_dir_subcomponent;
275
6c4f08e2 276 if (process_vhost_flags("vhost-sock-dir", ovs_rundir(),
01961bbd
DDP
277 NAME_MAX, ovs_other_config,
278 &sock_dir_subcomponent)) {
279 struct stat s;
280 if (!strstr(sock_dir_subcomponent, "..")) {
281 vhost_sock_dir = xasprintf("%s/%s", ovs_rundir(),
282 sock_dir_subcomponent);
283
284 err = stat(vhost_sock_dir, &s);
285 if (err) {
286 VLOG_ERR("vhost-user sock directory '%s' does not exist.",
287 vhost_sock_dir);
288 }
289 } else {
290 vhost_sock_dir = xstrdup(ovs_rundir());
291 VLOG_ERR("vhost-user sock directory request '%s/%s' has invalid"
292 "characters '..' - using %s instead.",
293 ovs_rundir(), sock_dir_subcomponent, ovs_rundir());
294 }
295 free(sock_dir_subcomponent);
296 } else {
297 vhost_sock_dir = sock_dir_subcomponent;
298 }
299
300 argv = grow_argv(&argv, 0, 1);
301 argc = 1;
302 argv[0] = xstrdup(ovs_get_program_name());
303 argc_tmp = get_dpdk_args(ovs_other_config, &argv, argc);
304
305 while (argc_tmp != argc) {
306 if (!strcmp("-c", argv[argc]) || !strcmp("-l", argv[argc])) {
307 auto_determine = false;
308 break;
309 }
310 argc++;
311 }
312 argc = argc_tmp;
313
314 /**
315 * NOTE: This is an unsophisticated mechanism for determining the DPDK
316 * lcore for the DPDK Master.
317 */
318 if (auto_determine) {
319 int i;
320 /* Get the main thread affinity */
321 CPU_ZERO(&cpuset);
322 err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t),
323 &cpuset);
324 if (!err) {
325 for (i = 0; i < CPU_SETSIZE; i++) {
326 if (CPU_ISSET(i, &cpuset)) {
327 argv = grow_argv(&argv, argc, 2);
328 argv[argc++] = xstrdup("-c");
329 argv[argc++] = xasprintf("0x%08llX", (1ULL<<i));
330 i = CPU_SETSIZE;
331 }
332 }
333 } else {
334 VLOG_ERR("Thread getaffinity error %d. Using core 0x1", err);
335 /* User did not set dpdk-lcore-mask and unable to get current
336 * thread affintity - default to core 0x1 */
337 argv = grow_argv(&argv, argc, 2);
338 argv[argc++] = xstrdup("-c");
339 argv[argc++] = xasprintf("0x%X", 1);
340 }
341 }
342
343 argv = grow_argv(&argv, argc, 1);
344 argv[argc] = NULL;
345
346 optind = 1;
347
348 if (VLOG_IS_INFO_ENABLED()) {
349 struct ds eal_args;
350 int opt;
351 ds_init(&eal_args);
352 ds_put_cstr(&eal_args, "EAL ARGS:");
353 for (opt = 0; opt < argc; ++opt) {
354 ds_put_cstr(&eal_args, " ");
355 ds_put_cstr(&eal_args, argv[opt]);
356 }
357 VLOG_INFO("%s", ds_cstr_ro(&eal_args));
358 ds_destroy(&eal_args);
359 }
360
71e2a07a 361 argv_to_release = grow_argv(&argv_to_release, 0, argc);
fe11b9e0 362 for (argc_tmp = 0; argc_tmp < argc; ++argc_tmp) {
71e2a07a 363 argv_to_release[argc_tmp] = argv[argc_tmp];
fe11b9e0
AC
364 }
365
01961bbd
DDP
366 /* Make sure things are initialized ... */
367 result = rte_eal_init(argc, argv);
368 if (result < 0) {
369 ovs_abort(result, "Cannot init EAL");
370 }
71e2a07a 371 argv_release(argv, argv_to_release, argc);
01961bbd
DDP
372
373 /* Set the main thread affinity back to pre rte_eal_init() value */
374 if (auto_determine && !err) {
375 err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t),
376 &cpuset);
377 if (err) {
378 VLOG_ERR("Thread setaffinity error %d", err);
379 }
380 }
381
01961bbd
DDP
382 rte_memzone_dump(stdout);
383
384 /* We are called from the main thread here */
385 RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;
386
387#ifdef DPDK_PDUMP
388 VLOG_INFO("DPDK pdump packet capture enabled");
389 err = rte_pdump_init(ovs_rundir());
390 if (err) {
391 VLOG_INFO("Error initialising DPDK pdump");
392 rte_pdump_uninit();
393 } else {
394 char *server_socket_path;
395
396 server_socket_path = xasprintf("%s/%s", ovs_rundir(),
397 "pdump_server_socket");
398 fatal_signal_add_file_to_unlink(server_socket_path);
399 free(server_socket_path);
400 }
401#endif
402
403 /* Finally, register the dpdk classes */
404 netdev_dpdk_register();
405}
406
407void
408dpdk_init(const struct smap *ovs_other_config)
409{
ec2b0701
DDP
410 static bool enabled = false;
411
412 if (enabled || !ovs_other_config) {
413 return;
414 }
415
416 if (smap_get_bool(ovs_other_config, "dpdk-init", false)) {
417 static struct ovsthread_once once_enable = OVSTHREAD_ONCE_INITIALIZER;
01961bbd 418
ec2b0701
DDP
419 if (ovsthread_once_start(&once_enable)) {
420 VLOG_INFO("DPDK Enabled - initializing...");
421 dpdk_init__(ovs_other_config);
422 enabled = true;
423 VLOG_INFO("DPDK Enabled - initialized");
424 ovsthread_once_done(&once_enable);
425 }
426 } else {
427 static struct ovsthread_once once_disable = OVSTHREAD_ONCE_INITIALIZER;
428 if (ovsthread_once_start(&once_disable)) {
429 VLOG_INFO("DPDK Disabled - Use other_config:dpdk-init to enable");
430 ovsthread_once_done(&once_disable);
431 }
01961bbd
DDP
432 }
433}
434
435const char *
436dpdk_get_vhost_sock_dir(void)
437{
438 return vhost_sock_dir;
439}
440
441void
442dpdk_set_lcore_id(unsigned cpu)
443{
444 /* NON_PMD_CORE_ID is reserved for use by non pmd threads. */
445 ovs_assert(cpu != NON_PMD_CORE_ID);
446 RTE_PER_LCORE(_lcore_id) = cpu;
447}