54a8f66354febfaee39e64f2cd7a6dfe5ca2ab3f
[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 static int
1534 ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n, int flags,
1535                __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1536 {
1537   vppcom_endpt_t *ep = 0;
1538   vppcom_endpt_t _ep;
1539
1540   if (addr)
1541     {
1542       ep = &_ep;
1543       switch (addr->sa_family)
1544         {
1545         case AF_INET:
1546           ep->is_ip4 = VPPCOM_IS_IP4;
1547           ep->ip =
1548             (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
1549           ep->port = (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
1550           break;
1551
1552         case AF_INET6:
1553           ep->is_ip4 = VPPCOM_IS_IP6;
1554           ep->ip =
1555             (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1556           ep->port =
1557             (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
1558           break;
1559
1560         default:
1561           return EAFNOSUPPORT;
1562         }
1563     }
1564
1565   return vls_sendto (vlsh, (void *) buf, n, flags, ep);
1566 }
1567
1568 static int
1569 ldp_vls_recvfrom (vls_handle_t vlsh, void *__restrict buf, size_t n,
1570                   int flags, __SOCKADDR_ARG addr,
1571                   socklen_t * __restrict addr_len)
1572 {
1573   u8 src_addr[sizeof (struct sockaddr_in6)];
1574   vppcom_endpt_t ep;
1575   ssize_t size;
1576   int rv;
1577
1578   if (addr)
1579     {
1580       ep.ip = src_addr;
1581       size = vls_recvfrom (vlsh, buf, n, flags, &ep);
1582
1583       if (size > 0)
1584         {
1585           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1586           if (rv < 0)
1587             size = rv;
1588         }
1589     }
1590   else
1591     size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1592
1593   return size;
1594 }
1595
1596 ssize_t
1597 sendto (int fd, const void *buf, size_t n, int flags,
1598         __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1599 {
1600   vls_handle_t vlsh;
1601   ssize_t size;
1602
1603   ldp_init_check ();
1604
1605   vlsh = ldp_fd_to_vlsh (fd);
1606   if (vlsh != INVALID_SESSION_ID)
1607     {
1608       size = ldp_vls_sendo (vlsh, buf, n, flags, addr, addr_len);
1609       if (size < 0)
1610         {
1611           errno = -size;
1612           size = -1;
1613         }
1614     }
1615   else
1616     {
1617       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
1618     }
1619
1620   return size;
1621 }
1622
1623 ssize_t
1624 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
1625           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1626 {
1627   vls_handle_t vlsh;
1628   ssize_t size;
1629
1630   ldp_init_check ();
1631
1632   vlsh = ldp_fd_to_vlsh (fd);
1633   if (vlsh != VLS_INVALID_HANDLE)
1634     {
1635       size = ldp_vls_recvfrom (vlsh, buf, n, flags, addr, addr_len);
1636       if (size < 0)
1637         {
1638           errno = -size;
1639           size = -1;
1640         }
1641     }
1642   else
1643     {
1644       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
1645     }
1646
1647   return size;
1648 }
1649
1650 ssize_t
1651 sendmsg (int fd, const struct msghdr * msg, int flags)
1652 {
1653   vls_handle_t vlsh;
1654   ssize_t size;
1655
1656   ldp_init_check ();
1657
1658   vlsh = ldp_fd_to_vlsh (fd);
1659   if (vlsh != VLS_INVALID_HANDLE)
1660     {
1661       struct iovec *iov = msg->msg_iov;
1662       ssize_t total = 0;
1663       int i, rv;
1664
1665       for (i = 0; i < msg->msg_iovlen; ++i)
1666         {
1667           rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1668                               msg->msg_name, msg->msg_namelen);
1669           if (rv < 0)
1670             break;
1671           else
1672             {
1673               total += rv;
1674               if (rv < iov[i].iov_len)
1675                 break;
1676             }
1677         }
1678
1679       if (rv < 0 && total == 0)
1680         {
1681           errno = -rv;
1682           size = -1;
1683         }
1684       else
1685         size = total;
1686     }
1687   else
1688     {
1689       size = libc_sendmsg (fd, msg, flags);
1690     }
1691
1692   return size;
1693 }
1694
1695 #ifdef USE_GNU
1696 int
1697 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1698 {
1699   ssize_t size;
1700   const char *func_str;
1701   u32 sh = ldp_fd_to_vlsh (fd);
1702
1703   ldp_init_check ();
1704
1705   if (sh != INVALID_SESSION_ID)
1706     {
1707       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1708       errno = ENOSYS;
1709       size = -1;
1710     }
1711   else
1712     {
1713       func_str = "libc_sendmmsg";
1714
1715       if (LDP_DEBUG > 2)
1716         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1717                       "vmessages %p, vlen %u, flags 0x%x",
1718                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1719
1720       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1721     }
1722
1723   if (LDP_DEBUG > 2)
1724     {
1725       if (size < 0)
1726         {
1727           int errno_val = errno;
1728           perror (func_str);
1729           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1730                         "rv %d, errno = %d", getpid (), fd, fd,
1731                         func_str, size, errno_val);
1732           errno = errno_val;
1733         }
1734       else
1735         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1736                       getpid (), fd, fd, size, size);
1737     }
1738   return size;
1739 }
1740 #endif
1741
1742 ssize_t
1743 recvmsg (int fd, struct msghdr * msg, int flags)
1744 {
1745   vls_handle_t vlsh;
1746   ssize_t size;
1747
1748   ldp_init_check ();
1749
1750   vlsh = ldp_fd_to_vlsh (fd);
1751   if (vlsh != VLS_INVALID_HANDLE)
1752     {
1753       struct iovec *iov = msg->msg_iov;
1754       ssize_t max_deq, total = 0;
1755       int i, rv;
1756
1757       max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
1758       if (!max_deq)
1759         return 0;
1760
1761       for (i = 0; i < msg->msg_iovlen; i++)
1762         {
1763           rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1764                                  (i == 0 ? msg->msg_name : NULL),
1765                                  (i == 0 ? &msg->msg_namelen : NULL));
1766           if (rv <= 0)
1767             break;
1768           else
1769             {
1770               total += rv;
1771               if (rv < iov[i].iov_len)
1772                 break;
1773             }
1774           if (total >= max_deq)
1775             break;
1776         }
1777
1778       if (rv < 0 && total == 0)
1779         {
1780           errno = -rv;
1781           size = -1;
1782         }
1783       else
1784         size = total;
1785     }
1786   else
1787     {
1788       size = libc_recvmsg (fd, msg, flags);
1789     }
1790
1791   return size;
1792 }
1793
1794 #ifdef USE_GNU
1795 int
1796 recvmmsg (int fd, struct mmsghdr *vmessages,
1797           unsigned int vlen, int flags, struct timespec *tmo)
1798 {
1799   ssize_t size;
1800   const char *func_str;
1801   u32 sh = ldp_fd_to_vlsh (fd);
1802
1803   ldp_init_check ();
1804
1805   if (sh != INVALID_SESSION_ID)
1806     {
1807       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1808       errno = ENOSYS;
1809       size = -1;
1810     }
1811   else
1812     {
1813       func_str = "libc_recvmmsg";
1814
1815       if (LDP_DEBUG > 2)
1816         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1817                       "vmessages %p, vlen %u, flags 0x%x, tmo %p",
1818                       getpid (), fd, fd, func_str, vmessages, vlen,
1819                       flags, tmo);
1820
1821       size = libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1822     }
1823
1824   if (LDP_DEBUG > 2)
1825     {
1826       if (size < 0)
1827         {
1828           int errno_val = errno;
1829           perror (func_str);
1830           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1831                         "rv %d, errno = %d", getpid (), fd, fd,
1832                         func_str, size, errno_val);
1833           errno = errno_val;
1834         }
1835       else
1836         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1837                       getpid (), fd, fd, size, size);
1838     }
1839   return size;
1840 }
1841 #endif
1842
1843 int
1844 getsockopt (int fd, int level, int optname,
1845             void *__restrict optval, socklen_t * __restrict optlen)
1846 {
1847   vls_handle_t vlsh;
1848   int rv;
1849
1850   ldp_init_check ();
1851
1852   vlsh = ldp_fd_to_vlsh (fd);
1853   if (vlsh != VLS_INVALID_HANDLE)
1854     {
1855       rv = -EOPNOTSUPP;
1856
1857       switch (level)
1858         {
1859         case SOL_TCP:
1860           switch (optname)
1861             {
1862             case TCP_NODELAY:
1863               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
1864                              optval, optlen);
1865               break;
1866             case TCP_MAXSEG:
1867               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
1868                              optval, optlen);
1869               break;
1870             case TCP_KEEPIDLE:
1871               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
1872                              optval, optlen);
1873               break;
1874             case TCP_KEEPINTVL:
1875               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
1876                              optval, optlen);
1877               break;
1878             case TCP_INFO:
1879               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
1880                 {
1881                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
1882                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
1883                   memset (optval, 0, *optlen);
1884                   rv = VPPCOM_OK;
1885                 }
1886               else
1887                 rv = -EFAULT;
1888               break;
1889             case TCP_CONGESTION:
1890               *optlen = strlen ("cubic");
1891               strncpy (optval, "cubic", *optlen + 1);
1892               rv = 0;
1893               break;
1894             default:
1895               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
1896                     "optname %d unsupported!", fd, vlsh, optname);
1897               break;
1898             }
1899           break;
1900         case SOL_IPV6:
1901           switch (optname)
1902             {
1903             case IPV6_V6ONLY:
1904               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
1905               break;
1906             default:
1907               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
1908                     "optname %d unsupported!", fd, vlsh, optname);
1909               break;
1910             }
1911           break;
1912         case SOL_SOCKET:
1913           switch (optname)
1914             {
1915             case SO_ACCEPTCONN:
1916               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
1917               break;
1918             case SO_KEEPALIVE:
1919               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
1920               break;
1921             case SO_PROTOCOL:
1922               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
1923               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
1924               break;
1925             case SO_SNDBUF:
1926               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
1927                              optval, optlen);
1928               break;
1929             case SO_RCVBUF:
1930               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
1931                              optval, optlen);
1932               break;
1933             case SO_REUSEADDR:
1934               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
1935               break;
1936             case SO_REUSEPORT:
1937               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen);
1938               break;
1939             case SO_BROADCAST:
1940               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
1941               break;
1942             case SO_DOMAIN:
1943               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen);
1944               break;
1945             case SO_ERROR:
1946               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
1947               break;
1948             default:
1949               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
1950                     "optname %d unsupported!", fd, vlsh, optname);
1951               break;
1952             }
1953           break;
1954         default:
1955           break;
1956         }
1957
1958       if (rv != VPPCOM_OK)
1959         {
1960           errno = -rv;
1961           rv = -1;
1962         }
1963     }
1964   else
1965     {
1966       rv = libc_getsockopt (fd, level, optname, optval, optlen);
1967     }
1968
1969   return rv;
1970 }
1971
1972 int
1973 setsockopt (int fd, int level, int optname,
1974             const void *optval, socklen_t optlen)
1975 {
1976   vls_handle_t vlsh;
1977   int rv;
1978
1979   ldp_init_check ();
1980
1981   vlsh = ldp_fd_to_vlsh (fd);
1982   if (vlsh != VLS_INVALID_HANDLE)
1983     {
1984       rv = -EOPNOTSUPP;
1985
1986       switch (level)
1987         {
1988         case SOL_TCP:
1989           switch (optname)
1990             {
1991             case TCP_NODELAY:
1992               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
1993                              (void *) optval, &optlen);
1994               break;
1995             case TCP_MAXSEG:
1996               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
1997                              (void *) optval, &optlen);
1998               break;
1999             case TCP_KEEPIDLE:
2000               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2001                              (void *) optval, &optlen);
2002               break;
2003             case TCP_KEEPINTVL:
2004               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2005                              (void *) optval, &optlen);
2006               break;
2007             case TCP_CONGESTION:
2008             case TCP_CORK:
2009               /* Ignore */
2010               rv = 0;
2011               break;
2012             default:
2013               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2014                     "optname %d unsupported!", fd, vlsh, optname);
2015               break;
2016             }
2017           break;
2018         case SOL_IPV6:
2019           switch (optname)
2020             {
2021             case IPV6_V6ONLY:
2022               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2023                              (void *) optval, &optlen);
2024               break;
2025             default:
2026               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2027                     "optname %d unsupported!", fd, vlsh, optname);
2028               break;
2029             }
2030           break;
2031         case SOL_SOCKET:
2032           switch (optname)
2033             {
2034             case SO_KEEPALIVE:
2035               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2036                              (void *) optval, &optlen);
2037               break;
2038             case SO_REUSEADDR:
2039               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2040                              (void *) optval, &optlen);
2041               break;
2042             case SO_REUSEPORT:
2043               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval,
2044                              &optlen);
2045               break;
2046             case SO_BROADCAST:
2047               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2048                              (void *) optval, &optlen);
2049               break;
2050             case SO_LINGER:
2051               rv = 0;
2052               break;
2053             default:
2054               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2055                     "optname %d unsupported!", fd, vlsh, optname);
2056               break;
2057             }
2058           break;
2059         default:
2060           break;
2061         }
2062
2063       if (rv != VPPCOM_OK)
2064         {
2065           errno = -rv;
2066           rv = -1;
2067         }
2068     }
2069   else
2070     {
2071       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2072     }
2073
2074   return rv;
2075 }
2076
2077 int
2078 listen (int fd, int n)
2079 {
2080   vls_handle_t vlsh;
2081   int rv;
2082
2083   ldp_init_check ();
2084
2085   vlsh = ldp_fd_to_vlsh (fd);
2086   if (vlsh != VLS_INVALID_HANDLE)
2087     {
2088       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2089
2090       rv = vls_listen (vlsh, n);
2091       if (rv != VPPCOM_OK)
2092         {
2093           errno = -rv;
2094           rv = -1;
2095         }
2096     }
2097   else
2098     {
2099       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2100       rv = libc_listen (fd, n);
2101     }
2102
2103   LDBG (1, "fd %d: returning %d", fd, rv);
2104   return rv;
2105 }
2106
2107 static inline int
2108 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
2109              socklen_t * __restrict addr_len, int flags)
2110 {
2111   vls_handle_t listen_vlsh, accept_vlsh;
2112   int rv;
2113
2114   ldp_init_check ();
2115
2116   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2117   if (listen_vlsh != VLS_INVALID_HANDLE)
2118     {
2119       vppcom_endpt_t ep;
2120       u8 src_addr[sizeof (struct sockaddr_in6)];
2121       memset (&ep, 0, sizeof (ep));
2122       ep.ip = src_addr;
2123
2124       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2125             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2126
2127       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2128       if (accept_vlsh < 0)
2129         {
2130           errno = -accept_vlsh;
2131           rv = -1;
2132         }
2133       else
2134         {
2135           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2136           if (rv != VPPCOM_OK)
2137             {
2138               (void) vls_close (accept_vlsh);
2139               errno = -rv;
2140               rv = -1;
2141             }
2142           else
2143             {
2144               rv = ldp_vlsh_to_fd (accept_vlsh);
2145             }
2146         }
2147     }
2148   else
2149     {
2150       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2151             " flags 0x%x", listen_fd, addr, addr_len, flags);
2152
2153       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2154     }
2155
2156   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2157
2158   return rv;
2159 }
2160
2161 int
2162 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2163          int flags)
2164 {
2165   return ldp_accept4 (fd, addr, addr_len, flags);
2166 }
2167
2168 int
2169 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2170 {
2171   return ldp_accept4 (fd, addr, addr_len, 0);
2172 }
2173
2174 int
2175 shutdown (int fd, int how)
2176 {
2177   vls_handle_t vlsh;
2178   int rv = 0;
2179
2180   ldp_init_check ();
2181
2182   vlsh = ldp_fd_to_vlsh (fd);
2183   if (vlsh != VLS_INVALID_HANDLE)
2184     {
2185       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2186       rv = vls_shutdown (vlsh, how);
2187     }
2188   else
2189     {
2190       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2191       rv = libc_shutdown (fd, how);
2192     }
2193
2194   return rv;
2195 }
2196
2197 int
2198 epoll_create1 (int flags)
2199 {
2200   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2201   vls_handle_t vlsh;
2202   int rv;
2203
2204   ldp_init_check ();
2205
2206   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2207     {
2208       /* Make sure workers have been allocated */
2209       if (!ldp->workers)
2210         {
2211           ldp_alloc_workers ();
2212           ldpw = ldp_worker_get_current ();
2213         }
2214       rv = libc_epoll_create1 (flags);
2215       ldp->vcl_needs_real_epoll = 0;
2216       ldpw->vcl_mq_epfd = rv;
2217       LDBG (0, "created vcl epfd %u", rv);
2218       return rv;
2219     }
2220
2221   vlsh = vls_epoll_create ();
2222   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2223     {
2224       errno = -vlsh;
2225       rv = -1;
2226     }
2227   else
2228     {
2229       rv = ldp_vlsh_to_fd (vlsh);
2230     }
2231   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2232   return rv;
2233 }
2234
2235 int
2236 epoll_create (int size)
2237 {
2238   return epoll_create1 (0);
2239 }
2240
2241 int
2242 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2243 {
2244   vls_handle_t vep_vlsh, vlsh;
2245   int rv;
2246
2247   ldp_init_check ();
2248
2249   vep_vlsh = ldp_fd_to_vlsh (epfd);
2250   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2251     {
2252       /* The LDP epoll_create1 always creates VCL epfd's.
2253        * The app should never have a kernel base epoll fd unless it
2254        * was acquired outside of the LD_PRELOAD process context.
2255        * In any case, if we get one, punt it to libc_epoll_ctl.
2256        */
2257       LDBG (1, "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2258             " event %p", epfd, op, fd, event);
2259
2260       rv = libc_epoll_ctl (epfd, op, fd, event);
2261       goto done;
2262     }
2263
2264   vlsh = ldp_fd_to_vlsh (fd);
2265
2266   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2267         vlsh, op);
2268
2269   if (vlsh != VLS_INVALID_HANDLE)
2270     {
2271       LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2272             " event %p", epfd, vep_vlsh, op, vlsh, event);
2273
2274       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2275       if (rv != VPPCOM_OK)
2276         {
2277           errno = -rv;
2278           rv = -1;
2279         }
2280     }
2281   else
2282     {
2283       int libc_epfd;
2284       u32 size = sizeof (epfd);
2285
2286       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2287       if (!libc_epfd)
2288         {
2289           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2290                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2291
2292           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2293           if (libc_epfd < 0)
2294             {
2295               rv = libc_epfd;
2296               goto done;
2297             }
2298
2299           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2300                          &size);
2301           if (rv < 0)
2302             {
2303               errno = -rv;
2304               rv = -1;
2305               goto done;
2306             }
2307         }
2308       else if (PREDICT_FALSE (libc_epfd < 0))
2309         {
2310           errno = -epfd;
2311           rv = -1;
2312           goto done;
2313         }
2314
2315       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2316             " event %p", epfd, libc_epfd, op, fd, event);
2317
2318       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2319     }
2320
2321 done:
2322   return rv;
2323 }
2324
2325 static inline int
2326 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2327                  int timeout, const sigset_t * sigmask)
2328 {
2329   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2330   double time_to_wait = (double) 0, max_time;
2331   int libc_epfd, rv = 0;
2332   vls_handle_t ep_vlsh;
2333
2334   ldp_init_check ();
2335
2336   if (PREDICT_FALSE (!events || (timeout < -1)))
2337     {
2338       errno = EFAULT;
2339       return -1;
2340     }
2341
2342   if (epfd == ldpw->vcl_mq_epfd)
2343     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2344
2345   ep_vlsh = ldp_fd_to_vlsh (epfd);
2346   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2347     {
2348       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2349       errno = EBADFD;
2350       return -1;
2351     }
2352
2353   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2354     clib_time_init (&ldpw->clib_time);
2355   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2356   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2357
2358   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2359   if (PREDICT_FALSE (libc_epfd < 0))
2360     {
2361       errno = -libc_epfd;
2362       rv = -1;
2363       goto done;
2364     }
2365
2366   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2367         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2368         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2369   do
2370     {
2371       if (!ldpw->epoll_wait_vcl)
2372         {
2373           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2374           if (rv > 0)
2375             {
2376               ldpw->epoll_wait_vcl = 1;
2377               goto done;
2378             }
2379           else if (rv < 0)
2380             {
2381               errno = -rv;
2382               rv = -1;
2383               goto done;
2384             }
2385         }
2386       else
2387         ldpw->epoll_wait_vcl = 0;
2388
2389       if (libc_epfd > 0)
2390         {
2391           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2392           if (rv != 0)
2393             goto done;
2394         }
2395     }
2396   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2397
2398 done:
2399   return rv;
2400 }
2401
2402 static inline int
2403 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2404                          int maxevents, int timeout, const sigset_t * sigmask)
2405 {
2406   ldp_worker_ctx_t *ldpw;
2407   int libc_epfd, rv = 0, num_ev;
2408   vls_handle_t ep_vlsh;
2409
2410   ldp_init_check ();
2411
2412   if (PREDICT_FALSE (!events || (timeout < -1)))
2413     {
2414       errno = EFAULT;
2415       return -1;
2416     }
2417
2418   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2419    * one thread but it is now used on another */
2420   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2421     vls_register_vcl_worker ();
2422
2423   ldpw = ldp_worker_get_current ();
2424   if (epfd == ldpw->vcl_mq_epfd)
2425     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2426
2427   ep_vlsh = ldp_fd_to_vlsh (epfd);
2428   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2429     {
2430       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2431       errno = EBADFD;
2432       return -1;
2433     }
2434
2435   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2436   if (PREDICT_FALSE (!libc_epfd))
2437     {
2438       u32 size = sizeof (epfd);
2439
2440       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2441             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2442       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2443       if (libc_epfd < 0)
2444         {
2445           rv = libc_epfd;
2446           goto done;
2447         }
2448
2449       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2450       if (rv < 0)
2451         {
2452           errno = -rv;
2453           rv = -1;
2454           goto done;
2455         }
2456     }
2457   if (PREDICT_FALSE (libc_epfd <= 0))
2458     {
2459       errno = -libc_epfd;
2460       rv = -1;
2461       goto done;
2462     }
2463
2464   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2465     {
2466       struct epoll_event e = { 0 };
2467       e.events = EPOLLIN;
2468       e.data.fd = ldpw->vcl_mq_epfd;
2469       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2470           0)
2471         {
2472           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2473                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2474           rv = -1;
2475           goto done;
2476         }
2477       ldpw->mq_epfd_added = 1;
2478     }
2479
2480   /* Request to only drain unhandled to prevent libc_epoll_wait starved */
2481   rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2);
2482   if (rv > 0)
2483     goto done;
2484   else if (PREDICT_FALSE (rv < 0))
2485     {
2486       errno = -rv;
2487       rv = -1;
2488       goto done;
2489     }
2490
2491   rv = libc_epoll_pwait (libc_epfd, events, maxevents, timeout, sigmask);
2492   if (rv <= 0)
2493     goto done;
2494   for (int i = 0; i < rv; i++)
2495     {
2496       if (events[i].data.fd == ldpw->vcl_mq_epfd)
2497         {
2498           /* We should remove mq epoll fd from events. */
2499           rv--;
2500           if (i != rv)
2501             {
2502               events[i].events = events[rv].events;
2503               events[i].data.u64 = events[rv].data.u64;
2504             }
2505           num_ev = vls_epoll_wait (ep_vlsh, &events[rv], maxevents - rv, 0);
2506           if (PREDICT_TRUE (num_ev > 0))
2507             rv += num_ev;
2508           break;
2509         }
2510     }
2511
2512 done:
2513   return rv;
2514 }
2515
2516 int
2517 epoll_pwait (int epfd, struct epoll_event *events,
2518              int maxevents, int timeout, const sigset_t * sigmask)
2519 {
2520   if (vls_use_eventfd ())
2521     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2522                                     sigmask);
2523   else
2524     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2525 }
2526
2527 int
2528 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2529 {
2530   if (vls_use_eventfd ())
2531     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2532   else
2533     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2534 }
2535
2536 int
2537 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2538 {
2539   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2540   int rv, i, n_revents = 0;
2541   vls_handle_t vlsh;
2542   vcl_poll_t *vp;
2543   double max_time;
2544
2545   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2546
2547   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2548     clib_time_init (&ldpw->clib_time);
2549
2550   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2551   max_time += clib_time_now (&ldpw->clib_time);
2552
2553   for (i = 0; i < nfds; i++)
2554     {
2555       if (fds[i].fd < 0)
2556         continue;
2557
2558       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2559       if (vlsh != VLS_INVALID_HANDLE)
2560         {
2561           fds[i].fd = -fds[i].fd;
2562           vec_add2 (ldpw->vcl_poll, vp, 1);
2563           vp->fds_ndx = i;
2564           vp->sh = vlsh_to_sh (vlsh);
2565           vp->events = fds[i].events;
2566 #ifdef __USE_XOPEN2K
2567           if (fds[i].events & POLLRDNORM)
2568             vp->events |= POLLIN;
2569           if (fds[i].events & POLLWRNORM)
2570             vp->events |= POLLOUT;
2571 #endif
2572           vp->revents = fds[i].revents;
2573         }
2574       else
2575         {
2576           vec_add1 (ldpw->libc_poll, fds[i]);
2577           vec_add1 (ldpw->libc_poll_idxs, i);
2578         }
2579     }
2580
2581   do
2582     {
2583       if (vec_len (ldpw->vcl_poll))
2584         {
2585           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2586           if (rv < 0)
2587             {
2588               errno = -rv;
2589               rv = -1;
2590               goto done;
2591             }
2592           else
2593             n_revents += rv;
2594         }
2595
2596       if (vec_len (ldpw->libc_poll))
2597         {
2598           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2599           if (rv < 0)
2600             goto done;
2601           else
2602             n_revents += rv;
2603         }
2604
2605       if (n_revents)
2606         {
2607           rv = n_revents;
2608           goto done;
2609         }
2610     }
2611   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2612   rv = 0;
2613
2614 done:
2615   vec_foreach (vp, ldpw->vcl_poll)
2616   {
2617     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2618     fds[vp->fds_ndx].revents = vp->revents;
2619 #ifdef __USE_XOPEN2K
2620     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2621         (fds[vp->fds_ndx].events & POLLRDNORM))
2622       fds[vp->fds_ndx].revents |= POLLRDNORM;
2623     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2624         (fds[vp->fds_ndx].events & POLLWRNORM))
2625       fds[vp->fds_ndx].revents |= POLLWRNORM;
2626 #endif
2627   }
2628   vec_reset_length (ldpw->vcl_poll);
2629
2630   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2631     {
2632       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2633     }
2634   vec_reset_length (ldpw->libc_poll_idxs);
2635   vec_reset_length (ldpw->libc_poll);
2636
2637   return rv;
2638 }
2639
2640 #ifdef USE_GNU
2641 int
2642 ppoll (struct pollfd *fds, nfds_t nfds,
2643        const struct timespec *timeout, const sigset_t * sigmask)
2644 {
2645   ldp_init_check ();
2646
2647   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2648   errno = ENOSYS;
2649
2650
2651   return -1;
2652 }
2653 #endif
2654
2655 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2656
2657 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2658
2659 /*
2660  * This function is called when the library is loaded
2661  */
2662 void
2663 ldp_constructor (void)
2664 {
2665   swrap_constructor ();
2666   if (ldp_init () != 0)
2667     {
2668       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2669                getpid ());
2670       _exit (1);
2671     }
2672   else if (LDP_DEBUG > 0)
2673     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2674 }
2675
2676 /*
2677  * This function is called when the library is unloaded
2678  */
2679 void
2680 ldp_destructor (void)
2681 {
2682   /*
2683      swrap_destructor ();
2684      if (ldp->init)
2685      ldp->init = 0;
2686    */
2687
2688   /* Don't use clib_warning() here because that calls writev()
2689    * which will call ldp_init().
2690    */
2691   if (LDP_DEBUG > 0)
2692     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2693              __func__, __LINE__, getpid ());
2694 }
2695
2696
2697 /*
2698  * fd.io coding-style-patch-verification: ON
2699  *
2700  * Local Variables:
2701  * eval: (c-set-style "gnu")
2702  * End:
2703  */