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