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