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