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