566b5a858a33cd6fe6a2e92987365cf3be7f77a4
[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 #ifndef SO_ORIGINAL_DST
71 /* from <linux/netfilter_ipv4.h> */
72 #define SO_ORIGINAL_DST 80
73 #endif
74 typedef struct ldp_worker_ctx_
75 {
76   u8 *io_buffer;
77   clib_time_t clib_time;
78
79   /*
80    * Select state
81    */
82   clib_bitmap_t *rd_bitmap;
83   clib_bitmap_t *wr_bitmap;
84   clib_bitmap_t *ex_bitmap;
85   clib_bitmap_t *si_rd_bitmap;
86   clib_bitmap_t *si_wr_bitmap;
87   clib_bitmap_t *si_ex_bitmap;
88   clib_bitmap_t *libc_rd_bitmap;
89   clib_bitmap_t *libc_wr_bitmap;
90   clib_bitmap_t *libc_ex_bitmap;
91
92   /*
93    * Poll state
94    */
95   vcl_poll_t *vcl_poll;
96   struct pollfd *libc_poll;
97   u16 *libc_poll_idxs;
98
99   /*
100    * Epoll state
101    */
102   u8 epoll_wait_vcl;
103   u8 mq_epfd_added;
104   int vcl_mq_epfd;
105
106 } ldp_worker_ctx_t;
107
108 /* clib_bitmap_t, fd_mask and vcl_si_set are used interchangeably. Make sure
109  * they are the same size */
110 STATIC_ASSERT (sizeof (clib_bitmap_t) == sizeof (fd_mask),
111                "ldp bitmap size mismatch");
112 STATIC_ASSERT (sizeof (vcl_si_set) == sizeof (fd_mask),
113                "ldp bitmap size mismatch");
114
115 typedef struct
116 {
117   ldp_worker_ctx_t *workers;
118   int init;
119   char app_name[LDP_APP_NAME_MAX];
120   u32 vlsh_bit_val;
121   u32 vlsh_bit_mask;
122   u32 debug;
123
124   /** vcl needs next epoll_create to go to libc_epoll */
125   u8 vcl_needs_real_epoll;
126
127   /**
128    * crypto state used only for testing
129    */
130   u8 transparent_tls;
131   u32 ckpair_index;
132 } ldp_main_t;
133
134 #define LDP_DEBUG ldp->debug
135
136 #define LDBG(_lvl, _fmt, _args...)                                      \
137   if (ldp->debug > _lvl)                                                \
138     {                                                                   \
139       int errno_saved = errno;                                          \
140       fprintf (stderr, "ldp<%d>: " _fmt "\n", getpid(), ##_args);       \
141       errno = errno_saved;                                              \
142     }
143
144 static ldp_main_t ldp_main = {
145   .vlsh_bit_val = (1 << LDP_SID_BIT_MIN),
146   .vlsh_bit_mask = (1 << LDP_SID_BIT_MIN) - 1,
147   .debug = LDP_DEBUG_INIT,
148   .transparent_tls = 0,
149   .ckpair_index = ~0,
150 };
151
152 static ldp_main_t *ldp = &ldp_main;
153
154 static inline ldp_worker_ctx_t *
155 ldp_worker_get_current (void)
156 {
157   return (ldp->workers + vppcom_worker_index ());
158 }
159
160 /*
161  * RETURN:  0 on success or -1 on error.
162  * */
163 static inline void
164 ldp_set_app_name (char *app_name)
165 {
166   snprintf (ldp->app_name, LDP_APP_NAME_MAX, "%s-ldp-%d", app_name, getpid ());
167 }
168
169 static inline char *
170 ldp_get_app_name ()
171 {
172   if (ldp->app_name[0] == '\0')
173     ldp_set_app_name (program_invocation_short_name);
174
175   return ldp->app_name;
176 }
177
178 static inline int
179 ldp_vlsh_to_fd (vls_handle_t vlsh)
180 {
181   return (vlsh + ldp->vlsh_bit_val);
182 }
183
184 static inline vls_handle_t
185 ldp_fd_to_vlsh (int fd)
186 {
187   if (fd < ldp->vlsh_bit_val)
188     return VLS_INVALID_HANDLE;
189
190   return (fd - ldp->vlsh_bit_val);
191 }
192
193 static void
194 ldp_alloc_workers (void)
195 {
196   if (ldp->workers)
197     return;
198   ldp->workers = vec_new (ldp_worker_ctx_t, LDP_MAX_NWORKERS);
199 }
200
201 static void
202 ldp_init_cfg (void)
203 {
204   char *env_var_str = getenv (LDP_ENV_DEBUG);
205   if (env_var_str)
206     {
207       u32 tmp;
208       if (sscanf (env_var_str, "%u", &tmp) != 1)
209         clib_warning ("LDP<%d>: WARNING: Invalid LDP debug level specified in"
210                       " the env var " LDP_ENV_DEBUG " (%s)!", getpid (),
211                       env_var_str);
212       else
213         {
214           ldp->debug = tmp;
215           LDBG (0, "configured LDP debug level (%u) from env var "
216                 LDP_ENV_DEBUG "!", ldp->debug);
217         }
218     }
219
220   env_var_str = getenv (LDP_ENV_APP_NAME);
221   if (env_var_str)
222     {
223       ldp_set_app_name (env_var_str);
224       LDBG (0, "configured LDP app name (%s) from the env var "
225             LDP_ENV_APP_NAME "!", ldp->app_name);
226     }
227
228   env_var_str = getenv (LDP_ENV_SID_BIT);
229   if (env_var_str)
230     {
231       u32 sb;
232       if (sscanf (env_var_str, "%u", &sb) != 1)
233         {
234           LDBG (0, "WARNING: Invalid LDP sid bit specified in the env var "
235                 LDP_ENV_SID_BIT " (%s)! sid bit value %d (0x%x)", env_var_str,
236                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
237         }
238       else if (sb < LDP_SID_BIT_MIN)
239         {
240           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MIN);
241           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
242
243           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
244                 LDP_ENV_SID_BIT " (%s) is too small. Using LDP_SID_BIT_MIN"
245                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
246                 LDP_SID_BIT_MIN, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
247         }
248       else if (sb > LDP_SID_BIT_MAX)
249         {
250           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MAX);
251           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
252
253           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
254                 LDP_ENV_SID_BIT " (%s) is too big. Using LDP_SID_BIT_MAX"
255                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
256                 LDP_SID_BIT_MAX, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
257         }
258       else
259         {
260           ldp->vlsh_bit_val = (1 << sb);
261           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
262
263           LDBG (0, "configured LDP sid bit (%u) from "
264                 LDP_ENV_SID_BIT "!  sid bit value %d (0x%x)", sb,
265                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
266         }
267
268       /* Make sure there are enough bits in the fd set for vcl sessions */
269       if (ldp->vlsh_bit_val > FD_SETSIZE / 2)
270         {
271           /* Only valid for select/pselect, so just WARNING and not exit */
272           LDBG (0,
273                 "WARNING: LDP vlsh bit value %d > FD_SETSIZE/2 %d, "
274                 "select/pselect not supported now!",
275                 ldp->vlsh_bit_val, FD_SETSIZE / 2);
276         }
277     }
278   env_var_str = getenv (LDP_ENV_TLS_TRANS);
279   if (env_var_str)
280     {
281       ldp->transparent_tls = 1;
282     }
283 }
284
285 static int
286 ldp_init (void)
287 {
288   ldp_worker_ctx_t *ldpw;
289   int rv;
290
291   if (ldp->init)
292     {
293       LDBG (0, "LDP is initialized already");
294       return 0;
295     }
296
297   ldp_init_cfg ();
298   ldp->init = 1;
299   ldp->vcl_needs_real_epoll = 1;
300   rv = vls_app_create (ldp_get_app_name ());
301   if (rv != VPPCOM_OK)
302     {
303       ldp->vcl_needs_real_epoll = 0;
304       if (rv == VPPCOM_EEXIST)
305         return 0;
306       LDBG (2,
307             "\nERROR: ldp_init: vppcom_app_create()"
308             " failed!  rv = %d (%s)\n",
309             rv, vppcom_retval_str (rv));
310       ldp->init = 0;
311       return rv;
312     }
313   ldp->vcl_needs_real_epoll = 0;
314   ldp_alloc_workers ();
315
316   vec_foreach (ldpw, ldp->workers)
317     clib_memset (&ldpw->clib_time, 0, sizeof (ldpw->clib_time));
318
319   LDBG (0, "LDP initialization: done!");
320
321   return 0;
322 }
323
324 #define ldp_init_check()                                                      \
325   if (PREDICT_FALSE (!ldp->init))                                             \
326     {                                                                         \
327       if ((errno = -ldp_init ()))                                             \
328         return -1;                                                            \
329     }
330
331 int
332 close (int fd)
333 {
334   vls_handle_t vlsh;
335   int rv, epfd;
336
337   ldp_init_check ();
338
339   vlsh = ldp_fd_to_vlsh (fd);
340   if (vlsh != VLS_INVALID_HANDLE)
341     {
342       epfd = vls_attr (vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
343       if (epfd > 0)
344         {
345           ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
346           u32 size = sizeof (epfd);
347
348           LDBG (0, "fd %d: calling libc_close: epfd %u", fd, epfd);
349
350           libc_close (epfd);
351           ldpw->mq_epfd_added = 0;
352
353           epfd = 0;
354           (void) vls_attr (vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &epfd, &size);
355         }
356       else if (PREDICT_FALSE (epfd < 0))
357         {
358           errno = -epfd;
359           rv = -1;
360           goto done;
361         }
362
363       LDBG (0, "fd %d: calling vls_close: vlsh %u", fd, vlsh);
364
365       rv = vls_close (vlsh);
366       if (rv != VPPCOM_OK)
367         {
368           errno = -rv;
369           rv = -1;
370         }
371     }
372   else
373     {
374       LDBG (0, "fd %d: calling libc_close", fd);
375       rv = libc_close (fd);
376     }
377
378 done:
379   return rv;
380 }
381
382 ssize_t
383 read (int fd, void *buf, size_t nbytes)
384 {
385   vls_handle_t vlsh;
386   ssize_t size;
387
388   ldp_init_check ();
389
390   vlsh = ldp_fd_to_vlsh (fd);
391   if (vlsh != VLS_INVALID_HANDLE)
392     {
393       size = vls_read (vlsh, buf, nbytes);
394       if (size < 0)
395         {
396           errno = -size;
397           size = -1;
398         }
399     }
400   else
401     {
402       size = libc_read (fd, buf, nbytes);
403     }
404
405   return size;
406 }
407
408 ssize_t
409 readv (int fd, const struct iovec * iov, int iovcnt)
410 {
411   int rv = 0, i, total = 0;
412   vls_handle_t vlsh;
413   ssize_t size = 0;
414
415   ldp_init_check ();
416
417   vlsh = ldp_fd_to_vlsh (fd);
418   if (vlsh != VLS_INVALID_HANDLE)
419     {
420       for (i = 0; i < iovcnt; ++i)
421         {
422           rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len);
423           if (rv <= 0)
424             break;
425           else
426             {
427               total += rv;
428               if (rv < iov[i].iov_len)
429                 break;
430             }
431         }
432       if (rv < 0 && total == 0)
433         {
434           errno = -rv;
435           size = -1;
436         }
437       else
438         size = total;
439     }
440   else
441     {
442       size = libc_readv (fd, iov, iovcnt);
443     }
444
445   return size;
446 }
447
448 ssize_t
449 write (int fd, const void *buf, size_t nbytes)
450 {
451   vls_handle_t vlsh;
452   ssize_t size = 0;
453
454   ldp_init_check ();
455
456   vlsh = ldp_fd_to_vlsh (fd);
457   if (vlsh != VLS_INVALID_HANDLE)
458     {
459       size = vls_write_msg (vlsh, (void *) buf, nbytes);
460       if (size < 0)
461         {
462           errno = -size;
463           size = -1;
464         }
465     }
466   else
467     {
468       size = libc_write (fd, buf, nbytes);
469     }
470
471   return size;
472 }
473
474 ssize_t
475 writev (int fd, const struct iovec * iov, int iovcnt)
476 {
477   ssize_t size = 0, total = 0;
478   vls_handle_t vlsh;
479   int i, rv = 0;
480
481   ldp_init_check ();
482
483   vlsh = ldp_fd_to_vlsh (fd);
484   if (vlsh != VLS_INVALID_HANDLE)
485     {
486       for (i = 0; i < iovcnt; ++i)
487         {
488           rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len);
489           if (rv < 0)
490             break;
491           else
492             {
493               total += rv;
494               if (rv < iov[i].iov_len)
495                 break;
496             }
497         }
498
499       if (rv < 0 && total == 0)
500         {
501           errno = -rv;
502           size = -1;
503         }
504       else
505         size = total;
506     }
507   else
508     {
509       size = libc_writev (fd, iov, iovcnt);
510     }
511
512   return size;
513 }
514
515 static int
516 fcntl_internal (int fd, int cmd, va_list ap)
517 {
518   vls_handle_t vlsh;
519   int rv = 0;
520
521   vlsh = ldp_fd_to_vlsh (fd);
522   LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd);
523   if (vlsh != VLS_INVALID_HANDLE)
524     {
525       int flags = va_arg (ap, int);
526       u32 size;
527
528       size = sizeof (flags);
529       rv = -EOPNOTSUPP;
530       switch (cmd)
531         {
532         case F_SETFL:
533           rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
534           break;
535
536         case F_GETFL:
537           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
538           if (rv == VPPCOM_OK)
539             rv = flags;
540           break;
541         case F_SETFD:
542           /* TODO handle this */
543           LDBG (0, "F_SETFD ignored flags %u", flags);
544           rv = 0;
545           break;
546         default:
547           rv = -EOPNOTSUPP;
548           break;
549         }
550       if (rv < 0)
551         {
552           errno = -rv;
553           rv = -1;
554         }
555     }
556   else
557     {
558 #ifdef HAVE_FCNTL64
559       rv = libc_vfcntl64 (fd, cmd, ap);
560 #else
561       rv = libc_vfcntl (fd, cmd, ap);
562 #endif
563     }
564
565   return rv;
566 }
567
568 int
569 fcntl (int fd, int cmd, ...)
570 {
571   va_list ap;
572   int rv;
573
574   ldp_init_check ();
575
576   va_start (ap, cmd);
577   rv = fcntl_internal (fd, cmd, ap);
578   va_end (ap);
579
580   return rv;
581 }
582
583 int
584 fcntl64 (int fd, int cmd, ...)
585 {
586   va_list ap;
587   int rv;
588
589   ldp_init_check ();
590
591   va_start (ap, cmd);
592   rv = fcntl_internal (fd, cmd, ap);
593   va_end (ap);
594   return rv;
595 }
596
597 int
598 ioctl (int fd, unsigned long int cmd, ...)
599 {
600   vls_handle_t vlsh;
601   va_list ap;
602   int rv;
603
604   ldp_init_check ();
605
606   va_start (ap, cmd);
607
608   vlsh = ldp_fd_to_vlsh (fd);
609   if (vlsh != VLS_INVALID_HANDLE)
610     {
611       switch (cmd)
612         {
613         case FIONREAD:
614           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
615           break;
616
617         case FIONBIO:
618           {
619             u32 flags = *(va_arg (ap, int *)) ? O_NONBLOCK : 0;
620             u32 size = sizeof (flags);
621
622             /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
623              *      non-blocking, the flags should be read here and merged
624              *      with O_NONBLOCK.
625              */
626             rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
627           }
628           break;
629
630         default:
631           rv = -EOPNOTSUPP;
632           break;
633         }
634       if (rv < 0)
635         {
636           errno = -rv;
637           rv = -1;
638         }
639     }
640   else
641     {
642       rv = libc_vioctl (fd, cmd, ap);
643     }
644
645   va_end (ap);
646   return rv;
647 }
648
649 always_inline void
650 ldp_select_init_maps (fd_set * __restrict original,
651                       clib_bitmap_t ** resultb, clib_bitmap_t ** libcb,
652                       clib_bitmap_t ** vclb, int nfds, u32 minbits,
653                       u32 n_bytes, uword * si_bits, uword * libc_bits)
654 {
655   uword si_bits_set, libc_bits_set;
656   vls_handle_t vlsh;
657   int fd;
658
659   clib_bitmap_validate (*vclb, minbits);
660   clib_bitmap_validate (*libcb, minbits);
661   clib_bitmap_validate (*resultb, minbits);
662   clib_memcpy_fast (*resultb, original, n_bytes);
663   memset (original, 0, n_bytes);
664
665   clib_bitmap_foreach (fd, *resultb)  {
666     if (fd > nfds)
667       break;
668     vlsh = ldp_fd_to_vlsh (fd);
669     if (vlsh == VLS_INVALID_HANDLE)
670       clib_bitmap_set_no_check (*libcb, fd, 1);
671     else
672       *vclb = clib_bitmap_set (*vclb, vlsh_to_session_index (vlsh), 1);
673   }
674
675   si_bits_set = clib_bitmap_last_set (*vclb) + 1;
676   *si_bits = (si_bits_set > *si_bits) ? si_bits_set : *si_bits;
677   clib_bitmap_validate (*resultb, *si_bits);
678
679   libc_bits_set = clib_bitmap_last_set (*libcb) + 1;
680   *libc_bits = (libc_bits_set > *libc_bits) ? libc_bits_set : *libc_bits;
681 }
682
683 always_inline int
684 ldp_select_vcl_map_to_libc (clib_bitmap_t * vclb, fd_set * __restrict libcb)
685 {
686   vls_handle_t vlsh;
687   uword si;
688   int fd;
689
690   if (!libcb)
691     return 0;
692
693   clib_bitmap_foreach (si, vclb)  {
694     vlsh = vls_session_index_to_vlsh (si);
695     ASSERT (vlsh != VLS_INVALID_HANDLE);
696     fd = ldp_vlsh_to_fd (vlsh);
697     if (PREDICT_FALSE (fd < 0))
698       {
699         errno = EBADFD;
700         return -1;
701       }
702     FD_SET (fd, libcb);
703   }
704
705   return 0;
706 }
707
708 always_inline void
709 ldp_select_libc_map_merge (clib_bitmap_t * result, fd_set * __restrict libcb)
710 {
711   uword fd;
712
713   if (!libcb)
714     return;
715
716   clib_bitmap_foreach (fd, result)
717     FD_SET ((int)fd, libcb);
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           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1863                         "rv %d, errno = %d", getpid (), fd, fd,
1864                         func_str, size, errno_val);
1865           errno = errno_val;
1866         }
1867       else
1868         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1869                       getpid (), fd, fd, size, size);
1870     }
1871   return size;
1872 }
1873 #endif
1874
1875 ssize_t
1876 recvmsg (int fd, struct msghdr * msg, int flags)
1877 {
1878   vls_handle_t vlsh;
1879   ssize_t size;
1880
1881   ldp_init_check ();
1882
1883   vlsh = ldp_fd_to_vlsh (fd);
1884   if (vlsh != VLS_INVALID_HANDLE)
1885     {
1886       struct iovec *iov = msg->msg_iov;
1887       ssize_t max_deq, total = 0;
1888       int i, rv = 0;
1889
1890       max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
1891       if (!max_deq)
1892         return 0;
1893
1894       for (i = 0; i < msg->msg_iovlen; i++)
1895         {
1896           rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1897                                  (i == 0 ? msg->msg_name : NULL),
1898                                  (i == 0 ? &msg->msg_namelen : NULL));
1899           if (rv <= 0)
1900             break;
1901           else
1902             {
1903               total += rv;
1904               if (rv < iov[i].iov_len)
1905                 break;
1906             }
1907           if (total >= max_deq)
1908             break;
1909         }
1910
1911       if (rv < 0 && total == 0)
1912         {
1913           errno = -rv;
1914           size = -1;
1915         }
1916       else
1917         {
1918           if (msg->msg_controllen)
1919             ldp_make_cmsg (vlsh, msg);
1920           size = total;
1921         }
1922     }
1923   else
1924     {
1925       size = libc_recvmsg (fd, msg, flags);
1926     }
1927
1928   return size;
1929 }
1930
1931 #ifdef _GNU_SOURCE
1932 int
1933 recvmmsg (int fd, struct mmsghdr *vmessages,
1934           unsigned int vlen, int flags, struct timespec *tmo)
1935 {
1936   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1937   u32 sh;
1938
1939   ldp_init_check ();
1940
1941   sh = ldp_fd_to_vlsh (fd);
1942
1943   if (sh != VLS_INVALID_HANDLE)
1944     {
1945       struct mmsghdr *mh;
1946       ssize_t rv = 0;
1947       u32 nvecs = 0;
1948       f64 time_out;
1949
1950       if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
1951         clib_time_init (&ldpw->clib_time);
1952       if (tmo)
1953         {
1954           time_out = (f64) tmo->tv_sec + (f64) tmo->tv_nsec / (f64) 1e9;
1955           time_out += clib_time_now (&ldpw->clib_time);
1956         }
1957       else
1958         {
1959           time_out = (f64) ~0;
1960         }
1961
1962       while (nvecs < vlen)
1963         {
1964           mh = &vmessages[nvecs];
1965           rv = recvmsg (fd, &mh->msg_hdr, flags);
1966           if (rv > 0)
1967             {
1968               mh->msg_len = rv;
1969               nvecs += 1;
1970               continue;
1971             }
1972
1973           if (!time_out || clib_time_now (&ldpw->clib_time) >= time_out)
1974             break;
1975
1976           usleep (1);
1977         }
1978
1979       return nvecs > 0 ? nvecs : rv;
1980     }
1981   else
1982     {
1983       return libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1984     }
1985 }
1986 #endif
1987
1988 int
1989 getsockopt (int fd, int level, int optname,
1990             void *__restrict optval, socklen_t * __restrict optlen)
1991 {
1992   vls_handle_t vlsh;
1993   int rv;
1994
1995   ldp_init_check ();
1996
1997   vlsh = ldp_fd_to_vlsh (fd);
1998   if (vlsh != VLS_INVALID_HANDLE)
1999     {
2000       rv = -EOPNOTSUPP;
2001
2002       switch (level)
2003         {
2004         case SOL_TCP:
2005           switch (optname)
2006             {
2007             case TCP_NODELAY:
2008               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
2009                              optval, optlen);
2010               break;
2011             case TCP_MAXSEG:
2012               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
2013                              optval, optlen);
2014               break;
2015             case TCP_KEEPIDLE:
2016               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
2017                              optval, optlen);
2018               break;
2019             case TCP_KEEPINTVL:
2020               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
2021                              optval, optlen);
2022               break;
2023             case TCP_INFO:
2024               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
2025                 {
2026                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
2027                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
2028                   memset (optval, 0, *optlen);
2029                   rv = VPPCOM_OK;
2030                 }
2031               else
2032                 rv = -EFAULT;
2033               break;
2034             case TCP_CONGESTION:
2035               *optlen = strlen ("cubic");
2036               strncpy (optval, "cubic", *optlen + 1);
2037               rv = 0;
2038               break;
2039             default:
2040               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
2041                     "optname %d unsupported!", fd, vlsh, optname);
2042               break;
2043             }
2044           break;
2045         case SOL_IP:
2046           switch (optname)
2047             {
2048             case SO_ORIGINAL_DST:
2049               rv =
2050                 vls_attr (vlsh, VPPCOM_ATTR_GET_ORIGINAL_DST, optval, optlen);
2051               break;
2052             default:
2053               LDBG (0,
2054                     "ERROR: fd %d: getsockopt SOL_IP: vlsh %u "
2055                     "optname %d unsupported!",
2056                     fd, vlsh, optname);
2057               break;
2058             }
2059           break;
2060         case SOL_IPV6:
2061           switch (optname)
2062             {
2063             case IPV6_V6ONLY:
2064               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
2065               break;
2066             default:
2067               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
2068                     "optname %d unsupported!", fd, vlsh, optname);
2069               break;
2070             }
2071           break;
2072         case SOL_SOCKET:
2073           switch (optname)
2074             {
2075             case SO_ACCEPTCONN:
2076               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
2077               break;
2078             case SO_KEEPALIVE:
2079               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
2080               break;
2081             case SO_PROTOCOL:
2082               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
2083               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
2084               break;
2085             case SO_SNDBUF:
2086               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
2087                              optval, optlen);
2088               break;
2089             case SO_RCVBUF:
2090               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
2091                              optval, optlen);
2092               break;
2093             case SO_REUSEADDR:
2094               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
2095               break;
2096             case SO_REUSEPORT:
2097               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen);
2098               break;
2099             case SO_BROADCAST:
2100               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
2101               break;
2102             case SO_DOMAIN:
2103               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen);
2104               break;
2105             case SO_ERROR:
2106               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
2107               break;
2108             case SO_BINDTODEVICE:
2109               rv = 0;
2110               break;
2111             default:
2112               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
2113                     "optname %d unsupported!", fd, vlsh, optname);
2114               break;
2115             }
2116           break;
2117         default:
2118           break;
2119         }
2120
2121       if (rv != VPPCOM_OK)
2122         {
2123           errno = -rv;
2124           rv = -1;
2125         }
2126     }
2127   else
2128     {
2129       rv = libc_getsockopt (fd, level, optname, optval, optlen);
2130     }
2131
2132   return rv;
2133 }
2134
2135 int
2136 setsockopt (int fd, int level, int optname,
2137             const void *optval, socklen_t optlen)
2138 {
2139   vls_handle_t vlsh;
2140   int rv;
2141
2142   ldp_init_check ();
2143
2144   vlsh = ldp_fd_to_vlsh (fd);
2145   if (vlsh != VLS_INVALID_HANDLE)
2146     {
2147       rv = -EOPNOTSUPP;
2148
2149       switch (level)
2150         {
2151         case SOL_TCP:
2152           switch (optname)
2153             {
2154             case TCP_NODELAY:
2155               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
2156                              (void *) optval, &optlen);
2157               break;
2158             case TCP_MAXSEG:
2159               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
2160                              (void *) optval, &optlen);
2161               break;
2162             case TCP_KEEPIDLE:
2163               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2164                              (void *) optval, &optlen);
2165               break;
2166             case TCP_KEEPINTVL:
2167               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2168                              (void *) optval, &optlen);
2169               break;
2170             case TCP_CONGESTION:
2171             case TCP_CORK:
2172               /* Ignore */
2173               rv = 0;
2174               break;
2175             default:
2176               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2177                     "optname %d unsupported!", fd, vlsh, optname);
2178               break;
2179             }
2180           break;
2181         case SOL_IPV6:
2182           switch (optname)
2183             {
2184             case IPV6_V6ONLY:
2185               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2186                              (void *) optval, &optlen);
2187               break;
2188             default:
2189               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2190                     "optname %d unsupported!", fd, vlsh, optname);
2191               break;
2192             }
2193           break;
2194         case SOL_SOCKET:
2195           switch (optname)
2196             {
2197             case SO_KEEPALIVE:
2198               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2199                              (void *) optval, &optlen);
2200               break;
2201             case SO_REUSEADDR:
2202               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2203                              (void *) optval, &optlen);
2204               break;
2205             case SO_REUSEPORT:
2206               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval,
2207                              &optlen);
2208               break;
2209             case SO_BROADCAST:
2210               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2211                              (void *) optval, &optlen);
2212               break;
2213             case SO_LINGER:
2214               rv = 0;
2215               break;
2216             default:
2217               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2218                     "optname %d unsupported!", fd, vlsh, optname);
2219               break;
2220             }
2221           break;
2222         case SOL_IP:
2223           switch (optname)
2224             {
2225             case IP_PKTINFO:
2226               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_IP_PKTINFO, (void *) optval,
2227                              &optlen);
2228               break;
2229             default:
2230               LDBG (0,
2231                     "ERROR: fd %d: setsockopt SOL_IP: vlsh %u optname %d"
2232                     "unsupported!",
2233                     fd, vlsh, optname);
2234               break;
2235             }
2236           break;
2237         default:
2238           break;
2239         }
2240
2241       if (rv != VPPCOM_OK)
2242         {
2243           errno = -rv;
2244           rv = -1;
2245         }
2246     }
2247   else
2248     {
2249       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2250     }
2251
2252   return rv;
2253 }
2254
2255 int
2256 listen (int fd, int n)
2257 {
2258   vls_handle_t vlsh;
2259   int rv;
2260
2261   ldp_init_check ();
2262
2263   vlsh = ldp_fd_to_vlsh (fd);
2264   if (vlsh != VLS_INVALID_HANDLE)
2265     {
2266       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2267
2268       rv = vls_listen (vlsh, n);
2269       if (rv != VPPCOM_OK)
2270         {
2271           errno = -rv;
2272           rv = -1;
2273         }
2274     }
2275   else
2276     {
2277       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2278       rv = libc_listen (fd, n);
2279     }
2280
2281   LDBG (1, "fd %d: returning %d", fd, rv);
2282   return rv;
2283 }
2284
2285 static inline int
2286 ldp_accept4 (int listen_fd, __SOCKADDR_ARG _addr,
2287              socklen_t *__restrict addr_len, int flags)
2288 {
2289   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
2290   vls_handle_t listen_vlsh, accept_vlsh;
2291   int rv;
2292
2293   ldp_init_check ();
2294
2295   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2296   if (listen_vlsh != VLS_INVALID_HANDLE)
2297     {
2298       vppcom_endpt_t ep;
2299       u8 src_addr[sizeof (struct sockaddr_in6)];
2300       memset (&ep, 0, sizeof (ep));
2301       ep.ip = src_addr;
2302
2303       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2304             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2305
2306       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2307       if (accept_vlsh < 0)
2308         {
2309           errno = -accept_vlsh;
2310           rv = -1;
2311         }
2312       else
2313         {
2314           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2315           if (rv != VPPCOM_OK)
2316             {
2317               (void) vls_close (accept_vlsh);
2318               errno = -rv;
2319               rv = -1;
2320             }
2321           else
2322             {
2323               rv = ldp_vlsh_to_fd (accept_vlsh);
2324             }
2325         }
2326     }
2327   else
2328     {
2329       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2330             " flags 0x%x", listen_fd, addr, addr_len, flags);
2331
2332       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2333     }
2334
2335   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2336
2337   return rv;
2338 }
2339
2340 int
2341 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2342          int flags)
2343 {
2344   return ldp_accept4 (fd, addr, addr_len, flags);
2345 }
2346
2347 int
2348 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2349 {
2350   return ldp_accept4 (fd, addr, addr_len, 0);
2351 }
2352
2353 int
2354 shutdown (int fd, int how)
2355 {
2356   vls_handle_t vlsh;
2357   int rv = 0;
2358
2359   ldp_init_check ();
2360
2361   vlsh = ldp_fd_to_vlsh (fd);
2362   if (vlsh != VLS_INVALID_HANDLE)
2363     {
2364       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2365       rv = vls_shutdown (vlsh, how);
2366     }
2367   else
2368     {
2369       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2370       rv = libc_shutdown (fd, how);
2371     }
2372
2373   return rv;
2374 }
2375
2376 int
2377 epoll_create1 (int flags)
2378 {
2379   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2380   vls_handle_t vlsh;
2381   int rv;
2382
2383   ldp_init_check ();
2384
2385   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2386     {
2387       /* Make sure workers have been allocated */
2388       if (!ldp->workers)
2389         {
2390           ldp_alloc_workers ();
2391           ldpw = ldp_worker_get_current ();
2392         }
2393       rv = libc_epoll_create1 (flags);
2394       ldp->vcl_needs_real_epoll = 0;
2395       ldpw->vcl_mq_epfd = rv;
2396       LDBG (0, "created vcl epfd %u", rv);
2397       return rv;
2398     }
2399
2400   vlsh = vls_epoll_create ();
2401   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2402     {
2403       errno = -vlsh;
2404       rv = -1;
2405     }
2406   else
2407     {
2408       rv = ldp_vlsh_to_fd (vlsh);
2409     }
2410   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2411   return rv;
2412 }
2413
2414 int
2415 epoll_create (int size)
2416 {
2417   return epoll_create1 (0);
2418 }
2419
2420 int
2421 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2422 {
2423   vls_handle_t vep_vlsh, vlsh;
2424   int rv;
2425
2426   ldp_init_check ();
2427
2428   vep_vlsh = ldp_fd_to_vlsh (epfd);
2429   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2430     {
2431       /* The LDP epoll_create1 always creates VCL epfd's.
2432        * The app should never have a kernel base epoll fd unless it
2433        * was acquired outside of the LD_PRELOAD process context.
2434        * In any case, if we get one, punt it to libc_epoll_ctl.
2435        */
2436       LDBG (1,
2437             "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2438             " events 0x%x",
2439             epfd, op, fd, event ? event->events : 0);
2440
2441       rv = libc_epoll_ctl (epfd, op, fd, event);
2442       goto done;
2443     }
2444
2445   vlsh = ldp_fd_to_vlsh (fd);
2446
2447   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2448         vlsh, op);
2449
2450   if (vlsh != VLS_INVALID_HANDLE)
2451     {
2452       LDBG (1,
2453             "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2454             " events 0x%x",
2455             epfd, vep_vlsh, op, vlsh, event ? event->events : 0);
2456
2457       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2458       if (rv != VPPCOM_OK)
2459         {
2460           errno = -rv;
2461           rv = -1;
2462         }
2463     }
2464   else
2465     {
2466       int libc_epfd;
2467       u32 size = sizeof (epfd);
2468
2469       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2470       if (!libc_epfd)
2471         {
2472           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2473                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2474
2475           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2476           if (libc_epfd < 0)
2477             {
2478               rv = libc_epfd;
2479               goto done;
2480             }
2481
2482           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2483                          &size);
2484           if (rv < 0)
2485             {
2486               errno = -rv;
2487               rv = -1;
2488               goto done;
2489             }
2490         }
2491       else if (PREDICT_FALSE (libc_epfd < 0))
2492         {
2493           errno = -epfd;
2494           rv = -1;
2495           goto done;
2496         }
2497
2498       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2499             " event %p", epfd, libc_epfd, op, fd, event);
2500
2501       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2502     }
2503
2504 done:
2505   return rv;
2506 }
2507
2508 static inline int
2509 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2510                  int timeout, const sigset_t * sigmask)
2511 {
2512   ldp_worker_ctx_t *ldpw;
2513   double time_to_wait = (double) 0, max_time;
2514   int libc_epfd, rv = 0;
2515   vls_handle_t ep_vlsh;
2516
2517   ldp_init_check ();
2518
2519   if (PREDICT_FALSE (!events || (timeout < -1)))
2520     {
2521       errno = EFAULT;
2522       return -1;
2523     }
2524
2525   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2526     vls_register_vcl_worker ();
2527
2528   ldpw = ldp_worker_get_current ();
2529   if (epfd == ldpw->vcl_mq_epfd)
2530     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2531
2532   ep_vlsh = ldp_fd_to_vlsh (epfd);
2533   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2534     {
2535       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2536       errno = EBADFD;
2537       return -1;
2538     }
2539
2540   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2541     clib_time_init (&ldpw->clib_time);
2542   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2543   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2544
2545   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2546   if (PREDICT_FALSE (libc_epfd < 0))
2547     {
2548       errno = -libc_epfd;
2549       rv = -1;
2550       goto done;
2551     }
2552
2553   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2554         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2555         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2556   do
2557     {
2558       if (!ldpw->epoll_wait_vcl)
2559         {
2560           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2561           if (rv > 0)
2562             {
2563               ldpw->epoll_wait_vcl = 1;
2564               goto done;
2565             }
2566           else if (rv < 0)
2567             {
2568               errno = -rv;
2569               rv = -1;
2570               goto done;
2571             }
2572         }
2573       else
2574         ldpw->epoll_wait_vcl = 0;
2575
2576       if (libc_epfd > 0)
2577         {
2578           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2579           if (rv != 0)
2580             goto done;
2581         }
2582     }
2583   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2584
2585 done:
2586   return rv;
2587 }
2588
2589 static inline int
2590 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2591                          int maxevents, int timeout, const sigset_t * sigmask)
2592 {
2593   int libc_epfd, rv = 0, num_ev, libc_num_ev, vcl_wups = 0;
2594   struct epoll_event *libc_evts;
2595   ldp_worker_ctx_t *ldpw;
2596   vls_handle_t ep_vlsh;
2597
2598   ldp_init_check ();
2599
2600   if (PREDICT_FALSE (!events || (timeout < -1)))
2601     {
2602       errno = EFAULT;
2603       return -1;
2604     }
2605
2606   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2607    * one thread but it is now used on another */
2608   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2609     vls_register_vcl_worker ();
2610
2611   ldpw = ldp_worker_get_current ();
2612   if (epfd == ldpw->vcl_mq_epfd)
2613     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2614
2615   ep_vlsh = ldp_fd_to_vlsh (epfd);
2616   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2617     {
2618       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2619       errno = EBADFD;
2620       return -1;
2621     }
2622
2623   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2624   if (PREDICT_FALSE (!libc_epfd))
2625     {
2626       u32 size = sizeof (epfd);
2627
2628       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2629             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2630       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2631       if (libc_epfd < 0)
2632         {
2633           rv = libc_epfd;
2634           goto done;
2635         }
2636
2637       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2638       if (rv < 0)
2639         {
2640           errno = -rv;
2641           rv = -1;
2642           goto done;
2643         }
2644     }
2645   if (PREDICT_FALSE (libc_epfd <= 0))
2646     {
2647       errno = -libc_epfd;
2648       rv = -1;
2649       goto done;
2650     }
2651
2652   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2653     {
2654       struct epoll_event e = { 0 };
2655       e.events = EPOLLIN;
2656       e.data.fd = ldpw->vcl_mq_epfd;
2657       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2658           0)
2659         {
2660           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2661                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2662           rv = -1;
2663           goto done;
2664         }
2665       ldpw->mq_epfd_added = 1;
2666     }
2667
2668   /* Request to only drain unhandled to prevent libc_epoll_wait starved */
2669   rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2);
2670   if (rv > 0)
2671     {
2672       timeout = 0;
2673       if (rv >= maxevents)
2674         goto done;
2675       maxevents -= rv;
2676     }
2677   else if (PREDICT_FALSE (rv < 0))
2678     {
2679       errno = -rv;
2680       rv = -1;
2681       goto done;
2682     }
2683
2684 epoll_again:
2685
2686   libc_evts = &events[rv];
2687   libc_num_ev =
2688     libc_epoll_pwait (libc_epfd, libc_evts, maxevents, timeout, sigmask);
2689   if (libc_num_ev <= 0)
2690     {
2691       rv = rv >= 0 ? rv : -1;
2692       goto done;
2693     }
2694
2695   for (int i = 0; i < libc_num_ev; i++)
2696     {
2697       if (libc_evts[i].data.fd == ldpw->vcl_mq_epfd)
2698         {
2699           /* We should remove mq epoll fd from events. */
2700           libc_num_ev--;
2701           if (i != libc_num_ev)
2702             {
2703               libc_evts[i].events = libc_evts[libc_num_ev].events;
2704               libc_evts[i].data.u64 = libc_evts[libc_num_ev].data.u64;
2705             }
2706           num_ev = vls_epoll_wait (ep_vlsh, &libc_evts[libc_num_ev],
2707                                    maxevents - libc_num_ev, 0);
2708           if (PREDICT_TRUE (num_ev > 0))
2709             rv += num_ev;
2710           /* Woken up by vcl but no events generated. Accept it once */
2711           if (rv == 0 && libc_num_ev == 0 && timeout && vcl_wups++ < 1)
2712             goto epoll_again;
2713           break;
2714         }
2715     }
2716
2717   rv += libc_num_ev;
2718
2719 done:
2720   return rv;
2721 }
2722
2723 int
2724 epoll_pwait (int epfd, struct epoll_event *events,
2725              int maxevents, int timeout, const sigset_t * sigmask)
2726 {
2727   if (vls_use_eventfd ())
2728     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2729                                     sigmask);
2730   else
2731     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2732 }
2733
2734 int
2735 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2736 {
2737   if (vls_use_eventfd ())
2738     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2739   else
2740     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2741 }
2742
2743 int
2744 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2745 {
2746   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2747   int rv, i, n_revents = 0;
2748   vls_handle_t vlsh;
2749   vcl_poll_t *vp;
2750   double max_time;
2751
2752   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2753
2754   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2755     clib_time_init (&ldpw->clib_time);
2756
2757   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2758   max_time += clib_time_now (&ldpw->clib_time);
2759
2760   for (i = 0; i < nfds; i++)
2761     {
2762       if (fds[i].fd < 0)
2763         continue;
2764
2765       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2766       if (vlsh != VLS_INVALID_HANDLE)
2767         {
2768           fds[i].fd = -fds[i].fd;
2769           vec_add2 (ldpw->vcl_poll, vp, 1);
2770           vp->fds_ndx = i;
2771           vp->sh = vlsh_to_sh (vlsh);
2772           vp->events = fds[i].events;
2773 #ifdef __USE_XOPEN2K
2774           if (fds[i].events & POLLRDNORM)
2775             vp->events |= POLLIN;
2776           if (fds[i].events & POLLWRNORM)
2777             vp->events |= POLLOUT;
2778 #endif
2779           vp->revents = fds[i].revents;
2780         }
2781       else
2782         {
2783           vec_add1 (ldpw->libc_poll, fds[i]);
2784           vec_add1 (ldpw->libc_poll_idxs, i);
2785         }
2786     }
2787
2788   do
2789     {
2790       if (vec_len (ldpw->vcl_poll))
2791         {
2792           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2793           if (rv < 0)
2794             {
2795               errno = -rv;
2796               rv = -1;
2797               goto done;
2798             }
2799           else
2800             n_revents += rv;
2801         }
2802
2803       if (vec_len (ldpw->libc_poll))
2804         {
2805           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2806           if (rv < 0)
2807             goto done;
2808           else
2809             n_revents += rv;
2810         }
2811
2812       if (n_revents)
2813         {
2814           rv = n_revents;
2815           goto done;
2816         }
2817     }
2818   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2819   rv = 0;
2820
2821 done:
2822   vec_foreach (vp, ldpw->vcl_poll)
2823   {
2824     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2825     fds[vp->fds_ndx].revents = vp->revents;
2826 #ifdef __USE_XOPEN2K
2827     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2828         (fds[vp->fds_ndx].events & POLLRDNORM))
2829       fds[vp->fds_ndx].revents |= POLLRDNORM;
2830     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2831         (fds[vp->fds_ndx].events & POLLWRNORM))
2832       fds[vp->fds_ndx].revents |= POLLWRNORM;
2833 #endif
2834   }
2835   vec_reset_length (ldpw->vcl_poll);
2836
2837   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2838     {
2839       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2840     }
2841   vec_reset_length (ldpw->libc_poll_idxs);
2842   vec_reset_length (ldpw->libc_poll);
2843
2844   return rv;
2845 }
2846
2847 #ifdef _GNU_SOURCE
2848 int
2849 ppoll (struct pollfd *fds, nfds_t nfds,
2850        const struct timespec *timeout, const sigset_t * sigmask)
2851 {
2852   ldp_init_check ();
2853
2854   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2855   errno = ENOSYS;
2856
2857
2858   return -1;
2859 }
2860 #endif
2861
2862 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2863
2864 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2865
2866 /*
2867  * This function is called when the library is loaded
2868  */
2869 void
2870 ldp_constructor (void)
2871 {
2872   swrap_constructor ();
2873   if (ldp_init () != 0)
2874     {
2875       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2876                getpid ());
2877       _exit (1);
2878     }
2879   else if (LDP_DEBUG > 0)
2880     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2881 }
2882
2883 /*
2884  * This function is called when the library is unloaded
2885  */
2886 void
2887 ldp_destructor (void)
2888 {
2889   /*
2890      swrap_destructor ();
2891      if (ldp->init)
2892      ldp->init = 0;
2893    */
2894
2895   /* Don't use clib_warning() here because that calls writev()
2896    * which will call ldp_init().
2897    */
2898   if (LDP_DEBUG > 0)
2899     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2900              __func__, __LINE__, getpid ());
2901 }
2902
2903
2904 /*
2905  * fd.io coding-style-patch-verification: ON
2906  *
2907  * Local Variables:
2908  * eval: (c-set-style "gnu")
2909  * End:
2910  */