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