]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/libibverbs/src/init.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / libibverbs / src / init.c
1 /*
2  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 #if HAVE_CONFIG_H
35 #  include <config.h>
36 #endif /* HAVE_CONFIG_H */
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <glob.h>
41 #include <stdio.h>
42 #include <dlfcn.h>
43 #include <unistd.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <dirent.h>
49 #include <errno.h>
50
51 #include "ibverbs.h"
52
53 HIDDEN int abi_ver;
54
55 struct ibv_sysfs_dev {
56         char                    sysfs_name[IBV_SYSFS_NAME_MAX];
57         char                    ibdev_name[IBV_SYSFS_NAME_MAX];
58         char                    sysfs_path[IBV_SYSFS_PATH_MAX];
59         char                    ibdev_path[IBV_SYSFS_PATH_MAX];
60         struct ibv_sysfs_dev   *next;
61         int                     abi_ver;
62         int                     have_driver;
63 };
64
65 struct ibv_driver_name {
66         char                   *name;
67         struct ibv_driver_name *next;
68 };
69
70 struct ibv_driver {
71         const char             *name;
72         ibv_driver_init_func    init_func;
73         struct ibv_driver      *next;
74 };
75
76 static struct ibv_sysfs_dev *sysfs_dev_list;
77 static struct ibv_driver_name *driver_name_list;
78 static struct ibv_driver *head_driver, *tail_driver;
79
80 static int find_sysfs_devs(void)
81 {
82 #ifdef __linux__
83         char class_path[IBV_SYSFS_PATH_MAX];
84         DIR *class_dir;
85         struct dirent *dent;
86         struct ibv_sysfs_dev *sysfs_dev = NULL;
87         char value[8];
88         int ret = 0;
89
90         snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs",
91                  ibv_get_sysfs_path());
92
93         class_dir = opendir(class_path);
94         if (!class_dir)
95                 return ENOSYS;
96
97         while ((dent = readdir(class_dir))) {
98                 struct stat buf;
99
100                 if (dent->d_name[0] == '.')
101                         continue;
102
103                 if (!sysfs_dev)
104                         sysfs_dev = malloc(sizeof *sysfs_dev);
105                 if (!sysfs_dev) {
106                         ret = ENOMEM;
107                         goto out;
108                 }
109
110                 snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path,
111                          "%s/%s", class_path, dent->d_name);
112
113                 if (stat(sysfs_dev->sysfs_path, &buf)) {
114                         fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n",
115                                 sysfs_dev->sysfs_path);
116                         continue;
117                 }
118
119                 if (!S_ISDIR(buf.st_mode))
120                         continue;
121
122                 snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name,
123                         "%s", dent->d_name);
124
125                 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev",
126                                         sysfs_dev->ibdev_name,
127                                         sizeof sysfs_dev->ibdev_name) < 0) {
128                         fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n",
129                                 dent->d_name);
130                         continue;
131                 }
132
133                 snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path,
134                          "%s/class/infiniband/%s", ibv_get_sysfs_path(),
135                          sysfs_dev->ibdev_name);
136
137                 sysfs_dev->next        = sysfs_dev_list;
138                 sysfs_dev->have_driver = 0;
139                 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version",
140                                         value, sizeof value) > 0)
141                         sysfs_dev->abi_ver = strtol(value, NULL, 10);
142                 else
143                         sysfs_dev->abi_ver = 0;
144
145                 sysfs_dev_list = sysfs_dev;
146                 sysfs_dev      = NULL;
147         }
148
149  out:
150         if (sysfs_dev)
151                 free(sysfs_dev);
152
153         closedir(class_dir);
154         return ret;
155 #else
156         char class_path[IBV_SYSFS_PATH_MAX];
157         struct ibv_sysfs_dev *sysfs_dev = NULL;
158         char value[8];
159         int ret = 0;
160         int i;
161
162         snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs",
163                  ibv_get_sysfs_path());
164
165         for (i = 0; i < 256; i++) {
166                 if (!sysfs_dev)
167                         sysfs_dev = malloc(sizeof *sysfs_dev);
168                 if (!sysfs_dev) {
169                         ret = ENOMEM;
170                         goto out;
171                 }
172
173                 snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path,
174                          "%s/uverbs%d", class_path, i);
175
176                 snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name,
177                         "uverbs%d", i);
178
179                 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev",
180                                         sysfs_dev->ibdev_name,
181                                         sizeof sysfs_dev->ibdev_name) < 0)
182                         continue;
183
184                 snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path,
185                          "%s/class/infiniband/%s", ibv_get_sysfs_path(),
186                          sysfs_dev->ibdev_name);
187
188                 sysfs_dev->next        = sysfs_dev_list;
189                 sysfs_dev->have_driver = 0;
190                 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version",
191                                         value, sizeof value) > 0)
192                         sysfs_dev->abi_ver = strtol(value, NULL, 10);
193                 else
194                         sysfs_dev->abi_ver = 0;
195
196                 sysfs_dev_list = sysfs_dev;
197                 sysfs_dev      = NULL;
198         }
199
200  out:
201         if (sysfs_dev)
202                 free(sysfs_dev);
203
204         return ret;
205         
206 #endif
207 }
208
209 void ibv_register_driver(const char *name, ibv_driver_init_func init_func)
210 {
211         struct ibv_driver *driver;
212
213         driver = malloc(sizeof *driver);
214         if (!driver) {
215                 fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", name);
216                 return;
217         }
218
219         driver->name      = name;
220         driver->init_func = init_func;
221         driver->next      = NULL;
222
223         if (tail_driver)
224                 tail_driver->next = driver;
225         else
226                 head_driver = driver;
227         tail_driver = driver;
228 }
229
230 static void load_driver(const char *name)
231 {
232         char *so_name;
233         void *dlhandle;
234
235 #define __IBV_QUOTE(x)  #x
236 #define IBV_QUOTE(x)    __IBV_QUOTE(x)
237
238         if (asprintf(&so_name,
239                      name[0] == '/' ?
240                      "%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so" :
241                      "lib%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so",
242                      name) < 0) {
243                 fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n",
244                         name);
245                 return;
246         }
247
248         dlhandle = dlopen(so_name, RTLD_NOW);
249         if (!dlhandle) {
250                 fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n",
251                         name, dlerror());
252                 goto out;
253         }
254
255 out:
256         free(so_name);
257 }
258
259 static void load_drivers(void)
260 {
261         struct ibv_driver_name *name, *next_name;
262         const char *env;
263         char *list, *env_name;
264
265         /*
266          * Only use drivers passed in through the calling user's
267          * environment if we're not running setuid.
268          */
269         if (getuid() == geteuid()) {
270                 if ((env = getenv("RDMAV_DRIVERS"))) {
271                         list = strdupa(env);
272                         while ((env_name = strsep(&list, ":;")))
273                                 load_driver(env_name);
274                 } else if ((env = getenv("IBV_DRIVERS"))) {
275                         list = strdupa(env);
276                         while ((env_name = strsep(&list, ":;")))
277                                 load_driver(env_name);
278                 }
279         }
280
281         for (name = driver_name_list, next_name = name ? name->next : NULL;
282              name;
283              name = next_name, next_name = name ? name->next : NULL) {
284                 load_driver(name->name);
285                 free(name->name);
286                 free(name);
287         }
288 }
289
290 static void read_config_file(const char *path)
291 {
292         FILE *conf;
293         char *line = NULL;
294         char *config;
295         char *field;
296         size_t buflen = 0;
297         ssize_t len;
298
299         conf = fopen(path, "r");
300         if (!conf) {
301                 fprintf(stderr, PFX "Warning: couldn't read config file %s.\n",
302                         path);
303                 return;
304         }
305
306         while ((len = getline(&line, &buflen, conf)) != -1) {
307                 config = line + strspn(line, "\t ");
308                 if (config[0] == '\n' || config[0] == '#')
309                         continue;
310
311                 field = strsep(&config, "\n\t ");
312
313                 if (strcmp(field, "driver") == 0) {
314                         struct ibv_driver_name *driver_name;
315
316                         config += strspn(config, "\t ");
317                         field = strsep(&config, "\n\t ");
318
319                         driver_name = malloc(sizeof *driver_name);
320                         if (!driver_name) {
321                                 fprintf(stderr, PFX "Warning: couldn't allocate "
322                                         "driver name '%s'.\n", field);
323                                 continue;
324                         }
325
326                         driver_name->name = strdup(field);
327                         if (!driver_name->name) {
328                                 fprintf(stderr, PFX "Warning: couldn't allocate "
329                                         "driver name '%s'.\n", field);
330                                 free(driver_name);
331                                 continue;
332                         }
333
334                         driver_name->next = driver_name_list;
335                         driver_name_list  = driver_name;
336                 } else
337                         fprintf(stderr, PFX "Warning: ignoring bad config directive "
338                                 "'%s' in file '%s'.\n", field, path);
339         }
340
341         if (line)
342                 free(line);
343         fclose(conf);
344 }
345
346 static void read_config(void)
347 {
348         DIR *conf_dir;
349         struct dirent *dent;
350         char *path;
351
352         conf_dir = opendir(IBV_CONFIG_DIR);
353         if (!conf_dir) {
354                 fprintf(stderr, PFX "Warning: couldn't open config directory '%s'.\n",
355                         IBV_CONFIG_DIR);
356                 return;
357         }
358
359         while ((dent = readdir(conf_dir))) {
360                 struct stat buf;
361
362                 if (asprintf(&path, "%s/%s", IBV_CONFIG_DIR, dent->d_name) < 0) {
363                         fprintf(stderr, PFX "Warning: couldn't read config file %s/%s.\n",
364                                 IBV_CONFIG_DIR, dent->d_name);
365                         return;
366                 }
367
368                 if (stat(path, &buf)) {
369                         fprintf(stderr, PFX "Warning: couldn't stat config file '%s'.\n",
370                                 path);
371                         goto next;
372                 }
373
374                 if (!S_ISREG(buf.st_mode))
375                         goto next;
376
377                 read_config_file(path);
378 next:
379                 free(path);
380         }
381
382         closedir(conf_dir);
383 }
384
385 static struct ibv_device *try_driver(struct ibv_driver *driver,
386                                      struct ibv_sysfs_dev *sysfs_dev)
387 {
388         struct ibv_device *dev;
389         char value[8];
390
391         dev = driver->init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver);
392         if (!dev)
393                 return NULL;
394
395         if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) {
396                 fprintf(stderr, PFX "Warning: no node_type attr under %s.\n",
397                         sysfs_dev->ibdev_path);
398                         dev->node_type = IBV_NODE_UNKNOWN;
399         } else {
400                 dev->node_type = strtol(value, NULL, 10);
401                 if (dev->node_type < IBV_NODE_CA || dev->node_type > IBV_NODE_RNIC)
402                         dev->node_type = IBV_NODE_UNKNOWN;
403         }
404 out:
405
406         switch (dev->node_type) {
407         case IBV_NODE_CA:
408         case IBV_NODE_SWITCH:
409         case IBV_NODE_ROUTER:
410                 dev->transport_type = IBV_TRANSPORT_IB;
411                 break;
412         case IBV_NODE_RNIC:
413                 dev->transport_type = IBV_TRANSPORT_IWARP;
414                 break;
415         default:
416                 dev->transport_type = IBV_TRANSPORT_UNKNOWN;
417                 break;
418         }
419
420         strcpy(dev->dev_name,   sysfs_dev->sysfs_name);
421         strcpy(dev->dev_path,   sysfs_dev->sysfs_path);
422         strcpy(dev->name,       sysfs_dev->ibdev_name);
423         strcpy(dev->ibdev_path, sysfs_dev->ibdev_path);
424
425         return dev;
426 }
427
428 static struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev)
429 {
430         struct ibv_driver *driver;
431         struct ibv_device *dev;
432
433         for (driver = head_driver; driver; driver = driver->next) {
434                 dev = try_driver(driver, sysfs_dev);
435                 if (dev)
436                         return dev;
437         }
438
439         return NULL;
440 }
441
442 static int check_abi_version(const char *path)
443 {
444         char value[8];
445
446         if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version",
447                                 value, sizeof value) < 0) {
448                 return ENOSYS;
449         }
450
451         abi_ver = strtol(value, NULL, 10);
452
453         if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION ||
454             abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) {
455                 fprintf(stderr, PFX "Fatal: kernel ABI version %d "
456                         "doesn't match library version %d.\n",
457                         abi_ver, IB_USER_VERBS_MAX_ABI_VERSION);
458                 return ENOSYS;
459         }
460
461         return 0;
462 }
463
464 static void check_memlock_limit(void)
465 {
466         struct rlimit rlim;
467
468         if (!geteuid())
469                 return;
470
471         if (getrlimit(RLIMIT_MEMLOCK, &rlim)) {
472                 fprintf(stderr, PFX "Warning: getrlimit(RLIMIT_MEMLOCK) failed.");
473                 return;
474         }
475
476         if (rlim.rlim_cur <= 32768)
477                 fprintf(stderr, PFX "Warning: RLIMIT_MEMLOCK is %lu bytes.\n"
478                         "    This will severely limit memory registrations.\n",
479                         rlim.rlim_cur);
480 }
481
482 static void add_device(struct ibv_device *dev,
483                        struct ibv_device ***dev_list,
484                        int *num_devices,
485                        int *list_size)
486 {
487         struct ibv_device **new_list;
488
489         if (*list_size <= *num_devices) {
490                 *list_size = *list_size ? *list_size * 2 : 1;
491                 new_list = realloc(*dev_list, *list_size * sizeof (struct ibv_device *));
492                 if (!new_list)
493                         return;
494                 *dev_list = new_list;
495         }
496
497         (*dev_list)[(*num_devices)++] = dev;
498 }
499
500 HIDDEN int ibverbs_init(struct ibv_device ***list)
501 {
502         const char *sysfs_path;
503         struct ibv_sysfs_dev *sysfs_dev, *next_dev;
504         struct ibv_device *device;
505         int num_devices = 0;
506         int list_size = 0;
507         int statically_linked = 0;
508         int no_driver = 0;
509         int ret;
510
511         *list = NULL;
512
513         if (getenv("RDMAV_FORK_SAFE") || getenv("IBV_FORK_SAFE"))
514                 if (ibv_fork_init())
515                         fprintf(stderr, PFX "Warning: fork()-safety requested "
516                                 "but init failed\n");
517
518         sysfs_path = ibv_get_sysfs_path();
519         if (!sysfs_path)
520                 return -ENOSYS;
521
522         ret = check_abi_version(sysfs_path);
523         if (ret)
524                 return -ret;
525
526         check_memlock_limit();
527
528         read_config();
529
530         ret = find_sysfs_devs();
531         if (ret)
532                 return -ret;
533
534         for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) {
535                 device = try_drivers(sysfs_dev);
536                 if (device) {
537                         add_device(device, list, &num_devices, &list_size);
538                         sysfs_dev->have_driver = 1;
539                 } else
540                         no_driver = 1;
541         }
542
543         if (!no_driver)
544                 goto out;
545
546         /*
547          * Check if we can dlopen() ourselves.  If this fails,
548          * libibverbs is probably statically linked into the
549          * executable, and we should just give up, since trying to
550          * dlopen() a driver module will fail spectacularly (loading a
551          * driver .so will bring in dynamic copies of libibverbs and
552          * libdl to go along with the static copies the executable
553          * has, which quickly leads to a crash.
554          */
555         {
556                 void *hand = dlopen(NULL, RTLD_NOW);
557                 if (!hand) {
558                         fprintf(stderr, PFX "Warning: dlopen(NULL) failed, "
559                                 "assuming static linking.\n");
560                         statically_linked = 1;
561                         goto out;
562                 }
563                 dlclose(hand);
564         }
565
566         load_drivers();
567
568         for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) {
569                 if (sysfs_dev->have_driver)
570                         continue;
571
572                 device = try_drivers(sysfs_dev);
573                 if (device) {
574                         add_device(device, list, &num_devices, &list_size);
575                         sysfs_dev->have_driver = 1;
576                 }
577         }
578
579 out:
580         for (sysfs_dev = sysfs_dev_list,
581                      next_dev = sysfs_dev ? sysfs_dev->next : NULL;
582              sysfs_dev;
583              sysfs_dev = next_dev, next_dev = sysfs_dev ? sysfs_dev->next : NULL) {
584                 if (!sysfs_dev->have_driver) {
585                         fprintf(stderr, PFX "Warning: no userspace device-specific "
586                                 "driver found for %s\n", sysfs_dev->sysfs_path);
587                         if (statically_linked)
588                                 fprintf(stderr, "       When linking libibverbs statically, "
589                                         "driver must be statically linked too.\n");
590                 }
591                 free(sysfs_dev);
592         }
593
594         return num_devices;
595 }