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