blob: 5918f6b73d132a24677765e28036c53dea9277d7 [file] [log] [blame]
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <unistd.h>
16#include <stdio.h>
17#include <sys/uio.h>
18#include <limits.h>
19#define __need_IOV_MAX
20#include <bits/stdio_lim.h>
Stevenb59f2272017-10-12 17:10:33 -070021#include <netinet/tcp.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070022
23#include <vppinfra/types.h>
24#include <vppinfra/hash.h>
25#include <vppinfra/pool.h>
26
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040027#include <vcl/vcom_socket.h>
28#include <vcl/vcom_socket_wrapper.h>
29#include <vcl/vcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070030
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040031#include <vcl/vppcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070032
33
34/*
35 * VCOM_SOCKET Private definitions and functions.
36 */
37
38typedef struct vcom_socket_main_t_
39{
40 u8 init;
41
42 /* vcom_socket pool */
43 vcom_socket_t *vsockets;
44
45 /* Hash table for socketidx to fd mapping */
46 uword *sockidx_by_fd;
47
48 /* vcom_epoll pool */
49 vcom_epoll_t *vepolls;
50
51 /* Hash table for epollidx to epfd mapping */
52 uword *epollidx_by_epfd;
53
54
55 /* common epitem poll for all epfd */
56 /* TBD: epitem poll per epfd */
57 /* vcom_epitem pool */
58 vcom_epitem_t *vepitems;
59
60 /* Hash table for epitemidx to epfdfd mapping */
61 uword *epitemidx_by_epfdfd;
62
63 /* Hash table - key:epfd, value:vec of epitemidx */
64 uword *epitemidxs_by_epfd;
65 /* Hash table - key:fd, value:vec of epitemidx */
66 uword *epitemidxs_by_fd;
67
68} vcom_socket_main_t;
69
70vcom_socket_main_t vcom_socket_main;
71
72
73static int
74vcom_socket_open_socket (int domain, int type, int protocol)
75{
76 int rv = -1;
77
78 /* handle domains implemented by vpp */
79 switch (domain)
80 {
81 case AF_INET:
82 case AF_INET6:
83 /* get socket type and
84 * handle the socket types supported by vpp */
85 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
86 {
87 case SOCK_STREAM:
88 case SOCK_DGRAM:
89 /* the type argument serves a second purpose,
90 * in addition to specifying a socket type,
91 * it may include the bitwise OR of any of
92 * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
93 * the behavior of socket. */
94 rv = libc_socket (domain, type, protocol);
95 if (rv == -1)
96 rv = -errno;
97 break;
98
99 default:
100 break;
101 }
102
103 break;
104
105 default:
106 break;
107 }
108
109 return rv;
110}
111
112static int
113vcom_socket_open_epoll (int flags)
114{
115 int rv = -1;
116
117 if (flags < 0)
118 {
119 return -EINVAL;
120 }
121 if (flags && (flags & ~EPOLL_CLOEXEC))
122 {
123 return -EINVAL;
124 }
125
126 /* flags can be either zero or EPOLL_CLOEXEC */
127 rv = libc_epoll_create1 (flags);
128 if (rv == -1)
129 rv = -errno;
130
131 return rv;
132}
133
134static int
135vcom_socket_close_socket (int fd)
136{
137 int rv;
138
139 rv = libc_close (fd);
140 if (rv == -1)
141 rv = -errno;
142
143 return rv;
144}
145
146static int
147vcom_socket_close_epoll (int epfd)
148{
149 int rv;
150
151 rv = libc_close (epfd);
152 if (rv == -1)
153 rv = -errno;
154
155 return rv;
156}
157
158/*
159 * Public API functions
160 */
161
162
163int
164vcom_socket_is_vcom_fd (int fd)
165{
166 vcom_socket_main_t *vsm = &vcom_socket_main;
167 uword *p;
168 vcom_socket_t *vsock;
169
170 p = hash_get (vsm->sockidx_by_fd, fd);
171
172 if (p)
173 {
174 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
175 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
176 return 1;
177 }
178 return 0;
179}
180
181int
182vcom_socket_is_vcom_epfd (int epfd)
183{
184 vcom_socket_main_t *vsm = &vcom_socket_main;
185 uword *p;
186 vcom_epoll_t *vepoll;
187
188 p = hash_get (vsm->epollidx_by_epfd, epfd);
189
190 if (p)
191 {
192 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
193 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
194 return 1;
195 }
196 return 0;
197}
198
199static inline int
200vcom_socket_get_sid (int fd)
201{
202 vcom_socket_main_t *vsm = &vcom_socket_main;
203 uword *p;
204 vcom_socket_t *vsock;
205
206 p = hash_get (vsm->sockidx_by_fd, fd);
207
208 if (p)
209 {
210 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
211 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
212 return vsock->sid;
213 }
214 return INVALID_SESSION_ID;
215}
216
217static inline int
218vcom_socket_get_vep_idx (int epfd)
219{
220 vcom_socket_main_t *vsm = &vcom_socket_main;
221 uword *p;
222 vcom_epoll_t *vepoll;
223
224 p = hash_get (vsm->epollidx_by_epfd, epfd);
225
226 if (p)
227 {
228 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
229 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
230 return vepoll->vep_idx;
231 }
232 return INVALID_VEP_IDX;
233}
234
235static inline int
236vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
237{
238 vcom_socket_main_t *vsm = &vcom_socket_main;
239 uword *p;
240 vcom_socket_t *vsock;
241
242 p = hash_get (vsm->sockidx_by_fd, fd);
243
244 if (p)
245 {
246 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
247 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
248 {
249 *vsockp = vsock;
250 return vsock->sid;
251 }
252 }
253 return INVALID_SESSION_ID;
254}
255
256static inline int
257vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
258{
259 vcom_socket_main_t *vsm = &vcom_socket_main;
260 uword *p;
261 vcom_epoll_t *vepoll;
262
263 p = hash_get (vsm->epollidx_by_epfd, epfd);
264
265 if (p)
266 {
267 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
268 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
269 {
270 *vepollp = vepoll;
271 return vepoll->vep_idx;
272 }
273 }
274 return INVALID_VEP_IDX;
275}
276
277
278static int
279vcom_socket_close_vepoll (int epfd)
280{
281 int rv = -1;
282 vcom_socket_main_t *vsm = &vcom_socket_main;
283 uword *p;
284 vcom_epoll_t *vepoll;
285
286 p = hash_get (vsm->epollidx_by_epfd, epfd);
287 if (!p)
288 return -EBADF;
289
290 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
291 if (!vepoll)
292 return -EBADF;
293
294 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
295 return -EINVAL;
296
297 if (vepoll->count)
298 {
299 if (!vepoll->close)
300 {
301 vepoll->close = 1;
302 return 0;
303 }
304 else
305 {
306 return -EBADF;
307 }
308 }
309
310 /* count is zero */
311 rv = vppcom_session_close (vepoll->vep_idx);
312 rv = vcom_socket_close_epoll (vepoll->epfd);
313
314 vepoll_init (vepoll);
315 hash_unset (vsm->epollidx_by_epfd, epfd);
316 pool_put (vsm->vepolls, vepoll);
317
318 return rv;
319}
320
321static int
322vcom_socket_close_vsock (int fd)
323{
324 int rv = -1;
325 vcom_socket_main_t *vsm = &vcom_socket_main;
326 uword *p;
327 vcom_socket_t *vsock;
328
329 vcom_epitem_t *vepitem;
330
331 i32 *vepitemidxs = 0;
332 i32 *vepitemidxs_var = 0;
333
334 p = hash_get (vsm->sockidx_by_fd, fd);
335 if (!p)
336 return -EBADF;
337
338 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
339 if (!vsock)
340 return -ENOTSOCK;
341
342 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
343 return -EINVAL;
344
345 rv = vppcom_session_close (vsock->sid);
346 rv = vcom_socket_close_socket (vsock->fd);
347
348 vsocket_init (vsock);
349 hash_unset (vsm->sockidx_by_fd, fd);
350 pool_put (vsm->vsockets, vsock);
351
352 /*
353 * NOTE:
354 * Before calling close(), user should remove
355 * this fd from the epoll-set of all epoll instances,
356 * otherwise resource(epitems) leaks ensues.
357 */
358
359 /*
360 * 00. close all epoll instances that are marked as "close"
361 * of which this fd is the "last" remaining member.
362 * 01. epitems associated with this fd are intentionally
363 * not removed, see NOTE: above.
364 * */
365
366 /* does this fd participate in epoll */
367 p = hash_get (vsm->epitemidxs_by_fd, fd);
368 if (p)
369 {
370 vepitemidxs = *(i32 **) p;
371 vec_foreach (vepitemidxs_var, vepitemidxs)
372 {
373 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
374 if (vepitem && vepitem->fd == fd &&
375 vepitem->type == FD_TYPE_VCOM_SOCKET)
376 {
377 i32 vep_idx;
378 vcom_epoll_t *vepoll;
379 if ((vep_idx =
380 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
381 &vepoll)) !=
382 INVALID_VEP_IDX)
383 {
384 if (vepoll->close)
385 {
386 if (vepoll->count == 1)
387 {
388 /*
389 * force count to zero and
390 * close this epoll instance
391 * */
392 vepoll->count = 0;
393 vcom_socket_close_vepoll (vepoll->epfd);
394 }
395 else
396 {
397 vepoll->count -= 1;
398 }
399 }
400 }
401 }
402
403 }
404 }
405
406 return rv;
407}
408
409int
410vcom_socket_close (int __fd)
411{
412 int rv;
413
414 if (vcom_socket_is_vcom_fd (__fd))
415 {
416 rv = vcom_socket_close_vsock (__fd);
417 }
418 else if (vcom_socket_is_vcom_epfd (__fd))
419 {
420 rv = vcom_socket_close_vepoll (__fd);
421 }
422 else
423 {
424 rv = -EBADF;
425 }
426
427 return rv;
428}
429
430ssize_t
431vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
432{
433 int rv = -1;
434 vcom_socket_main_t *vsm = &vcom_socket_main;
435 uword *p;
436 vcom_socket_t *vsock;
437
438 p = hash_get (vsm->sockidx_by_fd, __fd);
439 if (!p)
440 return -EBADF;
441
442 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
443 if (!vsock)
444 return -ENOTSOCK;
445
446 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
447 return -EINVAL;
448
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400449 if (!__buf)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700450 {
451 return -EINVAL;
452 }
453
454 rv = vcom_fcntl (__fd, F_GETFL, 0);
455 if (rv < 0)
456 {
457 return rv;
458
459 }
460
461 /* is blocking */
462 if (!(rv & O_NONBLOCK))
463 {
464 do
465 {
466 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
467 }
Dave Wallace60f54822017-10-24 20:47:45 -0400468 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700469 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
470 return rv;
471 }
472 /* The file descriptor refers to a socket and has been
473 * marked nonblocking(O_NONBLOCK) and the read would
474 * block.
475 * */
476 /* is non blocking */
477 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
478 return rv;
479}
480
481ssize_t
482vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
483{
484 int rv;
485 vcom_socket_main_t *vsm = &vcom_socket_main;
486 uword *p;
487 vcom_socket_t *vsock;
488 ssize_t total = 0, len = 0;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400489 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700490
491 p = hash_get (vsm->sockidx_by_fd, __fd);
492 if (!p)
493 return -EBADF;
494
495 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
496 if (!vsock)
497 return -ENOTSOCK;
498
499 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
500 return -EINVAL;
501
502 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
503 return -EINVAL;
504
505 /* Sanity check */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400506 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700507 {
508 if (SSIZE_MAX - len < __iov[i].iov_len)
509 return -EINVAL;
510 len += __iov[i].iov_len;
511 }
512
513 rv = vcom_fcntl (__fd, F_GETFL, 0);
514 if (rv < 0)
515 {
516 return rv;
517 }
518
519 /* is blocking */
520 if (!(rv & O_NONBLOCK))
521 {
522 do
523 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400524 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700525 {
526 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
527 __iov[i].iov_len);
528 if (rv < 0)
529 break;
530 else
531 {
532 total += rv;
533 if (rv < __iov[i].iov_len)
534 /* Read less than buffer provided, no point to continue */
535 break;
536 }
537 }
538 }
Dave Wallace60f54822017-10-24 20:47:45 -0400539 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700540 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
541 return total;
542 }
543
544 /* is non blocking */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400545 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700546 {
547 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
548 __iov[i].iov_len);
549 if (rv < 0)
550 {
551 if (total > 0)
552 break;
553 else
554 {
555 errno = rv;
556 return rv;
557 }
558 }
559 else
560 {
561 total += rv;
562 if (rv < __iov[i].iov_len)
563 /* Read less than buffer provided, no point to continue */
564 break;
565 }
566 }
567 return total;
568}
569
570ssize_t
571vcom_socket_write (int __fd, const void *__buf, size_t __n)
572{
573 int rv = -1;
574 vcom_socket_main_t *vsm = &vcom_socket_main;
575 uword *p;
576 vcom_socket_t *vsock;
577
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400578 if (!__buf)
579 {
580 return -EINVAL;
581 }
582
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700583 p = hash_get (vsm->sockidx_by_fd, __fd);
584 if (!p)
585 return -EBADF;
586
587 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
588 if (!vsock)
589 return -ENOTSOCK;
590
591 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
592 return -EINVAL;
593
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700594 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
595 return rv;
596}
597
598ssize_t
599vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
600{
601 int rv = -1;
602 ssize_t total = 0;
603 vcom_socket_main_t *vsm = &vcom_socket_main;
604 uword *p;
605 vcom_socket_t *vsock;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400606 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700607
608 p = hash_get (vsm->sockidx_by_fd, __fd);
609 if (!p)
610 return -EBADF;
611
612 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
613 if (!vsock)
614 return -ENOTSOCK;
615
616 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
617 return -EINVAL;
618
619 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
620 return -EINVAL;
621
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400622 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700623 {
624 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
625 __iov[i].iov_len);
626 if (rv < 0)
627 {
628 if (total > 0)
629 break;
630 else
631 return rv;
632 }
633 else
634 total += rv;
635 }
636 return total;
637}
638
639/*
640 * RETURN: 0 - invalid cmd
641 * 1 - cmd not handled by vcom and vppcom
642 * 2 - cmd handled by vcom socket resource
643 * 3 - cmd handled by vppcom
644 * */
645/* TBD: incomplete list of cmd */
646static int
647vcom_socket_check_fcntl_cmd (int __cmd)
648{
649 switch (__cmd)
650 {
651 /*cmd not handled by vcom and vppcom */
652 /* Fallthrough */
653 case F_DUPFD:
654 case F_DUPFD_CLOEXEC:
655 return 1;
656
657 /* cmd handled by vcom socket resource */
658 /* Fallthrough */
659 case F_GETFD:
660 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700661 case F_GETLK:
662 case F_SETLK:
663 case F_SETLKW:
664 case F_GETOWN:
665 case F_SETOWN:
666 return 2;
667
Stevenb59f2272017-10-12 17:10:33 -0700668 /* cmd handled by vcom and vppcom */
669 case F_SETFL:
670 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700671 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700672
673 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700674 default:
Stevenb59f2272017-10-12 17:10:33 -0700675 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700676 }
677 return 0;
678}
679
Dave Wallacee22aa742017-10-20 12:30:38 -0400680static inline int
681vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700682{
Stevenb59f2272017-10-12 17:10:33 -0700683 int flags = va_arg (__ap, int);
684 int rv = -EOPNOTSUPP;
685 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700686
Stevenb59f2272017-10-12 17:10:33 -0700687 size = sizeof (flags);
688 if (__cmd == F_SETFL)
689 {
690 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
691 }
692 else if (__cmd == F_GETFL)
693 {
694 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
695 if (rv == VPPCOM_OK)
696 rv = flags;
697 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700698
699 return rv;
700}
701
702int
703vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
704{
705 int rv = -EBADF;
706 vcom_socket_main_t *vsm = &vcom_socket_main;
707 uword *p;
708 vcom_socket_t *vsock;
709
710 p = hash_get (vsm->sockidx_by_fd, __fd);
711 if (!p)
712 return -EBADF;
713
714 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
715 if (!vsock)
716 return -ENOTSOCK;
717
718 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
719 return -EINVAL;
720
721 switch (vcom_socket_check_fcntl_cmd (__cmd))
722 {
723 /* invalid cmd */
724 case 0:
725 rv = -EBADF;
726 break;
727 /*cmd not handled by vcom and vppcom */
728 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700729 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700730 break;
731 /* cmd handled by vcom socket resource */
732 case 2:
733 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
734 break;
735 /* cmd handled by vppcom */
736 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400737 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700738 break;
739
740 default:
741 rv = -EINVAL;
742 break;
743 }
744
745 return rv;
746}
747
Stevenb59f2272017-10-12 17:10:33 -0700748/*
749 * RETURN: 0 - invalid cmd
750 * 1 - cmd not handled by vcom and vppcom
751 * 2 - cmd handled by vcom socket resource
752 * 3 - cmd handled by vppcom
753 */
754static int
755vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
756{
757 int rc;
758
759 switch (__cmd)
760 {
761 /* cmd handled by vppcom */
762 case FIONREAD:
763 rc = 3;
764 break;
765
766 /* cmd not handled by vcom and vppcom */
767 default:
768 rc = 1;
769 break;
770 }
771 return rc;
772}
773
Dave Wallacee22aa742017-10-20 12:30:38 -0400774static inline int
775vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
Stevenb59f2272017-10-12 17:10:33 -0700776{
777 int rv;
778
779 if (__cmd == FIONREAD)
780 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
781 else
782 rv = -EOPNOTSUPP;
783 return rv;
784}
785
786int
787vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
788{
789 int rv = -EBADF;
790 vcom_socket_main_t *vsm = &vcom_socket_main;
791 uword *p;
792 vcom_socket_t *vsock;
793
794 p = hash_get (vsm->sockidx_by_fd, __fd);
795 if (!p)
796 return -EBADF;
797
798 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
799 if (!vsock)
800 return -ENOTSOCK;
801
802 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
803 return -EINVAL;
804
805 switch (vcom_socket_check_ioctl_cmd (__cmd))
806 {
807 /* Not supported cmd */
808 case 0:
809 rv = -EOPNOTSUPP;
810 break;
811
812 /* cmd not handled by vcom and vppcom */
813 case 1:
814 rv = libc_vioctl (vsock->fd, __cmd, __ap);
815 break;
816
817 /* cmd handled by vcom socket resource */
818 case 2:
819 rv = libc_vioctl (vsock->fd, __cmd, __ap);
820 break;
821
822 /* cmd handled by vppcom */
823 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400824 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
Stevenb59f2272017-10-12 17:10:33 -0700825 break;
826
827 default:
828 rv = -EINVAL;
829 break;
830 }
831
832 return rv;
833}
834
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700835static inline int
836vcom_socket_fds_2_sid_fds (
837 /* dest */
838 int *vcom_nsid_fds,
839 fd_set * __restrict vcom_rd_sid_fds,
840 fd_set * __restrict vcom_wr_sid_fds,
841 fd_set * __restrict vcom_ex_sid_fds,
842 /* src */
843 int vcom_nfds,
844 fd_set * __restrict vcom_readfds,
845 fd_set * __restrict vcom_writefds,
846 fd_set * __restrict vcom_exceptfds)
847{
848 int rv = 0;
849 int fd;
850 int sid;
851 /* invalid max_sid is -1 */
852 int max_sid = -1;
853 int nsid = 0;
854
855 /*
856 * set sid in sid sets corresponding to fd's in fd sets
857 * compute nsid and vcom_nsid_fds from sid sets
858 */
859
860 for (fd = 0; fd < vcom_nfds; fd++)
861 {
862 /*
863 * F fd set, src
864 * S sid set, dest
865 */
866#define _(S,F) \
867 if ((F) && (S) && FD_ISSET (fd, (F))) \
868 { \
869 sid = vcom_socket_get_sid (fd); \
870 if (sid != INVALID_SESSION_ID) \
871 { \
872 FD_SET (sid, (S)); \
873 if (sid > max_sid) \
874 { \
875 max_sid = sid; \
876 } \
877 ++nsid; \
878 } \
879 else \
880 { \
881 rv = -EBADFD; \
882 goto done; \
883 } \
884 }
885
886
887 _(vcom_rd_sid_fds, vcom_readfds);
888 _(vcom_wr_sid_fds, vcom_writefds);
889 _(vcom_ex_sid_fds, vcom_exceptfds);
890#undef _
891 }
892
893 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
894 rv = nsid;
895
896done:
897 return rv;
898}
899
900/*
901 * PRE: 00. sid sets were derived from fd sets
902 * 01. sid sets were updated with sids that actually changed
903 * status
904 * 02. fd sets still has watched fds
905 *
906 * This function will modify in place fd sets to indicate which fd's
907 * actually changed status(inferred from sid sets)
908 */
909static inline int
910vcom_socket_sid_fds_2_fds (
911 /* dest */
912 int *new_vcom_nfds,
913 int vcom_nfds,
914 fd_set * __restrict vcom_readfds,
915 fd_set * __restrict vcom_writefds,
916 fd_set * __restrict vcom_exceptfds,
917 /* src */
918 int vcom_nsid_fds,
919 fd_set * __restrict vcom_rd_sid_fds,
920 fd_set * __restrict vcom_wr_sid_fds,
921 fd_set * __restrict vcom_ex_sid_fds)
922{
923 int rv = 0;
924 int fd;
925 int sid;
926 /* invalid max_fd is -1 */
927 int max_fd = -1;
928 int nfd = 0;
929
930
931 /*
932 * modify in place fd sets to indicate which fd's
933 * actually changed status(inferred from sid sets)
934 */
935 for (fd = 0; fd < vcom_nfds; fd++)
936 {
937 /*
938 * F fd set, dest
939 * S sid set, src
940 */
941#define _(S,F) \
942 if ((F) && (S) && FD_ISSET (fd, (F))) \
943 { \
944 sid = vcom_socket_get_sid (fd); \
945 if (sid != INVALID_SESSION_ID) \
946 { \
947 if (!FD_ISSET (sid, (S))) \
948 { \
949 FD_CLR(fd, (F)); \
950 } \
951 } \
952 else \
953 { \
954 rv = -EBADFD; \
955 goto done; \
956 } \
957 }
958
959
960 _(vcom_rd_sid_fds, vcom_readfds);
961 _(vcom_wr_sid_fds, vcom_writefds);
962 _(vcom_ex_sid_fds, vcom_exceptfds);
963#undef _
964 }
965
966 /*
967 * compute nfd and new_vcom_nfds from fd sets
968 */
969 for (fd = 0; fd < vcom_nfds; fd++)
970 {
971
972#define _(F) \
973 if ((F) && FD_ISSET (fd, (F))) \
974 { \
975 if (fd > max_fd) \
976 { \
977 max_fd = fd; \
978 } \
979 ++nfd; \
980 }
981
982
983 _(vcom_readfds);
984 _(vcom_writefds);
985 _(vcom_exceptfds);
986#undef _
987
988 }
989
990 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
991 rv = nfd;
992
993done:
994 return rv;
995}
996
997/*
998 * PRE:
999 * vom_socket_select is always called with
1000 * timeout->tv_sec and timeout->tv_usec set to zero.
1001 * hence vppcom_select return immediately.
1002 */
1003/*
1004 * TBD: do{body;} while(timeout conditional); timeout loop
1005 */
1006int
1007vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1008 fd_set * __restrict vcom_writefds,
1009 fd_set * __restrict vcom_exceptfds,
1010 struct timeval *__restrict timeout)
1011{
Dave Wallacee22aa742017-10-20 12:30:38 -04001012 static unsigned long vcom_nsid_fds = 0;
1013 int vcom_nsid = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001014 int rv = -EBADF;
1015 pid_t pid = getpid ();
1016
1017 int new_vcom_nfds = 0;
1018 int new_vcom_nfd = 0;
1019
1020 /* vcom sid fds */
1021 fd_set vcom_rd_sid_fds;
1022 fd_set vcom_wr_sid_fds;
1023 fd_set vcom_ex_sid_fds;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001024
1025 /* in seconds eg. 3.123456789 seconds */
1026 double time_to_wait = (double) 0;
1027
1028 /* validate inputs */
1029 if (vcom_nfds < 0)
1030 {
1031 return -EINVAL;
1032 }
1033
1034 /* convert timeval timeout to double time_to_wait */
1035 if (timeout)
1036 {
1037 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1038 {
1039 /* polling: vppcom_select returns immediately */
1040 time_to_wait = (double) 0;
1041 }
1042 else
1043 {
1044 /*TBD: use timeval api */
1045 time_to_wait = (double) timeout->tv_sec +
1046 (double) timeout->tv_usec / (double) 1000000 +
1047 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1048 }
1049 }
1050 else
1051 {
1052 /*
1053 * no timeout: vppcom_select can block indefinitely
1054 * waiting for a file descriptor to become ready
1055 * */
1056 /* set to a phantom value */
1057 time_to_wait = ~0;
1058 }
1059
1060 /* zero the sid_sets */
1061 /*
1062 * F fd set
1063 * S sid set
1064 */
1065#define _(S,F) \
1066 if ((F)) \
1067 { \
1068 FD_ZERO ((S)); \
1069 }
1070
1071
1072 _(&vcom_rd_sid_fds, vcom_readfds);
1073 _(&vcom_wr_sid_fds, vcom_writefds);
1074 _(&vcom_ex_sid_fds, vcom_exceptfds);
1075#undef _
1076
Dave Wallacee22aa742017-10-20 12:30:38 -04001077 if (vcom_nfds == 0)
1078 {
1079 if (time_to_wait > 0)
1080 {
1081 if (VCOM_DEBUG > 0)
1082 fprintf (stderr,
1083 "[%d] vcom_socket_select called to "
1084 "emulate delay_ns()!\n", pid);
1085 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1086 }
1087 else
1088 {
1089 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1090 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1091 }
1092 return 0;
1093 }
1094
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001095 /* populate read, write and except sid_sets */
1096 vcom_nsid = vcom_socket_fds_2_sid_fds (
1097 /* dest */
1098 vcom_readfds || vcom_writefds
1099 || vcom_exceptfds ? (int *)
1100 &vcom_nsid_fds : NULL,
1101 vcom_readfds ? &vcom_rd_sid_fds :
1102 NULL,
1103 vcom_writefds ? &vcom_wr_sid_fds :
1104 NULL,
1105 vcom_exceptfds ? &vcom_ex_sid_fds :
1106 NULL,
1107 /* src */
1108 vcom_nfds,
1109 vcom_readfds,
1110 vcom_writefds, vcom_exceptfds);
1111 if (vcom_nsid < 0)
1112 {
1113 return vcom_nsid;
1114 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001115
1116 rv = vppcom_select (vcom_nsid_fds,
1117 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1118 NULL,
1119 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1120 NULL,
1121 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1122 NULL, time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001123 if (VCOM_DEBUG > 2)
1124 fprintf (stderr, "[%d] called vppcom_select(): "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001125 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1126
1127 /* check if any file descriptors changed status */
1128 if (rv > 0)
1129 {
1130 /*
1131 * on exit, sets are modified in place to indicate which
1132 * file descriptors actually changed status
1133 * */
1134
1135 /*
1136 * comply with pre-condition
1137 * do not clear vcom fd sets befor calling
1138 * vcom_socket_sid_fds_2_fds
1139 */
1140 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1141 /* dest */
1142 &new_vcom_nfds,
1143 vcom_nfds,
1144 vcom_readfds,
1145 vcom_writefds,
1146 vcom_exceptfds,
1147 /* src */
1148 vcom_nsid_fds,
1149 vcom_readfds ?
1150 &vcom_rd_sid_fds : NULL,
1151 vcom_writefds ?
1152 &vcom_wr_sid_fds : NULL,
1153 vcom_exceptfds ?
1154 &vcom_ex_sid_fds : NULL);
1155 if (new_vcom_nfd < 0)
1156 {
1157 return new_vcom_nfd;
1158 }
1159 if (new_vcom_nfds < 0)
1160 {
1161 return -EINVAL;
1162 }
1163 rv = new_vcom_nfd;
1164 }
1165 return rv;
1166}
1167
1168
1169int
1170vcom_socket_socket (int __domain, int __type, int __protocol)
1171{
1172 int rv = -1;
1173 vcom_socket_main_t *vsm = &vcom_socket_main;
1174 vcom_socket_t *vsock;
1175
1176 i32 fd;
1177 i32 sid;
1178 i32 sockidx;
1179 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1180 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1181
1182 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1183 if (fd < 0)
1184 {
1185 rv = fd;
1186 goto out;
1187 }
1188
1189 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1190 (type == SOCK_DGRAM) ?
1191 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1192 is_nonblocking);
1193 if (sid < 0)
1194 {
1195 rv = sid;
1196 goto out_close_socket;
1197 }
1198
1199 pool_get (vsm->vsockets, vsock);
1200 vsocket_init (vsock);
1201
1202 sockidx = vsock - vsm->vsockets;
1203 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1204
1205 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1206 return fd;
1207
1208out_close_socket:
1209 vcom_socket_close_socket (fd);
1210out:
1211 return rv;
1212}
1213
1214int
1215vcom_socket_socketpair (int __domain, int __type, int __protocol,
1216 int __fds[2])
1217{
1218/* TBD: */
1219 return 0;
1220}
1221
1222int
1223vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1224{
1225 int rv = -1;
1226 vcom_socket_main_t *vsm = &vcom_socket_main;
1227 uword *p;
1228 vcom_socket_t *vsock;
1229
1230 vppcom_endpt_t ep;
1231
1232 p = hash_get (vsm->sockidx_by_fd, __fd);
1233 if (!p)
1234 return -EBADF;
1235
1236 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1237 if (!vsock)
1238 return -ENOTSOCK;
1239
1240 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1241 return -EINVAL;
1242
1243 if (!__addr)
1244 {
1245 return -EINVAL;
1246 }
1247
1248 ep.vrf = VPPCOM_VRF_DEFAULT;
1249 switch (__addr->sa_family)
1250 {
1251 case AF_INET:
1252 if (__len != sizeof (struct sockaddr_in))
1253 {
1254 return -EINVAL;
1255 }
1256 ep.is_ip4 = VPPCOM_IS_IP4;
1257 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1258 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1259 break;
1260
1261 case AF_INET6:
1262 if (__len != sizeof (struct sockaddr_in6))
1263 {
1264 return -EINVAL;
1265 }
1266 ep.is_ip4 = VPPCOM_IS_IP6;
1267 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1268 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1269 break;
1270
1271 default:
1272 return -1;
1273 break;
1274 }
1275
1276 rv = vppcom_session_bind (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001277 return rv;
1278}
1279
Dave Wallacee22aa742017-10-20 12:30:38 -04001280static inline int
1281vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001282{
Steven2199aab2017-10-15 20:18:47 -07001283 int rv;
1284 uint32_t size = sizeof (*ep);
1285
1286 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1287 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001288}
1289
1290int
1291vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1292 socklen_t * __restrict __len)
1293{
1294 int rv = -1;
1295 vcom_socket_main_t *vsm = &vcom_socket_main;
1296 uword *p;
1297 vcom_socket_t *vsock;
1298
1299
1300 p = hash_get (vsm->sockidx_by_fd, __fd);
1301 if (!p)
1302 return -EBADF;
1303
1304 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1305 if (!vsock)
1306 return -ENOTSOCK;
1307
1308 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1309 return -EINVAL;
1310
1311 if (!__addr || !__len)
1312 return -EFAULT;
1313
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001314 vppcom_endpt_t ep;
1315 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001316 rv = vcom_session_getsockname (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001317 if (rv == 0)
1318 {
1319 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1320 {
1321 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1322 switch (__addr->sa_family)
1323 {
1324 case AF_INET:
1325 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1326 *__len = sizeof (struct sockaddr_in);
1327 break;
1328
1329 case AF_INET6:
1330 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1331 *__len = sizeof (struct sockaddr_in6);
1332 break;
1333
1334 default:
1335 break;
1336 }
1337 }
1338 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001339
1340 return rv;
1341}
1342
1343int
1344vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1345{
1346 int rv = -1;
1347 vcom_socket_main_t *vsm = &vcom_socket_main;
1348 uword *p;
1349 vcom_socket_t *vsock;
1350
1351 vppcom_endpt_t ep;
1352
1353 p = hash_get (vsm->sockidx_by_fd, __fd);
1354 if (p)
1355 {
1356 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1357
1358 ep.vrf = VPPCOM_VRF_DEFAULT;
1359 switch (__addr->sa_family)
1360 {
1361 case AF_INET:
1362 ep.is_ip4 = VPPCOM_IS_IP4;
1363 ep.ip =
1364 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1365 ep.port =
1366 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1367 break;
1368
1369 case AF_INET6:
1370 ep.is_ip4 = VPPCOM_IS_IP6;
1371 ep.ip =
1372 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1373 ep.port =
1374 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1375 break;
1376
1377 default:
1378 return -1;
1379 break;
1380 }
1381
1382 rv = vppcom_session_connect (vsock->sid, &ep);
1383 }
1384 return rv;
1385}
1386
Dave Wallacee22aa742017-10-20 12:30:38 -04001387static inline int
1388vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001389{
Steven2199aab2017-10-15 20:18:47 -07001390 int rv;
1391 uint32_t size = sizeof (*ep);
1392
1393 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1394 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001395}
1396
1397int
1398vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1399 socklen_t * __restrict __len)
1400{
1401 int rv = -1;
1402 vcom_socket_main_t *vsm = &vcom_socket_main;
1403 uword *p;
1404 vcom_socket_t *vsock;
1405
1406
1407 p = hash_get (vsm->sockidx_by_fd, __fd);
1408 if (!p)
1409 return -EBADF;
1410
1411 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1412 if (!vsock)
1413 return -ENOTSOCK;
1414
1415 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1416 return -EINVAL;
1417
1418 if (!__addr || !__len)
1419 return -EFAULT;
1420
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001421 vppcom_endpt_t ep;
1422 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001423 rv = vcom_session_getpeername (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001424 if (rv == 0)
1425 {
1426 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1427 {
1428 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1429 switch (__addr->sa_family)
1430 {
1431 case AF_INET:
1432 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1433 *__len = sizeof (struct sockaddr_in);
1434 break;
1435
1436 case AF_INET6:
1437 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1438 *__len = sizeof (struct sockaddr_in6);
1439 break;
1440
1441 default:
1442 break;
1443 }
1444 }
1445 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001446
1447 return rv;
1448}
1449
1450ssize_t
1451vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1452{
1453 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1454}
1455
1456ssize_t
1457vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1458{
1459 int rv = -1;
1460 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1461 return rv;
1462}
1463
1464/*
1465 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1466 * 0 otherwise
1467 * */
1468int
1469vcom_socket_is_connection_mode_socket (int __fd)
1470{
1471 int rv = -1;
1472 /* TBD define new vppcom api */
1473 vcom_socket_main_t *vsm = &vcom_socket_main;
1474 uword *p;
1475 vcom_socket_t *vsock;
1476
1477 int type;
1478 socklen_t optlen;
1479
1480 p = hash_get (vsm->sockidx_by_fd, __fd);
1481
1482 if (p)
1483 {
1484 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1485 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1486 {
1487 optlen = sizeof (type);
1488 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1489 if (rv != 0)
1490 {
1491 return 0;
1492 }
1493 /* get socket type */
1494 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1495 {
1496 case SOCK_STREAM:
1497 case SOCK_SEQPACKET:
1498 return 1;
1499 break;
1500
1501 default:
1502 return 0;
1503 break;
1504 }
1505 }
1506 }
1507 return 0;
1508}
1509
Dave Wallacee22aa742017-10-20 12:30:38 -04001510static inline ssize_t
1511vcom_session_sendto (int __sid, void *__buf, size_t __n,
1512 int __flags, __CONST_SOCKADDR_ARG __addr,
1513 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001514{
Dave Wallace617dffa2017-10-26 14:47:06 -04001515 vppcom_endpt_t *ep = 0;
Stevenac1f96d2017-10-24 16:03:58 -07001516
Dave Wallace617dffa2017-10-26 14:47:06 -04001517 if (__addr)
Stevenac1f96d2017-10-24 16:03:58 -07001518 {
Dave Wallace617dffa2017-10-26 14:47:06 -04001519 vppcom_endpt_t _ep;
Stevenac1f96d2017-10-24 16:03:58 -07001520
Dave Wallace617dffa2017-10-26 14:47:06 -04001521 ep = &_ep;
1522 ep->vrf = VPPCOM_VRF_DEFAULT;
1523 switch (__addr->sa_family)
1524 {
1525 case AF_INET:
1526 ep->is_ip4 = VPPCOM_IS_IP4;
1527 ep->ip =
1528 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1529 ep->port =
1530 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1531 break;
Stevenac1f96d2017-10-24 16:03:58 -07001532
Dave Wallace617dffa2017-10-26 14:47:06 -04001533 case AF_INET6:
1534 ep->is_ip4 = VPPCOM_IS_IP6;
1535 ep->ip =
1536 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1537 ep->port =
1538 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1539 break;
1540
1541 default:
1542 return -EAFNOSUPPORT;
1543 }
Stevenac1f96d2017-10-24 16:03:58 -07001544 }
1545
Dave Wallace617dffa2017-10-26 14:47:06 -04001546 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001547}
1548
1549ssize_t
1550vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1551 int __flags, __CONST_SOCKADDR_ARG __addr,
1552 socklen_t __addr_len)
1553{
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001554 vcom_socket_main_t *vsm = &vcom_socket_main;
1555 uword *p;
1556 vcom_socket_t *vsock;
1557
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001558 if (!__buf)
1559 {
1560 return -EINVAL;
1561 }
1562
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001563 p = hash_get (vsm->sockidx_by_fd, __fd);
1564 if (!p)
1565 return -EBADF;
1566
1567 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1568 if (!vsock)
1569 return -ENOTSOCK;
1570
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001571 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001572 {
1573 return -EINVAL;
1574 }
1575
1576 if (vcom_socket_is_connection_mode_socket (__fd))
1577 {
1578 /* ignore __addr and _addr_len */
1579 /* and EISCONN may be returned when they are not NULL and 0 */
1580 if ((__addr != NULL) || (__addr_len != 0))
1581 {
1582 return -EISCONN;
1583 }
1584 }
1585 else
1586 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001587 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001588 {
1589 return -EDESTADDRREQ;
1590 }
1591 /* not a vppcom supported address family */
Dave Wallace60f54822017-10-24 20:47:45 -04001592 if (!((__addr->sa_family == AF_INET) ||
1593 (__addr->sa_family == AF_INET6)))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001594 {
1595 return -EINVAL;
1596 }
1597 }
1598
Dave Wallace617dffa2017-10-26 14:47:06 -04001599 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1600 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001601}
1602
Dave Wallacee22aa742017-10-20 12:30:38 -04001603static inline ssize_t
1604vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1605 int __flags, __SOCKADDR_ARG __addr,
1606 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001607{
Stevenac1f96d2017-10-24 16:03:58 -07001608 int rv;
1609 vppcom_endpt_t ep;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001610 u8 src_addr[sizeof (struct sockaddr_in6)];
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001611
Stevenac1f96d2017-10-24 16:03:58 -07001612 if (__addr)
1613 {
Dave Wallacefaf9d772017-10-26 16:12:04 -04001614 ep.ip = src_addr;
Stevenac1f96d2017-10-24 16:03:58 -07001615 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1616
1617 if (rv > 0)
1618 {
1619 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1620 {
1621 __addr->sa_family =
1622 ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1623 switch (__addr->sa_family)
1624 {
1625 case AF_INET:
1626 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001627 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
1628 src_addr, sizeof (struct in_addr));
1629
Stevenac1f96d2017-10-24 16:03:58 -07001630 *__addr_len = sizeof (struct sockaddr_in);
1631 break;
1632
1633 case AF_INET6:
1634 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001635 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1636 __in6_u.__u6_addr8, src_addr,
1637 sizeof (struct in6_addr));
Stevenac1f96d2017-10-24 16:03:58 -07001638 *__addr_len = sizeof (struct sockaddr_in6);
1639 break;
1640
1641 default:
Dave Wallacefaf9d772017-10-26 16:12:04 -04001642 rv = -EAFNOSUPPORT;
Stevenac1f96d2017-10-24 16:03:58 -07001643 break;
1644 }
1645 }
1646 else
1647 rv = -1;
1648 }
1649 }
1650 else
1651 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1652
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001653 return rv;
1654}
1655
1656ssize_t
1657vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1658 int __flags, __SOCKADDR_ARG __addr,
1659 socklen_t * __restrict __addr_len)
1660{
1661 int rv = -1;
1662 vcom_socket_main_t *vsm = &vcom_socket_main;
1663 uword *p;
1664 vcom_socket_t *vsock;
1665
Stevenac1f96d2017-10-24 16:03:58 -07001666 if (__addr && !__addr_len)
1667 return -EINVAL;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001668
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001669 p = hash_get (vsm->sockidx_by_fd, __fd);
1670 if (!p)
1671 return -EBADF;
1672
1673 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1674 if (!vsock)
1675 return -ENOTSOCK;
1676
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001677 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001678 {
1679 return -EINVAL;
1680 }
1681
Dave Wallacee22aa742017-10-20 12:30:38 -04001682 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1683 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001684 return rv;
1685}
1686
1687/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001688static inline ssize_t
1689vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001690{
1691 int rv = -1;
1692 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1693 (int)__n); */
1694 return rv;
1695}
1696
1697ssize_t
1698vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1699{
1700 int rv = -1;
1701 vcom_socket_main_t *vsm = &vcom_socket_main;
1702 uword *p;
1703 vcom_socket_t *vsock;
1704
1705 p = hash_get (vsm->sockidx_by_fd, __fd);
1706 if (!p)
1707 return -EBADF;
1708
1709 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1710 if (!vsock)
1711 return -ENOTSOCK;
1712
1713 if (vcom_socket_is_connection_mode_socket (__fd))
1714 {
1715 /* ignore __addr and _addr_len */
1716 /* and EISCONN may be returned when they are not NULL and 0 */
1717 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1718 {
1719 return -EISCONN;
1720 }
1721 }
1722 else
1723 {
1724 /* TBD: validate __message->msg_name and __message->msg_namelen
1725 * and return -EINVAL on validation error
1726 * */
1727 ;
1728 }
1729
Dave Wallacee22aa742017-10-20 12:30:38 -04001730 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001731
1732 return rv;
1733}
1734
1735#ifdef __USE_GNU
1736int
1737vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1738 unsigned int __vlen, int __flags)
1739{
1740
1741 /* TBD: define a new vppcom api */
1742 return 0;
1743}
1744#endif
1745
1746/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001747static inline ssize_t
1748vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001749{
1750 int rv = -1;
1751 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1752 (int)__n); */
1753 rv = -EOPNOTSUPP;
1754 return rv;
1755}
1756
1757ssize_t
1758vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1759{
1760 int rv = -1;
1761 vcom_socket_main_t *vsm = &vcom_socket_main;
1762 uword *p;
1763 vcom_socket_t *vsock;
1764
1765 p = hash_get (vsm->sockidx_by_fd, __fd);
1766 if (!p)
1767 return -EBADF;
1768
1769 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1770 if (!vsock)
1771 return -ENOTSOCK;
1772
1773 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1774 return -EINVAL;
1775
1776 if (!__message)
1777 {
1778 return -EINVAL;
1779 }
1780
1781 /* validate __flags */
1782
Dave Wallacee22aa742017-10-20 12:30:38 -04001783 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001784 return rv;
1785}
1786
1787#ifdef __USE_GNU
1788int
1789vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1790 unsigned int __vlen, int __flags,
1791 struct timespec *__tmo)
1792{
1793 /* TBD: define a new vppcom api */
1794 return 0;
1795}
1796#endif
1797
1798/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001799static inline int
1800vcom_session_get_sockopt (int __sid, int __level, int __optname,
1801 void *__restrict __optval,
1802 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001803{
Stevenac1f96d2017-10-24 16:03:58 -07001804 int rv = 0;
1805
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001806 /* 1. for socket level options that are NOT socket attributes
1807 * and that has corresponding vpp options get from vppcom */
Stevenac1f96d2017-10-24 16:03:58 -07001808 switch (__level)
1809 {
1810 case SOL_SOCKET:
1811 switch (__optname)
1812 {
1813 case SO_ERROR:
1814 *(int *) __optval = 0;
1815 break;
1816 default:
1817 break;
1818 }
1819 default:
1820 break;
1821 }
1822 /* 2. unhandled options */
1823 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001824}
1825
1826int
1827vcom_socket_getsockopt (int __fd, int __level, int __optname,
1828 void *__restrict __optval,
1829 socklen_t * __restrict __optlen)
1830{
1831 int rv = -1;
1832 vcom_socket_main_t *vsm = &vcom_socket_main;
1833 uword *p;
1834 vcom_socket_t *vsock;
1835
Dave Wallacefaf9d772017-10-26 16:12:04 -04001836 if (!__optval || !__optlen)
1837 return -EINVAL;
1838
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001839 p = hash_get (vsm->sockidx_by_fd, __fd);
1840 if (!p)
1841 return -EBADF;
1842
1843 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1844 if (!vsock)
1845 return -ENOTSOCK;
1846
1847 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1848 return -EINVAL;
1849
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001850 switch (__level)
1851 {
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001852 case SOL_SOCKET:
1853 switch (__optname)
1854 {
1855/*
1856 * 1. for socket level options that are socket attributes,
1857 * get from libc_getsockopt.
1858 * 2. for socket level options that are NOT socket
1859 * attributes and that has corresponding vpp options
1860 * get from vppcom.
1861 * 3. for socket level options unimplemented
1862 * return -ENOPROTOOPT */
1863 case SO_DEBUG:
1864 case SO_DONTROUTE:
1865 case SO_BROADCAST:
1866 case SO_SNDBUF:
1867 case SO_RCVBUF:
1868 case SO_REUSEADDR:
1869 case SO_REUSEPORT:
1870 case SO_KEEPALIVE:
1871 case SO_TYPE:
1872 case SO_PROTOCOL:
1873 case SO_DOMAIN:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001874 case SO_OOBINLINE:
1875 case SO_NO_CHECK:
1876 case SO_PRIORITY:
1877 case SO_LINGER:
1878 case SO_BSDCOMPAT:
1879 case SO_TIMESTAMP:
1880 case SO_TIMESTAMPNS:
1881 case SO_TIMESTAMPING:
1882 case SO_RCVTIMEO:
1883 case SO_SNDTIMEO:
1884 case SO_RCVLOWAT:
1885 case SO_SNDLOWAT:
1886 case SO_PASSCRED:
1887 case SO_PEERCRED:
1888 case SO_PEERNAME:
1889 case SO_ACCEPTCONN:
1890 case SO_PASSSEC:
1891 case SO_PEERSEC:
1892 case SO_MARK:
1893 case SO_RXQ_OVFL:
1894 case SO_WIFI_STATUS:
1895 case SO_PEEK_OFF:
1896 case SO_NOFCS:
1897 case SO_BINDTODEVICE:
1898 case SO_GET_FILTER:
1899 case SO_LOCK_FILTER:
1900 case SO_BPF_EXTENSIONS:
1901 case SO_SELECT_ERR_QUEUE:
1902#ifdef CONFIG_NET_RX_BUSY_POLL
1903 case SO_BUSY_POLL:
1904#endif
1905 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001906#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001907 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001908#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001909 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1910 if (rv != 0)
1911 {
1912 rv = -errno;
1913 return rv;
1914 }
1915 break;
1916
Stevenac1f96d2017-10-24 16:03:58 -07001917 case SO_ERROR:
1918 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1919 __optval, __optlen);
1920 break;
1921
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001922 default:
1923 /* We implement the SO_SNDLOWAT etc to not be settable
1924 * (1003.1g 7).
1925 */
1926 return -ENOPROTOOPT;
1927 }
1928
1929 break;
1930
1931 default:
1932 /* 1. handle options that are NOT socket level options,
1933 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04001934 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1935 __optval, __optlen);
1936 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001937 }
1938
1939 return rv;
1940}
1941
1942/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001943static inline int
1944vcom_session_setsockopt (int __sid, int __level, int __optname,
1945 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001946{
Stevenb59f2272017-10-12 17:10:33 -07001947 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001948
Stevenb59f2272017-10-12 17:10:33 -07001949 switch (__level)
1950 {
Stevenbd187a82017-10-13 12:52:28 -07001951 case SOL_TCP:
1952 switch (__optname)
1953 {
1954 case TCP_KEEPIDLE:
1955 rv =
1956 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1957 break;
1958 case TCP_KEEPINTVL:
1959 rv =
1960 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1961 break;
1962 default:
1963 break;
1964 }
1965 break;
Stevenb59f2272017-10-12 17:10:33 -07001966 case SOL_IPV6:
1967 switch (__optname)
1968 {
1969 case IPV6_V6ONLY:
1970 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001971 break;
Stevenb59f2272017-10-12 17:10:33 -07001972 default:
Stevenbd187a82017-10-13 12:52:28 -07001973 break;
Stevenb59f2272017-10-12 17:10:33 -07001974 }
1975 break;
1976 case SOL_SOCKET:
1977 switch (__optname)
1978 {
Stevenbd187a82017-10-13 12:52:28 -07001979 case SO_KEEPALIVE:
1980 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1981 break;
Stevenb59f2272017-10-12 17:10:33 -07001982 case SO_REUSEADDR:
1983 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001984 break;
Stevenb59f2272017-10-12 17:10:33 -07001985 case SO_BROADCAST:
1986 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001987 break;
Stevenb59f2272017-10-12 17:10:33 -07001988 default:
Stevenbd187a82017-10-13 12:52:28 -07001989 break;
Stevenb59f2272017-10-12 17:10:33 -07001990 }
1991 break;
1992 default:
Stevenbd187a82017-10-13 12:52:28 -07001993 break;
Stevenb59f2272017-10-12 17:10:33 -07001994 }
1995
1996 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001997}
1998
1999int
2000vcom_socket_setsockopt (int __fd, int __level, int __optname,
2001 const void *__optval, socklen_t __optlen)
2002{
2003 int rv = -1;
2004 vcom_socket_main_t *vsm = &vcom_socket_main;
2005 uword *p;
2006 vcom_socket_t *vsock;
2007
2008 p = hash_get (vsm->sockidx_by_fd, __fd);
2009 if (!p)
2010 return -EBADF;
2011
2012 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2013 if (!vsock)
2014 return -ENOTSOCK;
2015
2016 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2017 return -EINVAL;
2018
2019 /*
2020 * Options without arguments
2021 */
2022
2023 if (__optname == SO_BINDTODEVICE)
2024 {
2025 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2026 if (rv != 0)
2027 {
2028 rv = -errno;
2029 }
2030 return rv;
2031 }
2032
2033 if (!__optval)
2034 return -EFAULT;
2035
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002036 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002037 return -EINVAL;
2038
2039 switch (__level)
2040 {
Stevenb59f2272017-10-12 17:10:33 -07002041 case SOL_IPV6:
2042 switch (__optname)
2043 {
2044 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04002045 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2046 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002047 break;
Stevenb59f2272017-10-12 17:10:33 -07002048 default:
2049 return -EOPNOTSUPP;
2050 }
2051 break;
2052 case SOL_TCP:
2053 switch (__optname)
2054 {
2055 case TCP_NODELAY:
2056 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002057 case TCP_KEEPIDLE:
2058 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04002059 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2060 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002061 break;
Stevenb59f2272017-10-12 17:10:33 -07002062 default:
2063 return -EOPNOTSUPP;
2064 }
2065 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002066 /* handle options at socket level */
2067 case SOL_SOCKET:
2068 switch (__optname)
2069 {
Stevenb59f2272017-10-12 17:10:33 -07002070 case SO_REUSEADDR:
2071 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002072 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04002073 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2074 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002075 break;
Stevenb59f2272017-10-12 17:10:33 -07002076
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002077 /*
2078 * 1. for socket level options that are socket attributes,
2079 * set it from libc_getsockopt
2080 * 2. for socket level options that are NOT socket
2081 * attributes and that has corresponding vpp options
2082 * set it from vppcom
2083 * 3. for socket level options unimplemented
2084 * return -ENOPROTOOPT */
2085 case SO_DEBUG:
2086 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002087 case SO_SNDBUF:
2088 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002089 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002090 case SO_TYPE:
2091 case SO_PROTOCOL:
2092 case SO_DOMAIN:
2093 case SO_ERROR:
2094 case SO_OOBINLINE:
2095 case SO_NO_CHECK:
2096 case SO_PRIORITY:
2097 case SO_LINGER:
2098 case SO_BSDCOMPAT:
2099 case SO_TIMESTAMP:
2100 case SO_TIMESTAMPNS:
2101 case SO_TIMESTAMPING:
2102 case SO_RCVTIMEO:
2103 case SO_SNDTIMEO:
2104 case SO_RCVLOWAT:
2105 case SO_SNDLOWAT:
2106 case SO_PASSCRED:
2107 case SO_PEERCRED:
2108 case SO_PEERNAME:
2109 case SO_ACCEPTCONN:
2110 case SO_PASSSEC:
2111 case SO_PEERSEC:
2112 case SO_MARK:
2113 case SO_RXQ_OVFL:
2114 case SO_WIFI_STATUS:
2115 case SO_PEEK_OFF:
2116 case SO_NOFCS:
2117 /*
2118 * SO_BINDTODEVICE already handled as
2119 * "Options without arguments" */
2120 /* case SO_BINDTODEVICE: */
2121 case SO_GET_FILTER:
2122 case SO_LOCK_FILTER:
2123 case SO_BPF_EXTENSIONS:
2124 case SO_SELECT_ERR_QUEUE:
2125#ifdef CONFIG_NET_RX_BUSY_POLL
2126 case SO_BUSY_POLL:
2127#endif
2128 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002129#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002130 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002131#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002132 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2133 if (rv != 0)
2134 {
2135 rv = -errno;
2136 return rv;
2137 }
2138 break;
2139
2140 default:
2141 /* We implement the SO_SNDLOWAT etc to not be settable
2142 * (1003.1g 7).
2143 */
2144 return -ENOPROTOOPT;
2145 }
2146
2147 break;
2148
2149 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002150 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002151 }
2152
2153 return rv;
2154}
2155
2156int
2157vcom_socket_listen (int __fd, int __n)
2158{
2159 int rv = -1;
2160 vcom_socket_main_t *vsm = &vcom_socket_main;
2161 uword *p;
2162 vcom_socket_t *vsock;
2163
2164 p = hash_get (vsm->sockidx_by_fd, __fd);
2165 if (p)
2166 {
2167 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2168
2169 /* TBD vppcom to accept __n parameter */
2170 rv = vppcom_session_listen (vsock->sid, __n);
2171 }
2172
2173 return rv;
2174}
2175
2176static int
2177vcom_socket_connected_socket (int __fd, int __sid,
2178 int *__domain,
2179 int *__type, int *__protocol, int flags)
2180{
2181 int rv = -1;
2182 vcom_socket_main_t *vsm = &vcom_socket_main;
2183 vcom_socket_t *vsock;
2184
2185 i32 fd;
2186 i32 sockidx;
2187
2188 socklen_t optlen;
2189
2190 optlen = sizeof (*__domain);
2191 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2192 if (rv != 0)
2193 {
2194 rv = -errno;
2195 goto out;
2196 }
2197
2198 optlen = sizeof (*__type);
2199 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2200 if (rv != 0)
2201 {
2202 rv = -errno;
2203 goto out;
2204 }
2205
2206 optlen = sizeof (*__protocol);
2207 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2208 if (rv != 0)
2209 {
2210 rv = -errno;
2211 goto out;
2212 }
2213
2214 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2215 if (fd < 0)
2216 {
2217 rv = fd;
2218 goto out;
2219 }
2220
2221 pool_get (vsm->vsockets, vsock);
2222 vsocket_init (vsock);
2223
2224 sockidx = vsock - vsm->vsockets;
2225 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2226
2227 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2228 return fd;
2229
2230out:
2231 return rv;
2232}
2233
2234/* If flag is 0, then accept4() is the same as accept().
2235 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2236 */
2237static int
2238vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2239 socklen_t * __restrict __addr_len, int flags)
2240{
2241 int rv = -1;
2242 vcom_socket_main_t *vsm = &vcom_socket_main;
2243 uword *p;
2244 vcom_socket_t *vsock;
2245
2246 int fd;
2247 int sid;
2248 int domain;
2249 int type;
2250 int protocol;
2251
2252 uint8_t addr8[sizeof (struct in6_addr)];
2253 vppcom_endpt_t ep;
2254
2255 ep.ip = addr8;
2256
2257 /* validate flags */
2258
2259 /*
2260 * for documentation
2261 * switch (flags)
2262 * {
2263 * case 0:
2264 * case SOCK_NONBLOCK:
2265 * case SOCK_CLOEXEC:
2266 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2267 * break;
2268 *
2269 * default:
2270 * return -1;
2271 * }
2272 */
2273 /* flags can be 0 or can be bitwise OR
2274 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2275
2276 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2277 {
2278 /* TBD: return proper error code */
2279 return -1;
2280 }
2281
2282 /* TBD: return proper error code */
2283
2284 if (!vcom_socket_is_connection_mode_socket (__fd))
2285 {
2286 return -EOPNOTSUPP;
2287 }
2288
2289 p = hash_get (vsm->sockidx_by_fd, __fd);
2290 if (p)
2291 {
2292 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2293
2294
2295 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2296 if (rv < 0)
2297 {
2298 return rv;
2299 }
2300
2301 /* is blocking */
2302 if (!(rv & O_NONBLOCK))
2303 {
2304 /* socket is not marked as nonblocking
2305 * and no pending connections are present
2306 * on the queue, accept () blocks the caller
2307 * until a connection is present.
2308 */
2309 rv = vppcom_session_accept (vsock->sid, &ep,
2310 -1.0 /* wait forever */ );
2311 }
2312 else
2313 {
2314 /* The file descriptor refers to a socket and has been
2315 * marked nonblocking(O_NONBLOCK) and the accept would
2316 * block.
2317 * */
2318 /* is non blocking */
2319 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2320 /* If the socket is marked nonblocking and
2321 * no pending connections are present on the
2322 * queue, accept fails with the error
2323 * EAGAIN or EWOULDBLOCK
2324 */
2325 if (rv == VPPCOM_ETIMEDOUT)
2326 {
2327 rv = VPPCOM_EAGAIN;
2328 }
2329 }
2330 if (rv < 0)
2331 {
2332 return rv;
2333 }
2334
2335 sid = rv;
2336
2337 /* create a new connected socket resource and set flags
2338 * on the new file descriptor.
2339 * update vsockets and sockidx_by_fd table
2340 * */
2341 fd = vcom_socket_connected_socket (__fd, sid,
2342 &domain, &type, &protocol, flags);
2343 if (fd < 0)
2344 {
2345 return fd;
2346 }
2347
2348 rv = fd;
2349
2350 /* TBD populate __addr and __addr_len */
2351 /* TBD: The returned address is truncated if the buffer
2352 * provided is too small, in this case, __addr_len will
2353 * return a value greater than was supplied to the call.*/
2354 if (__addr)
2355 {
2356 if (ep.is_cut_thru)
2357 {
2358 /* TBD populate __addr and __addr_len */
2359 switch (domain)
2360 {
2361 case AF_INET:
2362 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2363 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2364 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2365 addr8, sizeof (struct in_addr));
2366 /* TBD: populate __addr_len */
2367 if (__addr_len)
2368 {
2369 *__addr_len = sizeof (struct sockaddr_in);
2370 }
2371 break;
2372
2373 case AF_INET6:
2374 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2375 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2376 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2377 __in6_u.__u6_addr8, addr8,
2378 sizeof (struct in6_addr));
2379 /* TBD: populate __addr_len */
2380 if (__addr_len)
2381 {
2382 *__addr_len = sizeof (struct sockaddr_in6);
2383 }
2384 break;
2385
2386 default:
2387 return -EAFNOSUPPORT;
2388 }
2389 }
2390 else
2391 {
2392 switch (ep.is_ip4)
2393 {
2394 case VPPCOM_IS_IP4:
2395 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2396 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2397 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2398 addr8, sizeof (struct in_addr));
2399 /* TBD: populate __addr_len */
2400 if (__addr_len)
2401 {
2402 *__addr_len = sizeof (struct sockaddr_in);
2403 }
2404 break;
2405
2406 case VPPCOM_IS_IP6:
2407 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2408 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2409 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2410 __in6_u.__u6_addr8, addr8,
2411 sizeof (struct in6_addr));
2412 /* TBD: populate __addr_len */
2413 if (__addr_len)
2414 {
2415 *__addr_len = sizeof (struct sockaddr_in6);
2416 }
2417 break;
2418
2419 default:
2420 return -EAFNOSUPPORT;
2421 }
2422 }
2423 }
2424 else
2425 {
2426 /* when __addr is NULL, nothing is filled in,
2427 * in this case, __addr_len is not used,
2428 * and should also be null
2429 * */
2430 if (__addr_len)
2431 {
2432 /* TBD: return proper error code */
2433 return -1;
2434 }
2435 }
2436 }
2437
2438 return rv;
2439}
2440
2441int
2442vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2443 socklen_t * __restrict __addr_len)
2444{
2445 /* set flags to 0 for accept() */
2446 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2447}
2448
2449#ifdef __USE_GNU
2450int
2451vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2452 socklen_t * __restrict __addr_len, int __flags)
2453{
2454 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2455 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2456}
2457#endif
2458
2459/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002460static inline int
2461vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002462{
2463 return 0;
2464}
2465
2466int
2467vcom_socket_shutdown (int __fd, int __how)
2468{
2469 int rv = -1;
2470 vcom_socket_main_t *vsm = &vcom_socket_main;
2471 uword *p;
2472 vcom_socket_t *vsock;
2473
2474 p = hash_get (vsm->sockidx_by_fd, __fd);
2475 if (p)
2476 {
2477 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2478 switch (__how)
2479 {
2480 case SHUT_RD:
2481 case SHUT_WR:
2482 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002483 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002484 return rv;
2485 break;
2486
2487 default:
2488 return -EINVAL;
2489 break;
2490 }
2491 }
2492
2493 return rv;
2494}
2495
2496int
2497vcom_socket_epoll_create1 (int __flags)
2498{
2499 int rv = -1;
2500 vcom_socket_main_t *vsm = &vcom_socket_main;
2501 vcom_epoll_t *vepoll;
2502
2503 i32 epfd;
2504 i32 vep_idx;
2505 i32 epollidx;
2506
2507 epfd = vcom_socket_open_epoll (__flags);
2508 if (epfd < 0)
2509 {
2510 rv = epfd;
2511 goto out;
2512 }
2513
2514 vep_idx = vppcom_epoll_create ();
2515 if (vep_idx < 0)
2516 {
2517 rv = vep_idx;
2518 goto out_close_epoll;
2519 }
2520
2521 pool_get (vsm->vepolls, vepoll);
2522 vepoll_init (vepoll);
2523
2524 epollidx = vepoll - vsm->vepolls;
2525 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2526
2527 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2528
2529 return epfd;
2530
2531out_close_epoll:
2532 vcom_socket_close_epoll (epfd);
2533out:
2534 return rv;
2535}
2536
2537/*
2538 * PRE: vppcom_epoll_ctl() is successful
2539 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2540 */
2541int
2542vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2543 struct epoll_event *__event,
2544 i32 vep_idx, vcom_epoll_t * vepoll,
2545 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2546 int free_vepitem_on_del)
2547{
2548 int rv = -1;
2549 vcom_socket_main_t *vsm = &vcom_socket_main;
2550 vcom_epitem_t *vepitem;
2551
2552 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2553 uword *p;
2554 i32 vepitemidx;
2555
2556 i32 *vepitemidxs = 0;
2557
2558 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2559
2560 i32 vec_idx;
2561
2562 /* perform control operations on the epoll instance */
2563 switch (__op)
2564 {
2565 case EPOLL_CTL_ADD:
2566 /*
2567 * supplied file descriptor is already
2568 * registered with this epoll instance
2569 * */
2570 /* vepitem exists */
2571 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2572 if (p)
2573 {
2574 rv = -EEXIST;
2575 goto out;
2576 }
2577
2578 /* add a new vepitem */
2579 pool_get (vsm->vepitems, vepitem);
2580 vepitem_init (vepitem);
2581
2582 vepitemidx = vepitem - vsm->vepitems;
2583 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2584 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2585
2586 /* update epitemidxs */
2587 /* by_epfd */
2588 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2589 if (!p) /* not exist */
2590 {
2591 vepitemidxs = 0;
2592 vec_add1 (vepitemidxs, vepitemidx);
2593 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2594 }
2595 else /* exists */
2596 {
2597 vepitemidxs = *(i32 **) p;
2598 vec_add1 (vepitemidxs, vepitemidx);
2599 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2600 }
2601 /* update epitemidxs */
2602 /* by_fd */
2603 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2604 if (!p) /* not exist */
2605 {
2606 vepitemidxs = 0;
2607 vec_add1 (vepitemidxs, vepitemidx);
2608 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2609 }
2610 else /* exists */
2611 {
2612 vepitemidxs = *(i32 **) p;
2613 vec_add1 (vepitemidxs, vepitemidx);
2614 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2615 }
2616
2617 /* increment vepoll fd count by 1 */
2618 vepoll->count += 1;
2619
2620 rv = 0;
2621 goto out;
2622 break;
2623
2624 case EPOLL_CTL_MOD:
2625 /*
2626 * supplied file descriptor is not
2627 * registered with this epoll instance
2628 * */
2629 /* vepitem not exist */
2630 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2631 if (!p)
2632 {
2633 rv = -ENOENT;
2634 goto out;
2635 }
2636 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2637 if (vepitem)
2638 {
2639 vepitem->event = *__event;
2640 vepitem->revent = revent;
2641 }
2642
2643 rv = 0;
2644 goto out;
2645 break;
2646
2647 case EPOLL_CTL_DEL:
2648 /*
2649 * supplied file descriptor is not
2650 * registered with this epoll instance
2651 * */
2652 /* vepitem not exist */
2653 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2654 if (!p)
2655 {
2656 rv = -ENOENT;
2657 goto out;
2658 }
2659 vepitemidx = *(i32 *) p;
2660 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2661
2662 /* update epitemidxs */
2663 /* by_epfd */
2664 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2665 if (!p) /* not exist */
2666 {
2667 rv = -ENOENT;
2668 goto out;
2669 }
2670 else /* exists */
2671 {
2672 vepitemidxs = *(i32 **) p;
2673 vec_idx = vec_search (vepitemidxs, vepitemidx);
2674 if (vec_idx != ~0)
2675 {
2676 vec_del1 (vepitemidxs, vec_idx);
2677 if (!vec_len (vepitemidxs))
2678 {
2679 vec_free (vepitemidxs);
2680 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2681 }
2682 }
2683 }
2684
2685 /* update epitemidxs */
2686 /* by_fd */
2687 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2688 if (!p) /* not exist */
2689 {
2690 rv = -ENOENT;
2691 goto out;
2692 }
2693 else /* exists */
2694 {
2695 vepitemidxs = *(i32 **) p;
2696 vec_idx = vec_search (vepitemidxs, vepitemidx);
2697 if (vec_idx != ~0)
2698 {
2699 vec_del1 (vepitemidxs, vec_idx);
2700 if (!vec_len (vepitemidxs))
2701 {
2702 vec_free (vepitemidxs);
2703 hash_unset (vsm->epitemidxs_by_fd, __fd);
2704 }
2705 }
2706 }
2707
2708 /* pool put vepitem */
2709 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2710 if (free_vepitem_on_del)
2711 {
2712 if (!vepitem)
2713 {
2714 rv = -ENOENT;
2715 goto out;
2716 }
2717 vepitem_init (vepitem);
2718 pool_put (vsm->vepitems, vepitem);
2719 }
2720 else
2721 {
2722 if (!vepitem)
2723 {
2724 vepitem_init (vepitem);
2725 }
2726 }
2727
2728 /* decrement vepoll fd count by 1 */
2729 vepoll->count -= 1;
2730
2731 rv = 0;
2732 goto out;
2733 break;
2734
2735 default:
2736 rv = -EINVAL;
2737 goto out;
2738 break;
2739 }
2740
2741out:
2742 return rv;
2743}
2744
2745/*
2746 * PRE: 00. null pointer check on __event
2747 * 01. all other parameters are validated
2748 */
2749
2750static int
2751vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2752 struct epoll_event *__event,
2753 int free_vepitem_on_del)
2754{
2755 int rv = -1;
2756
2757 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2758 vcom_epoll_t *vepoll;
2759
2760 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2761 void *vfd;
2762 vcom_epoll_t *vfd_vepoll;
2763 vcom_socket_t *vfd_vsock;
2764
2765 i32 vep_idx;
2766 i32 vfd_id;
2767
2768 vcom_fd_type_t type = FD_TYPE_INVALID;
2769
2770 /* validate __event */
2771
2772 /* get vep_idx and vepoll */
2773 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2774 if (vep_idx == INVALID_VEP_IDX)
2775 {
2776 return -EBADF;
2777 }
2778
2779 /* get vcom fd type, vfd_id and vfd */
2780 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2781 if (vfd_id != INVALID_SESSION_ID)
2782 {
2783 type = FD_TYPE_VCOM_SOCKET;
2784 vfd = vfd_vsock;
2785 }
2786 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2787 != INVALID_VEP_IDX)
2788 {
2789 type = FD_TYPE_EPOLL;
2790 vfd = vfd_vepoll;
2791 }
2792 else
2793 {
2794 /* FD_TYPE_KERNEL not supported by epoll instance */
2795 type = FD_TYPE_INVALID;
2796 return -EBADF;
2797 }
2798
2799
2800 /* vepoll and vsock are now valid */
2801 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2802 if (rv < 0)
2803 {
2804 return rv;
2805 }
2806
2807 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2808 __event,
2809 vep_idx, vepoll,
2810 vfd_id, vfd, type, free_vepitem_on_del);
2811 return rv;
2812}
2813
2814int
2815vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2816 struct epoll_event *__event)
2817{
2818 int rv = -1;
2819
2820 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2821 return rv;
2822}
2823
2824static int
2825vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2826 struct epoll_event *__event)
2827{
2828 int rv = -1;
2829
2830 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2831 return rv;
2832}
2833
2834int
2835vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2836 int __maxevents, int __timeout,
2837 const __sigset_t * __ss)
2838{
2839 int rv = -EBADF;
2840
2841 /* in seconds eg. 3.123456789 seconds */
2842 double time_to_wait = (double) 0;
2843
2844 i32 vep_idx;
2845
2846 /* validate __event */
2847 if (!__events)
2848 {
2849 rv = -EFAULT;
2850 goto out;
2851 }
2852
2853 /* validate __timeout */
2854 if (__timeout > 0)
2855 {
2856 time_to_wait = (double) __timeout / (double) 1000;
2857 }
2858 else if (__timeout == 0)
2859 {
2860 time_to_wait = (double) 0;
2861 }
2862 else if (__timeout == -1)
2863 {
2864 time_to_wait = ~0;
2865 }
2866 else
2867 {
2868 rv = -EBADF;
2869 goto out;
2870 }
2871
2872 /* get vep_idx */
2873 vep_idx = vcom_socket_get_vep_idx (__epfd);
2874 if (vep_idx != INVALID_VEP_IDX)
2875 {
2876 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2877 }
2878out:
2879 return rv;
2880}
2881
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002882static inline void
2883vcom_pollfds_2_selectfds (
2884 /* src */
2885 struct pollfd *__fds, nfds_t __nfds,
2886 /* dest */
2887 int vcom_nfds,
2888 fd_set * __restrict vcom_readfds,
2889 fd_set * __restrict vcom_writefds,
2890 fd_set * __restrict vcom_exceptfds)
2891{
2892 nfds_t fds_idx = 0;
2893
2894 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2895 {
2896 /* ignore negative fds */
2897 if (__fds[fds_idx].fd < 0)
2898 {
2899 continue;
2900 }
2901
2902 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2903 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2904
2905 /* requested events */
2906 if (__fds[fds_idx].events)
2907 {
2908 if (__fds[fds_idx].events & POLLIN)
2909 {
2910 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2911 }
2912 if (__fds[fds_idx].events & POLLPRI)
2913 {
2914 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2915 }
2916 if (__fds[fds_idx].events & POLLOUT)
2917 {
2918 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2919 }
2920#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2921 if (__fds[fds_idx].events & POLLRDNORM)
2922 {
2923 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2924 }
2925 if (__fds[fds_idx].events & POLLRDBAND)
2926 {
2927 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2928 }
2929 if (__fds[fds_idx].events & POLLWRNORM)
2930 {
2931 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2932 }
2933 if (__fds[fds_idx].events & POLLWRBAND)
2934 {
2935 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2936 }
2937#endif
2938 }
2939 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2940}
2941
2942static inline void
2943vcom_selectfds_2_pollfds (
2944 /* dest */
2945 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2946 /* src */
2947 int vcom_nfds,
2948 fd_set * __restrict vcom_readfds,
2949 fd_set * __restrict vcom_writefds,
2950 fd_set * __restrict vcom_exceptfds)
2951{
2952 nfds_t fds_idx = 0;
2953
2954
2955 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2956 {
2957 /* ignore negative fds */
2958 if (__fds[fds_idx].fd < 0)
2959 {
2960 __fds[fds_idx].revents = 0;
2961 }
2962
2963 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2964 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2965 {
2966 /*
2967 * TBD: for now any select exception
2968 * is flagged as POLLERR
2969 * */
2970 __fds[fds_idx].revents |= POLLERR;
2971 }
2972
2973 /* requested events */
2974 if (__fds[fds_idx].events & POLLIN)
2975 {
2976 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2977 {
2978 __fds[fds_idx].revents |= POLLIN;
2979 }
2980 }
2981 if (__fds[fds_idx].events & POLLPRI)
2982 {
2983 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2984 {
2985 __fds[fds_idx].revents |= POLLIN;
2986 }
2987 }
2988 if (__fds[fds_idx].events & POLLOUT)
2989 {
2990 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2991 {
2992 __fds[fds_idx].revents |= POLLOUT;
2993 }
2994 }
2995#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2996 if (__fds[fds_idx].events & POLLRDNORM)
2997 {
2998 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2999 {
3000 __fds[fds_idx].revents |= POLLRDNORM;
3001 }
3002 }
3003 if (__fds[fds_idx].events & POLLRDBAND)
3004 {
3005 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3006 {
3007 __fds[fds_idx].revents |= POLLRDBAND;
3008 }
3009 }
3010 if (__fds[fds_idx].events & POLLWRNORM)
3011 {
3012 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3013 {
3014 __fds[fds_idx].revents |= POLLWRNORM;
3015 }
3016 }
3017 if (__fds[fds_idx].events & POLLWRBAND)
3018 {
3019 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3020 {
3021 __fds[fds_idx].revents |= POLLWRBAND;
3022 }
3023 }
3024#endif
3025 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3026
3027 /*
3028 * nfd:
3029 * the number of structures which have nonzero revents fields
3030 * (in other words, those descriptors with events or
3031 * errors reported)
3032 * */
3033 *nfd = 0;
3034 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3035 {
3036 /* ignore negative fds */
3037 if (__fds[fds_idx].fd < 0)
3038 {
3039 continue;
3040 }
3041
3042 if (__fds[fds_idx].revents)
3043 {
3044 (*nfd)++;
3045 }
3046 }
3047}
3048
3049/*
3050 * PRE: parameters are validated,
3051 * vcom_socket_poll is always called with __timeout set to zero
3052 * hence returns immediately
3053 *
3054 * ACTION: handle non negative validated vcom fds and ignore rest
3055 */
3056
3057/*
3058 * implements vcom_socket_poll () interface
3059 *
3060 * internally uses vcom_socket_select ()
3061 * to realize the behavior
3062 * */
3063int
3064vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3065 int __timeout)
3066{
3067 int rv;
3068 pid_t pid = getpid ();
3069
3070 nfds_t fds_idx = 0;
3071 int nfd = 0;
3072
3073 /* vcom */
3074 int vcom_nfds = 0;
3075 fd_set vcom_readfds;
3076 fd_set vcom_writefds;
3077 fd_set vcom_exceptfds;
3078 int vcom_nfd = -1;
3079 /* invalid max_vcom_fd is -1 */
3080 int max_vcom_fd = -1;
3081
3082 /* __timeout is zero to get ready events and return immediately */
3083 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3084
3085 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003086 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003087 {
3088 rv = -EINVAL;
3089 goto poll_done;
3090 }
3091
3092 /* zero vcom fd sets */
3093 /*
3094 * V vcom fd set
3095 */
3096#define _(V) \
3097 FD_ZERO ((V))
3098
3099 _(&vcom_readfds);
3100 _(&vcom_writefds);
3101 _(&vcom_exceptfds);
3102#undef _
3103
3104 vcom_nfds = 0;
3105 vcom_nfd = -1;
3106
3107
3108 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3109 {
3110 /* ignore negative fds */
3111 if (__fds[fds_idx].fd < 0)
3112 {
3113 continue;
3114 }
3115
3116 /* non negative validated vcom fds */
3117 if (__fds[fds_idx].fd > FD_SETSIZE)
3118 {
3119 rv = -EINVAL;
3120 goto poll_done;
3121 }
3122
3123 /* max_vcom_fd and vcom_nfd */
3124 if (__fds[fds_idx].fd > max_vcom_fd)
3125 {
3126 /* requested events */
3127 if (__fds[fds_idx].events)
3128 {
3129 max_vcom_fd = __fds[fds_idx].fd;
3130 }
3131 }
3132 ++vcom_nfd;
3133 }
3134
3135 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3136
3137 if (!vcom_nfds)
3138 {
3139 rv = vcom_nfds;
3140 goto poll_done;
3141 }
3142
3143 vcom_pollfds_2_selectfds (
3144 /* src */
3145 __fds, __nfds,
3146 /* dest */
3147 vcom_nfds,
3148 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3149
3150 /* select on vcom fds */
3151 vcom_nfd = vcom_socket_select (vcom_nfds,
3152 &vcom_readfds,
3153 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003154 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003155 fprintf (stderr,
3156 "[%d] vcom_socket_select: "
3157 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3158
3159 if (vcom_nfd < 0)
3160 {
3161 rv = vcom_nfd;
3162 goto poll_done;
3163 }
3164
3165 vcom_selectfds_2_pollfds (
3166 /* dest */
3167 __fds, __nfds, &nfd,
3168 /* src */
3169 vcom_nfds,
3170 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3171
3172 rv = nfd;
3173
3174poll_done:
3175 return rv;
3176}
3177
3178/*
3179 * TBD: remove this static function once vppcom
3180 * has an implementation in place
3181 *
3182 * ACTION:
3183 */
3184static int
3185vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3186{
3187 return -EOPNOTSUPP;
3188}
3189
3190int
3191vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3192 int __timeout)
3193{
3194 nfds_t fds_idx = 0;
3195
3196 /* in seconds eg. 3.123456789 seconds */
3197 double time_to_wait = (double) 0;
3198
3199 i32 sid;
3200 i32 vep_idx;
3201
3202 /* replace vcom fd with session idx */
3203 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3204 {
3205 /* ignore negative fds */
3206 if (__fds[fds_idx].fd < 0)
3207 {
3208 continue;
3209 }
3210
3211 /* non negative validated vcom fds */
3212 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3213 if (sid != INVALID_SESSION_ID)
3214 {
3215 __fds[fds_idx].fd = sid;
3216 }
3217 else
3218 {
3219 /* get vep_idx */
3220 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3221 if (vep_idx != INVALID_VEP_IDX)
3222 {
3223 __fds[fds_idx].fd = vep_idx;
3224 }
3225 else
3226 {
3227 return -EBADF;
3228 }
3229 }
3230 }
3231
3232 /* validate __timeout */
3233 if (__timeout > 0)
3234 {
3235 time_to_wait = (double) __timeout / (double) 1000;
3236 }
3237 else if (__timeout == 0)
3238 {
3239 time_to_wait = (double) 0;
3240 }
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003241 else
3242 {
Dave Wallace60f54822017-10-24 20:47:45 -04003243 time_to_wait = ~0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003244 }
3245
3246 return vppcom_poll (__fds, __nfds, time_to_wait);
3247}
3248
3249int
3250vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3251{
3252 /* select an implementation */
3253
3254 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3255 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3256}
3257
3258#ifdef __USE_GNU
3259int
3260vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3261 const struct timespec *__timeout, const __sigset_t * __ss)
3262{
3263 return -EOPNOTSUPP;
3264}
3265#endif
3266
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003267int
3268vcom_socket_main_init (void)
3269{
3270 vcom_socket_main_t *vsm = &vcom_socket_main;
3271
3272 if (VCOM_DEBUG > 0)
3273 printf ("vcom_socket_main_init\n");
3274
3275 if (!vsm->init)
3276 {
3277 /* TBD: define FD_MAXSIZE and use it here */
3278 pool_alloc (vsm->vsockets, FD_SETSIZE);
3279 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3280
3281 pool_alloc (vsm->vepolls, FD_SETSIZE);
3282 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3283
3284 pool_alloc (vsm->vepitems, FD_SETSIZE);
3285 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3286
3287 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3288 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3289
3290 vsm->init = 1;
3291 }
3292
3293 return 0;
3294}
3295
3296
3297void
3298vcom_socket_main_show (void)
3299{
3300 vcom_socket_main_t *vsm = &vcom_socket_main;
3301 vcom_socket_t *vsock;
3302
3303 vcom_epoll_t *vepoll;
3304
3305 vcom_epitem_t *vepitem;
3306
3307 i32 epfd;
3308 i32 fd;
3309 i32 *vepitemidxs, *vepitemidxs_var;
3310
3311 if (vsm->init)
3312 {
3313 /* from active list of vsockets show vsock */
3314
3315 /* *INDENT-OFF* */
3316 pool_foreach (vsock, vsm->vsockets,
3317 ({
3318 printf(
3319 "fd='%04d', sid='%08x',type='%-30s'\n",
3320 vsock->fd, vsock->sid,
3321 vcom_socket_type_str (vsock->type));
3322 }));
3323 /* *INDENT-ON* */
3324
3325 /* from active list of vepolls, show vepoll */
3326
3327 /* *INDENT-OFF* */
3328 pool_foreach (vepoll, vsm->vepolls,
3329 ({
3330 printf(
3331 "epfd='%04d', vep_idx='%08x', "
3332 "type='%-30s', "
3333 "flags='%d', count='%d', close='%d'\n",
3334 vepoll->epfd, vepoll->vep_idx,
3335 vcom_socket_epoll_type_str (vepoll->type),
3336 vepoll->flags, vepoll->count, vepoll->close);
3337 }));
3338 /* *INDENT-ON* */
3339
3340 /* from active list of vepitems, show vepitem */
3341
3342 /* *INDENT-OFF* */
3343 pool_foreach (vepitem, vsm->vepitems,
3344 ({
3345 printf(
3346 "epfd='%04d', fd='%04d', "
3347 "next_fd='%04d', prev_fd='%04d', "
3348 "type='%-30s', "
3349 "events='%04x', revents='%04x'\n",
3350 vepitem->epfd, vepitem->fd,
3351 vepitem->next_fd, vepitem->prev_fd,
3352 vcom_socket_vcom_fd_type_str (vepitem->type),
3353 vepitem->event.events, vepitem->revent.events);
3354 }));
3355
3356 /* *INDENT-ON* */
3357
3358 /* show epitemidxs for epfd */
3359 /* *INDENT-OFF* */
3360 hash_foreach (epfd, vepitemidxs,
3361 vsm->epitemidxs_by_epfd,
3362 ({
3363 printf("\n[ '%04d': ", epfd);
3364 vec_foreach (vepitemidxs_var,vepitemidxs)
3365 {
3366 printf("'%04d' ", (int)vepitemidxs_var[0]);
3367 }
3368 printf("]\n");
3369 }));
3370 /* *INDENT-ON* */
3371
3372 /* show epitemidxs for fd */
3373 /* *INDENT-OFF* */
3374 hash_foreach (fd, vepitemidxs,
3375 vsm->epitemidxs_by_fd,
3376 ({
3377 printf("\n{ '%04d': ", fd);
3378 vec_foreach (vepitemidxs_var,vepitemidxs)
3379 {
3380 printf("'%04d' ", (int)vepitemidxs_var[0]);
3381 }
3382 printf("}\n");
3383 }));
3384 /* *INDENT-ON* */
3385
3386 }
3387}
3388
3389void
3390vcom_socket_main_destroy (void)
3391{
3392 vcom_socket_main_t *vsm = &vcom_socket_main;
3393 vcom_socket_t *vsock;
3394
3395 vcom_epoll_t *vepoll;
3396
3397 vcom_epitem_t *vepitem;
3398
3399 i32 epfd;
3400 i32 fd;
3401 i32 *vepitemidxs;
3402
3403
3404 if (VCOM_DEBUG > 0)
3405 printf ("vcom_socket_main_destroy\n");
3406
3407 if (vsm->init)
3408 {
3409
3410 /*
3411 * from active list of vepitems,
3412 * remove all "vepitem" elements from the pool in a safe way
3413 * */
3414
3415 /* *INDENT-OFF* */
3416 pool_flush (vepitem, vsm->vepitems,
3417 ({
Dave Wallace60f54822017-10-24 20:47:45 -04003418 if ((vepitem->type == FD_TYPE_EPOLL) ||
3419 (vepitem->type == FD_TYPE_VCOM_SOCKET))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003420 {
Dave Wallace60f54822017-10-24 20:47:45 -04003421 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003422 vepitem->fd, NULL);
3423 vepitem_init (vepitem);
3424 }
3425 }));
3426 /* *INDENT-ON* */
3427
3428 pool_free (vsm->vepitems);
3429 hash_free (vsm->epitemidx_by_epfdfd);
3430
3431 /* free vepitemidxs for each epfd */
3432 /* *INDENT-OFF* */
3433 hash_foreach (epfd, vepitemidxs,
3434 vsm->epitemidxs_by_epfd,
3435 ({
3436 vec_free (vepitemidxs);
3437 }));
3438 /* *INDENT-ON* */
3439 hash_free (vsm->epitemidxs_by_epfd);
3440
3441 /* free vepitemidxs for each fd */
3442 /* *INDENT-OFF* */
3443 hash_foreach (fd, vepitemidxs,
3444 vsm->epitemidxs_by_fd,
3445 ({
3446 vec_free (vepitemidxs);
3447 }));
3448 /* *INDENT-ON* */
3449 hash_free (vsm->epitemidxs_by_fd);
3450
3451
3452 /*
3453 * from active list of vsockets,
3454 * close socket and vppcom session
3455 * */
3456
3457 /* *INDENT-OFF* */
3458 pool_foreach (vsock, vsm->vsockets,
3459 ({
3460 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3461 {
3462 vppcom_session_close (vsock->sid);
3463 vcom_socket_close_socket (vsock->fd);
3464 vsocket_init (vsock);
3465 }
3466 }));
3467 /* *INDENT-ON* */
3468
3469 /*
3470 * return vsocket element to the pool
3471 * */
3472
3473 /* *INDENT-OFF* */
3474 pool_flush (vsock, vsm->vsockets,
3475 ({
3476 // vsocket_init(vsock);
3477 ;
3478 }));
3479 /* *INDENT-ON* */
3480
3481 pool_free (vsm->vsockets);
3482 hash_free (vsm->sockidx_by_fd);
3483
3484 /*
3485 * from active list of vepolls,
3486 * close epoll and vppcom_epoll
3487 * */
3488
3489 /* *INDENT-OFF* */
3490 pool_foreach (vepoll, vsm->vepolls,
3491 ({
3492 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3493 {
3494 vppcom_session_close (vepoll->vep_idx);
3495 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3496 vepoll_init (vepoll);
3497 }
3498 }));
3499 /* *INDENT-ON* */
3500
3501 /*
3502 * return vepoll element to the pool
3503 * */
3504
3505 /* *INDENT-OFF* */
3506 pool_flush (vepoll, vsm->vepolls,
3507 ({
3508 // vepoll_init(vepoll);
3509 ;
3510 }));
3511 /* *INDENT-ON* */
3512
3513 pool_free (vsm->vepolls);
3514 hash_free (vsm->epollidx_by_epfd);
3515
3516 vsm->init = 0;
3517 }
3518}
3519
3520
3521/*
3522 * fd.io coding-style-patch-verification: ON
3523 *
3524 * Local Variables:
3525 * eval: (c-set-style "gnu")
3526 * End:
3527 */