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