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/sock.h" 37 #include "spdk_internal/sock.h" 38 #include "spdk/log.h" 39 40 #define SPDK_SOCK_DEFAULT_PRIORITY 0 41 #define SPDK_SOCK_DEFAULT_ZCOPY true 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 static struct spdk_net_impl *g_default_impl; 46 47 struct spdk_sock_placement_id_entry { 48 int placement_id; 49 uint32_t ref; 50 struct spdk_sock_group *group; 51 STAILQ_ENTRY(spdk_sock_placement_id_entry) link; 52 }; 53 54 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER( 55 g_placement_id_map); 56 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER; 57 58 /* Insert a group into the placement map. 59 * If the group is already in the map, take a reference. 60 */ 61 static int 62 sock_map_insert(int placement_id, struct spdk_sock_group *group) 63 { 64 struct spdk_sock_placement_id_entry *entry; 65 66 pthread_mutex_lock(&g_map_table_mutex); 67 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 68 if (placement_id == entry->placement_id) { 69 /* The mapping already exists, it means that different sockets have 70 * the same placement_ids. 71 */ 72 entry->ref++; 73 pthread_mutex_unlock(&g_map_table_mutex); 74 return 0; 75 } 76 } 77 78 entry = calloc(1, sizeof(*entry)); 79 if (!entry) { 80 SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id); 81 pthread_mutex_unlock(&g_map_table_mutex); 82 return -ENOMEM; 83 } 84 85 entry->placement_id = placement_id; 86 entry->group = group; 87 entry->ref++; 88 89 STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link); 90 pthread_mutex_unlock(&g_map_table_mutex); 91 92 return 0; 93 } 94 95 /* Release a reference to the group for a given placement_id. 96 * We use lazy free method. If a placement_id with a sock is associated with the group, 97 * it will possibly be associated again by another sock with the same placement_id. And 98 * there will no memory leak, because if a polling group is destroyed, the 99 * sock_remove_sock_group_from_map_table will be called to guarantee the mapping correctness. 100 */ 101 static void 102 sock_map_release(int placement_id) 103 { 104 struct spdk_sock_placement_id_entry *entry; 105 106 pthread_mutex_lock(&g_map_table_mutex); 107 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 108 if (placement_id == entry->placement_id) { 109 assert(entry->ref > 0); 110 entry->ref--; 111 break; 112 } 113 } 114 115 pthread_mutex_unlock(&g_map_table_mutex); 116 } 117 118 /* Look up the group for a placement_id. */ 119 static void 120 sock_map_lookup(int placement_id, struct spdk_sock_group **group) 121 { 122 struct spdk_sock_placement_id_entry *entry; 123 124 *group = NULL; 125 pthread_mutex_lock(&g_map_table_mutex); 126 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 127 if (placement_id == entry->placement_id) { 128 assert(entry->group != NULL); 129 *group = entry->group; 130 break; 131 } 132 } 133 pthread_mutex_unlock(&g_map_table_mutex); 134 } 135 136 /* Remove the socket group from the map table */ 137 static void 138 sock_remove_sock_group_from_map_table(struct spdk_sock_group *group) 139 { 140 struct spdk_sock_placement_id_entry *entry, *tmp; 141 142 pthread_mutex_lock(&g_map_table_mutex); 143 STAILQ_FOREACH_SAFE(entry, &g_placement_id_map, link, tmp) { 144 if (entry->group == group) { 145 STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); 146 free(entry); 147 } 148 } 149 pthread_mutex_unlock(&g_map_table_mutex); 150 151 } 152 153 static int 154 sock_get_placement_id(struct spdk_sock *sock) 155 { 156 int rc; 157 int placement_id; 158 159 if (!sock->placement_id) { 160 rc = sock->net_impl->get_placement_id(sock, &placement_id); 161 if (!rc && (placement_id != 0)) { 162 sock->placement_id = placement_id; 163 } 164 } 165 166 return sock->placement_id; 167 } 168 169 int 170 spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group) 171 { 172 int placement_id; 173 174 placement_id = sock_get_placement_id(sock); 175 if (placement_id != 0) { 176 sock_map_lookup(placement_id, group); 177 return 0; 178 } else { 179 return -1; 180 } 181 } 182 183 int 184 spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, 185 char *caddr, int clen, uint16_t *cport) 186 { 187 return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport); 188 } 189 190 void 191 spdk_sock_get_default_opts(struct spdk_sock_opts *opts) 192 { 193 assert(opts); 194 195 if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) { 196 opts->priority = SPDK_SOCK_DEFAULT_PRIORITY; 197 } 198 199 if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) { 200 opts->zcopy = SPDK_SOCK_DEFAULT_ZCOPY; 201 } 202 } 203 204 /* 205 * opts The opts allocated in the current library. 206 * opts_user The opts passed by the caller. 207 * */ 208 static void 209 sock_init_opts(struct spdk_sock_opts *opts, struct spdk_sock_opts *opts_user) 210 { 211 assert(opts); 212 assert(opts_user); 213 214 opts->opts_size = sizeof(*opts); 215 spdk_sock_get_default_opts(opts); 216 217 /* reset the size according to the user */ 218 opts->opts_size = opts_user->opts_size; 219 if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) { 220 opts->priority = opts_user->priority; 221 } 222 223 if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) { 224 opts->zcopy = opts_user->zcopy; 225 } 226 } 227 228 struct spdk_sock * 229 spdk_sock_connect(const char *ip, int port, char *impl_name) 230 { 231 struct spdk_sock_opts opts; 232 233 opts.opts_size = sizeof(opts); 234 spdk_sock_get_default_opts(&opts); 235 return spdk_sock_connect_ext(ip, port, impl_name, &opts); 236 } 237 238 struct spdk_sock * 239 spdk_sock_connect_ext(const char *ip, int port, char *_impl_name, struct spdk_sock_opts *opts) 240 { 241 struct spdk_net_impl *impl = NULL; 242 struct spdk_sock *sock; 243 struct spdk_sock_opts opts_local; 244 const char *impl_name = NULL; 245 246 if (opts == NULL) { 247 SPDK_ERRLOG("the opts should not be NULL pointer\n"); 248 return NULL; 249 } 250 251 if (_impl_name) { 252 impl_name = _impl_name; 253 } else if (g_default_impl) { 254 impl_name = g_default_impl->name; 255 } 256 257 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 258 if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) { 259 continue; 260 } 261 262 SPDK_DEBUGLOG(sock, "Creating a client socket using impl %s\n", impl->name); 263 sock_init_opts(&opts_local, opts); 264 sock = impl->connect(ip, port, &opts_local); 265 if (sock != NULL) { 266 /* Copy the contents, both the two structures are the same ABI version */ 267 memcpy(&sock->opts, &opts_local, sizeof(sock->opts)); 268 sock->net_impl = impl; 269 TAILQ_INIT(&sock->queued_reqs); 270 TAILQ_INIT(&sock->pending_reqs); 271 return sock; 272 } 273 } 274 275 return NULL; 276 } 277 278 struct spdk_sock * 279 spdk_sock_listen(const char *ip, int port, char *impl_name) 280 { 281 struct spdk_sock_opts opts; 282 283 opts.opts_size = sizeof(opts); 284 spdk_sock_get_default_opts(&opts); 285 return spdk_sock_listen_ext(ip, port, impl_name, &opts); 286 } 287 288 struct spdk_sock * 289 spdk_sock_listen_ext(const char *ip, int port, char *_impl_name, struct spdk_sock_opts *opts) 290 { 291 struct spdk_net_impl *impl = NULL; 292 struct spdk_sock *sock; 293 struct spdk_sock_opts opts_local; 294 const char *impl_name = NULL; 295 296 if (opts == NULL) { 297 SPDK_ERRLOG("the opts should not be NULL pointer\n"); 298 return NULL; 299 } 300 301 if (_impl_name) { 302 impl_name = _impl_name; 303 } else if (g_default_impl) { 304 impl_name = g_default_impl->name; 305 } 306 307 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 308 if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) { 309 continue; 310 } 311 312 SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name); 313 sock_init_opts(&opts_local, opts); 314 sock = impl->listen(ip, port, &opts_local); 315 if (sock != NULL) { 316 /* Copy the contents, both the two structures are the same ABI version */ 317 memcpy(&sock->opts, &opts_local, sizeof(sock->opts)); 318 sock->net_impl = impl; 319 /* Don't need to initialize the request queues for listen 320 * sockets. */ 321 return sock; 322 } 323 } 324 325 return NULL; 326 } 327 328 struct spdk_sock * 329 spdk_sock_accept(struct spdk_sock *sock) 330 { 331 struct spdk_sock *new_sock; 332 333 new_sock = sock->net_impl->accept(sock); 334 if (new_sock != NULL) { 335 /* Inherit the opts from the "accept sock" */ 336 new_sock->opts = sock->opts; 337 memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts)); 338 new_sock->net_impl = sock->net_impl; 339 TAILQ_INIT(&new_sock->queued_reqs); 340 TAILQ_INIT(&new_sock->pending_reqs); 341 } 342 343 return new_sock; 344 } 345 346 int 347 spdk_sock_close(struct spdk_sock **_sock) 348 { 349 struct spdk_sock *sock = *_sock; 350 int rc; 351 352 if (sock == NULL) { 353 errno = EBADF; 354 return -1; 355 } 356 357 if (sock->cb_fn != NULL) { 358 /* This sock is still part of a sock_group. */ 359 errno = EBUSY; 360 return -1; 361 } 362 363 sock->flags.closed = true; 364 365 if (sock->cb_cnt > 0) { 366 /* Let the callback unwind before destroying the socket */ 367 return 0; 368 } 369 370 spdk_sock_abort_requests(sock); 371 372 rc = sock->net_impl->close(sock); 373 if (rc == 0) { 374 *_sock = NULL; 375 } 376 377 return rc; 378 } 379 380 ssize_t 381 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) 382 { 383 if (sock == NULL) { 384 errno = EBADF; 385 return -1; 386 } 387 388 if (sock->flags.closed) { 389 errno = EBADF; 390 return -1; 391 } 392 393 return sock->net_impl->recv(sock, buf, len); 394 } 395 396 ssize_t 397 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 398 { 399 if (sock == NULL) { 400 errno = EBADF; 401 return -1; 402 } 403 404 if (sock->flags.closed) { 405 errno = EBADF; 406 return -1; 407 } 408 409 return sock->net_impl->readv(sock, iov, iovcnt); 410 } 411 412 ssize_t 413 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 414 { 415 if (sock == NULL) { 416 errno = EBADF; 417 return -1; 418 } 419 420 if (sock->flags.closed) { 421 errno = EBADF; 422 return -1; 423 } 424 425 return sock->net_impl->writev(sock, iov, iovcnt); 426 } 427 428 void 429 spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req) 430 { 431 assert(req->cb_fn != NULL); 432 433 if (sock == NULL) { 434 req->cb_fn(req->cb_arg, -EBADF); 435 return; 436 } 437 438 if (sock->flags.closed) { 439 req->cb_fn(req->cb_arg, -EBADF); 440 return; 441 } 442 443 sock->net_impl->writev_async(sock, req); 444 } 445 446 int 447 spdk_sock_flush(struct spdk_sock *sock) 448 { 449 if (sock == NULL) { 450 return -EBADF; 451 } 452 453 if (sock->flags.closed) { 454 return -EBADF; 455 } 456 457 /* Sock is in a polling group, so group polling mechanism will work */ 458 if (sock->group_impl != NULL) { 459 return 0; 460 } 461 462 return sock->net_impl->flush(sock); 463 } 464 465 int 466 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) 467 { 468 return sock->net_impl->set_recvlowat(sock, nbytes); 469 } 470 471 int 472 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz) 473 { 474 return sock->net_impl->set_recvbuf(sock, sz); 475 } 476 477 int 478 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz) 479 { 480 return sock->net_impl->set_sendbuf(sock, sz); 481 } 482 483 bool 484 spdk_sock_is_ipv6(struct spdk_sock *sock) 485 { 486 return sock->net_impl->is_ipv6(sock); 487 } 488 489 bool 490 spdk_sock_is_ipv4(struct spdk_sock *sock) 491 { 492 return sock->net_impl->is_ipv4(sock); 493 } 494 495 bool 496 spdk_sock_is_connected(struct spdk_sock *sock) 497 { 498 return sock->net_impl->is_connected(sock); 499 } 500 501 struct spdk_sock_group * 502 spdk_sock_group_create(void *ctx) 503 { 504 struct spdk_net_impl *impl = NULL; 505 struct spdk_sock_group *group; 506 struct spdk_sock_group_impl *group_impl; 507 508 group = calloc(1, sizeof(*group)); 509 if (group == NULL) { 510 return NULL; 511 } 512 513 STAILQ_INIT(&group->group_impls); 514 515 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 516 group_impl = impl->group_impl_create(); 517 if (group_impl != NULL) { 518 STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link); 519 TAILQ_INIT(&group_impl->socks); 520 group_impl->num_removed_socks = 0; 521 group_impl->net_impl = impl; 522 } 523 } 524 525 group->ctx = ctx; 526 return group; 527 } 528 529 void * 530 spdk_sock_group_get_ctx(struct spdk_sock_group *group) 531 { 532 if (group == NULL) { 533 return NULL; 534 } 535 536 return group->ctx; 537 } 538 539 int 540 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, 541 spdk_sock_cb cb_fn, void *cb_arg) 542 { 543 struct spdk_sock_group_impl *group_impl = NULL; 544 int rc, placement_id = 0; 545 546 if (cb_fn == NULL) { 547 errno = EINVAL; 548 return -1; 549 } 550 551 if (sock->group_impl != NULL) { 552 /* 553 * This sock is already part of a sock_group. Currently we don't 554 * support this. 555 */ 556 errno = EBUSY; 557 return -1; 558 } 559 560 placement_id = sock_get_placement_id(sock); 561 if (placement_id != 0) { 562 rc = sock_map_insert(placement_id, group); 563 if (rc < 0) { 564 return -1; 565 } 566 } 567 568 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 569 if (sock->net_impl == group_impl->net_impl) { 570 break; 571 } 572 } 573 574 if (group_impl == NULL) { 575 errno = EINVAL; 576 return -1; 577 } 578 579 rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock); 580 if (rc == 0) { 581 TAILQ_INSERT_TAIL(&group_impl->socks, sock, link); 582 sock->group_impl = group_impl; 583 sock->cb_fn = cb_fn; 584 sock->cb_arg = cb_arg; 585 } 586 587 return rc; 588 } 589 590 int 591 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) 592 { 593 struct spdk_sock_group_impl *group_impl = NULL; 594 int rc, placement_id = 0; 595 596 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 597 if (sock->net_impl == group_impl->net_impl) { 598 break; 599 } 600 } 601 602 if (group_impl == NULL) { 603 errno = EINVAL; 604 return -1; 605 } 606 607 assert(group_impl == sock->group_impl); 608 609 placement_id = sock_get_placement_id(sock); 610 if (placement_id != 0) { 611 sock_map_release(placement_id); 612 } 613 614 rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); 615 if (rc == 0) { 616 TAILQ_REMOVE(&group_impl->socks, sock, link); 617 assert(group_impl->num_removed_socks < MAX_EVENTS_PER_POLL); 618 group_impl->removed_socks[group_impl->num_removed_socks] = (uintptr_t)sock; 619 group_impl->num_removed_socks++; 620 sock->group_impl = NULL; 621 sock->cb_fn = NULL; 622 sock->cb_arg = NULL; 623 } 624 625 return rc; 626 } 627 628 int 629 spdk_sock_group_poll(struct spdk_sock_group *group) 630 { 631 return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL); 632 } 633 634 static int 635 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl, 636 struct spdk_sock_group *group, 637 int max_events) 638 { 639 struct spdk_sock *socks[MAX_EVENTS_PER_POLL]; 640 int num_events, i; 641 642 if (TAILQ_EMPTY(&group_impl->socks)) { 643 return 0; 644 } 645 646 /* The number of removed sockets should be reset for each call to poll. */ 647 group_impl->num_removed_socks = 0; 648 649 num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks); 650 if (num_events == -1) { 651 return -1; 652 } 653 654 for (i = 0; i < num_events; i++) { 655 struct spdk_sock *sock = socks[i]; 656 int j; 657 bool valid = true; 658 for (j = 0; j < group_impl->num_removed_socks; j++) { 659 if ((uintptr_t)sock == group_impl->removed_socks[j]) { 660 valid = false; 661 break; 662 } 663 } 664 665 if (valid) { 666 assert(sock->cb_fn != NULL); 667 sock->cb_fn(sock->cb_arg, group, sock); 668 } 669 } 670 671 return num_events; 672 } 673 674 int 675 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events) 676 { 677 struct spdk_sock_group_impl *group_impl = NULL; 678 int rc, num_events = 0; 679 680 if (max_events < 1) { 681 errno = -EINVAL; 682 return -1; 683 } 684 685 /* 686 * Only poll for up to 32 events at a time - if more events are pending, 687 * the next call to this function will reap them. 688 */ 689 if (max_events > MAX_EVENTS_PER_POLL) { 690 max_events = MAX_EVENTS_PER_POLL; 691 } 692 693 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 694 rc = sock_group_impl_poll_count(group_impl, group, max_events); 695 if (rc < 0) { 696 num_events = -1; 697 SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n", 698 group_impl->net_impl->name); 699 } else if (num_events >= 0) { 700 num_events += rc; 701 } 702 } 703 704 return num_events; 705 } 706 707 int 708 spdk_sock_group_close(struct spdk_sock_group **group) 709 { 710 struct spdk_sock_group_impl *group_impl = NULL, *tmp; 711 int rc; 712 713 if (*group == NULL) { 714 errno = EBADF; 715 return -1; 716 } 717 718 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 719 if (!TAILQ_EMPTY(&group_impl->socks)) { 720 errno = EBUSY; 721 return -1; 722 } 723 } 724 725 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 726 rc = group_impl->net_impl->group_impl_close(group_impl); 727 if (rc != 0) { 728 SPDK_ERRLOG("group_impl_close for net(%s) failed\n", 729 group_impl->net_impl->name); 730 } 731 } 732 733 sock_remove_sock_group_from_map_table(*group); 734 free(*group); 735 *group = NULL; 736 737 return 0; 738 } 739 740 static inline struct spdk_net_impl * 741 sock_get_impl_by_name(const char *impl_name) 742 { 743 struct spdk_net_impl *impl; 744 745 assert(impl_name != NULL); 746 STAILQ_FOREACH(impl, &g_net_impls, link) { 747 if (0 == strcmp(impl_name, impl->name)) { 748 return impl; 749 } 750 } 751 752 return NULL; 753 } 754 755 int 756 spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len) 757 { 758 struct spdk_net_impl *impl; 759 760 if (!impl_name || !opts || !len) { 761 errno = EINVAL; 762 return -1; 763 } 764 765 impl = sock_get_impl_by_name(impl_name); 766 if (!impl) { 767 errno = EINVAL; 768 return -1; 769 } 770 771 if (!impl->get_opts) { 772 errno = ENOTSUP; 773 return -1; 774 } 775 776 return impl->get_opts(opts, len); 777 } 778 779 int 780 spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len) 781 { 782 struct spdk_net_impl *impl; 783 784 if (!impl_name || !opts) { 785 errno = EINVAL; 786 return -1; 787 } 788 789 impl = sock_get_impl_by_name(impl_name); 790 if (!impl) { 791 errno = EINVAL; 792 return -1; 793 } 794 795 if (!impl->set_opts) { 796 errno = ENOTSUP; 797 return -1; 798 } 799 800 return impl->set_opts(opts, len); 801 } 802 803 void 804 spdk_sock_write_config_json(struct spdk_json_write_ctx *w) 805 { 806 struct spdk_net_impl *impl; 807 struct spdk_sock_impl_opts opts; 808 size_t len; 809 810 assert(w != NULL); 811 812 spdk_json_write_array_begin(w); 813 814 if (g_default_impl) { 815 spdk_json_write_object_begin(w); 816 spdk_json_write_named_string(w, "method", "sock_set_default_impl"); 817 spdk_json_write_named_object_begin(w, "params"); 818 spdk_json_write_named_string(w, "impl_name", g_default_impl->name); 819 spdk_json_write_object_end(w); 820 spdk_json_write_object_end(w); 821 } 822 823 STAILQ_FOREACH(impl, &g_net_impls, link) { 824 if (!impl->get_opts) { 825 continue; 826 } 827 828 len = sizeof(opts); 829 if (impl->get_opts(&opts, &len) == 0) { 830 spdk_json_write_object_begin(w); 831 spdk_json_write_named_string(w, "method", "sock_impl_set_options"); 832 spdk_json_write_named_object_begin(w, "params"); 833 spdk_json_write_named_string(w, "impl_name", impl->name); 834 spdk_json_write_named_uint32(w, "recv_buf_size", opts.recv_buf_size); 835 spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size); 836 spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe); 837 spdk_json_write_named_bool(w, "enable_zerocopy_send", opts.enable_zerocopy_send); 838 spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack); 839 spdk_json_write_named_bool(w, "enable_placement_id", opts.enable_placement_id); 840 spdk_json_write_object_end(w); 841 spdk_json_write_object_end(w); 842 } else { 843 SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name); 844 } 845 } 846 847 spdk_json_write_array_end(w); 848 } 849 850 void 851 spdk_net_impl_register(struct spdk_net_impl *impl, int priority) 852 { 853 struct spdk_net_impl *cur, *prev; 854 855 impl->priority = priority; 856 prev = NULL; 857 STAILQ_FOREACH(cur, &g_net_impls, link) { 858 if (impl->priority > cur->priority) { 859 break; 860 } 861 prev = cur; 862 } 863 864 if (prev) { 865 STAILQ_INSERT_AFTER(&g_net_impls, prev, impl, link); 866 } else { 867 STAILQ_INSERT_HEAD(&g_net_impls, impl, link); 868 } 869 } 870 871 int spdk_sock_set_default_impl(const char *impl_name) 872 { 873 struct spdk_net_impl *impl; 874 875 if (!impl_name) { 876 errno = EINVAL; 877 return -1; 878 } 879 880 impl = sock_get_impl_by_name(impl_name); 881 if (!impl) { 882 errno = EINVAL; 883 return -1; 884 } 885 886 if (impl == g_default_impl) { 887 return 0; 888 } 889 890 if (g_default_impl) { 891 SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name, 892 impl->name); 893 } else { 894 SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name); 895 } 896 897 g_default_impl = impl; 898 899 return 0; 900 } 901 902 SPDK_LOG_REGISTER_COMPONENT(sock) 903