xref: /spdk/lib/sock/sock.c (revision 7521dc6f4b7ea46945f4add1aabf3f320c81ad5a)
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 #include "spdk/trace.h"
15 #include "spdk_internal/trace_defs.h"
16 
17 #define SPDK_SOCK_DEFAULT_PRIORITY 0
18 #define SPDK_SOCK_DEFAULT_ZCOPY true
19 #define SPDK_SOCK_DEFAULT_ACK_TIMEOUT 0
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 const char *
235 spdk_sock_get_impl_name(struct spdk_sock *sock)
236 {
237 	return sock->net_impl->name;
238 }
239 
240 void
241 spdk_sock_get_default_opts(struct spdk_sock_opts *opts)
242 {
243 	assert(opts);
244 
245 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
246 		opts->priority = SPDK_SOCK_DEFAULT_PRIORITY;
247 	}
248 
249 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
250 		opts->zcopy = SPDK_SOCK_DEFAULT_ZCOPY;
251 	}
252 
253 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
254 		opts->ack_timeout = SPDK_SOCK_DEFAULT_ACK_TIMEOUT;
255 	}
256 
257 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
258 		opts->impl_opts = NULL;
259 	}
260 
261 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts_size)) {
262 		opts->impl_opts_size = 0;
263 	}
264 }
265 
266 /*
267  * opts The opts allocated in the current library.
268  * opts_user The opts passed by the caller.
269  * */
270 static void
271 sock_init_opts(struct spdk_sock_opts *opts, struct spdk_sock_opts *opts_user)
272 {
273 	assert(opts);
274 	assert(opts_user);
275 
276 	opts->opts_size = sizeof(*opts);
277 	spdk_sock_get_default_opts(opts);
278 
279 	/* reset the size according to the user */
280 	opts->opts_size = opts_user->opts_size;
281 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, priority)) {
282 		opts->priority = opts_user->priority;
283 	}
284 
285 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, zcopy)) {
286 		opts->zcopy = opts_user->zcopy;
287 	}
288 
289 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, ack_timeout)) {
290 		opts->ack_timeout = opts_user->ack_timeout;
291 	}
292 
293 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
294 		opts->impl_opts = opts_user->impl_opts;
295 	}
296 
297 	if (SPDK_SOCK_OPTS_FIELD_OK(opts, impl_opts)) {
298 		opts->impl_opts_size = opts_user->impl_opts_size;
299 	}
300 }
301 
302 struct spdk_sock *
303 spdk_sock_connect(const char *ip, int port, const char *impl_name)
304 {
305 	struct spdk_sock_opts opts;
306 
307 	opts.opts_size = sizeof(opts);
308 	spdk_sock_get_default_opts(&opts);
309 	return spdk_sock_connect_ext(ip, port, impl_name, &opts);
310 }
311 
312 struct spdk_sock *
313 spdk_sock_connect_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
314 {
315 	struct spdk_net_impl *impl = NULL;
316 	struct spdk_sock *sock;
317 	struct spdk_sock_opts opts_local;
318 	const char *impl_name = NULL;
319 
320 	if (opts == NULL) {
321 		SPDK_ERRLOG("the opts should not be NULL pointer\n");
322 		return NULL;
323 	}
324 
325 	if (_impl_name) {
326 		impl_name = _impl_name;
327 	} else if (g_default_impl) {
328 		impl_name = g_default_impl->name;
329 	}
330 
331 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
332 		if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
333 			continue;
334 		}
335 
336 		SPDK_DEBUGLOG(sock, "Creating a client socket using impl %s\n", impl->name);
337 		sock_init_opts(&opts_local, opts);
338 		sock = impl->connect(ip, port, &opts_local);
339 		if (sock != NULL) {
340 			/* Copy the contents, both the two structures are the same ABI version */
341 			memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
342 			/* Clear out impl_opts to make sure we don't keep reference to a dangling
343 			 * pointer */
344 			sock->opts.impl_opts = NULL;
345 			sock->net_impl = impl;
346 			TAILQ_INIT(&sock->queued_reqs);
347 			TAILQ_INIT(&sock->pending_reqs);
348 
349 			return sock;
350 		}
351 	}
352 
353 	return NULL;
354 }
355 
356 struct spdk_sock *
357 spdk_sock_listen(const char *ip, int port, const char *impl_name)
358 {
359 	struct spdk_sock_opts opts;
360 
361 	opts.opts_size = sizeof(opts);
362 	spdk_sock_get_default_opts(&opts);
363 	return spdk_sock_listen_ext(ip, port, impl_name, &opts);
364 }
365 
366 struct spdk_sock *
367 spdk_sock_listen_ext(const char *ip, int port, const char *_impl_name, struct spdk_sock_opts *opts)
368 {
369 	struct spdk_net_impl *impl = NULL;
370 	struct spdk_sock *sock;
371 	struct spdk_sock_opts opts_local;
372 	const char *impl_name = NULL;
373 
374 	if (opts == NULL) {
375 		SPDK_ERRLOG("the opts should not be NULL pointer\n");
376 		return NULL;
377 	}
378 
379 	if (_impl_name) {
380 		impl_name = _impl_name;
381 	} else if (g_default_impl) {
382 		impl_name = g_default_impl->name;
383 	}
384 
385 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
386 		if (impl_name && strncmp(impl_name, impl->name, strlen(impl->name) + 1)) {
387 			continue;
388 		}
389 
390 		SPDK_DEBUGLOG(sock, "Creating a listening socket using impl %s\n", impl->name);
391 		sock_init_opts(&opts_local, opts);
392 		sock = impl->listen(ip, port, &opts_local);
393 		if (sock != NULL) {
394 			/* Copy the contents, both the two structures are the same ABI version */
395 			memcpy(&sock->opts, &opts_local, sizeof(sock->opts));
396 			/* Clear out impl_opts to make sure we don't keep reference to a dangling
397 			 * pointer */
398 			sock->opts.impl_opts = NULL;
399 			sock->net_impl = impl;
400 			/* Don't need to initialize the request queues for listen
401 			 * sockets. */
402 			return sock;
403 		}
404 	}
405 
406 	return NULL;
407 }
408 
409 struct spdk_sock *
410 spdk_sock_accept(struct spdk_sock *sock)
411 {
412 	struct spdk_sock *new_sock;
413 
414 	new_sock = sock->net_impl->accept(sock);
415 	if (new_sock != NULL) {
416 		/* Inherit the opts from the "accept sock" */
417 		new_sock->opts = sock->opts;
418 		memcpy(&new_sock->opts, &sock->opts, sizeof(new_sock->opts));
419 		new_sock->net_impl = sock->net_impl;
420 		TAILQ_INIT(&new_sock->queued_reqs);
421 		TAILQ_INIT(&new_sock->pending_reqs);
422 	}
423 
424 	return new_sock;
425 }
426 
427 int
428 spdk_sock_close(struct spdk_sock **_sock)
429 {
430 	struct spdk_sock *sock = *_sock;
431 
432 	if (sock == NULL) {
433 		errno = EBADF;
434 		return -1;
435 	}
436 
437 	if (sock->cb_fn != NULL) {
438 		/* This sock is still part of a sock_group. */
439 		errno = EBUSY;
440 		return -1;
441 	}
442 
443 	/* Beyond this point the socket is considered closed. */
444 	*_sock = NULL;
445 
446 	sock->flags.closed = true;
447 
448 	if (sock->cb_cnt > 0) {
449 		/* Let the callback unwind before destroying the socket */
450 		return 0;
451 	}
452 
453 	spdk_sock_abort_requests(sock);
454 
455 	return sock->net_impl->close(sock);
456 }
457 
458 ssize_t
459 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
460 {
461 	if (sock == NULL || sock->flags.closed) {
462 		errno = EBADF;
463 		return -1;
464 	}
465 
466 	return sock->net_impl->recv(sock, buf, len);
467 }
468 
469 ssize_t
470 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
471 {
472 	if (sock == NULL || sock->flags.closed) {
473 		errno = EBADF;
474 		return -1;
475 	}
476 
477 	return sock->net_impl->readv(sock, iov, iovcnt);
478 }
479 
480 ssize_t
481 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt)
482 {
483 	if (sock == NULL || sock->flags.closed) {
484 		errno = EBADF;
485 		return -1;
486 	}
487 
488 	return sock->net_impl->writev(sock, iov, iovcnt);
489 }
490 
491 void
492 spdk_sock_writev_async(struct spdk_sock *sock, struct spdk_sock_request *req)
493 {
494 	assert(req->cb_fn != NULL);
495 
496 	if (sock == NULL || sock->flags.closed) {
497 		req->cb_fn(req->cb_arg, -EBADF);
498 		return;
499 	}
500 
501 	sock->net_impl->writev_async(sock, req);
502 }
503 
504 int
505 spdk_sock_recv_next(struct spdk_sock *sock, void **buf, void **ctx)
506 {
507 	if (sock == NULL || sock->flags.closed) {
508 		errno = EBADF;
509 		return -1;
510 	}
511 
512 	if (sock->group_impl == NULL) {
513 		errno = ENOTSUP;
514 		return -1;
515 	}
516 
517 	return sock->net_impl->recv_next(sock, buf, ctx);
518 }
519 
520 int
521 spdk_sock_flush(struct spdk_sock *sock)
522 {
523 	if (sock == NULL || sock->flags.closed) {
524 		errno = EBADF;
525 		return -1;
526 	}
527 
528 	return sock->net_impl->flush(sock);
529 }
530 
531 int
532 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes)
533 {
534 	return sock->net_impl->set_recvlowat(sock, nbytes);
535 }
536 
537 int
538 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz)
539 {
540 	return sock->net_impl->set_recvbuf(sock, sz);
541 }
542 
543 int
544 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz)
545 {
546 	return sock->net_impl->set_sendbuf(sock, sz);
547 }
548 
549 bool
550 spdk_sock_is_ipv6(struct spdk_sock *sock)
551 {
552 	return sock->net_impl->is_ipv6(sock);
553 }
554 
555 bool
556 spdk_sock_is_ipv4(struct spdk_sock *sock)
557 {
558 	return sock->net_impl->is_ipv4(sock);
559 }
560 
561 bool
562 spdk_sock_is_connected(struct spdk_sock *sock)
563 {
564 	return sock->net_impl->is_connected(sock);
565 }
566 
567 struct spdk_sock_group *
568 spdk_sock_group_create(void *ctx)
569 {
570 	struct spdk_net_impl *impl = NULL;
571 	struct spdk_sock_group *group;
572 	struct spdk_sock_group_impl *group_impl;
573 
574 	group = calloc(1, sizeof(*group));
575 	if (group == NULL) {
576 		return NULL;
577 	}
578 
579 	STAILQ_INIT(&group->group_impls);
580 	STAILQ_INIT(&group->pool);
581 
582 	STAILQ_FOREACH_FROM(impl, &g_net_impls, link) {
583 		group_impl = impl->group_impl_create();
584 		if (group_impl != NULL) {
585 			STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link);
586 			TAILQ_INIT(&group_impl->socks);
587 			group_impl->net_impl = impl;
588 			group_impl->group = group;
589 		}
590 	}
591 
592 	group->ctx = ctx;
593 
594 	return group;
595 }
596 
597 void *
598 spdk_sock_group_get_ctx(struct spdk_sock_group *group)
599 {
600 	if (group == NULL) {
601 		return NULL;
602 	}
603 
604 	return group->ctx;
605 }
606 
607 int
608 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock,
609 			 spdk_sock_cb cb_fn, void *cb_arg)
610 {
611 	struct spdk_sock_group_impl *group_impl = NULL;
612 	int rc;
613 
614 	if (cb_fn == NULL) {
615 		errno = EINVAL;
616 		return -1;
617 	}
618 
619 	if (sock->group_impl != NULL) {
620 		/*
621 		 * This sock is already part of a sock_group.
622 		 */
623 		errno = EINVAL;
624 		return -1;
625 	}
626 
627 	group_impl = sock_get_group_impl_from_group(sock, group);
628 	if (group_impl == NULL) {
629 		errno = EINVAL;
630 		return -1;
631 	}
632 
633 	rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock);
634 	if (rc != 0) {
635 		return rc;
636 	}
637 
638 	TAILQ_INSERT_TAIL(&group_impl->socks, sock, link);
639 	sock->group_impl = group_impl;
640 	sock->cb_fn = cb_fn;
641 	sock->cb_arg = cb_arg;
642 
643 	return 0;
644 }
645 
646 int
647 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock)
648 {
649 	struct spdk_sock_group_impl *group_impl = NULL;
650 	int rc;
651 
652 	group_impl = sock_get_group_impl_from_group(sock, group);
653 	if (group_impl == NULL) {
654 		errno = EINVAL;
655 		return -1;
656 	}
657 
658 	assert(group_impl == sock->group_impl);
659 
660 	rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock);
661 	if (rc == 0) {
662 		TAILQ_REMOVE(&group_impl->socks, sock, link);
663 		sock->group_impl = NULL;
664 		sock->cb_fn = NULL;
665 		sock->cb_arg = NULL;
666 	}
667 
668 	return rc;
669 }
670 
671 int
672 spdk_sock_group_provide_buf(struct spdk_sock_group *group, void *buf, size_t len, void *ctx)
673 {
674 	struct spdk_sock_group_provided_buf *provided;
675 
676 	provided = (struct spdk_sock_group_provided_buf *)buf;
677 
678 	provided->len = len;
679 	provided->ctx = ctx;
680 	STAILQ_INSERT_HEAD(&group->pool, provided, link);
681 
682 	return 0;
683 }
684 
685 size_t
686 spdk_sock_group_get_buf(struct spdk_sock_group *group, void **buf, void **ctx)
687 {
688 	struct spdk_sock_group_provided_buf *provided;
689 
690 	provided = STAILQ_FIRST(&group->pool);
691 	if (provided == NULL) {
692 		*buf = NULL;
693 		return 0;
694 	}
695 	STAILQ_REMOVE_HEAD(&group->pool, link);
696 
697 	*buf = provided;
698 	*ctx = provided->ctx;
699 	return provided->len;
700 }
701 
702 int
703 spdk_sock_group_poll(struct spdk_sock_group *group)
704 {
705 	return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL);
706 }
707 
708 static int
709 sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl,
710 			   struct spdk_sock_group *group,
711 			   int max_events)
712 {
713 	struct spdk_sock *socks[MAX_EVENTS_PER_POLL];
714 	int num_events, i;
715 
716 	if (TAILQ_EMPTY(&group_impl->socks)) {
717 		return 0;
718 	}
719 
720 	num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks);
721 	if (num_events == -1) {
722 		return -1;
723 	}
724 
725 	for (i = 0; i < num_events; i++) {
726 		struct spdk_sock *sock = socks[i];
727 		assert(sock->cb_fn != NULL);
728 		sock->cb_fn(sock->cb_arg, group, sock);
729 	}
730 
731 	return num_events;
732 }
733 
734 int
735 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events)
736 {
737 	struct spdk_sock_group_impl *group_impl = NULL;
738 	int rc, num_events = 0;
739 
740 	if (max_events < 1) {
741 		errno = -EINVAL;
742 		return -1;
743 	}
744 
745 	/*
746 	 * Only poll for up to 32 events at a time - if more events are pending,
747 	 *  the next call to this function will reap them.
748 	 */
749 	if (max_events > MAX_EVENTS_PER_POLL) {
750 		max_events = MAX_EVENTS_PER_POLL;
751 	}
752 
753 	STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) {
754 		rc = sock_group_impl_poll_count(group_impl, group, max_events);
755 		if (rc < 0) {
756 			num_events = -1;
757 			SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n",
758 				    group_impl->net_impl->name);
759 		} else if (num_events >= 0) {
760 			num_events += rc;
761 		}
762 	}
763 
764 	return num_events;
765 }
766 
767 int
768 spdk_sock_group_close(struct spdk_sock_group **group)
769 {
770 	struct spdk_sock_group_impl *group_impl = NULL, *tmp;
771 	int rc;
772 
773 	if (*group == NULL) {
774 		errno = EBADF;
775 		return -1;
776 	}
777 
778 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
779 		if (!TAILQ_EMPTY(&group_impl->socks)) {
780 			errno = EBUSY;
781 			return -1;
782 		}
783 	}
784 
785 	STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) {
786 		rc = group_impl->net_impl->group_impl_close(group_impl);
787 		if (rc != 0) {
788 			SPDK_ERRLOG("group_impl_close for net failed\n");
789 		}
790 	}
791 
792 	free(*group);
793 	*group = NULL;
794 
795 	return 0;
796 }
797 
798 static inline struct spdk_net_impl *
799 sock_get_impl_by_name(const char *impl_name)
800 {
801 	struct spdk_net_impl *impl;
802 
803 	assert(impl_name != NULL);
804 	STAILQ_FOREACH(impl, &g_net_impls, link) {
805 		if (0 == strcmp(impl_name, impl->name)) {
806 			return impl;
807 		}
808 	}
809 
810 	return NULL;
811 }
812 
813 int
814 spdk_sock_impl_get_opts(const char *impl_name, struct spdk_sock_impl_opts *opts, size_t *len)
815 {
816 	struct spdk_net_impl *impl;
817 
818 	if (!impl_name || !opts || !len) {
819 		errno = EINVAL;
820 		return -1;
821 	}
822 
823 	impl = sock_get_impl_by_name(impl_name);
824 	if (!impl) {
825 		errno = EINVAL;
826 		return -1;
827 	}
828 
829 	if (!impl->get_opts) {
830 		errno = ENOTSUP;
831 		return -1;
832 	}
833 
834 	return impl->get_opts(opts, len);
835 }
836 
837 int
838 spdk_sock_impl_set_opts(const char *impl_name, const struct spdk_sock_impl_opts *opts, size_t len)
839 {
840 	struct spdk_net_impl *impl;
841 
842 	if (!impl_name || !opts) {
843 		errno = EINVAL;
844 		return -1;
845 	}
846 
847 	impl = sock_get_impl_by_name(impl_name);
848 	if (!impl) {
849 		errno = EINVAL;
850 		return -1;
851 	}
852 
853 	if (!impl->set_opts) {
854 		errno = ENOTSUP;
855 		return -1;
856 	}
857 
858 	return impl->set_opts(opts, len);
859 }
860 
861 void
862 spdk_sock_write_config_json(struct spdk_json_write_ctx *w)
863 {
864 	struct spdk_net_impl *impl;
865 	struct spdk_sock_impl_opts opts;
866 	size_t len;
867 
868 	assert(w != NULL);
869 
870 	spdk_json_write_array_begin(w);
871 
872 	if (g_default_impl) {
873 		spdk_json_write_object_begin(w);
874 		spdk_json_write_named_string(w, "method", "sock_set_default_impl");
875 		spdk_json_write_named_object_begin(w, "params");
876 		spdk_json_write_named_string(w, "impl_name", g_default_impl->name);
877 		spdk_json_write_object_end(w);
878 		spdk_json_write_object_end(w);
879 	}
880 
881 	STAILQ_FOREACH(impl, &g_net_impls, link) {
882 		if (!impl->get_opts) {
883 			continue;
884 		}
885 
886 		len = sizeof(opts);
887 		if (impl->get_opts(&opts, &len) == 0) {
888 			spdk_json_write_object_begin(w);
889 			spdk_json_write_named_string(w, "method", "sock_impl_set_options");
890 			spdk_json_write_named_object_begin(w, "params");
891 			spdk_json_write_named_string(w, "impl_name", impl->name);
892 			spdk_json_write_named_uint32(w, "recv_buf_size", opts.recv_buf_size);
893 			spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
894 			spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
895 			spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack);
896 			spdk_json_write_named_uint32(w, "enable_placement_id", opts.enable_placement_id);
897 			spdk_json_write_named_bool(w, "enable_zerocopy_send_server", opts.enable_zerocopy_send_server);
898 			spdk_json_write_named_bool(w, "enable_zerocopy_send_client", opts.enable_zerocopy_send_client);
899 			spdk_json_write_named_uint32(w, "zerocopy_threshold", opts.zerocopy_threshold);
900 			spdk_json_write_named_uint32(w, "tls_version", opts.tls_version);
901 			spdk_json_write_named_bool(w, "enable_ktls", opts.enable_ktls);
902 			spdk_json_write_object_end(w);
903 			spdk_json_write_object_end(w);
904 		} else {
905 			SPDK_ERRLOG("Failed to get socket options for socket implementation %s\n", impl->name);
906 		}
907 	}
908 
909 	spdk_json_write_array_end(w);
910 }
911 
912 void
913 spdk_net_impl_register(struct spdk_net_impl *impl)
914 {
915 	STAILQ_INSERT_HEAD(&g_net_impls, impl, link);
916 }
917 
918 int
919 spdk_sock_set_default_impl(const char *impl_name)
920 {
921 	struct spdk_net_impl *impl;
922 
923 	if (!impl_name) {
924 		errno = EINVAL;
925 		return -1;
926 	}
927 
928 	impl = sock_get_impl_by_name(impl_name);
929 	if (!impl) {
930 		errno = EINVAL;
931 		return -1;
932 	}
933 
934 	if (impl == g_default_impl) {
935 		return 0;
936 	}
937 
938 	if (g_default_impl) {
939 		SPDK_DEBUGLOG(sock, "Change the default sock impl from %s to %s\n", g_default_impl->name,
940 			      impl->name);
941 	} else {
942 		SPDK_DEBUGLOG(sock, "Set default sock implementation to %s\n", impl_name);
943 	}
944 
945 	g_default_impl = impl;
946 
947 	return 0;
948 }
949 
950 const char *
951 spdk_sock_get_default_impl(void)
952 {
953 	if (g_default_impl) {
954 		return g_default_impl->name;
955 	}
956 
957 	return NULL;
958 }
959 
960 SPDK_LOG_REGISTER_COMPONENT(sock)
961 
962 SPDK_TRACE_REGISTER_FN(sock_trace, "sock", TRACE_GROUP_SOCK)
963 {
964 	struct spdk_trace_tpoint_opts opts[] = {
965 		{
966 			"SOCK_REQ_QUEUE", TRACE_SOCK_REQ_QUEUE,
967 			OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 1,
968 			{
969 				{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
970 			}
971 		},
972 		{
973 			"SOCK_REQ_PEND", TRACE_SOCK_REQ_PEND,
974 			OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
975 			{
976 				{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
977 			}
978 		},
979 		{
980 			"SOCK_REQ_COMPLETE", TRACE_SOCK_REQ_COMPLETE,
981 			OWNER_TYPE_SOCK, OBJECT_SOCK_REQ, 0,
982 			{
983 				{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 },
984 			}
985 		},
986 	};
987 
988 	spdk_trace_register_owner_type(OWNER_TYPE_SOCK, 's');
989 	spdk_trace_register_object(OBJECT_SOCK_REQ, 's');
990 	spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
991 }
992