1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/log.h" 37 #include "spdk/sock.h" 38 #include "spdk_internal/sock.h" 39 #include "spdk/queue.h" 40 41 #define SPDK_SOCK_DEFAULT_PRIORITY 0 42 #define SPDK_SOCK_OPTS_FIELD_OK(opts, field) (offsetof(struct spdk_sock_opts, field) + sizeof(opts->field) <= (opts->opts_size)) 43 44 static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls); 45 46 struct spdk_sock_placement_id_entry { 47 int placement_id; 48 uint32_t ref; 49 struct spdk_sock_group *group; 50 STAILQ_ENTRY(spdk_sock_placement_id_entry) link; 51 }; 52 53 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER( 54 g_placement_id_map); 55 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER; 56 57 /* Insert a group into the placement map. 58 * If the group is already in the map, take a reference. 59 */ 60 static int 61 sock_map_insert(int placement_id, struct spdk_sock_group *group) 62 { 63 struct spdk_sock_placement_id_entry *entry; 64 65 pthread_mutex_lock(&g_map_table_mutex); 66 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 67 if (placement_id == entry->placement_id) { 68 /* The mapping already exists, it means that different sockets have 69 * the same placement_ids. 70 */ 71 entry->ref++; 72 pthread_mutex_unlock(&g_map_table_mutex); 73 return 0; 74 } 75 } 76 77 entry = calloc(1, sizeof(*entry)); 78 if (!entry) { 79 SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id); 80 pthread_mutex_unlock(&g_map_table_mutex); 81 return -ENOMEM; 82 } 83 84 entry->placement_id = placement_id; 85 entry->group = group; 86 entry->ref++; 87 88 STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link); 89 pthread_mutex_unlock(&g_map_table_mutex); 90 91 return 0; 92 } 93 94 /* Release a reference to the group for a given placement_id. 95 * If the reference count is 0, remove the group. 96 */ 97 static void 98 sock_map_release(int placement_id) 99 { 100 struct spdk_sock_placement_id_entry *entry; 101 102 pthread_mutex_lock(&g_map_table_mutex); 103 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 104 if (placement_id == entry->placement_id) { 105 assert(entry->ref > 0); 106 entry->ref--; 107 break; 108 } 109 } 110 111 pthread_mutex_unlock(&g_map_table_mutex); 112 } 113 114 /* Look up the group for a placement_id. */ 115 static void 116 sock_map_lookup(int placement_id, struct spdk_sock_group **group) 117 { 118 struct spdk_sock_placement_id_entry *entry; 119 120 *group = NULL; 121 pthread_mutex_lock(&g_map_table_mutex); 122 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 123 if (placement_id == entry->placement_id) { 124 assert(entry->group != NULL); 125 *group = entry->group; 126 break; 127 } 128 } 129 pthread_mutex_unlock(&g_map_table_mutex); 130 } 131 132 /* Remove the socket group from the map table */ 133 static void 134 sock_remove_sock_group_from_map_table(struct spdk_sock_group *group) 135 { 136 struct spdk_sock_placement_id_entry *entry, *tmp; 137 138 pthread_mutex_lock(&g_map_table_mutex); 139 STAILQ_FOREACH_SAFE(entry, &g_placement_id_map, link, tmp) { 140 if (entry->group == group) { 141 STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); 142 free(entry); 143 } 144 } 145 pthread_mutex_unlock(&g_map_table_mutex); 146 147 } 148 149 int 150 spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group) 151 { 152 int placement_id = 0, rc; 153 154 rc = sock->net_impl->get_placement_id(sock, &placement_id); 155 if (!rc && (placement_id != 0)) { 156 sock_map_lookup(placement_id, group); 157 return 0; 158 } else { 159 return -1; 160 } 161 } 162 163 int 164 spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, 165 char *caddr, int clen, uint16_t *cport) 166 { 167 return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport); 168 } 169 170 void 171 spdk_sock_get_default_opts(struct spdk_sock_opts *opts) 172 { 173 assert(opts); 174 175 if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) { 176 opts->priority = SPDK_SOCK_DEFAULT_PRIORITY; 177 } 178 } 179 180 /* 181 * opts The opts allocated in the current library. 182 * opts_user The opts passed by the caller. 183 * */ 184 static void 185 sock_init_opts(struct spdk_sock_opts *opts, struct spdk_sock_opts *opts_user) 186 { 187 assert(opts); 188 assert(opts_user); 189 190 opts->opts_size = sizeof(*opts); 191 spdk_sock_get_default_opts(opts); 192 193 /* reset the size according to the user */ 194 opts->opts_size = opts_user->opts_size; 195 if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) { 196 opts->priority = opts_user->priority; 197 } 198 } 199 200 struct spdk_sock * 201 spdk_sock_connect(const char *ip, int port, char *impl_name) 202 { 203 struct spdk_sock_opts opts; 204 205 opts.opts_size = sizeof(opts); 206 spdk_sock_get_default_opts(&opts); 207 return spdk_sock_connect_ext(ip, port, impl_name, &opts); 208 } 209 210 struct spdk_sock * 211 spdk_sock_connect_ext(const char *ip, int port, char *impl_name, struct spdk_sock_opts *opts) 212 { 213 struct spdk_net_impl *impl = NULL; 214 struct spdk_sock *sock; 215 struct spdk_sock_opts opts_local; 216 217 if (opts == NULL) { 218 SPDK_ERRLOG("the opts should not be NULL pointer\n"); 219 return NULL; 220 } 221 222 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 223 if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) { 224 continue; 225 } 226 227 sock_init_opts(&opts_local, opts); 228 sock = impl->connect(ip, port, &opts_local); 229 if (sock != NULL) { 230 /* Copy the contents, both the two structures are the same ABI version */ 231 memcpy(&sock->opts, &opts_local, sizeof(sock->opts)); 232 sock->net_impl = impl; 233 TAILQ_INIT(&sock->queued_reqs); 234 TAILQ_INIT(&sock->pending_reqs); 235 return sock; 236 } 237 } 238 239 return NULL; 240 } 241 242 struct spdk_sock * 243 spdk_sock_listen(const char *ip, int port, char *impl_name) 244 { 245 struct spdk_sock_opts opts; 246 247 opts.opts_size = sizeof(opts); 248 spdk_sock_get_default_opts(&opts); 249 return spdk_sock_listen_ext(ip, port, impl_name, &opts); 250 } 251 252 struct spdk_sock * 253 spdk_sock_listen_ext(const char *ip, int port, char *impl_name, struct spdk_sock_opts *opts) 254 { 255 struct spdk_net_impl *impl = NULL; 256 struct spdk_sock *sock; 257 struct spdk_sock_opts opts_local; 258 259 if (opts == NULL) { 260 SPDK_ERRLOG("the opts should not be NULL pointer\n"); 261 return NULL; 262 } 263 264 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 265 if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) { 266 continue; 267 } 268 269 sock_init_opts(&opts_local, opts); 270 sock = impl->listen(ip, port, &opts_local); 271 if (sock != NULL) { 272 /* Copy the contents, both the two structures are the same ABI version */ 273 memcpy(&sock->opts, &opts_local, sizeof(sock->opts)); 274 sock->net_impl = impl; 275 /* Don't need to initialize the request queues for listen 276 * sockets. */ 277 return sock; 278 } 279 } 280 281 return NULL; 282 } 283 284 struct spdk_sock * 285 spdk_sock_accept(struct spdk_sock *sock) 286 { 287 struct spdk_sock *new_sock; 288 289 new_sock = sock->net_impl->accept(sock); 290 if (new_sock != NULL) { 291 /* Inherit the opts from the "accept sock" */ 292 new_sock->opts = sock->opts; 293 memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts)); 294 new_sock->net_impl = sock->net_impl; 295 TAILQ_INIT(&new_sock->queued_reqs); 296 TAILQ_INIT(&new_sock->pending_reqs); 297 } 298 299 return new_sock; 300 } 301 302 int 303 spdk_sock_close(struct spdk_sock **_sock) 304 { 305 struct spdk_sock *sock = *_sock; 306 int rc; 307 308 if (sock == NULL) { 309 errno = EBADF; 310 return -1; 311 } 312 313 if (sock->cb_fn != NULL) { 314 /* This sock is still part of a sock_group. */ 315 errno = EBUSY; 316 return -1; 317 } 318 319 sock->flags.closed = true; 320 321 if (sock->cb_cnt > 0) { 322 /* Let the callback unwind before destroying the socket */ 323 return 0; 324 } 325 326 spdk_sock_abort_requests(sock); 327 328 rc = sock->net_impl->close(sock); 329 if (rc == 0) { 330 *_sock = NULL; 331 } 332 333 return rc; 334 } 335 336 ssize_t 337 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) 338 { 339 if (sock == NULL) { 340 errno = EBADF; 341 return -1; 342 } 343 344 if (sock->flags.closed) { 345 errno = EBADF; 346 return -1; 347 } 348 349 return sock->net_impl->recv(sock, buf, len); 350 } 351 352 ssize_t 353 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 354 { 355 if (sock == NULL) { 356 errno = EBADF; 357 return -1; 358 } 359 360 if (sock->flags.closed) { 361 errno = EBADF; 362 return -1; 363 } 364 365 return sock->net_impl->readv(sock, iov, iovcnt); 366 } 367 368 ssize_t 369 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 370 { 371 if (sock == NULL) { 372 errno = EBADF; 373 return -1; 374 } 375 376 if (sock->flags.closed) { 377 errno = EBADF; 378 return -1; 379 } 380 381 return sock->net_impl->writev(sock, iov, iovcnt); 382 } 383 384 void 385 spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req) 386 { 387 assert(req->cb_fn != NULL); 388 389 if (sock == NULL) { 390 req->cb_fn(req->cb_arg, -EBADF); 391 return; 392 } 393 394 if (sock->flags.closed) { 395 req->cb_fn(req->cb_arg, -EBADF); 396 return; 397 } 398 399 sock->net_impl->writev_async(sock, req); 400 } 401 402 int 403 spdk_sock_flush(struct spdk_sock *sock) 404 { 405 if (sock == NULL) { 406 return -EBADF; 407 } 408 409 if (sock->flags.closed) { 410 return -EBADF; 411 } 412 413 return sock->net_impl->flush(sock); 414 } 415 416 int 417 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) 418 { 419 return sock->net_impl->set_recvlowat(sock, nbytes); 420 } 421 422 int 423 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz) 424 { 425 return sock->net_impl->set_recvbuf(sock, sz); 426 } 427 428 int 429 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz) 430 { 431 return sock->net_impl->set_sendbuf(sock, sz); 432 } 433 434 bool 435 spdk_sock_is_ipv6(struct spdk_sock *sock) 436 { 437 return sock->net_impl->is_ipv6(sock); 438 } 439 440 bool 441 spdk_sock_is_ipv4(struct spdk_sock *sock) 442 { 443 return sock->net_impl->is_ipv4(sock); 444 } 445 446 bool 447 spdk_sock_is_connected(struct spdk_sock *sock) 448 { 449 return sock->net_impl->is_connected(sock); 450 } 451 452 struct spdk_sock_group * 453 spdk_sock_group_create(void *ctx) 454 { 455 struct spdk_net_impl *impl = NULL; 456 struct spdk_sock_group *group; 457 struct spdk_sock_group_impl *group_impl; 458 459 group = calloc(1, sizeof(*group)); 460 if (group == NULL) { 461 return NULL; 462 } 463 464 STAILQ_INIT(&group->group_impls); 465 466 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 467 group_impl = impl->group_impl_create(); 468 if (group_impl != NULL) { 469 STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link); 470 TAILQ_INIT(&group_impl->socks); 471 group_impl->num_removed_socks = 0; 472 group_impl->net_impl = impl; 473 } 474 } 475 476 group->ctx = ctx; 477 return group; 478 } 479 480 void * 481 spdk_sock_group_get_ctx(struct spdk_sock_group *group) 482 { 483 if (group == NULL) { 484 return NULL; 485 } 486 487 return group->ctx; 488 } 489 490 int 491 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, 492 spdk_sock_cb cb_fn, void *cb_arg) 493 { 494 struct spdk_sock_group_impl *group_impl = NULL; 495 int rc, placement_id = 0; 496 497 if (cb_fn == NULL) { 498 errno = EINVAL; 499 return -1; 500 } 501 502 if (sock->group_impl != NULL) { 503 /* 504 * This sock is already part of a sock_group. Currently we don't 505 * support this. 506 */ 507 errno = EBUSY; 508 return -1; 509 } 510 511 rc = sock->net_impl->get_placement_id(sock, &placement_id); 512 if (!rc && (placement_id != 0)) { 513 rc = sock_map_insert(placement_id, group); 514 if (rc < 0) { 515 return -1; 516 } 517 } 518 519 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 520 if (sock->net_impl == group_impl->net_impl) { 521 break; 522 } 523 } 524 525 if (group_impl == NULL) { 526 errno = EINVAL; 527 return -1; 528 } 529 530 rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock); 531 if (rc == 0) { 532 TAILQ_INSERT_TAIL(&group_impl->socks, sock, link); 533 sock->group_impl = group_impl; 534 sock->cb_fn = cb_fn; 535 sock->cb_arg = cb_arg; 536 } 537 538 return rc; 539 } 540 541 int 542 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) 543 { 544 struct spdk_sock_group_impl *group_impl = NULL; 545 int rc, placement_id = 0; 546 547 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 548 if (sock->net_impl == group_impl->net_impl) { 549 break; 550 } 551 } 552 553 if (group_impl == NULL) { 554 errno = EINVAL; 555 return -1; 556 } 557 558 assert(group_impl == sock->group_impl); 559 560 rc = sock->net_impl->get_placement_id(sock, &placement_id); 561 if (!rc && (placement_id != 0)) { 562 sock_map_release(placement_id); 563 } 564 565 rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); 566 if (rc == 0) { 567 TAILQ_REMOVE(&group_impl->socks, sock, link); 568 assert(group_impl->num_removed_socks < MAX_EVENTS_PER_POLL); 569 group_impl->removed_socks[group_impl->num_removed_socks] = (uintptr_t)sock; 570 group_impl->num_removed_socks++; 571 sock->group_impl = NULL; 572 sock->cb_fn = NULL; 573 sock->cb_arg = NULL; 574 } 575 576 return rc; 577 } 578 579 int 580 spdk_sock_group_poll(struct spdk_sock_group *group) 581 { 582 return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL); 583 } 584 585 static int 586 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl, 587 struct spdk_sock_group *group, 588 int max_events) 589 { 590 struct spdk_sock *socks[MAX_EVENTS_PER_POLL]; 591 int num_events, i; 592 593 if (TAILQ_EMPTY(&group_impl->socks)) { 594 return 0; 595 } 596 597 /* The number of removed sockets should be reset for each call to poll. */ 598 group_impl->num_removed_socks = 0; 599 600 num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks); 601 if (num_events == -1) { 602 return -1; 603 } 604 605 for (i = 0; i < num_events; i++) { 606 struct spdk_sock *sock = socks[i]; 607 int j; 608 bool valid = true; 609 for (j = 0; j < group_impl->num_removed_socks; j++) { 610 if ((uintptr_t)sock == group_impl->removed_socks[j]) { 611 valid = false; 612 break; 613 } 614 } 615 616 if (valid) { 617 assert(sock->cb_fn != NULL); 618 sock->cb_fn(sock->cb_arg, group, sock); 619 } 620 } 621 622 return num_events; 623 } 624 625 int 626 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events) 627 { 628 struct spdk_sock_group_impl *group_impl = NULL; 629 int rc, num_events = 0; 630 631 if (max_events < 1) { 632 errno = -EINVAL; 633 return -1; 634 } 635 636 /* 637 * Only poll for up to 32 events at a time - if more events are pending, 638 * the next call to this function will reap them. 639 */ 640 if (max_events > MAX_EVENTS_PER_POLL) { 641 max_events = MAX_EVENTS_PER_POLL; 642 } 643 644 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 645 rc = sock_group_impl_poll_count(group_impl, group, max_events); 646 if (rc < 0) { 647 num_events = -1; 648 SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n", 649 group_impl->net_impl->name); 650 } else if (num_events >= 0) { 651 num_events += rc; 652 } 653 } 654 655 return num_events; 656 } 657 658 int 659 spdk_sock_group_close(struct spdk_sock_group **group) 660 { 661 struct spdk_sock_group_impl *group_impl = NULL, *tmp; 662 int rc; 663 664 if (*group == NULL) { 665 errno = EBADF; 666 return -1; 667 } 668 669 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 670 if (!TAILQ_EMPTY(&group_impl->socks)) { 671 errno = EBUSY; 672 return -1; 673 } 674 } 675 676 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 677 rc = group_impl->net_impl->group_impl_close(group_impl); 678 if (rc != 0) { 679 SPDK_ERRLOG("group_impl_close for net(%s) failed\n", 680 group_impl->net_impl->name); 681 } 682 } 683 684 sock_remove_sock_group_from_map_table(*group); 685 free(*group); 686 *group = NULL; 687 688 return 0; 689 } 690 691 static inline struct spdk_net_impl * 692 sock_get_impl_by_name(const char *impl_name) 693 { 694 struct spdk_net_impl *impl; 695 696 assert(impl_name != NULL); 697 STAILQ_FOREACH(impl, &g_net_impls, link) { 698 if (0 == strcmp(impl_name, impl->name)) { 699 return impl; 700 } 701 } 702 703 return NULL; 704 } 705 706 int 707 spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len) 708 { 709 struct spdk_net_impl *impl; 710 711 if (!impl_name || !opts || !len) { 712 errno = EINVAL; 713 return -1; 714 } 715 716 impl = sock_get_impl_by_name(impl_name); 717 if (!impl) { 718 errno = EINVAL; 719 return -1; 720 } 721 722 if (!impl->get_opts) { 723 errno = ENOTSUP; 724 return -1; 725 } 726 727 return impl->get_opts(opts, len); 728 } 729 730 int 731 spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len) 732 { 733 struct spdk_net_impl *impl; 734 735 if (!impl_name || !opts) { 736 errno = EINVAL; 737 return -1; 738 } 739 740 impl = sock_get_impl_by_name(impl_name); 741 if (!impl) { 742 errno = EINVAL; 743 return -1; 744 } 745 746 if (!impl->set_opts) { 747 errno = ENOTSUP; 748 return -1; 749 } 750 751 return impl->set_opts(opts, len); 752 } 753 754 void 755 spdk_net_impl_register(struct spdk_net_impl *impl, int priority) 756 { 757 struct spdk_net_impl *cur, *prev; 758 759 impl->priority = priority; 760 prev = NULL; 761 STAILQ_FOREACH(cur, &g_net_impls, link) { 762 if (impl->priority > cur->priority) { 763 break; 764 } 765 prev = cur; 766 } 767 768 if (prev) { 769 STAILQ_INSERT_AFTER(&g_net_impls, prev, impl, link); 770 } else { 771 STAILQ_INSERT_HEAD(&g_net_impls, impl, link); 772 } 773 } 774