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