xref: /spdk/lib/sock/sock.c (revision d9e3ffea488025798a892048c1c3211cbb5a42c6)
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 #include "spdk/env.h"
40 
41 #define SPDK_SOCK_DEFAULT_PRIORITY 0
42 #define SPDK_SOCK_DEFAULT_ZCOPY true
43 #define SPDK_SOCK_OPTS_FIELD_OK(opts, field) (offsetof(struct spdk_sock_opts, field) + sizeof(opts->field) <= (opts->opts_size))
44 
45 static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls);
46 static struct spdk_net_impl *g_default_impl;
47 
48 struct spdk_sock_placement_id_entry {
49 	int placement_id;
50 	uint32_t ref;
51 	struct spdk_sock_group *group;
52 	STAILQ_ENTRY(spdk_sock_placement_id_entry) link;
53 };
54 
55 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER(
56 			g_placement_id_map);
57 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER;
58 
59 /* Insert a group into the placement map.
60  * If the group is already in the map, take a reference.
61  */
62 static int
63 sock_map_insert(int placement_id, struct spdk_sock_group *group)
64 {
65 	struct spdk_sock_placement_id_entry *entry;
66 
67 	pthread_mutex_lock(&g_map_table_mutex);
68 	STAILQ_FOREACH(entry, &g_placement_id_map, link) {
69 		if (placement_id == entry->placement_id) {
70 			if (entry->group != group) {
71 				pthread_mutex_unlock(&g_map_table_mutex);
72 				return -EINVAL;
73 			}
74 			entry->ref++;
75 			pthread_mutex_unlock(&g_map_table_mutex);
76 			return 0;
77 		}
78 	}
79 
80 	entry = calloc(1, sizeof(*entry));
81 	if (!entry) {
82 		SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id);
83 		pthread_mutex_unlock(&g_map_table_mutex);
84 		return -ENOMEM;
85 	}
86 
87 	entry->placement_id = placement_id;
88 	entry->group = group;
89 	entry->ref++;
90 
91 	STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link);
92 	pthread_mutex_unlock(&g_map_table_mutex);
93 
94 	return 0;
95 }
96 
97 /* Release a reference to the group for a given placement_id */
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 = -1;
155 
156 	if (sock->placement_id == -1) {
157 		rc = sock->net_impl->get_placement_id(sock, &placement_id);
158 		if (!rc && (placement_id != -1)) {
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 = -1;
170 
171 	placement_id = sock_get_placement_id(sock);
172 	if (placement_id != -1) {
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 			/* Set the placement_id to -1 explicitly */
267 			sock->placement_id = -1;
268 			TAILQ_INIT(&sock->queued_reqs);
269 			TAILQ_INIT(&sock->pending_reqs);
270 			return sock;
271 		}
272 	}
273 
274 	return NULL;
275 }
276 
277 struct spdk_sock *
278 spdk_sock_listen(const char *ip, int port, char *impl_name)
279 {
280 	struct spdk_sock_opts opts;
281 
282 	opts.opts_size = sizeof(opts);
283 	spdk_sock_get_default_opts(&opts);
284 	return spdk_sock_listen_ext(ip, port, impl_name, &opts);
285 }
286 
287 struct spdk_sock *
288 spdk_sock_listen_ext(const char *ip, int port, char *_impl_name, struct spdk_sock_opts *opts)
289 {
290 	struct spdk_net_impl *impl = NULL;
291 	struct spdk_sock *sock;
292 	struct spdk_sock_opts opts_local;
293 	const char *impl_name = NULL;
294 
295 	if (opts == NULL) {
296 		SPDK_ERRLOG("the opts should not be NULL pointer\n");
297 		return NULL;
298 	}
299 
300 	if (_impl_name) {
301 		impl_name = _impl_name;
302 	} else if (g_default_impl) {
303 		impl_name = g_default_impl->name;
304 	}
305 
306 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
307 		if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
308 			continue;
309 		}
310 
311 		SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name);
312 		sock_init_opts(&opts_local, opts);
313 		sock = impl->listen(ip, port, &opts_local);
314 		if (sock != NULL) {
315 			/* Copy the contents, both the two structures are the same ABI version */
316 			memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
317 			sock->net_impl = impl;
318 			/* Don't need to initialize the request queues for listen
319 			 * sockets. */
320 			return sock;
321 		}
322 	}
323 
324 	return NULL;
325 }
326 
327 struct spdk_sock *
328 spdk_sock_accept(struct spdk_sock *sock)
329 {
330 	struct spdk_sock *new_sock;
331 
332 	new_sock = sock->net_impl->accept(sock);
333 	if (new_sock != NULL) {
334 		/* Inherit the opts from the "accept sock" */
335 		new_sock->opts = sock->opts;
336 		memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts));
337 		new_sock->net_impl = sock->net_impl;
338 		/* Set the placement_id to -1 explicitly */
339 		new_sock->placement_id = -1;
340 		TAILQ_INIT(&new_sock->queued_reqs);
341 		TAILQ_INIT(&new_sock->pending_reqs);
342 	}
343 
344 	return new_sock;
345 }
346 
347 int
348 spdk_sock_close(struct spdk_sock **_sock)
349 {
350 	struct spdk_sock *sock = *_sock;
351 	int rc;
352 
353 	if (sock == NULL) {
354 		errno = EBADF;
355 		return -1;
356 	}
357 
358 	if (sock->cb_fn != NULL) {
359 		/* This sock is still part of a sock_group. */
360 		errno = EBUSY;
361 		return -1;
362 	}
363 
364 	sock->flags.closed = true;
365 
366 	if (sock->cb_cnt > 0) {
367 		/* Let the callback unwind before destroying the socket */
368 		return 0;
369 	}
370 
371 	spdk_sock_abort_requests(sock);
372 
373 	rc = sock->net_impl->close(sock);
374 	if (rc == 0) {
375 		*_sock = NULL;
376 	}
377 
378 	return rc;
379 }
380 
381 ssize_t
382 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
383 {
384 	if (sock == NULL || sock->flags.closed) {
385 		errno = EBADF;
386 		return -1;
387 	}
388 
389 	return sock->net_impl->recv(sock, buf, len);
390 }
391 
392 ssize_t
393 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
394 {
395 	if (sock == NULL || sock->flags.closed) {
396 		errno = EBADF;
397 		return -1;
398 	}
399 
400 	return sock->net_impl->readv(sock, iov, iovcnt);
401 }
402 
403 ssize_t
404 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
405 {
406 	if (sock == NULL || sock->flags.closed) {
407 		errno = EBADF;
408 		return -1;
409 	}
410 
411 	return sock->net_impl->writev(sock, iov, iovcnt);
412 }
413 
414 void
415 spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req)
416 {
417 	assert(req->cb_fn != NULL);
418 
419 	if (sock == NULL || sock->flags.closed) {
420 		req->cb_fn(req->cb_arg, -EBADF);
421 		return;
422 	}
423 
424 	sock->net_impl->writev_async(sock, req);
425 }
426 
427 int
428 spdk_sock_flush(struct spdk_sock *sock)
429 {
430 	if (sock == NULL || sock->flags.closed) {
431 		return -EBADF;
432 	}
433 
434 	/* Sock is in a polling group, so group polling mechanism will work */
435 	if (sock->group_impl != NULL) {
436 		return 0;
437 	}
438 
439 	return sock->net_impl->flush(sock);
440 }
441 
442 int
443 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
444 {
445 	return sock->net_impl->set_recvlowat(sock, nbytes);
446 }
447 
448 int
449 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
450 {
451 	return sock->net_impl->set_recvbuf(sock, sz);
452 }
453 
454 int
455 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
456 {
457 	return sock->net_impl->set_sendbuf(sock, sz);
458 }
459 
460 bool
461 spdk_sock_is_ipv6(struct spdk_sock *sock)
462 {
463 	return sock->net_impl->is_ipv6(sock);
464 }
465 
466 bool
467 spdk_sock_is_ipv4(struct spdk_sock *sock)
468 {
469 	return sock->net_impl->is_ipv4(sock);
470 }
471 
472 bool
473 spdk_sock_is_connected(struct spdk_sock *sock)
474 {
475 	return sock->net_impl->is_connected(sock);
476 }
477 
478 struct spdk_sock_group *
479 spdk_sock_group_create(void *ctx)
480 {
481 	struct spdk_net_impl *impl = NULL;
482 	struct spdk_sock_group *group;
483 	struct spdk_sock_group_impl *group_impl;
484 	struct spdk_sock_impl_opts sock_opts = {};
485 	size_t sock_len;
486 	bool enable_incoming_cpu = false;
487 
488 	group = calloc(1, sizeof(*group));
489 	if (group == NULL) {
490 		return NULL;
491 	}
492 
493 	STAILQ_INIT(&group->group_impls);
494 
495 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
496 		group_impl = impl->group_impl_create();
497 		if (group_impl != NULL) {
498 			STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
499 			TAILQ_INIT(&group_impl->socks);
500 			group_impl->net_impl = impl;
501 
502 			sock_len = sizeof(sock_opts);
503 			spdk_sock_impl_get_opts(impl->name, &sock_opts, &sock_len);
504 			if (sock_opts.enable_placement_id == PLACEMENT_CPU) {
505 				enable_incoming_cpu = true;
506 			}
507 		}
508 	}
509 
510 	group->ctx = ctx;
511 
512 	/* if any net_impl is configured to use SO_INCOMING_CPU, initialize the sock map */
513 	if (enable_incoming_cpu) {
514 		sock_map_insert(spdk_env_get_current_core(), group);
515 	}
516 
517 	return group;
518 }
519 
520 void *
521 spdk_sock_group_get_ctx(struct spdk_sock_group *group)
522 {
523 	if (group == NULL) {
524 		return NULL;
525 	}
526 
527 	return group->ctx;
528 }
529 
530 int
531 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
532 			 spdk_sock_cb cb_fn, void *cb_arg)
533 {
534 	struct spdk_sock_group_impl *group_impl = NULL;
535 	int rc, placement_id = 0;
536 
537 	if (cb_fn == NULL) {
538 		errno = EINVAL;
539 		return -1;
540 	}
541 
542 	if (sock->group_impl != NULL) {
543 		/*
544 		 * This sock is already part of a sock_group.
545 		 */
546 		errno = EINVAL;
547 		return -1;
548 	}
549 
550 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
551 		if (sock->net_impl == group_impl->net_impl) {
552 			break;
553 		}
554 	}
555 
556 	if (group_impl == NULL) {
557 		errno = EINVAL;
558 		return -1;
559 	}
560 
561 	rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
562 	if (rc != 0) {
563 		return rc;
564 	}
565 
566 	TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
567 	sock->group_impl = group_impl;
568 	sock->cb_fn = cb_fn;
569 	sock->cb_arg = cb_arg;
570 
571 	placement_id = sock_get_placement_id(sock);
572 	if (placement_id != -1) {
573 		rc = sock_map_insert(placement_id, group);
574 		if (rc != 0) {
575 			SPDK_ERRLOG("Failed to insert sock group into map: %d", rc);
576 			/* Do not treat this as an error. The system will continue running. */
577 		}
578 	}
579 
580 	return 0;
581 }
582 
583 int
584 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
585 {
586 	struct spdk_sock_group_impl *group_impl = NULL;
587 	int rc, placement_id = 0;
588 
589 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
590 		if (sock->net_impl == group_impl->net_impl) {
591 			break;
592 		}
593 	}
594 
595 	if (group_impl == NULL) {
596 		errno = EINVAL;
597 		return -1;
598 	}
599 
600 	assert(group_impl == sock->group_impl);
601 
602 	placement_id = sock_get_placement_id(sock);
603 	if (placement_id != -1) {
604 		sock_map_release(placement_id);
605 	}
606 
607 	rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
608 	if (rc == 0) {
609 		TAILQ_REMOVE(&group_impl->socks, sock, link);
610 		sock->group_impl = NULL;
611 		sock->cb_fn = NULL;
612 		sock->cb_arg = NULL;
613 	}
614 
615 	return rc;
616 }
617 
618 int
619 spdk_sock_group_poll(struct spdk_sock_group *group)
620 {
621 	return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
622 }
623 
624 static int
625 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
626 			   struct spdk_sock_group *group,
627 			   int max_events)
628 {
629 	struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
630 	int num_events, i;
631 
632 	if (TAILQ_EMPTY(&group_impl->socks)) {
633 		return 0;
634 	}
635 
636 	num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
637 	if (num_events == -1) {
638 		return -1;
639 	}
640 
641 	for (i = 0; i < num_events; i++) {
642 		struct spdk_sock *sock = socks[i];
643 		assert(sock->cb_fn != NULL);
644 		sock->cb_fn(sock->cb_arg, group, sock);
645 	}
646 
647 	return num_events;
648 }
649 
650 int
651 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
652 {
653 	struct spdk_sock_group_impl *group_impl = NULL;
654 	int rc, num_events = 0;
655 
656 	if (max_events < 1) {
657 		errno = -EINVAL;
658 		return -1;
659 	}
660 
661 	/*
662 	 * Only poll for up to 32 events at a time - if more events are pending,
663 	 *  the next call to this function will reap them.
664 	 */
665 	if (max_events > MAX_EVENTS_PER_POLL) {
666 		max_events = MAX_EVENTS_PER_POLL;
667 	}
668 
669 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
670 		rc = sock_group_impl_poll_count(group_impl, group, max_events);
671 		if (rc < 0) {
672 			num_events = -1;
673 			SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
674 				    group_impl->net_impl->name);
675 		} else if (num_events >= 0) {
676 			num_events += rc;
677 		}
678 	}
679 
680 	return num_events;
681 }
682 
683 int
684 spdk_sock_group_close(struct spdk_sock_group **group)
685 {
686 	struct spdk_sock_group_impl *group_impl = NULL, *tmp;
687 	int rc;
688 	struct spdk_sock_impl_opts sock_opts = {};
689 	size_t sock_len;
690 	bool enable_incoming_cpu = false;
691 
692 	if (*group == NULL) {
693 		errno = EBADF;
694 		return -1;
695 	}
696 
697 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
698 		if (!TAILQ_EMPTY(&group_impl->socks)) {
699 			errno = EBUSY;
700 			return -1;
701 		}
702 	}
703 
704 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
705 		sock_len = sizeof(sock_opts);
706 		spdk_sock_impl_get_opts(group_impl->net_impl->name, &sock_opts, &sock_len);
707 		if (sock_opts.enable_placement_id == PLACEMENT_CPU) {
708 			enable_incoming_cpu = true;
709 			break;
710 		}
711 	}
712 
713 	if (enable_incoming_cpu) {
714 		sock_map_release(spdk_env_get_current_core());
715 	}
716 
717 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
718 		rc = group_impl->net_impl->group_impl_close(group_impl);
719 		if (rc != 0) {
720 			SPDK_ERRLOG("group_impl_close for net(%s) failed\n",
721 				    group_impl->net_impl->name);
722 		}
723 	}
724 
725 	sock_remove_sock_group_from_map_table(*group);
726 	free(*group);
727 	*group = NULL;
728 
729 	return 0;
730 }
731 
732 static inline struct spdk_net_impl *
733 sock_get_impl_by_name(const char *impl_name)
734 {
735 	struct spdk_net_impl *impl;
736 
737 	assert(impl_name != NULL);
738 	STAILQ_FOREACH(impl, &g_net_impls, link) {
739 		if (0 == strcmp(impl_name, impl->name)) {
740 			return impl;
741 		}
742 	}
743 
744 	return NULL;
745 }
746 
747 int
748 spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len)
749 {
750 	struct spdk_net_impl *impl;
751 
752 	if (!impl_name || !opts || !len) {
753 		errno = EINVAL;
754 		return -1;
755 	}
756 
757 	impl = sock_get_impl_by_name(impl_name);
758 	if (!impl) {
759 		errno = EINVAL;
760 		return -1;
761 	}
762 
763 	if (!impl->get_opts) {
764 		errno = ENOTSUP;
765 		return -1;
766 	}
767 
768 	return impl->get_opts(opts, len);
769 }
770 
771 int
772 spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len)
773 {
774 	struct spdk_net_impl *impl;
775 
776 	if (!impl_name || !opts) {
777 		errno = EINVAL;
778 		return -1;
779 	}
780 
781 	impl = sock_get_impl_by_name(impl_name);
782 	if (!impl) {
783 		errno = EINVAL;
784 		return -1;
785 	}
786 
787 	if (!impl->set_opts) {
788 		errno = ENOTSUP;
789 		return -1;
790 	}
791 
792 	return impl->set_opts(opts, len);
793 }
794 
795 void
796 spdk_sock_write_config_json(struct spdk_json_write_ctx *w)
797 {
798 	struct spdk_net_impl *impl;
799 	struct spdk_sock_impl_opts opts;
800 	size_t len;
801 
802 	assert(w != NULL);
803 
804 	spdk_json_write_array_begin(w);
805 
806 	if (g_default_impl) {
807 		spdk_json_write_object_begin(w);
808 		spdk_json_write_named_string(w, "method", "sock_set_default_impl");
809 		spdk_json_write_named_object_begin(w, "params");
810 		spdk_json_write_named_string(w, "impl_name", g_default_impl->name);
811 		spdk_json_write_object_end(w);
812 		spdk_json_write_object_end(w);
813 	}
814 
815 	STAILQ_FOREACH(impl, &g_net_impls, link) {
816 		if (!impl->get_opts) {
817 			continue;
818 		}
819 
820 		len = sizeof(opts);
821 		if (impl->get_opts(&opts, &len) == 0) {
822 			spdk_json_write_object_begin(w);
823 			spdk_json_write_named_string(w, "method", "sock_impl_set_options");
824 			spdk_json_write_named_object_begin(w, "params");
825 			spdk_json_write_named_string(w, "impl_name", impl->name);
826 			spdk_json_write_named_uint32(w, "recv_buf_size", opts.recv_buf_size);
827 			spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
828 			spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
829 			spdk_json_write_named_bool(w, "enable_zerocopy_send", opts.enable_zerocopy_send);
830 			spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack);
831 			spdk_json_write_named_uint32(w, "enable_placement_id", opts.enable_placement_id);
832 			spdk_json_write_object_end(w);
833 			spdk_json_write_object_end(w);
834 		} else {
835 			SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name);
836 		}
837 	}
838 
839 	spdk_json_write_array_end(w);
840 }
841 
842 void
843 spdk_net_impl_register(struct spdk_net_impl *impl, int priority)
844 {
845 	struct spdk_net_impl *cur, *prev;
846 
847 	impl->priority = priority;
848 	prev = NULL;
849 	STAILQ_FOREACH(cur, &g_net_impls, link) {
850 		if (impl->priority > cur->priority) {
851 			break;
852 		}
853 		prev = cur;
854 	}
855 
856 	if (prev) {
857 		STAILQ_INSERT_AFTER(&g_net_impls, prev, impl, link);
858 	} else {
859 		STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
860 	}
861 }
862 
863 int spdk_sock_set_default_impl(const char *impl_name)
864 {
865 	struct spdk_net_impl *impl;
866 
867 	if (!impl_name) {
868 		errno = EINVAL;
869 		return -1;
870 	}
871 
872 	impl = sock_get_impl_by_name(impl_name);
873 	if (!impl) {
874 		errno = EINVAL;
875 		return -1;
876 	}
877 
878 	if (impl == g_default_impl) {
879 		return 0;
880 	}
881 
882 	if (g_default_impl) {
883 		SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name,
884 			      impl->name);
885 	} else {
886 		SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name);
887 	}
888 
889 	g_default_impl = impl;
890 
891 	return 0;
892 }
893 
894 SPDK_LOG_REGISTER_COMPONENT(sock)
895