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