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