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