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