]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/sock/posix/posix.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / lib / sock / posix / posix.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/stdinc.h"
35
36 #if defined(__linux__)
37 #include <sys/epoll.h>
38 #elif defined(__FreeBSD__)
39 #include <sys/event.h>
40 #endif
41
42 #include "spdk/log.h"
43 #include "spdk/sock.h"
44 #include "spdk_internal/sock.h"
45
46 #define MAX_TMPBUF 1024
47 #define PORTNUMLEN 32
48
49 struct spdk_posix_sock {
50 struct spdk_sock base;
51 int fd;
52 };
53
54 struct spdk_posix_sock_group_impl {
55 struct spdk_sock_group_impl base;
56 int fd;
57 };
58
59 static int
60 get_addr_str(struct sockaddr *sa, char *host, size_t hlen)
61 {
62 const char *result = NULL;
63
64 if (sa == NULL || host == NULL) {
65 return -1;
66 }
67
68 switch (sa->sa_family) {
69 case AF_INET:
70 result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
71 host, hlen);
72 break;
73 case AF_INET6:
74 result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
75 host, hlen);
76 break;
77 default:
78 break;
79 }
80
81 if (result != NULL) {
82 return 0;
83 } else {
84 return -1;
85 }
86 }
87
88 #define __posix_sock(sock) (struct spdk_posix_sock *)sock
89 #define __posix_group_impl(group) (struct spdk_posix_sock_group_impl *)group
90
91 static int
92 spdk_posix_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport,
93 char *caddr, int clen, uint16_t *cport)
94 {
95 struct spdk_posix_sock *sock = __posix_sock(_sock);
96 struct sockaddr_storage sa;
97 socklen_t salen;
98 int rc;
99
100 assert(sock != NULL);
101
102 memset(&sa, 0, sizeof sa);
103 salen = sizeof sa;
104 rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
105 if (rc != 0) {
106 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
107 return -1;
108 }
109
110 switch (sa.ss_family) {
111 case AF_UNIX:
112 /* Acceptable connection types that don't have IPs */
113 return 0;
114 case AF_INET:
115 case AF_INET6:
116 /* Code below will get IP addresses */
117 break;
118 default:
119 /* Unsupported socket family */
120 return -1;
121 }
122
123 rc = get_addr_str((struct sockaddr *)&sa, saddr, slen);
124 if (rc != 0) {
125 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
126 return -1;
127 }
128
129 if (sport) {
130 if (sa.ss_family == AF_INET) {
131 *sport = ntohs(((struct sockaddr_in *) &sa)->sin_port);
132 } else if (sa.ss_family == AF_INET6) {
133 *sport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port);
134 }
135 }
136
137 memset(&sa, 0, sizeof sa);
138 salen = sizeof sa;
139 rc = getpeername(sock->fd, (struct sockaddr *) &sa, &salen);
140 if (rc != 0) {
141 SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
142 return -1;
143 }
144
145 rc = get_addr_str((struct sockaddr *)&sa, caddr, clen);
146 if (rc != 0) {
147 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
148 return -1;
149 }
150
151 if (cport) {
152 if (sa.ss_family == AF_INET) {
153 *cport = ntohs(((struct sockaddr_in *) &sa)->sin_port);
154 } else if (sa.ss_family == AF_INET6) {
155 *cport = ntohs(((struct sockaddr_in6 *) &sa)->sin6_port);
156 }
157 }
158
159 return 0;
160 }
161
162 enum spdk_posix_sock_create_type {
163 SPDK_SOCK_CREATE_LISTEN,
164 SPDK_SOCK_CREATE_CONNECT,
165 };
166
167 static struct spdk_sock *
168 spdk_posix_sock_create(const char *ip, int port, enum spdk_posix_sock_create_type type)
169 {
170 struct spdk_posix_sock *sock;
171 char buf[MAX_TMPBUF];
172 char portnum[PORTNUMLEN];
173 char *p;
174 struct addrinfo hints, *res, *res0;
175 int fd, flag;
176 int val = 1;
177 int rc;
178
179 if (ip == NULL) {
180 return NULL;
181 }
182 if (ip[0] == '[') {
183 snprintf(buf, sizeof(buf), "%s", ip + 1);
184 p = strchr(buf, ']');
185 if (p != NULL) {
186 *p = '\0';
187 }
188 ip = (const char *) &buf[0];
189 }
190
191 snprintf(portnum, sizeof portnum, "%d", port);
192 memset(&hints, 0, sizeof hints);
193 hints.ai_family = PF_UNSPEC;
194 hints.ai_socktype = SOCK_STREAM;
195 hints.ai_flags = AI_NUMERICSERV;
196 hints.ai_flags |= AI_PASSIVE;
197 hints.ai_flags |= AI_NUMERICHOST;
198 rc = getaddrinfo(ip, portnum, &hints, &res0);
199 if (rc != 0) {
200 SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
201 return NULL;
202 }
203
204 /* try listen */
205 fd = -1;
206 for (res = res0; res != NULL; res = res->ai_next) {
207 retry:
208 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
209 if (fd < 0) {
210 /* error */
211 continue;
212 }
213 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
214 if (rc != 0) {
215 close(fd);
216 /* error */
217 continue;
218 }
219 rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
220 if (rc != 0) {
221 close(fd);
222 /* error */
223 continue;
224 }
225
226 if (res->ai_family == AF_INET6) {
227 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val);
228 if (rc != 0) {
229 close(fd);
230 /* error */
231 continue;
232 }
233 }
234
235 if (type == SPDK_SOCK_CREATE_LISTEN) {
236 rc = bind(fd, res->ai_addr, res->ai_addrlen);
237 if (rc != 0) {
238 SPDK_ERRLOG("bind() failed, errno = %d\n", errno);
239 switch (errno) {
240 case EINTR:
241 /* interrupted? */
242 close(fd);
243 goto retry;
244 case EADDRNOTAVAIL:
245 SPDK_ERRLOG("IP address %s not available. "
246 "Verify IP address in config file "
247 "and make sure setup script is "
248 "run before starting spdk app.\n", ip);
249 /* FALLTHROUGH */
250 default:
251 /* try next family */
252 close(fd);
253 fd = -1;
254 continue;
255 }
256 }
257 /* bind OK */
258 rc = listen(fd, 512);
259 if (rc != 0) {
260 SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
261 close(fd);
262 fd = -1;
263 break;
264 }
265 } else if (type == SPDK_SOCK_CREATE_CONNECT) {
266 rc = connect(fd, res->ai_addr, res->ai_addrlen);
267 if (rc != 0) {
268 SPDK_ERRLOG("connect() failed, errno = %d\n", errno);
269 /* try next family */
270 close(fd);
271 fd = -1;
272 continue;
273 }
274 }
275
276 flag = fcntl(fd, F_GETFL);
277 if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
278 SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd, errno);
279 close(fd);
280 fd = -1;
281 break;
282 }
283 break;
284 }
285 freeaddrinfo(res0);
286
287 if (fd < 0) {
288 return NULL;
289 }
290
291 sock = calloc(1, sizeof(*sock));
292 if (sock == NULL) {
293 SPDK_ERRLOG("sock allocation failed\n");
294 close(fd);
295 return NULL;
296 }
297
298 sock->fd = fd;
299 return &sock->base;
300 }
301
302 static struct spdk_sock *
303 spdk_posix_sock_listen(const char *ip, int port)
304 {
305 return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN);
306 }
307
308 static struct spdk_sock *
309 spdk_posix_sock_connect(const char *ip, int port)
310 {
311 return spdk_posix_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT);
312 }
313
314 static struct spdk_sock *
315 spdk_posix_sock_accept(struct spdk_sock *_sock)
316 {
317 struct spdk_posix_sock *sock = __posix_sock(_sock);
318 struct sockaddr_storage sa;
319 socklen_t salen;
320 int rc;
321 struct spdk_posix_sock *new_sock;
322 int flag;
323
324 memset(&sa, 0, sizeof(sa));
325 salen = sizeof(sa);
326
327 assert(sock != NULL);
328
329 rc = accept(sock->fd, (struct sockaddr *)&sa, &salen);
330
331 if (rc == -1) {
332 return NULL;
333 }
334
335 flag = fcntl(rc, F_GETFL);
336 if ((!(flag & O_NONBLOCK)) && (fcntl(rc, F_SETFL, flag | O_NONBLOCK) < 0)) {
337 SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", rc, errno);
338 close(rc);
339 return NULL;
340 }
341
342 new_sock = calloc(1, sizeof(*sock));
343 if (new_sock == NULL) {
344 SPDK_ERRLOG("sock allocation failed\n");
345 close(rc);
346 return NULL;
347 }
348
349 new_sock->fd = rc;
350 return &new_sock->base;
351 }
352
353 static int
354 spdk_posix_sock_close(struct spdk_sock *_sock)
355 {
356 struct spdk_posix_sock *sock = __posix_sock(_sock);
357 int rc;
358
359 rc = close(sock->fd);
360 if (rc == 0) {
361 free(sock);
362 }
363
364 return rc;
365 }
366
367 static ssize_t
368 spdk_posix_sock_recv(struct spdk_sock *_sock, void *buf, size_t len)
369 {
370 struct spdk_posix_sock *sock = __posix_sock(_sock);
371
372 return recv(sock->fd, buf, len, MSG_DONTWAIT);
373 }
374
375 static ssize_t
376 spdk_posix_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
377 {
378 struct spdk_posix_sock *sock = __posix_sock(_sock);
379
380 return writev(sock->fd, iov, iovcnt);
381 }
382
383 static int
384 spdk_posix_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
385 {
386 struct spdk_posix_sock *sock = __posix_sock(_sock);
387 int val;
388 int rc;
389
390 assert(sock != NULL);
391
392 val = nbytes;
393 rc = setsockopt(sock->fd, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
394 if (rc != 0) {
395 return -1;
396 }
397 return 0;
398 }
399
400 static int
401 spdk_posix_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
402 {
403 struct spdk_posix_sock *sock = __posix_sock(_sock);
404
405 assert(sock != NULL);
406
407 return setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
408 &sz, sizeof(sz));
409 }
410
411 static int
412 spdk_posix_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
413 {
414 struct spdk_posix_sock *sock = __posix_sock(_sock);
415
416 assert(sock != NULL);
417
418 return setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF,
419 &sz, sizeof(sz));
420 }
421
422 static bool
423 spdk_posix_sock_is_ipv6(struct spdk_sock *_sock)
424 {
425 struct spdk_posix_sock *sock = __posix_sock(_sock);
426 struct sockaddr_storage sa;
427 socklen_t salen;
428 int rc;
429
430 assert(sock != NULL);
431
432 memset(&sa, 0, sizeof sa);
433 salen = sizeof sa;
434 rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
435 if (rc != 0) {
436 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
437 return false;
438 }
439
440 return (sa.ss_family == AF_INET6);
441 }
442
443 static bool
444 spdk_posix_sock_is_ipv4(struct spdk_sock *_sock)
445 {
446 struct spdk_posix_sock *sock = __posix_sock(_sock);
447 struct sockaddr_storage sa;
448 socklen_t salen;
449 int rc;
450
451 assert(sock != NULL);
452
453 memset(&sa, 0, sizeof sa);
454 salen = sizeof sa;
455 rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
456 if (rc != 0) {
457 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
458 return false;
459 }
460
461 return (sa.ss_family == AF_INET);
462 }
463
464 static struct spdk_sock_group_impl *
465 spdk_posix_sock_group_impl_create(void)
466 {
467 struct spdk_posix_sock_group_impl *group_impl;
468 int fd;
469
470 #if defined(__linux__)
471 fd = epoll_create1(0);
472 #elif defined(__FreeBSD__)
473 fd = kqueue();
474 #endif
475 if (fd == -1) {
476 return NULL;
477 }
478
479 group_impl = calloc(1, sizeof(*group_impl));
480 if (group_impl == NULL) {
481 SPDK_ERRLOG("group_impl allocation failed\n");
482 close(fd);
483 return NULL;
484 }
485
486 group_impl->fd = fd;
487
488 return &group_impl->base;
489 }
490
491 static int
492 spdk_posix_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
493 {
494 struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
495 struct spdk_posix_sock *sock = __posix_sock(_sock);
496 int rc;
497
498 #if defined(__linux__)
499 struct epoll_event event;
500
501 event.events = EPOLLIN;
502 event.data.ptr = sock;
503
504 rc = epoll_ctl(group->fd, EPOLL_CTL_ADD, sock->fd, &event);
505 #elif defined(__FreeBSD__)
506 struct kevent event;
507 struct timespec ts = {0};
508
509 EV_SET(&event, sock->fd, EVFILT_READ, EV_ADD, 0, 0, sock);
510
511 rc = kevent(group->fd, &event, 1, NULL, 0, &ts);
512 #endif
513 return rc;
514 }
515
516 static int
517 spdk_posix_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group, struct spdk_sock *_sock)
518 {
519 struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
520 struct spdk_posix_sock *sock = __posix_sock(_sock);
521 int rc;
522 #if defined(__linux__)
523 struct epoll_event event;
524
525 /* Event parameter is ignored but some old kernel version still require it. */
526 rc = epoll_ctl(group->fd, EPOLL_CTL_DEL, sock->fd, &event);
527 #elif defined(__FreeBSD__)
528 struct kevent event;
529 struct timespec ts = {0};
530
531 EV_SET(&event, sock->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
532
533 rc = kevent(group->fd, &event, 1, NULL, 0, &ts);
534 if (rc == 0 && event.flags & EV_ERROR) {
535 rc = -1;
536 errno = event.data;
537 }
538 #endif
539 return rc;
540 }
541
542 static int
543 spdk_posix_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
544 struct spdk_sock **socks)
545 {
546 struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
547 int num_events, i;
548
549 #if defined(__linux__)
550 struct epoll_event events[MAX_EVENTS_PER_POLL];
551
552 num_events = epoll_wait(group->fd, events, max_events, 0);
553 #elif defined(__FreeBSD__)
554 struct kevent events[MAX_EVENTS_PER_POLL];
555 struct timespec ts = {0};
556
557 num_events = kevent(group->fd, NULL, 0, events, max_events, &ts);
558 #endif
559
560 if (num_events == -1) {
561 return -1;
562 }
563
564 for (i = 0; i < num_events; i++) {
565 #if defined(__linux__)
566 socks[i] = events[i].data.ptr;
567 #elif defined(__FreeBSD__)
568 socks[i] = events[i].udata;
569 #endif
570 }
571
572 return num_events;
573 }
574
575 static int
576 spdk_posix_sock_group_impl_close(struct spdk_sock_group_impl *_group)
577 {
578 struct spdk_posix_sock_group_impl *group = __posix_group_impl(_group);
579
580 return close(group->fd);
581 }
582
583 static struct spdk_net_impl g_posix_net_impl = {
584 .name = "posix",
585 .getaddr = spdk_posix_sock_getaddr,
586 .connect = spdk_posix_sock_connect,
587 .listen = spdk_posix_sock_listen,
588 .accept = spdk_posix_sock_accept,
589 .close = spdk_posix_sock_close,
590 .recv = spdk_posix_sock_recv,
591 .writev = spdk_posix_sock_writev,
592 .set_recvlowat = spdk_posix_sock_set_recvlowat,
593 .set_recvbuf = spdk_posix_sock_set_recvbuf,
594 .set_sendbuf = spdk_posix_sock_set_sendbuf,
595 .is_ipv6 = spdk_posix_sock_is_ipv6,
596 .is_ipv4 = spdk_posix_sock_is_ipv4,
597 .group_impl_create = spdk_posix_sock_group_impl_create,
598 .group_impl_add_sock = spdk_posix_sock_group_impl_add_sock,
599 .group_impl_remove_sock = spdk_posix_sock_group_impl_remove_sock,
600 .group_impl_poll = spdk_posix_sock_group_impl_poll,
601 .group_impl_close = spdk_posix_sock_group_impl_close,
602 };
603
604 SPDK_NET_IMPL_REGISTER(posix, &g_posix_net_impl);