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