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 #define _GNU_SOURCE 34 #include <config.h> 35 36 #include <stdlib.h> 37 #include <string.h> 38 #include <glob.h> 39 #include <stdio.h> 40 #include <dlfcn.h> 41 #include <unistd.h> 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <sys/time.h> 45 #include <sys/resource.h> 46 #include <dirent.h> 47 #include <errno.h> 48 #include <assert.h> 49 50 #include "ibverbs.h" 51 52 #pragma GCC diagnostic ignored "-Wmissing-prototypes" 53 54 int abi_ver; 55 56 struct ibv_sysfs_dev { 57 char sysfs_name[IBV_SYSFS_NAME_MAX]; 58 char ibdev_name[IBV_SYSFS_NAME_MAX]; 59 char sysfs_path[IBV_SYSFS_PATH_MAX]; 60 char ibdev_path[IBV_SYSFS_PATH_MAX]; 61 struct ibv_sysfs_dev *next; 62 int abi_ver; 63 int have_driver; 64 }; 65 66 struct ibv_driver_name { 67 char *name; 68 struct ibv_driver_name *next; 69 }; 70 71 struct ibv_driver { 72 const char *name; 73 verbs_driver_init_func verbs_init_func; 74 struct ibv_driver *next; 75 }; 76 77 static struct ibv_sysfs_dev *sysfs_dev_list; 78 static struct ibv_driver_name *driver_name_list; 79 static struct ibv_driver *head_driver, *tail_driver; 80 81 static int find_sysfs_devs(void) 82 { 83 #ifdef __linux__ 84 char class_path[IBV_SYSFS_PATH_MAX]; 85 DIR *class_dir; 86 struct dirent *dent; 87 struct ibv_sysfs_dev *sysfs_dev = NULL; 88 char value[8]; 89 int ret = 0; 90 91 if (!check_snprintf(class_path, sizeof(class_path), 92 "%s/class/infiniband_verbs", ibv_get_sysfs_path())) 93 return ENOMEM; 94 95 class_dir = opendir(class_path); 96 if (!class_dir) 97 return ENOSYS; 98 99 while ((dent = readdir(class_dir))) { 100 struct stat buf; 101 102 if (dent->d_name[0] == '.') 103 continue; 104 105 if (!sysfs_dev) 106 sysfs_dev = malloc(sizeof *sysfs_dev); 107 if (!sysfs_dev) { 108 ret = ENOMEM; 109 goto out; 110 } 111 112 if (!check_snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, 113 "%s/%s", class_path, dent->d_name)) 114 continue; 115 116 if (stat(sysfs_dev->sysfs_path, &buf)) { 117 fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n", 118 sysfs_dev->sysfs_path); 119 continue; 120 } 121 122 if (!S_ISDIR(buf.st_mode)) 123 continue; 124 125 if (!check_snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, 126 "%s", dent->d_name)) 127 continue; 128 129 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", 130 sysfs_dev->ibdev_name, 131 sizeof sysfs_dev->ibdev_name) < 0) { 132 fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n", 133 dent->d_name); 134 continue; 135 } 136 137 if (!check_snprintf( 138 sysfs_dev->ibdev_path, sizeof(sysfs_dev->ibdev_path), 139 "%s/class/infiniband/%s", ibv_get_sysfs_path(), 140 sysfs_dev->ibdev_name)) 141 continue; 142 143 sysfs_dev->next = sysfs_dev_list; 144 sysfs_dev->have_driver = 0; 145 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", 146 value, sizeof value) > 0) 147 sysfs_dev->abi_ver = strtol(value, NULL, 10); 148 else 149 sysfs_dev->abi_ver = 0; 150 151 sysfs_dev_list = sysfs_dev; 152 sysfs_dev = NULL; 153 } 154 155 out: 156 if (sysfs_dev) 157 free(sysfs_dev); 158 159 closedir(class_dir); 160 return ret; 161 #else 162 char class_path[IBV_SYSFS_PATH_MAX]; 163 struct ibv_sysfs_dev *sysfs_dev = NULL; 164 char value[8]; 165 int ret = 0; 166 int i; 167 168 snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", 169 ibv_get_sysfs_path()); 170 171 for (i = 0; i < 256; i++) { 172 if (!sysfs_dev) 173 sysfs_dev = malloc(sizeof *sysfs_dev); 174 if (!sysfs_dev) { 175 ret = ENOMEM; 176 goto out; 177 } 178 179 snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, 180 "%s/uverbs%d", class_path, i); 181 182 snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, 183 "uverbs%d", i); 184 185 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", 186 sysfs_dev->ibdev_name, 187 sizeof sysfs_dev->ibdev_name) < 0) 188 continue; 189 190 snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, 191 "%s/class/infiniband/%s", ibv_get_sysfs_path(), 192 sysfs_dev->ibdev_name); 193 194 sysfs_dev->next = sysfs_dev_list; 195 sysfs_dev->have_driver = 0; 196 if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", 197 value, sizeof value) > 0) 198 sysfs_dev->abi_ver = strtol(value, NULL, 10); 199 else 200 sysfs_dev->abi_ver = 0; 201 202 sysfs_dev_list = sysfs_dev; 203 sysfs_dev = NULL; 204 } 205 206 out: 207 if (sysfs_dev) 208 free(sysfs_dev); 209 210 return ret; 211 #endif 212 } 213 214 void verbs_register_driver(const char *name, 215 verbs_driver_init_func verbs_init_func) 216 { 217 struct ibv_driver *driver; 218 219 driver = malloc(sizeof *driver); 220 if (!driver) { 221 fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", name); 222 return; 223 } 224 225 driver->name = name; 226 driver->verbs_init_func = verbs_init_func; 227 driver->next = NULL; 228 229 if (tail_driver) 230 tail_driver->next = driver; 231 else 232 head_driver = driver; 233 tail_driver = driver; 234 } 235 236 #define __IBV_QUOTE(x) #x 237 #define IBV_QUOTE(x) __IBV_QUOTE(x) 238 #define DLOPEN_TRAILER "-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so" 239 240 static void load_driver(const char *name) 241 { 242 char *so_name; 243 void *dlhandle; 244 245 /* If the name is an absolute path then open that path after appending 246 the trailer suffix */ 247 if (name[0] == '/') { 248 if (asprintf(&so_name, "%s" DLOPEN_TRAILER, name) < 0) 249 goto out_asprintf; 250 dlhandle = dlopen(so_name, RTLD_NOW); 251 if (!dlhandle) 252 goto out_dlopen; 253 free(so_name); 254 return; 255 } 256 257 /* If configured with a provider plugin path then try that next */ 258 if (sizeof(VERBS_PROVIDER_DIR) > 1) { 259 if (asprintf(&so_name, VERBS_PROVIDER_DIR "/lib%s" DLOPEN_TRAILER, name) < 260 0) 261 goto out_asprintf; 262 dlhandle = dlopen(so_name, RTLD_NOW); 263 free(so_name); 264 if (dlhandle) 265 return; 266 } 267 268 /* Otherwise use the system libary search path. This is the historical 269 behavior of libibverbs */ 270 if (asprintf(&so_name, "lib%s" DLOPEN_TRAILER, name) < 0) 271 goto out_asprintf; 272 dlhandle = dlopen(so_name, RTLD_NOW); 273 if (!dlhandle) 274 goto out_dlopen; 275 free(so_name); 276 return; 277 278 out_asprintf: 279 fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n", name); 280 return; 281 out_dlopen: 282 fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n", so_name, 283 dlerror()); 284 free(so_name); 285 return; 286 } 287 288 static void load_drivers(void) 289 { 290 struct ibv_driver_name *name, *next_name; 291 const char *env; 292 char *list, *env_name; 293 294 /* 295 * Only use drivers passed in through the calling user's 296 * environment if we're not running setuid. 297 */ 298 if (getuid() == geteuid()) { 299 if ((env = getenv("RDMAV_DRIVERS"))) { 300 list = strdupa(env); 301 while ((env_name = strsep(&list, ":;"))) 302 load_driver(env_name); 303 } else if ((env = getenv("IBV_DRIVERS"))) { 304 list = strdupa(env); 305 while ((env_name = strsep(&list, ":;"))) 306 load_driver(env_name); 307 } 308 } 309 310 for (name = driver_name_list, next_name = name ? name->next : NULL; 311 name; 312 name = next_name, next_name = name ? name->next : NULL) { 313 load_driver(name->name); 314 free(name->name); 315 free(name); 316 } 317 } 318 319 static void read_config_file(const char *path) 320 { 321 FILE *conf; 322 char *line = NULL; 323 char *config; 324 char *field; 325 size_t buflen = 0; 326 ssize_t len; 327 328 conf = fopen(path, "r" STREAM_CLOEXEC); 329 if (!conf) { 330 fprintf(stderr, PFX "Warning: couldn't read config file %s.\n", 331 path); 332 return; 333 } 334 335 while ((len = getline(&line, &buflen, conf)) != -1) { 336 config = line + strspn(line, "\t "); 337 if (config[0] == '\n' || config[0] == '#') 338 continue; 339 340 field = strsep(&config, "\n\t "); 341 342 if (strcmp(field, "driver") == 0 && config != NULL) { 343 struct ibv_driver_name *driver_name; 344 345 config += strspn(config, "\t "); 346 field = strsep(&config, "\n\t "); 347 348 driver_name = malloc(sizeof *driver_name); 349 if (!driver_name) { 350 fprintf(stderr, PFX "Warning: couldn't allocate " 351 "driver name '%s'.\n", field); 352 continue; 353 } 354 355 driver_name->name = strdup(field); 356 if (!driver_name->name) { 357 fprintf(stderr, PFX "Warning: couldn't allocate " 358 "driver name '%s'.\n", field); 359 free(driver_name); 360 continue; 361 } 362 363 driver_name->next = driver_name_list; 364 driver_name_list = driver_name; 365 } else 366 fprintf(stderr, PFX "Warning: ignoring bad config directive " 367 "'%s' in file '%s'.\n", field, path); 368 } 369 370 if (line) 371 free(line); 372 fclose(conf); 373 } 374 375 static void read_config(void) 376 { 377 DIR *conf_dir; 378 struct dirent *dent; 379 char *path; 380 381 conf_dir = opendir(IBV_CONFIG_DIR); 382 if (!conf_dir) { 383 fprintf(stderr, PFX "Warning: couldn't open config directory '%s'.\n", 384 IBV_CONFIG_DIR); 385 return; 386 } 387 388 while ((dent = readdir(conf_dir))) { 389 struct stat buf; 390 391 if (asprintf(&path, "%s/%s", IBV_CONFIG_DIR, dent->d_name) < 0) { 392 fprintf(stderr, PFX "Warning: couldn't read config file %s/%s.\n", 393 IBV_CONFIG_DIR, dent->d_name); 394 goto out; 395 } 396 397 if (stat(path, &buf)) { 398 fprintf(stderr, PFX "Warning: couldn't stat config file '%s'.\n", 399 path); 400 goto next; 401 } 402 403 if (!S_ISREG(buf.st_mode)) 404 goto next; 405 406 read_config_file(path); 407 next: 408 free(path); 409 } 410 411 out: 412 closedir(conf_dir); 413 } 414 415 static struct ibv_device *try_driver(struct ibv_driver *driver, 416 struct ibv_sysfs_dev *sysfs_dev) 417 { 418 struct verbs_device *vdev; 419 struct ibv_device *dev; 420 char value[16]; 421 422 vdev = driver->verbs_init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver); 423 if (!vdev) 424 return NULL; 425 426 dev = &vdev->device; 427 assert(dev->_ops._dummy1 == NULL); 428 assert(dev->_ops._dummy2 == NULL); 429 430 if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) { 431 fprintf(stderr, PFX "Warning: no node_type attr under %s.\n", 432 sysfs_dev->ibdev_path); 433 dev->node_type = IBV_NODE_UNKNOWN; 434 } else { 435 dev->node_type = strtol(value, NULL, 10); 436 if (dev->node_type < IBV_NODE_CA || dev->node_type > IBV_NODE_USNIC_UDP) 437 dev->node_type = IBV_NODE_UNKNOWN; 438 } 439 440 switch (dev->node_type) { 441 case IBV_NODE_CA: 442 case IBV_NODE_SWITCH: 443 case IBV_NODE_ROUTER: 444 dev->transport_type = IBV_TRANSPORT_IB; 445 break; 446 case IBV_NODE_RNIC: 447 dev->transport_type = IBV_TRANSPORT_IWARP; 448 break; 449 case IBV_NODE_USNIC: 450 dev->transport_type = IBV_TRANSPORT_USNIC; 451 break; 452 case IBV_NODE_USNIC_UDP: 453 dev->transport_type = IBV_TRANSPORT_USNIC_UDP; 454 break; 455 default: 456 dev->transport_type = IBV_TRANSPORT_UNKNOWN; 457 break; 458 } 459 460 strcpy(dev->dev_name, sysfs_dev->sysfs_name); 461 strcpy(dev->dev_path, sysfs_dev->sysfs_path); 462 strcpy(dev->name, sysfs_dev->ibdev_name); 463 strcpy(dev->ibdev_path, sysfs_dev->ibdev_path); 464 465 return dev; 466 } 467 468 static struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev) 469 { 470 struct ibv_driver *driver; 471 struct ibv_device *dev; 472 473 for (driver = head_driver; driver; driver = driver->next) { 474 dev = try_driver(driver, sysfs_dev); 475 if (dev) 476 return dev; 477 } 478 479 return NULL; 480 } 481 482 static int check_abi_version(const char *path) 483 { 484 char value[8]; 485 486 if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version", 487 value, sizeof value) < 0) { 488 return ENOSYS; 489 } 490 491 abi_ver = strtol(value, NULL, 10); 492 493 if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION || 494 abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) { 495 fprintf(stderr, PFX "Fatal: kernel ABI version %d " 496 "doesn't match library version %d.\n", 497 abi_ver, IB_USER_VERBS_MAX_ABI_VERSION); 498 return ENOSYS; 499 } 500 501 return 0; 502 } 503 504 static void check_memlock_limit(void) 505 { 506 struct rlimit rlim; 507 508 if (!geteuid()) 509 return; 510 511 if (getrlimit(RLIMIT_MEMLOCK, &rlim)) { 512 fprintf(stderr, PFX "Warning: getrlimit(RLIMIT_MEMLOCK) failed."); 513 return; 514 } 515 516 if (rlim.rlim_cur <= 32768) 517 fprintf(stderr, PFX "Warning: RLIMIT_MEMLOCK is %lu bytes.\n" 518 " This will severely limit memory registrations.\n", 519 rlim.rlim_cur); 520 } 521 522 static void add_device(struct ibv_device *dev, 523 struct ibv_device ***dev_list, 524 int *num_devices, 525 int *list_size) 526 { 527 struct ibv_device **new_list; 528 529 if (*list_size <= *num_devices) { 530 *list_size = *list_size ? *list_size * 2 : 1; 531 new_list = realloc(*dev_list, *list_size * sizeof (struct ibv_device *)); 532 if (!new_list) 533 return; 534 *dev_list = new_list; 535 } 536 537 (*dev_list)[(*num_devices)++] = dev; 538 } 539 540 int ibverbs_init(struct ibv_device ***list) 541 { 542 const char *sysfs_path; 543 struct ibv_sysfs_dev *sysfs_dev, *next_dev; 544 struct ibv_device *device; 545 int num_devices = 0; 546 int list_size = 0; 547 int statically_linked = 0; 548 int no_driver = 0; 549 int ret; 550 551 *list = NULL; 552 553 if (getenv("RDMAV_FORK_SAFE") || getenv("IBV_FORK_SAFE")) 554 if (ibv_fork_init()) 555 fprintf(stderr, PFX "Warning: fork()-safety requested " 556 "but init failed\n"); 557 558 sysfs_path = ibv_get_sysfs_path(); 559 if (!sysfs_path) 560 return -ENOSYS; 561 562 ret = check_abi_version(sysfs_path); 563 if (ret) 564 return -ret; 565 566 check_memlock_limit(); 567 568 read_config(); 569 570 ret = find_sysfs_devs(); 571 if (ret) 572 return -ret; 573 574 for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { 575 device = try_drivers(sysfs_dev); 576 if (device) { 577 add_device(device, list, &num_devices, &list_size); 578 sysfs_dev->have_driver = 1; 579 } else 580 no_driver = 1; 581 } 582 583 if (!no_driver) 584 goto out; 585 586 /* 587 * Check if we can dlopen() ourselves. If this fails, 588 * libibverbs is probably statically linked into the 589 * executable, and we should just give up, since trying to 590 * dlopen() a driver module will fail spectacularly (loading a 591 * driver .so will bring in dynamic copies of libibverbs and 592 * libdl to go along with the static copies the executable 593 * has, which quickly leads to a crash. 594 */ 595 { 596 void *hand = dlopen(NULL, RTLD_NOW); 597 if (!hand) { 598 fprintf(stderr, PFX "Warning: dlopen(NULL) failed, " 599 "assuming static linking.\n"); 600 statically_linked = 1; 601 goto out; 602 } 603 dlclose(hand); 604 } 605 606 load_drivers(); 607 608 for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { 609 if (sysfs_dev->have_driver) 610 continue; 611 612 device = try_drivers(sysfs_dev); 613 if (device) { 614 add_device(device, list, &num_devices, &list_size); 615 sysfs_dev->have_driver = 1; 616 } 617 } 618 619 out: 620 for (sysfs_dev = sysfs_dev_list, 621 next_dev = sysfs_dev ? sysfs_dev->next : NULL; 622 sysfs_dev; 623 sysfs_dev = next_dev, next_dev = sysfs_dev ? sysfs_dev->next : NULL) { 624 if (!sysfs_dev->have_driver && getenv("IBV_SHOW_WARNINGS")) { 625 fprintf(stderr, PFX "Warning: no userspace device-specific " 626 "driver found for %s\n", sysfs_dev->sysfs_path); 627 if (statically_linked) 628 fprintf(stderr, " When linking libibverbs statically, " 629 "driver must be statically linked too.\n"); 630 } 631 free(sysfs_dev); 632 } 633 634 return num_devices; 635 } 636