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