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