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