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