]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2010-2014 Intel Corporation. | |
3 | * Copyright(c) 2014 6WIND S.A. | |
7c673cae FG |
4 | */ |
5 | ||
6 | #include <stdlib.h> | |
7 | #include <unistd.h> | |
8 | #include <string.h> | |
9 | #include <syslog.h> | |
10 | #include <ctype.h> | |
11 | #include <limits.h> | |
12 | #include <errno.h> | |
13 | #include <getopt.h> | |
14 | #include <dlfcn.h> | |
15 | #include <sys/types.h> | |
16 | #include <sys/stat.h> | |
17 | #include <dirent.h> | |
18 | ||
9f95a23c | 19 | #include <rte_string_fns.h> |
7c673cae FG |
20 | #include <rte_eal.h> |
21 | #include <rte_log.h> | |
22 | #include <rte_lcore.h> | |
9f95a23c | 23 | #include <rte_tailq.h> |
7c673cae FG |
24 | #include <rte_version.h> |
25 | #include <rte_devargs.h> | |
26 | #include <rte_memcpy.h> | |
27 | ||
28 | #include "eal_internal_cfg.h" | |
29 | #include "eal_options.h" | |
30 | #include "eal_filesystem.h" | |
9f95a23c | 31 | #include "eal_private.h" |
7c673cae FG |
32 | |
33 | #define BITS_PER_HEX 4 | |
9f95a23c TL |
34 | #define LCORE_OPT_LST 1 |
35 | #define LCORE_OPT_MSK 2 | |
36 | #define LCORE_OPT_MAP 3 | |
7c673cae FG |
37 | |
38 | const char | |
39 | eal_short_options[] = | |
40 | "b:" /* pci-blacklist */ | |
41 | "c:" /* coremask */ | |
9f95a23c | 42 | "s:" /* service coremask */ |
7c673cae FG |
43 | "d:" /* driver */ |
44 | "h" /* help */ | |
45 | "l:" /* corelist */ | |
9f95a23c | 46 | "S:" /* service corelist */ |
7c673cae FG |
47 | "m:" /* memory size */ |
48 | "n:" /* memory channels */ | |
49 | "r:" /* memory ranks */ | |
50 | "v" /* version */ | |
51 | "w:" /* pci-whitelist */ | |
52 | ; | |
53 | ||
54 | const struct option | |
55 | eal_long_options[] = { | |
56 | {OPT_BASE_VIRTADDR, 1, NULL, OPT_BASE_VIRTADDR_NUM }, | |
57 | {OPT_CREATE_UIO_DEV, 0, NULL, OPT_CREATE_UIO_DEV_NUM }, | |
58 | {OPT_FILE_PREFIX, 1, NULL, OPT_FILE_PREFIX_NUM }, | |
59 | {OPT_HELP, 0, NULL, OPT_HELP_NUM }, | |
60 | {OPT_HUGE_DIR, 1, NULL, OPT_HUGE_DIR_NUM }, | |
61 | {OPT_HUGE_UNLINK, 0, NULL, OPT_HUGE_UNLINK_NUM }, | |
9f95a23c | 62 | {OPT_IOVA_MODE, 1, NULL, OPT_IOVA_MODE_NUM }, |
7c673cae FG |
63 | {OPT_LCORES, 1, NULL, OPT_LCORES_NUM }, |
64 | {OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM }, | |
65 | {OPT_MASTER_LCORE, 1, NULL, OPT_MASTER_LCORE_NUM }, | |
9f95a23c | 66 | {OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM}, |
7c673cae FG |
67 | {OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM }, |
68 | {OPT_NO_HUGE, 0, NULL, OPT_NO_HUGE_NUM }, | |
69 | {OPT_NO_PCI, 0, NULL, OPT_NO_PCI_NUM }, | |
70 | {OPT_NO_SHCONF, 0, NULL, OPT_NO_SHCONF_NUM }, | |
9f95a23c | 71 | {OPT_IN_MEMORY, 0, NULL, OPT_IN_MEMORY_NUM }, |
7c673cae FG |
72 | {OPT_PCI_BLACKLIST, 1, NULL, OPT_PCI_BLACKLIST_NUM }, |
73 | {OPT_PCI_WHITELIST, 1, NULL, OPT_PCI_WHITELIST_NUM }, | |
74 | {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, | |
75 | {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, | |
9f95a23c | 76 | {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, |
7c673cae FG |
77 | {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, |
78 | {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, | |
79 | {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, | |
80 | {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, | |
9f95a23c TL |
81 | {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM }, |
82 | {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM}, | |
83 | {OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM}, | |
7c673cae FG |
84 | {0, 0, NULL, 0 } |
85 | }; | |
86 | ||
87 | TAILQ_HEAD(shared_driver_list, shared_driver); | |
88 | ||
89 | /* Definition for shared object drivers. */ | |
90 | struct shared_driver { | |
91 | TAILQ_ENTRY(shared_driver) next; | |
92 | ||
93 | char name[PATH_MAX]; | |
94 | void* lib_handle; | |
95 | }; | |
96 | ||
97 | /* List of external loadable drivers */ | |
98 | static struct shared_driver_list solib_list = | |
99 | TAILQ_HEAD_INITIALIZER(solib_list); | |
100 | ||
101 | /* Default path of external loadable drivers */ | |
102 | static const char *default_solib_dir = RTE_EAL_PMD_PATH; | |
103 | ||
104 | /* | |
105 | * Stringified version of solib path used by dpdk-pmdinfo.py | |
106 | * Note: PLEASE DO NOT ALTER THIS without making a corresponding | |
11fdf7f2 | 107 | * change to usertools/dpdk-pmdinfo.py |
7c673cae FG |
108 | */ |
109 | static const char dpdk_solib_path[] __attribute__((used)) = | |
110 | "DPDK_PLUGIN_PATH=" RTE_EAL_PMD_PATH; | |
111 | ||
9f95a23c TL |
112 | TAILQ_HEAD(device_option_list, device_option); |
113 | ||
114 | struct device_option { | |
115 | TAILQ_ENTRY(device_option) next; | |
116 | ||
117 | enum rte_devtype type; | |
118 | char arg[]; | |
119 | }; | |
120 | ||
121 | static struct device_option_list devopt_list = | |
122 | TAILQ_HEAD_INITIALIZER(devopt_list); | |
7c673cae FG |
123 | |
124 | static int master_lcore_parsed; | |
125 | static int mem_parsed; | |
11fdf7f2 | 126 | static int core_parsed; |
7c673cae | 127 | |
9f95a23c TL |
128 | static int |
129 | eal_option_device_add(enum rte_devtype type, const char *optarg) | |
130 | { | |
131 | struct device_option *devopt; | |
132 | size_t optlen; | |
133 | int ret; | |
134 | ||
135 | optlen = strlen(optarg) + 1; | |
136 | devopt = calloc(1, sizeof(*devopt) + optlen); | |
137 | if (devopt == NULL) { | |
138 | RTE_LOG(ERR, EAL, "Unable to allocate device option\n"); | |
139 | return -ENOMEM; | |
140 | } | |
141 | ||
142 | devopt->type = type; | |
143 | ret = strlcpy(devopt->arg, optarg, optlen); | |
144 | if (ret < 0) { | |
145 | RTE_LOG(ERR, EAL, "Unable to copy device option\n"); | |
146 | free(devopt); | |
147 | return -EINVAL; | |
148 | } | |
149 | TAILQ_INSERT_TAIL(&devopt_list, devopt, next); | |
150 | return 0; | |
151 | } | |
152 | ||
153 | int | |
154 | eal_option_device_parse(void) | |
155 | { | |
156 | struct device_option *devopt; | |
157 | void *tmp; | |
158 | int ret = 0; | |
159 | ||
160 | TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) { | |
161 | if (ret == 0) { | |
162 | ret = rte_devargs_add(devopt->type, devopt->arg); | |
163 | if (ret) | |
164 | RTE_LOG(ERR, EAL, "Unable to parse device '%s'\n", | |
165 | devopt->arg); | |
166 | } | |
167 | TAILQ_REMOVE(&devopt_list, devopt, next); | |
168 | free(devopt); | |
169 | } | |
170 | return ret; | |
171 | } | |
172 | ||
173 | const char * | |
174 | eal_get_hugefile_prefix(void) | |
175 | { | |
176 | if (internal_config.hugefile_prefix != NULL) | |
177 | return internal_config.hugefile_prefix; | |
178 | return HUGEFILE_PREFIX_DEFAULT; | |
179 | } | |
180 | ||
7c673cae FG |
181 | void |
182 | eal_reset_internal_config(struct internal_config *internal_cfg) | |
183 | { | |
184 | int i; | |
185 | ||
186 | internal_cfg->memory = 0; | |
187 | internal_cfg->force_nrank = 0; | |
188 | internal_cfg->force_nchannel = 0; | |
9f95a23c | 189 | internal_cfg->hugefile_prefix = NULL; |
7c673cae FG |
190 | internal_cfg->hugepage_dir = NULL; |
191 | internal_cfg->force_sockets = 0; | |
192 | /* zero out the NUMA config */ | |
193 | for (i = 0; i < RTE_MAX_NUMA_NODES; i++) | |
194 | internal_cfg->socket_mem[i] = 0; | |
9f95a23c TL |
195 | internal_cfg->force_socket_limits = 0; |
196 | /* zero out the NUMA limits config */ | |
197 | for (i = 0; i < RTE_MAX_NUMA_NODES; i++) | |
198 | internal_cfg->socket_limit[i] = 0; | |
7c673cae | 199 | /* zero out hugedir descriptors */ |
9f95a23c TL |
200 | for (i = 0; i < MAX_HUGEPAGE_SIZES; i++) { |
201 | memset(&internal_cfg->hugepage_info[i], 0, | |
202 | sizeof(internal_cfg->hugepage_info[0])); | |
7c673cae | 203 | internal_cfg->hugepage_info[i].lock_descriptor = -1; |
9f95a23c | 204 | } |
7c673cae FG |
205 | internal_cfg->base_virtaddr = 0; |
206 | ||
207 | internal_cfg->syslog_facility = LOG_DAEMON; | |
7c673cae | 208 | |
7c673cae FG |
209 | /* if set to NONE, interrupt mode is determined automatically */ |
210 | internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; | |
211 | ||
212 | #ifdef RTE_LIBEAL_USE_HPET | |
213 | internal_cfg->no_hpet = 0; | |
214 | #else | |
215 | internal_cfg->no_hpet = 1; | |
216 | #endif | |
217 | internal_cfg->vmware_tsc_map = 0; | |
218 | internal_cfg->create_uio_dev = 0; | |
9f95a23c TL |
219 | internal_cfg->iova_mode = RTE_IOVA_DC; |
220 | internal_cfg->user_mbuf_pool_ops_name = NULL; | |
221 | CPU_ZERO(&internal_cfg->ctrl_cpuset); | |
222 | internal_cfg->init_complete = 0; | |
7c673cae FG |
223 | } |
224 | ||
225 | static int | |
226 | eal_plugin_add(const char *path) | |
227 | { | |
228 | struct shared_driver *solib; | |
229 | ||
230 | solib = malloc(sizeof(*solib)); | |
231 | if (solib == NULL) { | |
232 | RTE_LOG(ERR, EAL, "malloc(solib) failed\n"); | |
233 | return -1; | |
234 | } | |
235 | memset(solib, 0, sizeof(*solib)); | |
9f95a23c | 236 | strlcpy(solib->name, path, PATH_MAX-1); |
7c673cae FG |
237 | solib->name[PATH_MAX-1] = 0; |
238 | TAILQ_INSERT_TAIL(&solib_list, solib, next); | |
239 | ||
240 | return 0; | |
241 | } | |
242 | ||
243 | static int | |
244 | eal_plugindir_init(const char *path) | |
245 | { | |
246 | DIR *d = NULL; | |
247 | struct dirent *dent = NULL; | |
248 | char sopath[PATH_MAX]; | |
249 | ||
250 | if (path == NULL || *path == '\0') | |
251 | return 0; | |
252 | ||
253 | d = opendir(path); | |
254 | if (d == NULL) { | |
255 | RTE_LOG(ERR, EAL, "failed to open directory %s: %s\n", | |
256 | path, strerror(errno)); | |
257 | return -1; | |
258 | } | |
259 | ||
260 | while ((dent = readdir(d)) != NULL) { | |
261 | struct stat sb; | |
262 | ||
263 | snprintf(sopath, PATH_MAX-1, "%s/%s", path, dent->d_name); | |
264 | sopath[PATH_MAX-1] = 0; | |
265 | ||
266 | if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode))) | |
267 | continue; | |
268 | ||
269 | if (eal_plugin_add(sopath) == -1) | |
270 | break; | |
271 | } | |
272 | ||
273 | closedir(d); | |
274 | /* XXX this ignores failures from readdir() itself */ | |
275 | return (dent == NULL) ? 0 : -1; | |
276 | } | |
277 | ||
278 | int | |
279 | eal_plugins_init(void) | |
280 | { | |
281 | struct shared_driver *solib = NULL; | |
9f95a23c | 282 | struct stat sb; |
7c673cae | 283 | |
9f95a23c TL |
284 | if (*default_solib_dir != '\0' && stat(default_solib_dir, &sb) == 0 && |
285 | S_ISDIR(sb.st_mode)) | |
7c673cae FG |
286 | eal_plugin_add(default_solib_dir); |
287 | ||
288 | TAILQ_FOREACH(solib, &solib_list, next) { | |
7c673cae FG |
289 | |
290 | if (stat(solib->name, &sb) == 0 && S_ISDIR(sb.st_mode)) { | |
291 | if (eal_plugindir_init(solib->name) == -1) { | |
292 | RTE_LOG(ERR, EAL, | |
293 | "Cannot init plugin directory %s\n", | |
294 | solib->name); | |
295 | return -1; | |
296 | } | |
297 | } else { | |
298 | RTE_LOG(DEBUG, EAL, "open shared lib %s\n", | |
299 | solib->name); | |
300 | solib->lib_handle = dlopen(solib->name, RTLD_NOW); | |
301 | if (solib->lib_handle == NULL) { | |
302 | RTE_LOG(ERR, EAL, "%s\n", dlerror()); | |
303 | return -1; | |
304 | } | |
305 | } | |
306 | ||
307 | } | |
308 | return 0; | |
309 | } | |
310 | ||
311 | /* | |
312 | * Parse the coremask given as argument (hexadecimal string) and fill | |
313 | * the global configuration (core role and core count) with the parsed | |
314 | * value. | |
315 | */ | |
316 | static int xdigit2val(unsigned char c) | |
317 | { | |
318 | int val; | |
319 | ||
320 | if (isdigit(c)) | |
321 | val = c - '0'; | |
322 | else if (isupper(c)) | |
323 | val = c - 'A' + 10; | |
324 | else | |
325 | val = c - 'a' + 10; | |
326 | return val; | |
327 | } | |
328 | ||
329 | static int | |
9f95a23c | 330 | eal_parse_service_coremask(const char *coremask) |
7c673cae FG |
331 | { |
332 | struct rte_config *cfg = rte_eal_get_configuration(); | |
333 | int i, j, idx = 0; | |
9f95a23c | 334 | unsigned int count = 0; |
7c673cae FG |
335 | char c; |
336 | int val; | |
9f95a23c | 337 | uint32_t taken_lcore_count = 0; |
7c673cae FG |
338 | |
339 | if (coremask == NULL) | |
340 | return -1; | |
341 | /* Remove all blank characters ahead and after . | |
342 | * Remove 0x/0X if exists. | |
343 | */ | |
344 | while (isblank(*coremask)) | |
345 | coremask++; | |
346 | if (coremask[0] == '0' && ((coremask[1] == 'x') | |
347 | || (coremask[1] == 'X'))) | |
348 | coremask += 2; | |
349 | i = strlen(coremask); | |
350 | while ((i > 0) && isblank(coremask[i - 1])) | |
351 | i--; | |
9f95a23c | 352 | |
7c673cae FG |
353 | if (i == 0) |
354 | return -1; | |
355 | ||
356 | for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) { | |
357 | c = coremask[i]; | |
358 | if (isxdigit(c) == 0) { | |
359 | /* invalid characters */ | |
360 | return -1; | |
361 | } | |
362 | val = xdigit2val(c); | |
9f95a23c TL |
363 | for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; |
364 | j++, idx++) { | |
7c673cae | 365 | if ((1 << j) & val) { |
9f95a23c TL |
366 | /* handle master lcore already parsed */ |
367 | uint32_t lcore = idx; | |
368 | if (master_lcore_parsed && | |
369 | cfg->master_lcore == lcore) { | |
370 | RTE_LOG(ERR, EAL, | |
371 | "lcore %u is master lcore, cannot use as service core\n", | |
372 | idx); | |
373 | return -1; | |
374 | } | |
375 | ||
7c673cae | 376 | if (!lcore_config[idx].detected) { |
9f95a23c TL |
377 | RTE_LOG(ERR, EAL, |
378 | "lcore %u unavailable\n", idx); | |
7c673cae FG |
379 | return -1; |
380 | } | |
9f95a23c TL |
381 | |
382 | if (cfg->lcore_role[idx] == ROLE_RTE) | |
383 | taken_lcore_count++; | |
384 | ||
385 | lcore_config[idx].core_role = ROLE_SERVICE; | |
7c673cae | 386 | count++; |
7c673cae FG |
387 | } |
388 | } | |
389 | } | |
9f95a23c | 390 | |
7c673cae FG |
391 | for (; i >= 0; i--) |
392 | if (coremask[i] != '0') | |
393 | return -1; | |
9f95a23c TL |
394 | |
395 | for (; idx < RTE_MAX_LCORE; idx++) | |
7c673cae | 396 | lcore_config[idx].core_index = -1; |
9f95a23c TL |
397 | |
398 | if (count == 0) | |
399 | return -1; | |
400 | ||
401 | if (core_parsed && taken_lcore_count != count) { | |
402 | RTE_LOG(WARNING, EAL, | |
403 | "Not all service cores are in the coremask. " | |
404 | "Please ensure -c or -l includes service cores\n"); | |
405 | } | |
406 | ||
407 | cfg->service_lcore_count = count; | |
408 | return 0; | |
409 | } | |
410 | ||
411 | static int | |
412 | eal_service_cores_parsed(void) | |
413 | { | |
414 | int idx; | |
415 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) { | |
416 | if (lcore_config[idx].core_role == ROLE_SERVICE) | |
417 | return 1; | |
418 | } | |
419 | return 0; | |
420 | } | |
421 | ||
422 | static int | |
423 | update_lcore_config(int *cores) | |
424 | { | |
425 | struct rte_config *cfg = rte_eal_get_configuration(); | |
426 | unsigned int count = 0; | |
427 | unsigned int i; | |
428 | int ret = 0; | |
429 | ||
430 | for (i = 0; i < RTE_MAX_LCORE; i++) { | |
431 | if (cores[i] != -1) { | |
432 | if (!lcore_config[i].detected) { | |
433 | RTE_LOG(ERR, EAL, "lcore %u unavailable\n", i); | |
434 | ret = -1; | |
435 | continue; | |
436 | } | |
437 | cfg->lcore_role[i] = ROLE_RTE; | |
438 | count++; | |
439 | } else { | |
440 | cfg->lcore_role[i] = ROLE_OFF; | |
441 | } | |
442 | lcore_config[i].core_index = cores[i]; | |
443 | } | |
444 | if (!ret) | |
445 | cfg->lcore_count = count; | |
446 | return ret; | |
447 | } | |
448 | ||
449 | static int | |
450 | eal_parse_coremask(const char *coremask, int *cores) | |
451 | { | |
452 | unsigned count = 0; | |
453 | int i, j, idx; | |
454 | int val; | |
455 | char c; | |
456 | ||
457 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) | |
458 | cores[idx] = -1; | |
459 | idx = 0; | |
460 | ||
461 | /* Remove all blank characters ahead and after . | |
462 | * Remove 0x/0X if exists. | |
463 | */ | |
464 | while (isblank(*coremask)) | |
465 | coremask++; | |
466 | if (coremask[0] == '0' && ((coremask[1] == 'x') | |
467 | || (coremask[1] == 'X'))) | |
468 | coremask += 2; | |
469 | i = strlen(coremask); | |
470 | while ((i > 0) && isblank(coremask[i - 1])) | |
471 | i--; | |
472 | if (i == 0) | |
473 | return -1; | |
474 | ||
475 | for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) { | |
476 | c = coremask[i]; | |
477 | if (isxdigit(c) == 0) { | |
478 | /* invalid characters */ | |
479 | return -1; | |
480 | } | |
481 | val = xdigit2val(c); | |
482 | for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++) | |
483 | { | |
484 | if ((1 << j) & val) { | |
485 | cores[idx] = count; | |
486 | count++; | |
487 | } | |
488 | } | |
7c673cae | 489 | } |
9f95a23c TL |
490 | for (; i >= 0; i--) |
491 | if (coremask[i] != '0') | |
492 | return -1; | |
7c673cae FG |
493 | if (count == 0) |
494 | return -1; | |
7c673cae FG |
495 | return 0; |
496 | } | |
497 | ||
498 | static int | |
9f95a23c | 499 | eal_parse_service_corelist(const char *corelist) |
7c673cae FG |
500 | { |
501 | struct rte_config *cfg = rte_eal_get_configuration(); | |
502 | int i, idx = 0; | |
503 | unsigned count = 0; | |
504 | char *end = NULL; | |
505 | int min, max; | |
9f95a23c | 506 | uint32_t taken_lcore_count = 0; |
7c673cae FG |
507 | |
508 | if (corelist == NULL) | |
509 | return -1; | |
510 | ||
511 | /* Remove all blank characters ahead and after */ | |
512 | while (isblank(*corelist)) | |
513 | corelist++; | |
514 | i = strlen(corelist); | |
515 | while ((i > 0) && isblank(corelist[i - 1])) | |
516 | i--; | |
517 | ||
7c673cae FG |
518 | /* Get list of cores */ |
519 | min = RTE_MAX_LCORE; | |
520 | do { | |
521 | while (isblank(*corelist)) | |
522 | corelist++; | |
523 | if (*corelist == '\0') | |
524 | return -1; | |
525 | errno = 0; | |
526 | idx = strtoul(corelist, &end, 10); | |
527 | if (errno || end == NULL) | |
528 | return -1; | |
529 | while (isblank(*end)) | |
530 | end++; | |
531 | if (*end == '-') { | |
532 | min = idx; | |
533 | } else if ((*end == ',') || (*end == '\0')) { | |
534 | max = idx; | |
535 | if (min == RTE_MAX_LCORE) | |
536 | min = idx; | |
537 | for (idx = min; idx <= max; idx++) { | |
9f95a23c TL |
538 | if (cfg->lcore_role[idx] != ROLE_SERVICE) { |
539 | /* handle master lcore already parsed */ | |
540 | uint32_t lcore = idx; | |
541 | if (cfg->master_lcore == lcore && | |
542 | master_lcore_parsed) { | |
543 | RTE_LOG(ERR, EAL, | |
544 | "Error: lcore %u is master lcore, cannot use as service core\n", | |
545 | idx); | |
546 | return -1; | |
547 | } | |
548 | if (cfg->lcore_role[idx] == ROLE_RTE) | |
549 | taken_lcore_count++; | |
550 | ||
551 | lcore_config[idx].core_role = | |
552 | ROLE_SERVICE; | |
7c673cae FG |
553 | count++; |
554 | } | |
555 | } | |
556 | min = RTE_MAX_LCORE; | |
557 | } else | |
558 | return -1; | |
559 | corelist = end + 1; | |
560 | } while (*end != '\0'); | |
561 | ||
562 | if (count == 0) | |
563 | return -1; | |
564 | ||
9f95a23c TL |
565 | if (core_parsed && taken_lcore_count != count) { |
566 | RTE_LOG(WARNING, EAL, | |
567 | "Not all service cores were in the coremask. " | |
568 | "Please ensure -c or -l includes service cores\n"); | |
569 | } | |
570 | ||
571 | return 0; | |
572 | } | |
573 | ||
574 | static int | |
575 | eal_parse_corelist(const char *corelist, int *cores) | |
576 | { | |
577 | unsigned count = 0; | |
578 | char *end = NULL; | |
579 | int min, max; | |
580 | int idx; | |
581 | ||
582 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) | |
583 | cores[idx] = -1; | |
584 | ||
585 | /* Remove all blank characters ahead */ | |
586 | while (isblank(*corelist)) | |
587 | corelist++; | |
588 | ||
589 | /* Get list of cores */ | |
590 | min = RTE_MAX_LCORE; | |
591 | do { | |
592 | while (isblank(*corelist)) | |
593 | corelist++; | |
594 | if (*corelist == '\0') | |
595 | return -1; | |
596 | errno = 0; | |
597 | idx = strtol(corelist, &end, 10); | |
598 | if (errno || end == NULL) | |
599 | return -1; | |
600 | if (idx < 0 || idx >= RTE_MAX_LCORE) | |
601 | return -1; | |
602 | while (isblank(*end)) | |
603 | end++; | |
604 | if (*end == '-') { | |
605 | min = idx; | |
606 | } else if ((*end == ',') || (*end == '\0')) { | |
607 | max = idx; | |
608 | if (min == RTE_MAX_LCORE) | |
609 | min = idx; | |
610 | for (idx = min; idx <= max; idx++) { | |
611 | if (cores[idx] == -1) { | |
612 | cores[idx] = count; | |
613 | count++; | |
614 | } | |
615 | } | |
616 | min = RTE_MAX_LCORE; | |
617 | } else | |
618 | return -1; | |
619 | corelist = end + 1; | |
620 | } while (*end != '\0'); | |
7c673cae | 621 | |
9f95a23c TL |
622 | if (count == 0) |
623 | return -1; | |
7c673cae FG |
624 | return 0; |
625 | } | |
626 | ||
627 | /* Changes the lcore id of the master thread */ | |
628 | static int | |
629 | eal_parse_master_lcore(const char *arg) | |
630 | { | |
631 | char *parsing_end; | |
632 | struct rte_config *cfg = rte_eal_get_configuration(); | |
633 | ||
634 | errno = 0; | |
635 | cfg->master_lcore = (uint32_t) strtol(arg, &parsing_end, 0); | |
636 | if (errno || parsing_end[0] != 0) | |
637 | return -1; | |
638 | if (cfg->master_lcore >= RTE_MAX_LCORE) | |
639 | return -1; | |
640 | master_lcore_parsed = 1; | |
9f95a23c TL |
641 | |
642 | /* ensure master core is not used as service core */ | |
643 | if (lcore_config[cfg->master_lcore].core_role == ROLE_SERVICE) { | |
644 | RTE_LOG(ERR, EAL, | |
645 | "Error: Master lcore is used as a service core\n"); | |
646 | return -1; | |
647 | } | |
648 | ||
7c673cae FG |
649 | return 0; |
650 | } | |
651 | ||
652 | /* | |
653 | * Parse elem, the elem could be single number/range or '(' ')' group | |
654 | * 1) A single number elem, it's just a simple digit. e.g. 9 | |
655 | * 2) A single range elem, two digits with a '-' between. e.g. 2-6 | |
656 | * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6) | |
657 | * Within group elem, '-' used for a range separator; | |
658 | * ',' used for a single number. | |
659 | */ | |
660 | static int | |
661 | eal_parse_set(const char *input, uint16_t set[], unsigned num) | |
662 | { | |
663 | unsigned idx; | |
664 | const char *str = input; | |
665 | char *end = NULL; | |
666 | unsigned min, max; | |
667 | ||
668 | memset(set, 0, num * sizeof(uint16_t)); | |
669 | ||
670 | while (isblank(*str)) | |
671 | str++; | |
672 | ||
673 | /* only digit or left bracket is qualify for start point */ | |
674 | if ((!isdigit(*str) && *str != '(') || *str == '\0') | |
675 | return -1; | |
676 | ||
677 | /* process single number or single range of number */ | |
678 | if (*str != '(') { | |
679 | errno = 0; | |
680 | idx = strtoul(str, &end, 10); | |
681 | if (errno || end == NULL || idx >= num) | |
682 | return -1; | |
683 | else { | |
684 | while (isblank(*end)) | |
685 | end++; | |
686 | ||
687 | min = idx; | |
688 | max = idx; | |
689 | if (*end == '-') { | |
690 | /* process single <number>-<number> */ | |
691 | end++; | |
692 | while (isblank(*end)) | |
693 | end++; | |
694 | if (!isdigit(*end)) | |
695 | return -1; | |
696 | ||
697 | errno = 0; | |
698 | idx = strtoul(end, &end, 10); | |
699 | if (errno || end == NULL || idx >= num) | |
700 | return -1; | |
701 | max = idx; | |
702 | while (isblank(*end)) | |
703 | end++; | |
704 | if (*end != ',' && *end != '\0') | |
705 | return -1; | |
706 | } | |
707 | ||
708 | if (*end != ',' && *end != '\0' && | |
709 | *end != '@') | |
710 | return -1; | |
711 | ||
712 | for (idx = RTE_MIN(min, max); | |
713 | idx <= RTE_MAX(min, max); idx++) | |
714 | set[idx] = 1; | |
715 | ||
716 | return end - input; | |
717 | } | |
718 | } | |
719 | ||
720 | /* process set within bracket */ | |
721 | str++; | |
722 | while (isblank(*str)) | |
723 | str++; | |
724 | if (*str == '\0') | |
725 | return -1; | |
726 | ||
727 | min = RTE_MAX_LCORE; | |
728 | do { | |
729 | ||
730 | /* go ahead to the first digit */ | |
731 | while (isblank(*str)) | |
732 | str++; | |
733 | if (!isdigit(*str)) | |
734 | return -1; | |
735 | ||
736 | /* get the digit value */ | |
737 | errno = 0; | |
738 | idx = strtoul(str, &end, 10); | |
739 | if (errno || end == NULL || idx >= num) | |
740 | return -1; | |
741 | ||
742 | /* go ahead to separator '-',',' and ')' */ | |
743 | while (isblank(*end)) | |
744 | end++; | |
745 | if (*end == '-') { | |
746 | if (min == RTE_MAX_LCORE) | |
747 | min = idx; | |
748 | else /* avoid continuous '-' */ | |
749 | return -1; | |
750 | } else if ((*end == ',') || (*end == ')')) { | |
751 | max = idx; | |
752 | if (min == RTE_MAX_LCORE) | |
753 | min = idx; | |
754 | for (idx = RTE_MIN(min, max); | |
755 | idx <= RTE_MAX(min, max); idx++) | |
756 | set[idx] = 1; | |
757 | ||
758 | min = RTE_MAX_LCORE; | |
759 | } else | |
760 | return -1; | |
761 | ||
762 | str = end + 1; | |
763 | } while (*end != '\0' && *end != ')'); | |
764 | ||
765 | /* | |
766 | * to avoid failure that tail blank makes end character check fail | |
767 | * in eal_parse_lcores( ) | |
768 | */ | |
769 | while (isblank(*str)) | |
770 | str++; | |
771 | ||
772 | return str - input; | |
773 | } | |
774 | ||
775 | /* convert from set array to cpuset bitmap */ | |
776 | static int | |
777 | convert_to_cpuset(rte_cpuset_t *cpusetp, | |
778 | uint16_t *set, unsigned num) | |
779 | { | |
780 | unsigned idx; | |
781 | ||
782 | CPU_ZERO(cpusetp); | |
783 | ||
784 | for (idx = 0; idx < num; idx++) { | |
785 | if (!set[idx]) | |
786 | continue; | |
787 | ||
788 | if (!lcore_config[idx].detected) { | |
789 | RTE_LOG(ERR, EAL, "core %u " | |
790 | "unavailable\n", idx); | |
791 | return -1; | |
792 | } | |
793 | ||
794 | CPU_SET(idx, cpusetp); | |
795 | } | |
796 | ||
797 | return 0; | |
798 | } | |
799 | ||
800 | /* | |
801 | * The format pattern: --lcores='<lcores[@cpus]>[<,lcores[@cpus]>...]' | |
802 | * lcores, cpus could be a single digit/range or a group. | |
803 | * '(' and ')' are necessary if it's a group. | |
804 | * If not supply '@cpus', the value of cpus uses the same as lcores. | |
805 | * e.g. '1,2@(5-7),(3-5)@(0,2),(0,6),7-8' means start 9 EAL thread as below | |
806 | * lcore 0 runs on cpuset 0x41 (cpu 0,6) | |
807 | * lcore 1 runs on cpuset 0x2 (cpu 1) | |
808 | * lcore 2 runs on cpuset 0xe0 (cpu 5,6,7) | |
809 | * lcore 3,4,5 runs on cpuset 0x5 (cpu 0,2) | |
810 | * lcore 6 runs on cpuset 0x41 (cpu 0,6) | |
811 | * lcore 7 runs on cpuset 0x80 (cpu 7) | |
812 | * lcore 8 runs on cpuset 0x100 (cpu 8) | |
813 | */ | |
814 | static int | |
815 | eal_parse_lcores(const char *lcores) | |
816 | { | |
817 | struct rte_config *cfg = rte_eal_get_configuration(); | |
818 | static uint16_t set[RTE_MAX_LCORE]; | |
819 | unsigned idx = 0; | |
820 | unsigned count = 0; | |
821 | const char *lcore_start = NULL; | |
822 | const char *end = NULL; | |
823 | int offset; | |
824 | rte_cpuset_t cpuset; | |
825 | int lflags; | |
826 | int ret = -1; | |
827 | ||
828 | if (lcores == NULL) | |
829 | return -1; | |
830 | ||
831 | /* Remove all blank characters ahead and after */ | |
832 | while (isblank(*lcores)) | |
833 | lcores++; | |
834 | ||
835 | CPU_ZERO(&cpuset); | |
836 | ||
837 | /* Reset lcore config */ | |
838 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) { | |
839 | cfg->lcore_role[idx] = ROLE_OFF; | |
840 | lcore_config[idx].core_index = -1; | |
841 | CPU_ZERO(&lcore_config[idx].cpuset); | |
842 | } | |
843 | ||
844 | /* Get list of cores */ | |
845 | do { | |
846 | while (isblank(*lcores)) | |
847 | lcores++; | |
848 | if (*lcores == '\0') | |
849 | goto err; | |
850 | ||
851 | lflags = 0; | |
852 | ||
853 | /* record lcore_set start point */ | |
854 | lcore_start = lcores; | |
855 | ||
856 | /* go across a complete bracket */ | |
857 | if (*lcore_start == '(') { | |
858 | lcores += strcspn(lcores, ")"); | |
859 | if (*lcores++ == '\0') | |
860 | goto err; | |
861 | } | |
862 | ||
863 | /* scan the separator '@', ','(next) or '\0'(finish) */ | |
864 | lcores += strcspn(lcores, "@,"); | |
865 | ||
866 | if (*lcores == '@') { | |
867 | /* explicit assign cpu_set */ | |
868 | offset = eal_parse_set(lcores + 1, set, RTE_DIM(set)); | |
869 | if (offset < 0) | |
870 | goto err; | |
871 | ||
872 | /* prepare cpu_set and update the end cursor */ | |
873 | if (0 > convert_to_cpuset(&cpuset, | |
874 | set, RTE_DIM(set))) | |
875 | goto err; | |
876 | end = lcores + 1 + offset; | |
877 | } else { /* ',' or '\0' */ | |
878 | /* haven't given cpu_set, current loop done */ | |
879 | end = lcores; | |
880 | ||
881 | /* go back to check <number>-<number> */ | |
882 | offset = strcspn(lcore_start, "(-"); | |
883 | if (offset < (end - lcore_start) && | |
884 | *(lcore_start + offset) != '(') | |
885 | lflags = 1; | |
886 | } | |
887 | ||
888 | if (*end != ',' && *end != '\0') | |
889 | goto err; | |
890 | ||
891 | /* parse lcore_set from start point */ | |
892 | if (0 > eal_parse_set(lcore_start, set, RTE_DIM(set))) | |
893 | goto err; | |
894 | ||
895 | /* without '@', by default using lcore_set as cpu_set */ | |
896 | if (*lcores != '@' && | |
897 | 0 > convert_to_cpuset(&cpuset, set, RTE_DIM(set))) | |
898 | goto err; | |
899 | ||
900 | /* start to update lcore_set */ | |
901 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) { | |
902 | if (!set[idx]) | |
903 | continue; | |
904 | ||
905 | if (cfg->lcore_role[idx] != ROLE_RTE) { | |
906 | lcore_config[idx].core_index = count; | |
907 | cfg->lcore_role[idx] = ROLE_RTE; | |
908 | count++; | |
909 | } | |
910 | ||
911 | if (lflags) { | |
912 | CPU_ZERO(&cpuset); | |
913 | CPU_SET(idx, &cpuset); | |
914 | } | |
915 | rte_memcpy(&lcore_config[idx].cpuset, &cpuset, | |
916 | sizeof(rte_cpuset_t)); | |
917 | } | |
918 | ||
919 | lcores = end + 1; | |
920 | } while (*end != '\0'); | |
921 | ||
922 | if (count == 0) | |
923 | goto err; | |
924 | ||
925 | cfg->lcore_count = count; | |
926 | ret = 0; | |
927 | ||
928 | err: | |
929 | ||
930 | return ret; | |
931 | } | |
932 | ||
933 | static int | |
934 | eal_parse_syslog(const char *facility, struct internal_config *conf) | |
935 | { | |
936 | int i; | |
9f95a23c | 937 | static const struct { |
7c673cae FG |
938 | const char *name; |
939 | int value; | |
940 | } map[] = { | |
941 | { "auth", LOG_AUTH }, | |
942 | { "cron", LOG_CRON }, | |
943 | { "daemon", LOG_DAEMON }, | |
944 | { "ftp", LOG_FTP }, | |
945 | { "kern", LOG_KERN }, | |
946 | { "lpr", LOG_LPR }, | |
947 | { "mail", LOG_MAIL }, | |
948 | { "news", LOG_NEWS }, | |
949 | { "syslog", LOG_SYSLOG }, | |
950 | { "user", LOG_USER }, | |
951 | { "uucp", LOG_UUCP }, | |
952 | { "local0", LOG_LOCAL0 }, | |
953 | { "local1", LOG_LOCAL1 }, | |
954 | { "local2", LOG_LOCAL2 }, | |
955 | { "local3", LOG_LOCAL3 }, | |
956 | { "local4", LOG_LOCAL4 }, | |
957 | { "local5", LOG_LOCAL5 }, | |
958 | { "local6", LOG_LOCAL6 }, | |
959 | { "local7", LOG_LOCAL7 }, | |
960 | { NULL, 0 } | |
961 | }; | |
962 | ||
963 | for (i = 0; map[i].name; i++) { | |
964 | if (!strcmp(facility, map[i].name)) { | |
965 | conf->syslog_facility = map[i].value; | |
966 | return 0; | |
967 | } | |
968 | } | |
969 | return -1; | |
970 | } | |
971 | ||
972 | static int | |
9f95a23c | 973 | eal_parse_log_priority(const char *level) |
7c673cae | 974 | { |
9f95a23c TL |
975 | static const char * const levels[] = { |
976 | [RTE_LOG_EMERG] = "emergency", | |
977 | [RTE_LOG_ALERT] = "alert", | |
978 | [RTE_LOG_CRIT] = "critical", | |
979 | [RTE_LOG_ERR] = "error", | |
980 | [RTE_LOG_WARNING] = "warning", | |
981 | [RTE_LOG_NOTICE] = "notice", | |
982 | [RTE_LOG_INFO] = "info", | |
983 | [RTE_LOG_DEBUG] = "debug", | |
984 | }; | |
985 | size_t len = strlen(level); | |
7c673cae | 986 | unsigned long tmp; |
9f95a23c TL |
987 | char *end; |
988 | unsigned int i; | |
7c673cae | 989 | |
9f95a23c | 990 | if (len == 0) |
11fdf7f2 TL |
991 | return -1; |
992 | ||
9f95a23c TL |
993 | /* look for named values, skip 0 which is not a valid level */ |
994 | for (i = 1; i < RTE_DIM(levels); i++) { | |
995 | if (strncmp(levels[i], level, len) == 0) | |
996 | return i; | |
11fdf7f2 TL |
997 | } |
998 | ||
9f95a23c | 999 | /* not a string, maybe it is numeric */ |
7c673cae FG |
1000 | errno = 0; |
1001 | tmp = strtoul(level, &end, 0); | |
1002 | ||
1003 | /* check for errors */ | |
9f95a23c TL |
1004 | if (errno != 0 || end == NULL || *end != '\0' || |
1005 | tmp >= UINT32_MAX) | |
1006 | return -1; | |
7c673cae | 1007 | |
9f95a23c TL |
1008 | return tmp; |
1009 | } | |
1010 | ||
1011 | static int | |
1012 | eal_parse_log_level(const char *arg) | |
1013 | { | |
1014 | const char *pattern = NULL; | |
1015 | const char *regex = NULL; | |
1016 | char *str, *level; | |
1017 | int priority; | |
11fdf7f2 | 1018 | |
9f95a23c TL |
1019 | str = strdup(arg); |
1020 | if (str == NULL) | |
1021 | return -1; | |
1022 | ||
1023 | if ((level = strchr(str, ','))) { | |
1024 | regex = str; | |
1025 | *level++ = '\0'; | |
1026 | } else if ((level = strchr(str, ':'))) { | |
1027 | pattern = str; | |
1028 | *level++ = '\0'; | |
1029 | } else { | |
1030 | level = str; | |
1031 | } | |
1032 | ||
1033 | priority = eal_parse_log_priority(level); | |
1034 | if (priority < 0) { | |
1035 | fprintf(stderr, "invalid log priority: %s\n", level); | |
11fdf7f2 TL |
1036 | goto fail; |
1037 | } | |
7c673cae | 1038 | |
9f95a23c TL |
1039 | if (regex) { |
1040 | if (rte_log_set_level_regexp(regex, priority) < 0) { | |
1041 | fprintf(stderr, "cannot set log level %s,%d\n", | |
1042 | pattern, priority); | |
1043 | goto fail; | |
1044 | } | |
1045 | if (rte_log_save_regexp(regex, priority) < 0) | |
1046 | goto fail; | |
1047 | } else if (pattern) { | |
1048 | if (rte_log_set_level_pattern(pattern, priority) < 0) { | |
1049 | fprintf(stderr, "cannot set log level %s:%d\n", | |
1050 | pattern, priority); | |
1051 | goto fail; | |
1052 | } | |
1053 | if (rte_log_save_pattern(pattern, priority) < 0) | |
1054 | goto fail; | |
1055 | } else { | |
1056 | rte_log_set_global_level(priority); | |
1057 | } | |
1058 | ||
11fdf7f2 | 1059 | free(str); |
7c673cae | 1060 | return 0; |
11fdf7f2 TL |
1061 | |
1062 | fail: | |
1063 | free(str); | |
1064 | return -1; | |
7c673cae FG |
1065 | } |
1066 | ||
1067 | static enum rte_proc_type_t | |
1068 | eal_parse_proc_type(const char *arg) | |
1069 | { | |
1070 | if (strncasecmp(arg, "primary", sizeof("primary")) == 0) | |
1071 | return RTE_PROC_PRIMARY; | |
1072 | if (strncasecmp(arg, "secondary", sizeof("secondary")) == 0) | |
1073 | return RTE_PROC_SECONDARY; | |
1074 | if (strncasecmp(arg, "auto", sizeof("auto")) == 0) | |
1075 | return RTE_PROC_AUTO; | |
1076 | ||
1077 | return RTE_PROC_INVALID; | |
1078 | } | |
1079 | ||
9f95a23c TL |
1080 | static int |
1081 | eal_parse_iova_mode(const char *name) | |
1082 | { | |
1083 | int mode; | |
1084 | ||
1085 | if (name == NULL) | |
1086 | return -1; | |
1087 | ||
1088 | if (!strcmp("pa", name)) | |
1089 | mode = RTE_IOVA_PA; | |
1090 | else if (!strcmp("va", name)) | |
1091 | mode = RTE_IOVA_VA; | |
1092 | else | |
1093 | return -1; | |
1094 | ||
1095 | internal_config.iova_mode = mode; | |
1096 | return 0; | |
1097 | } | |
1098 | ||
1099 | /* caller is responsible for freeing the returned string */ | |
1100 | static char * | |
1101 | available_cores(void) | |
1102 | { | |
1103 | char *str = NULL; | |
1104 | int previous; | |
1105 | int sequence; | |
1106 | char *tmp; | |
1107 | int idx; | |
1108 | ||
1109 | /* find the first available cpu */ | |
1110 | for (idx = 0; idx < RTE_MAX_LCORE; idx++) { | |
1111 | if (!lcore_config[idx].detected) | |
1112 | continue; | |
1113 | break; | |
1114 | } | |
1115 | if (idx >= RTE_MAX_LCORE) | |
1116 | return NULL; | |
1117 | ||
1118 | /* first sequence */ | |
1119 | if (asprintf(&str, "%d", idx) < 0) | |
1120 | return NULL; | |
1121 | previous = idx; | |
1122 | sequence = 0; | |
1123 | ||
1124 | for (idx++ ; idx < RTE_MAX_LCORE; idx++) { | |
1125 | if (!lcore_config[idx].detected) | |
1126 | continue; | |
1127 | ||
1128 | if (idx == previous + 1) { | |
1129 | previous = idx; | |
1130 | sequence = 1; | |
1131 | continue; | |
1132 | } | |
1133 | ||
1134 | /* finish current sequence */ | |
1135 | if (sequence) { | |
1136 | if (asprintf(&tmp, "%s-%d", str, previous) < 0) { | |
1137 | free(str); | |
1138 | return NULL; | |
1139 | } | |
1140 | free(str); | |
1141 | str = tmp; | |
1142 | } | |
1143 | ||
1144 | /* new sequence */ | |
1145 | if (asprintf(&tmp, "%s,%d", str, idx) < 0) { | |
1146 | free(str); | |
1147 | return NULL; | |
1148 | } | |
1149 | free(str); | |
1150 | str = tmp; | |
1151 | previous = idx; | |
1152 | sequence = 0; | |
1153 | } | |
1154 | ||
1155 | /* finish last sequence */ | |
1156 | if (sequence) { | |
1157 | if (asprintf(&tmp, "%s-%d", str, previous) < 0) { | |
1158 | free(str); | |
1159 | return NULL; | |
1160 | } | |
1161 | free(str); | |
1162 | str = tmp; | |
1163 | } | |
1164 | ||
1165 | return str; | |
1166 | } | |
1167 | ||
7c673cae FG |
1168 | int |
1169 | eal_parse_common_option(int opt, const char *optarg, | |
1170 | struct internal_config *conf) | |
1171 | { | |
9f95a23c TL |
1172 | static int b_used; |
1173 | static int w_used; | |
1174 | ||
7c673cae FG |
1175 | switch (opt) { |
1176 | /* blacklist */ | |
1177 | case 'b': | |
9f95a23c TL |
1178 | if (w_used) |
1179 | goto bw_used; | |
1180 | if (eal_option_device_add(RTE_DEVTYPE_BLACKLISTED_PCI, | |
7c673cae FG |
1181 | optarg) < 0) { |
1182 | return -1; | |
1183 | } | |
9f95a23c | 1184 | b_used = 1; |
7c673cae FG |
1185 | break; |
1186 | /* whitelist */ | |
1187 | case 'w': | |
9f95a23c TL |
1188 | if (b_used) |
1189 | goto bw_used; | |
1190 | if (eal_option_device_add(RTE_DEVTYPE_WHITELISTED_PCI, | |
7c673cae FG |
1191 | optarg) < 0) { |
1192 | return -1; | |
1193 | } | |
9f95a23c | 1194 | w_used = 1; |
7c673cae FG |
1195 | break; |
1196 | /* coremask */ | |
9f95a23c TL |
1197 | case 'c': { |
1198 | int lcore_indexes[RTE_MAX_LCORE]; | |
1199 | ||
1200 | if (eal_service_cores_parsed()) | |
1201 | RTE_LOG(WARNING, EAL, | |
1202 | "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S\n"); | |
1203 | if (eal_parse_coremask(optarg, lcore_indexes) < 0) { | |
1204 | RTE_LOG(ERR, EAL, "invalid coremask syntax\n"); | |
1205 | return -1; | |
1206 | } | |
1207 | if (update_lcore_config(lcore_indexes) < 0) { | |
1208 | char *available = available_cores(); | |
1209 | ||
1210 | RTE_LOG(ERR, EAL, | |
1211 | "invalid coremask, please check specified cores are part of %s\n", | |
1212 | available); | |
1213 | free(available); | |
1214 | return -1; | |
1215 | } | |
1216 | ||
1217 | if (core_parsed) { | |
1218 | RTE_LOG(ERR, EAL, "Option -c is ignored, because (%s) is set!\n", | |
1219 | (core_parsed == LCORE_OPT_LST) ? "-l" : | |
1220 | (core_parsed == LCORE_OPT_MAP) ? "--lcore" : | |
1221 | "-c"); | |
7c673cae FG |
1222 | return -1; |
1223 | } | |
9f95a23c TL |
1224 | |
1225 | core_parsed = LCORE_OPT_MSK; | |
7c673cae | 1226 | break; |
9f95a23c | 1227 | } |
7c673cae | 1228 | /* corelist */ |
9f95a23c TL |
1229 | case 'l': { |
1230 | int lcore_indexes[RTE_MAX_LCORE]; | |
1231 | ||
1232 | if (eal_service_cores_parsed()) | |
1233 | RTE_LOG(WARNING, EAL, | |
1234 | "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S\n"); | |
1235 | ||
1236 | if (eal_parse_corelist(optarg, lcore_indexes) < 0) { | |
1237 | RTE_LOG(ERR, EAL, "invalid core list syntax\n"); | |
1238 | return -1; | |
1239 | } | |
1240 | if (update_lcore_config(lcore_indexes) < 0) { | |
1241 | char *available = available_cores(); | |
1242 | ||
1243 | RTE_LOG(ERR, EAL, | |
1244 | "invalid core list, please check specified cores are part of %s\n", | |
1245 | available); | |
1246 | free(available); | |
1247 | return -1; | |
1248 | } | |
1249 | ||
1250 | if (core_parsed) { | |
1251 | RTE_LOG(ERR, EAL, "Option -l is ignored, because (%s) is set!\n", | |
1252 | (core_parsed == LCORE_OPT_MSK) ? "-c" : | |
1253 | (core_parsed == LCORE_OPT_MAP) ? "--lcore" : | |
1254 | "-l"); | |
1255 | return -1; | |
1256 | } | |
1257 | ||
1258 | core_parsed = LCORE_OPT_LST; | |
1259 | break; | |
1260 | } | |
1261 | /* service coremask */ | |
1262 | case 's': | |
1263 | if (eal_parse_service_coremask(optarg) < 0) { | |
1264 | RTE_LOG(ERR, EAL, "invalid service coremask\n"); | |
1265 | return -1; | |
1266 | } | |
1267 | break; | |
1268 | /* service corelist */ | |
1269 | case 'S': | |
1270 | if (eal_parse_service_corelist(optarg) < 0) { | |
1271 | RTE_LOG(ERR, EAL, "invalid service core list\n"); | |
7c673cae FG |
1272 | return -1; |
1273 | } | |
1274 | break; | |
1275 | /* size of memory */ | |
1276 | case 'm': | |
1277 | conf->memory = atoi(optarg); | |
1278 | conf->memory *= 1024ULL; | |
1279 | conf->memory *= 1024ULL; | |
1280 | mem_parsed = 1; | |
1281 | break; | |
1282 | /* force number of channels */ | |
1283 | case 'n': | |
1284 | conf->force_nchannel = atoi(optarg); | |
1285 | if (conf->force_nchannel == 0) { | |
1286 | RTE_LOG(ERR, EAL, "invalid channel number\n"); | |
1287 | return -1; | |
1288 | } | |
1289 | break; | |
1290 | /* force number of ranks */ | |
1291 | case 'r': | |
1292 | conf->force_nrank = atoi(optarg); | |
1293 | if (conf->force_nrank == 0 || | |
1294 | conf->force_nrank > 16) { | |
1295 | RTE_LOG(ERR, EAL, "invalid rank number\n"); | |
1296 | return -1; | |
1297 | } | |
1298 | break; | |
1299 | /* force loading of external driver */ | |
1300 | case 'd': | |
1301 | if (eal_plugin_add(optarg) == -1) | |
1302 | return -1; | |
1303 | break; | |
1304 | case 'v': | |
1305 | /* since message is explicitly requested by user, we | |
1306 | * write message at highest log level so it can always | |
1307 | * be seen | |
1308 | * even if info or warning messages are disabled */ | |
1309 | RTE_LOG(CRIT, EAL, "RTE Version: '%s'\n", rte_version()); | |
1310 | break; | |
1311 | ||
1312 | /* long options */ | |
1313 | case OPT_HUGE_UNLINK_NUM: | |
1314 | conf->hugepage_unlink = 1; | |
1315 | break; | |
1316 | ||
1317 | case OPT_NO_HUGE_NUM: | |
1318 | conf->no_hugetlbfs = 1; | |
9f95a23c TL |
1319 | /* no-huge is legacy mem */ |
1320 | conf->legacy_mem = 1; | |
7c673cae FG |
1321 | break; |
1322 | ||
1323 | case OPT_NO_PCI_NUM: | |
1324 | conf->no_pci = 1; | |
1325 | break; | |
1326 | ||
1327 | case OPT_NO_HPET_NUM: | |
1328 | conf->no_hpet = 1; | |
1329 | break; | |
1330 | ||
1331 | case OPT_VMWARE_TSC_MAP_NUM: | |
1332 | conf->vmware_tsc_map = 1; | |
1333 | break; | |
1334 | ||
1335 | case OPT_NO_SHCONF_NUM: | |
1336 | conf->no_shconf = 1; | |
1337 | break; | |
1338 | ||
9f95a23c TL |
1339 | case OPT_IN_MEMORY_NUM: |
1340 | conf->in_memory = 1; | |
1341 | /* in-memory is a superset of noshconf and huge-unlink */ | |
1342 | conf->no_shconf = 1; | |
1343 | conf->hugepage_unlink = 1; | |
1344 | break; | |
1345 | ||
7c673cae FG |
1346 | case OPT_PROC_TYPE_NUM: |
1347 | conf->process_type = eal_parse_proc_type(optarg); | |
1348 | break; | |
1349 | ||
1350 | case OPT_MASTER_LCORE_NUM: | |
1351 | if (eal_parse_master_lcore(optarg) < 0) { | |
1352 | RTE_LOG(ERR, EAL, "invalid parameter for --" | |
1353 | OPT_MASTER_LCORE "\n"); | |
1354 | return -1; | |
1355 | } | |
1356 | break; | |
1357 | ||
1358 | case OPT_VDEV_NUM: | |
9f95a23c | 1359 | if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, |
7c673cae FG |
1360 | optarg) < 0) { |
1361 | return -1; | |
1362 | } | |
1363 | break; | |
1364 | ||
1365 | case OPT_SYSLOG_NUM: | |
1366 | if (eal_parse_syslog(optarg, conf) < 0) { | |
1367 | RTE_LOG(ERR, EAL, "invalid parameters for --" | |
1368 | OPT_SYSLOG "\n"); | |
1369 | return -1; | |
1370 | } | |
1371 | break; | |
1372 | ||
1373 | case OPT_LOG_LEVEL_NUM: { | |
11fdf7f2 | 1374 | if (eal_parse_log_level(optarg) < 0) { |
7c673cae FG |
1375 | RTE_LOG(ERR, EAL, |
1376 | "invalid parameters for --" | |
1377 | OPT_LOG_LEVEL "\n"); | |
1378 | return -1; | |
1379 | } | |
7c673cae FG |
1380 | break; |
1381 | } | |
1382 | case OPT_LCORES_NUM: | |
1383 | if (eal_parse_lcores(optarg) < 0) { | |
1384 | RTE_LOG(ERR, EAL, "invalid parameter for --" | |
1385 | OPT_LCORES "\n"); | |
1386 | return -1; | |
1387 | } | |
9f95a23c TL |
1388 | |
1389 | if (core_parsed) { | |
1390 | RTE_LOG(ERR, EAL, "Option --lcore is ignored, because (%s) is set!\n", | |
1391 | (core_parsed == LCORE_OPT_LST) ? "-l" : | |
1392 | (core_parsed == LCORE_OPT_MSK) ? "-c" : | |
1393 | "--lcore"); | |
1394 | return -1; | |
1395 | } | |
1396 | ||
1397 | core_parsed = LCORE_OPT_MAP; | |
1398 | break; | |
1399 | case OPT_LEGACY_MEM_NUM: | |
1400 | conf->legacy_mem = 1; | |
1401 | break; | |
1402 | case OPT_SINGLE_FILE_SEGMENTS_NUM: | |
1403 | conf->single_file_segments = 1; | |
1404 | break; | |
1405 | case OPT_IOVA_MODE_NUM: | |
1406 | if (eal_parse_iova_mode(optarg) < 0) { | |
1407 | RTE_LOG(ERR, EAL, "invalid parameters for --" | |
1408 | OPT_IOVA_MODE "\n"); | |
1409 | return -1; | |
1410 | } | |
7c673cae FG |
1411 | break; |
1412 | ||
1413 | /* don't know what to do, leave this to caller */ | |
1414 | default: | |
1415 | return 1; | |
1416 | ||
1417 | } | |
1418 | ||
1419 | return 0; | |
9f95a23c TL |
1420 | bw_used: |
1421 | RTE_LOG(ERR, EAL, "Options blacklist (-b) and whitelist (-w) " | |
1422 | "cannot be used at the same time\n"); | |
1423 | return -1; | |
7c673cae FG |
1424 | } |
1425 | ||
11fdf7f2 TL |
1426 | static void |
1427 | eal_auto_detect_cores(struct rte_config *cfg) | |
1428 | { | |
1429 | unsigned int lcore_id; | |
1430 | unsigned int removed = 0; | |
1431 | rte_cpuset_t affinity_set; | |
11fdf7f2 | 1432 | |
9f95a23c TL |
1433 | if (pthread_getaffinity_np(pthread_self(), sizeof(rte_cpuset_t), |
1434 | &affinity_set)) | |
11fdf7f2 TL |
1435 | CPU_ZERO(&affinity_set); |
1436 | ||
1437 | for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { | |
1438 | if (cfg->lcore_role[lcore_id] == ROLE_RTE && | |
1439 | !CPU_ISSET(lcore_id, &affinity_set)) { | |
1440 | cfg->lcore_role[lcore_id] = ROLE_OFF; | |
1441 | removed++; | |
1442 | } | |
1443 | } | |
1444 | ||
1445 | cfg->lcore_count -= removed; | |
1446 | } | |
1447 | ||
9f95a23c TL |
1448 | static void |
1449 | compute_ctrl_threads_cpuset(struct internal_config *internal_cfg) | |
1450 | { | |
1451 | rte_cpuset_t *cpuset = &internal_cfg->ctrl_cpuset; | |
1452 | rte_cpuset_t default_set; | |
1453 | unsigned int lcore_id; | |
1454 | ||
1455 | for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { | |
1456 | if (eal_cpu_detected(lcore_id) && | |
1457 | rte_lcore_has_role(lcore_id, ROLE_OFF)) { | |
1458 | CPU_SET(lcore_id, cpuset); | |
1459 | } | |
1460 | } | |
1461 | ||
1462 | if (pthread_getaffinity_np(pthread_self(), sizeof(rte_cpuset_t), | |
1463 | &default_set)) | |
1464 | CPU_ZERO(&default_set); | |
1465 | ||
1466 | RTE_CPU_AND(cpuset, cpuset, &default_set); | |
1467 | ||
1468 | /* if no detected CPU is off, use master core */ | |
1469 | if (!CPU_COUNT(cpuset)) | |
1470 | CPU_SET(rte_get_master_lcore(), cpuset); | |
1471 | } | |
1472 | ||
1473 | int | |
1474 | eal_cleanup_config(struct internal_config *internal_cfg) | |
1475 | { | |
1476 | if (internal_cfg->hugefile_prefix != NULL) | |
1477 | free(internal_cfg->hugefile_prefix); | |
1478 | if (internal_cfg->hugepage_dir != NULL) | |
1479 | free(internal_cfg->hugepage_dir); | |
1480 | if (internal_cfg->user_mbuf_pool_ops_name != NULL) | |
1481 | free(internal_cfg->user_mbuf_pool_ops_name); | |
1482 | ||
1483 | return 0; | |
1484 | } | |
1485 | ||
7c673cae FG |
1486 | int |
1487 | eal_adjust_config(struct internal_config *internal_cfg) | |
1488 | { | |
1489 | int i; | |
1490 | struct rte_config *cfg = rte_eal_get_configuration(); | |
1491 | ||
11fdf7f2 TL |
1492 | if (!core_parsed) |
1493 | eal_auto_detect_cores(cfg); | |
1494 | ||
7c673cae FG |
1495 | if (internal_config.process_type == RTE_PROC_AUTO) |
1496 | internal_config.process_type = eal_proc_type_detect(); | |
1497 | ||
1498 | /* default master lcore is the first one */ | |
9f95a23c | 1499 | if (!master_lcore_parsed) { |
7c673cae | 1500 | cfg->master_lcore = rte_get_next_lcore(-1, 0, 0); |
9f95a23c TL |
1501 | if (cfg->master_lcore >= RTE_MAX_LCORE) |
1502 | return -1; | |
1503 | lcore_config[cfg->master_lcore].core_role = ROLE_RTE; | |
1504 | } | |
1505 | ||
1506 | compute_ctrl_threads_cpuset(internal_cfg); | |
7c673cae FG |
1507 | |
1508 | /* if no memory amounts were requested, this will result in 0 and | |
1509 | * will be overridden later, right after eal_hugepage_info_init() */ | |
1510 | for (i = 0; i < RTE_MAX_NUMA_NODES; i++) | |
1511 | internal_cfg->memory += internal_cfg->socket_mem[i]; | |
1512 | ||
1513 | return 0; | |
1514 | } | |
1515 | ||
1516 | int | |
1517 | eal_check_common_options(struct internal_config *internal_cfg) | |
1518 | { | |
1519 | struct rte_config *cfg = rte_eal_get_configuration(); | |
1520 | ||
1521 | if (cfg->lcore_role[cfg->master_lcore] != ROLE_RTE) { | |
1522 | RTE_LOG(ERR, EAL, "Master lcore is not enabled for DPDK\n"); | |
1523 | return -1; | |
1524 | } | |
1525 | ||
1526 | if (internal_cfg->process_type == RTE_PROC_INVALID) { | |
1527 | RTE_LOG(ERR, EAL, "Invalid process type specified\n"); | |
1528 | return -1; | |
1529 | } | |
9f95a23c TL |
1530 | if (internal_cfg->hugefile_prefix != NULL && |
1531 | strlen(internal_cfg->hugefile_prefix) < 1) { | |
1532 | RTE_LOG(ERR, EAL, "Invalid length of --" OPT_FILE_PREFIX " option\n"); | |
1533 | return -1; | |
1534 | } | |
1535 | if (internal_cfg->hugepage_dir != NULL && | |
1536 | strlen(internal_cfg->hugepage_dir) < 1) { | |
1537 | RTE_LOG(ERR, EAL, "Invalid length of --" OPT_HUGE_DIR" option\n"); | |
1538 | return -1; | |
1539 | } | |
1540 | if (internal_cfg->user_mbuf_pool_ops_name != NULL && | |
1541 | strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) { | |
1542 | RTE_LOG(ERR, EAL, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option\n"); | |
1543 | return -1; | |
1544 | } | |
1545 | if (index(eal_get_hugefile_prefix(), '%') != NULL) { | |
7c673cae FG |
1546 | RTE_LOG(ERR, EAL, "Invalid char, '%%', in --"OPT_FILE_PREFIX" " |
1547 | "option\n"); | |
1548 | return -1; | |
1549 | } | |
1550 | if (mem_parsed && internal_cfg->force_sockets == 1) { | |
1551 | RTE_LOG(ERR, EAL, "Options -m and --"OPT_SOCKET_MEM" cannot " | |
1552 | "be specified at the same time\n"); | |
1553 | return -1; | |
1554 | } | |
1555 | if (internal_cfg->no_hugetlbfs && internal_cfg->force_sockets == 1) { | |
1556 | RTE_LOG(ERR, EAL, "Option --"OPT_SOCKET_MEM" cannot " | |
1557 | "be specified together with --"OPT_NO_HUGE"\n"); | |
1558 | return -1; | |
1559 | } | |
9f95a23c TL |
1560 | if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink && |
1561 | !internal_cfg->in_memory) { | |
7c673cae FG |
1562 | RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot " |
1563 | "be specified together with --"OPT_NO_HUGE"\n"); | |
1564 | return -1; | |
1565 | } | |
9f95a23c TL |
1566 | if (internal_config.force_socket_limits && internal_config.legacy_mem) { |
1567 | RTE_LOG(ERR, EAL, "Option --"OPT_SOCKET_LIMIT | |
1568 | " is only supported in non-legacy memory mode\n"); | |
1569 | } | |
1570 | if (internal_cfg->single_file_segments && | |
1571 | internal_cfg->hugepage_unlink && | |
1572 | !internal_cfg->in_memory) { | |
1573 | RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is " | |
1574 | "not compatible with --"OPT_HUGE_UNLINK"\n"); | |
1575 | return -1; | |
1576 | } | |
1577 | if (internal_cfg->legacy_mem && | |
1578 | internal_cfg->in_memory) { | |
1579 | RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible " | |
1580 | "with --"OPT_IN_MEMORY"\n"); | |
1581 | return -1; | |
1582 | } | |
1583 | if (internal_cfg->legacy_mem && internal_cfg->match_allocations) { | |
1584 | RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible " | |
1585 | "with --"OPT_MATCH_ALLOCATIONS"\n"); | |
1586 | return -1; | |
1587 | } | |
1588 | if (internal_cfg->no_hugetlbfs && internal_cfg->match_allocations) { | |
1589 | RTE_LOG(ERR, EAL, "Option --"OPT_NO_HUGE" is not compatible " | |
1590 | "with --"OPT_MATCH_ALLOCATIONS"\n"); | |
7c673cae FG |
1591 | return -1; |
1592 | } | |
1593 | ||
1594 | return 0; | |
1595 | } | |
1596 | ||
1597 | void | |
1598 | eal_common_usage(void) | |
1599 | { | |
1600 | printf("[options]\n\n" | |
1601 | "EAL common options:\n" | |
1602 | " -c COREMASK Hexadecimal bitmask of cores to run on\n" | |
1603 | " -l CORELIST List of cores to run on\n" | |
1604 | " The argument format is <c1>[-c2][,c3[-c4],...]\n" | |
1605 | " where c1, c2, etc are core indexes between 0 and %d\n" | |
1606 | " --"OPT_LCORES" COREMAP Map lcore set to physical cpu set\n" | |
1607 | " The argument format is\n" | |
1608 | " '<lcores[@cpus]>[<,lcores[@cpus]>...]'\n" | |
1609 | " lcores and cpus list are grouped by '(' and ')'\n" | |
1610 | " Within the group, '-' is used for range separator,\n" | |
1611 | " ',' is used for single number separator.\n" | |
1612 | " '( )' can be omitted for single element group,\n" | |
1613 | " '@' can be omitted if cpus and lcores have the same value\n" | |
9f95a23c | 1614 | " -s SERVICE COREMASK Hexadecimal bitmask of cores to be used as service cores\n" |
7c673cae | 1615 | " --"OPT_MASTER_LCORE" ID Core ID that is used as master\n" |
9f95a23c | 1616 | " --"OPT_MBUF_POOL_OPS_NAME" Pool ops name for mbuf to use\n" |
7c673cae FG |
1617 | " -n CHANNELS Number of memory channels\n" |
1618 | " -m MB Memory to allocate (see also --"OPT_SOCKET_MEM")\n" | |
1619 | " -r RANKS Force number of memory ranks (don't detect)\n" | |
1620 | " -b, --"OPT_PCI_BLACKLIST" Add a PCI device in black list.\n" | |
1621 | " Prevent EAL from using this PCI device. The argument\n" | |
1622 | " format is <domain:bus:devid.func>.\n" | |
1623 | " -w, --"OPT_PCI_WHITELIST" Add a PCI device in white list.\n" | |
1624 | " Only use the specified PCI devices. The argument format\n" | |
1625 | " is <[domain:]bus:devid.func>. This option can be present\n" | |
1626 | " several times (once per device).\n" | |
1627 | " [NOTE: PCI whitelist cannot be used with -b option]\n" | |
1628 | " --"OPT_VDEV" Add a virtual device.\n" | |
1629 | " The argument format is <driver><id>[,key=val,...]\n" | |
1630 | " (ex: --vdev=net_pcap0,iface=eth2).\n" | |
9f95a23c TL |
1631 | " --"OPT_IOVA_MODE" Set IOVA mode. 'pa' for IOVA_PA\n" |
1632 | " 'va' for IOVA_VA\n" | |
7c673cae FG |
1633 | " -d LIB.so|DIR Add a driver or driver directory\n" |
1634 | " (can be used multiple times)\n" | |
1635 | " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" | |
1636 | " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" | |
1637 | " --"OPT_SYSLOG" Set syslog facility\n" | |
11fdf7f2 | 1638 | " --"OPT_LOG_LEVEL"=<int> Set global log level\n" |
9f95a23c | 1639 | " --"OPT_LOG_LEVEL"=<type-match>:<int>\n" |
11fdf7f2 | 1640 | " Set specific log level\n" |
7c673cae FG |
1641 | " -v Display version information on startup\n" |
1642 | " -h, --help This help\n" | |
9f95a23c TL |
1643 | " --"OPT_IN_MEMORY" Operate entirely in memory. This will\n" |
1644 | " disable secondary process support\n" | |
7c673cae FG |
1645 | "\nEAL options for DEBUG use only:\n" |
1646 | " --"OPT_HUGE_UNLINK" Unlink hugepage files after init\n" | |
1647 | " --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n" | |
1648 | " --"OPT_NO_PCI" Disable PCI\n" | |
1649 | " --"OPT_NO_HPET" Disable HPET\n" | |
1650 | " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n" | |
1651 | "\n", RTE_MAX_LCORE); | |
9f95a23c | 1652 | rte_option_usage(); |
7c673cae | 1653 | } |