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