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