misc: refactor clib_bitmap_foreach macro
[vpp.git] / src / vcl / ldp.c
1 /*
2  * Copyright (c) 2016-2019 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 <signal.h>
18 #include <dlfcn.h>
19 #include <pthread.h>
20 #include <time.h>
21 #include <stdarg.h>
22 #include <sys/resource.h>
23 #include <netinet/tcp.h>
24
25 #include <vcl/ldp_socket_wrapper.h>
26 #include <vcl/ldp.h>
27 #include <sys/time.h>
28
29 #include <vcl/vcl_locked.h>
30 #include <vppinfra/time.h>
31 #include <vppinfra/bitmap.h>
32 #include <vppinfra/lock.h>
33 #include <vppinfra/pool.h>
34 #include <vppinfra/hash.h>
35
36 #define HAVE_CONSTRUCTOR_ATTRIBUTE
37 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
38 #define CONSTRUCTOR_ATTRIBUTE                       \
39     __attribute__ ((constructor))
40 #else
41 #define CONSTRUCTOR_ATTRIBUTE
42 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
43
44 #define HAVE_DESTRUCTOR_ATTRIBUTE
45 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
46 #define DESTRUCTOR_ATTRIBUTE                        \
47     __attribute__ ((destructor))
48 #else
49 #define DESTRUCTOR_ATTRIBUTE
50 #endif
51
52 #define LDP_MAX_NWORKERS 32
53
54 typedef struct ldp_worker_ctx_
55 {
56   u8 *io_buffer;
57   clib_time_t clib_time;
58
59   /*
60    * Select state
61    */
62   clib_bitmap_t *rd_bitmap;
63   clib_bitmap_t *wr_bitmap;
64   clib_bitmap_t *ex_bitmap;
65   clib_bitmap_t *si_rd_bitmap;
66   clib_bitmap_t *si_wr_bitmap;
67   clib_bitmap_t *si_ex_bitmap;
68   clib_bitmap_t *libc_rd_bitmap;
69   clib_bitmap_t *libc_wr_bitmap;
70   clib_bitmap_t *libc_ex_bitmap;
71
72   /*
73    * Poll state
74    */
75   vcl_poll_t *vcl_poll;
76   struct pollfd *libc_poll;
77   u16 *libc_poll_idxs;
78
79   /*
80    * Epoll state
81    */
82   u8 epoll_wait_vcl;
83   u8 mq_epfd_added;
84   int vcl_mq_epfd;
85
86 } ldp_worker_ctx_t;
87
88 /* clib_bitmap_t, fd_mask and vcl_si_set are used interchangeably. Make sure
89  * they are the same size */
90 STATIC_ASSERT (sizeof (clib_bitmap_t) == sizeof (fd_mask),
91                "ldp bitmap size mismatch");
92 STATIC_ASSERT (sizeof (vcl_si_set) == sizeof (fd_mask),
93                "ldp bitmap size mismatch");
94
95 typedef struct
96 {
97   ldp_worker_ctx_t *workers;
98   int init;
99   char app_name[LDP_APP_NAME_MAX];
100   u32 vlsh_bit_val;
101   u32 vlsh_bit_mask;
102   u32 debug;
103   u8 transparent_tls;
104
105   /** vcl needs next epoll_create to go to libc_epoll */
106   u8 vcl_needs_real_epoll;
107 } ldp_main_t;
108
109 #define LDP_DEBUG ldp->debug
110
111 #define LDBG(_lvl, _fmt, _args...)                                      \
112   if (ldp->debug > _lvl)                                                \
113     {                                                                   \
114       int errno_saved = errno;                                          \
115       fprintf (stderr, "ldp<%d>: " _fmt "\n", getpid(), ##_args);       \
116       errno = errno_saved;                                              \
117     }
118
119 static ldp_main_t ldp_main = {
120   .vlsh_bit_val = (1 << LDP_SID_BIT_MIN),
121   .vlsh_bit_mask = (1 << LDP_SID_BIT_MIN) - 1,
122   .debug = LDP_DEBUG_INIT,
123   .transparent_tls = 0,
124 };
125
126 static ldp_main_t *ldp = &ldp_main;
127
128 static inline ldp_worker_ctx_t *
129 ldp_worker_get_current (void)
130 {
131   return (ldp->workers + vppcom_worker_index ());
132 }
133
134 /*
135  * RETURN:  0 on success or -1 on error.
136  * */
137 static inline void
138 ldp_set_app_name (char *app_name)
139 {
140   snprintf (ldp->app_name, LDP_APP_NAME_MAX,
141             "ldp-%d-%s", getpid (), app_name);
142 }
143
144 static inline char *
145 ldp_get_app_name ()
146 {
147   if (ldp->app_name[0] == '\0')
148     ldp_set_app_name ("app");
149
150   return ldp->app_name;
151 }
152
153 static inline int
154 ldp_vlsh_to_fd (vls_handle_t vlsh)
155 {
156   return (vlsh + ldp->vlsh_bit_val);
157 }
158
159 static inline vls_handle_t
160 ldp_fd_to_vlsh (int fd)
161 {
162   if (fd < ldp->vlsh_bit_val)
163     return VLS_INVALID_HANDLE;
164
165   return (fd - ldp->vlsh_bit_val);
166 }
167
168 static void
169 ldp_alloc_workers (void)
170 {
171   if (ldp->workers)
172     return;
173   pool_alloc (ldp->workers, LDP_MAX_NWORKERS);
174 }
175
176 static inline int
177 ldp_init (void)
178 {
179   ldp_worker_ctx_t *ldpw;
180   int rv;
181
182   if (PREDICT_TRUE (ldp->init))
183     return 0;
184
185   ldp->init = 1;
186   ldp->vcl_needs_real_epoll = 1;
187   rv = vls_app_create (ldp_get_app_name ());
188   if (rv != VPPCOM_OK)
189     {
190       ldp->vcl_needs_real_epoll = 0;
191       if (rv == VPPCOM_EEXIST)
192         return 0;
193       LDBG (2, "\nERROR: ldp_init: vppcom_app_create()"
194             " failed!  rv = %d (%s)\n", rv, vppcom_retval_str (rv));
195       ldp->init = 0;
196       return rv;
197     }
198   ldp->vcl_needs_real_epoll = 0;
199   ldp_alloc_workers ();
200   ldpw = ldp_worker_get_current ();
201
202   char *env_var_str = getenv (LDP_ENV_DEBUG);
203   if (env_var_str)
204     {
205       u32 tmp;
206       if (sscanf (env_var_str, "%u", &tmp) != 1)
207         clib_warning ("LDP<%d>: WARNING: Invalid LDP debug level specified in"
208                       " the env var " LDP_ENV_DEBUG " (%s)!", getpid (),
209                       env_var_str);
210       else
211         {
212           ldp->debug = tmp;
213           LDBG (0, "configured LDP debug level (%u) from env var "
214                 LDP_ENV_DEBUG "!", ldp->debug);
215         }
216     }
217
218   env_var_str = getenv (LDP_ENV_APP_NAME);
219   if (env_var_str)
220     {
221       ldp_set_app_name (env_var_str);
222       LDBG (0, "configured LDP app name (%s) from the env var "
223             LDP_ENV_APP_NAME "!", ldp->app_name);
224     }
225
226   env_var_str = getenv (LDP_ENV_SID_BIT);
227   if (env_var_str)
228     {
229       u32 sb;
230       if (sscanf (env_var_str, "%u", &sb) != 1)
231         {
232           LDBG (0, "WARNING: Invalid LDP sid bit specified in the env var "
233                 LDP_ENV_SID_BIT " (%s)! sid bit value %d (0x%x)", env_var_str,
234                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
235         }
236       else if (sb < LDP_SID_BIT_MIN)
237         {
238           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MIN);
239           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
240
241           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
242                 LDP_ENV_SID_BIT " (%s) is too small. Using LDP_SID_BIT_MIN"
243                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
244                 LDP_SID_BIT_MIN, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
245         }
246       else if (sb > LDP_SID_BIT_MAX)
247         {
248           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MAX);
249           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
250
251           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
252                 LDP_ENV_SID_BIT " (%s) is too big. Using LDP_SID_BIT_MAX"
253                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
254                 LDP_SID_BIT_MAX, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
255         }
256       else
257         {
258           ldp->vlsh_bit_val = (1 << sb);
259           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
260
261           LDBG (0, "configured LDP sid bit (%u) from "
262                 LDP_ENV_SID_BIT "!  sid bit value %d (0x%x)", sb,
263                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
264         }
265
266       /* Make sure there are enough bits in the fd set for vcl sessions */
267       if (ldp->vlsh_bit_val > FD_SETSIZE / 2)
268         {
269           LDBG (0, "ERROR: LDP vlsh bit value %d > FD_SETSIZE/2 %d!",
270                 ldp->vlsh_bit_val, FD_SETSIZE / 2);
271           ldp->init = 0;
272           return -1;
273         }
274     }
275   env_var_str = getenv (LDP_ENV_TLS_TRANS);
276   if (env_var_str)
277     {
278       ldp->transparent_tls = 1;
279     }
280
281   /* *INDENT-OFF* */
282   pool_foreach (ldpw, ldp->workers)  {
283     clib_memset (&ldpw->clib_time, 0, sizeof (ldpw->clib_time));
284   }
285   /* *INDENT-ON* */
286
287   LDBG (0, "LDP initialization: done!");
288
289   return 0;
290 }
291
292 int
293 close (int fd)
294 {
295   vls_handle_t vlsh;
296   int rv, epfd;
297
298   if ((errno = -ldp_init ()))
299     return -1;
300
301   vlsh = ldp_fd_to_vlsh (fd);
302   if (vlsh != VLS_INVALID_HANDLE)
303     {
304       epfd = vls_attr (vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
305       if (epfd > 0)
306         {
307           LDBG (0, "fd %d: calling libc_close: epfd %u", fd, epfd);
308
309           rv = libc_close (epfd);
310           if (rv < 0)
311             {
312               u32 size = sizeof (epfd);
313               epfd = 0;
314
315               (void) vls_attr (vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &epfd, &size);
316             }
317         }
318       else if (PREDICT_FALSE (epfd < 0))
319         {
320           errno = -epfd;
321           rv = -1;
322           goto done;
323         }
324
325       LDBG (0, "fd %d: calling vls_close: vlsh %u", fd, vlsh);
326
327       rv = vls_close (vlsh);
328       if (rv != VPPCOM_OK)
329         {
330           errno = -rv;
331           rv = -1;
332         }
333     }
334   else
335     {
336       LDBG (0, "fd %d: calling libc_close", fd);
337       rv = libc_close (fd);
338     }
339
340 done:
341   return rv;
342 }
343
344 ssize_t
345 read (int fd, void *buf, size_t nbytes)
346 {
347   vls_handle_t vlsh;
348   ssize_t size;
349
350   if ((errno = -ldp_init ()))
351     return -1;
352
353   vlsh = ldp_fd_to_vlsh (fd);
354   if (vlsh != VLS_INVALID_HANDLE)
355     {
356       size = vls_read (vlsh, buf, nbytes);
357       if (size < 0)
358         {
359           errno = -size;
360           size = -1;
361         }
362     }
363   else
364     {
365       size = libc_read (fd, buf, nbytes);
366     }
367
368   return size;
369 }
370
371 ssize_t
372 readv (int fd, const struct iovec * iov, int iovcnt)
373 {
374   int rv = 0, i, total = 0;
375   vls_handle_t vlsh;
376   ssize_t size = 0;
377
378   if ((errno = -ldp_init ()))
379     return -1;
380
381   vlsh = ldp_fd_to_vlsh (fd);
382   if (vlsh != VLS_INVALID_HANDLE)
383     {
384       for (i = 0; i < iovcnt; ++i)
385         {
386           rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len);
387           if (rv <= 0)
388             break;
389           else
390             {
391               total += rv;
392               if (rv < iov[i].iov_len)
393                 break;
394             }
395         }
396       if (rv < 0 && total == 0)
397         {
398           errno = -rv;
399           size = -1;
400         }
401       else
402         size = total;
403     }
404   else
405     {
406       size = libc_readv (fd, iov, iovcnt);
407     }
408
409   return size;
410 }
411
412 ssize_t
413 write (int fd, const void *buf, size_t nbytes)
414 {
415   vls_handle_t vlsh;
416   ssize_t size = 0;
417
418   if ((errno = -ldp_init ()))
419     return -1;
420
421   vlsh = ldp_fd_to_vlsh (fd);
422   if (vlsh != VLS_INVALID_HANDLE)
423     {
424       size = vls_write_msg (vlsh, (void *) buf, nbytes);
425       if (size < 0)
426         {
427           errno = -size;
428           size = -1;
429         }
430     }
431   else
432     {
433       size = libc_write (fd, buf, nbytes);
434     }
435
436   return size;
437 }
438
439 ssize_t
440 writev (int fd, const struct iovec * iov, int iovcnt)
441 {
442   ssize_t size = 0, total = 0;
443   vls_handle_t vlsh;
444   int i, rv = 0;
445
446   if ((errno = -ldp_init ()))
447     return -1;
448
449   vlsh = ldp_fd_to_vlsh (fd);
450   if (vlsh != VLS_INVALID_HANDLE)
451     {
452       for (i = 0; i < iovcnt; ++i)
453         {
454           rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len);
455           if (rv < 0)
456             break;
457           else
458             {
459               total += rv;
460               if (rv < iov[i].iov_len)
461                 break;
462             }
463         }
464
465       if (rv < 0 && total == 0)
466         {
467           errno = -rv;
468           size = -1;
469         }
470       else
471         size = total;
472     }
473   else
474     {
475       size = libc_writev (fd, iov, iovcnt);
476     }
477
478   return size;
479 }
480
481 static int
482 fcntl_internal (int fd, int cmd, va_list ap)
483 {
484   vls_handle_t vlsh;
485   int rv = 0;
486
487   vlsh = ldp_fd_to_vlsh (fd);
488   LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd);
489   if (vlsh != VLS_INVALID_HANDLE)
490     {
491       int flags = va_arg (ap, int);
492       u32 size;
493
494       size = sizeof (flags);
495       rv = -EOPNOTSUPP;
496       switch (cmd)
497         {
498         case F_SETFL:
499           rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
500           break;
501
502         case F_GETFL:
503           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
504           if (rv == VPPCOM_OK)
505             rv = flags;
506           break;
507         case F_SETFD:
508           /* TODO handle this */
509           LDBG (0, "F_SETFD ignored flags %u", flags);
510           rv = 0;
511           break;
512         default:
513           rv = -EOPNOTSUPP;
514           break;
515         }
516       if (rv < 0)
517         {
518           errno = -rv;
519           rv = -1;
520         }
521     }
522   else
523     {
524 #ifdef HAVE_FCNTL64
525       rv = libc_vfcntl64 (fd, cmd, ap);
526 #else
527       rv = libc_vfcntl (fd, cmd, ap);
528 #endif
529     }
530
531   return rv;
532 }
533
534 int
535 fcntl (int fd, int cmd, ...)
536 {
537   va_list ap;
538   int rv;
539
540   if ((errno = -ldp_init ()))
541     return -1;
542
543   va_start (ap, cmd);
544   rv = fcntl_internal (fd, cmd, ap);
545   va_end (ap);
546
547   return rv;
548 }
549
550 int
551 fcntl64 (int fd, int cmd, ...)
552 {
553   va_list ap;
554   int rv;
555
556   if ((errno = -ldp_init ()))
557     return -1;
558
559   va_start (ap, cmd);
560   rv = fcntl_internal (fd, cmd, ap);
561   va_end (ap);
562   return rv;
563 }
564
565 int
566 ioctl (int fd, unsigned long int cmd, ...)
567 {
568   vls_handle_t vlsh;
569   va_list ap;
570   int rv;
571
572   if ((errno = -ldp_init ()))
573     return -1;
574
575   va_start (ap, cmd);
576
577   vlsh = ldp_fd_to_vlsh (fd);
578   if (vlsh != VLS_INVALID_HANDLE)
579     {
580       switch (cmd)
581         {
582         case FIONREAD:
583           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
584           break;
585
586         case FIONBIO:
587           {
588             u32 flags = va_arg (ap, int) ? O_NONBLOCK : 0;
589             u32 size = sizeof (flags);
590
591             /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
592              *      non-blocking, the flags should be read here and merged
593              *      with O_NONBLOCK.
594              */
595             rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
596           }
597           break;
598
599         default:
600           rv = -EOPNOTSUPP;
601           break;
602         }
603       if (rv < 0)
604         {
605           errno = -rv;
606           rv = -1;
607         }
608     }
609   else
610     {
611       rv = libc_vioctl (fd, cmd, ap);
612     }
613
614   va_end (ap);
615   return rv;
616 }
617
618 always_inline void
619 ldp_select_init_maps (fd_set * __restrict original,
620                       clib_bitmap_t ** resultb, clib_bitmap_t ** libcb,
621                       clib_bitmap_t ** vclb, int nfds, u32 minbits,
622                       u32 n_bytes, uword * si_bits, uword * libc_bits)
623 {
624   uword si_bits_set, libc_bits_set;
625   vls_handle_t vlsh;
626   int fd;
627
628   clib_bitmap_validate (*vclb, minbits);
629   clib_bitmap_validate (*libcb, minbits);
630   clib_bitmap_validate (*resultb, minbits);
631   clib_memcpy_fast (*resultb, original, n_bytes);
632   memset (original, 0, n_bytes);
633
634   /* *INDENT-OFF* */
635   clib_bitmap_foreach (fd, *resultb)  {
636     if (fd > nfds)
637       break;
638     vlsh = ldp_fd_to_vlsh (fd);
639     if (vlsh == VLS_INVALID_HANDLE)
640       clib_bitmap_set_no_check (*libcb, fd, 1);
641     else
642       *vclb = clib_bitmap_set (*vclb, vlsh_to_session_index (vlsh), 1);
643   }
644   /* *INDENT-ON* */
645
646   si_bits_set = clib_bitmap_last_set (*vclb) + 1;
647   *si_bits = (si_bits_set > *si_bits) ? si_bits_set : *si_bits;
648   clib_bitmap_validate (*resultb, *si_bits);
649
650   libc_bits_set = clib_bitmap_last_set (*libcb) + 1;
651   *libc_bits = (libc_bits_set > *libc_bits) ? libc_bits_set : *libc_bits;
652 }
653
654 always_inline int
655 ldp_select_vcl_map_to_libc (clib_bitmap_t * vclb, fd_set * __restrict libcb)
656 {
657   vls_handle_t vlsh;
658   uword si;
659   int fd;
660
661   if (!libcb)
662     return 0;
663
664   /* *INDENT-OFF* */
665   clib_bitmap_foreach (si, vclb)  {
666     vlsh = vls_session_index_to_vlsh (si);
667     ASSERT (vlsh != VLS_INVALID_HANDLE);
668     fd = ldp_vlsh_to_fd (vlsh);
669     if (PREDICT_FALSE (fd < 0))
670       {
671         errno = EBADFD;
672         return -1;
673       }
674     FD_SET (fd, libcb);
675   }
676   /* *INDENT-ON* */
677
678   return 0;
679 }
680
681 always_inline void
682 ldp_select_libc_map_merge (clib_bitmap_t * result, fd_set * __restrict libcb)
683 {
684   uword fd;
685
686   if (!libcb)
687     return;
688
689   /* *INDENT-OFF* */
690   clib_bitmap_foreach (fd, result)
691     FD_SET ((int)fd, libcb);
692   /* *INDENT-ON* */
693 }
694
695 int
696 ldp_pselect (int nfds, fd_set * __restrict readfds,
697              fd_set * __restrict writefds,
698              fd_set * __restrict exceptfds,
699              const struct timespec *__restrict timeout,
700              const __sigset_t * __restrict sigmask)
701 {
702   u32 minbits = clib_max (nfds, BITS (uword)), n_bytes;
703   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
704   struct timespec libc_tspec = { 0 };
705   f64 time_out, vcl_timeout = 0;
706   uword si_bits, libc_bits;
707   int rv, bits_set = 0;
708
709   if (nfds < 0)
710     {
711       errno = EINVAL;
712       return -1;
713     }
714
715   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
716     clib_time_init (&ldpw->clib_time);
717
718   if (timeout)
719     {
720       time_out = (timeout->tv_sec == 0 && timeout->tv_nsec == 0) ?
721         (f64) 0 : (f64) timeout->tv_sec + (f64) timeout->tv_nsec / (f64) 1e9;
722
723       /* select as fine grained sleep */
724       if (!nfds)
725         {
726           time_out += clib_time_now (&ldpw->clib_time);
727           while (clib_time_now (&ldpw->clib_time) < time_out)
728             ;
729           return 0;
730         }
731     }
732   else if (!nfds)
733     {
734       errno = EINVAL;
735       return -1;
736     }
737   else
738     time_out = -1;
739
740   if (nfds <= ldp->vlsh_bit_val)
741     {
742       rv = libc_pselect (nfds, readfds, writefds, exceptfds,
743                          timeout, sigmask);
744       goto done;
745     }
746
747   si_bits = libc_bits = 0;
748   n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0);
749
750   if (readfds)
751     ldp_select_init_maps (readfds, &ldpw->rd_bitmap, &ldpw->libc_rd_bitmap,
752                           &ldpw->si_rd_bitmap, nfds, minbits, n_bytes,
753                           &si_bits, &libc_bits);
754   if (writefds)
755     ldp_select_init_maps (writefds, &ldpw->wr_bitmap,
756                           &ldpw->libc_wr_bitmap, &ldpw->si_wr_bitmap, nfds,
757                           minbits, n_bytes, &si_bits, &libc_bits);
758   if (exceptfds)
759     ldp_select_init_maps (exceptfds, &ldpw->ex_bitmap,
760                           &ldpw->libc_ex_bitmap, &ldpw->si_ex_bitmap, nfds,
761                           minbits, n_bytes, &si_bits, &libc_bits);
762
763   if (PREDICT_FALSE (!si_bits && !libc_bits))
764     {
765       errno = EINVAL;
766       rv = -1;
767       goto done;
768     }
769
770   if (!si_bits)
771     libc_tspec = timeout ? *timeout : libc_tspec;
772
773   do
774     {
775       if (si_bits)
776         {
777           if (readfds)
778             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->si_rd_bitmap,
779                               vec_len (ldpw->si_rd_bitmap) *
780                               sizeof (clib_bitmap_t));
781           if (writefds)
782             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->si_wr_bitmap,
783                               vec_len (ldpw->si_wr_bitmap) *
784                               sizeof (clib_bitmap_t));
785           if (exceptfds)
786             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->si_ex_bitmap,
787                               vec_len (ldpw->si_ex_bitmap) *
788                               sizeof (clib_bitmap_t));
789
790           rv = vls_select (si_bits, readfds ? ldpw->rd_bitmap : NULL,
791                            writefds ? ldpw->wr_bitmap : NULL,
792                            exceptfds ? ldpw->ex_bitmap : NULL, vcl_timeout);
793           if (rv < 0)
794             {
795               errno = -rv;
796               rv = -1;
797               goto done;
798             }
799           else if (rv > 0)
800             {
801               if (ldp_select_vcl_map_to_libc (ldpw->rd_bitmap, readfds))
802                 {
803                   rv = -1;
804                   goto done;
805                 }
806
807               if (ldp_select_vcl_map_to_libc (ldpw->wr_bitmap, writefds))
808                 {
809                   rv = -1;
810                   goto done;
811                 }
812
813               if (ldp_select_vcl_map_to_libc (ldpw->ex_bitmap, exceptfds))
814                 {
815                   rv = -1;
816                   goto done;
817                 }
818               bits_set = rv;
819             }
820         }
821       if (libc_bits)
822         {
823           if (readfds)
824             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->libc_rd_bitmap,
825                               vec_len (ldpw->libc_rd_bitmap) *
826                               sizeof (clib_bitmap_t));
827           if (writefds)
828             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->libc_wr_bitmap,
829                               vec_len (ldpw->libc_wr_bitmap) *
830                               sizeof (clib_bitmap_t));
831           if (exceptfds)
832             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->libc_ex_bitmap,
833                               vec_len (ldpw->libc_ex_bitmap) *
834                               sizeof (clib_bitmap_t));
835
836           rv = libc_pselect (libc_bits,
837                              readfds ? (fd_set *) ldpw->rd_bitmap : NULL,
838                              writefds ? (fd_set *) ldpw->wr_bitmap : NULL,
839                              exceptfds ? (fd_set *) ldpw->ex_bitmap : NULL,
840                              &libc_tspec, sigmask);
841           if (rv > 0)
842             {
843               ldp_select_libc_map_merge (ldpw->rd_bitmap, readfds);
844               ldp_select_libc_map_merge (ldpw->wr_bitmap, writefds);
845               ldp_select_libc_map_merge (ldpw->ex_bitmap, exceptfds);
846               bits_set += rv;
847             }
848         }
849
850       if (bits_set)
851         {
852           rv = bits_set;
853           goto done;
854         }
855     }
856   while ((time_out == -1) || (clib_time_now (&ldpw->clib_time) < time_out));
857   rv = 0;
858
859 done:
860   /* TBD: set timeout to amount of time left */
861   clib_bitmap_zero (ldpw->rd_bitmap);
862   clib_bitmap_zero (ldpw->si_rd_bitmap);
863   clib_bitmap_zero (ldpw->libc_rd_bitmap);
864   clib_bitmap_zero (ldpw->wr_bitmap);
865   clib_bitmap_zero (ldpw->si_wr_bitmap);
866   clib_bitmap_zero (ldpw->libc_wr_bitmap);
867   clib_bitmap_zero (ldpw->ex_bitmap);
868   clib_bitmap_zero (ldpw->si_ex_bitmap);
869   clib_bitmap_zero (ldpw->libc_ex_bitmap);
870
871   return rv;
872 }
873
874 int
875 select (int nfds, fd_set * __restrict readfds,
876         fd_set * __restrict writefds,
877         fd_set * __restrict exceptfds, struct timeval *__restrict timeout)
878 {
879   struct timespec tspec;
880
881   if (timeout)
882     {
883       tspec.tv_sec = timeout->tv_sec;
884       tspec.tv_nsec = timeout->tv_usec * 1000;
885     }
886   return ldp_pselect (nfds, readfds, writefds, exceptfds,
887                       timeout ? &tspec : NULL, NULL);
888 }
889
890 #ifdef __USE_XOPEN2K
891 int
892 pselect (int nfds, fd_set * __restrict readfds,
893          fd_set * __restrict writefds,
894          fd_set * __restrict exceptfds,
895          const struct timespec *__restrict timeout,
896          const __sigset_t * __restrict sigmask)
897 {
898   return ldp_pselect (nfds, readfds, writefds, exceptfds, timeout, 0);
899 }
900 #endif
901
902 /* If transparent TLS mode is turned on, then ldp will load key and cert.
903  */
904 static int
905 load_tls_cert (vls_handle_t vlsh)
906 {
907   char *env_var_str = getenv (LDP_ENV_TLS_CERT);
908   char inbuf[4096];
909   char *tls_cert;
910   int cert_size;
911   FILE *fp;
912
913   if (env_var_str)
914     {
915       fp = fopen (env_var_str, "r");
916       if (fp == NULL)
917         {
918           LDBG (0, "ERROR: failed to open cert file %s \n", env_var_str);
919           return -1;
920         }
921       cert_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
922       tls_cert = inbuf;
923       vppcom_session_tls_add_cert (vlsh_to_session_index (vlsh), tls_cert,
924                                    cert_size);
925       fclose (fp);
926     }
927   else
928     {
929       LDBG (0, "ERROR: failed to read LDP environment %s\n",
930             LDP_ENV_TLS_CERT);
931       return -1;
932     }
933   return 0;
934 }
935
936 static int
937 load_tls_key (vls_handle_t vlsh)
938 {
939   char *env_var_str = getenv (LDP_ENV_TLS_KEY);
940   char inbuf[4096];
941   char *tls_key;
942   int key_size;
943   FILE *fp;
944
945   if (env_var_str)
946     {
947       fp = fopen (env_var_str, "r");
948       if (fp == NULL)
949         {
950           LDBG (0, "ERROR: failed to open key file %s \n", env_var_str);
951           return -1;
952         }
953       key_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
954       tls_key = inbuf;
955       vppcom_session_tls_add_key (vlsh_to_session_index (vlsh), tls_key,
956                                   key_size);
957       fclose (fp);
958     }
959   else
960     {
961       LDBG (0, "ERROR: failed to read LDP environment %s\n", LDP_ENV_TLS_KEY);
962       return -1;
963     }
964   return 0;
965 }
966
967 int
968 socket (int domain, int type, int protocol)
969 {
970   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
971   u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0;
972   vls_handle_t vlsh;
973
974   if ((errno = -ldp_init ()))
975     return -1;
976
977   if (((domain == AF_INET) || (domain == AF_INET6)) &&
978       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
979     {
980       u8 proto;
981       if (ldp->transparent_tls)
982         {
983           proto = VPPCOM_PROTO_TLS;
984         }
985       else
986         proto = ((sock_type == SOCK_DGRAM) ?
987                  VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
988
989       LDBG (0, "calling vls_create: proto %u (%s), is_nonblocking %u",
990             proto, vppcom_proto_str (proto), is_nonblocking);
991
992       vlsh = vls_create (proto, is_nonblocking);
993       if (vlsh < 0)
994         {
995           errno = -vlsh;
996           rv = -1;
997         }
998       else
999         {
1000           if (ldp->transparent_tls)
1001             {
1002               if (load_tls_cert (vlsh) < 0 || load_tls_key (vlsh) < 0)
1003                 {
1004                   return -1;
1005                 }
1006             }
1007           rv = ldp_vlsh_to_fd (vlsh);
1008         }
1009     }
1010   else
1011     {
1012       LDBG (0, "calling libc_socket");
1013       rv = libc_socket (domain, type, protocol);
1014     }
1015
1016   return rv;
1017 }
1018
1019 /*
1020  * Create two new sockets, of type TYPE in domain DOMAIN and using
1021  * protocol PROTOCOL, which are connected to each other, and put file
1022  * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
1023  * one will be chosen automatically.
1024  * Returns 0 on success, -1 for errors.
1025  * */
1026 int
1027 socketpair (int domain, int type, int protocol, int fds[2])
1028 {
1029   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
1030
1031   if ((errno = -ldp_init ()))
1032     return -1;
1033
1034   if (((domain == AF_INET) || (domain == AF_INET6)) &&
1035       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
1036     {
1037       LDBG (0, "LDP-TBD");
1038       errno = ENOSYS;
1039       rv = -1;
1040     }
1041   else
1042     {
1043       LDBG (1, "calling libc_socketpair");
1044       rv = libc_socketpair (domain, type, protocol, fds);
1045     }
1046
1047   return rv;
1048 }
1049
1050 int
1051 bind (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
1052 {
1053   vls_handle_t vlsh;
1054   int rv;
1055
1056   if ((errno = -ldp_init ()))
1057     return -1;
1058
1059   vlsh = ldp_fd_to_vlsh (fd);
1060   if (vlsh != VLS_INVALID_HANDLE)
1061     {
1062       vppcom_endpt_t ep;
1063
1064       switch (addr->sa_family)
1065         {
1066         case AF_INET:
1067           if (len != sizeof (struct sockaddr_in))
1068             {
1069               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET addr len %u!",
1070                     fd, vlsh, len);
1071               errno = EINVAL;
1072               rv = -1;
1073               goto done;
1074             }
1075           ep.is_ip4 = VPPCOM_IS_IP4;
1076           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1077           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1078           break;
1079
1080         case AF_INET6:
1081           if (len != sizeof (struct sockaddr_in6))
1082             {
1083               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET6 addr len %u!",
1084                     fd, vlsh, len);
1085               errno = EINVAL;
1086               rv = -1;
1087               goto done;
1088             }
1089           ep.is_ip4 = VPPCOM_IS_IP6;
1090           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1091           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1092           break;
1093
1094         default:
1095           LDBG (0, "ERROR: fd %d: vlsh %u: Unsupported address family %u!",
1096                 fd, vlsh, addr->sa_family);
1097           errno = EAFNOSUPPORT;
1098           rv = -1;
1099           goto done;
1100         }
1101       LDBG (0, "fd %d: calling vls_bind: vlsh %u, addr %p, len %u", fd, vlsh,
1102             addr, len);
1103
1104       rv = vls_bind (vlsh, &ep);
1105       if (rv != VPPCOM_OK)
1106         {
1107           errno = -rv;
1108           rv = -1;
1109         }
1110     }
1111   else
1112     {
1113       LDBG (0, "fd %d: calling libc_bind: addr %p, len %u", fd, addr, len);
1114       rv = libc_bind (fd, addr, len);
1115     }
1116
1117 done:
1118   LDBG (1, "fd %d: returning %d", fd, rv);
1119
1120   return rv;
1121 }
1122
1123 static inline int
1124 ldp_copy_ep_to_sockaddr (__SOCKADDR_ARG addr, socklen_t * __restrict len,
1125                          vppcom_endpt_t * ep)
1126 {
1127   int rv = 0;
1128   int sa_len, copy_len;
1129
1130   if ((errno = -ldp_init ()))
1131     return -1;
1132
1133   if (addr && len && ep)
1134     {
1135       addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1136       switch (addr->sa_family)
1137         {
1138         case AF_INET:
1139           ((struct sockaddr_in *) addr)->sin_port = ep->port;
1140           if (*len > sizeof (struct sockaddr_in))
1141             *len = sizeof (struct sockaddr_in);
1142           sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1143           copy_len = *len - sa_len;
1144           if (copy_len > 0)
1145             memcpy (&((struct sockaddr_in *) addr)->sin_addr, ep->ip,
1146                     copy_len);
1147           break;
1148
1149         case AF_INET6:
1150           ((struct sockaddr_in6 *) addr)->sin6_port = ep->port;
1151           if (*len > sizeof (struct sockaddr_in6))
1152             *len = sizeof (struct sockaddr_in6);
1153           sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1154           copy_len = *len - sa_len;
1155           if (copy_len > 0)
1156             memcpy (((struct sockaddr_in6 *) addr)->sin6_addr.
1157                     __in6_u.__u6_addr8, ep->ip, copy_len);
1158           break;
1159
1160         default:
1161           /* Not possible */
1162           rv = -EAFNOSUPPORT;
1163           break;
1164         }
1165     }
1166   return rv;
1167 }
1168
1169 int
1170 getsockname (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1171 {
1172   vls_handle_t vlsh;
1173   int rv;
1174
1175   if ((errno = -ldp_init ()))
1176     return -1;
1177
1178   vlsh = ldp_fd_to_vlsh (fd);
1179   if (vlsh != VLS_INVALID_HANDLE)
1180     {
1181       vppcom_endpt_t ep;
1182       u8 addr_buf[sizeof (struct in6_addr)];
1183       u32 size = sizeof (ep);
1184
1185       ep.ip = addr_buf;
1186
1187       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
1188       if (rv != VPPCOM_OK)
1189         {
1190           errno = -rv;
1191           rv = -1;
1192         }
1193       else
1194         {
1195           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1196           if (rv != VPPCOM_OK)
1197             {
1198               errno = -rv;
1199               rv = -1;
1200             }
1201         }
1202     }
1203   else
1204     {
1205       rv = libc_getsockname (fd, addr, len);
1206     }
1207
1208   return rv;
1209 }
1210
1211 int
1212 connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
1213 {
1214   vls_handle_t vlsh;
1215   int rv;
1216
1217   if ((errno = -ldp_init ()))
1218     return -1;
1219
1220   if (!addr)
1221     {
1222       LDBG (0, "ERROR: fd %d: NULL addr, len %u", fd, len);
1223       errno = EINVAL;
1224       rv = -1;
1225       goto done;
1226     }
1227
1228   vlsh = ldp_fd_to_vlsh (fd);
1229   if (vlsh != VLS_INVALID_HANDLE)
1230     {
1231       vppcom_endpt_t ep;
1232
1233       switch (addr->sa_family)
1234         {
1235         case AF_INET:
1236           if (len != sizeof (struct sockaddr_in))
1237             {
1238               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET addr len %u!",
1239                     fd, vlsh, len);
1240               errno = EINVAL;
1241               rv = -1;
1242               goto done;
1243             }
1244           ep.is_ip4 = VPPCOM_IS_IP4;
1245           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1246           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1247           break;
1248
1249         case AF_INET6:
1250           if (len != sizeof (struct sockaddr_in6))
1251             {
1252               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET6 addr len %u!",
1253                     fd, vlsh, len);
1254               errno = EINVAL;
1255               rv = -1;
1256               goto done;
1257             }
1258           ep.is_ip4 = VPPCOM_IS_IP6;
1259           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1260           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1261           break;
1262
1263         default:
1264           LDBG (0, "fd %d: ERROR vlsh %u: Unsupported address family %u!",
1265                 fd, vlsh, addr->sa_family);
1266           errno = EAFNOSUPPORT;
1267           rv = -1;
1268           goto done;
1269         }
1270       LDBG (0, "fd %d: calling vls_connect(): vlsh %u addr %p len %u", fd,
1271             vlsh, addr, len);
1272
1273       rv = vls_connect (vlsh, &ep);
1274       if (rv != VPPCOM_OK)
1275         {
1276           errno = -rv;
1277           rv = -1;
1278         }
1279     }
1280   else
1281     {
1282       LDBG (0, "fd %d: calling libc_connect(): addr %p, len %u",
1283             fd, addr, len);
1284
1285       rv = libc_connect (fd, addr, len);
1286     }
1287
1288 done:
1289   LDBG (1, "fd %d: returning %d (0x%x)", fd, rv, rv);
1290   return rv;
1291 }
1292
1293 int
1294 getpeername (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1295 {
1296   vls_handle_t vlsh;
1297   int rv;
1298
1299   if ((errno = -ldp_init ()))
1300     return -1;
1301
1302   vlsh = ldp_fd_to_vlsh (fd);
1303   if (vlsh != VLS_INVALID_HANDLE)
1304     {
1305       vppcom_endpt_t ep;
1306       u8 addr_buf[sizeof (struct in6_addr)];
1307       u32 size = sizeof (ep);
1308
1309       ep.ip = addr_buf;
1310       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size);
1311       if (rv != VPPCOM_OK)
1312         {
1313           errno = -rv;
1314           rv = -1;
1315         }
1316       else
1317         {
1318           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1319           if (rv != VPPCOM_OK)
1320             {
1321               errno = -rv;
1322               rv = -1;
1323             }
1324         }
1325     }
1326   else
1327     {
1328       rv = libc_getpeername (fd, addr, len);
1329     }
1330
1331   return rv;
1332 }
1333
1334 ssize_t
1335 send (int fd, const void *buf, size_t n, int flags)
1336 {
1337   vls_handle_t vlsh = ldp_fd_to_vlsh (fd);
1338   ssize_t size;
1339
1340   if ((errno = -ldp_init ()))
1341     return -1;
1342
1343   if (vlsh != VLS_INVALID_HANDLE)
1344     {
1345       size = vls_sendto (vlsh, (void *) buf, n, flags, NULL);
1346       if (size < VPPCOM_OK)
1347         {
1348           errno = -size;
1349           size = -1;
1350         }
1351     }
1352   else
1353     {
1354       size = libc_send (fd, buf, n, flags);
1355     }
1356
1357   return size;
1358 }
1359
1360 ssize_t
1361 sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
1362 {
1363   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1364   vls_handle_t vlsh;
1365   ssize_t size = 0;
1366
1367   if ((errno = -ldp_init ()))
1368     return -1;
1369
1370   vlsh = ldp_fd_to_vlsh (out_fd);
1371   if (vlsh != VLS_INVALID_HANDLE)
1372     {
1373       int rv;
1374       ssize_t results = 0;
1375       size_t n_bytes_left = len;
1376       size_t bytes_to_read;
1377       int nbytes;
1378       u8 eagain = 0;
1379       u32 flags, flags_len = sizeof (flags);
1380
1381       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &flags_len);
1382       if (PREDICT_FALSE (rv != VPPCOM_OK))
1383         {
1384           LDBG (0, "ERROR: out fd %d: vls_attr: vlsh %u, returned %d (%s)!",
1385                 out_fd, vlsh, rv, vppcom_retval_str (rv));
1386
1387           vec_reset_length (ldpw->io_buffer);
1388           errno = -rv;
1389           size = -1;
1390           goto done;
1391         }
1392
1393       if (offset)
1394         {
1395           off_t off = lseek (in_fd, *offset, SEEK_SET);
1396           if (PREDICT_FALSE (off == -1))
1397             {
1398               size = -1;
1399               goto done;
1400             }
1401
1402           ASSERT (off == *offset);
1403         }
1404
1405       do
1406         {
1407           size = vls_attr (vlsh, VPPCOM_ATTR_GET_NWRITE, 0, 0);
1408           if (size < 0)
1409             {
1410               LDBG (0, "ERROR: fd %d: vls_attr: vlsh %u returned %ld (%s)!",
1411                     out_fd, vlsh, size, vppcom_retval_str (size));
1412               vec_reset_length (ldpw->io_buffer);
1413               errno = -size;
1414               size = -1;
1415               goto done;
1416             }
1417
1418           bytes_to_read = size;
1419           if (bytes_to_read == 0)
1420             {
1421               if (flags & O_NONBLOCK)
1422                 {
1423                   if (!results)
1424                     eagain = 1;
1425                   goto update_offset;
1426                 }
1427               else
1428                 continue;
1429             }
1430           bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1431           vec_validate (ldpw->io_buffer, bytes_to_read);
1432           nbytes = libc_read (in_fd, ldpw->io_buffer, bytes_to_read);
1433           if (nbytes < 0)
1434             {
1435               if (results == 0)
1436                 {
1437                   vec_reset_length (ldpw->io_buffer);
1438                   size = -1;
1439                   goto done;
1440                 }
1441               goto update_offset;
1442             }
1443
1444           size = vls_write (vlsh, ldpw->io_buffer, nbytes);
1445           if (size < 0)
1446             {
1447               if (size == VPPCOM_EAGAIN)
1448                 {
1449                   if (flags & O_NONBLOCK)
1450                     {
1451                       if (!results)
1452                         eagain = 1;
1453                       goto update_offset;
1454                     }
1455                   else
1456                     continue;
1457                 }
1458               if (results == 0)
1459                 {
1460                   vec_reset_length (ldpw->io_buffer);
1461                   errno = -size;
1462                   size = -1;
1463                   goto done;
1464                 }
1465               goto update_offset;
1466             }
1467
1468           results += nbytes;
1469           ASSERT (n_bytes_left >= nbytes);
1470           n_bytes_left = n_bytes_left - nbytes;
1471         }
1472       while (n_bytes_left > 0);
1473
1474     update_offset:
1475       vec_reset_length (ldpw->io_buffer);
1476       if (offset)
1477         {
1478           off_t off = lseek (in_fd, *offset, SEEK_SET);
1479           if (PREDICT_FALSE (off == -1))
1480             {
1481               size = -1;
1482               goto done;
1483             }
1484
1485           ASSERT (off == *offset);
1486           *offset += results + 1;
1487         }
1488       if (eagain)
1489         {
1490           errno = EAGAIN;
1491           size = -1;
1492         }
1493       else
1494         size = results;
1495     }
1496   else
1497     {
1498       size = libc_sendfile (out_fd, in_fd, offset, len);
1499     }
1500
1501 done:
1502   return size;
1503 }
1504
1505 ssize_t
1506 sendfile64 (int out_fd, int in_fd, off_t * offset, size_t len)
1507 {
1508   return sendfile (out_fd, in_fd, offset, len);
1509 }
1510
1511 ssize_t
1512 recv (int fd, void *buf, size_t n, int flags)
1513 {
1514   vls_handle_t vlsh;
1515   ssize_t size;
1516
1517   if ((errno = -ldp_init ()))
1518     return -1;
1519
1520   vlsh = ldp_fd_to_vlsh (fd);
1521   if (vlsh != VLS_INVALID_HANDLE)
1522     {
1523       size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1524       if (size < 0)
1525         {
1526           errno = -size;
1527           size = -1;
1528         }
1529     }
1530   else
1531     {
1532       size = libc_recv (fd, buf, n, flags);
1533     }
1534
1535   return size;
1536 }
1537
1538 static int
1539 ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n, int flags,
1540                __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1541 {
1542   vppcom_endpt_t *ep = 0;
1543   vppcom_endpt_t _ep;
1544
1545   if (addr)
1546     {
1547       ep = &_ep;
1548       switch (addr->sa_family)
1549         {
1550         case AF_INET:
1551           ep->is_ip4 = VPPCOM_IS_IP4;
1552           ep->ip =
1553             (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
1554           ep->port = (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
1555           break;
1556
1557         case AF_INET6:
1558           ep->is_ip4 = VPPCOM_IS_IP6;
1559           ep->ip =
1560             (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1561           ep->port =
1562             (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
1563           break;
1564
1565         default:
1566           return EAFNOSUPPORT;
1567         }
1568     }
1569
1570   return vls_sendto (vlsh, (void *) buf, n, flags, ep);
1571 }
1572
1573 static int
1574 ldp_vls_recvfrom (vls_handle_t vlsh, void *__restrict buf, size_t n,
1575                   int flags, __SOCKADDR_ARG addr,
1576                   socklen_t * __restrict addr_len)
1577 {
1578   u8 src_addr[sizeof (struct sockaddr_in6)];
1579   vppcom_endpt_t ep;
1580   ssize_t size;
1581   int rv;
1582
1583   if (addr)
1584     {
1585       ep.ip = src_addr;
1586       size = vls_recvfrom (vlsh, buf, n, flags, &ep);
1587
1588       if (size > 0)
1589         {
1590           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1591           if (rv < 0)
1592             size = rv;
1593         }
1594     }
1595   else
1596     size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1597
1598   return size;
1599 }
1600
1601 ssize_t
1602 sendto (int fd, const void *buf, size_t n, int flags,
1603         __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1604 {
1605   vls_handle_t vlsh;
1606   ssize_t size;
1607
1608   if ((errno = -ldp_init ()))
1609     return -1;
1610
1611   vlsh = ldp_fd_to_vlsh (fd);
1612   if (vlsh != INVALID_SESSION_ID)
1613     {
1614       size = ldp_vls_sendo (vlsh, buf, n, flags, addr, addr_len);
1615       if (size < 0)
1616         {
1617           errno = -size;
1618           size = -1;
1619         }
1620     }
1621   else
1622     {
1623       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
1624     }
1625
1626   return size;
1627 }
1628
1629 ssize_t
1630 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
1631           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1632 {
1633   vls_handle_t vlsh;
1634   ssize_t size;
1635
1636   if ((errno = -ldp_init ()))
1637     return -1;
1638
1639   vlsh = ldp_fd_to_vlsh (fd);
1640   if (vlsh != VLS_INVALID_HANDLE)
1641     {
1642       size = ldp_vls_recvfrom (vlsh, buf, n, flags, addr, addr_len);
1643       if (size < 0)
1644         {
1645           errno = -size;
1646           size = -1;
1647         }
1648     }
1649   else
1650     {
1651       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
1652     }
1653
1654   return size;
1655 }
1656
1657 ssize_t
1658 sendmsg (int fd, const struct msghdr * msg, int flags)
1659 {
1660   vls_handle_t vlsh;
1661   ssize_t size;
1662
1663   if ((errno = -ldp_init ()))
1664     return -1;
1665
1666   vlsh = ldp_fd_to_vlsh (fd);
1667   if (vlsh != VLS_INVALID_HANDLE)
1668     {
1669       struct iovec *iov = msg->msg_iov;
1670       ssize_t total = 0;
1671       int i, rv;
1672
1673       for (i = 0; i < msg->msg_iovlen; ++i)
1674         {
1675           rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1676                               msg->msg_name, msg->msg_namelen);
1677           if (rv < 0)
1678             break;
1679           else
1680             {
1681               total += rv;
1682               if (rv < iov[i].iov_len)
1683                 break;
1684             }
1685         }
1686
1687       if (rv < 0 && total == 0)
1688         {
1689           errno = -rv;
1690           size = -1;
1691         }
1692       else
1693         size = total;
1694     }
1695   else
1696     {
1697       size = libc_sendmsg (fd, msg, flags);
1698     }
1699
1700   return size;
1701 }
1702
1703 #ifdef USE_GNU
1704 int
1705 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1706 {
1707   ssize_t size;
1708   const char *func_str;
1709   u32 sh = ldp_fd_to_vlsh (fd);
1710
1711   if ((errno = -ldp_init ()))
1712     return -1;
1713
1714   if (sh != INVALID_SESSION_ID)
1715     {
1716       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1717       errno = ENOSYS;
1718       size = -1;
1719     }
1720   else
1721     {
1722       func_str = "libc_sendmmsg";
1723
1724       if (LDP_DEBUG > 2)
1725         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1726                       "vmessages %p, vlen %u, flags 0x%x",
1727                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1728
1729       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1730     }
1731
1732   if (LDP_DEBUG > 2)
1733     {
1734       if (size < 0)
1735         {
1736           int errno_val = errno;
1737           perror (func_str);
1738           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1739                         "rv %d, errno = %d", getpid (), fd, fd,
1740                         func_str, size, errno_val);
1741           errno = errno_val;
1742         }
1743       else
1744         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1745                       getpid (), fd, fd, size, size);
1746     }
1747   return size;
1748 }
1749 #endif
1750
1751 ssize_t
1752 recvmsg (int fd, struct msghdr * msg, int flags)
1753 {
1754   vls_handle_t vlsh;
1755   ssize_t size;
1756
1757   if ((errno = -ldp_init ()))
1758     return -1;
1759
1760   vlsh = ldp_fd_to_vlsh (fd);
1761   if (vlsh != VLS_INVALID_HANDLE)
1762     {
1763       struct iovec *iov = msg->msg_iov;
1764       ssize_t max_deq, total = 0;
1765       int i, rv;
1766
1767       max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
1768       if (!max_deq)
1769         return 0;
1770
1771       for (i = 0; i < msg->msg_iovlen; i++)
1772         {
1773           rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1774                                  (i == 0 ? msg->msg_name : NULL),
1775                                  (i == 0 ? &msg->msg_namelen : NULL));
1776           if (rv <= 0)
1777             break;
1778           else
1779             {
1780               total += rv;
1781               if (rv < iov[i].iov_len)
1782                 break;
1783             }
1784           if (total >= max_deq)
1785             break;
1786         }
1787
1788       if (rv < 0 && total == 0)
1789         {
1790           errno = -rv;
1791           size = -1;
1792         }
1793       else
1794         size = total;
1795     }
1796   else
1797     {
1798       size = libc_recvmsg (fd, msg, flags);
1799     }
1800
1801   return size;
1802 }
1803
1804 #ifdef USE_GNU
1805 int
1806 recvmmsg (int fd, struct mmsghdr *vmessages,
1807           unsigned int vlen, int flags, struct timespec *tmo)
1808 {
1809   ssize_t size;
1810   const char *func_str;
1811   u32 sh = ldp_fd_to_vlsh (fd);
1812
1813   if ((errno = -ldp_init ()))
1814     return -1;
1815
1816   if (sh != INVALID_SESSION_ID)
1817     {
1818       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1819       errno = ENOSYS;
1820       size = -1;
1821     }
1822   else
1823     {
1824       func_str = "libc_recvmmsg";
1825
1826       if (LDP_DEBUG > 2)
1827         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1828                       "vmessages %p, vlen %u, flags 0x%x, tmo %p",
1829                       getpid (), fd, fd, func_str, vmessages, vlen,
1830                       flags, tmo);
1831
1832       size = libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1833     }
1834
1835   if (LDP_DEBUG > 2)
1836     {
1837       if (size < 0)
1838         {
1839           int errno_val = errno;
1840           perror (func_str);
1841           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1842                         "rv %d, errno = %d", getpid (), fd, fd,
1843                         func_str, size, errno_val);
1844           errno = errno_val;
1845         }
1846       else
1847         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1848                       getpid (), fd, fd, size, size);
1849     }
1850   return size;
1851 }
1852 #endif
1853
1854 int
1855 getsockopt (int fd, int level, int optname,
1856             void *__restrict optval, socklen_t * __restrict optlen)
1857 {
1858   vls_handle_t vlsh;
1859   int rv;
1860
1861   if ((errno = -ldp_init ()))
1862     return -1;
1863
1864   vlsh = ldp_fd_to_vlsh (fd);
1865   if (vlsh != VLS_INVALID_HANDLE)
1866     {
1867       rv = -EOPNOTSUPP;
1868
1869       switch (level)
1870         {
1871         case SOL_TCP:
1872           switch (optname)
1873             {
1874             case TCP_NODELAY:
1875               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
1876                              optval, optlen);
1877               break;
1878             case TCP_MAXSEG:
1879               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
1880                              optval, optlen);
1881               break;
1882             case TCP_KEEPIDLE:
1883               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
1884                              optval, optlen);
1885               break;
1886             case TCP_KEEPINTVL:
1887               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
1888                              optval, optlen);
1889               break;
1890             case TCP_INFO:
1891               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
1892                 {
1893                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
1894                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
1895                   memset (optval, 0, *optlen);
1896                   rv = VPPCOM_OK;
1897                 }
1898               else
1899                 rv = -EFAULT;
1900               break;
1901             case TCP_CONGESTION:
1902               *optlen = strlen ("cubic");
1903               strncpy (optval, "cubic", *optlen + 1);
1904               rv = 0;
1905               break;
1906             default:
1907               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
1908                     "optname %d unsupported!", fd, vlsh, optname);
1909               break;
1910             }
1911           break;
1912         case SOL_IPV6:
1913           switch (optname)
1914             {
1915             case IPV6_V6ONLY:
1916               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
1917               break;
1918             default:
1919               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
1920                     "optname %d unsupported!", fd, vlsh, optname);
1921               break;
1922             }
1923           break;
1924         case SOL_SOCKET:
1925           switch (optname)
1926             {
1927             case SO_ACCEPTCONN:
1928               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
1929               break;
1930             case SO_KEEPALIVE:
1931               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
1932               break;
1933             case SO_PROTOCOL:
1934               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
1935               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
1936               break;
1937             case SO_SNDBUF:
1938               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
1939                              optval, optlen);
1940               break;
1941             case SO_RCVBUF:
1942               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
1943                              optval, optlen);
1944               break;
1945             case SO_REUSEADDR:
1946               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
1947               break;
1948             case SO_BROADCAST:
1949               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
1950               break;
1951             case SO_ERROR:
1952               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
1953               break;
1954             default:
1955               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
1956                     "optname %d unsupported!", fd, vlsh, optname);
1957               break;
1958             }
1959           break;
1960         default:
1961           break;
1962         }
1963
1964       if (rv != VPPCOM_OK)
1965         {
1966           errno = -rv;
1967           rv = -1;
1968         }
1969     }
1970   else
1971     {
1972       rv = libc_getsockopt (fd, level, optname, optval, optlen);
1973     }
1974
1975   return rv;
1976 }
1977
1978 int
1979 setsockopt (int fd, int level, int optname,
1980             const void *optval, socklen_t optlen)
1981 {
1982   vls_handle_t vlsh;
1983   int rv;
1984
1985   if ((errno = -ldp_init ()))
1986     return -1;
1987
1988   vlsh = ldp_fd_to_vlsh (fd);
1989   if (vlsh != VLS_INVALID_HANDLE)
1990     {
1991       rv = -EOPNOTSUPP;
1992
1993       switch (level)
1994         {
1995         case SOL_TCP:
1996           switch (optname)
1997             {
1998             case TCP_NODELAY:
1999               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
2000                              (void *) optval, &optlen);
2001               break;
2002             case TCP_MAXSEG:
2003               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
2004                              (void *) optval, &optlen);
2005               break;
2006             case TCP_KEEPIDLE:
2007               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2008                              (void *) optval, &optlen);
2009               break;
2010             case TCP_KEEPINTVL:
2011               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2012                              (void *) optval, &optlen);
2013               break;
2014             case TCP_CONGESTION:
2015             case TCP_CORK:
2016               /* Ignore */
2017               rv = 0;
2018               break;
2019             default:
2020               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2021                     "optname %d unsupported!", fd, vlsh, optname);
2022               break;
2023             }
2024           break;
2025         case SOL_IPV6:
2026           switch (optname)
2027             {
2028             case IPV6_V6ONLY:
2029               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2030                              (void *) optval, &optlen);
2031               break;
2032             default:
2033               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2034                     "optname %d unsupported!", fd, vlsh, optname);
2035               break;
2036             }
2037           break;
2038         case SOL_SOCKET:
2039           switch (optname)
2040             {
2041             case SO_KEEPALIVE:
2042               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2043                              (void *) optval, &optlen);
2044               break;
2045             case SO_REUSEADDR:
2046               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2047                              (void *) optval, &optlen);
2048               break;
2049             case SO_BROADCAST:
2050               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2051                              (void *) optval, &optlen);
2052               break;
2053             default:
2054               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2055                     "optname %d unsupported!", fd, vlsh, optname);
2056               break;
2057             }
2058           break;
2059         default:
2060           break;
2061         }
2062
2063       if (rv != VPPCOM_OK)
2064         {
2065           errno = -rv;
2066           rv = -1;
2067         }
2068     }
2069   else
2070     {
2071       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2072     }
2073
2074   return rv;
2075 }
2076
2077 int
2078 listen (int fd, int n)
2079 {
2080   vls_handle_t vlsh;
2081   int rv;
2082
2083   if ((errno = -ldp_init ()))
2084     return -1;
2085
2086   vlsh = ldp_fd_to_vlsh (fd);
2087   if (vlsh != VLS_INVALID_HANDLE)
2088     {
2089       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2090
2091       rv = vls_listen (vlsh, n);
2092       if (rv != VPPCOM_OK)
2093         {
2094           errno = -rv;
2095           rv = -1;
2096         }
2097     }
2098   else
2099     {
2100       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2101       rv = libc_listen (fd, n);
2102     }
2103
2104   LDBG (1, "fd %d: returning %d", fd, rv);
2105   return rv;
2106 }
2107
2108 static inline int
2109 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
2110              socklen_t * __restrict addr_len, int flags)
2111 {
2112   vls_handle_t listen_vlsh, accept_vlsh;
2113   int rv;
2114
2115   if ((errno = -ldp_init ()))
2116     return -1;
2117
2118   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2119   if (listen_vlsh != VLS_INVALID_HANDLE)
2120     {
2121       vppcom_endpt_t ep;
2122       u8 src_addr[sizeof (struct sockaddr_in6)];
2123       memset (&ep, 0, sizeof (ep));
2124       ep.ip = src_addr;
2125
2126       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2127             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2128
2129       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2130       if (accept_vlsh < 0)
2131         {
2132           errno = -accept_vlsh;
2133           rv = -1;
2134         }
2135       else
2136         {
2137           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2138           if (rv != VPPCOM_OK)
2139             {
2140               (void) vls_close (accept_vlsh);
2141               errno = -rv;
2142               rv = -1;
2143             }
2144           else
2145             {
2146               rv = ldp_vlsh_to_fd (accept_vlsh);
2147             }
2148         }
2149     }
2150   else
2151     {
2152       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2153             " flags 0x%x", listen_fd, addr, addr_len, flags);
2154
2155       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2156     }
2157
2158   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2159
2160   return rv;
2161 }
2162
2163 int
2164 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2165          int flags)
2166 {
2167   return ldp_accept4 (fd, addr, addr_len, flags);
2168 }
2169
2170 int
2171 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2172 {
2173   return ldp_accept4 (fd, addr, addr_len, 0);
2174 }
2175
2176 int
2177 shutdown (int fd, int how)
2178 {
2179   vls_handle_t vlsh;
2180   int rv = 0, flags;
2181   u32 flags_len = sizeof (flags);
2182
2183   if ((errno = -ldp_init ()))
2184     return -1;
2185
2186   vlsh = ldp_fd_to_vlsh (fd);
2187   if (vlsh != VLS_INVALID_HANDLE)
2188     {
2189       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2190
2191       if (vls_attr (vlsh, VPPCOM_ATTR_SET_SHUT, &how, &flags_len))
2192         {
2193           close (fd);
2194           return -1;
2195         }
2196
2197       if (vls_attr (vlsh, VPPCOM_ATTR_GET_SHUT, &flags, &flags_len))
2198         {
2199           close (fd);
2200           return -1;
2201         }
2202
2203       if (flags == SHUT_RDWR)
2204         rv = close (fd);
2205     }
2206   else
2207     {
2208       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2209       rv = libc_shutdown (fd, how);
2210     }
2211
2212   return rv;
2213 }
2214
2215 int
2216 epoll_create1 (int flags)
2217 {
2218   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2219   vls_handle_t vlsh;
2220   int rv;
2221
2222   if ((errno = -ldp_init ()))
2223     return -1;
2224
2225   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2226     {
2227       /* Make sure workers have been allocated */
2228       if (!ldp->workers)
2229         {
2230           ldp_alloc_workers ();
2231           ldpw = ldp_worker_get_current ();
2232         }
2233       rv = libc_epoll_create1 (flags);
2234       ldp->vcl_needs_real_epoll = 0;
2235       ldpw->vcl_mq_epfd = rv;
2236       LDBG (0, "created vcl epfd %u", rv);
2237       return rv;
2238     }
2239
2240   vlsh = vls_epoll_create ();
2241   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2242     {
2243       errno = -vlsh;
2244       rv = -1;
2245     }
2246   else
2247     {
2248       rv = ldp_vlsh_to_fd (vlsh);
2249     }
2250   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2251   return rv;
2252 }
2253
2254 int
2255 epoll_create (int size)
2256 {
2257   return epoll_create1 (0);
2258 }
2259
2260 int
2261 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2262 {
2263   vls_handle_t vep_vlsh, vlsh;
2264   int rv;
2265
2266   if ((errno = -ldp_init ()))
2267     return -1;
2268
2269   vep_vlsh = ldp_fd_to_vlsh (epfd);
2270   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2271     {
2272       /* The LDP epoll_create1 always creates VCL epfd's.
2273        * The app should never have a kernel base epoll fd unless it
2274        * was acquired outside of the LD_PRELOAD process context.
2275        * In any case, if we get one, punt it to libc_epoll_ctl.
2276        */
2277       LDBG (1, "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2278             " event %p", epfd, op, fd, event);
2279
2280       rv = libc_epoll_ctl (epfd, op, fd, event);
2281       goto done;
2282     }
2283
2284   vlsh = ldp_fd_to_vlsh (fd);
2285
2286   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2287         vlsh, op);
2288
2289   if (vlsh != VLS_INVALID_HANDLE)
2290     {
2291       LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2292             " event %p", epfd, vep_vlsh, op, vlsh, event);
2293
2294       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2295       if (rv != VPPCOM_OK)
2296         {
2297           errno = -rv;
2298           rv = -1;
2299         }
2300     }
2301   else
2302     {
2303       int libc_epfd;
2304       u32 size = sizeof (epfd);
2305
2306       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2307       if (!libc_epfd)
2308         {
2309           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2310                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2311
2312           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2313           if (libc_epfd < 0)
2314             {
2315               rv = libc_epfd;
2316               goto done;
2317             }
2318
2319           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2320                          &size);
2321           if (rv < 0)
2322             {
2323               errno = -rv;
2324               rv = -1;
2325               goto done;
2326             }
2327         }
2328       else if (PREDICT_FALSE (libc_epfd < 0))
2329         {
2330           errno = -epfd;
2331           rv = -1;
2332           goto done;
2333         }
2334
2335       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2336             " event %p", epfd, libc_epfd, op, fd, event);
2337
2338       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2339     }
2340
2341 done:
2342   return rv;
2343 }
2344
2345 static inline int
2346 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2347                  int timeout, const sigset_t * sigmask)
2348 {
2349   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2350   double time_to_wait = (double) 0, max_time;
2351   int libc_epfd, rv = 0;
2352   vls_handle_t ep_vlsh;
2353
2354   if ((errno = -ldp_init ()))
2355     return -1;
2356
2357   if (PREDICT_FALSE (!events || (timeout < -1)))
2358     {
2359       errno = EFAULT;
2360       return -1;
2361     }
2362
2363   if (epfd == ldpw->vcl_mq_epfd)
2364     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2365
2366   ep_vlsh = ldp_fd_to_vlsh (epfd);
2367   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2368     {
2369       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2370       errno = EBADFD;
2371       return -1;
2372     }
2373
2374   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2375     clib_time_init (&ldpw->clib_time);
2376   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2377   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2378
2379   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2380   if (PREDICT_FALSE (libc_epfd < 0))
2381     {
2382       errno = -libc_epfd;
2383       rv = -1;
2384       goto done;
2385     }
2386
2387   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2388         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2389         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2390   do
2391     {
2392       if (!ldpw->epoll_wait_vcl)
2393         {
2394           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2395           if (rv > 0)
2396             {
2397               ldpw->epoll_wait_vcl = 1;
2398               goto done;
2399             }
2400           else if (rv < 0)
2401             {
2402               errno = -rv;
2403               rv = -1;
2404               goto done;
2405             }
2406         }
2407       else
2408         ldpw->epoll_wait_vcl = 0;
2409
2410       if (libc_epfd > 0)
2411         {
2412           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2413           if (rv != 0)
2414             goto done;
2415         }
2416     }
2417   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2418
2419 done:
2420   return rv;
2421 }
2422
2423 static inline int
2424 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2425                          int maxevents, int timeout, const sigset_t * sigmask)
2426 {
2427   ldp_worker_ctx_t *ldpw;
2428   int libc_epfd, rv = 0, num_ev;
2429   vls_handle_t ep_vlsh;
2430
2431   if ((errno = -ldp_init ()))
2432     return -1;
2433
2434   if (PREDICT_FALSE (!events || (timeout < -1)))
2435     {
2436       errno = EFAULT;
2437       return -1;
2438     }
2439
2440   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2441    * one thread but it is now used on another */
2442   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2443     vls_register_vcl_worker ();
2444
2445   ldpw = ldp_worker_get_current ();
2446   if (epfd == ldpw->vcl_mq_epfd)
2447     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2448
2449   ep_vlsh = ldp_fd_to_vlsh (epfd);
2450   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2451     {
2452       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2453       errno = EBADFD;
2454       return -1;
2455     }
2456
2457   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2458   if (PREDICT_FALSE (!libc_epfd))
2459     {
2460       u32 size = sizeof (epfd);
2461
2462       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2463             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2464       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2465       if (libc_epfd < 0)
2466         {
2467           rv = libc_epfd;
2468           goto done;
2469         }
2470
2471       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2472       if (rv < 0)
2473         {
2474           errno = -rv;
2475           rv = -1;
2476           goto done;
2477         }
2478     }
2479   if (PREDICT_FALSE (libc_epfd <= 0))
2480     {
2481       errno = -libc_epfd;
2482       rv = -1;
2483       goto done;
2484     }
2485
2486   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2487     {
2488       struct epoll_event e = { 0 };
2489       e.events = EPOLLIN;
2490       e.data.fd = ldpw->vcl_mq_epfd;
2491       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2492           0)
2493         {
2494           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2495                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2496           rv = -1;
2497           goto done;
2498         }
2499       ldpw->mq_epfd_added = 1;
2500     }
2501
2502   rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2503   if (rv > 0)
2504     goto done;
2505   else if (PREDICT_FALSE (rv < 0))
2506     {
2507       errno = -rv;
2508       rv = -1;
2509       goto done;
2510     }
2511
2512   rv = libc_epoll_pwait (libc_epfd, events, maxevents, timeout, sigmask);
2513   if (rv <= 0)
2514     goto done;
2515   for (int i = 0; i < rv; i++)
2516     {
2517       if (events[i].data.fd == ldpw->vcl_mq_epfd)
2518         {
2519           /* We should remove mq epoll fd from events. */
2520           rv--;
2521           if (i != rv)
2522             {
2523               events[i].events = events[rv].events;
2524               events[i].data.u64 = events[rv].data.u64;
2525             }
2526           num_ev = vls_epoll_wait (ep_vlsh, &events[rv], maxevents - rv, 0);
2527           if (PREDICT_TRUE (num_ev > 0))
2528             rv += num_ev;
2529           break;
2530         }
2531     }
2532
2533 done:
2534   return rv;
2535 }
2536
2537 int
2538 epoll_pwait (int epfd, struct epoll_event *events,
2539              int maxevents, int timeout, const sigset_t * sigmask)
2540 {
2541   if (vls_use_eventfd ())
2542     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2543                                     sigmask);
2544   else
2545     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2546 }
2547
2548 int
2549 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2550 {
2551   if (vls_use_eventfd ())
2552     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2553   else
2554     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2555 }
2556
2557 int
2558 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2559 {
2560   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2561   int rv, i, n_revents = 0;
2562   vls_handle_t vlsh;
2563   vcl_poll_t *vp;
2564   double max_time;
2565
2566   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2567
2568   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2569     clib_time_init (&ldpw->clib_time);
2570
2571   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2572   max_time += clib_time_now (&ldpw->clib_time);
2573
2574   for (i = 0; i < nfds; i++)
2575     {
2576       if (fds[i].fd < 0)
2577         continue;
2578
2579       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2580       if (vlsh != VLS_INVALID_HANDLE)
2581         {
2582           fds[i].fd = -fds[i].fd;
2583           vec_add2 (ldpw->vcl_poll, vp, 1);
2584           vp->fds_ndx = i;
2585           vp->sh = vlsh_to_sh (vlsh);
2586           vp->events = fds[i].events;
2587 #ifdef __USE_XOPEN2K
2588           if (fds[i].events & POLLRDNORM)
2589             vp->events |= POLLIN;
2590           if (fds[i].events & POLLWRNORM)
2591             vp->events |= POLLOUT;
2592 #endif
2593           vp->revents = fds[i].revents;
2594         }
2595       else
2596         {
2597           vec_add1 (ldpw->libc_poll, fds[i]);
2598           vec_add1 (ldpw->libc_poll_idxs, i);
2599         }
2600     }
2601
2602   do
2603     {
2604       if (vec_len (ldpw->vcl_poll))
2605         {
2606           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2607           if (rv < 0)
2608             {
2609               errno = -rv;
2610               rv = -1;
2611               goto done;
2612             }
2613           else
2614             n_revents += rv;
2615         }
2616
2617       if (vec_len (ldpw->libc_poll))
2618         {
2619           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2620           if (rv < 0)
2621             goto done;
2622           else
2623             n_revents += rv;
2624         }
2625
2626       if (n_revents)
2627         {
2628           rv = n_revents;
2629           goto done;
2630         }
2631     }
2632   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2633   rv = 0;
2634
2635 done:
2636   vec_foreach (vp, ldpw->vcl_poll)
2637   {
2638     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2639     fds[vp->fds_ndx].revents = vp->revents;
2640 #ifdef __USE_XOPEN2K
2641     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2642         (fds[vp->fds_ndx].events & POLLRDNORM))
2643       fds[vp->fds_ndx].revents |= POLLRDNORM;
2644     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2645         (fds[vp->fds_ndx].events & POLLWRNORM))
2646       fds[vp->fds_ndx].revents |= POLLWRNORM;
2647 #endif
2648   }
2649   vec_reset_length (ldpw->vcl_poll);
2650
2651   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2652     {
2653       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2654     }
2655   vec_reset_length (ldpw->libc_poll_idxs);
2656   vec_reset_length (ldpw->libc_poll);
2657
2658   return rv;
2659 }
2660
2661 #ifdef USE_GNU
2662 int
2663 ppoll (struct pollfd *fds, nfds_t nfds,
2664        const struct timespec *timeout, const sigset_t * sigmask)
2665 {
2666   if ((errno = -ldp_init ()))
2667     return -1;
2668
2669   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2670   errno = ENOSYS;
2671
2672
2673   return -1;
2674 }
2675 #endif
2676
2677 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2678
2679 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2680
2681 /*
2682  * This function is called when the library is loaded
2683  */
2684 void
2685 ldp_constructor (void)
2686 {
2687   swrap_constructor ();
2688   if (ldp_init () != 0)
2689     {
2690       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2691                getpid ());
2692       _exit (1);
2693     }
2694   else if (LDP_DEBUG > 0)
2695     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2696 }
2697
2698 /*
2699  * This function is called when the library is unloaded
2700  */
2701 void
2702 ldp_destructor (void)
2703 {
2704   /*
2705      swrap_destructor ();
2706      if (ldp->init)
2707      ldp->init = 0;
2708    */
2709
2710   /* Don't use clib_warning() here because that calls writev()
2711    * which will call ldp_init().
2712    */
2713   if (LDP_DEBUG > 0)
2714     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2715              __func__, __LINE__, getpid ());
2716 }
2717
2718
2719 /*
2720  * fd.io coding-style-patch-verification: ON
2721  *
2722  * Local Variables:
2723  * eval: (c-set-style "gnu")
2724  * End:
2725  */