xref: /spdk/lib/sock/sock.c (revision 4e8e97c886e47e337dc470ac8c1ffa044d729af0)
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 	return sock->net_impl->flush(sock);
455 }
456 
457 int
458 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
459 {
460 	return sock->net_impl->set_recvlowat(sock, nbytes);
461 }
462 
463 int
464 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
465 {
466 	return sock->net_impl->set_recvbuf(sock, sz);
467 }
468 
469 int
470 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
471 {
472 	return sock->net_impl->set_sendbuf(sock, sz);
473 }
474 
475 bool
476 spdk_sock_is_ipv6(struct spdk_sock *sock)
477 {
478 	return sock->net_impl->is_ipv6(sock);
479 }
480 
481 bool
482 spdk_sock_is_ipv4(struct spdk_sock *sock)
483 {
484 	return sock->net_impl->is_ipv4(sock);
485 }
486 
487 bool
488 spdk_sock_is_connected(struct spdk_sock *sock)
489 {
490 	return sock->net_impl->is_connected(sock);
491 }
492 
493 struct spdk_sock_group *
494 spdk_sock_group_create(void *ctx)
495 {
496 	struct spdk_net_impl *impl = NULL;
497 	struct spdk_sock_group *group;
498 	struct spdk_sock_group_impl *group_impl;
499 
500 	group = calloc(1, sizeof(*group));
501 	if (group == NULL) {
502 		return NULL;
503 	}
504 
505 	STAILQ_INIT(&group->group_impls);
506 
507 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
508 		group_impl = impl->group_impl_create();
509 		if (group_impl != NULL) {
510 			STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
511 			TAILQ_INIT(&group_impl->socks);
512 			group_impl->num_removed_socks = 0;
513 			group_impl->net_impl = impl;
514 		}
515 	}
516 
517 	group->ctx = ctx;
518 	return group;
519 }
520 
521 void *
522 spdk_sock_group_get_ctx(struct spdk_sock_group *group)
523 {
524 	if (group == NULL) {
525 		return NULL;
526 	}
527 
528 	return group->ctx;
529 }
530 
531 int
532 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
533 			 spdk_sock_cb cb_fn, void *cb_arg)
534 {
535 	struct spdk_sock_group_impl *group_impl = NULL;
536 	int rc, placement_id = 0;
537 
538 	if (cb_fn == NULL) {
539 		errno = EINVAL;
540 		return -1;
541 	}
542 
543 	if (sock->group_impl != NULL) {
544 		/*
545 		 * This sock is already part of a sock_group.  Currently we don't
546 		 *  support this.
547 		 */
548 		errno = EBUSY;
549 		return -1;
550 	}
551 
552 	placement_id = sock_get_placement_id(sock);
553 	if (placement_id != 0) {
554 		rc = sock_map_insert(placement_id, group);
555 		if (rc < 0) {
556 			return -1;
557 		}
558 	}
559 
560 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
561 		if (sock->net_impl == group_impl->net_impl) {
562 			break;
563 		}
564 	}
565 
566 	if (group_impl == NULL) {
567 		errno = EINVAL;
568 		return -1;
569 	}
570 
571 	rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
572 	if (rc == 0) {
573 		TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
574 		sock->group_impl = group_impl;
575 		sock->cb_fn = cb_fn;
576 		sock->cb_arg = cb_arg;
577 	}
578 
579 	return rc;
580 }
581 
582 int
583 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
584 {
585 	struct spdk_sock_group_impl *group_impl = NULL;
586 	int rc, placement_id = 0;
587 
588 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
589 		if (sock->net_impl == group_impl->net_impl) {
590 			break;
591 		}
592 	}
593 
594 	if (group_impl == NULL) {
595 		errno = EINVAL;
596 		return -1;
597 	}
598 
599 	assert(group_impl == sock->group_impl);
600 
601 	placement_id = sock_get_placement_id(sock);
602 	if (placement_id != 0) {
603 		sock_map_release(placement_id);
604 	}
605 
606 	rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
607 	if (rc == 0) {
608 		TAILQ_REMOVE(&group_impl->socks, sock, link);
609 		assert(group_impl->num_removed_socks < MAX_EVENTS_PER_POLL);
610 		group_impl->removed_socks[group_impl->num_removed_socks] = (uintptr_t)sock;
611 		group_impl->num_removed_socks++;
612 		sock->group_impl = NULL;
613 		sock->cb_fn = NULL;
614 		sock->cb_arg = NULL;
615 	}
616 
617 	return rc;
618 }
619 
620 int
621 spdk_sock_group_poll(struct spdk_sock_group *group)
622 {
623 	return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
624 }
625 
626 static int
627 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
628 			   struct spdk_sock_group *group,
629 			   int max_events)
630 {
631 	struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
632 	int num_events, i;
633 
634 	if (TAILQ_EMPTY(&group_impl->socks)) {
635 		return 0;
636 	}
637 
638 	/* The number of removed sockets should be reset for each call to poll. */
639 	group_impl->num_removed_socks = 0;
640 
641 	num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
642 	if (num_events == -1) {
643 		return -1;
644 	}
645 
646 	for (i = 0; i < num_events; i++) {
647 		struct spdk_sock *sock = socks[i];
648 		int j;
649 		bool valid = true;
650 		for (j = 0; j < group_impl->num_removed_socks; j++) {
651 			if ((uintptr_t)sock == group_impl->removed_socks[j]) {
652 				valid = false;
653 				break;
654 			}
655 		}
656 
657 		if (valid) {
658 			assert(sock->cb_fn != NULL);
659 			sock->cb_fn(sock->cb_arg, group, sock);
660 		}
661 	}
662 
663 	return num_events;
664 }
665 
666 int
667 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
668 {
669 	struct spdk_sock_group_impl *group_impl = NULL;
670 	int rc, num_events = 0;
671 
672 	if (max_events < 1) {
673 		errno = -EINVAL;
674 		return -1;
675 	}
676 
677 	/*
678 	 * Only poll for up to 32 events at a time - if more events are pending,
679 	 *  the next call to this function will reap them.
680 	 */
681 	if (max_events > MAX_EVENTS_PER_POLL) {
682 		max_events = MAX_EVENTS_PER_POLL;
683 	}
684 
685 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
686 		rc = sock_group_impl_poll_count(group_impl, group, max_events);
687 		if (rc < 0) {
688 			num_events = -1;
689 			SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
690 				    group_impl->net_impl->name);
691 		} else if (num_events >= 0) {
692 			num_events += rc;
693 		}
694 	}
695 
696 	return num_events;
697 }
698 
699 int
700 spdk_sock_group_close(struct spdk_sock_group **group)
701 {
702 	struct spdk_sock_group_impl *group_impl = NULL, *tmp;
703 	int rc;
704 
705 	if (*group == NULL) {
706 		errno = EBADF;
707 		return -1;
708 	}
709 
710 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
711 		if (!TAILQ_EMPTY(&group_impl->socks)) {
712 			errno = EBUSY;
713 			return -1;
714 		}
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_object_end(w);
831 			spdk_json_write_object_end(w);
832 		} else {
833 			SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name);
834 		}
835 	}
836 
837 	spdk_json_write_array_end(w);
838 }
839 
840 void
841 spdk_net_impl_register(struct spdk_net_impl *impl, int priority)
842 {
843 	struct spdk_net_impl *cur, *prev;
844 
845 	impl->priority = priority;
846 	prev = NULL;
847 	STAILQ_FOREACH(cur, &g_net_impls, link) {
848 		if (impl->priority > cur->priority) {
849 			break;
850 		}
851 		prev = cur;
852 	}
853 
854 	if (prev) {
855 		STAILQ_INSERT_AFTER(&g_net_impls, prev, impl, link);
856 	} else {
857 		STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
858 	}
859 }
860 
861 int spdk_sock_set_default_impl(const char *impl_name)
862 {
863 	struct spdk_net_impl *impl;
864 
865 	if (!impl_name) {
866 		errno = EINVAL;
867 		return -1;
868 	}
869 
870 	impl = sock_get_impl_by_name(impl_name);
871 	if (!impl) {
872 		errno = EINVAL;
873 		return -1;
874 	}
875 
876 	if (impl == g_default_impl) {
877 		return 0;
878 	}
879 
880 	if (g_default_impl) {
881 		SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name,
882 			      impl->name);
883 	} else {
884 		SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name);
885 	}
886 
887 	g_default_impl = impl;
888 
889 	return 0;
890 }
891 
892 SPDK_LOG_REGISTER_COMPONENT(sock)
893