xref: /spdk/lib/sock/sock.c (revision fecffda6ecf8853b82edccde429b68252f0a62c5)
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