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