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