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