Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation.
3 : : * Copyright(c) 2014 6WIND S.A.
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <pthread.h>
9 : : #include <ctype.h>
10 : : #include <limits.h>
11 : : #include <errno.h>
12 : : #include <getopt.h>
13 : : #include <sys/queue.h>
14 : : #ifndef RTE_EXEC_ENV_WINDOWS
15 : : #include <dlfcn.h>
16 : : #include <libgen.h>
17 : : #endif
18 : : #include <sys/stat.h>
19 : : #ifndef RTE_EXEC_ENV_WINDOWS
20 : : #include <dirent.h>
21 : : #endif
22 : :
23 : : #include <rte_string_fns.h>
24 : : #include <rte_eal.h>
25 : : #include <rte_log.h>
26 : : #include <rte_lcore.h>
27 : : #include <rte_memory.h>
28 : : #include <rte_tailq.h>
29 : : #include <rte_version.h>
30 : : #include <rte_devargs.h>
31 : : #include <rte_memcpy.h>
32 : : #ifndef RTE_EXEC_ENV_WINDOWS
33 : : #include <rte_telemetry.h>
34 : : #endif
35 : : #include <rte_vect.h>
36 : :
37 : : #include <rte_argparse.h>
38 : : #include <eal_export.h>
39 : : #include "eal_internal_cfg.h"
40 : : #include "eal_options.h"
41 : : #include "eal_filesystem.h"
42 : : #include "eal_private.h"
43 : : #include "log_internal.h"
44 : : #ifndef RTE_EXEC_ENV_WINDOWS
45 : : #include "eal_trace.h"
46 : : #endif
47 : :
48 : : #define BITS_PER_HEX 4
49 : : #define NUMA_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10)
50 : :
51 : : /* Allow the application to print its usage message too if set */
52 : : static rte_usage_hook_t rte_application_usage_hook;
53 : :
54 : : struct arg_list_elem {
55 : : TAILQ_ENTRY(arg_list_elem) next;
56 : : char *arg;
57 : : };
58 : : TAILQ_HEAD(arg_list, arg_list_elem);
59 : :
60 : : struct eal_init_args {
61 : : /* define a struct member for each EAL option, member name is the same as option name.
62 : : * Parameters that take an argument e.g. -l, are char *,
63 : : * parameters that take no options e.g. --no-huge, are bool.
64 : : * parameters that can be given multiple times e.g. -a, are arg_lists,
65 : : * parameters that are optional e.g. --huge-unlink,
66 : : * are char * but are set to (void *)1 if the parameter is not given.
67 : : * for aliases, i.e. options under different names, no field needs to be output
68 : : */
69 : : #define LIST_ARG(long, short, help_str, fieldname) struct arg_list fieldname;
70 : : #define STR_ARG(long, short, help_str, fieldname) char *fieldname;
71 : : #define OPT_STR_ARG(long, short, help_str, fieldname) char *fieldname;
72 : : #define BOOL_ARG(long, short, help_str, fieldname) bool fieldname;
73 : : #define STR_ALIAS(long, short, help_str, fieldname)
74 : :
75 : : #define INCLUDE_ALL_ARG 1 /* for struct definition, include even unsupported values */
76 : : #include "eal_option_list.h"
77 : : };
78 : :
79 : : /* define the structure itself, with initializers. Only the LIST_ARGS need init */
80 : : #define LIST_ARG(long, short, help_str, fieldname) \
81 : : .fieldname = TAILQ_HEAD_INITIALIZER(args.fieldname),
82 : : #define STR_ARG(long, short, help_str, fieldname)
83 : : #define OPT_STR_ARG(long, short, help_str, fieldname)
84 : : #define BOOL_ARG(long, short, help_str, fieldname)
85 : : #define STR_ALIAS(long, short, help_str, fieldname)
86 : :
87 : : struct eal_init_args args = {
88 : : #include "eal_option_list.h"
89 : : };
90 : : #undef INCLUDE_ALL_ARG
91 : :
92 : : /* an rte_argparse callback to append the argument to an arg_list
93 : : * in args. The index is the offset into the struct of the list.
94 : : */
95 : : static int
96 : 32 : arg_list_callback(uint32_t index, const char *arg, void *init_args)
97 : : {
98 : 32 : struct arg_list *list = RTE_PTR_ADD(init_args, index);
99 : : struct arg_list_elem *elem;
100 : :
101 : 32 : elem = malloc(sizeof(*elem));
102 [ + - ]: 32 : if (elem == NULL)
103 : : return -1;
104 : :
105 : 32 : elem->arg = strdup(arg);
106 [ - + ]: 32 : if (elem->arg == NULL) {
107 : 0 : free(elem);
108 : 0 : return -1;
109 : : }
110 : :
111 : 32 : TAILQ_INSERT_TAIL(list, elem, next);
112 : 32 : return 0;
113 : : }
114 : :
115 : : static void
116 : 0 : eal_usage(const struct rte_argparse *obj)
117 : : {
118 : 0 : rte_argparse_print_help(stdout, obj);
119 [ # # ]: 0 : if (rte_application_usage_hook != NULL)
120 : 0 : rte_application_usage_hook(obj->prog_name);
121 : 0 : }
122 : :
123 : : /* For arguments which have an arg_list type, they use callback (no val_saver),
124 : : * require a value, and have the SUPPORT_MULTI flag.
125 : : */
126 : : #define LIST_ARG(long, short, help_str, fieldname) { \
127 : : .name_long = long, \
128 : : .name_short = short, \
129 : : .help = help_str, \
130 : : .val_set = (void *)offsetof(struct eal_init_args, fieldname), \
131 : : .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
132 : : .flags = RTE_ARGPARSE_FLAG_SUPPORT_MULTI, \
133 : : },
134 : : /* For arguments which have a string type, they use val_saver (no callback),
135 : : * and normally REQUIRED_VALUE.
136 : : */
137 : : #define STR_ARG(long, short, help_str, fieldname) { \
138 : : .name_long = long, \
139 : : .name_short = short, \
140 : : .help = help_str, \
141 : : .val_saver = &args.fieldname, \
142 : : .value_required = RTE_ARGPARSE_VALUE_REQUIRED, \
143 : : .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
144 : : },
145 : : /* For flags which have optional arguments, they use both val_saver and val_set,
146 : : * but still have a string type.
147 : : */
148 : : #define OPT_STR_ARG(long, short, help_str, fieldname) { \
149 : : .name_long = long, \
150 : : .name_short = short, \
151 : : .help = help_str, \
152 : : .val_saver = &args.fieldname, \
153 : : .val_set = (void *)1, \
154 : : .value_required = RTE_ARGPARSE_VALUE_OPTIONAL, \
155 : : .value_type = RTE_ARGPARSE_VALUE_TYPE_STR, \
156 : : },
157 : : /* For boolean arguments, they use val_saver and val_set, with NO_VALUE flag.
158 : : */
159 : : #define BOOL_ARG(long, short, help_str, fieldname) { \
160 : : .name_long = long, \
161 : : .name_short = short, \
162 : : .help = help_str, \
163 : : .val_saver = &args.fieldname, \
164 : : .val_set = (void *)1, \
165 : : .value_required = RTE_ARGPARSE_VALUE_NONE, \
166 : : .value_type = RTE_ARGPARSE_VALUE_TYPE_BOOL, \
167 : : },
168 : : #define STR_ALIAS STR_ARG
169 : :
170 : : #if RTE_VER_RELEASE == 99
171 : : #define GUIDES_PATH "https://doc.dpdk.org/guides-" RTE_STR(RTE_VER_YEAR) "." RTE_STR(RTE_VER_MONTH)
172 : : #else
173 : : #define GUIDES_PATH "https://doc.dpdk.org/guides"
174 : : #endif
175 : :
176 : : struct rte_argparse eal_argparse = {
177 : : .prog_name = "",
178 : : .usage = "<DPDK EAL options> -- <App options>",
179 : : .epilog = "For more information on EAL options, see the DPDK documentation at:\n"
180 : : "\t" GUIDES_PATH "/" RTE_EXEC_ENV_NAME "_gsg/",
181 : : .exit_on_error = true,
182 : : .ignore_non_flag_args = true,
183 : : .callback = arg_list_callback,
184 : : .print_help = eal_usage,
185 : : .opaque = &args,
186 : : .args = {
187 : : #include "eal_option_list.h"
188 : : ARGPARSE_ARG_END(),
189 : : }
190 : : };
191 : :
192 : : static inline bool
193 : 3399 : conflicting_options(uintptr_t opt1, uintptr_t opt2, const char *opt1_name, const char *opt2_name)
194 : : {
195 : : char name1[64]; /* should be the max length of any argument */
196 : : char name2[64];
197 : :
198 : : strlcpy(name1, opt1_name, sizeof(name1));
199 : : strlcpy(name2, opt2_name, sizeof(name2));
200 [ + + ]: 37650 : for (int i = 0; name1[i] != '\0'; i++)
201 [ + + ]: 34251 : if (name1[i] == '_')
202 : 3394 : name1[i] = '-';
203 [ + + ]: 44622 : for (int i = 0; name2[i] != '\0'; i++)
204 [ + + ]: 41223 : if (name2[i] == '_')
205 : 3391 : name2[i] = '-';
206 [ + + ]: 3399 : if (opt1 && opt2) {
207 : 5 : EAL_LOG(ERR, "Options '%s' and '%s' can't be used at the same time", name1, name2);
208 : 5 : return true;
209 : : }
210 : : return false; /* no conflicts */
211 : : }
212 : : #define CONFLICTING_OPTIONS(args, opt1, opt2) \
213 : : conflicting_options((uintptr_t)(args.opt1), (uintptr_t)(args.opt2), #opt1, #opt2)
214 : :
215 : : /* function to call into argparse library to parse the passed argc/argv parameters
216 : : * to the eal_init_args structure.
217 : : */
218 : : int
219 : 253 : eal_collate_args(int argc, char **argv)
220 : : {
221 [ + - + - ]: 253 : if (argc < 1 || argv == NULL || argv[0] == NULL)
222 : : return -EINVAL;
223 : :
224 : : /* parse the arguments */
225 : 253 : eal_argparse.prog_name = argv[0];
226 : 253 : int retval = rte_argparse_parse(&eal_argparse, argc, argv);
227 [ + - ]: 246 : if (retval < 0)
228 : : return retval;
229 : :
230 : : /* check for conflicting options */
231 : : /* both -a and -b cannot be used together (one list must be empty at least) */
232 [ + + - + ]: 246 : if (!TAILQ_EMPTY(&args.allow) && !TAILQ_EMPTY(&args.block)) {
233 : 0 : EAL_LOG(ERR, "Options allow (-a) and block (-b) can't be used at the same time");
234 : 0 : return -1;
235 : : }
236 : :
237 : : /* for non-list args, we can just check for zero/null values using macro */
238 [ + - + - ]: 492 : if (CONFLICTING_OPTIONS(args, coremask, lcores) ||
239 [ + - ]: 492 : CONFLICTING_OPTIONS(args, service_coremask, service_corelist) ||
240 [ + + ]: 492 : CONFLICTING_OPTIONS(args, no_telemetry, telemetry) ||
241 [ + + ]: 490 : CONFLICTING_OPTIONS(args, memory_size, numa_mem) ||
242 [ + + ]: 487 : CONFLICTING_OPTIONS(args, no_huge, numa_mem) ||
243 [ + - ]: 484 : CONFLICTING_OPTIONS(args, no_huge, huge_worker_stack) ||
244 [ + - ]: 482 : CONFLICTING_OPTIONS(args, numa_limit, legacy_mem) ||
245 [ + - ]: 482 : CONFLICTING_OPTIONS(args, legacy_mem, in_memory) ||
246 [ + - ]: 482 : CONFLICTING_OPTIONS(args, legacy_mem, match_allocations) ||
247 [ + - ]: 482 : CONFLICTING_OPTIONS(args, no_huge, match_allocations) ||
248 [ + - ]: 482 : CONFLICTING_OPTIONS(args, no_huge, huge_unlink) ||
249 [ + - ]: 482 : CONFLICTING_OPTIONS(args, single_file_segments, huge_unlink) ||
250 [ - + ]: 482 : CONFLICTING_OPTIONS(args, no_huge, single_file_segments) ||
251 : 241 : CONFLICTING_OPTIONS(args, in_memory, huge_unlink))
252 : 5 : return -1;
253 : :
254 : 241 : argv[retval - 1] = argv[0];
255 : 241 : return retval - 1;
256 : : }
257 : :
258 : : TAILQ_HEAD(shared_driver_list, shared_driver);
259 : :
260 : : /* Definition for shared object drivers. */
261 : : struct shared_driver {
262 : : TAILQ_ENTRY(shared_driver) next;
263 : :
264 : : char name[PATH_MAX];
265 : : void* lib_handle;
266 : : };
267 : :
268 : : /* List of external loadable drivers */
269 : : static struct shared_driver_list solib_list =
270 : : TAILQ_HEAD_INITIALIZER(solib_list);
271 : :
272 : : #ifndef RTE_EXEC_ENV_WINDOWS
273 : : /* Default path of external loadable drivers */
274 : : static const char *default_solib_dir = RTE_EAL_PMD_PATH;
275 : : #endif
276 : :
277 : : /*
278 : : * Stringified version of solib path used by dpdk-pmdinfo.py
279 : : * Note: PLEASE DO NOT ALTER THIS without making a corresponding
280 : : * change to usertools/dpdk-pmdinfo.py
281 : : */
282 : : RTE_PMD_EXPORT_SYMBOL(const char, dpdk_solib_path)[] =
283 : : "DPDK_PLUGIN_PATH=" RTE_EAL_PMD_PATH;
284 : :
285 : : TAILQ_HEAD(device_option_list, device_option);
286 : :
287 : : struct device_option {
288 : : TAILQ_ENTRY(device_option) next;
289 : :
290 : : enum rte_devtype type;
291 : : char arg[];
292 : : };
293 : :
294 : : static struct device_option_list devopt_list =
295 : : TAILQ_HEAD_INITIALIZER(devopt_list);
296 : :
297 : : /* Returns rte_usage_hook_t */
298 : : rte_usage_hook_t
299 : 0 : eal_get_application_usage_hook(void)
300 : : {
301 : 0 : return rte_application_usage_hook;
302 : : }
303 : :
304 : : /* Set a per-application usage message */
305 : : RTE_EXPORT_SYMBOL(rte_set_application_usage_hook)
306 : : rte_usage_hook_t
307 : 2 : rte_set_application_usage_hook(rte_usage_hook_t usage_func)
308 : : {
309 : : rte_usage_hook_t old_func;
310 : :
311 : : /* Will be NULL on the first call to denote the last usage routine. */
312 : 2 : old_func = rte_application_usage_hook;
313 : 2 : rte_application_usage_hook = usage_func;
314 : :
315 : 2 : return old_func;
316 : : }
317 : :
318 : : #ifdef RTE_EXEC_ENV_WINDOWS
319 : : int
320 : : eal_save_args(__rte_unused int argc, __rte_unused char **argv)
321 : : {
322 : : return 0;
323 : : }
324 : :
325 : : void
326 : : eal_clean_saved_args(void)
327 : : {
328 : : /* no-op */
329 : : }
330 : : #else /* RTE_EXEC_ENV_WINDOWS */
331 : : static char **eal_args;
332 : : static char **eal_app_args;
333 : :
334 : : #define EAL_PARAM_REQ "/eal/params"
335 : : #define EAL_APP_PARAM_REQ "/eal/app_params"
336 : :
337 : : /* callback handler for telemetry library to report out EAL flags */
338 : : int
339 : 6 : handle_eal_info_request(const char *cmd, const char *params __rte_unused,
340 : : struct rte_tel_data *d)
341 : : {
342 : : char **args;
343 : : int used = 0;
344 : : int i = 0;
345 : :
346 [ + + ]: 6 : if (strcmp(cmd, EAL_PARAM_REQ) == 0)
347 : 3 : args = eal_args;
348 : : else
349 : 3 : args = eal_app_args;
350 : :
351 : 6 : rte_tel_data_start_array(d, RTE_TEL_STRING_VAL);
352 [ + + + - ]: 6 : if (args == NULL || args[0] == NULL)
353 : : return 0;
354 : :
355 [ + + ]: 36 : for ( ; args[i] != NULL; i++)
356 : 33 : used = rte_tel_data_add_array_string(d, args[i]);
357 : : return used;
358 : : }
359 : :
360 : : int
361 : 253 : eal_save_args(int argc, char **argv)
362 : : {
363 : : int i, j;
364 : :
365 : 253 : rte_telemetry_register_cmd(EAL_PARAM_REQ, handle_eal_info_request,
366 : : "Returns EAL commandline parameters used. Takes no parameters");
367 : 253 : rte_telemetry_register_cmd(EAL_APP_PARAM_REQ, handle_eal_info_request,
368 : : "Returns app commandline parameters used. Takes no parameters");
369 : :
370 : : /* clone argv to report out later. We overprovision, but
371 : : * this does not waste huge amounts of memory
372 : : */
373 : 253 : eal_args = calloc(argc + 1, sizeof(*eal_args));
374 [ + - ]: 253 : if (eal_args == NULL)
375 : : return -1;
376 : :
377 [ + + ]: 1289 : for (i = 0; i < argc; i++) {
378 [ + - ]: 1036 : if (strcmp(argv[i], "--") == 0)
379 : : break;
380 : 1036 : eal_args[i] = strdup(argv[i]);
381 [ - + ]: 1036 : if (eal_args[i] == NULL)
382 : 0 : goto error;
383 : : }
384 : 253 : eal_args[i++] = NULL; /* always finish with NULL */
385 : :
386 : : /* allow reporting of any app args we know about too */
387 [ - + ]: 253 : if (i >= argc)
388 : : return 0;
389 : :
390 : 0 : eal_app_args = calloc(argc - i + 1, sizeof(*eal_args));
391 [ # # ]: 0 : if (eal_app_args == NULL)
392 : 0 : goto error;
393 : :
394 [ # # ]: 0 : for (j = 0; i < argc; j++, i++) {
395 : 0 : eal_app_args[j] = strdup(argv[i]);
396 [ # # ]: 0 : if (eal_app_args[j] == NULL)
397 : 0 : goto error;
398 : : }
399 : 0 : eal_app_args[j] = NULL;
400 : :
401 : 0 : return 0;
402 : :
403 : 0 : error:
404 : 0 : eal_clean_saved_args();
405 : 0 : return -1;
406 : : }
407 : :
408 : : void
409 : 65 : eal_clean_saved_args(void)
410 : : {
411 : : int i;
412 : :
413 [ + - ]: 65 : if (eal_args == NULL)
414 : : return;
415 : :
416 [ - + ]: 65 : if (eal_app_args != NULL) {
417 : : i = 0;
418 [ # # ]: 0 : while (eal_app_args[i] != NULL)
419 : 0 : free(eal_app_args[i++]);
420 : 0 : free(eal_app_args);
421 : 0 : eal_app_args = NULL;
422 : : }
423 : : i = 0;
424 [ + + ]: 396 : while (eal_args[i] != NULL)
425 : 331 : free(eal_args[i++]);
426 : 65 : free(eal_args);
427 : 65 : eal_args = NULL;
428 : : }
429 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
430 : :
431 : : static int
432 : 31 : eal_option_device_add(enum rte_devtype type, const char *optarg)
433 : : {
434 : : struct device_option *devopt;
435 : : size_t optlen;
436 : : int ret;
437 : :
438 : 31 : optlen = strlen(optarg) + 1;
439 : 31 : devopt = calloc(1, sizeof(*devopt) + optlen);
440 [ - + ]: 31 : if (devopt == NULL) {
441 : 0 : EAL_LOG(ERR, "Unable to allocate device option");
442 : 0 : return -ENOMEM;
443 : : }
444 : :
445 : 31 : devopt->type = type;
446 [ - + ]: 31 : ret = strlcpy(devopt->arg, optarg, optlen);
447 [ - + ]: 31 : if (ret < 0) {
448 : 0 : EAL_LOG(ERR, "Unable to copy device option");
449 : 0 : free(devopt);
450 : 0 : return -EINVAL;
451 : : }
452 : 31 : TAILQ_INSERT_TAIL(&devopt_list, devopt, next);
453 : 31 : return 0;
454 : : }
455 : :
456 : : int
457 : 200 : eal_option_device_parse(void)
458 : : {
459 : : struct device_option *devopt;
460 : : void *tmp;
461 : : int ret = 0;
462 : :
463 [ + + ]: 231 : RTE_TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
464 [ + - ]: 31 : if (ret == 0) {
465 : 31 : ret = rte_devargs_add(devopt->type, devopt->arg);
466 [ + + ]: 31 : if (ret)
467 : 13 : EAL_LOG(ERR, "Unable to parse device '%s'",
468 : : devopt->arg);
469 : : }
470 [ + + ]: 31 : TAILQ_REMOVE(&devopt_list, devopt, next);
471 : 31 : free(devopt);
472 : : }
473 : 200 : return ret;
474 : : }
475 : :
476 : : const char *
477 : 4283 : eal_get_hugefile_prefix(void)
478 : : {
479 : : const struct internal_config *internal_conf =
480 : 4283 : eal_get_internal_configuration();
481 : :
482 [ + + ]: 4283 : if (internal_conf->hugefile_prefix != NULL)
483 : 2287 : return internal_conf->hugefile_prefix;
484 : : return HUGEFILE_PREFIX_DEFAULT;
485 : : }
486 : :
487 : : void
488 : 238 : eal_reset_internal_config(struct internal_config *internal_cfg)
489 : : {
490 : : int i;
491 : :
492 : 238 : internal_cfg->memory = 0;
493 : 238 : internal_cfg->force_nrank = 0;
494 : 238 : internal_cfg->force_nchannel = 0;
495 : 238 : internal_cfg->hugefile_prefix = NULL;
496 : 238 : internal_cfg->hugepage_dir = NULL;
497 : 238 : internal_cfg->hugepage_file.unlink_before_mapping = false;
498 : 238 : internal_cfg->hugepage_file.unlink_existing = true;
499 : 238 : internal_cfg->force_numa = 0;
500 : : /* zero out the NUMA config */
501 [ + + ]: 7854 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
502 : 7616 : internal_cfg->numa_mem[i] = 0;
503 : 238 : internal_cfg->force_numa_limits = 0;
504 : : /* zero out the NUMA limits config */
505 [ + + ]: 7854 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
506 : 7616 : internal_cfg->numa_limit[i] = 0;
507 : : /* zero out hugedir descriptors */
508 [ + + ]: 952 : for (i = 0; i < MAX_HUGEPAGE_SIZES; i++) {
509 : 714 : memset(&internal_cfg->hugepage_info[i], 0,
510 : : sizeof(internal_cfg->hugepage_info[0]));
511 : 714 : internal_cfg->hugepage_info[i].lock_descriptor = -1;
512 : : }
513 : 238 : internal_cfg->base_virtaddr = 0;
514 : :
515 : : /* if set to NONE, interrupt mode is determined automatically */
516 : 238 : internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE;
517 : 238 : memset(internal_cfg->vfio_vf_token, 0,
518 : : sizeof(internal_cfg->vfio_vf_token));
519 : :
520 : : #ifdef RTE_LIBEAL_USE_HPET
521 : : internal_cfg->no_hpet = 0;
522 : : #else
523 : 238 : internal_cfg->no_hpet = 1;
524 : : #endif
525 : 238 : internal_cfg->vmware_tsc_map = 0;
526 : 238 : internal_cfg->create_uio_dev = 0;
527 : 238 : internal_cfg->iova_mode = RTE_IOVA_DC;
528 : 238 : internal_cfg->user_mbuf_pool_ops_name = NULL;
529 : 238 : CPU_ZERO(&internal_cfg->ctrl_cpuset);
530 : 238 : internal_cfg->init_complete = 0;
531 : 238 : internal_cfg->max_simd_bitwidth.bitwidth = RTE_VECT_DEFAULT_SIMD_BITWIDTH;
532 : 238 : internal_cfg->max_simd_bitwidth.forced = 0;
533 : 238 : }
534 : :
535 : : static int
536 : 0 : eal_plugin_add(const char *path)
537 : : {
538 : : struct shared_driver *solib;
539 : :
540 : 0 : solib = malloc(sizeof(*solib));
541 [ # # ]: 0 : if (solib == NULL) {
542 : 0 : EAL_LOG(ERR, "malloc(solib) failed");
543 : 0 : return -1;
544 : : }
545 : : memset(solib, 0, sizeof(*solib));
546 : 0 : strlcpy(solib->name, path, PATH_MAX);
547 : 0 : TAILQ_INSERT_TAIL(&solib_list, solib, next);
548 : :
549 : 0 : return 0;
550 : : }
551 : :
552 : : #ifdef RTE_EXEC_ENV_WINDOWS
553 : : int
554 : : eal_plugins_init(void)
555 : : {
556 : : return 0;
557 : : }
558 : : #else
559 : :
560 : : static bool
561 : 0 : ends_with(const char *str, const char *tail)
562 : : {
563 : 0 : size_t tail_len = strlen(tail);
564 : 0 : size_t str_len = strlen(str);
565 : :
566 [ # # # # ]: 0 : return str_len >= tail_len && strcmp(&str[str_len - tail_len], tail) == 0;
567 : : }
568 : :
569 : : static int
570 : 0 : eal_plugindir_init(const char *path)
571 : : {
572 : : struct dirent *dent = NULL;
573 : : char sopath[PATH_MAX];
574 : : DIR *d = NULL;
575 : :
576 [ # # # # ]: 0 : if (path == NULL || *path == '\0')
577 : : return 0;
578 : :
579 : 0 : d = opendir(path);
580 [ # # ]: 0 : if (d == NULL) {
581 : 0 : EAL_LOG(ERR, "failed to open directory %s: %s",
582 : : path, strerror(errno));
583 : 0 : return -1;
584 : : }
585 : :
586 [ # # ]: 0 : while ((dent = readdir(d)) != NULL) {
587 : : struct stat sb;
588 : :
589 [ # # # # ]: 0 : if (!ends_with(dent->d_name, ".so") && !ends_with(dent->d_name, ".so."ABI_VERSION))
590 : 0 : continue;
591 : :
592 : : snprintf(sopath, sizeof(sopath), "%s/%s", path, dent->d_name);
593 : :
594 : : /* if a regular file, add to list to load */
595 [ # # # # ]: 0 : if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode)))
596 : 0 : continue;
597 : :
598 [ # # ]: 0 : if (eal_plugin_add(sopath) == -1)
599 : : break;
600 : : }
601 : :
602 : 0 : closedir(d);
603 : : /* XXX this ignores failures from readdir() itself */
604 [ # # ]: 0 : return (dent == NULL) ? 0 : -1;
605 : : }
606 : :
607 : : static int
608 : 0 : verify_perms(const char *dirpath)
609 : : {
610 : : struct stat st;
611 : :
612 : : /* if not root, check down one level first */
613 [ # # ]: 0 : if (strcmp(dirpath, "/") != 0) {
614 : : static __thread char last_dir_checked[PATH_MAX];
615 : : char copy[PATH_MAX];
616 : : const char *dir;
617 : :
618 : : strlcpy(copy, dirpath, PATH_MAX);
619 : 0 : dir = dirname(copy);
620 [ # # ]: 0 : if (strncmp(dir, last_dir_checked, PATH_MAX) != 0) {
621 [ # # ]: 0 : if (verify_perms(dir) != 0)
622 : 0 : return -1;
623 : : strlcpy(last_dir_checked, dir, PATH_MAX);
624 : : }
625 : : }
626 : :
627 : : /* call stat to check for permissions and ensure not world writable */
628 [ # # ]: 0 : if (stat(dirpath, &st) != 0) {
629 : 0 : EAL_LOG(ERR, "Error with stat on %s, %s",
630 : : dirpath, strerror(errno));
631 : 0 : return -1;
632 : : }
633 [ # # ]: 0 : if (st.st_mode & S_IWOTH) {
634 : 0 : EAL_LOG(ERR,
635 : : "Error, directory path %s is world-writable and insecure",
636 : : dirpath);
637 : 0 : return -1;
638 : : }
639 : :
640 : : return 0;
641 : : }
642 : :
643 : : static void *
644 [ # # ]: 0 : eal_dlopen(const char *pathname)
645 : : {
646 : : void *retval = NULL;
647 : : char *realp = realpath(pathname, NULL);
648 : :
649 [ # # # # ]: 0 : if (realp == NULL && errno == ENOENT) {
650 : : /* not a full or relative path, try a load from system dirs */
651 : 0 : retval = dlopen(pathname, RTLD_NOW);
652 [ # # ]: 0 : if (retval == NULL)
653 : 0 : EAL_LOG(ERR, "%s", dlerror());
654 : 0 : return retval;
655 : : }
656 [ # # ]: 0 : if (realp == NULL) {
657 : 0 : EAL_LOG(ERR, "Error with realpath for %s, %s",
658 : : pathname, strerror(errno));
659 : 0 : goto out;
660 : : }
661 [ # # ]: 0 : if (strnlen(realp, PATH_MAX) == PATH_MAX) {
662 : 0 : EAL_LOG(ERR, "Error, driver path greater than PATH_MAX");
663 : 0 : goto out;
664 : : }
665 : :
666 : : /* do permissions checks */
667 [ # # ]: 0 : if (verify_perms(realp) != 0)
668 : 0 : goto out;
669 : :
670 : 0 : retval = dlopen(realp, RTLD_NOW);
671 [ # # ]: 0 : if (retval == NULL)
672 : 0 : EAL_LOG(ERR, "%s", dlerror());
673 : 0 : out:
674 : 0 : free(realp);
675 : 0 : return retval;
676 : : }
677 : :
678 : : static int
679 [ - + ]: 200 : is_shared_build(void)
680 : : {
681 : : #define EAL_SO "librte_eal.so"
682 : : char soname[32];
683 : : size_t len, minlen = strlen(EAL_SO);
684 : :
685 : : len = strlcpy(soname, EAL_SO"."ABI_VERSION, sizeof(soname));
686 [ - + ]: 200 : if (len > sizeof(soname)) {
687 : 0 : EAL_LOG(ERR, "Shared lib name too long in shared build check");
688 : : len = sizeof(soname) - 1;
689 : : }
690 : :
691 [ + + ]: 800 : while (len >= minlen) {
692 : : void *handle;
693 : :
694 : : /* check if we have this .so loaded, if so - shared build */
695 : 600 : EAL_LOG(DEBUG, "Checking presence of .so '%s'", soname);
696 : 600 : handle = dlopen(soname, RTLD_LAZY | RTLD_NOLOAD);
697 [ - + ]: 600 : if (handle != NULL) {
698 : 0 : EAL_LOG(INFO, "Detected shared linkage of DPDK");
699 : 0 : dlclose(handle);
700 : 0 : return 1;
701 : : }
702 : :
703 : : /* remove any version numbers off the end to retry */
704 [ + - ]: 1600 : while (len-- > 0)
705 [ + + ]: 1600 : if (soname[len] == '.') {
706 : 600 : soname[len] = '\0';
707 : 600 : break;
708 : : }
709 : : }
710 : :
711 : 200 : EAL_LOG(INFO, "Detected static linkage of DPDK");
712 : 200 : return 0;
713 : : }
714 : :
715 : : int
716 : 200 : eal_plugins_init(void)
717 : : {
718 : : struct shared_driver *solib = NULL;
719 : : struct stat sb;
720 : :
721 : : /* If we are not statically linked, add default driver loading
722 : : * path if it exists as a directory.
723 : : * (Using dlopen with NOLOAD flag on EAL, will return NULL if the EAL
724 : : * shared library is not already loaded i.e. it's statically linked.)
725 : : */
726 [ - + ]: 200 : if (is_shared_build() &&
727 [ # # # # ]: 0 : *default_solib_dir != '\0' &&
728 : 0 : stat(default_solib_dir, &sb) == 0 &&
729 [ # # ]: 0 : S_ISDIR(sb.st_mode))
730 : 0 : eal_plugin_add(default_solib_dir);
731 : :
732 [ - + ]: 200 : TAILQ_FOREACH(solib, &solib_list, next) {
733 : :
734 [ # # # # ]: 0 : if (stat(solib->name, &sb) == 0 && S_ISDIR(sb.st_mode)) {
735 [ # # ]: 0 : if (eal_plugindir_init(solib->name) == -1) {
736 : 0 : EAL_LOG(ERR,
737 : : "Cannot init plugin directory %s",
738 : : solib->name);
739 : 0 : return -1;
740 : : }
741 : : } else {
742 : 0 : EAL_LOG(DEBUG, "open shared lib %s",
743 : : solib->name);
744 : 0 : solib->lib_handle = eal_dlopen(solib->name);
745 [ # # ]: 0 : if (solib->lib_handle == NULL)
746 : : return -1;
747 : : }
748 : :
749 : : }
750 : : return 0;
751 : : }
752 : : #endif
753 : :
754 : : /*
755 : : * Parse the coremask given as argument (hexadecimal string) and fill
756 : : * the global configuration (core role and core count) with the parsed
757 : : * value.
758 : : */
759 : 10 : static int xdigit2val(unsigned char c)
760 : : {
761 : : int val;
762 : :
763 [ + - ]: 10 : if (isdigit(c))
764 : 10 : val = c - '0';
765 [ # # ]: 0 : else if (isupper(c))
766 : 0 : val = c - 'A' + 10;
767 : : else
768 : 0 : val = c - 'a' + 10;
769 : 10 : return val;
770 : : }
771 : :
772 : : static int
773 : 0 : eal_parse_service_coremask(const char *coremask)
774 : : {
775 : 0 : struct rte_config *cfg = rte_eal_get_configuration();
776 : : int i, j, idx = 0;
777 : : unsigned int count = 0;
778 : : char c;
779 : : int val;
780 : : uint32_t taken_lcore_count = 0;
781 : :
782 : 0 : EAL_LOG(WARNING, "'-s <service-coremask>' is deprecated, and will be removed in a future release.");
783 : 0 : EAL_LOG(WARNING, "\tUse '-S <service-corelist>' option instead.");
784 : :
785 [ # # ]: 0 : if (coremask == NULL)
786 : : return -1;
787 : : /* Remove all blank characters ahead and after .
788 : : * Remove 0x/0X if exists.
789 : : */
790 [ # # ]: 0 : while (isblank(*coremask))
791 : 0 : coremask++;
792 [ # # ]: 0 : if (coremask[0] == '0' && ((coremask[1] == 'x')
793 [ # # ]: 0 : || (coremask[1] == 'X')))
794 : 0 : coremask += 2;
795 : 0 : i = strlen(coremask);
796 [ # # # # ]: 0 : while ((i > 0) && isblank(coremask[i - 1]))
797 : 0 : i--;
798 : :
799 [ # # ]: 0 : if (i == 0)
800 : : return -1;
801 : :
802 [ # # ]: 0 : for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
803 : 0 : c = coremask[i];
804 [ # # ]: 0 : if (isxdigit(c) == 0) {
805 : : /* invalid characters */
806 : : return -1;
807 : : }
808 : 0 : val = xdigit2val(c);
809 [ # # ]: 0 : for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE;
810 : 0 : j++, idx++) {
811 [ # # ]: 0 : if ((1 << j) & val) {
812 : :
813 [ # # ]: 0 : if (eal_cpu_detected(idx) == 0) {
814 : 0 : EAL_LOG(ERR,
815 : : "lcore %u unavailable", idx);
816 : 0 : return -1;
817 : : }
818 : :
819 [ # # ]: 0 : if (cfg->lcore_role[idx] == ROLE_RTE)
820 : 0 : taken_lcore_count++;
821 : :
822 : 0 : lcore_config[idx].core_role = ROLE_SERVICE;
823 : 0 : count++;
824 : : }
825 : : }
826 : : }
827 : :
828 [ # # ]: 0 : for (; i >= 0; i--)
829 [ # # ]: 0 : if (coremask[i] != '0')
830 : : return -1;
831 : :
832 [ # # ]: 0 : for (; idx < RTE_MAX_LCORE; idx++)
833 : 0 : lcore_config[idx].core_index = -1;
834 : :
835 [ # # ]: 0 : if (count == 0)
836 : : return -1;
837 : :
838 [ # # ]: 0 : if (taken_lcore_count != count) {
839 : 0 : EAL_LOG(WARNING,
840 : : "Not all service cores are in the coremask. "
841 : : "Please ensure -c or -l includes service cores");
842 : : }
843 : :
844 : 0 : cfg->service_lcore_count = count;
845 : 0 : return 0;
846 : : }
847 : :
848 : : static int
849 : 216 : update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
850 : : {
851 : 216 : struct rte_config *cfg = rte_eal_get_configuration();
852 : 216 : unsigned int lcore_id = remap_base;
853 : : unsigned int count = 0;
854 : : unsigned int i;
855 : : int ret = 0;
856 : :
857 : : /* set everything to disabled first, then set up values */
858 [ + + ]: 27864 : for (i = 0; i < RTE_MAX_LCORE; i++) {
859 : 27648 : cfg->lcore_role[i] = ROLE_OFF;
860 : 27648 : lcore_config[i].core_index = -1;
861 : : }
862 : :
863 : : /* now go through the cpuset */
864 [ + + ]: 221400 : for (i = 0; i < CPU_SETSIZE; i++) {
865 [ + + ]: 221184 : if (CPU_ISSET(i, cpuset)) {
866 [ + + ]: 470 : if (eal_cpu_detected(i) == 0) {
867 : 114 : EAL_LOG(ERR, "lcore %u unavailable", i);
868 : : ret = -1;
869 : 114 : continue;
870 : : }
871 : :
872 [ - + ]: 356 : if (count >= RTE_MAX_LCORE) {
873 : 0 : EAL_LOG(WARNING, "Too many lcores provided (>=RTE_MAX_LCORE[%d]). All remaining lcores will be skipped.",
874 : : RTE_MAX_LCORE);
875 : 0 : break;
876 : : }
877 : :
878 [ + - ]: 356 : if (!remap)
879 : : lcore_id = i;
880 [ - + ]: 356 : if (lcore_id >= RTE_MAX_LCORE) {
881 : 0 : EAL_LOG(ERR, "lcore %u >= RTE_MAX_LCORE (%d), cannot use.",
882 : : lcore_id, RTE_MAX_LCORE);
883 : : ret = -1;
884 : 0 : continue;
885 : : }
886 : :
887 : 356 : cfg->lcore_role[lcore_id] = ROLE_RTE;
888 : 356 : lcore_config[lcore_id].core_index = count;
889 : 356 : CPU_ZERO(&lcore_config[lcore_id].cpuset);
890 : 356 : CPU_SET(i, &lcore_config[lcore_id].cpuset);
891 : 356 : EAL_LOG(DEBUG, "lcore %u mapped to physical core %u", lcore_id, i);
892 : 356 : lcore_id++;
893 : 356 : count++;
894 : : }
895 : : }
896 [ + + ]: 216 : if (count == 0) {
897 : 1 : EAL_LOG(ERR, "No valid lcores in core list");
898 : : ret = -1;
899 : : }
900 [ + + ]: 215 : if (!ret)
901 : 214 : cfg->lcore_count = count;
902 : 216 : return ret;
903 : : }
904 : :
905 : : static int
906 : 10 : check_core_list(int *lcores, unsigned int count)
907 : : {
908 : : char lcorestr[RTE_MAX_LCORE * 10];
909 : : bool overflow = false;
910 : : int len = 0, ret;
911 : : unsigned int i;
912 : :
913 [ + + ]: 25 : for (i = 0; i < count; i++) {
914 [ + - ]: 15 : if (lcores[i] < RTE_MAX_LCORE)
915 : 15 : continue;
916 : :
917 : 0 : EAL_LOG(ERR, "lcore %d >= RTE_MAX_LCORE (%d)",
918 : : lcores[i], RTE_MAX_LCORE);
919 : : overflow = true;
920 : : }
921 [ - + ]: 10 : if (!overflow)
922 : : return 0;
923 : :
924 : : /*
925 : : * We've encountered a core that's greater than RTE_MAX_LCORE,
926 : : * suggest using --lcores option to map lcores onto physical cores
927 : : * greater than RTE_MAX_LCORE.
928 : : */
929 [ # # ]: 0 : for (i = 0; i < count; i++) {
930 : 0 : ret = snprintf(&lcorestr[len], sizeof(lcorestr) - len,
931 [ # # ]: 0 : "%d@%d,", i, lcores[i]);
932 [ # # ]: 0 : if (ret > 0)
933 : 0 : len = len + ret;
934 : : }
935 [ # # ]: 0 : if (len > 0)
936 : 0 : lcorestr[len - 1] = 0;
937 : 0 : EAL_LOG(ERR, "To use high physical core ids, "
938 : : "please use --lcores to map them to lcore ids below RTE_MAX_LCORE, "
939 : : "e.g. --lcores %s", lcorestr);
940 : 0 : return -1;
941 : : }
942 : :
943 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_eal_parse_coremask)
944 : : int
945 : 11 : rte_eal_parse_coremask(const char *coremask, rte_cpuset_t *cpuset, bool limit_range)
946 : : {
947 : : const char *coremask_orig = coremask;
948 : : int lcores[CPU_SETSIZE];
949 : : unsigned int count = 0;
950 : : int i, j, idx;
951 : : int val;
952 : : char c;
953 : :
954 : 11 : CPU_ZERO(cpuset);
955 : : idx = 0;
956 : :
957 : 11 : EAL_LOG(WARNING, "'-c <coremask>' option is deprecated, and will be removed in a future release");
958 : 11 : EAL_LOG(WARNING, "\tUse '-l <corelist>' or '--lcores=<corelist>' option instead");
959 : :
960 : : /* Remove all blank characters ahead and after .
961 : : * Remove 0x/0X if exists.
962 : : */
963 [ - + ]: 11 : while (isblank(*coremask))
964 : 0 : coremask++;
965 [ - + ]: 11 : if (coremask[0] == '0' && ((coremask[1] == 'x')
966 [ # # ]: 0 : || (coremask[1] == 'X')))
967 : 0 : coremask += 2;
968 : 11 : i = strlen(coremask);
969 [ + - - + ]: 11 : while ((i > 0) && isblank(coremask[i - 1]))
970 : 0 : i--;
971 [ - + ]: 11 : if (i == 0) {
972 : 0 : EAL_LOG(ERR, "No lcores in coremask: [%s]",
973 : : coremask_orig);
974 : 0 : return -1;
975 : : }
976 : :
977 [ + + ]: 21 : for (i = i - 1; i >= 0; i--) {
978 : 11 : c = coremask[i];
979 [ + + ]: 11 : if (isxdigit(c) == 0) {
980 : : /* invalid characters */
981 : 1 : EAL_LOG(ERR, "invalid characters in coremask: [%s]",
982 : : coremask_orig);
983 : 1 : return -1;
984 : : }
985 : 10 : val = xdigit2val(c);
986 [ + + ]: 50 : for (j = 0; j < BITS_PER_HEX; j++, idx++)
987 : : {
988 [ + + ]: 40 : if ((1 << j) & val) {
989 [ - + ]: 15 : if (count >= RTE_MAX_LCORE) {
990 : 0 : EAL_LOG(ERR, "Too many lcores provided. Cannot exceed RTE_MAX_LCORE (%d)",
991 : : RTE_MAX_LCORE);
992 : 0 : return -1;
993 : : }
994 [ - + ]: 15 : if (idx >= CPU_SETSIZE) {
995 : 0 : EAL_LOG(ERR, "lcore %d >= CPU_SETSIZE (%d), cannot use.",
996 : : idx, CPU_SETSIZE);
997 : 0 : return -1;
998 : : }
999 : 15 : lcores[count++] = idx;
1000 [ + - ]: 15 : CPU_SET(idx, cpuset);
1001 : : }
1002 : : }
1003 : : }
1004 [ - + ]: 10 : if (count == 0) {
1005 : 0 : EAL_LOG(ERR, "No lcores in coremask: [%s]",
1006 : : coremask_orig);
1007 : 0 : return -1;
1008 : : }
1009 : :
1010 : : /* if we are asked to, we need to check that cores < RTE_MAX_LCORE */
1011 [ + - - + ]: 10 : if (limit_range && check_core_list(lcores, count) != 0)
1012 : 0 : return -1;
1013 : :
1014 : : return 0;
1015 : : }
1016 : :
1017 : : static int
1018 : 0 : eal_parse_service_corelist(const char *corelist)
1019 : : {
1020 : 0 : struct rte_config *cfg = rte_eal_get_configuration();
1021 : : int i;
1022 : : unsigned count = 0;
1023 : 0 : char *end = NULL;
1024 : : uint32_t min, max, idx;
1025 : : uint32_t taken_lcore_count = 0;
1026 : :
1027 [ # # ]: 0 : if (corelist == NULL)
1028 : : return -1;
1029 : :
1030 : : /* Remove all blank characters ahead and after */
1031 [ # # ]: 0 : while (isblank(*corelist))
1032 : 0 : corelist++;
1033 : : i = strlen(corelist);
1034 : : while ((i > 0) && isblank(corelist[i - 1]))
1035 : : i--;
1036 : :
1037 : : /* Get list of cores */
1038 : : min = RTE_MAX_LCORE;
1039 : : do {
1040 [ # # ]: 0 : while (isblank(*corelist))
1041 : 0 : corelist++;
1042 [ # # ]: 0 : if (*corelist == '\0')
1043 : : return -1;
1044 : 0 : errno = 0;
1045 : 0 : idx = strtoul(corelist, &end, 10);
1046 [ # # # # ]: 0 : if (errno || end == NULL)
1047 : : return -1;
1048 [ # # ]: 0 : if (idx >= RTE_MAX_LCORE)
1049 : : return -1;
1050 [ # # ]: 0 : while (isblank(*end))
1051 : 0 : end++;
1052 [ # # ]: 0 : if (*end == '-') {
1053 : : min = idx;
1054 [ # # ]: 0 : } else if ((*end == ',') || (*end == '\0')) {
1055 : : max = idx;
1056 [ # # ]: 0 : if (min == RTE_MAX_LCORE)
1057 : : min = idx;
1058 [ # # ]: 0 : for (idx = min; idx <= max; idx++) {
1059 [ # # ]: 0 : if (cfg->lcore_role[idx] != ROLE_SERVICE) {
1060 [ # # ]: 0 : if (cfg->lcore_role[idx] == ROLE_RTE)
1061 : 0 : taken_lcore_count++;
1062 : :
1063 : 0 : lcore_config[idx].core_role =
1064 : : ROLE_SERVICE;
1065 : 0 : count++;
1066 : : }
1067 : : }
1068 : : min = RTE_MAX_LCORE;
1069 : : } else
1070 : : return -1;
1071 : 0 : corelist = end + 1;
1072 [ # # ]: 0 : } while (*end != '\0');
1073 : :
1074 [ # # ]: 0 : if (count == 0)
1075 : : return -1;
1076 : :
1077 [ # # ]: 0 : if (taken_lcore_count != count) {
1078 : 0 : EAL_LOG(WARNING,
1079 : : "Not all service cores were in the coremask. "
1080 : : "Please ensure -c or -l includes service cores");
1081 : : }
1082 : :
1083 : : /* log the configured service cores for debugging */
1084 : : rte_cpuset_t service_cpuset;
1085 : 0 : CPU_ZERO(&service_cpuset);
1086 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
1087 [ # # ]: 0 : if (lcore_config[i].core_role == ROLE_SERVICE)
1088 : 0 : CPU_SET(i, &service_cpuset);
1089 : : }
1090 [ # # ]: 0 : if (CPU_COUNT(&service_cpuset) > 0) {
1091 : 0 : char *cpuset_str = eal_cpuset_to_str(&service_cpuset);
1092 [ # # ]: 0 : if (cpuset_str != NULL) {
1093 : 0 : EAL_LOG(DEBUG, "Service cores configured: %s", cpuset_str);
1094 : 0 : free(cpuset_str);
1095 : : }
1096 : : }
1097 : :
1098 : : return 0;
1099 : : }
1100 : :
1101 : : /* Changes the lcore id of the main thread */
1102 : : static int
1103 : 5 : eal_parse_main_lcore(const char *arg)
1104 : : {
1105 : : char *parsing_end;
1106 : 5 : struct rte_config *cfg = rte_eal_get_configuration();
1107 : :
1108 : 5 : errno = 0;
1109 : 5 : cfg->main_lcore = (uint32_t) strtol(arg, &parsing_end, 0);
1110 [ + - + + ]: 5 : if (errno || parsing_end[0] != 0)
1111 : : return -1;
1112 [ + + ]: 4 : if (cfg->main_lcore >= RTE_MAX_LCORE)
1113 : : return -1;
1114 : :
1115 : : /* ensure main core is not used as service core */
1116 [ - + ]: 3 : if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
1117 : 0 : EAL_LOG(ERR, "Error: Main lcore is used as a service core");
1118 : 0 : return -1;
1119 : : }
1120 : : /* check that we have the core recorded in the core list */
1121 [ + + ]: 3 : if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
1122 : 1 : EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
1123 : 1 : return -1;
1124 : : }
1125 : :
1126 : : return 0;
1127 : : }
1128 : :
1129 : : /*
1130 : : * Parse elem, the elem could be single number/range or '(' ')' group
1131 : : * 1) A single number elem, it's just a simple digit. e.g. 9
1132 : : * 2) A single range elem, two digits with a '-' between. e.g. 2-6
1133 : : * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
1134 : : * Within group elem, '-' used for a range separator;
1135 : : * ',' used for a single number.
1136 : : */
1137 : : static int
1138 : 12 : eal_parse_set(const char *input, rte_cpuset_t *set)
1139 : : {
1140 : : unsigned idx;
1141 : : const char *str = input;
1142 : 12 : char *end = NULL;
1143 : : unsigned min, max;
1144 : :
1145 : 12 : CPU_ZERO(set);
1146 : :
1147 [ - + ]: 12 : while (isblank(*str))
1148 : 0 : str++;
1149 : :
1150 : : /* only digit or left bracket is qualify for start point */
1151 [ + + + + : 12 : if ((!isdigit(*str) && *str != '(') || *str == '\0')
+ - ]
1152 : : return -1;
1153 : :
1154 : : /* process single number or single range of number */
1155 [ + + ]: 11 : if (*str != '(') {
1156 : 3 : errno = 0;
1157 : 3 : idx = strtoul(str, &end, 10);
1158 [ + - + - : 3 : if (errno || end == NULL || idx >= CPU_SETSIZE)
+ + ]
1159 : : return -1;
1160 : : else {
1161 [ - + ]: 2 : while (isblank(*end))
1162 : 0 : end++;
1163 : :
1164 : : min = idx;
1165 : : max = idx;
1166 [ + + ]: 2 : if (*end == '-') {
1167 : : /* process single <number>-<number> */
1168 : 1 : end++;
1169 [ - + ]: 1 : while (isblank(*end))
1170 : 0 : end++;
1171 [ + - ]: 1 : if (!isdigit(*end))
1172 : : return -1;
1173 : :
1174 : 1 : errno = 0;
1175 : 1 : idx = strtoul(end, &end, 10);
1176 [ + - + - : 1 : if (errno || end == NULL || idx >= CPU_SETSIZE)
+ - ]
1177 : : return -1;
1178 : : max = idx;
1179 [ - + ]: 1 : while (isblank(*end))
1180 : 0 : end++;
1181 [ - + ]: 1 : if (*end != ',' && *end != '\0')
1182 : : return -1;
1183 : : }
1184 : :
1185 [ + - - + ]: 1 : if (*end != ',' && *end != '\0' &&
1186 : : *end != '@')
1187 : : return -1;
1188 : :
1189 : 0 : for (idx = RTE_MIN(min, max);
1190 [ # # ]: 0 : idx <= RTE_MAX(min, max); idx++)
1191 [ # # ]: 0 : CPU_SET(idx, set);
1192 : :
1193 : 0 : return end - input;
1194 : : }
1195 : : }
1196 : :
1197 : : /* process set within bracket */
1198 : 8 : str++;
1199 [ - + ]: 8 : while (isblank(*str))
1200 : 0 : str++;
1201 [ + - ]: 8 : if (*str == '\0')
1202 : : return -1;
1203 : :
1204 : : min = RTE_MAX_LCORE;
1205 : : do {
1206 : :
1207 : : /* go ahead to the first digit */
1208 [ - + ]: 13 : while (isblank(*str))
1209 : 0 : str++;
1210 [ + + ]: 13 : if (!isdigit(*str))
1211 : : return -1;
1212 : :
1213 : : /* get the digit value */
1214 : 9 : errno = 0;
1215 : 9 : idx = strtoul(str, &end, 10);
1216 [ + - + - : 9 : if (errno || end == NULL || idx >= CPU_SETSIZE)
+ - ]
1217 : : return -1;
1218 : :
1219 : : /* go ahead to separator '-',',' and ')' */
1220 [ - + ]: 9 : while (isblank(*end))
1221 : 0 : end++;
1222 [ + + ]: 9 : if (*end == '-') {
1223 [ + + ]: 4 : if (min == RTE_MAX_LCORE)
1224 : : min = idx;
1225 : : else /* avoid continuous '-' */
1226 : : return -1;
1227 [ + - ]: 5 : } else if ((*end == ',') || (*end == ')')) {
1228 : : max = idx;
1229 [ + + ]: 5 : if (min == RTE_MAX_LCORE)
1230 : : min = idx;
1231 : 5 : for (idx = RTE_MIN(min, max);
1232 [ + + ]: 13 : idx <= RTE_MAX(min, max); idx++)
1233 [ + - ]: 8 : CPU_SET(idx, set);
1234 : :
1235 : : min = RTE_MAX_LCORE;
1236 : : } else
1237 : : return -1;
1238 : :
1239 : 8 : str = end + 1;
1240 [ + + ]: 8 : } while (*end != '\0' && *end != ')');
1241 : :
1242 : : /*
1243 : : * to avoid failure that tail blank makes end character check fail
1244 : : * in eal_parse_lcores( )
1245 : : */
1246 [ - + ]: 3 : while (isblank(*str))
1247 : 0 : str++;
1248 : :
1249 : 3 : return str - input;
1250 : : }
1251 : :
1252 : : static int
1253 : 4 : check_cpuset(rte_cpuset_t *set)
1254 : : {
1255 : : unsigned int idx;
1256 : :
1257 [ + + ]: 4100 : for (idx = 0; idx < CPU_SETSIZE; idx++) {
1258 [ + + ]: 4096 : if (!CPU_ISSET(idx, set))
1259 : 4080 : continue;
1260 : :
1261 [ - + ]: 16 : if (eal_cpu_detected(idx) == 0) {
1262 : 0 : EAL_LOG(ERR, "core %u "
1263 : : "unavailable", idx);
1264 : 0 : return -1;
1265 : : }
1266 : : }
1267 : : return 0;
1268 : : }
1269 : :
1270 : : /*
1271 : : * The format pattern: --lcores='<lcores[@cpus]>[<,lcores[@cpus]>...]'
1272 : : * lcores, cpus could be a single digit/range or a group.
1273 : : * '(' and ')' are necessary if it's a group.
1274 : : * If not supply '@cpus', the value of cpus uses the same as lcores.
1275 : : * e.g. '1,2@(5-7),(3-5)@(0,2),(0,6),7-8' means start 9 EAL thread as below
1276 : : * lcore 0 runs on cpuset 0x41 (cpu 0,6)
1277 : : * lcore 1 runs on cpuset 0x2 (cpu 1)
1278 : : * lcore 2 runs on cpuset 0xe0 (cpu 5,6,7)
1279 : : * lcore 3,4,5 runs on cpuset 0x5 (cpu 0,2)
1280 : : * lcore 6 runs on cpuset 0x41 (cpu 0,6)
1281 : : * lcore 7 runs on cpuset 0x80 (cpu 7)
1282 : : * lcore 8 runs on cpuset 0x100 (cpu 8)
1283 : : */
1284 : : static int
1285 : 9 : eal_parse_lcores(const char *lcores)
1286 : : {
1287 : 9 : struct rte_config *cfg = rte_eal_get_configuration();
1288 : : rte_cpuset_t lcore_set;
1289 : : unsigned int set_count;
1290 : : unsigned idx = 0;
1291 : : unsigned count = 0;
1292 : : const char *lcore_start = NULL;
1293 : : const char *end = NULL;
1294 : : int offset;
1295 : : rte_cpuset_t cpuset;
1296 : : int lflags;
1297 : : int ret = -1;
1298 : :
1299 [ + - ]: 9 : if (lcores == NULL)
1300 : : return -1;
1301 : :
1302 : : /* Remove all blank characters ahead and after */
1303 [ - + ]: 9 : while (isblank(*lcores))
1304 : 0 : lcores++;
1305 : :
1306 : 9 : CPU_ZERO(&cpuset);
1307 : :
1308 : : /* Reset lcore config */
1309 [ + + ]: 1161 : for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
1310 : 1152 : cfg->lcore_role[idx] = ROLE_OFF;
1311 : 1152 : lcore_config[idx].core_index = -1;
1312 : 1152 : CPU_ZERO(&lcore_config[idx].cpuset);
1313 : : }
1314 : :
1315 : : /* Get list of cores */
1316 : : do {
1317 [ - + ]: 10 : while (isblank(*lcores))
1318 : 0 : lcores++;
1319 [ - + ]: 10 : if (*lcores == '\0')
1320 : 0 : goto err;
1321 : :
1322 : : lflags = 0;
1323 : :
1324 : : /* record lcore_set start point */
1325 : : lcore_start = lcores;
1326 : :
1327 : : /* go across a complete bracket */
1328 [ + + ]: 10 : if (*lcore_start == '(') {
1329 : 5 : lcores += strcspn(lcores, ")");
1330 [ - + ]: 5 : if (*lcores++ == '\0')
1331 : 0 : goto err;
1332 : : }
1333 : :
1334 : : /* scan the separator '@', ','(next) or '\0'(finish) */
1335 : 10 : lcores += strcspn(lcores, "@,");
1336 : :
1337 [ + + ]: 10 : if (*lcores == '@') {
1338 : : /* explicit assign cpuset and update the end cursor */
1339 : 5 : offset = eal_parse_set(lcores + 1, &cpuset);
1340 [ + + ]: 5 : if (offset < 0)
1341 : 3 : goto err;
1342 : 2 : end = lcores + 1 + offset;
1343 : : } else { /* ',' or '\0' */
1344 : : /* haven't given cpuset, current loop done */
1345 : : end = lcores;
1346 : :
1347 : : /* go back to check <number>-<number> */
1348 : 5 : offset = strcspn(lcore_start, "(-");
1349 [ + + ]: 5 : if (offset < (end - lcore_start) &&
1350 [ - + ]: 4 : *(lcore_start + offset) != '(')
1351 : : lflags = 1;
1352 : : }
1353 : :
1354 [ - + ]: 7 : if (*end != ',' && *end != '\0')
1355 : 0 : goto err;
1356 : :
1357 : : /* parse lcore_set from start point */
1358 [ + + ]: 7 : if (eal_parse_set(lcore_start, &lcore_set) < 0)
1359 : 6 : goto err;
1360 : :
1361 : : /* without '@', by default using lcore_set as cpuset */
1362 [ + - ]: 1 : if (*lcores != '@')
1363 : : rte_memcpy(&cpuset, &lcore_set, sizeof(cpuset));
1364 : :
1365 : 1 : set_count = CPU_COUNT(&lcore_set);
1366 : : /* start to update lcore_set */
1367 [ + + ]: 129 : for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
1368 [ + + ]: 128 : if (!CPU_ISSET(idx, &lcore_set))
1369 : 124 : continue;
1370 : 4 : set_count--;
1371 : :
1372 [ + - ]: 4 : if (cfg->lcore_role[idx] != ROLE_RTE) {
1373 : 4 : lcore_config[idx].core_index = count;
1374 : 4 : cfg->lcore_role[idx] = ROLE_RTE;
1375 : 4 : count++;
1376 : : }
1377 : :
1378 [ - + ]: 4 : if (lflags) {
1379 : 0 : CPU_ZERO(&cpuset);
1380 : 0 : CPU_SET(idx, &cpuset);
1381 : : }
1382 : :
1383 [ - + ]: 4 : if (check_cpuset(&cpuset) < 0)
1384 : 0 : goto err;
1385 [ + - ]: 4 : rte_memcpy(&lcore_config[idx].cpuset, &cpuset,
1386 : : sizeof(rte_cpuset_t));
1387 : : }
1388 : :
1389 : : /* some cores from the lcore_set can't be handled by EAL */
1390 [ - + ]: 1 : if (set_count != 0)
1391 : 0 : goto err;
1392 : :
1393 : 1 : lcores = end + 1;
1394 [ + - ]: 1 : } while (*end != '\0');
1395 : :
1396 [ # # ]: 0 : if (count == 0)
1397 : 0 : goto err;
1398 : :
1399 : 0 : cfg->lcore_count = count;
1400 : : ret = 0;
1401 : :
1402 : : err:
1403 : :
1404 : : return ret;
1405 : : }
1406 : :
1407 : : static void
1408 : 0 : eal_log_usage(void)
1409 : : {
1410 : : unsigned int level;
1411 : :
1412 : : printf("Log type is a pattern matching items of this list"
1413 : : " (plugins may be missing):\n");
1414 : 0 : rte_log_list_types(stdout, "\t");
1415 : : printf("\n");
1416 : : printf("Syntax using globbing pattern: ");
1417 : : printf("--log-level pattern:level\n");
1418 : : printf("Syntax using regular expression: ");
1419 : : printf("--log-level regexp,level\n");
1420 : : printf("Syntax for the global level: ");
1421 : : printf("--log-level level\n");
1422 : : printf("Logs are emitted if allowed by both global and specific levels.\n");
1423 : : printf("\n");
1424 : : printf("Log level can be a number or the first letters of its name:\n");
1425 [ # # ]: 0 : for (level = 1; level <= RTE_LOG_MAX; level++)
1426 : 0 : printf("\t%d %s\n", level, eal_log_level2str(level));
1427 : 0 : }
1428 : :
1429 : : static int
1430 : 0 : eal_parse_log_priority(const char *level)
1431 : : {
1432 : 0 : size_t len = strlen(level);
1433 : : unsigned long tmp;
1434 : : char *end;
1435 : : unsigned int i;
1436 : :
1437 [ # # ]: 0 : if (len == 0)
1438 : : return -1;
1439 : :
1440 : : /* look for named values, skip 0 which is not a valid level */
1441 [ # # ]: 0 : for (i = 1; i <= RTE_LOG_MAX; i++) {
1442 [ # # ]: 0 : if (strncmp(eal_log_level2str(i), level, len) == 0)
1443 : 0 : return i;
1444 : : }
1445 : :
1446 : : /* not a string, maybe it is numeric */
1447 : 0 : errno = 0;
1448 : 0 : tmp = strtoul(level, &end, 0);
1449 : :
1450 : : /* check for errors */
1451 [ # # # # : 0 : if (errno != 0 || end == NULL || *end != '\0' ||
# # # # ]
1452 : : tmp >= UINT32_MAX)
1453 : : return -1;
1454 : :
1455 : 0 : return tmp;
1456 : : }
1457 : :
1458 : : static int
1459 : 0 : eal_parse_log_level(const char *arg)
1460 : : {
1461 : : const char *pattern = NULL;
1462 : : const char *regex = NULL;
1463 : : char *str, *level;
1464 : : int priority;
1465 : :
1466 [ # # ]: 0 : if (strcmp(arg, "help") == 0) {
1467 : 0 : eal_log_usage();
1468 : 0 : exit(EXIT_SUCCESS);
1469 : : }
1470 : :
1471 : 0 : str = strdup(arg);
1472 [ # # ]: 0 : if (str == NULL)
1473 : : return -1;
1474 : :
1475 [ # # ]: 0 : if ((level = strchr(str, ','))) {
1476 : : regex = str;
1477 : 0 : *level++ = '\0';
1478 [ # # ]: 0 : } else if ((level = strchr(str, ':'))) {
1479 : : pattern = str;
1480 : 0 : *level++ = '\0';
1481 : : } else {
1482 : : level = str;
1483 : : }
1484 : :
1485 : 0 : priority = eal_parse_log_priority(level);
1486 [ # # ]: 0 : if (priority <= 0) {
1487 : 0 : fprintf(stderr, "Invalid log level: %s\n", level);
1488 : 0 : goto fail;
1489 : : }
1490 [ # # ]: 0 : if (priority > (int)RTE_LOG_MAX) {
1491 : 0 : fprintf(stderr, "Log level %d higher than maximum (%d)\n",
1492 : : priority, RTE_LOG_MAX);
1493 : : priority = RTE_LOG_MAX;
1494 : : }
1495 : :
1496 [ # # ]: 0 : if (regex) {
1497 [ # # ]: 0 : if (rte_log_set_level_regexp(regex, priority) < 0) {
1498 : 0 : fprintf(stderr, "cannot set log level %s,%d\n",
1499 : : regex, priority);
1500 : 0 : goto fail;
1501 : : }
1502 [ # # ]: 0 : if (eal_log_save_regexp(regex, priority) < 0)
1503 : 0 : goto fail;
1504 [ # # ]: 0 : } else if (pattern) {
1505 [ # # ]: 0 : if (rte_log_set_level_pattern(pattern, priority) < 0) {
1506 : 0 : fprintf(stderr, "cannot set log level %s:%d\n",
1507 : : pattern, priority);
1508 : 0 : goto fail;
1509 : : }
1510 [ # # ]: 0 : if (eal_log_save_pattern(pattern, priority) < 0)
1511 : 0 : goto fail;
1512 : : } else {
1513 : 0 : rte_log_set_global_level(priority);
1514 : : }
1515 : :
1516 : 0 : free(str);
1517 : 0 : return 0;
1518 : :
1519 : 0 : fail:
1520 : 0 : free(str);
1521 : 0 : return -1;
1522 : : }
1523 : :
1524 : : static enum rte_proc_type_t
1525 : 73 : eal_parse_proc_type(const char *arg)
1526 : : {
1527 [ + - ]: 73 : if (strncasecmp(arg, "primary", sizeof("primary")) == 0)
1528 : : return RTE_PROC_PRIMARY;
1529 [ + + ]: 73 : if (strncasecmp(arg, "secondary", sizeof("secondary")) == 0)
1530 : : return RTE_PROC_SECONDARY;
1531 [ + + ]: 4 : if (strncasecmp(arg, "auto", sizeof("auto")) == 0)
1532 : 3 : return RTE_PROC_AUTO;
1533 : :
1534 : : return RTE_PROC_INVALID;
1535 : : }
1536 : :
1537 : : static int
1538 : 0 : eal_parse_iova_mode(const char *name)
1539 : : {
1540 : : int mode;
1541 : : struct internal_config *internal_conf =
1542 : 0 : eal_get_internal_configuration();
1543 : :
1544 [ # # ]: 0 : if (name == NULL)
1545 : : return -1;
1546 : :
1547 [ # # ]: 0 : if (!strcmp("pa", name))
1548 : : mode = RTE_IOVA_PA;
1549 [ # # ]: 0 : else if (!strcmp("va", name))
1550 : : mode = RTE_IOVA_VA;
1551 : : else
1552 : : return -1;
1553 : :
1554 : 0 : internal_conf->iova_mode = mode;
1555 : 0 : return 0;
1556 : : }
1557 : :
1558 : : static int
1559 : 0 : eal_parse_simd_bitwidth(const char *arg)
1560 : : {
1561 : : char *end;
1562 : : unsigned long bitwidth;
1563 : : int ret;
1564 : : struct internal_config *internal_conf =
1565 : 0 : eal_get_internal_configuration();
1566 : :
1567 [ # # # # ]: 0 : if (arg == NULL || arg[0] == '\0')
1568 : : return -1;
1569 : :
1570 : 0 : errno = 0;
1571 : 0 : bitwidth = strtoul(arg, &end, 0);
1572 : :
1573 : : /* check for errors */
1574 [ # # # # : 0 : if (errno != 0 || end == NULL || *end != '\0' || bitwidth > RTE_VECT_SIMD_MAX)
# # # # ]
1575 : : return -1;
1576 : :
1577 [ # # ]: 0 : if (bitwidth == 0)
1578 : : bitwidth = (unsigned long) RTE_VECT_SIMD_MAX;
1579 : 0 : ret = rte_vect_set_max_simd_bitwidth(bitwidth);
1580 [ # # ]: 0 : if (ret < 0)
1581 : : return -1;
1582 : 0 : internal_conf->max_simd_bitwidth.forced = 1;
1583 : 0 : return 0;
1584 : : }
1585 : :
1586 : : static int
1587 : 1 : eal_parse_base_virtaddr(const char *arg)
1588 : : {
1589 : : char *end;
1590 : : uint64_t addr;
1591 : : struct internal_config *internal_conf =
1592 : 1 : eal_get_internal_configuration();
1593 : :
1594 : 1 : errno = 0;
1595 : 1 : addr = strtoull(arg, &end, 16);
1596 : :
1597 : : /* check for errors */
1598 [ + - + - : 1 : if ((errno != 0) || (arg[0] == '\0') || end == NULL || (*end != '\0'))
+ - + - ]
1599 : : return -1;
1600 : :
1601 : : /* make sure we don't exceed 32-bit boundary on 32-bit target */
1602 : : #ifndef RTE_ARCH_64
1603 : : if (addr >= UINTPTR_MAX)
1604 : : return -1;
1605 : : #endif
1606 : :
1607 : : /* align the addr on 16M boundary, 16MB is the minimum huge page
1608 : : * size on IBM Power architecture. If the addr is aligned to 16MB,
1609 : : * it can align to 2MB for x86. So this alignment can also be used
1610 : : * on x86 and other architectures.
1611 : : */
1612 : 1 : internal_conf->base_virtaddr =
1613 : 1 : RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
1614 : :
1615 : 1 : return 0;
1616 : : }
1617 : :
1618 : : /* caller is responsible for freeing the returned string */
1619 : : char *
1620 : 730 : eal_cpuset_to_str(const rte_cpuset_t *cpuset)
1621 : : {
1622 : 730 : char *str = NULL;
1623 : : int previous;
1624 : : int sequence;
1625 : : char *tmp;
1626 : : int idx;
1627 : :
1628 : : /* find the first set cpu */
1629 [ + - ]: 988 : for (idx = 0; idx < CPU_SETSIZE; idx++) {
1630 [ + + ]: 988 : if (!CPU_ISSET(idx, cpuset))
1631 : : continue;
1632 : : break;
1633 : : }
1634 [ + - ]: 730 : if (idx >= CPU_SETSIZE)
1635 : : return NULL;
1636 : :
1637 : : /* first sequence */
1638 [ + - ]: 730 : if (asprintf(&str, "%d", idx) < 0)
1639 : : return NULL;
1640 : : previous = idx;
1641 : : sequence = 0;
1642 : :
1643 [ + + ]: 747262 : for (idx++ ; idx < CPU_SETSIZE; idx++) {
1644 [ + - + + ]: 746532 : if (!CPU_ISSET(idx, cpuset))
1645 : 746248 : continue;
1646 : :
1647 [ + - ]: 284 : if (idx == previous + 1) {
1648 : : previous = idx;
1649 : : sequence = 1;
1650 : 284 : continue;
1651 : : }
1652 : :
1653 : : /* finish current sequence */
1654 [ # # ]: 0 : if (sequence) {
1655 [ # # ]: 0 : if (asprintf(&tmp, "%s-%d", str, previous) < 0) {
1656 : 0 : free(str);
1657 : 0 : return NULL;
1658 : : }
1659 : 0 : free(str);
1660 : 0 : str = tmp;
1661 : : }
1662 : :
1663 : : /* new sequence */
1664 [ # # ]: 0 : if (asprintf(&tmp, "%s,%d", str, idx) < 0) {
1665 : 0 : free(str);
1666 : 0 : return NULL;
1667 : : }
1668 : 0 : free(str);
1669 : 0 : str = tmp;
1670 : : previous = idx;
1671 : : sequence = 0;
1672 : : }
1673 : :
1674 : : /* finish last sequence */
1675 [ + + ]: 730 : if (sequence) {
1676 [ - + ]: 130 : if (asprintf(&tmp, "%s-%d", str, previous) < 0) {
1677 : 0 : free(str);
1678 : 0 : return NULL;
1679 : : }
1680 : 130 : free(str);
1681 : 130 : str = tmp;
1682 : : }
1683 : :
1684 : 730 : return str;
1685 : : }
1686 : :
1687 : : /* caller is responsible for freeing the returned string */
1688 : : static char *
1689 : 2 : available_cores(void)
1690 : : {
1691 : : rte_cpuset_t cpuset;
1692 : : int idx;
1693 : :
1694 : : /* build cpuset of available cores */
1695 : 2 : CPU_ZERO(&cpuset);
1696 [ + + ]: 258 : for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
1697 [ + + ]: 256 : if (eal_cpu_detected(idx))
1698 : 32 : CPU_SET(idx, &cpuset);
1699 : : }
1700 : :
1701 : 2 : return eal_cpuset_to_str(&cpuset);
1702 : : }
1703 : :
1704 : : #define HUGE_UNLINK_NEVER "never"
1705 : :
1706 : : static int
1707 : 1 : eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
1708 : : {
1709 [ + - - + ]: 1 : if (arg == NULL || strcmp(arg, "always") == 0) {
1710 : 0 : out->unlink_before_mapping = true;
1711 : 0 : return 0;
1712 : : }
1713 [ + - ]: 1 : if (strcmp(arg, "existing") == 0) {
1714 : : /* same as not specifying the option */
1715 : : return 0;
1716 : : }
1717 [ + - ]: 1 : if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
1718 : 1 : EAL_LOG(WARNING, "Using --huge-unlink="
1719 : : HUGE_UNLINK_NEVER" may create data leaks.");
1720 : 1 : out->unlink_existing = false;
1721 : 1 : return 0;
1722 : : }
1723 : : return -1;
1724 : : }
1725 : :
1726 : : /* Parse all arguments looking for log related ones */
1727 : : int
1728 : 241 : eal_parse_log_options(void)
1729 : : {
1730 : : struct arg_list_elem *arg;
1731 [ - + ]: 241 : TAILQ_FOREACH(arg, &args.log_level, next) {
1732 [ # # ]: 0 : if (eal_parse_log_level(arg->arg) < 0) {
1733 : 0 : EAL_LOG(ERR, "invalid log-level parameter");
1734 : 0 : return -1;
1735 : : }
1736 : : }
1737 [ + + ]: 241 : if (args.log_color != NULL) {
1738 : : /* if value is 1, no argument specified, so pass NULL */
1739 [ + + ]: 3 : if (args.log_color == (void *)1)
1740 : 1 : args.log_color = NULL;
1741 [ + + ]: 3 : if (eal_log_color(args.log_color) < 0) {
1742 : 1 : EAL_LOG(ERR, "invalid log-color parameter");
1743 : 1 : return -1;
1744 : : }
1745 : : }
1746 [ + + ]: 240 : if (args.log_timestamp != NULL) {
1747 : : /* similarly log_timestamp may be 1 */
1748 [ + + ]: 3 : if (args.log_timestamp == (void *)1)
1749 : 1 : args.log_timestamp = NULL;
1750 [ + + ]: 3 : if (eal_log_timestamp(args.log_timestamp) < 0) {
1751 : 1 : EAL_LOG(ERR, "invalid log-timestamp parameter");
1752 : 1 : return -1;
1753 : : }
1754 : : }
1755 [ + + ]: 239 : if (args.syslog != NULL) {
1756 : : #ifdef RTE_EXEC_ENV_WINDOWS
1757 : : EAL_LOG(WARNING, "syslog is not supported on Windows, ignoring parameter");
1758 : : #else
1759 : : /* also syslog parameter may be 1 */
1760 [ + + ]: 3 : if (args.syslog == (void *)1)
1761 : 1 : args.syslog = NULL;
1762 [ + + ]: 3 : if (eal_log_syslog(args.syslog) < 0) {
1763 : 1 : EAL_LOG(ERR, "invalid syslog parameter");
1764 : 1 : return -1;
1765 : : }
1766 : : #endif
1767 : : }
1768 : : return 0;
1769 : : }
1770 : :
1771 : : static int
1772 : 7 : eal_parse_socket_arg(char *strval, volatile uint64_t *socket_arg)
1773 : : {
1774 : : char *arg[RTE_MAX_NUMA_NODES];
1775 : : char *end;
1776 : : int arg_num, i, len;
1777 : :
1778 : 7 : len = strnlen(strval, NUMA_MEM_STRLEN);
1779 [ - + ]: 7 : if (len == NUMA_MEM_STRLEN) {
1780 : 0 : EAL_LOG(ERR, "--numa-mem/--socket-mem parameter is too long");
1781 : 0 : return -1;
1782 : : }
1783 : :
1784 : : /* all other error cases will be caught later */
1785 [ + + ]: 7 : if (!isdigit(strval[len-1]))
1786 : : return -1;
1787 : :
1788 : : /* split the optarg into separate socket values */
1789 : 4 : arg_num = rte_strsplit(strval, len,
1790 : : arg, RTE_MAX_NUMA_NODES, ',');
1791 : :
1792 : : /* if split failed, or 0 arguments */
1793 [ + - ]: 4 : if (arg_num <= 0)
1794 : : return -1;
1795 : :
1796 : : /* parse each defined socket option */
1797 : 4 : errno = 0;
1798 [ + + ]: 12 : for (i = 0; i < arg_num; i++) {
1799 : : uint64_t val;
1800 : 9 : end = NULL;
1801 : 9 : val = strtoull(arg[i], &end, 10);
1802 : :
1803 : : /* check for invalid input */
1804 [ + - ]: 9 : if ((errno != 0) ||
1805 [ + - + - : 9 : (arg[i][0] == '\0') || (end == NULL) || (*end != '\0'))
+ + ]
1806 : : return -1;
1807 : 8 : val <<= 20;
1808 : 8 : socket_arg[i] = val;
1809 : : }
1810 : :
1811 : : return 0;
1812 : : }
1813 : :
1814 : : static int
1815 : 4 : eal_parse_vfio_intr(const char *mode)
1816 : : {
1817 : : struct internal_config *internal_conf =
1818 : 4 : eal_get_internal_configuration();
1819 : : static struct {
1820 : : const char *name;
1821 : : enum rte_intr_mode value;
1822 : : } map[] = {
1823 : : { "legacy", RTE_INTR_MODE_LEGACY },
1824 : : { "msi", RTE_INTR_MODE_MSI },
1825 : : { "msix", RTE_INTR_MODE_MSIX },
1826 : : };
1827 : :
1828 [ + + ]: 10 : for (size_t i = 0; i < RTE_DIM(map); i++) {
1829 [ + + ]: 9 : if (!strcmp(mode, map[i].name)) {
1830 : 3 : internal_conf->vfio_intr_mode = map[i].value;
1831 : 3 : return 0;
1832 : : }
1833 : : }
1834 : : return -1;
1835 : : }
1836 : :
1837 : : static int
1838 : 0 : eal_parse_vfio_vf_token(const char *vf_token)
1839 : : {
1840 : 0 : struct internal_config *cfg = eal_get_internal_configuration();
1841 : : rte_uuid_t uuid;
1842 : :
1843 [ # # ]: 0 : if (!rte_uuid_parse(vf_token, uuid)) {
1844 : 0 : rte_uuid_copy(cfg->vfio_vf_token, uuid);
1845 : 0 : return 0;
1846 : : }
1847 : :
1848 : : return -1;
1849 : : }
1850 : :
1851 : : static int
1852 : 2 : eal_parse_huge_worker_stack(const char *arg)
1853 : : {
1854 : : #ifdef RTE_EXEC_ENV_WINDOWS
1855 : : EAL_LOG(WARNING, "Cannot set worker stack size on Windows, parameter ignored");
1856 : : RTE_SET_USED(arg);
1857 : : #else
1858 : 2 : struct internal_config *cfg = eal_get_internal_configuration();
1859 : :
1860 [ + + - + ]: 3 : if (arg == NULL || arg[0] == '\0') {
1861 : : pthread_attr_t attr;
1862 : : int ret;
1863 : :
1864 [ - + ]: 1 : if (pthread_attr_init(&attr) != 0) {
1865 : 0 : EAL_LOG(ERR, "Could not retrieve default stack size");
1866 : 0 : return -1;
1867 : : }
1868 : 1 : ret = pthread_attr_getstacksize(&attr, &cfg->huge_worker_stack_size);
1869 : 1 : pthread_attr_destroy(&attr);
1870 [ - + ]: 1 : if (ret != 0) {
1871 : 0 : EAL_LOG(ERR, "Could not retrieve default stack size");
1872 : 0 : return -1;
1873 : : }
1874 : : } else {
1875 : : unsigned long stack_size;
1876 : : char *end;
1877 : :
1878 : 1 : errno = 0;
1879 : 1 : stack_size = strtoul(arg, &end, 10);
1880 [ + - + - : 1 : if (errno || end == NULL || stack_size == 0 ||
- + ]
1881 : : stack_size >= (size_t)-1 / 1024)
1882 : 0 : return -1;
1883 : :
1884 : 1 : cfg->huge_worker_stack_size = stack_size * 1024;
1885 : : }
1886 : :
1887 : 2 : EAL_LOG(DEBUG, "Each worker thread will use %zu kB of DPDK memory as stack",
1888 : : cfg->huge_worker_stack_size / 1024);
1889 : : #endif
1890 : 2 : return 0;
1891 : : }
1892 : :
1893 : : /* Parse the arguments given in the command line of the application */
1894 : : int
1895 : 238 : eal_parse_args(void)
1896 : : {
1897 : 238 : struct internal_config *int_cfg = eal_get_internal_configuration();
1898 : 238 : struct rte_config *rte_cfg = rte_eal_get_configuration();
1899 : 238 : bool remap_lcores = (args.remap_lcore_ids != NULL);
1900 : : struct arg_list_elem *arg;
1901 : : uint16_t lcore_id_base = 0;
1902 : :
1903 : : /* print version before anything else */
1904 : : /* since message is explicitly requested by user, we write message
1905 : : * at highest log level so it can always be seen even if info or
1906 : : * warning messages are disabled
1907 : : */
1908 [ + + ]: 238 : if (args.version)
1909 : 1 : EAL_LOG(CRIT, "RTE Version: '%s'", rte_version());
1910 : :
1911 : : /* parse the process type */
1912 [ + + ]: 238 : if (args.proc_type != NULL) {
1913 : 73 : int_cfg->process_type = eal_parse_proc_type(args.proc_type);
1914 [ + + ]: 73 : if (int_cfg->process_type == RTE_PROC_INVALID) {
1915 : 1 : EAL_LOG(ERR, "invalid process type: %s", args.proc_type);
1916 : 1 : return -1;
1917 : : }
1918 : : }
1919 : :
1920 : : /* device -a/-b/-vdev options*/
1921 [ + + ]: 250 : TAILQ_FOREACH(arg, &args.allow, next)
1922 [ + - ]: 13 : if (eal_option_device_add(RTE_DEVTYPE_ALLOWED, arg->arg) < 0)
1923 : : return -1;
1924 [ + + ]: 244 : TAILQ_FOREACH(arg, &args.block, next)
1925 [ + - ]: 7 : if (eal_option_device_add(RTE_DEVTYPE_BLOCKED, arg->arg) < 0)
1926 : : return -1;
1927 [ + + ]: 248 : TAILQ_FOREACH(arg, &args.vdev, next)
1928 [ + - ]: 11 : if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, arg->arg) < 0)
1929 : : return -1;
1930 : : /* driver loading options */
1931 [ - + ]: 237 : TAILQ_FOREACH(arg, &args.driver_path, next)
1932 [ # # ]: 0 : if (eal_plugin_add(arg->arg) < 0)
1933 : : return -1;
1934 : :
1935 [ - + - - ]: 237 : if (remap_lcores && args.remap_lcore_ids != (void *)1) {
1936 : : char *endp;
1937 : 0 : errno = 0;
1938 : 0 : lcore_id_base = (uint16_t)strtoul(args.remap_lcore_ids, &endp, 0);
1939 [ # # # # : 0 : if (errno != 0 || lcore_id_base >= RTE_MAX_LCORE || *endp != '\0') {
# # ]
1940 : 0 : EAL_LOG(ERR, "invalid lcore base id: %s", args.remap_lcore_ids);
1941 : 0 : return -1;
1942 : : }
1943 : : }
1944 : :
1945 : : /* parse the core list arguments */
1946 : : /* check if we are using manual mapping */
1947 [ + + ]: 237 : bool manual_lcore_mapping = (args.lcores != NULL) &&
1948 [ + + + + ]: 27 : ((strchr(args.lcores, '@') != NULL || strchr(args.lcores, '(') != NULL));
1949 : :
1950 [ - + ]: 237 : if (manual_lcore_mapping && remap_lcores) {
1951 : 0 : EAL_LOG(ERR, "cannot use '@' or core groupings '()' in lcore list when remapping lcores");
1952 : 0 : return -1;
1953 : : }
1954 : :
1955 : : /* First handle the special case where we have explicit core mapping/remapping */
1956 [ + + ]: 237 : if (manual_lcore_mapping) {
1957 [ + - ]: 9 : if (eal_parse_lcores(args.lcores) < 0) {
1958 : 9 : EAL_LOG(ERR, "invalid lcore mapping list: '%s'", args.lcores);
1959 : 9 : return -1;
1960 : : }
1961 : : } else {
1962 : : /* otherwise get a cpuset of the cores to be used and then handle that
1963 : : * taking mappings into account. Cpuset comes from either:
1964 : : * 1. coremask parameter
1965 : : * 2. core list parameter
1966 : : * 3. autodetecting current thread affinities
1967 : : */
1968 : : rte_cpuset_t cpuset;
1969 : : const char *cpuset_source;
1970 [ + + ]: 228 : if (args.coremask != NULL) {
1971 [ + + ]: 11 : if (rte_eal_parse_coremask(args.coremask, &cpuset, !remap_lcores) < 0) {
1972 : 1 : EAL_LOG(ERR, "invalid coremask syntax");
1973 : 14 : return -1;
1974 : : }
1975 : : cpuset_source = "coremask";
1976 [ + + ]: 217 : } else if (args.lcores != NULL) {
1977 [ + + ]: 18 : if (rte_argparse_parse_type(args.lcores,
1978 : : RTE_ARGPARSE_VALUE_TYPE_CORELIST, &cpuset) != 0) {
1979 : 11 : EAL_LOG(ERR, "Error parsing lcore list: '%s'", args.lcores);
1980 : 11 : return -1;
1981 : : }
1982 : : cpuset_source = "core list";
1983 : : } else {
1984 [ - + ]: 199 : if (rte_thread_get_affinity_by_id(rte_thread_self(), &cpuset) != 0) {
1985 : 0 : EAL_LOG(ERR, "Error querying current process thread affinities");
1986 : 0 : return -1;
1987 : : }
1988 : : cpuset_source = "affinity auto-detection";
1989 : : }
1990 : 216 : char *cpuset_str = eal_cpuset_to_str(&cpuset);
1991 [ + - ]: 216 : if (cpuset_str != NULL) {
1992 : 216 : EAL_LOG(DEBUG, "Cores selected by %s: %s", cpuset_source, cpuset_str);
1993 : 216 : free(cpuset_str);
1994 : : }
1995 [ + + ]: 216 : if (update_lcore_config(&cpuset, remap_lcores, lcore_id_base) < 0) {
1996 : 2 : char *available = available_cores();
1997 : :
1998 : 2 : EAL_LOG(ERR, "invalid coremask or core-list parameter, please check specified cores are part of %s",
1999 : : available);
2000 : 2 : free(available);
2001 : 2 : return -1;
2002 : : }
2003 : : }
2004 : :
2005 : : /* service core options */
2006 [ - + ]: 214 : if (args.service_coremask != NULL) {
2007 [ # # ]: 0 : if (eal_parse_service_coremask(args.service_coremask) < 0) {
2008 : 0 : EAL_LOG(ERR, "invalid service coremask: '%s'",
2009 : : args.service_coremask);
2010 : 0 : return -1;
2011 : : }
2012 [ - + ]: 214 : } else if (args.service_corelist != NULL) {
2013 [ # # ]: 0 : if (eal_parse_service_corelist(args.service_corelist) < 0) {
2014 : 0 : EAL_LOG(ERR, "invalid service core list: '%s'",
2015 : : args.service_corelist);
2016 : 0 : return -1;
2017 : : }
2018 : : }
2019 [ + + ]: 214 : if (args.main_lcore != NULL) {
2020 [ + + ]: 5 : if (eal_parse_main_lcore(args.main_lcore) < 0)
2021 : : return -1;
2022 : : } else {
2023 : : /* default main lcore is the first one */
2024 : 209 : rte_cfg->main_lcore = rte_get_next_lcore(-1, 0, 0);
2025 [ - + ]: 209 : if (rte_cfg->main_lcore >= RTE_MAX_LCORE) {
2026 : 0 : EAL_LOG(ERR, "Main lcore is not enabled for DPDK");
2027 : 0 : return -1;
2028 : : }
2029 : : }
2030 : :
2031 : : /* memory options */
2032 [ + + ]: 211 : if (args.memory_size != NULL) {
2033 : 109 : int_cfg->memory = atoi(args.memory_size);
2034 : 109 : int_cfg->memory *= 1024ULL;
2035 : 109 : int_cfg->memory *= 1024ULL;
2036 : : }
2037 [ + + ]: 211 : if (args.memory_channels != NULL) {
2038 : 3 : int_cfg->force_nchannel = atoi(args.memory_channels);
2039 [ + + ]: 3 : if (int_cfg->force_nchannel == 0) {
2040 : 2 : EAL_LOG(ERR, "invalid memory channel parameter");
2041 : 2 : return -1;
2042 : : }
2043 : : }
2044 [ + + ]: 209 : if (args.memory_ranks != NULL) {
2045 : 5 : int_cfg->force_nrank = atoi(args.memory_ranks);
2046 [ + + + + ]: 5 : if (int_cfg->force_nrank == 0 || int_cfg->force_nrank > 16) {
2047 : 4 : EAL_LOG(ERR, "invalid memory rank parameter");
2048 : 4 : return -1;
2049 : : }
2050 : : }
2051 [ + + ]: 205 : if (args.no_huge) {
2052 : 101 : int_cfg->no_hugetlbfs = 1;
2053 : : /* no-huge is legacy mem */
2054 : 101 : int_cfg->legacy_mem = 1;
2055 : : }
2056 [ + + ]: 205 : if (args.in_memory) {
2057 : 3 : int_cfg->in_memory = 1;
2058 : : /* in-memory is a superset of noshconf and huge-unlink */
2059 : 3 : int_cfg->no_shconf = 1;
2060 : 3 : int_cfg->hugepage_file.unlink_before_mapping = true;
2061 : : }
2062 [ + + ]: 205 : if (args.legacy_mem) {
2063 : 2 : int_cfg->legacy_mem = 1;
2064 [ - + - - ]: 2 : if (args.memory_size == NULL && args.numa_mem == NULL)
2065 : 0 : EAL_LOG(NOTICE, "Static memory layout is selected, amount of reserved memory can be adjusted with -m or --socket-mem");
2066 : : }
2067 [ + + ]: 205 : if (args.single_file_segments)
2068 : 1 : int_cfg->single_file_segments = 1;
2069 [ + + ]: 205 : if (args.huge_dir != NULL) {
2070 [ - + ]: 5 : if (strlen(args.huge_dir) < 1) {
2071 : 0 : EAL_LOG(ERR, "Invalid hugepage dir parameter");
2072 : 0 : return -1;
2073 : : }
2074 : 5 : free(int_cfg->hugepage_dir); /* free old hugepage dir */
2075 : 5 : int_cfg->hugepage_dir = strdup(args.huge_dir);
2076 [ - + ]: 5 : if (int_cfg->hugepage_dir == NULL) {
2077 : 0 : EAL_LOG(ERR, "failed to allocate memory for hugepage dir parameter");
2078 : 0 : return -1;
2079 : : }
2080 : : }
2081 [ + + ]: 205 : if (args.file_prefix != NULL) {
2082 [ - + ]: 82 : if (strlen(args.file_prefix) < 1) {
2083 : 0 : EAL_LOG(ERR, "Invalid file prefix parameter");
2084 : 0 : return -1;
2085 : : }
2086 [ - + ]: 82 : if (strchr(args.file_prefix, '%') != NULL) {
2087 : 0 : EAL_LOG(ERR, "Invalid char, '%%', in file_prefix parameter");
2088 : 0 : return -1;
2089 : : }
2090 : 82 : free(int_cfg->hugefile_prefix); /* free old file prefix */
2091 : 82 : int_cfg->hugefile_prefix = strdup(args.file_prefix);
2092 [ - + ]: 82 : if (int_cfg->hugefile_prefix == NULL) {
2093 : 0 : EAL_LOG(ERR, "failed to allocate memory for file prefix parameter");
2094 : 0 : return -1;
2095 : : }
2096 : : }
2097 [ + + ]: 205 : if (args.huge_unlink != NULL) {
2098 [ - + ]: 1 : if (args.huge_unlink == (void *)1)
2099 : 0 : args.huge_unlink = NULL;
2100 [ - + ]: 1 : if (eal_parse_huge_unlink(args.huge_unlink, &int_cfg->hugepage_file) < 0) {
2101 : 0 : EAL_LOG(ERR, "invalid huge-unlink parameter");
2102 : 0 : return -1;
2103 : : }
2104 : : }
2105 [ + + ]: 205 : if (args.numa_mem != NULL) {
2106 [ + + ]: 7 : if (eal_parse_socket_arg(args.numa_mem, int_cfg->numa_mem) < 0) {
2107 : 4 : EAL_LOG(ERR, "invalid numa-mem parameter: '%s'", args.numa_mem);
2108 : 4 : return -1;
2109 : : }
2110 : 3 : int_cfg->force_numa = 1;
2111 : : }
2112 [ - + ]: 201 : if (args.numa_limit != NULL) {
2113 [ # # ]: 0 : if (eal_parse_socket_arg(args.numa_limit, int_cfg->numa_limit) < 0) {
2114 : 0 : EAL_LOG(ERR, "invalid numa-limit parameter: '%s'", args.numa_limit);
2115 : 0 : return -1;
2116 : : }
2117 : 0 : int_cfg->force_numa_limits = 1;
2118 : : }
2119 : :
2120 : : /* tracing settings, not supported on windows */
2121 : : #ifdef RTE_EXEC_ENV_WINDOWS
2122 : : if (!TAILQ_EMPTY(&args.trace) ||
2123 : : args.trace_dir != NULL ||
2124 : : args.trace_bufsz != NULL ||
2125 : : args.trace_mode != NULL)
2126 : : EAL_LOG(WARNING, "Tracing is not supported on Windows, ignoring tracing parameters");
2127 : : #else
2128 [ + + ]: 202 : TAILQ_FOREACH(arg, &args.trace, next) {
2129 [ - + ]: 1 : if (eal_trace_args_save(arg->arg) < 0) {
2130 : 0 : EAL_LOG(ERR, "invalid trace parameter, '%s'", arg->arg);
2131 : 0 : return -1;
2132 : : }
2133 : : }
2134 [ + + ]: 201 : if (args.trace_dir != NULL) {
2135 [ - + ]: 1 : if (eal_trace_dir_args_save(args.trace_dir) < 0) {
2136 : 0 : EAL_LOG(ERR, "invalid trace directory, '%s'", args.trace_dir);
2137 : 0 : return -1;
2138 : : }
2139 : : }
2140 [ - + ]: 201 : if (args.trace_bufsz != NULL) {
2141 [ # # ]: 0 : if (eal_trace_bufsz_args_save(args.trace_bufsz) < 0) {
2142 : 0 : EAL_LOG(ERR, "invalid trace buffer size, '%s'", args.trace_bufsz);
2143 : 0 : return -1;
2144 : : }
2145 : : }
2146 [ - + ]: 201 : if (args.trace_mode != NULL) {
2147 [ # # ]: 0 : if (eal_trace_mode_args_save(args.trace_mode) < 0) {
2148 : 0 : EAL_LOG(ERR, "invalid trace mode, '%s'", args.trace_mode);
2149 : 0 : return -1;
2150 : : }
2151 : : }
2152 : : #endif
2153 : :
2154 : : /* simple flag settings
2155 : : * Only set these to 1, as we don't want to set them to 0 in case
2156 : : * other options above have already set them.
2157 : : */
2158 [ + + ]: 201 : if (args.no_pci)
2159 : 1 : int_cfg->no_pci = 1;
2160 [ + + ]: 201 : if (args.no_hpet)
2161 : 1 : int_cfg->no_hpet = 1;
2162 [ - + ]: 201 : if (args.vmware_tsc_map)
2163 : 0 : int_cfg->vmware_tsc_map = 1;
2164 [ + + ]: 201 : if (args.no_shconf)
2165 : 4 : int_cfg->no_shconf = 1;
2166 [ - + ]: 201 : if (args.no_telemetry)
2167 : 0 : int_cfg->no_telemetry = 1;
2168 [ - + ]: 201 : if (args.match_allocations)
2169 : 0 : int_cfg->match_allocations = 1;
2170 [ + + ]: 201 : if (args.create_uio_dev)
2171 : 1 : int_cfg->create_uio_dev = 1;
2172 : :
2173 : : /* other misc settings */
2174 [ - + ]: 201 : if (args.iova_mode != NULL) {
2175 [ # # ]: 0 : if (eal_parse_iova_mode(args.iova_mode) < 0) {
2176 : 0 : EAL_LOG(ERR, "invalid iova mode parameter '%s'", args.iova_mode);
2177 : 0 : return -1;
2178 : : }
2179 : : };
2180 [ + + ]: 201 : if (args.base_virtaddr != NULL) {
2181 [ - + ]: 1 : if (eal_parse_base_virtaddr(args.base_virtaddr) < 0) {
2182 : 0 : EAL_LOG(ERR, "invalid base virtaddr '%s'", args.base_virtaddr);
2183 : 0 : return -1;
2184 : : }
2185 : : }
2186 [ - + ]: 201 : if (args.force_max_simd_bitwidth != NULL) {
2187 [ # # ]: 0 : if (eal_parse_simd_bitwidth(args.force_max_simd_bitwidth) < 0) {
2188 : 0 : EAL_LOG(ERR, "invalid SIMD bitwidth parameter '%s'",
2189 : : args.force_max_simd_bitwidth);
2190 : 0 : return -1;
2191 : : }
2192 : : }
2193 [ + + ]: 201 : if (args.vfio_intr != NULL) {
2194 [ + + ]: 4 : if (eal_parse_vfio_intr(args.vfio_intr) < 0) {
2195 : 1 : EAL_LOG(ERR, "invalid vfio interrupt parameter: '%s'", args.vfio_intr);
2196 : 1 : return -1;
2197 : : }
2198 : : }
2199 [ - + ]: 200 : if (args.vfio_vf_token != NULL) {
2200 [ # # ]: 0 : if (eal_parse_vfio_vf_token(args.vfio_vf_token) < 0) {
2201 : 0 : EAL_LOG(ERR, "invalid vfio vf token parameter: '%s'", args.vfio_vf_token);
2202 : 0 : return -1;
2203 : : }
2204 : : }
2205 : :
2206 [ + + ]: 200 : if (args.huge_worker_stack != NULL) {
2207 [ + + ]: 2 : if (args.huge_worker_stack == (void *)1)
2208 : 1 : args.huge_worker_stack = NULL;
2209 [ - + ]: 2 : if (eal_parse_huge_worker_stack(args.huge_worker_stack) < 0) {
2210 : 0 : EAL_LOG(ERR, "invalid huge worker stack parameter");
2211 : 0 : return -1;
2212 : : }
2213 : : }
2214 [ - + ]: 200 : if (args.mbuf_pool_ops_name != NULL) {
2215 : 0 : free(int_cfg->user_mbuf_pool_ops_name); /* free old ops name */
2216 : 0 : int_cfg->user_mbuf_pool_ops_name = strdup(args.mbuf_pool_ops_name);
2217 [ # # ]: 0 : if (int_cfg->user_mbuf_pool_ops_name == NULL) {
2218 : 0 : EAL_LOG(ERR, "failed to allocate memory for mbuf pool ops name parameter");
2219 : 0 : return -1;
2220 : : }
2221 [ # # ]: 0 : if (strlen(int_cfg->user_mbuf_pool_ops_name) < 1) {
2222 : 0 : EAL_LOG(ERR, "Invalid mbuf pool ops name parameter");
2223 : 0 : return -1;
2224 : : }
2225 : : }
2226 : :
2227 : : #ifndef RTE_EXEC_ENV_WINDOWS
2228 : : /* create runtime data directory. In no_shconf mode, skip any errors */
2229 [ - + ]: 200 : if (eal_create_runtime_dir() < 0) {
2230 [ # # ]: 0 : if (int_cfg->no_shconf == 0) {
2231 : 0 : EAL_LOG(ERR, "Cannot create runtime directory");
2232 : 0 : return -1;
2233 : : }
2234 : 0 : EAL_LOG(WARNING, "No DPDK runtime directory created");
2235 : : }
2236 : : #endif
2237 : :
2238 [ - + ]: 200 : if (eal_adjust_config(int_cfg) != 0) {
2239 : 0 : EAL_LOG(ERR, "Invalid configuration");
2240 : 0 : return -1;
2241 : : }
2242 : :
2243 : : return 0;
2244 : : }
2245 : :
2246 : : static void
2247 : 200 : compute_ctrl_threads_cpuset(struct internal_config *internal_cfg)
2248 : : {
2249 : 200 : rte_cpuset_t *cpuset = &internal_cfg->ctrl_cpuset;
2250 : : rte_cpuset_t default_set;
2251 : : unsigned int lcore_id;
2252 : :
2253 [ + + ]: 25800 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2254 [ + + ]: 25600 : if (rte_lcore_has_role(lcore_id, ROLE_OFF))
2255 : 25276 : continue;
2256 [ + + ]: 5508 : RTE_CPU_OR(cpuset, cpuset, &lcore_config[lcore_id].cpuset);
2257 : : }
2258 [ + + + + ]: 208200 : RTE_CPU_NOT(cpuset, cpuset);
2259 : :
2260 [ - + ]: 200 : if (rte_thread_get_affinity_by_id(rte_thread_self(), &default_set) != 0)
2261 : 0 : CPU_ZERO(&default_set);
2262 : :
2263 [ + + ]: 3400 : RTE_CPU_AND(cpuset, cpuset, &default_set);
2264 : :
2265 : : /* if no remaining cpu, use main lcore cpu affinity */
2266 [ + - ]: 200 : if (!CPU_COUNT(cpuset)) {
2267 : 200 : memcpy(cpuset, &lcore_config[rte_get_main_lcore()].cpuset,
2268 : : sizeof(*cpuset));
2269 : : }
2270 : :
2271 : : /* log the computed control thread cpuset for debugging */
2272 : 200 : char *cpuset_str = eal_cpuset_to_str(cpuset);
2273 [ + - ]: 200 : if (cpuset_str != NULL) {
2274 : 200 : EAL_LOG(DEBUG, "Control threads will use cores: %s", cpuset_str);
2275 : 200 : free(cpuset_str);
2276 : : }
2277 : 200 : }
2278 : :
2279 : : int
2280 : 246 : eal_cleanup_config(struct internal_config *internal_cfg)
2281 : : {
2282 : 246 : free(internal_cfg->hugefile_prefix);
2283 : 246 : free(internal_cfg->hugepage_dir);
2284 : 246 : free(internal_cfg->user_mbuf_pool_ops_name);
2285 : :
2286 : 246 : return 0;
2287 : : }
2288 : :
2289 : : int
2290 : 200 : eal_adjust_config(struct internal_config *internal_cfg)
2291 : : {
2292 : : int i;
2293 : :
2294 [ + + ]: 200 : if (internal_cfg->process_type == RTE_PROC_AUTO)
2295 : 3 : internal_cfg->process_type = eal_proc_type_detect();
2296 : :
2297 : 200 : compute_ctrl_threads_cpuset(internal_cfg);
2298 : :
2299 : : /* if no memory amounts were requested, this will result in 0 and
2300 : : * will be overridden later, right after eal_hugepage_info_init() */
2301 [ + + ]: 6600 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
2302 : 6400 : internal_cfg->memory += internal_cfg->numa_mem[i];
2303 : :
2304 : 200 : return 0;
2305 : : }
2306 : :
2307 : : RTE_EXPORT_SYMBOL(rte_vect_get_max_simd_bitwidth)
2308 : : uint16_t
2309 : 66472 : rte_vect_get_max_simd_bitwidth(void)
2310 : : {
2311 : : const struct internal_config *internal_conf =
2312 : 66472 : eal_get_internal_configuration();
2313 : 66472 : return internal_conf->max_simd_bitwidth.bitwidth;
2314 : : }
2315 : :
2316 : : RTE_EXPORT_SYMBOL(rte_vect_set_max_simd_bitwidth)
2317 : : int
2318 : 0 : rte_vect_set_max_simd_bitwidth(uint16_t bitwidth)
2319 : : {
2320 : : struct internal_config *internal_conf =
2321 : 0 : eal_get_internal_configuration();
2322 [ # # ]: 0 : if (internal_conf->max_simd_bitwidth.forced) {
2323 : 0 : EAL_LOG(NOTICE, "Cannot set max SIMD bitwidth - user runtime override enabled");
2324 : 0 : return -EPERM;
2325 : : }
2326 : :
2327 [ # # # # ]: 0 : if (bitwidth < RTE_VECT_SIMD_DISABLED || !rte_is_power_of_2(bitwidth)) {
2328 : 0 : EAL_LOG(ERR, "Invalid bitwidth value!");
2329 : 0 : return -EINVAL;
2330 : : }
2331 : 0 : internal_conf->max_simd_bitwidth.bitwidth = bitwidth;
2332 : 0 : return 0;
2333 : : }
|