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