Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2018 Intel Corporation.
3 : : * Copyright(c) 2012-2014 6WIND S.A.
4 : : */
5 : :
6 : : #include <ctype.h>
7 : : #include <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <stdint.h>
10 : : #include <string.h>
11 : : #include <unistd.h>
12 : : #include <pthread.h>
13 : : #include <getopt.h>
14 : : #include <sys/file.h>
15 : : #include <dirent.h>
16 : : #include <fcntl.h>
17 : : #include <fnmatch.h>
18 : : #include <stddef.h>
19 : : #include <errno.h>
20 : : #include <limits.h>
21 : : #include <sys/mman.h>
22 : : #include <sys/stat.h>
23 : : #if defined(RTE_ARCH_X86)
24 : : #include <sys/io.h>
25 : : #endif
26 : : #include <linux/version.h>
27 : :
28 : : #include <rte_common.h>
29 : : #include <rte_debug.h>
30 : : #include <rte_memory.h>
31 : : #include <rte_launch.h>
32 : : #include <rte_eal.h>
33 : : #include <rte_eal_memconfig.h>
34 : : #include <rte_eal_paging.h>
35 : : #include <rte_errno.h>
36 : : #include <rte_lcore.h>
37 : : #include <rte_service_component.h>
38 : : #include <rte_log.h>
39 : : #include <rte_string_fns.h>
40 : : #include <rte_cpuflags.h>
41 : : #include <rte_bus.h>
42 : : #include <rte_version.h>
43 : : #include <malloc_heap.h>
44 : : #include <rte_vfio.h>
45 : :
46 : : #include <telemetry_internal.h>
47 : : #include <eal_export.h>
48 : : #include "eal_private.h"
49 : : #include "eal_thread.h"
50 : : #include "eal_lcore_var.h"
51 : : #include "eal_internal_cfg.h"
52 : : #include "eal_filesystem.h"
53 : : #include "eal_hugepages.h"
54 : : #include "eal_memcfg.h"
55 : : #include "eal_trace.h"
56 : : #include "eal_options.h"
57 : : #include "eal_vfio.h"
58 : : #include "hotplug_mp.h"
59 : : #include "log_internal.h"
60 : :
61 : : #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
62 : : #define KERNEL_IOMMU_GROUPS_PATH "/sys/kernel/iommu_groups"
63 : :
64 : : /* define fd variable here, because file needs to be kept open for the
65 : : * duration of the program, as we hold a write lock on it in the primary proc */
66 : : static int mem_cfg_fd = -1;
67 : :
68 : : static struct flock wr_lock = {
69 : : .l_type = F_WRLCK,
70 : : .l_whence = SEEK_SET,
71 : : .l_start = offsetof(struct rte_mem_config, memsegs),
72 : : .l_len = RTE_SIZEOF_FIELD(struct rte_mem_config, memsegs),
73 : : };
74 : :
75 : : /* internal configuration (per-core) */
76 : : struct lcore_config lcore_config[RTE_MAX_LCORE];
77 : :
78 : : /* used by rte_rdtsc() */
79 : : RTE_EXPORT_SYMBOL(rte_cycles_vmware_tsc_map)
80 : : int rte_cycles_vmware_tsc_map;
81 : :
82 : :
83 : : int
84 : 210 : eal_clean_runtime_dir(void)
85 : : {
86 : 210 : const char *runtime_dir = rte_eal_get_runtime_dir();
87 : : DIR *dir;
88 : : struct dirent *dirent;
89 : : int dir_fd, fd, lck_result;
90 : : static const char * const filters[] = {
91 : : "fbarray_*",
92 : : "mp_socket_*"
93 : : };
94 : :
95 : : /* open directory */
96 : 210 : dir = opendir(runtime_dir);
97 [ - + ]: 210 : if (!dir) {
98 : 0 : EAL_LOG(ERR, "Unable to open runtime directory %s",
99 : : runtime_dir);
100 : 0 : goto error;
101 : : }
102 : 210 : dir_fd = dirfd(dir);
103 : :
104 : : /* lock the directory before doing anything, to avoid races */
105 [ - + ]: 210 : if (flock(dir_fd, LOCK_EX) < 0) {
106 : 0 : EAL_LOG(ERR, "Unable to lock runtime directory %s",
107 : : runtime_dir);
108 : 0 : goto error;
109 : : }
110 : :
111 : 210 : dirent = readdir(dir);
112 [ - + ]: 210 : if (!dirent) {
113 : 0 : EAL_LOG(ERR, "Unable to read runtime directory %s",
114 : : runtime_dir);
115 : 0 : goto error;
116 : : }
117 : :
118 [ + + ]: 1796 : while (dirent != NULL) {
119 : : unsigned int f_idx;
120 : : bool skip = true;
121 : :
122 : : /* skip files that don't match the patterns */
123 [ + + ]: 3598 : for (f_idx = 0; f_idx < RTE_DIM(filters); f_idx++) {
124 : 2607 : const char *filter = filters[f_idx];
125 : :
126 [ + + ]: 2607 : if (fnmatch(filter, dirent->d_name, 0) == 0) {
127 : : skip = false;
128 : : break;
129 : : }
130 : : }
131 [ + + ]: 1586 : if (skip) {
132 : 991 : dirent = readdir(dir);
133 : 991 : continue;
134 : : }
135 : :
136 : : /* try and lock the file */
137 : 595 : fd = openat(dir_fd, dirent->d_name, O_RDONLY);
138 : :
139 : : /* skip to next file */
140 [ + + ]: 595 : if (fd == -1) {
141 : 30 : dirent = readdir(dir);
142 : 30 : continue;
143 : : }
144 : :
145 : : /* non-blocking lock */
146 : 565 : lck_result = flock(fd, LOCK_EX | LOCK_NB);
147 : :
148 : : /* if lock succeeds, remove the file */
149 [ + + ]: 565 : if (lck_result != -1)
150 : 1 : unlinkat(dir_fd, dirent->d_name, 0);
151 : 565 : close(fd);
152 : 565 : dirent = readdir(dir);
153 : : }
154 : :
155 : : /* closedir closes dir_fd and drops the lock */
156 : 210 : closedir(dir);
157 : 210 : return 0;
158 : :
159 : 0 : error:
160 [ # # ]: 0 : if (dir)
161 : 0 : closedir(dir);
162 : :
163 : 0 : EAL_LOG(ERR, "Error while clearing runtime dir: %s",
164 : : strerror(errno));
165 : :
166 : 0 : return -1;
167 : : }
168 : :
169 : :
170 : : /* create memory configuration in shared/mmap memory. Take out
171 : : * a write lock on the memsegs, so we can auto-detect primary/secondary.
172 : : * This means we never close the file while running (auto-close on exit).
173 : : * We also don't lock the whole file, so that in future we can use read-locks
174 : : * on other parts, e.g. memzones, to detect if there are running secondary
175 : : * processes. */
176 : : static int
177 : 193 : rte_eal_config_create(void)
178 : : {
179 : 193 : struct rte_config *config = rte_eal_get_configuration();
180 : 193 : size_t page_sz = rte_mem_page_size();
181 : : size_t cfg_len = sizeof(*config->mem_config);
182 : 193 : size_t cfg_len_aligned = RTE_ALIGN(cfg_len, page_sz);
183 : : void *rte_mem_cfg_addr, *mapped_mem_cfg_addr;
184 : : int retval;
185 : : const struct internal_config *internal_conf =
186 : 193 : eal_get_internal_configuration();
187 : :
188 : 193 : const char *pathname = eal_runtime_config_path();
189 : :
190 [ + + ]: 193 : if (internal_conf->no_shconf)
191 : : return 0;
192 : :
193 : : /* map the config before hugepage address so that we don't waste a page */
194 [ + + ]: 183 : if (internal_conf->base_virtaddr != 0)
195 : 1 : rte_mem_cfg_addr = (void *)
196 : 1 : RTE_ALIGN_FLOOR(internal_conf->base_virtaddr -
197 : : sizeof(struct rte_mem_config), page_sz);
198 : : else
199 : : rte_mem_cfg_addr = NULL;
200 : :
201 [ + - ]: 183 : if (mem_cfg_fd < 0){
202 : 183 : mem_cfg_fd = open(pathname, O_RDWR | O_CREAT, 0600);
203 [ - + ]: 183 : if (mem_cfg_fd < 0) {
204 : 0 : EAL_LOG(ERR, "Cannot open '%s' for rte_mem_config",
205 : : pathname);
206 : 0 : return -1;
207 : : }
208 : : }
209 : :
210 : 183 : retval = ftruncate(mem_cfg_fd, cfg_len);
211 [ - + ]: 183 : if (retval < 0){
212 : 0 : close(mem_cfg_fd);
213 : 0 : mem_cfg_fd = -1;
214 : 0 : EAL_LOG(ERR, "Cannot resize '%s' for rte_mem_config",
215 : : pathname);
216 : 0 : return -1;
217 : : }
218 : :
219 : 183 : retval = fcntl(mem_cfg_fd, F_SETLK, &wr_lock);
220 [ - + ]: 183 : if (retval < 0){
221 : 0 : close(mem_cfg_fd);
222 : 0 : mem_cfg_fd = -1;
223 : 0 : EAL_LOG(ERR, "Cannot create lock on '%s'. Is another primary "
224 : : "process running?", pathname);
225 : 0 : return -1;
226 : : }
227 : :
228 : : /* reserve space for config */
229 : 183 : rte_mem_cfg_addr = eal_get_virtual_area(rte_mem_cfg_addr,
230 : : &cfg_len_aligned, page_sz, 0, 0);
231 [ - + ]: 183 : if (rte_mem_cfg_addr == NULL) {
232 : 0 : EAL_LOG(ERR, "Cannot mmap memory for rte_config");
233 : 0 : close(mem_cfg_fd);
234 : 0 : mem_cfg_fd = -1;
235 : 0 : return -1;
236 : : }
237 : :
238 : : /* remap the actual file into the space we've just reserved */
239 : 183 : mapped_mem_cfg_addr = mmap(rte_mem_cfg_addr,
240 : : cfg_len_aligned, PROT_READ | PROT_WRITE,
241 : : MAP_SHARED | MAP_FIXED, mem_cfg_fd, 0);
242 [ - + ]: 183 : if (mapped_mem_cfg_addr == MAP_FAILED) {
243 : 0 : munmap(rte_mem_cfg_addr, cfg_len);
244 : 0 : close(mem_cfg_fd);
245 : 0 : mem_cfg_fd = -1;
246 : 0 : EAL_LOG(ERR, "Cannot remap memory for rte_config");
247 : 0 : return -1;
248 : : }
249 : :
250 : 183 : memcpy(rte_mem_cfg_addr, config->mem_config, sizeof(struct rte_mem_config));
251 : 183 : config->mem_config = rte_mem_cfg_addr;
252 : :
253 : : /* store address of the config in the config itself so that secondary
254 : : * processes could later map the config into this exact location
255 : : */
256 : 183 : config->mem_config->mem_cfg_addr = (uintptr_t) rte_mem_cfg_addr;
257 : 183 : config->mem_config->dma_maskbits = 0;
258 : :
259 : 183 : return 0;
260 : : }
261 : :
262 : : /* attach to an existing shared memory config */
263 : : static int
264 : 33 : rte_eal_config_attach(void)
265 : : {
266 : 33 : struct rte_config *config = rte_eal_get_configuration();
267 : : struct rte_mem_config *mem_config;
268 : : const struct internal_config *internal_conf =
269 : 33 : eal_get_internal_configuration();
270 : :
271 : 33 : const char *pathname = eal_runtime_config_path();
272 : :
273 [ + - ]: 33 : if (internal_conf->no_shconf)
274 : : return 0;
275 : :
276 [ + + ]: 33 : if (mem_cfg_fd < 0){
277 : 32 : mem_cfg_fd = open(pathname, O_RDWR);
278 [ + + ]: 32 : if (mem_cfg_fd < 0) {
279 : 1 : EAL_LOG(ERR, "Cannot open '%s' for rte_mem_config",
280 : : pathname);
281 : 1 : return -1;
282 : : }
283 : : }
284 : :
285 : : /* map it as read-only first */
286 : 32 : mem_config = (struct rte_mem_config *) mmap(NULL, sizeof(*mem_config),
287 : : PROT_READ, MAP_SHARED, mem_cfg_fd, 0);
288 [ - + ]: 32 : if (mem_config == MAP_FAILED) {
289 : 0 : close(mem_cfg_fd);
290 : 0 : mem_cfg_fd = -1;
291 : 0 : EAL_LOG(ERR, "Cannot mmap memory for rte_config! error %i (%s)",
292 : : errno, strerror(errno));
293 : 0 : return -1;
294 : : }
295 : :
296 : 32 : config->mem_config = mem_config;
297 : :
298 : 32 : return 0;
299 : : }
300 : :
301 : : /* reattach the shared config at exact memory location primary process has it */
302 : : static int
303 : 32 : rte_eal_config_reattach(void)
304 : : {
305 : 32 : struct rte_config *config = rte_eal_get_configuration();
306 : : struct rte_mem_config *mem_config;
307 : : void *rte_mem_cfg_addr;
308 : : const struct internal_config *internal_conf =
309 : 32 : eal_get_internal_configuration();
310 : :
311 [ + - ]: 32 : if (internal_conf->no_shconf)
312 : : return 0;
313 : :
314 : : /* save the address primary process has mapped shared config to */
315 : 32 : rte_mem_cfg_addr =
316 : 32 : (void *) (uintptr_t) config->mem_config->mem_cfg_addr;
317 : :
318 : : /* unmap original config */
319 : 32 : munmap(config->mem_config, sizeof(struct rte_mem_config));
320 : :
321 : : /* remap the config at proper address */
322 : 32 : mem_config = (struct rte_mem_config *) mmap(rte_mem_cfg_addr,
323 : : sizeof(*mem_config), PROT_READ | PROT_WRITE, MAP_SHARED,
324 : : mem_cfg_fd, 0);
325 : :
326 : 32 : close(mem_cfg_fd);
327 : 32 : mem_cfg_fd = -1;
328 : :
329 [ - + ]: 32 : if (mem_config == MAP_FAILED || mem_config != rte_mem_cfg_addr) {
330 [ # # ]: 0 : if (mem_config != MAP_FAILED) {
331 : : /* errno is stale, don't use */
332 : 0 : EAL_LOG(ERR, "Cannot mmap memory for rte_config at [%p], got [%p] - please use '--base-virtaddr' option",
333 : : rte_mem_cfg_addr, mem_config);
334 : 0 : munmap(mem_config, sizeof(struct rte_mem_config));
335 : 0 : return -1;
336 : : }
337 : 0 : EAL_LOG(ERR, "Cannot mmap memory for rte_config! error %i (%s)",
338 : : errno, strerror(errno));
339 : 0 : return -1;
340 : : }
341 : :
342 : 32 : config->mem_config = mem_config;
343 : :
344 : 32 : return 0;
345 : : }
346 : :
347 : : /* Detect if we are a primary or a secondary process */
348 : : enum rte_proc_type_t
349 : 3 : eal_proc_type_detect(void)
350 : : {
351 : : enum rte_proc_type_t ptype = RTE_PROC_PRIMARY;
352 : 3 : const char *pathname = eal_runtime_config_path();
353 : : const struct internal_config *internal_conf =
354 : 3 : eal_get_internal_configuration();
355 : :
356 : : /* if there no shared config, there can be no secondary processes */
357 [ + + ]: 3 : if (!internal_conf->no_shconf) {
358 : : /* if we can open the file but not get a write-lock we are a
359 : : * secondary process. NOTE: if we get a file handle back, we
360 : : * keep that open and don't close it to prevent a race condition
361 : : * between multiple opens.
362 : : */
363 [ + + + - ]: 3 : if (((mem_cfg_fd = open(pathname, O_RDWR)) >= 0) &&
364 : 1 : (fcntl(mem_cfg_fd, F_SETLK, &wr_lock) < 0))
365 : : ptype = RTE_PROC_SECONDARY;
366 : : }
367 : :
368 : 3 : EAL_LOG(INFO, "Auto-detected process type: %s",
369 : : ptype == RTE_PROC_PRIMARY ? "PRIMARY" : "SECONDARY");
370 : :
371 : 3 : return ptype;
372 : : }
373 : :
374 : : /* Sets up rte_config structure with the pointer to shared memory config.*/
375 : : static int
376 : 226 : rte_config_init(void)
377 : : {
378 : 226 : struct rte_config *config = rte_eal_get_configuration();
379 : : const struct internal_config *internal_conf =
380 : 226 : eal_get_internal_configuration();
381 : :
382 : 226 : config->process_type = internal_conf->process_type;
383 : :
384 [ + + - - ]: 226 : switch (config->process_type) {
385 : 193 : case RTE_PROC_PRIMARY:
386 [ + - ]: 193 : if (rte_eal_config_create() < 0)
387 : : return -1;
388 : 193 : eal_mcfg_update_from_internal();
389 : 193 : break;
390 : 33 : case RTE_PROC_SECONDARY:
391 [ + + ]: 33 : if (rte_eal_config_attach() < 0)
392 : : return -1;
393 : 32 : eal_mcfg_wait_complete();
394 [ - + ]: 32 : if (eal_mcfg_check_version() < 0) {
395 : 0 : EAL_LOG(ERR, "Primary and secondary process DPDK version mismatch");
396 : 0 : return -1;
397 : : }
398 [ + - ]: 32 : if (rte_eal_config_reattach() < 0)
399 : : return -1;
400 [ - + ]: 32 : if (!__rte_mp_enable()) {
401 : 0 : EAL_LOG(ERR, "Primary process refused secondary attachment");
402 : 0 : return -1;
403 : : }
404 : 32 : eal_mcfg_update_internal();
405 : 32 : break;
406 : 0 : case RTE_PROC_AUTO:
407 : : case RTE_PROC_INVALID:
408 : 0 : EAL_LOG(ERR, "Invalid process type %d",
409 : : config->process_type);
410 : 0 : return -1;
411 : : }
412 : :
413 : : return 0;
414 : : }
415 : :
416 : : /* Unlocks hugepage directories that were locked by eal_hugepage_info_init */
417 : : static void
418 : 220 : eal_hugedirs_unlock(void)
419 : : {
420 : : int i;
421 : : struct internal_config *internal_conf =
422 : 220 : eal_get_internal_configuration();
423 : :
424 [ + + ]: 880 : for (i = 0; i < MAX_HUGEPAGE_SIZES; i++)
425 : : {
426 : : /* skip uninitialized */
427 [ + + ]: 660 : if (internal_conf->hugepage_info[i].lock_descriptor < 0)
428 : 598 : continue;
429 : : /* unlock hugepage file */
430 : 62 : flock(internal_conf->hugepage_info[i].lock_descriptor, LOCK_UN);
431 : 62 : close(internal_conf->hugepage_info[i].lock_descriptor);
432 : : /* reset the field */
433 : 62 : internal_conf->hugepage_info[i].lock_descriptor = -1;
434 : : }
435 : 220 : }
436 : :
437 : : static int
438 : 220 : check_socket(const struct rte_memseg_list *msl, void *arg)
439 : : {
440 : : int *socket_id = arg;
441 : :
442 [ + - ]: 220 : if (msl->external)
443 : : return 0;
444 : :
445 : 220 : return *socket_id == msl->socket_id;
446 : : }
447 : :
448 : : static void
449 : 220 : eal_check_mem_on_local_socket(void)
450 : : {
451 : : int socket_id;
452 : 220 : const struct rte_config *config = rte_eal_get_configuration();
453 : :
454 : 220 : socket_id = rte_lcore_to_socket_id(config->main_lcore);
455 : :
456 [ - + ]: 220 : if (rte_memseg_list_walk(check_socket, &socket_id) == 0)
457 : 0 : EAL_LOG(WARNING, "WARNING: Main core has no memory on local socket!");
458 : 220 : }
459 : :
460 : : static int
461 : 153 : sync_func(__rte_unused void *arg)
462 : : {
463 : 153 : return 0;
464 : : }
465 : :
466 : : /*
467 : : * Request iopl privilege for all RPL, returns 0 on success
468 : : * iopl() call is mostly for the i386 architecture. For other architectures,
469 : : * return -1 to indicate IO privilege can't be changed in this way.
470 : : */
471 : : RTE_EXPORT_SYMBOL(rte_eal_iopl_init)
472 : : int
473 : 301 : rte_eal_iopl_init(void)
474 : : {
475 : : #if defined(RTE_ARCH_X86)
476 [ - + ]: 301 : if (iopl(3) != 0)
477 : 0 : return -1;
478 : : #endif
479 : : return 0;
480 : : }
481 : :
482 : 63 : static void rte_eal_init_alert(const char *msg)
483 : : {
484 : 63 : EAL_LOG(ALERT, "%s", msg);
485 : 63 : }
486 : :
487 : : /*
488 : : * On Linux 3.6+, even if VFIO is not loaded, whenever IOMMU is enabled in the
489 : : * BIOS and in the kernel, /sys/kernel/iommu_groups path will contain kernel
490 : : * IOMMU groups. If IOMMU is not enabled, that path would be empty.
491 : : * Therefore, checking if the path is empty will tell us if IOMMU is enabled.
492 : : */
493 : : static bool
494 : 97 : is_iommu_enabled(void)
495 : : {
496 : 97 : DIR *dir = opendir(KERNEL_IOMMU_GROUPS_PATH);
497 : : struct dirent *d;
498 : : int n = 0;
499 : :
500 : : /* if directory doesn't exist, assume IOMMU is not enabled */
501 [ + - ]: 97 : if (dir == NULL)
502 : : return false;
503 : :
504 [ + + ]: 291 : while ((d = readdir(dir)) != NULL) {
505 : : /* skip dot and dot-dot */
506 [ + - ]: 194 : if (++n > 2)
507 : : break;
508 : : }
509 : 97 : closedir(dir);
510 : :
511 : 97 : return n > 2;
512 : : }
513 : :
514 : : static __rte_noreturn void *
515 : 153 : eal_worker_thread_loop(void *arg)
516 : : {
517 : 153 : eal_thread_loop(arg);
518 : : }
519 : :
520 : : static int
521 : 153 : eal_worker_thread_create(unsigned int lcore_id)
522 : : {
523 : : pthread_attr_t *attrp = NULL;
524 : : void *stack_ptr = NULL;
525 : : pthread_attr_t attr;
526 : : size_t stack_size;
527 : : int ret = -1;
528 : :
529 : 153 : stack_size = eal_get_internal_configuration()->huge_worker_stack_size;
530 [ - + ]: 153 : if (stack_size != 0) {
531 : : /* Allocate NUMA aware stack memory and set pthread attributes */
532 : 0 : stack_ptr = rte_zmalloc_socket("lcore_stack", stack_size,
533 : 0 : RTE_CACHE_LINE_SIZE, rte_lcore_to_socket_id(lcore_id));
534 [ # # ]: 0 : if (stack_ptr == NULL) {
535 : 0 : rte_eal_init_alert("Cannot allocate worker lcore stack memory");
536 : 0 : rte_errno = ENOMEM;
537 : 0 : goto out;
538 : : }
539 : :
540 [ # # ]: 0 : if (pthread_attr_init(&attr) != 0) {
541 : 0 : rte_eal_init_alert("Cannot init pthread attributes");
542 : 0 : rte_errno = EFAULT;
543 : 0 : goto out;
544 : : }
545 : : attrp = &attr;
546 : :
547 [ # # ]: 0 : if (pthread_attr_setstack(attrp, stack_ptr, stack_size) != 0) {
548 : 0 : rte_eal_init_alert("Cannot set pthread stack attributes");
549 : 0 : rte_errno = EFAULT;
550 : 0 : goto out;
551 : : }
552 : : }
553 : :
554 [ - + ]: 153 : if (pthread_create((pthread_t *)&lcore_config[lcore_id].thread_id.opaque_id,
555 : 153 : attrp, eal_worker_thread_loop, (void *)(uintptr_t)lcore_id) == 0)
556 : : ret = 0;
557 : :
558 : 0 : out:
559 [ - + ]: 153 : if (ret != 0)
560 : 0 : rte_free(stack_ptr);
561 [ - + ]: 153 : if (attrp != NULL)
562 : 0 : pthread_attr_destroy(attrp);
563 : 153 : return ret;
564 : : }
565 : :
566 : : /* Launch threads, called at application init(). */
567 : : RTE_EXPORT_SYMBOL(rte_eal_init)
568 : : int
569 : 303 : rte_eal_init(int argc, char **argv)
570 : : {
571 : : int i, fctret, ret;
572 : : static RTE_ATOMIC(uint32_t) run_once;
573 : : uint32_t has_run = 0;
574 : : char cpuset[RTE_CPU_AFFINITY_STR_LEN];
575 : : char thread_name[RTE_THREAD_NAME_SIZE];
576 : : bool phys_addrs;
577 : 303 : const struct rte_config *config = rte_eal_get_configuration();
578 : : struct internal_config *internal_conf =
579 : 302 : eal_get_internal_configuration();
580 : :
581 : : /* first check if we have been run before */
582 [ + + ]: 302 : if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
583 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
584 : 2 : rte_eal_init_alert("already called initialization.");
585 : 2 : rte_errno = EALREADY;
586 : 2 : return -1;
587 : : }
588 : :
589 : : /* clone argv to report out later in telemetry */
590 : 301 : eal_save_args(argc, argv);
591 : :
592 : 301 : fctret = eal_collate_args(argc, argv);
593 [ + + ]: 294 : if (fctret < 0) {
594 : 7 : rte_eal_init_alert("Invalid command line arguments.");
595 : 7 : rte_errno = EINVAL;
596 : 7 : goto err_out;
597 : : }
598 : :
599 : : /* setup log as early as possible */
600 [ + + ]: 287 : if (eal_parse_log_options() < 0) {
601 : 3 : rte_eal_init_alert("invalid log arguments.");
602 : 3 : rte_errno = EINVAL;
603 : 3 : goto err_out;
604 : : }
605 : :
606 : 284 : eal_log_init(program_invocation_short_name);
607 : :
608 : : /* checks if the machine is adequate */
609 [ - + ]: 284 : if (!rte_cpu_is_supported()) {
610 : 0 : rte_eal_init_alert("unsupported cpu type.");
611 : 0 : rte_errno = ENOTSUP;
612 : 0 : goto err_out;
613 : : }
614 : :
615 : : /* verify if DPDK supported on architecture MMU */
616 [ - + ]: 284 : if (!eal_mmu_supported()) {
617 : 0 : rte_eal_init_alert("unsupported MMU type.");
618 : 0 : rte_errno = ENOTSUP;
619 : 0 : goto err_out;
620 : : }
621 : :
622 : 284 : eal_reset_internal_config(internal_conf);
623 : :
624 [ - + ]: 284 : if (rte_eal_cpu_init() < 0) {
625 : 0 : rte_eal_init_alert("Cannot detect lcores.");
626 : 0 : rte_errno = ENOTSUP;
627 : 0 : goto err_out;
628 : : }
629 : :
630 [ + + ]: 284 : if (eal_parse_args() < 0) {
631 : 45 : rte_eal_init_alert("Error parsing command line arguments.");
632 : 45 : rte_errno = EINVAL;
633 : 45 : goto err_out;
634 : : }
635 : :
636 [ - + ]: 239 : if (eal_plugins_init() < 0) {
637 : 0 : rte_eal_init_alert("Cannot init plugins");
638 : 0 : rte_errno = EINVAL;
639 : 0 : goto err_out;
640 : : }
641 : :
642 [ - + ]: 239 : if (eal_trace_init() < 0) {
643 : 0 : rte_eal_init_alert("Cannot init trace");
644 : 0 : rte_errno = EFAULT;
645 : 0 : goto err_out;
646 : : }
647 : :
648 [ + + ]: 239 : if (eal_option_device_parse()) {
649 : 13 : rte_errno = ENODEV;
650 : 13 : goto err_out;
651 : : }
652 : :
653 [ + + ]: 226 : if (rte_config_init() < 0) {
654 : 1 : rte_eal_init_alert("Cannot init config");
655 : 1 : goto err_out;
656 : : }
657 : :
658 [ - + ]: 225 : if (rte_eal_intr_init() < 0) {
659 : 0 : rte_eal_init_alert("Cannot init interrupt-handling thread");
660 : 0 : goto err_out;
661 : : }
662 : :
663 [ - + ]: 225 : if (rte_eal_alarm_init() < 0) {
664 : 0 : rte_eal_init_alert("Cannot init alarm");
665 : : /* rte_eal_alarm_init sets rte_errno on failure. */
666 : 0 : goto err_out;
667 : : }
668 : :
669 : : /* Put mp channel init before bus scan so that we can init the vdev
670 : : * bus through mp channel in the secondary process before the bus scan.
671 : : */
672 [ + + - + ]: 225 : if (rte_mp_channel_init() < 0 && rte_errno != ENOTSUP) {
673 : 0 : rte_eal_init_alert("failed to init mp channel");
674 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
675 : 0 : rte_errno = EFAULT;
676 : 0 : goto err_out;
677 : : }
678 : : }
679 : :
680 [ - + ]: 225 : if (rte_bus_scan()) {
681 : 0 : rte_eal_init_alert("Cannot scan the buses for devices");
682 : 0 : rte_errno = ENODEV;
683 : 0 : goto err_out;
684 : : }
685 : :
686 : 225 : phys_addrs = rte_eal_using_phys_addrs() != 0;
687 : :
688 : : /* Always call rte_bus_get_iommu_class() to trigger DMA mask detection and validation */
689 : 225 : enum rte_iova_mode bus_iova_mode = rte_bus_get_iommu_class();
690 : :
691 : : /* if no EAL option "--iova-mode=<pa|va>", use bus IOVA scheme */
692 [ + - ]: 225 : if (internal_conf->iova_mode == RTE_IOVA_DC) {
693 : : /* autodetect the IOVA mapping mode */
694 : : enum rte_iova_mode iova_mode = bus_iova_mode;
695 : :
696 [ + + ]: 225 : if (iova_mode == RTE_IOVA_DC) {
697 : 224 : EAL_LOG(DEBUG, "Buses did not request a specific IOVA mode.");
698 : :
699 : : if (!RTE_IOVA_IN_MBUF) {
700 : : iova_mode = RTE_IOVA_VA;
701 : : EAL_LOG(DEBUG, "IOVA as VA mode is forced by build option.");
702 [ + + ]: 224 : } else if (!phys_addrs) {
703 : : /* if we have no access to physical addresses,
704 : : * pick IOVA as VA mode.
705 : : */
706 : : iova_mode = RTE_IOVA_VA;
707 : 127 : EAL_LOG(DEBUG, "Physical addresses are unavailable, selecting IOVA as VA mode.");
708 [ - + ]: 97 : } else if (is_iommu_enabled()) {
709 : : /* we have an IOMMU, pick IOVA as VA mode */
710 : : iova_mode = RTE_IOVA_VA;
711 : 0 : EAL_LOG(DEBUG, "IOMMU is available, selecting IOVA as VA mode.");
712 : : } else {
713 : : /* physical addresses available, and no IOMMU
714 : : * found, so pick IOVA as PA.
715 : : */
716 : : iova_mode = RTE_IOVA_PA;
717 : 97 : EAL_LOG(DEBUG, "IOMMU is not available, selecting IOVA as PA mode.");
718 : : }
719 : : }
720 : 225 : rte_eal_get_configuration()->iova_mode = iova_mode;
721 : : } else {
722 : 0 : rte_eal_get_configuration()->iova_mode =
723 : 0 : internal_conf->iova_mode;
724 : : }
725 : :
726 [ + + - + ]: 225 : if (rte_eal_iova_mode() == RTE_IOVA_PA && !phys_addrs) {
727 : 0 : rte_eal_init_alert("Cannot use IOVA as 'PA' since physical addresses are not available");
728 : 0 : rte_errno = EINVAL;
729 : 0 : goto err_out;
730 : : }
731 : :
732 : 225 : if (rte_eal_iova_mode() == RTE_IOVA_PA && !RTE_IOVA_IN_MBUF) {
733 : : rte_eal_init_alert("Cannot use IOVA as 'PA' as it is disabled during build");
734 : : rte_errno = EINVAL;
735 : : goto err_out;
736 : : }
737 : :
738 [ + + ]: 353 : EAL_LOG(INFO, "Selected IOVA mode '%s'",
739 : : rte_eal_iova_mode() == RTE_IOVA_PA ? "PA" : "VA");
740 : :
741 [ + + ]: 225 : if (internal_conf->no_hugetlbfs == 0) {
742 : : /* rte_config isn't initialized yet */
743 : 97 : ret = internal_conf->process_type == RTE_PROC_PRIMARY ?
744 [ + + ]: 97 : eal_hugepage_info_init() :
745 : 32 : eal_hugepage_info_read();
746 [ + + ]: 97 : if (ret < 0) {
747 : 3 : rte_eal_init_alert("Cannot get hugepage information.");
748 : 3 : rte_errno = EACCES;
749 : 3 : goto err_out;
750 : : }
751 [ + + - + ]: 157 : if (internal_conf->process_type == RTE_PROC_PRIMARY &&
752 : 63 : eal_apply_hugepage_mem_sz_limits(internal_conf) < 0) {
753 : 0 : rte_eal_init_alert("Cannot apply hugepage memory limits.");
754 : 0 : rte_errno = EINVAL;
755 : 0 : goto err_out;
756 : : }
757 : : }
758 : :
759 [ + + + + ]: 222 : if (internal_conf->memory == 0 && internal_conf->force_numa == 0) {
760 [ + + ]: 86 : if (internal_conf->no_hugetlbfs)
761 : 9 : internal_conf->memory = MEMSIZE_IF_NO_HUGE_PAGE;
762 : : }
763 : :
764 [ - + ]: 222 : if (internal_conf->vmware_tsc_map == 1) {
765 : : #ifdef RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT
766 : : rte_cycles_vmware_tsc_map = 1;
767 : : EAL_LOG(DEBUG, "Using VMWARE TSC MAP, "
768 : : "you must have monitor_control.pseudo_perfctr = TRUE");
769 : : #else
770 : 0 : EAL_LOG(WARNING, "Ignoring --vmware-tsc-map because "
771 : : "RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT is not set");
772 : : #endif
773 : : }
774 : :
775 [ - + ]: 222 : if (rte_vfio_enable("vfio")) {
776 : 0 : rte_eal_init_alert("Cannot init VFIO");
777 : 0 : rte_errno = EAGAIN;
778 : 0 : goto err_out;
779 : : }
780 : : /* in secondary processes, memory init may allocate additional fbarrays
781 : : * not present in primary processes, so to avoid any potential issues,
782 : : * initialize memzones first.
783 : : */
784 [ - + ]: 222 : if (rte_eal_memzone_init() < 0) {
785 : 0 : rte_eal_init_alert("Cannot init memzone");
786 : 0 : rte_errno = ENODEV;
787 : 0 : goto err_out;
788 : : }
789 : :
790 : 222 : rte_mcfg_mem_read_lock();
791 : :
792 [ + + ]: 222 : if (rte_eal_memory_init() < 0) {
793 : 2 : rte_mcfg_mem_read_unlock();
794 : 2 : rte_eal_init_alert("Cannot init memory");
795 : 2 : rte_errno = ENOMEM;
796 : 2 : goto err_out;
797 : : }
798 : :
799 : : /* the directories are locked during eal_hugepage_info_init */
800 : 220 : eal_hugedirs_unlock();
801 : :
802 [ - + ]: 220 : if (rte_eal_malloc_heap_init() < 0) {
803 : 0 : rte_mcfg_mem_read_unlock();
804 : 0 : rte_eal_init_alert("Cannot init malloc heap");
805 : 0 : rte_errno = ENODEV;
806 : 0 : goto err_out;
807 : : }
808 : :
809 : 220 : rte_mcfg_mem_read_unlock();
810 : :
811 [ - + ]: 220 : if (rte_eal_malloc_heap_populate() < 0) {
812 : 0 : rte_eal_init_alert("Cannot init malloc heap");
813 : 0 : rte_errno = ENODEV;
814 : 0 : goto err_out;
815 : : }
816 : :
817 : : /* register multi-process action callbacks for hotplug after memory init */
818 [ - + ]: 220 : if (eal_mp_dev_hotplug_init() < 0) {
819 : 0 : rte_eal_init_alert("failed to register mp callback for hotplug");
820 : 0 : goto err_out;
821 : : }
822 : :
823 [ - + ]: 220 : if (rte_eal_tailqs_init() < 0) {
824 : 0 : rte_eal_init_alert("Cannot init tail queues for objects");
825 : 0 : rte_errno = EFAULT;
826 : 0 : goto err_out;
827 : : }
828 : :
829 [ - + ]: 220 : if (rte_eal_timer_init() < 0) {
830 : 0 : rte_eal_init_alert("Cannot init HPET or TSC timers");
831 : 0 : rte_errno = ENOTSUP;
832 : 0 : goto err_out;
833 : : }
834 : :
835 : 220 : eal_rand_init();
836 : :
837 : 220 : eal_check_mem_on_local_socket();
838 : :
839 [ - + ]: 220 : if (rte_thread_set_affinity_by_id(rte_thread_self(),
840 : 220 : &lcore_config[config->main_lcore].cpuset) != 0) {
841 : 0 : rte_eal_init_alert("Cannot set affinity");
842 : 0 : rte_errno = EINVAL;
843 : 0 : goto err_out;
844 : : }
845 : 220 : __rte_thread_init(config->main_lcore,
846 : 220 : &lcore_config[config->main_lcore].cpuset);
847 : :
848 : 220 : ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
849 [ - + ]: 220 : EAL_LOG(DEBUG, "Main lcore %u is ready (tid=%zx;cpuset=[%s%s])",
850 : : config->main_lcore, (uintptr_t)pthread_self(), cpuset,
851 : : ret == 0 ? "" : "...");
852 : :
853 [ + + ]: 373 : RTE_LCORE_FOREACH_WORKER(i) {
854 : :
855 : : /*
856 : : * create communication pipes between main thread
857 : : * and children
858 : : */
859 [ - + ]: 153 : if (pipe(lcore_config[i].pipe_main2worker) < 0)
860 : 0 : rte_panic("Cannot create pipe\n");
861 [ - + ]: 153 : if (pipe(lcore_config[i].pipe_worker2main) < 0)
862 : 0 : rte_panic("Cannot create pipe\n");
863 : :
864 : 153 : lcore_config[i].state = WAIT;
865 : :
866 : : /* create a thread for each lcore */
867 : 153 : ret = eal_worker_thread_create(i);
868 [ - + ]: 153 : if (ret != 0)
869 : 0 : rte_panic("Cannot create thread\n");
870 : :
871 : : /* Set thread_name for aid in debugging. */
872 : : ret = snprintf(thread_name, sizeof(thread_name), "dpdk-worker%d", i);
873 [ - + ]: 153 : if (ret >= RTE_THREAD_NAME_SIZE)
874 : 0 : EAL_LOG(INFO, "Worker thread name %s truncated", thread_name);
875 : :
876 : 153 : rte_thread_set_name(lcore_config[i].thread_id, thread_name);
877 : :
878 : 153 : ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id,
879 : 153 : &lcore_config[i].cpuset);
880 [ - + ]: 153 : if (ret != 0)
881 : 0 : rte_panic("Cannot set affinity\n");
882 : : }
883 : :
884 : : /*
885 : : * Launch a dummy function on all worker lcores, so that main lcore
886 : : * knows they are all ready when this function returns.
887 : : */
888 : 220 : rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MAIN);
889 : 220 : rte_eal_mp_wait_lcore();
890 : :
891 : : /* initialize services so vdevs register service during bus_probe. */
892 : 220 : ret = rte_service_init();
893 [ - + ]: 220 : if (ret) {
894 : 0 : rte_eal_init_alert("rte_service_init() failed");
895 : 0 : rte_errno = -ret;
896 : 0 : goto err_out;
897 : : }
898 : :
899 : : /* Probe all the buses and devices/drivers on them */
900 [ - + ]: 220 : if (rte_bus_probe()) {
901 : 0 : rte_eal_init_alert("Cannot probe devices");
902 : 0 : rte_errno = ENOTSUP;
903 : 0 : goto err_out;
904 : : }
905 : :
906 : : /* initialize default service/lcore mappings and start running. Ignore
907 : : * -ENOTSUP, as it indicates no service coremask passed to EAL.
908 : : */
909 : 220 : ret = rte_service_start_with_defaults();
910 [ - + ]: 220 : if (ret < 0 && ret != -ENOTSUP) {
911 : 0 : rte_errno = -ret;
912 : 0 : goto err_out;
913 : : }
914 : :
915 : : /*
916 : : * Clean up unused files in runtime directory. We do this at the end of
917 : : * init and not at the beginning because we want to clean stuff up
918 : : * whether we are primary or secondary process, but we cannot remove
919 : : * primary process' files because secondary should be able to run even
920 : : * if primary process is dead.
921 : : *
922 : : * In no_shconf mode, no runtime directory is created in the first
923 : : * place, so no cleanup needed.
924 : : */
925 [ + + - + ]: 220 : if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
926 : 0 : rte_eal_init_alert("Cannot clear runtime directory");
927 : 0 : goto err_out;
928 : : }
929 [ + + + + ]: 220 : if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
930 [ - + ]: 185 : if (rte_telemetry_init(rte_eal_get_runtime_dir(),
931 : : rte_version(),
932 : : &internal_conf->ctrl_cpuset) != 0)
933 : 0 : goto err_out;
934 : : }
935 : :
936 : 220 : eal_mcfg_complete();
937 : :
938 : 220 : return fctret;
939 : :
940 : 74 : err_out:
941 : 74 : rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
942 : 74 : eal_clean_saved_args();
943 : 74 : return -1;
944 : : }
945 : :
946 : : static int
947 : 61498526 : mark_freeable(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
948 : : void *arg __rte_unused)
949 : : {
950 : : /* ms is const, so find this memseg */
951 : : struct rte_memseg *found;
952 : :
953 [ + - ]: 61498526 : if (msl->external)
954 : : return 0;
955 : :
956 : 61498526 : found = rte_mem_virt2memseg(ms->addr, msl);
957 : :
958 : 61498526 : found->flags &= ~RTE_MEMSEG_FLAG_DO_NOT_FREE;
959 : :
960 : 61498526 : return 0;
961 : : }
962 : :
963 : : RTE_EXPORT_SYMBOL(rte_eal_cleanup)
964 : : int
965 : 294 : rte_eal_cleanup(void)
966 : : {
967 : : static RTE_ATOMIC(uint32_t) run_once;
968 : : uint32_t has_run = 0;
969 : :
970 [ - + ]: 294 : if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
971 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
972 : 0 : EAL_LOG(WARNING, "Already called cleanup");
973 : 0 : rte_errno = EALREADY;
974 : 0 : return -1;
975 : : }
976 : :
977 : : /* if we're in a primary process, we need to mark hugepages as freeable
978 : : * so that finalization can release them back to the system.
979 : : */
980 : : struct internal_config *internal_conf =
981 : 294 : eal_get_internal_configuration();
982 : :
983 [ + + ]: 294 : if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
984 [ + + ]: 261 : internal_conf->hugepage_file.unlink_existing)
985 : 250 : rte_memseg_walk(mark_freeable, NULL);
986 : :
987 : 294 : rte_service_finalize();
988 : 294 : eal_bus_cleanup();
989 : 294 : vfio_mp_sync_cleanup();
990 : 294 : rte_mp_channel_cleanup();
991 : 294 : rte_eal_alarm_cleanup();
992 : 294 : rte_trace_save();
993 : 294 : eal_trace_fini();
994 : 294 : eal_mp_dev_hotplug_cleanup();
995 : : /* after this point, any DPDK pointers will become dangling */
996 : 294 : rte_eal_memory_detach();
997 : 294 : rte_eal_malloc_heap_cleanup();
998 : 294 : eal_cleanup_config(internal_conf);
999 : 294 : eal_lcore_var_cleanup();
1000 : 294 : rte_eal_log_cleanup();
1001 : 294 : return 0;
1002 : : }
1003 : :
1004 : : RTE_EXPORT_SYMBOL(rte_eal_create_uio_dev)
1005 : 0 : int rte_eal_create_uio_dev(void)
1006 : : {
1007 : : const struct internal_config *internal_conf =
1008 : 0 : eal_get_internal_configuration();
1009 : :
1010 : 0 : return internal_conf->create_uio_dev;
1011 : : }
1012 : :
1013 : : RTE_EXPORT_SYMBOL(rte_eal_vfio_intr_mode)
1014 : : enum rte_intr_mode
1015 : 0 : rte_eal_vfio_intr_mode(void)
1016 : : {
1017 : : const struct internal_config *internal_conf =
1018 : 0 : eal_get_internal_configuration();
1019 : :
1020 : 0 : return internal_conf->vfio_intr_mode;
1021 : : }
1022 : :
1023 : : RTE_EXPORT_SYMBOL(rte_eal_vfio_get_vf_token)
1024 : : void
1025 : 0 : rte_eal_vfio_get_vf_token(rte_uuid_t vf_token)
1026 : : {
1027 : 0 : struct internal_config *cfg = eal_get_internal_configuration();
1028 : :
1029 : 0 : rte_uuid_copy(vf_token, cfg->vfio_vf_token);
1030 : 0 : }
1031 : :
1032 : : int
1033 : 222 : rte_eal_check_module(const char *module_name)
1034 : : {
1035 : : char sysfs_mod_name[PATH_MAX];
1036 : : struct stat st;
1037 : : int n;
1038 : :
1039 [ + - ]: 222 : if (NULL == module_name)
1040 : : return -1;
1041 : :
1042 : : /* Check if there is sysfs mounted */
1043 [ - + ]: 222 : if (stat("/sys/module", &st) != 0) {
1044 : 0 : EAL_LOG(DEBUG, "sysfs is not mounted! error %i (%s)",
1045 : : errno, strerror(errno));
1046 : 0 : return -1;
1047 : : }
1048 : :
1049 : : /* A module might be built-in, therefore try sysfs */
1050 : : n = snprintf(sysfs_mod_name, PATH_MAX, "/sys/module/%s", module_name);
1051 [ - + ]: 222 : if (n < 0 || n > PATH_MAX) {
1052 : 0 : EAL_LOG(DEBUG, "Could not format module path");
1053 : 0 : return -1;
1054 : : }
1055 : :
1056 [ + - ]: 222 : if (stat(sysfs_mod_name, &st) != 0) {
1057 : 222 : EAL_LOG(DEBUG, "Module %s not found! error %i (%s)",
1058 : : sysfs_mod_name, errno, strerror(errno));
1059 : 222 : return 0;
1060 : : }
1061 : :
1062 : : /* Module has been found */
1063 : : return 1;
1064 : : }
|