common/mlx5: introduce common library
[dpdk.git] / drivers / common / mlx5 / mlx5_common.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2019 Mellanox Technologies, Ltd
3  */
4
5 #include <dlfcn.h>
6 #include <unistd.h>
7 #include <string.h>
8
9 #include <rte_errno.h>
10
11 #include "mlx5_common.h"
12 #include "mlx5_common_utils.h"
13 #include "mlx5_glue.h"
14
15
16 int mlx5_common_logtype;
17
18
19 #ifdef RTE_IBVERBS_LINK_DLOPEN
20
21 /**
22  * Suffix RTE_EAL_PMD_PATH with "-glue".
23  *
24  * This function performs a sanity check on RTE_EAL_PMD_PATH before
25  * suffixing its last component.
26  *
27  * @param buf[out]
28  *   Output buffer, should be large enough otherwise NULL is returned.
29  * @param size
30  *   Size of @p out.
31  *
32  * @return
33  *   Pointer to @p buf or @p NULL in case suffix cannot be appended.
34  */
35 static char *
36 mlx5_glue_path(char *buf, size_t size)
37 {
38         static const char *const bad[] = { "/", ".", "..", NULL };
39         const char *path = RTE_EAL_PMD_PATH;
40         size_t len = strlen(path);
41         size_t off;
42         int i;
43
44         while (len && path[len - 1] == '/')
45                 --len;
46         for (off = len; off && path[off - 1] != '/'; --off)
47                 ;
48         for (i = 0; bad[i]; ++i)
49                 if (!strncmp(path + off, bad[i], (int)(len - off)))
50                         goto error;
51         i = snprintf(buf, size, "%.*s-glue", (int)len, path);
52         if (i == -1 || (size_t)i >= size)
53                 goto error;
54         return buf;
55 error:
56         RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of"
57                 " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please"
58                 " re-configure DPDK");
59         return NULL;
60 }
61 #endif
62
63 /**
64  * Initialization routine for run-time dependency on rdma-core.
65  */
66 RTE_INIT_PRIO(mlx5_glue_init, CLASS)
67 {
68         void *handle = NULL;
69
70         /* Initialize common log type. */
71         mlx5_common_logtype = rte_log_register("pmd.common.mlx5");
72         if (mlx5_common_logtype >= 0)
73                 rte_log_set_level(mlx5_common_logtype, RTE_LOG_NOTICE);
74         /*
75          * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use
76          * huge pages. Calling ibv_fork_init() during init allows
77          * applications to use fork() safely for purposes other than
78          * using this PMD, which is not supported in forked processes.
79          */
80         setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
81         /* Match the size of Rx completion entry to the size of a cacheline. */
82         if (RTE_CACHE_LINE_SIZE == 128)
83                 setenv("MLX5_CQE_SIZE", "128", 0);
84         /*
85          * MLX5_DEVICE_FATAL_CLEANUP tells ibv_destroy functions to
86          * cleanup all the Verbs resources even when the device was removed.
87          */
88         setenv("MLX5_DEVICE_FATAL_CLEANUP", "1", 1);
89         /* The glue initialization was done earlier by mlx5 common library. */
90 #ifdef RTE_IBVERBS_LINK_DLOPEN
91         char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")];
92         const char *path[] = {
93                 /*
94                  * A basic security check is necessary before trusting
95                  * MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH.
96                  */
97                 (geteuid() == getuid() && getegid() == getgid() ?
98                  getenv("MLX5_GLUE_PATH") : NULL),
99                 /*
100                  * When RTE_EAL_PMD_PATH is set, use its glue-suffixed
101                  * variant, otherwise let dlopen() look up libraries on its
102                  * own.
103                  */
104                 (*RTE_EAL_PMD_PATH ?
105                  mlx5_glue_path(glue_path, sizeof(glue_path)) : ""),
106         };
107         unsigned int i = 0;
108         void **sym;
109         const char *dlmsg;
110
111         while (!handle && i != RTE_DIM(path)) {
112                 const char *end;
113                 size_t len;
114                 int ret;
115
116                 if (!path[i]) {
117                         ++i;
118                         continue;
119                 }
120                 end = strpbrk(path[i], ":;");
121                 if (!end)
122                         end = path[i] + strlen(path[i]);
123                 len = end - path[i];
124                 ret = 0;
125                 do {
126                         char name[ret + 1];
127
128                         ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE,
129                                        (int)len, path[i],
130                                        (!len || *(end - 1) == '/') ? "" : "/");
131                         if (ret == -1)
132                                 break;
133                         if (sizeof(name) != (size_t)ret + 1)
134                                 continue;
135                         DRV_LOG(DEBUG, "Looking for rdma-core glue as "
136                                 "\"%s\"", name);
137                         handle = dlopen(name, RTLD_LAZY);
138                         break;
139                 } while (1);
140                 path[i] = end + 1;
141                 if (!*end)
142                         ++i;
143         }
144         if (!handle) {
145                 rte_errno = EINVAL;
146                 dlmsg = dlerror();
147                 if (dlmsg)
148                         DRV_LOG(WARNING, "Cannot load glue library: %s", dlmsg);
149                 goto glue_error;
150         }
151         sym = dlsym(handle, "mlx5_glue");
152         if (!sym || !*sym) {
153                 rte_errno = EINVAL;
154                 dlmsg = dlerror();
155                 if (dlmsg)
156                         DRV_LOG(ERR, "Cannot resolve glue symbol: %s", dlmsg);
157                 goto glue_error;
158         }
159         mlx5_glue = *sym;
160 #endif /* RTE_IBVERBS_LINK_DLOPEN */
161 #ifndef NDEBUG
162         /* Glue structure must not contain any NULL pointers. */
163         {
164                 unsigned int i;
165
166                 for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i)
167                         assert(((const void *const *)mlx5_glue)[i]);
168         }
169 #endif
170         if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) {
171                 rte_errno = EINVAL;
172                 DRV_LOG(ERR, "rdma-core glue \"%s\" mismatch: \"%s\" is "
173                         "required", mlx5_glue->version, MLX5_GLUE_VERSION);
174                 goto glue_error;
175         }
176         mlx5_glue->fork_init();
177         return;
178 glue_error:
179         if (handle)
180                 dlclose(handle);
181         DRV_LOG(WARNING, "Cannot initialize MLX5 common due to missing"
182                 " run-time dependency on rdma-core libraries (libibverbs,"
183                 " libmlx5)");
184         mlx5_glue = NULL;
185         return;
186 }