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 #include "spdk/env.h" 40 41 #define SPDK_SOCK_DEFAULT_PRIORITY 0 42 #define SPDK_SOCK_DEFAULT_ZCOPY true 43 #define SPDK_SOCK_OPTS_FIELD_OK(opts, field) (offsetof(struct spdk_sock_opts, field) + sizeof(opts->field) <= (opts->opts_size)) 44 45 static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls); 46 static struct spdk_net_impl *g_default_impl; 47 48 struct spdk_sock_placement_id_entry { 49 int placement_id; 50 uint32_t ref; 51 struct spdk_sock_group *group; 52 STAILQ_ENTRY(spdk_sock_placement_id_entry) link; 53 }; 54 55 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER( 56 g_placement_id_map); 57 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER; 58 59 /* Insert a group into the placement map. 60 * If the group is already in the map, take a reference. 61 */ 62 static int 63 sock_map_insert(int placement_id, struct spdk_sock_group *group) 64 { 65 struct spdk_sock_placement_id_entry *entry; 66 67 pthread_mutex_lock(&g_map_table_mutex); 68 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 69 if (placement_id == entry->placement_id) { 70 if (entry->group != group) { 71 pthread_mutex_unlock(&g_map_table_mutex); 72 return -EINVAL; 73 } 74 entry->ref++; 75 pthread_mutex_unlock(&g_map_table_mutex); 76 return 0; 77 } 78 } 79 80 entry = calloc(1, sizeof(*entry)); 81 if (!entry) { 82 SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id); 83 pthread_mutex_unlock(&g_map_table_mutex); 84 return -ENOMEM; 85 } 86 87 entry->placement_id = placement_id; 88 entry->group = group; 89 entry->ref++; 90 91 STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link); 92 pthread_mutex_unlock(&g_map_table_mutex); 93 94 return 0; 95 } 96 97 /* Release a reference to the group for a given placement_id */ 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 = -1; 155 156 if (sock->placement_id == -1) { 157 rc = sock->net_impl->get_placement_id(sock, &placement_id); 158 if (!rc && (placement_id != -1)) { 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 = -1; 170 171 placement_id = sock_get_placement_id(sock); 172 if (placement_id != -1) { 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 /* Set the placement_id to -1 explicitly */ 267 sock->placement_id = -1; 268 TAILQ_INIT(&sock->queued_reqs); 269 TAILQ_INIT(&sock->pending_reqs); 270 return sock; 271 } 272 } 273 274 return NULL; 275 } 276 277 struct spdk_sock * 278 spdk_sock_listen(const char *ip, int port, char *impl_name) 279 { 280 struct spdk_sock_opts opts; 281 282 opts.opts_size = sizeof(opts); 283 spdk_sock_get_default_opts(&opts); 284 return spdk_sock_listen_ext(ip, port, impl_name, &opts); 285 } 286 287 struct spdk_sock * 288 spdk_sock_listen_ext(const char *ip, int port, char *_impl_name, struct spdk_sock_opts *opts) 289 { 290 struct spdk_net_impl *impl = NULL; 291 struct spdk_sock *sock; 292 struct spdk_sock_opts opts_local; 293 const char *impl_name = NULL; 294 295 if (opts == NULL) { 296 SPDK_ERRLOG("the opts should not be NULL pointer\n"); 297 return NULL; 298 } 299 300 if (_impl_name) { 301 impl_name = _impl_name; 302 } else if (g_default_impl) { 303 impl_name = g_default_impl->name; 304 } 305 306 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 307 if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) { 308 continue; 309 } 310 311 SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name); 312 sock_init_opts(&opts_local, opts); 313 sock = impl->listen(ip, port, &opts_local); 314 if (sock != NULL) { 315 /* Copy the contents, both the two structures are the same ABI version */ 316 memcpy(&sock->opts, &opts_local, sizeof(sock->opts)); 317 sock->net_impl = impl; 318 /* Don't need to initialize the request queues for listen 319 * sockets. */ 320 return sock; 321 } 322 } 323 324 return NULL; 325 } 326 327 struct spdk_sock * 328 spdk_sock_accept(struct spdk_sock *sock) 329 { 330 struct spdk_sock *new_sock; 331 332 new_sock = sock->net_impl->accept(sock); 333 if (new_sock != NULL) { 334 /* Inherit the opts from the "accept sock" */ 335 new_sock->opts = sock->opts; 336 memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts)); 337 new_sock->net_impl = sock->net_impl; 338 /* Set the placement_id to -1 explicitly */ 339 new_sock->placement_id = -1; 340 TAILQ_INIT(&new_sock->queued_reqs); 341 TAILQ_INIT(&new_sock->pending_reqs); 342 } 343 344 return new_sock; 345 } 346 347 int 348 spdk_sock_close(struct spdk_sock **_sock) 349 { 350 struct spdk_sock *sock = *_sock; 351 int rc; 352 353 if (sock == NULL) { 354 errno = EBADF; 355 return -1; 356 } 357 358 if (sock->cb_fn != NULL) { 359 /* This sock is still part of a sock_group. */ 360 errno = EBUSY; 361 return -1; 362 } 363 364 sock->flags.closed = true; 365 366 if (sock->cb_cnt > 0) { 367 /* Let the callback unwind before destroying the socket */ 368 return 0; 369 } 370 371 spdk_sock_abort_requests(sock); 372 373 rc = sock->net_impl->close(sock); 374 if (rc == 0) { 375 *_sock = NULL; 376 } 377 378 return rc; 379 } 380 381 ssize_t 382 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) 383 { 384 if (sock == NULL || sock->flags.closed) { 385 errno = EBADF; 386 return -1; 387 } 388 389 return sock->net_impl->recv(sock, buf, len); 390 } 391 392 ssize_t 393 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 394 { 395 if (sock == NULL || sock->flags.closed) { 396 errno = EBADF; 397 return -1; 398 } 399 400 return sock->net_impl->readv(sock, iov, iovcnt); 401 } 402 403 ssize_t 404 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 405 { 406 if (sock == NULL || sock->flags.closed) { 407 errno = EBADF; 408 return -1; 409 } 410 411 return sock->net_impl->writev(sock, iov, iovcnt); 412 } 413 414 void 415 spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req) 416 { 417 assert(req->cb_fn != NULL); 418 419 if (sock == NULL || sock->flags.closed) { 420 req->cb_fn(req->cb_arg, -EBADF); 421 return; 422 } 423 424 sock->net_impl->writev_async(sock, req); 425 } 426 427 int 428 spdk_sock_flush(struct spdk_sock *sock) 429 { 430 if (sock == NULL || sock->flags.closed) { 431 return -EBADF; 432 } 433 434 /* Sock is in a polling group, so group polling mechanism will work */ 435 if (sock->group_impl != NULL) { 436 return 0; 437 } 438 439 return sock->net_impl->flush(sock); 440 } 441 442 int 443 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) 444 { 445 return sock->net_impl->set_recvlowat(sock, nbytes); 446 } 447 448 int 449 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz) 450 { 451 return sock->net_impl->set_recvbuf(sock, sz); 452 } 453 454 int 455 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz) 456 { 457 return sock->net_impl->set_sendbuf(sock, sz); 458 } 459 460 bool 461 spdk_sock_is_ipv6(struct spdk_sock *sock) 462 { 463 return sock->net_impl->is_ipv6(sock); 464 } 465 466 bool 467 spdk_sock_is_ipv4(struct spdk_sock *sock) 468 { 469 return sock->net_impl->is_ipv4(sock); 470 } 471 472 bool 473 spdk_sock_is_connected(struct spdk_sock *sock) 474 { 475 return sock->net_impl->is_connected(sock); 476 } 477 478 struct spdk_sock_group * 479 spdk_sock_group_create(void *ctx) 480 { 481 struct spdk_net_impl *impl = NULL; 482 struct spdk_sock_group *group; 483 struct spdk_sock_group_impl *group_impl; 484 struct spdk_sock_impl_opts sock_opts = {}; 485 size_t sock_len; 486 bool enable_incoming_cpu = false; 487 488 group = calloc(1, sizeof(*group)); 489 if (group == NULL) { 490 return NULL; 491 } 492 493 STAILQ_INIT(&group->group_impls); 494 495 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 496 group_impl = impl->group_impl_create(); 497 if (group_impl != NULL) { 498 STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link); 499 TAILQ_INIT(&group_impl->socks); 500 group_impl->net_impl = impl; 501 502 sock_len = sizeof(sock_opts); 503 spdk_sock_impl_get_opts(impl->name, &sock_opts, &sock_len); 504 if (sock_opts.enable_placement_id == PLACEMENT_CPU) { 505 enable_incoming_cpu = true; 506 } 507 } 508 } 509 510 group->ctx = ctx; 511 512 /* if any net_impl is configured to use SO_INCOMING_CPU, initialize the sock map */ 513 if (enable_incoming_cpu) { 514 sock_map_insert(spdk_env_get_current_core(), group); 515 } 516 517 return group; 518 } 519 520 void * 521 spdk_sock_group_get_ctx(struct spdk_sock_group *group) 522 { 523 if (group == NULL) { 524 return NULL; 525 } 526 527 return group->ctx; 528 } 529 530 int 531 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, 532 spdk_sock_cb cb_fn, void *cb_arg) 533 { 534 struct spdk_sock_group_impl *group_impl = NULL; 535 int rc, placement_id = 0; 536 537 if (cb_fn == NULL) { 538 errno = EINVAL; 539 return -1; 540 } 541 542 if (sock->group_impl != NULL) { 543 /* 544 * This sock is already part of a sock_group. 545 */ 546 errno = EINVAL; 547 return -1; 548 } 549 550 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 551 if (sock->net_impl == group_impl->net_impl) { 552 break; 553 } 554 } 555 556 if (group_impl == NULL) { 557 errno = EINVAL; 558 return -1; 559 } 560 561 rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock); 562 if (rc != 0) { 563 return rc; 564 } 565 566 TAILQ_INSERT_TAIL(&group_impl->socks, sock, link); 567 sock->group_impl = group_impl; 568 sock->cb_fn = cb_fn; 569 sock->cb_arg = cb_arg; 570 571 placement_id = sock_get_placement_id(sock); 572 if (placement_id != -1) { 573 rc = sock_map_insert(placement_id, group); 574 if (rc != 0) { 575 SPDK_ERRLOG("Failed to insert sock group into map: %d", rc); 576 /* Do not treat this as an error. The system will continue running. */ 577 } 578 } 579 580 return 0; 581 } 582 583 int 584 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) 585 { 586 struct spdk_sock_group_impl *group_impl = NULL; 587 int rc, placement_id = 0; 588 589 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 590 if (sock->net_impl == group_impl->net_impl) { 591 break; 592 } 593 } 594 595 if (group_impl == NULL) { 596 errno = EINVAL; 597 return -1; 598 } 599 600 assert(group_impl == sock->group_impl); 601 602 placement_id = sock_get_placement_id(sock); 603 if (placement_id != -1) { 604 sock_map_release(placement_id); 605 } 606 607 rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); 608 if (rc == 0) { 609 TAILQ_REMOVE(&group_impl->socks, sock, link); 610 sock->group_impl = NULL; 611 sock->cb_fn = NULL; 612 sock->cb_arg = NULL; 613 } 614 615 return rc; 616 } 617 618 int 619 spdk_sock_group_poll(struct spdk_sock_group *group) 620 { 621 return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL); 622 } 623 624 static int 625 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl, 626 struct spdk_sock_group *group, 627 int max_events) 628 { 629 struct spdk_sock *socks[MAX_EVENTS_PER_POLL]; 630 int num_events, i; 631 632 if (TAILQ_EMPTY(&group_impl->socks)) { 633 return 0; 634 } 635 636 num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks); 637 if (num_events == -1) { 638 return -1; 639 } 640 641 for (i = 0; i < num_events; i++) { 642 struct spdk_sock *sock = socks[i]; 643 assert(sock->cb_fn != NULL); 644 sock->cb_fn(sock->cb_arg, group, sock); 645 } 646 647 return num_events; 648 } 649 650 int 651 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events) 652 { 653 struct spdk_sock_group_impl *group_impl = NULL; 654 int rc, num_events = 0; 655 656 if (max_events < 1) { 657 errno = -EINVAL; 658 return -1; 659 } 660 661 /* 662 * Only poll for up to 32 events at a time - if more events are pending, 663 * the next call to this function will reap them. 664 */ 665 if (max_events > MAX_EVENTS_PER_POLL) { 666 max_events = MAX_EVENTS_PER_POLL; 667 } 668 669 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 670 rc = sock_group_impl_poll_count(group_impl, group, max_events); 671 if (rc < 0) { 672 num_events = -1; 673 SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n", 674 group_impl->net_impl->name); 675 } else if (num_events >= 0) { 676 num_events += rc; 677 } 678 } 679 680 return num_events; 681 } 682 683 int 684 spdk_sock_group_close(struct spdk_sock_group **group) 685 { 686 struct spdk_sock_group_impl *group_impl = NULL, *tmp; 687 int rc; 688 struct spdk_sock_impl_opts sock_opts = {}; 689 size_t sock_len; 690 bool enable_incoming_cpu = false; 691 692 if (*group == NULL) { 693 errno = EBADF; 694 return -1; 695 } 696 697 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 698 if (!TAILQ_EMPTY(&group_impl->socks)) { 699 errno = EBUSY; 700 return -1; 701 } 702 } 703 704 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 705 sock_len = sizeof(sock_opts); 706 spdk_sock_impl_get_opts(group_impl->net_impl->name, &sock_opts, &sock_len); 707 if (sock_opts.enable_placement_id == PLACEMENT_CPU) { 708 enable_incoming_cpu = true; 709 break; 710 } 711 } 712 713 if (enable_incoming_cpu) { 714 sock_map_release(spdk_env_get_current_core()); 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_named_bool(w, "enable_quickack", opts.enable_quickack); 831 spdk_json_write_named_uint32(w, "enable_placement_id", opts.enable_placement_id); 832 spdk_json_write_object_end(w); 833 spdk_json_write_object_end(w); 834 } else { 835 SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name); 836 } 837 } 838 839 spdk_json_write_array_end(w); 840 } 841 842 void 843 spdk_net_impl_register(struct spdk_net_impl *impl, int priority) 844 { 845 struct spdk_net_impl *cur, *prev; 846 847 impl->priority = priority; 848 prev = NULL; 849 STAILQ_FOREACH(cur, &g_net_impls, link) { 850 if (impl->priority > cur->priority) { 851 break; 852 } 853 prev = cur; 854 } 855 856 if (prev) { 857 STAILQ_INSERT_AFTER(&g_net_impls, prev, impl, link); 858 } else { 859 STAILQ_INSERT_HEAD(&g_net_impls, impl, link); 860 } 861 } 862 863 int spdk_sock_set_default_impl(const char *impl_name) 864 { 865 struct spdk_net_impl *impl; 866 867 if (!impl_name) { 868 errno = EINVAL; 869 return -1; 870 } 871 872 impl = sock_get_impl_by_name(impl_name); 873 if (!impl) { 874 errno = EINVAL; 875 return -1; 876 } 877 878 if (impl == g_default_impl) { 879 return 0; 880 } 881 882 if (g_default_impl) { 883 SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name, 884 impl->name); 885 } else { 886 SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name); 887 } 888 889 g_default_impl = impl; 890 891 return 0; 892 } 893 894 SPDK_LOG_REGISTER_COMPONENT(sock) 895