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 53HIDDEN int abi_ver; 54 55struct 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 65struct ibv_driver_name { 66 char *name; 67 struct ibv_driver_name *next; 68}; 69 70struct ibv_driver { 71 const char *name; 72 ibv_driver_init_func init_func; 73 struct ibv_driver *next; 74}; 75 76static struct ibv_sysfs_dev *sysfs_dev_list; 77static struct ibv_driver_name *driver_name_list; 78static struct ibv_driver *head_driver, *tail_driver; 79 80static 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 209void 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 230static 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 255out: 256 free(so_name); 257} 258 259static 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 290static 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 346static 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); 378next: 379 free(path); 380 } 381 382 closedir(conf_dir); 383} 384 385static 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 } 404out: 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 428static 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 442static 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 464static 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 482static 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 500HIDDEN 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 579out: 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} 596