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