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