2256a2b9061c4b08db243f9f341c63794e230f44
[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   memset (cmsg, 0, sizeof (*cmsg));
1752
1753   if (!vls_attr (vlsh, VPPCOM_ATTR_GET_IP_PKTINFO, (void *) &optval, &optlen))
1754     return 0;
1755
1756   if (optval)
1757     {
1758       vppcom_endpt_t ep;
1759       u8 addr_buf[sizeof (struct in_addr)];
1760       u32 size = sizeof (ep);
1761
1762       ep.ip = addr_buf;
1763
1764       if (!vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size))
1765         {
1766           struct in_pktinfo pi = {};
1767
1768           clib_memcpy (&pi.ipi_addr, ep.ip, sizeof (struct in_addr));
1769           cmsg->cmsg_level = SOL_IP;
1770           cmsg->cmsg_type = IP_PKTINFO;
1771           cmsg->cmsg_len = CMSG_LEN (sizeof (pi));
1772           clib_memcpy (CMSG_DATA (cmsg), &pi, sizeof (pi));
1773         }
1774     }
1775
1776   return 0;
1777 }
1778
1779 ssize_t
1780 sendmsg (int fd, const struct msghdr * msg, int flags)
1781 {
1782   vls_handle_t vlsh;
1783   ssize_t size;
1784
1785   ldp_init_check ();
1786
1787   vlsh = ldp_fd_to_vlsh (fd);
1788   if (vlsh != VLS_INVALID_HANDLE)
1789     {
1790       vppcom_endpt_tlv_t *app_tlvs = 0;
1791       struct iovec *iov = msg->msg_iov;
1792       ssize_t total = 0;
1793       int i, rv = 0;
1794
1795       ldp_parse_cmsg (vlsh, msg, &app_tlvs);
1796
1797       for (i = 0; i < msg->msg_iovlen; ++i)
1798         {
1799           rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, app_tlvs,
1800                               flags, msg->msg_name, msg->msg_namelen);
1801           if (rv < 0)
1802             break;
1803           else
1804             {
1805               total += rv;
1806               if (rv < iov[i].iov_len)
1807                 break;
1808             }
1809         }
1810
1811       vec_free (app_tlvs);
1812
1813       if (rv < 0 && total == 0)
1814         {
1815           errno = -rv;
1816           size = -1;
1817         }
1818       else
1819         size = total;
1820     }
1821   else
1822     {
1823       size = libc_sendmsg (fd, msg, flags);
1824     }
1825
1826   return size;
1827 }
1828
1829 #ifdef _GNU_SOURCE
1830 int
1831 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1832 {
1833   ssize_t size;
1834   const char *func_str;
1835   u32 sh = ldp_fd_to_vlsh (fd);
1836
1837   ldp_init_check ();
1838
1839   if (sh != VLS_INVALID_HANDLE)
1840     {
1841       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1842       errno = ENOSYS;
1843       size = -1;
1844     }
1845   else
1846     {
1847       func_str = "libc_sendmmsg";
1848
1849       if (LDP_DEBUG > 2)
1850         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1851                       "vmessages %p, vlen %u, flags 0x%x",
1852                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1853
1854       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1855     }
1856
1857   if (LDP_DEBUG > 2)
1858     {
1859       if (size < 0)
1860         {
1861           int errno_val = errno;
1862           perror (func_str);
1863           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1864                         "rv %d, errno = %d", getpid (), fd, fd,
1865                         func_str, size, errno_val);
1866           errno = errno_val;
1867         }
1868       else
1869         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1870                       getpid (), fd, fd, size, size);
1871     }
1872   return size;
1873 }
1874 #endif
1875
1876 ssize_t
1877 recvmsg (int fd, struct msghdr * msg, int flags)
1878 {
1879   vls_handle_t vlsh;
1880   ssize_t size;
1881
1882   ldp_init_check ();
1883
1884   vlsh = ldp_fd_to_vlsh (fd);
1885   if (vlsh != VLS_INVALID_HANDLE)
1886     {
1887       struct iovec *iov = msg->msg_iov;
1888       ssize_t max_deq, total = 0;
1889       int i, rv;
1890
1891       max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
1892       if (!max_deq)
1893         return 0;
1894
1895       for (i = 0; i < msg->msg_iovlen; i++)
1896         {
1897           rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1898                                  (i == 0 ? msg->msg_name : NULL),
1899                                  (i == 0 ? &msg->msg_namelen : NULL));
1900           if (rv <= 0)
1901             break;
1902           else
1903             {
1904               total += rv;
1905               if (rv < iov[i].iov_len)
1906                 break;
1907             }
1908           if (total >= max_deq)
1909             break;
1910         }
1911
1912       if (rv < 0 && total == 0)
1913         {
1914           errno = -rv;
1915           size = -1;
1916         }
1917       else
1918         {
1919           if (msg->msg_controllen)
1920             ldp_make_cmsg (vlsh, msg);
1921           size = total;
1922         }
1923     }
1924   else
1925     {
1926       size = libc_recvmsg (fd, msg, flags);
1927     }
1928
1929   return size;
1930 }
1931
1932 #ifdef _GNU_SOURCE
1933 int
1934 recvmmsg (int fd, struct mmsghdr *vmessages,
1935           unsigned int vlen, int flags, struct timespec *tmo)
1936 {
1937   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1938   u32 sh;
1939
1940   ldp_init_check ();
1941
1942   sh = ldp_fd_to_vlsh (fd);
1943
1944   if (sh != VLS_INVALID_HANDLE)
1945     {
1946       struct mmsghdr *mh;
1947       ssize_t rv = 0;
1948       u32 nvecs = 0;
1949       f64 time_out;
1950
1951       if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
1952         clib_time_init (&ldpw->clib_time);
1953       if (tmo)
1954         {
1955           time_out = (f64) tmo->tv_sec + (f64) tmo->tv_nsec / (f64) 1e9;
1956           time_out += clib_time_now (&ldpw->clib_time);
1957         }
1958       else
1959         {
1960           time_out = (f64) ~0;
1961         }
1962
1963       while (nvecs < vlen)
1964         {
1965           mh = &vmessages[nvecs];
1966           rv = recvmsg (fd, &mh->msg_hdr, flags);
1967           if (rv > 0)
1968             {
1969               mh->msg_len = rv;
1970               nvecs += 1;
1971               continue;
1972             }
1973
1974           if (!time_out || clib_time_now (&ldpw->clib_time) >= time_out)
1975             break;
1976
1977           usleep (1);
1978         }
1979
1980       return nvecs > 0 ? nvecs : rv;
1981     }
1982   else
1983     {
1984       return libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1985     }
1986 }
1987 #endif
1988
1989 int
1990 getsockopt (int fd, int level, int optname,
1991             void *__restrict optval, socklen_t * __restrict optlen)
1992 {
1993   vls_handle_t vlsh;
1994   int rv;
1995
1996   ldp_init_check ();
1997
1998   vlsh = ldp_fd_to_vlsh (fd);
1999   if (vlsh != VLS_INVALID_HANDLE)
2000     {
2001       rv = -EOPNOTSUPP;
2002
2003       switch (level)
2004         {
2005         case SOL_TCP:
2006           switch (optname)
2007             {
2008             case TCP_NODELAY:
2009               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
2010                              optval, optlen);
2011               break;
2012             case TCP_MAXSEG:
2013               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
2014                              optval, optlen);
2015               break;
2016             case TCP_KEEPIDLE:
2017               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
2018                              optval, optlen);
2019               break;
2020             case TCP_KEEPINTVL:
2021               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
2022                              optval, optlen);
2023               break;
2024             case TCP_INFO:
2025               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
2026                 {
2027                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
2028                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
2029                   memset (optval, 0, *optlen);
2030                   rv = VPPCOM_OK;
2031                 }
2032               else
2033                 rv = -EFAULT;
2034               break;
2035             case TCP_CONGESTION:
2036               *optlen = strlen ("cubic");
2037               strncpy (optval, "cubic", *optlen + 1);
2038               rv = 0;
2039               break;
2040             default:
2041               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
2042                     "optname %d unsupported!", fd, vlsh, optname);
2043               break;
2044             }
2045           break;
2046         case SOL_IPV6:
2047           switch (optname)
2048             {
2049             case IPV6_V6ONLY:
2050               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
2051               break;
2052             default:
2053               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
2054                     "optname %d unsupported!", fd, vlsh, optname);
2055               break;
2056             }
2057           break;
2058         case SOL_SOCKET:
2059           switch (optname)
2060             {
2061             case SO_ACCEPTCONN:
2062               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
2063               break;
2064             case SO_KEEPALIVE:
2065               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
2066               break;
2067             case SO_PROTOCOL:
2068               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
2069               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
2070               break;
2071             case SO_SNDBUF:
2072               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
2073                              optval, optlen);
2074               break;
2075             case SO_RCVBUF:
2076               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
2077                              optval, optlen);
2078               break;
2079             case SO_REUSEADDR:
2080               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
2081               break;
2082             case SO_REUSEPORT:
2083               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen);
2084               break;
2085             case SO_BROADCAST:
2086               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
2087               break;
2088             case SO_DOMAIN:
2089               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen);
2090               break;
2091             case SO_ERROR:
2092               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
2093               break;
2094             case SO_BINDTODEVICE:
2095               rv = 0;
2096               break;
2097             default:
2098               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
2099                     "optname %d unsupported!", fd, vlsh, optname);
2100               break;
2101             }
2102           break;
2103         default:
2104           break;
2105         }
2106
2107       if (rv != VPPCOM_OK)
2108         {
2109           errno = -rv;
2110           rv = -1;
2111         }
2112     }
2113   else
2114     {
2115       rv = libc_getsockopt (fd, level, optname, optval, optlen);
2116     }
2117
2118   return rv;
2119 }
2120
2121 int
2122 setsockopt (int fd, int level, int optname,
2123             const void *optval, socklen_t optlen)
2124 {
2125   vls_handle_t vlsh;
2126   int rv;
2127
2128   ldp_init_check ();
2129
2130   vlsh = ldp_fd_to_vlsh (fd);
2131   if (vlsh != VLS_INVALID_HANDLE)
2132     {
2133       rv = -EOPNOTSUPP;
2134
2135       switch (level)
2136         {
2137         case SOL_TCP:
2138           switch (optname)
2139             {
2140             case TCP_NODELAY:
2141               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
2142                              (void *) optval, &optlen);
2143               break;
2144             case TCP_MAXSEG:
2145               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
2146                              (void *) optval, &optlen);
2147               break;
2148             case TCP_KEEPIDLE:
2149               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2150                              (void *) optval, &optlen);
2151               break;
2152             case TCP_KEEPINTVL:
2153               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2154                              (void *) optval, &optlen);
2155               break;
2156             case TCP_CONGESTION:
2157             case TCP_CORK:
2158               /* Ignore */
2159               rv = 0;
2160               break;
2161             default:
2162               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2163                     "optname %d unsupported!", fd, vlsh, optname);
2164               break;
2165             }
2166           break;
2167         case SOL_IPV6:
2168           switch (optname)
2169             {
2170             case IPV6_V6ONLY:
2171               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2172                              (void *) optval, &optlen);
2173               break;
2174             default:
2175               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2176                     "optname %d unsupported!", fd, vlsh, optname);
2177               break;
2178             }
2179           break;
2180         case SOL_SOCKET:
2181           switch (optname)
2182             {
2183             case SO_KEEPALIVE:
2184               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2185                              (void *) optval, &optlen);
2186               break;
2187             case SO_REUSEADDR:
2188               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2189                              (void *) optval, &optlen);
2190               break;
2191             case SO_REUSEPORT:
2192               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval,
2193                              &optlen);
2194               break;
2195             case SO_BROADCAST:
2196               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2197                              (void *) optval, &optlen);
2198               break;
2199             case SO_LINGER:
2200               rv = 0;
2201               break;
2202             default:
2203               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2204                     "optname %d unsupported!", fd, vlsh, optname);
2205               break;
2206             }
2207           break;
2208         case SOL_IP:
2209           switch (optname)
2210             {
2211             case IP_PKTINFO:
2212               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_IP_PKTINFO, (void *) optval,
2213                              &optlen);
2214               break;
2215             default:
2216               LDBG (0,
2217                     "ERROR: fd %d: setsockopt SOL_IP: vlsh %u optname %d"
2218                     "unsupported!",
2219                     fd, vlsh, optname);
2220               break;
2221             }
2222           break;
2223         default:
2224           break;
2225         }
2226
2227       if (rv != VPPCOM_OK)
2228         {
2229           errno = -rv;
2230           rv = -1;
2231         }
2232     }
2233   else
2234     {
2235       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2236     }
2237
2238   return rv;
2239 }
2240
2241 int
2242 listen (int fd, int n)
2243 {
2244   vls_handle_t vlsh;
2245   int rv;
2246
2247   ldp_init_check ();
2248
2249   vlsh = ldp_fd_to_vlsh (fd);
2250   if (vlsh != VLS_INVALID_HANDLE)
2251     {
2252       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2253
2254       rv = vls_listen (vlsh, n);
2255       if (rv != VPPCOM_OK)
2256         {
2257           errno = -rv;
2258           rv = -1;
2259         }
2260     }
2261   else
2262     {
2263       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2264       rv = libc_listen (fd, n);
2265     }
2266
2267   LDBG (1, "fd %d: returning %d", fd, rv);
2268   return rv;
2269 }
2270
2271 static inline int
2272 ldp_accept4 (int listen_fd, __SOCKADDR_ARG _addr,
2273              socklen_t *__restrict addr_len, int flags)
2274 {
2275   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
2276   vls_handle_t listen_vlsh, accept_vlsh;
2277   int rv;
2278
2279   ldp_init_check ();
2280
2281   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2282   if (listen_vlsh != VLS_INVALID_HANDLE)
2283     {
2284       vppcom_endpt_t ep;
2285       u8 src_addr[sizeof (struct sockaddr_in6)];
2286       memset (&ep, 0, sizeof (ep));
2287       ep.ip = src_addr;
2288
2289       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2290             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2291
2292       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2293       if (accept_vlsh < 0)
2294         {
2295           errno = -accept_vlsh;
2296           rv = -1;
2297         }
2298       else
2299         {
2300           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2301           if (rv != VPPCOM_OK)
2302             {
2303               (void) vls_close (accept_vlsh);
2304               errno = -rv;
2305               rv = -1;
2306             }
2307           else
2308             {
2309               rv = ldp_vlsh_to_fd (accept_vlsh);
2310             }
2311         }
2312     }
2313   else
2314     {
2315       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2316             " flags 0x%x", listen_fd, addr, addr_len, flags);
2317
2318       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2319     }
2320
2321   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2322
2323   return rv;
2324 }
2325
2326 int
2327 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2328          int flags)
2329 {
2330   return ldp_accept4 (fd, addr, addr_len, flags);
2331 }
2332
2333 int
2334 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2335 {
2336   return ldp_accept4 (fd, addr, addr_len, 0);
2337 }
2338
2339 int
2340 shutdown (int fd, int how)
2341 {
2342   vls_handle_t vlsh;
2343   int rv = 0;
2344
2345   ldp_init_check ();
2346
2347   vlsh = ldp_fd_to_vlsh (fd);
2348   if (vlsh != VLS_INVALID_HANDLE)
2349     {
2350       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2351       rv = vls_shutdown (vlsh, how);
2352     }
2353   else
2354     {
2355       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2356       rv = libc_shutdown (fd, how);
2357     }
2358
2359   return rv;
2360 }
2361
2362 int
2363 epoll_create1 (int flags)
2364 {
2365   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2366   vls_handle_t vlsh;
2367   int rv;
2368
2369   ldp_init_check ();
2370
2371   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2372     {
2373       /* Make sure workers have been allocated */
2374       if (!ldp->workers)
2375         {
2376           ldp_alloc_workers ();
2377           ldpw = ldp_worker_get_current ();
2378         }
2379       rv = libc_epoll_create1 (flags);
2380       ldp->vcl_needs_real_epoll = 0;
2381       ldpw->vcl_mq_epfd = rv;
2382       LDBG (0, "created vcl epfd %u", rv);
2383       return rv;
2384     }
2385
2386   vlsh = vls_epoll_create ();
2387   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2388     {
2389       errno = -vlsh;
2390       rv = -1;
2391     }
2392   else
2393     {
2394       rv = ldp_vlsh_to_fd (vlsh);
2395     }
2396   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2397   return rv;
2398 }
2399
2400 int
2401 epoll_create (int size)
2402 {
2403   return epoll_create1 (0);
2404 }
2405
2406 int
2407 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2408 {
2409   vls_handle_t vep_vlsh, vlsh;
2410   int rv;
2411
2412   ldp_init_check ();
2413
2414   vep_vlsh = ldp_fd_to_vlsh (epfd);
2415   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2416     {
2417       /* The LDP epoll_create1 always creates VCL epfd's.
2418        * The app should never have a kernel base epoll fd unless it
2419        * was acquired outside of the LD_PRELOAD process context.
2420        * In any case, if we get one, punt it to libc_epoll_ctl.
2421        */
2422       LDBG (1,
2423             "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2424             " events 0x%x",
2425             epfd, op, fd, event ? event->events : 0);
2426
2427       rv = libc_epoll_ctl (epfd, op, fd, event);
2428       goto done;
2429     }
2430
2431   vlsh = ldp_fd_to_vlsh (fd);
2432
2433   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2434         vlsh, op);
2435
2436   if (vlsh != VLS_INVALID_HANDLE)
2437     {
2438       LDBG (1,
2439             "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2440             " events 0x%x",
2441             epfd, vep_vlsh, op, vlsh, event ? event->events : 0);
2442
2443       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2444       if (rv != VPPCOM_OK)
2445         {
2446           errno = -rv;
2447           rv = -1;
2448         }
2449     }
2450   else
2451     {
2452       int libc_epfd;
2453       u32 size = sizeof (epfd);
2454
2455       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2456       if (!libc_epfd)
2457         {
2458           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2459                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2460
2461           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2462           if (libc_epfd < 0)
2463             {
2464               rv = libc_epfd;
2465               goto done;
2466             }
2467
2468           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2469                          &size);
2470           if (rv < 0)
2471             {
2472               errno = -rv;
2473               rv = -1;
2474               goto done;
2475             }
2476         }
2477       else if (PREDICT_FALSE (libc_epfd < 0))
2478         {
2479           errno = -epfd;
2480           rv = -1;
2481           goto done;
2482         }
2483
2484       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2485             " event %p", epfd, libc_epfd, op, fd, event);
2486
2487       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2488     }
2489
2490 done:
2491   return rv;
2492 }
2493
2494 static inline int
2495 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2496                  int timeout, const sigset_t * sigmask)
2497 {
2498   ldp_worker_ctx_t *ldpw;
2499   double time_to_wait = (double) 0, max_time;
2500   int libc_epfd, rv = 0;
2501   vls_handle_t ep_vlsh;
2502
2503   ldp_init_check ();
2504
2505   if (PREDICT_FALSE (!events || (timeout < -1)))
2506     {
2507       errno = EFAULT;
2508       return -1;
2509     }
2510
2511   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2512     vls_register_vcl_worker ();
2513
2514   ldpw = ldp_worker_get_current ();
2515   if (epfd == ldpw->vcl_mq_epfd)
2516     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2517
2518   ep_vlsh = ldp_fd_to_vlsh (epfd);
2519   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2520     {
2521       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2522       errno = EBADFD;
2523       return -1;
2524     }
2525
2526   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2527     clib_time_init (&ldpw->clib_time);
2528   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2529   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2530
2531   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2532   if (PREDICT_FALSE (libc_epfd < 0))
2533     {
2534       errno = -libc_epfd;
2535       rv = -1;
2536       goto done;
2537     }
2538
2539   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2540         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2541         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2542   do
2543     {
2544       if (!ldpw->epoll_wait_vcl)
2545         {
2546           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2547           if (rv > 0)
2548             {
2549               ldpw->epoll_wait_vcl = 1;
2550               goto done;
2551             }
2552           else if (rv < 0)
2553             {
2554               errno = -rv;
2555               rv = -1;
2556               goto done;
2557             }
2558         }
2559       else
2560         ldpw->epoll_wait_vcl = 0;
2561
2562       if (libc_epfd > 0)
2563         {
2564           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2565           if (rv != 0)
2566             goto done;
2567         }
2568     }
2569   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2570
2571 done:
2572   return rv;
2573 }
2574
2575 static inline int
2576 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2577                          int maxevents, int timeout, const sigset_t * sigmask)
2578 {
2579   int libc_epfd, rv = 0, num_ev, libc_num_ev, vcl_wups = 0;
2580   struct epoll_event *libc_evts;
2581   ldp_worker_ctx_t *ldpw;
2582   vls_handle_t ep_vlsh;
2583
2584   ldp_init_check ();
2585
2586   if (PREDICT_FALSE (!events || (timeout < -1)))
2587     {
2588       errno = EFAULT;
2589       return -1;
2590     }
2591
2592   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2593    * one thread but it is now used on another */
2594   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2595     vls_register_vcl_worker ();
2596
2597   ldpw = ldp_worker_get_current ();
2598   if (epfd == ldpw->vcl_mq_epfd)
2599     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2600
2601   ep_vlsh = ldp_fd_to_vlsh (epfd);
2602   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2603     {
2604       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2605       errno = EBADFD;
2606       return -1;
2607     }
2608
2609   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2610   if (PREDICT_FALSE (!libc_epfd))
2611     {
2612       u32 size = sizeof (epfd);
2613
2614       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2615             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2616       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2617       if (libc_epfd < 0)
2618         {
2619           rv = libc_epfd;
2620           goto done;
2621         }
2622
2623       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2624       if (rv < 0)
2625         {
2626           errno = -rv;
2627           rv = -1;
2628           goto done;
2629         }
2630     }
2631   if (PREDICT_FALSE (libc_epfd <= 0))
2632     {
2633       errno = -libc_epfd;
2634       rv = -1;
2635       goto done;
2636     }
2637
2638   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2639     {
2640       struct epoll_event e = { 0 };
2641       e.events = EPOLLIN;
2642       e.data.fd = ldpw->vcl_mq_epfd;
2643       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2644           0)
2645         {
2646           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2647                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2648           rv = -1;
2649           goto done;
2650         }
2651       ldpw->mq_epfd_added = 1;
2652     }
2653
2654   /* Request to only drain unhandled to prevent libc_epoll_wait starved */
2655   rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2);
2656   if (rv > 0)
2657     {
2658       timeout = 0;
2659       if (rv >= maxevents)
2660         goto done;
2661     }
2662   else if (PREDICT_FALSE (rv < 0))
2663     {
2664       errno = -rv;
2665       rv = -1;
2666       goto done;
2667     }
2668
2669 epoll_again:
2670
2671   libc_evts = &events[rv];
2672   libc_num_ev =
2673     libc_epoll_pwait (libc_epfd, libc_evts, maxevents - rv, timeout, sigmask);
2674   if (libc_num_ev <= 0)
2675     {
2676       rv = rv >= 0 ? rv : -1;
2677       goto done;
2678     }
2679
2680   for (int i = 0; i < libc_num_ev; i++)
2681     {
2682       if (libc_evts[i].data.fd == ldpw->vcl_mq_epfd)
2683         {
2684           /* We should remove mq epoll fd from events. */
2685           libc_num_ev--;
2686           if (i != libc_num_ev)
2687             {
2688               libc_evts[i].events = libc_evts[libc_num_ev].events;
2689               libc_evts[i].data.u64 = libc_evts[libc_num_ev].data.u64;
2690             }
2691           num_ev = vls_epoll_wait (ep_vlsh, &libc_evts[libc_num_ev],
2692                                    maxevents - libc_num_ev, 0);
2693           if (PREDICT_TRUE (num_ev > 0))
2694             rv += num_ev;
2695           /* Woken up by vcl but no events generated. Accept it once */
2696           if (rv == 0 && libc_num_ev == 0 && timeout && vcl_wups++ < 1)
2697             goto epoll_again;
2698           break;
2699         }
2700     }
2701
2702   rv += libc_num_ev;
2703
2704 done:
2705   return rv;
2706 }
2707
2708 int
2709 epoll_pwait (int epfd, struct epoll_event *events,
2710              int maxevents, int timeout, const sigset_t * sigmask)
2711 {
2712   if (vls_use_eventfd ())
2713     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2714                                     sigmask);
2715   else
2716     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2717 }
2718
2719 int
2720 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2721 {
2722   if (vls_use_eventfd ())
2723     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2724   else
2725     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2726 }
2727
2728 int
2729 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2730 {
2731   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2732   int rv, i, n_revents = 0;
2733   vls_handle_t vlsh;
2734   vcl_poll_t *vp;
2735   double max_time;
2736
2737   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2738
2739   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2740     clib_time_init (&ldpw->clib_time);
2741
2742   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2743   max_time += clib_time_now (&ldpw->clib_time);
2744
2745   for (i = 0; i < nfds; i++)
2746     {
2747       if (fds[i].fd < 0)
2748         continue;
2749
2750       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2751       if (vlsh != VLS_INVALID_HANDLE)
2752         {
2753           fds[i].fd = -fds[i].fd;
2754           vec_add2 (ldpw->vcl_poll, vp, 1);
2755           vp->fds_ndx = i;
2756           vp->sh = vlsh_to_sh (vlsh);
2757           vp->events = fds[i].events;
2758 #ifdef __USE_XOPEN2K
2759           if (fds[i].events & POLLRDNORM)
2760             vp->events |= POLLIN;
2761           if (fds[i].events & POLLWRNORM)
2762             vp->events |= POLLOUT;
2763 #endif
2764           vp->revents = fds[i].revents;
2765         }
2766       else
2767         {
2768           vec_add1 (ldpw->libc_poll, fds[i]);
2769           vec_add1 (ldpw->libc_poll_idxs, i);
2770         }
2771     }
2772
2773   do
2774     {
2775       if (vec_len (ldpw->vcl_poll))
2776         {
2777           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2778           if (rv < 0)
2779             {
2780               errno = -rv;
2781               rv = -1;
2782               goto done;
2783             }
2784           else
2785             n_revents += rv;
2786         }
2787
2788       if (vec_len (ldpw->libc_poll))
2789         {
2790           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2791           if (rv < 0)
2792             goto done;
2793           else
2794             n_revents += rv;
2795         }
2796
2797       if (n_revents)
2798         {
2799           rv = n_revents;
2800           goto done;
2801         }
2802     }
2803   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2804   rv = 0;
2805
2806 done:
2807   vec_foreach (vp, ldpw->vcl_poll)
2808   {
2809     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2810     fds[vp->fds_ndx].revents = vp->revents;
2811 #ifdef __USE_XOPEN2K
2812     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2813         (fds[vp->fds_ndx].events & POLLRDNORM))
2814       fds[vp->fds_ndx].revents |= POLLRDNORM;
2815     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2816         (fds[vp->fds_ndx].events & POLLWRNORM))
2817       fds[vp->fds_ndx].revents |= POLLWRNORM;
2818 #endif
2819   }
2820   vec_reset_length (ldpw->vcl_poll);
2821
2822   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2823     {
2824       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2825     }
2826   vec_reset_length (ldpw->libc_poll_idxs);
2827   vec_reset_length (ldpw->libc_poll);
2828
2829   return rv;
2830 }
2831
2832 #ifdef _GNU_SOURCE
2833 int
2834 ppoll (struct pollfd *fds, nfds_t nfds,
2835        const struct timespec *timeout, const sigset_t * sigmask)
2836 {
2837   ldp_init_check ();
2838
2839   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2840   errno = ENOSYS;
2841
2842
2843   return -1;
2844 }
2845 #endif
2846
2847 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2848
2849 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2850
2851 /*
2852  * This function is called when the library is loaded
2853  */
2854 void
2855 ldp_constructor (void)
2856 {
2857   swrap_constructor ();
2858   if (ldp_init () != 0)
2859     {
2860       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2861                getpid ());
2862       _exit (1);
2863     }
2864   else if (LDP_DEBUG > 0)
2865     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2866 }
2867
2868 /*
2869  * This function is called when the library is unloaded
2870  */
2871 void
2872 ldp_destructor (void)
2873 {
2874   /*
2875      swrap_destructor ();
2876      if (ldp->init)
2877      ldp->init = 0;
2878    */
2879
2880   /* Don't use clib_warning() here because that calls writev()
2881    * which will call ldp_init().
2882    */
2883   if (LDP_DEBUG > 0)
2884     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2885              __func__, __LINE__, getpid ());
2886 }
2887
2888
2889 /*
2890  * fd.io coding-style-patch-verification: ON
2891  *
2892  * Local Variables:
2893  * eval: (c-set-style "gnu")
2894  * End:
2895  */