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