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