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