xref: /spdk/lib/sock/sock.c (revision ea8f5b27612fa03698a9ce3ad4bd37765d9cdfa5)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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 		return -EBADF;
520 	}
521 
522 	/* Sock is in a polling group, so group polling mechanism will work */
523 	if (sock->group_impl != NULL) {
524 		return 0;
525 	}
526 
527 	return sock->net_impl->flush(sock);
528 }
529 
530 int
531 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
532 {
533 	return sock->net_impl->set_recvlowat(sock, nbytes);
534 }
535 
536 int
537 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
538 {
539 	return sock->net_impl->set_recvbuf(sock, sz);
540 }
541 
542 int
543 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
544 {
545 	return sock->net_impl->set_sendbuf(sock, sz);
546 }
547 
548 bool
549 spdk_sock_is_ipv6(struct spdk_sock *sock)
550 {
551 	return sock->net_impl->is_ipv6(sock);
552 }
553 
554 bool
555 spdk_sock_is_ipv4(struct spdk_sock *sock)
556 {
557 	return sock->net_impl->is_ipv4(sock);
558 }
559 
560 bool
561 spdk_sock_is_connected(struct spdk_sock *sock)
562 {
563 	return sock->net_impl->is_connected(sock);
564 }
565 
566 struct spdk_sock_group *
567 spdk_sock_group_create(void *ctx)
568 {
569 	struct spdk_net_impl *impl = NULL;
570 	struct spdk_sock_group *group;
571 	struct spdk_sock_group_impl *group_impl;
572 
573 	group = calloc(1, sizeof(*group));
574 	if (group == NULL) {
575 		return NULL;
576 	}
577 
578 	STAILQ_INIT(&group->group_impls);
579 
580 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
581 		group_impl = impl->group_impl_create();
582 		if (group_impl != NULL) {
583 			STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
584 			TAILQ_INIT(&group_impl->socks);
585 			group_impl->net_impl = impl;
586 			group_impl->group = group;
587 		}
588 	}
589 
590 	group->ctx = ctx;
591 
592 	return group;
593 }
594 
595 void *
596 spdk_sock_group_get_ctx(struct spdk_sock_group *group)
597 {
598 	if (group == NULL) {
599 		return NULL;
600 	}
601 
602 	return group->ctx;
603 }
604 
605 int
606 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
607 			 spdk_sock_cb cb_fn, void *cb_arg)
608 {
609 	struct spdk_sock_group_impl *group_impl = NULL;
610 	int rc;
611 
612 	if (cb_fn == NULL) {
613 		errno = EINVAL;
614 		return -1;
615 	}
616 
617 	if (sock->group_impl != NULL) {
618 		/*
619 		 * This sock is already part of a sock_group.
620 		 */
621 		errno = EINVAL;
622 		return -1;
623 	}
624 
625 	group_impl = sock_get_group_impl_from_group(sock, group);
626 	if (group_impl == NULL) {
627 		errno = EINVAL;
628 		return -1;
629 	}
630 
631 	rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
632 	if (rc != 0) {
633 		return rc;
634 	}
635 
636 	TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
637 	sock->group_impl = group_impl;
638 	sock->cb_fn = cb_fn;
639 	sock->cb_arg = cb_arg;
640 
641 	return 0;
642 }
643 
644 int
645 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
646 {
647 	struct spdk_sock_group_impl *group_impl = NULL;
648 	int rc;
649 
650 	group_impl = sock_get_group_impl_from_group(sock, group);
651 	if (group_impl == NULL) {
652 		errno = EINVAL;
653 		return -1;
654 	}
655 
656 	assert(group_impl == sock->group_impl);
657 
658 	rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
659 	if (rc == 0) {
660 		TAILQ_REMOVE(&group_impl->socks, sock, link);
661 		sock->group_impl = NULL;
662 		sock->cb_fn = NULL;
663 		sock->cb_arg = NULL;
664 	}
665 
666 	return rc;
667 }
668 
669 int
670 spdk_sock_group_poll(struct spdk_sock_group *group)
671 {
672 	return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
673 }
674 
675 static int
676 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
677 			   struct spdk_sock_group *group,
678 			   int max_events)
679 {
680 	struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
681 	int num_events, i;
682 
683 	if (TAILQ_EMPTY(&group_impl->socks)) {
684 		return 0;
685 	}
686 
687 	num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
688 	if (num_events == -1) {
689 		return -1;
690 	}
691 
692 	for (i = 0; i < num_events; i++) {
693 		struct spdk_sock *sock = socks[i];
694 		assert(sock->cb_fn != NULL);
695 		sock->cb_fn(sock->cb_arg, group, sock);
696 	}
697 
698 	return num_events;
699 }
700 
701 int
702 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
703 {
704 	struct spdk_sock_group_impl *group_impl = NULL;
705 	int rc, num_events = 0;
706 
707 	if (max_events < 1) {
708 		errno = -EINVAL;
709 		return -1;
710 	}
711 
712 	/*
713 	 * Only poll for up to 32 events at a time - if more events are pending,
714 	 *  the next call to this function will reap them.
715 	 */
716 	if (max_events > MAX_EVENTS_PER_POLL) {
717 		max_events = MAX_EVENTS_PER_POLL;
718 	}
719 
720 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
721 		rc = sock_group_impl_poll_count(group_impl, group, max_events);
722 		if (rc < 0) {
723 			num_events = -1;
724 			SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
725 				    group_impl->net_impl->name);
726 		} else if (num_events >= 0) {
727 			num_events += rc;
728 		}
729 	}
730 
731 	return num_events;
732 }
733 
734 int
735 spdk_sock_group_close(struct spdk_sock_group **group)
736 {
737 	struct spdk_sock_group_impl *group_impl = NULL, *tmp;
738 	int rc;
739 
740 	if (*group == NULL) {
741 		errno = EBADF;
742 		return -1;
743 	}
744 
745 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
746 		if (!TAILQ_EMPTY(&group_impl->socks)) {
747 			errno = EBUSY;
748 			return -1;
749 		}
750 	}
751 
752 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
753 		rc = group_impl->net_impl->group_impl_close(group_impl);
754 		if (rc != 0) {
755 			SPDK_ERRLOG("group_impl_close for net(%s) failed\n",
756 				    group_impl->net_impl->name);
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