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