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 : 174 : eal_clean_runtime_dir(void)
85 : : {
86 : 174 : 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 : 174 : dir = opendir(runtime_dir);
97 [ - + ]: 174 : if (!dir) {
98 : 0 : EAL_LOG(ERR, "Unable to open runtime directory %s",
99 : : runtime_dir);
100 : 0 : goto error;
101 : : }
102 : 174 : dir_fd = dirfd(dir);
103 : :
104 : : /* lock the directory before doing anything, to avoid races */
105 [ - + ]: 174 : 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 : 174 : dirent = readdir(dir);
112 [ - + ]: 174 : if (!dirent) {
113 : 0 : EAL_LOG(ERR, "Unable to read runtime directory %s",
114 : : runtime_dir);
115 : 0 : goto error;
116 : : }
117 : :
118 [ + + ]: 2338 : while (dirent != NULL) {
119 : : unsigned int f_idx;
120 : : bool skip = true;
121 : :
122 : : /* skip files that don't match the patterns */
123 [ + + ]: 4017 : for (f_idx = 0; f_idx < RTE_DIM(filters); f_idx++) {
124 : 3103 : const char *filter = filters[f_idx];
125 : :
126 [ + + ]: 3103 : if (fnmatch(filter, dirent->d_name, 0) == 0) {
127 : : skip = false;
128 : : break;
129 : : }
130 : : }
131 [ + + ]: 2164 : if (skip) {
132 : 914 : dirent = readdir(dir);
133 : 914 : continue;
134 : : }
135 : :
136 : : /* try and lock the file */
137 : 1250 : fd = openat(dir_fd, dirent->d_name, O_RDONLY);
138 : :
139 : : /* skip to next file */
140 [ + + ]: 1250 : if (fd == -1) {
141 : 25 : dirent = readdir(dir);
142 : 25 : continue;
143 : : }
144 : :
145 : : /* non-blocking lock */
146 : 1225 : lck_result = flock(fd, LOCK_EX | LOCK_NB);
147 : :
148 : : /* if lock succeeds, remove the file */
149 [ + + ]: 1225 : if (lck_result != -1)
150 : 145 : unlinkat(dir_fd, dirent->d_name, 0);
151 : 1225 : close(fd);
152 : 1225 : dirent = readdir(dir);
153 : : }
154 : :
155 : : /* closedir closes dir_fd and drops the lock */
156 : 174 : closedir(dir);
157 : 174 : 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 : 159 : rte_eal_config_create(void)
178 : : {
179 : 159 : struct rte_config *config = rte_eal_get_configuration();
180 : 159 : size_t page_sz = rte_mem_page_size();
181 : : size_t cfg_len = sizeof(*config->mem_config);
182 : 159 : 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 : 159 : eal_get_internal_configuration();
187 : :
188 : 159 : const char *pathname = eal_runtime_config_path();
189 : :
190 [ + + ]: 159 : 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 [ + + ]: 152 : 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 [ + - ]: 152 : if (mem_cfg_fd < 0){
202 : 152 : mem_cfg_fd = open(pathname, O_RDWR | O_CREAT, 0600);
203 [ - + ]: 152 : 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 : 152 : retval = ftruncate(mem_cfg_fd, cfg_len);
211 [ - + ]: 152 : 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 : 152 : retval = fcntl(mem_cfg_fd, F_SETLK, &wr_lock);
220 [ - + ]: 152 : 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 : 152 : rte_mem_cfg_addr = eal_get_virtual_area(rte_mem_cfg_addr,
230 : : &cfg_len_aligned, page_sz, 0, 0);
231 [ - + ]: 152 : 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 : 152 : 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 [ - + ]: 152 : 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 : 152 : memcpy(rte_mem_cfg_addr, config->mem_config, sizeof(struct rte_mem_config));
251 : 152 : 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 : 152 : config->mem_config->mem_cfg_addr = (uintptr_t) rte_mem_cfg_addr;
257 : 152 : config->mem_config->dma_maskbits = 0;
258 : :
259 : 152 : return 0;
260 : : }
261 : :
262 : : /* attach to an existing shared memory config */
263 : : static int
264 : 28 : rte_eal_config_attach(void)
265 : : {
266 : 28 : struct rte_config *config = rte_eal_get_configuration();
267 : : struct rte_mem_config *mem_config;
268 : : const struct internal_config *internal_conf =
269 : 28 : eal_get_internal_configuration();
270 : :
271 : 28 : const char *pathname = eal_runtime_config_path();
272 : :
273 [ + - ]: 28 : if (internal_conf->no_shconf)
274 : : return 0;
275 : :
276 [ + + ]: 28 : if (mem_cfg_fd < 0){
277 : 27 : mem_cfg_fd = open(pathname, O_RDWR);
278 [ + + ]: 27 : 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 : 27 : mem_config = (struct rte_mem_config *) mmap(NULL, sizeof(*mem_config),
287 : : PROT_READ, MAP_SHARED, mem_cfg_fd, 0);
288 [ - + ]: 27 : 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 : 27 : config->mem_config = mem_config;
297 : :
298 : 27 : return 0;
299 : : }
300 : :
301 : : /* reattach the shared config at exact memory location primary process has it */
302 : : static int
303 : 27 : rte_eal_config_reattach(void)
304 : : {
305 : 27 : 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 : 27 : eal_get_internal_configuration();
310 : :
311 [ + - ]: 27 : if (internal_conf->no_shconf)
312 : : return 0;
313 : :
314 : : /* save the address primary process has mapped shared config to */
315 : 27 : rte_mem_cfg_addr =
316 : 27 : (void *) (uintptr_t) config->mem_config->mem_cfg_addr;
317 : :
318 : : /* unmap original config */
319 : 27 : munmap(config->mem_config, sizeof(struct rte_mem_config));
320 : :
321 : : /* remap the config at proper address */
322 : 27 : 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 : 27 : close(mem_cfg_fd);
327 : 27 : mem_cfg_fd = -1;
328 : :
329 [ - + ]: 27 : 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 : 27 : config->mem_config = mem_config;
343 : :
344 : 27 : 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 : 187 : rte_config_init(void)
377 : : {
378 : 187 : struct rte_config *config = rte_eal_get_configuration();
379 : : const struct internal_config *internal_conf =
380 : 187 : eal_get_internal_configuration();
381 : :
382 : 187 : config->process_type = internal_conf->process_type;
383 : :
384 [ + + - - ]: 187 : switch (config->process_type) {
385 : 159 : case RTE_PROC_PRIMARY:
386 [ + - ]: 159 : if (rte_eal_config_create() < 0)
387 : : return -1;
388 : 159 : eal_mcfg_update_from_internal();
389 : 159 : break;
390 : 28 : case RTE_PROC_SECONDARY:
391 [ + + ]: 28 : if (rte_eal_config_attach() < 0)
392 : : return -1;
393 : 27 : eal_mcfg_wait_complete();
394 [ - + ]: 27 : if (eal_mcfg_check_version() < 0) {
395 : 0 : EAL_LOG(ERR, "Primary and secondary process DPDK version mismatch");
396 : 0 : return -1;
397 : : }
398 [ + - ]: 27 : if (rte_eal_config_reattach() < 0)
399 : : return -1;
400 [ - + ]: 27 : if (!__rte_mp_enable()) {
401 : 0 : EAL_LOG(ERR, "Primary process refused secondary attachment");
402 : 0 : return -1;
403 : : }
404 : 27 : eal_mcfg_update_internal();
405 : 27 : 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 : 181 : eal_hugedirs_unlock(void)
419 : : {
420 : : int i;
421 : : struct internal_config *internal_conf =
422 : 181 : eal_get_internal_configuration();
423 : :
424 [ + + ]: 724 : for (i = 0; i < MAX_HUGEPAGE_SIZES; i++)
425 : : {
426 : : /* skip uninitialized */
427 [ + + ]: 543 : if (internal_conf->hugepage_info[i].lock_descriptor < 0)
428 : 487 : continue;
429 : : /* unlock hugepage file */
430 : 56 : flock(internal_conf->hugepage_info[i].lock_descriptor, LOCK_UN);
431 : 56 : close(internal_conf->hugepage_info[i].lock_descriptor);
432 : : /* reset the field */
433 : 56 : internal_conf->hugepage_info[i].lock_descriptor = -1;
434 : : }
435 : 181 : }
436 : :
437 : : static int
438 : 181 : check_socket(const struct rte_memseg_list *msl, void *arg)
439 : : {
440 : : int *socket_id = arg;
441 : :
442 [ + - ]: 181 : if (msl->external)
443 : : return 0;
444 : :
445 : 181 : return *socket_id == msl->socket_id;
446 : : }
447 : :
448 : : static void
449 : 181 : eal_check_mem_on_local_socket(void)
450 : : {
451 : : int socket_id;
452 : 181 : const struct rte_config *config = rte_eal_get_configuration();
453 : :
454 : 181 : socket_id = rte_lcore_to_socket_id(config->main_lcore);
455 : :
456 [ - + ]: 181 : 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 : 181 : }
459 : :
460 : : static int
461 : 124 : sync_func(__rte_unused void *arg)
462 : : {
463 : 124 : 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 : 253 : rte_eal_iopl_init(void)
474 : : {
475 : : #if defined(RTE_ARCH_X86)
476 [ - + ]: 253 : if (iopl(3) != 0)
477 : 0 : return -1;
478 : : #endif
479 : : return 0;
480 : : }
481 : :
482 : 54 : static void rte_eal_init_alert(const char *msg)
483 : : {
484 : 54 : EAL_LOG(ALERT, "%s", msg);
485 : 54 : }
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 : 86 : is_iommu_enabled(void)
495 : : {
496 : 86 : 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 [ + - ]: 86 : if (dir == NULL)
502 : : return false;
503 : :
504 [ + + ]: 258 : while ((d = readdir(dir)) != NULL) {
505 : : /* skip dot and dot-dot */
506 [ + - ]: 172 : if (++n > 2)
507 : : break;
508 : : }
509 : 86 : closedir(dir);
510 : :
511 : 86 : return n > 2;
512 : : }
513 : :
514 : : static __rte_noreturn void *
515 : 124 : eal_worker_thread_loop(void *arg)
516 : : {
517 : 124 : eal_thread_loop(arg);
518 : : }
519 : :
520 : : static int
521 : 124 : 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 : 124 : stack_size = eal_get_internal_configuration()->huge_worker_stack_size;
530 [ - + ]: 124 : 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 [ - + ]: 124 : if (pthread_create((pthread_t *)&lcore_config[lcore_id].thread_id.opaque_id,
555 : 124 : attrp, eal_worker_thread_loop, (void *)(uintptr_t)lcore_id) == 0)
556 : : ret = 0;
557 : :
558 : 0 : out:
559 [ - + ]: 124 : if (ret != 0)
560 : 0 : rte_free(stack_ptr);
561 [ - + ]: 124 : if (attrp != NULL)
562 : 0 : pthread_attr_destroy(attrp);
563 : 124 : return ret;
564 : : }
565 : :
566 : : /* Launch threads, called at application init(). */
567 : : RTE_EXPORT_SYMBOL(rte_eal_init)
568 : : int
569 : 255 : 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 : 255 : const struct rte_config *config = rte_eal_get_configuration();
578 : : struct internal_config *internal_conf =
579 : 255 : eal_get_internal_configuration();
580 : :
581 : : /* first check if we have been run before */
582 [ + + ]: 255 : 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 : 253 : eal_save_args(argc, argv);
591 : :
592 : 253 : fctret = eal_collate_args(argc, argv);
593 [ + + ]: 246 : if (fctret < 0) {
594 : 5 : rte_eal_init_alert("Invalid command line arguments.");
595 : 5 : rte_errno = EINVAL;
596 : 5 : goto err_out;
597 : : }
598 : :
599 : : /* setup log as early as possible */
600 [ + + ]: 241 : 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 : 238 : eal_log_init(program_invocation_short_name);
607 : :
608 : : /* checks if the machine is adequate */
609 [ - + ]: 238 : 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 [ - + ]: 238 : 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 : 238 : eal_reset_internal_config(internal_conf);
623 : :
624 [ - + ]: 238 : 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 [ + + ]: 238 : if (eal_parse_args() < 0) {
631 : 38 : rte_eal_init_alert("Error parsing command line arguments.");
632 : 38 : rte_errno = EINVAL;
633 : 38 : goto err_out;
634 : : }
635 : :
636 [ - + ]: 200 : 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 [ - + ]: 200 : 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 [ + + ]: 200 : if (eal_option_device_parse()) {
649 : 13 : rte_errno = ENODEV;
650 : 13 : goto err_out;
651 : : }
652 : :
653 [ + + ]: 187 : if (rte_config_init() < 0) {
654 : 1 : rte_eal_init_alert("Cannot init config");
655 : 1 : goto err_out;
656 : : }
657 : :
658 [ - + ]: 186 : 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 [ - + ]: 186 : 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 [ + + - + ]: 186 : 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 [ - + ]: 186 : 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 : 186 : 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 : 186 : 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 [ + - ]: 186 : 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 [ + + ]: 186 : if (iova_mode == RTE_IOVA_DC) {
697 : 185 : 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 [ + + ]: 185 : } 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 : 99 : EAL_LOG(DEBUG, "Physical addresses are unavailable, selecting IOVA as VA mode.");
708 [ - + ]: 86 : } 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 : 86 : EAL_LOG(DEBUG, "IOMMU is not available, selecting IOVA as PA mode.");
718 : : }
719 : : }
720 : 186 : 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 [ + + - + ]: 186 : 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 : 186 : 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 [ + + ]: 286 : EAL_LOG(INFO, "Selected IOVA mode '%s'",
739 : : rte_eal_iova_mode() == RTE_IOVA_PA ? "PA" : "VA");
740 : :
741 [ + + ]: 186 : if (internal_conf->no_hugetlbfs == 0) {
742 : : /* rte_config isn't initialized yet */
743 : 86 : ret = internal_conf->process_type == RTE_PROC_PRIMARY ?
744 [ + + ]: 86 : eal_hugepage_info_init() :
745 : 27 : eal_hugepage_info_read();
746 [ + + ]: 86 : if (ret < 0) {
747 : 2 : rte_eal_init_alert("Cannot get hugepage information.");
748 : 2 : rte_errno = EACCES;
749 : 2 : goto err_out;
750 : : }
751 : : }
752 : :
753 [ + + + + ]: 184 : if (internal_conf->memory == 0 && internal_conf->force_numa == 0) {
754 [ + + ]: 74 : if (internal_conf->no_hugetlbfs)
755 : 7 : internal_conf->memory = MEMSIZE_IF_NO_HUGE_PAGE;
756 : : }
757 : :
758 [ - + ]: 184 : if (internal_conf->vmware_tsc_map == 1) {
759 : : #ifdef RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT
760 : : rte_cycles_vmware_tsc_map = 1;
761 : : EAL_LOG(DEBUG, "Using VMWARE TSC MAP, "
762 : : "you must have monitor_control.pseudo_perfctr = TRUE");
763 : : #else
764 : 0 : EAL_LOG(WARNING, "Ignoring --vmware-tsc-map because "
765 : : "RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT is not set");
766 : : #endif
767 : : }
768 : :
769 [ - + ]: 184 : if (rte_vfio_enable("vfio")) {
770 : 0 : rte_eal_init_alert("Cannot init VFIO");
771 : 0 : rte_errno = EAGAIN;
772 : 0 : goto err_out;
773 : : }
774 : : /* in secondary processes, memory init may allocate additional fbarrays
775 : : * not present in primary processes, so to avoid any potential issues,
776 : : * initialize memzones first.
777 : : */
778 [ - + ]: 184 : if (rte_eal_memzone_init() < 0) {
779 : 0 : rte_eal_init_alert("Cannot init memzone");
780 : 0 : rte_errno = ENODEV;
781 : 0 : goto err_out;
782 : : }
783 : :
784 : 184 : rte_mcfg_mem_read_lock();
785 : :
786 [ + + ]: 184 : if (rte_eal_memory_init() < 0) {
787 : 3 : rte_mcfg_mem_read_unlock();
788 : 3 : rte_eal_init_alert("Cannot init memory");
789 : 3 : rte_errno = ENOMEM;
790 : 3 : goto err_out;
791 : : }
792 : :
793 : : /* the directories are locked during eal_hugepage_info_init */
794 : 181 : eal_hugedirs_unlock();
795 : :
796 [ - + ]: 181 : if (rte_eal_malloc_heap_init() < 0) {
797 : 0 : rte_mcfg_mem_read_unlock();
798 : 0 : rte_eal_init_alert("Cannot init malloc heap");
799 : 0 : rte_errno = ENODEV;
800 : 0 : goto err_out;
801 : : }
802 : :
803 : 181 : rte_mcfg_mem_read_unlock();
804 : :
805 [ - + ]: 181 : if (rte_eal_malloc_heap_populate() < 0) {
806 : 0 : rte_eal_init_alert("Cannot init malloc heap");
807 : 0 : rte_errno = ENODEV;
808 : 0 : goto err_out;
809 : : }
810 : :
811 : : /* register multi-process action callbacks for hotplug after memory init */
812 [ - + ]: 181 : if (eal_mp_dev_hotplug_init() < 0) {
813 : 0 : rte_eal_init_alert("failed to register mp callback for hotplug");
814 : 0 : goto err_out;
815 : : }
816 : :
817 [ - + ]: 181 : if (rte_eal_tailqs_init() < 0) {
818 : 0 : rte_eal_init_alert("Cannot init tail queues for objects");
819 : 0 : rte_errno = EFAULT;
820 : 0 : goto err_out;
821 : : }
822 : :
823 [ - + ]: 181 : if (rte_eal_timer_init() < 0) {
824 : 0 : rte_eal_init_alert("Cannot init HPET or TSC timers");
825 : 0 : rte_errno = ENOTSUP;
826 : 0 : goto err_out;
827 : : }
828 : :
829 : 181 : eal_rand_init();
830 : :
831 : 181 : eal_check_mem_on_local_socket();
832 : :
833 [ - + ]: 181 : if (rte_thread_set_affinity_by_id(rte_thread_self(),
834 : 181 : &lcore_config[config->main_lcore].cpuset) != 0) {
835 : 0 : rte_eal_init_alert("Cannot set affinity");
836 : 0 : rte_errno = EINVAL;
837 : 0 : goto err_out;
838 : : }
839 : 181 : __rte_thread_init(config->main_lcore,
840 : 181 : &lcore_config[config->main_lcore].cpuset);
841 : :
842 : 181 : ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
843 [ - + ]: 181 : EAL_LOG(DEBUG, "Main lcore %u is ready (tid=%zx;cpuset=[%s%s])",
844 : : config->main_lcore, (uintptr_t)pthread_self(), cpuset,
845 : : ret == 0 ? "" : "...");
846 : :
847 [ + + ]: 305 : RTE_LCORE_FOREACH_WORKER(i) {
848 : :
849 : : /*
850 : : * create communication pipes between main thread
851 : : * and children
852 : : */
853 [ - + ]: 124 : if (pipe(lcore_config[i].pipe_main2worker) < 0)
854 : 0 : rte_panic("Cannot create pipe\n");
855 [ - + ]: 124 : if (pipe(lcore_config[i].pipe_worker2main) < 0)
856 : 0 : rte_panic("Cannot create pipe\n");
857 : :
858 : 124 : lcore_config[i].state = WAIT;
859 : :
860 : : /* create a thread for each lcore */
861 : 124 : ret = eal_worker_thread_create(i);
862 [ - + ]: 124 : if (ret != 0)
863 : 0 : rte_panic("Cannot create thread\n");
864 : :
865 : : /* Set thread_name for aid in debugging. */
866 : : snprintf(thread_name, sizeof(thread_name),
867 : : "dpdk-worker%d", i);
868 : 124 : rte_thread_set_name(lcore_config[i].thread_id, thread_name);
869 : :
870 : 124 : ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id,
871 : 124 : &lcore_config[i].cpuset);
872 [ - + ]: 124 : if (ret != 0)
873 : 0 : rte_panic("Cannot set affinity\n");
874 : : }
875 : :
876 : : /*
877 : : * Launch a dummy function on all worker lcores, so that main lcore
878 : : * knows they are all ready when this function returns.
879 : : */
880 : 181 : rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MAIN);
881 : 181 : rte_eal_mp_wait_lcore();
882 : :
883 : : /* initialize services so vdevs register service during bus_probe. */
884 : 181 : ret = rte_service_init();
885 [ - + ]: 181 : if (ret) {
886 : 0 : rte_eal_init_alert("rte_service_init() failed");
887 : 0 : rte_errno = -ret;
888 : 0 : goto err_out;
889 : : }
890 : :
891 : : /* Probe all the buses and devices/drivers on them */
892 [ - + ]: 181 : if (rte_bus_probe()) {
893 : 0 : rte_eal_init_alert("Cannot probe devices");
894 : 0 : rte_errno = ENOTSUP;
895 : 0 : goto err_out;
896 : : }
897 : :
898 : : /* initialize default service/lcore mappings and start running. Ignore
899 : : * -ENOTSUP, as it indicates no service coremask passed to EAL.
900 : : */
901 : 181 : ret = rte_service_start_with_defaults();
902 [ - + ]: 181 : if (ret < 0 && ret != -ENOTSUP) {
903 : 0 : rte_errno = -ret;
904 : 0 : goto err_out;
905 : : }
906 : :
907 : : /*
908 : : * Clean up unused files in runtime directory. We do this at the end of
909 : : * init and not at the beginning because we want to clean stuff up
910 : : * whether we are primary or secondary process, but we cannot remove
911 : : * primary process' files because secondary should be able to run even
912 : : * if primary process is dead.
913 : : *
914 : : * In no_shconf mode, no runtime directory is created in the first
915 : : * place, so no cleanup needed.
916 : : */
917 [ + + - + ]: 181 : if (!internal_conf->no_shconf && eal_clean_runtime_dir() < 0) {
918 : 0 : rte_eal_init_alert("Cannot clear runtime directory");
919 : 0 : goto err_out;
920 : : }
921 [ + + + - ]: 181 : if (rte_eal_process_type() == RTE_PROC_PRIMARY && !internal_conf->no_telemetry) {
922 [ - + ]: 156 : if (rte_telemetry_init(rte_eal_get_runtime_dir(),
923 : : rte_version(),
924 : : &internal_conf->ctrl_cpuset) != 0)
925 : 0 : goto err_out;
926 : : }
927 : :
928 : 181 : eal_mcfg_complete();
929 : :
930 : 181 : return fctret;
931 : :
932 : 65 : err_out:
933 : 65 : rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
934 : 65 : eal_clean_saved_args();
935 : 65 : return -1;
936 : : }
937 : :
938 : : static int
939 : 47834264 : mark_freeable(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
940 : : void *arg __rte_unused)
941 : : {
942 : : /* ms is const, so find this memseg */
943 : : struct rte_memseg *found;
944 : :
945 [ + - ]: 47834264 : if (msl->external)
946 : : return 0;
947 : :
948 : 47834264 : found = rte_mem_virt2memseg(ms->addr, msl);
949 : :
950 : 47834264 : found->flags &= ~RTE_MEMSEG_FLAG_DO_NOT_FREE;
951 : :
952 : 47834264 : return 0;
953 : : }
954 : :
955 : : RTE_EXPORT_SYMBOL(rte_eal_cleanup)
956 : : int
957 : 246 : rte_eal_cleanup(void)
958 : : {
959 : : static RTE_ATOMIC(uint32_t) run_once;
960 : : uint32_t has_run = 0;
961 : :
962 [ - + ]: 246 : if (!rte_atomic_compare_exchange_strong_explicit(&run_once, &has_run, 1,
963 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
964 : 0 : EAL_LOG(WARNING, "Already called cleanup");
965 : 0 : rte_errno = EALREADY;
966 : 0 : return -1;
967 : : }
968 : :
969 : : /* if we're in a primary process, we need to mark hugepages as freeable
970 : : * so that finalization can release them back to the system.
971 : : */
972 : : struct internal_config *internal_conf =
973 : 246 : eal_get_internal_configuration();
974 : :
975 [ + + ]: 246 : if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
976 [ + + ]: 218 : internal_conf->hugepage_file.unlink_existing)
977 : 209 : rte_memseg_walk(mark_freeable, NULL);
978 : :
979 : 246 : rte_service_finalize();
980 : 246 : eal_bus_cleanup();
981 : 246 : vfio_mp_sync_cleanup();
982 : 246 : rte_mp_channel_cleanup();
983 : 246 : rte_eal_alarm_cleanup();
984 : 246 : rte_trace_save();
985 : 246 : eal_trace_fini();
986 : 246 : eal_mp_dev_hotplug_cleanup();
987 : : /* after this point, any DPDK pointers will become dangling */
988 : 246 : rte_eal_memory_detach();
989 : 246 : rte_eal_malloc_heap_cleanup();
990 : 246 : eal_cleanup_config(internal_conf);
991 : 246 : eal_lcore_var_cleanup();
992 : 246 : rte_eal_log_cleanup();
993 : 246 : return 0;
994 : : }
995 : :
996 : : RTE_EXPORT_SYMBOL(rte_eal_create_uio_dev)
997 : 0 : int rte_eal_create_uio_dev(void)
998 : : {
999 : : const struct internal_config *internal_conf =
1000 : 0 : eal_get_internal_configuration();
1001 : :
1002 : 0 : return internal_conf->create_uio_dev;
1003 : : }
1004 : :
1005 : : RTE_EXPORT_SYMBOL(rte_eal_vfio_intr_mode)
1006 : : enum rte_intr_mode
1007 : 0 : rte_eal_vfio_intr_mode(void)
1008 : : {
1009 : : const struct internal_config *internal_conf =
1010 : 0 : eal_get_internal_configuration();
1011 : :
1012 : 0 : return internal_conf->vfio_intr_mode;
1013 : : }
1014 : :
1015 : : RTE_EXPORT_SYMBOL(rte_eal_vfio_get_vf_token)
1016 : : void
1017 : 0 : rte_eal_vfio_get_vf_token(rte_uuid_t vf_token)
1018 : : {
1019 : 0 : struct internal_config *cfg = eal_get_internal_configuration();
1020 : :
1021 : 0 : rte_uuid_copy(vf_token, cfg->vfio_vf_token);
1022 : 0 : }
1023 : :
1024 : : int
1025 : 184 : rte_eal_check_module(const char *module_name)
1026 : : {
1027 : : char sysfs_mod_name[PATH_MAX];
1028 : : struct stat st;
1029 : : int n;
1030 : :
1031 [ + - ]: 184 : if (NULL == module_name)
1032 : : return -1;
1033 : :
1034 : : /* Check if there is sysfs mounted */
1035 [ - + ]: 184 : if (stat("/sys/module", &st) != 0) {
1036 : 0 : EAL_LOG(DEBUG, "sysfs is not mounted! error %i (%s)",
1037 : : errno, strerror(errno));
1038 : 0 : return -1;
1039 : : }
1040 : :
1041 : : /* A module might be built-in, therefore try sysfs */
1042 : : n = snprintf(sysfs_mod_name, PATH_MAX, "/sys/module/%s", module_name);
1043 [ - + ]: 184 : if (n < 0 || n > PATH_MAX) {
1044 : 0 : EAL_LOG(DEBUG, "Could not format module path");
1045 : 0 : return -1;
1046 : : }
1047 : :
1048 [ - + ]: 184 : if (stat(sysfs_mod_name, &st) != 0) {
1049 : 0 : EAL_LOG(DEBUG, "Module %s not found! error %i (%s)",
1050 : : sysfs_mod_name, errno, strerror(errno));
1051 : 0 : return 0;
1052 : : }
1053 : :
1054 : : /* Module has been found */
1055 : : return 1;
1056 : : }
|