X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fldp.c;h=b51d2e0ebb45bc25f6d11684974257c1f7a8ce34;hb=5f33d0d43784bd08c334dac58220040a3d0da28a;hp=1c038b0a10230419b725900af41a81675650155f;hpb=7baeb71f92826ee6ef02ab2c3d16484bb64d9301;p=vpp.git diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c index 1c038b0a102..b51d2e0ebb4 100644 --- a/src/vcl/ldp.c +++ b/src/vcl/ldp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016-2019 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -62,13 +62,12 @@ typedef struct ldp_worker_ctx_ clib_bitmap_t *rd_bitmap; clib_bitmap_t *wr_bitmap; clib_bitmap_t *ex_bitmap; - clib_bitmap_t *sid_rd_bitmap; - clib_bitmap_t *sid_wr_bitmap; - clib_bitmap_t *sid_ex_bitmap; + clib_bitmap_t *si_rd_bitmap; + clib_bitmap_t *si_wr_bitmap; + clib_bitmap_t *si_ex_bitmap; clib_bitmap_t *libc_rd_bitmap; clib_bitmap_t *libc_wr_bitmap; clib_bitmap_t *libc_ex_bitmap; - u8 select_vcl; /* * Poll state @@ -81,10 +80,18 @@ typedef struct ldp_worker_ctx_ * Epoll state */ u8 epoll_wait_vcl; + u8 mq_epfd_added; int vcl_mq_epfd; } ldp_worker_ctx_t; +/* clib_bitmap_t, fd_mask and vcl_si_set are used interchangeably. Make sure + * they are the same size */ +STATIC_ASSERT (sizeof (clib_bitmap_t) == sizeof (fd_mask), + "ldp bitmap size mismatch"); +STATIC_ASSERT (sizeof (vcl_si_set) == sizeof (fd_mask), + "ldp bitmap size mismatch"); + typedef struct { ldp_worker_ctx_t *workers; @@ -96,18 +103,30 @@ typedef struct /** vcl needs next epoll_create to go to libc_epoll */ u8 vcl_needs_real_epoll; + + /** + * crypto state used only for testing + */ + u8 transparent_tls; + u32 ckpair_index; } ldp_main_t; #define LDP_DEBUG ldp->debug #define LDBG(_lvl, _fmt, _args...) \ if (ldp->debug > _lvl) \ - clib_warning ("ldp<%d>: " _fmt, getpid(), ##_args) + { \ + int errno_saved = errno; \ + fprintf (stderr, "ldp<%d>: " _fmt "\n", getpid(), ##_args); \ + errno = errno_saved; \ + } static ldp_main_t ldp_main = { .vlsh_bit_val = (1 << LDP_SID_BIT_MIN), .vlsh_bit_mask = (1 << LDP_SID_BIT_MIN) - 1, .debug = LDP_DEBUG_INIT, + .transparent_tls = 0, + .ckpair_index = ~0, }; static ldp_main_t *ldp = &ldp_main; @@ -124,11 +143,8 @@ ldp_worker_get_current (void) static inline void ldp_set_app_name (char *app_name) { - int rv = snprintf (ldp->app_name, LDP_APP_NAME_MAX, - "ldp-%d-%s", getpid (), app_name); - - if (rv >= LDP_APP_NAME_MAX) - app_name[LDP_APP_NAME_MAX - 1] = 0; + snprintf (ldp->app_name, LDP_APP_NAME_MAX, + "ldp-%d-%s", getpid (), app_name); } static inline char * @@ -155,14 +171,21 @@ ldp_fd_to_vlsh (int fd) return (fd - ldp->vlsh_bit_val); } -static inline int +static void +ldp_alloc_workers (void) +{ + if (ldp->workers) + return; + pool_alloc (ldp->workers, LDP_MAX_NWORKERS); +} + +static int ldp_init (void) { ldp_worker_ctx_t *ldpw; int rv; - if (PREDICT_TRUE (ldp->init)) - return 0; + ASSERT (!ldp->init); ldp->init = 1; ldp->vcl_needs_real_epoll = 1; @@ -178,7 +201,7 @@ ldp_init (void) return rv; } ldp->vcl_needs_real_epoll = 0; - pool_alloc (ldp->workers, LDP_MAX_NWORKERS); + ldp_alloc_workers (); ldpw = ldp_worker_get_current (); char *env_var_str = getenv (LDP_ENV_DEBUG); @@ -211,32 +234,29 @@ ldp_init (void) u32 sb; if (sscanf (env_var_str, "%u", &sb) != 1) { - clib_warning ("LDP<%d>: WARNING: Invalid LDP sid bit specified in" - " the env var " LDP_ENV_SID_BIT " (%s)! sid bit " - "value %d (0x%x)", getpid (), env_var_str, - ldp->vlsh_bit_val, ldp->vlsh_bit_val); + LDBG (0, "WARNING: Invalid LDP sid bit specified in the env var " + LDP_ENV_SID_BIT " (%s)! sid bit value %d (0x%x)", env_var_str, + ldp->vlsh_bit_val, ldp->vlsh_bit_val); } else if (sb < LDP_SID_BIT_MIN) { ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MIN); ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1; - clib_warning ("LDP<%d>: WARNING: LDP sid bit (%u) specified in the" - " env var " LDP_ENV_SID_BIT " (%s) is too small. " - "Using LDP_SID_BIT_MIN (%d)! sid bit value %d (0x%x)", - getpid (), sb, env_var_str, LDP_SID_BIT_MIN, - ldp->vlsh_bit_val, ldp->vlsh_bit_val); + LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var " + LDP_ENV_SID_BIT " (%s) is too small. Using LDP_SID_BIT_MIN" + " (%d)! sid bit value %d (0x%x)", sb, env_var_str, + LDP_SID_BIT_MIN, ldp->vlsh_bit_val, ldp->vlsh_bit_val); } else if (sb > LDP_SID_BIT_MAX) { ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MAX); ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1; - clib_warning ("LDP<%d>: WARNING: LDP sid bit (%u) specified in the" - " env var " LDP_ENV_SID_BIT " (%s) is too big. Using" - " LDP_SID_BIT_MAX (%d)! sid bit value %d (0x%x)", - getpid (), sb, env_var_str, LDP_SID_BIT_MAX, - ldp->vlsh_bit_val, ldp->vlsh_bit_val); + LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var " + LDP_ENV_SID_BIT " (%s) is too big. Using LDP_SID_BIT_MAX" + " (%d)! sid bit value %d (0x%x)", sb, env_var_str, + LDP_SID_BIT_MAX, ldp->vlsh_bit_val, ldp->vlsh_bit_val); } else { @@ -247,22 +267,47 @@ ldp_init (void) LDP_ENV_SID_BIT "! sid bit value %d (0x%x)", sb, ldp->vlsh_bit_val, ldp->vlsh_bit_val); } + + /* Make sure there are enough bits in the fd set for vcl sessions */ + if (ldp->vlsh_bit_val > FD_SETSIZE / 2) + { + LDBG (0, "ERROR: LDP vlsh bit value %d > FD_SETSIZE/2 %d!", + ldp->vlsh_bit_val, FD_SETSIZE / 2); + ldp->init = 0; + return -1; + } + } + env_var_str = getenv (LDP_ENV_TLS_TRANS); + if (env_var_str) + { + ldp->transparent_tls = 1; } - clib_time_init (&ldpw->clib_time); + /* *INDENT-OFF* */ + pool_foreach (ldpw, ldp->workers) { + clib_memset (&ldpw->clib_time, 0, sizeof (ldpw->clib_time)); + } + /* *INDENT-ON* */ + LDBG (0, "LDP initialization: done!"); return 0; } +#define ldp_init_check() \ + if (PREDICT_FALSE (!ldp->init)) \ + { \ + if ((errno = -ldp_init ())) \ + return -1; \ + } + int close (int fd) { vls_handle_t vlsh; int rv, epfd; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -313,8 +358,7 @@ read (int fd, void *buf, size_t nbytes) vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -341,30 +385,24 @@ readv (int fd, const struct iovec * iov, int iovcnt) vls_handle_t vlsh; ssize_t size = 0; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) { - do + for (i = 0; i < iovcnt; ++i) { - for (i = 0; i < iovcnt; ++i) + rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len); + if (rv <= 0) + break; + else { - rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len); - if (rv < 0) + total += rv; + if (rv < iov[i].iov_len) break; - else - { - total += rv; - if (rv < iov[i].iov_len) - break; - } } } - while ((rv >= 0) && (total == 0)); - - if (rv < 0) + if (rv < 0 && total == 0) { errno = -rv; size = -1; @@ -386,8 +424,7 @@ write (int fd, const void *buf, size_t nbytes) vls_handle_t vlsh; ssize_t size = 0; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -414,30 +451,25 @@ writev (int fd, const struct iovec * iov, int iovcnt) vls_handle_t vlsh; int i, rv = 0; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) { - do + for (i = 0; i < iovcnt; ++i) { - for (i = 0; i < iovcnt; ++i) + rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len); + if (rv < 0) + break; + else { - rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len); - if (rv < 0) + total += rv; + if (rv < iov[i].iov_len) break; - else - { - total += rv; - if (rv < iov[i].iov_len) - break; - } } } - while ((rv >= 0) && (total == 0)); - if (rv < 0) + if (rv < 0 && total == 0) { errno = -rv; size = -1; @@ -453,17 +485,11 @@ writev (int fd, const struct iovec * iov, int iovcnt) return size; } -int -fcntl (int fd, int cmd, ...) +static int +fcntl_internal (int fd, int cmd, va_list ap) { vls_handle_t vlsh; int rv = 0; - va_list ap; - - if ((errno = -ldp_init ())) - return -1; - - va_start (ap, cmd); vlsh = ldp_fd_to_vlsh (fd); LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd); @@ -502,14 +528,45 @@ fcntl (int fd, int cmd, ...) } else { +#ifdef HAVE_FCNTL64 + rv = libc_vfcntl64 (fd, cmd, ap); +#else rv = libc_vfcntl (fd, cmd, ap); +#endif } + return rv; +} + +int +fcntl (int fd, int cmd, ...) +{ + va_list ap; + int rv; + + ldp_init_check (); + + va_start (ap, cmd); + rv = fcntl_internal (fd, cmd, ap); va_end (ap); return rv; } +int +fcntl64 (int fd, int cmd, ...) +{ + va_list ap; + int rv; + + ldp_init_check (); + + va_start (ap, cmd); + rv = fcntl_internal (fd, cmd, ap); + va_end (ap); + return rv; +} + int ioctl (int fd, unsigned long int cmd, ...) { @@ -517,8 +574,7 @@ ioctl (int fd, unsigned long int cmd, ...) va_list ap; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); va_start (ap, cmd); @@ -563,6 +619,83 @@ ioctl (int fd, unsigned long int cmd, ...) return rv; } +always_inline void +ldp_select_init_maps (fd_set * __restrict original, + clib_bitmap_t ** resultb, clib_bitmap_t ** libcb, + clib_bitmap_t ** vclb, int nfds, u32 minbits, + u32 n_bytes, uword * si_bits, uword * libc_bits) +{ + uword si_bits_set, libc_bits_set; + vls_handle_t vlsh; + int fd; + + clib_bitmap_validate (*vclb, minbits); + clib_bitmap_validate (*libcb, minbits); + clib_bitmap_validate (*resultb, minbits); + clib_memcpy_fast (*resultb, original, n_bytes); + memset (original, 0, n_bytes); + + /* *INDENT-OFF* */ + clib_bitmap_foreach (fd, *resultb) { + if (fd > nfds) + break; + vlsh = ldp_fd_to_vlsh (fd); + if (vlsh == VLS_INVALID_HANDLE) + clib_bitmap_set_no_check (*libcb, fd, 1); + else + *vclb = clib_bitmap_set (*vclb, vlsh_to_session_index (vlsh), 1); + } + /* *INDENT-ON* */ + + si_bits_set = clib_bitmap_last_set (*vclb) + 1; + *si_bits = (si_bits_set > *si_bits) ? si_bits_set : *si_bits; + clib_bitmap_validate (*resultb, *si_bits); + + libc_bits_set = clib_bitmap_last_set (*libcb) + 1; + *libc_bits = (libc_bits_set > *libc_bits) ? libc_bits_set : *libc_bits; +} + +always_inline int +ldp_select_vcl_map_to_libc (clib_bitmap_t * vclb, fd_set * __restrict libcb) +{ + vls_handle_t vlsh; + uword si; + int fd; + + if (!libcb) + return 0; + + /* *INDENT-OFF* */ + clib_bitmap_foreach (si, vclb) { + vlsh = vls_session_index_to_vlsh (si); + ASSERT (vlsh != VLS_INVALID_HANDLE); + fd = ldp_vlsh_to_fd (vlsh); + if (PREDICT_FALSE (fd < 0)) + { + errno = EBADFD; + return -1; + } + FD_SET (fd, libcb); + } + /* *INDENT-ON* */ + + return 0; +} + +always_inline void +ldp_select_libc_map_merge (clib_bitmap_t * result, fd_set * __restrict libcb) +{ + uword fd; + + if (!libcb) + return; + + /* *INDENT-OFF* */ + clib_bitmap_foreach (fd, result) + FD_SET ((int)fd, libcb); + /* *INDENT-ON* */ +} + int ldp_pselect (int nfds, fd_set * __restrict readfds, fd_set * __restrict writefds, @@ -570,12 +703,12 @@ ldp_pselect (int nfds, fd_set * __restrict readfds, const struct timespec *__restrict timeout, const __sigset_t * __restrict sigmask) { - uword sid_bits, sid_bits_set, libc_bits, libc_bits_set; + u32 minbits = clib_max (nfds, BITS (uword)), n_bytes; ldp_worker_ctx_t *ldpw = ldp_worker_get_current (); - u32 minbits = clib_max (nfds, BITS (uword)), si; - vls_handle_t vlsh; - f64 time_out; - int rv, fd; + struct timespec libc_tspec = { 0 }; + f64 time_out, vcl_timeout = 0; + uword si_bits, libc_bits; + int rv, bits_set = 0; if (nfds < 0) { @@ -583,6 +716,9 @@ ldp_pselect (int nfds, fd_set * __restrict readfds, return -1; } + if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0)) + clib_time_init (&ldpw->clib_time); + if (timeout) { time_out = (timeout->tv_sec == 0 && timeout->tv_nsec == 0) ? @@ -605,7 +741,6 @@ ldp_pselect (int nfds, fd_set * __restrict readfds, else time_out = -1; - if (nfds <= ldp->vlsh_bit_val) { rv = libc_pselect (nfds, readfds, writefds, exceptfds, @@ -613,218 +748,113 @@ ldp_pselect (int nfds, fd_set * __restrict readfds, goto done; } - if (PREDICT_FALSE (ldp->vlsh_bit_val > FD_SETSIZE / 2)) - { - LDBG (0, "ERROR: LDP sid bit value %d > FD_SETSIZE/2 %d!", - ldp->vlsh_bit_val, FD_SETSIZE / 2); - errno = EOVERFLOW; - return -1; - } - - sid_bits = libc_bits = 0; - u32 n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0); + si_bits = libc_bits = 0; + n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0); if (readfds) - { - clib_bitmap_validate (ldpw->sid_rd_bitmap, minbits); - clib_bitmap_validate (ldpw->libc_rd_bitmap, minbits); - clib_bitmap_validate (ldpw->rd_bitmap, minbits); - clib_memcpy_fast (ldpw->rd_bitmap, readfds, n_bytes); - memset (readfds, 0, n_bytes); - - /* *INDENT-OFF* */ - clib_bitmap_foreach (fd, ldpw->rd_bitmap, ({ - if (fd > nfds) - break; - vlsh = ldp_fd_to_vlsh (fd); - if (vlsh == VLS_INVALID_HANDLE) - clib_bitmap_set_no_check (ldpw->libc_rd_bitmap, fd, 1); - else - clib_bitmap_set_no_check (ldpw->sid_rd_bitmap, - vlsh_to_session_index (vlsh), 1); - })); - /* *INDENT-ON* */ - - sid_bits_set = clib_bitmap_last_set (ldpw->sid_rd_bitmap) + 1; - sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits; - - libc_bits_set = clib_bitmap_last_set (ldpw->libc_rd_bitmap) + 1; - libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits; - } + ldp_select_init_maps (readfds, &ldpw->rd_bitmap, &ldpw->libc_rd_bitmap, + &ldpw->si_rd_bitmap, nfds, minbits, n_bytes, + &si_bits, &libc_bits); if (writefds) - { - clib_bitmap_validate (ldpw->sid_wr_bitmap, minbits); - clib_bitmap_validate (ldpw->libc_wr_bitmap, minbits); - clib_bitmap_validate (ldpw->wr_bitmap, minbits); - clib_memcpy_fast (ldpw->wr_bitmap, writefds, n_bytes); - memset (writefds, 0, n_bytes); - - /* *INDENT-OFF* */ - clib_bitmap_foreach (fd, ldpw->wr_bitmap, ({ - if (fd > nfds) - break; - vlsh = ldp_fd_to_vlsh (fd); - if (vlsh == VLS_INVALID_HANDLE) - clib_bitmap_set_no_check (ldpw->libc_wr_bitmap, fd, 1); - else - clib_bitmap_set_no_check (ldpw->sid_wr_bitmap, - vlsh_to_session_index (vlsh), 1); - })); - /* *INDENT-ON* */ - - sid_bits_set = clib_bitmap_last_set (ldpw->sid_wr_bitmap) + 1; - sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits; - - libc_bits_set = clib_bitmap_last_set (ldpw->libc_wr_bitmap) + 1; - libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits; - - } + ldp_select_init_maps (writefds, &ldpw->wr_bitmap, + &ldpw->libc_wr_bitmap, &ldpw->si_wr_bitmap, nfds, + minbits, n_bytes, &si_bits, &libc_bits); if (exceptfds) - { - clib_bitmap_validate (ldpw->sid_ex_bitmap, minbits); - clib_bitmap_validate (ldpw->libc_ex_bitmap, minbits); - clib_bitmap_validate (ldpw->ex_bitmap, minbits); - clib_memcpy_fast (ldpw->ex_bitmap, exceptfds, n_bytes); - memset (exceptfds, 0, n_bytes); + ldp_select_init_maps (exceptfds, &ldpw->ex_bitmap, + &ldpw->libc_ex_bitmap, &ldpw->si_ex_bitmap, nfds, + minbits, n_bytes, &si_bits, &libc_bits); - /* *INDENT-OFF* */ - clib_bitmap_foreach (fd, ldpw->ex_bitmap, ({ - if (fd > nfds) - break; - vlsh = ldp_fd_to_vlsh (fd); - if (vlsh == VLS_INVALID_HANDLE) - clib_bitmap_set_no_check (ldpw->libc_ex_bitmap, fd, 1); - else - clib_bitmap_set_no_check (ldpw->sid_ex_bitmap, - vlsh_to_session_index (vlsh), 1); - })); - /* *INDENT-ON* */ - - sid_bits_set = clib_bitmap_last_set (ldpw->sid_ex_bitmap) + 1; - sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits; - - libc_bits_set = clib_bitmap_last_set (ldpw->libc_ex_bitmap) + 1; - libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits; - } - - if (PREDICT_FALSE (!sid_bits && !libc_bits)) + if (PREDICT_FALSE (!si_bits && !libc_bits)) { errno = EINVAL; rv = -1; goto done; } + if (!si_bits) + libc_tspec = timeout ? *timeout : libc_tspec; + do { - if (sid_bits) + if (si_bits) { - if (!ldpw->select_vcl) + if (readfds) + clib_memcpy_fast (ldpw->rd_bitmap, ldpw->si_rd_bitmap, + vec_len (ldpw->si_rd_bitmap) * + sizeof (clib_bitmap_t)); + if (writefds) + clib_memcpy_fast (ldpw->wr_bitmap, ldpw->si_wr_bitmap, + vec_len (ldpw->si_wr_bitmap) * + sizeof (clib_bitmap_t)); + if (exceptfds) + clib_memcpy_fast (ldpw->ex_bitmap, ldpw->si_ex_bitmap, + vec_len (ldpw->si_ex_bitmap) * + sizeof (clib_bitmap_t)); + + rv = vls_select (si_bits, readfds ? ldpw->rd_bitmap : NULL, + writefds ? ldpw->wr_bitmap : NULL, + exceptfds ? ldpw->ex_bitmap : NULL, vcl_timeout); + if (rv < 0) { - if (readfds) - clib_memcpy_fast (ldpw->rd_bitmap, ldpw->sid_rd_bitmap, - vec_len (ldpw->rd_bitmap) * - sizeof (clib_bitmap_t)); - if (writefds) - clib_memcpy_fast (ldpw->wr_bitmap, ldpw->sid_wr_bitmap, - vec_len (ldpw->wr_bitmap) * - sizeof (clib_bitmap_t)); - if (exceptfds) - clib_memcpy_fast (ldpw->ex_bitmap, ldpw->sid_ex_bitmap, - vec_len (ldpw->ex_bitmap) * - sizeof (clib_bitmap_t)); - - rv = vppcom_select (sid_bits, - readfds ? (unsigned long *) ldpw->rd_bitmap - : NULL, - writefds ? (unsigned long *) ldpw->wr_bitmap - : NULL, - exceptfds ? (unsigned long *) - ldpw->ex_bitmap : NULL, 0); - if (rv < 0) + errno = -rv; + rv = -1; + goto done; + } + else if (rv > 0) + { + if (ldp_select_vcl_map_to_libc (ldpw->rd_bitmap, readfds)) { - errno = -rv; rv = -1; + goto done; } - else if (rv > 0) + + if (ldp_select_vcl_map_to_libc (ldpw->wr_bitmap, writefds)) { - if (readfds) - { - /* *INDENT-OFF* */ - clib_bitmap_foreach (si, ldpw->rd_bitmap, ({ - vlsh = vls_session_index_to_vlsh (si); - fd = ldp_vlsh_to_fd (vlsh); - if (PREDICT_FALSE (fd < 0)) - { - errno = EBADFD; - rv = -1; - goto done; - } - FD_SET (fd, readfds); - })); - /* *INDENT-ON* */ - } - if (writefds) - { - /* *INDENT-OFF* */ - clib_bitmap_foreach (si, ldpw->wr_bitmap, ({ - vlsh = vls_session_index_to_vlsh (si); - fd = ldp_vlsh_to_fd (vlsh); - if (PREDICT_FALSE (fd < 0)) - { - errno = EBADFD; - rv = -1; - goto done; - } - FD_SET (fd, writefds); - })); - /* *INDENT-ON* */ - } - if (exceptfds) - { - /* *INDENT-OFF* */ - clib_bitmap_foreach (si, ldpw->ex_bitmap, ({ - vlsh = vls_session_index_to_vlsh (si); - fd = ldp_vlsh_to_fd (vlsh); - if (PREDICT_FALSE (fd < 0)) - { - errno = EBADFD; - rv = -1; - goto done; - } - FD_SET (fd, exceptfds); - })); - /* *INDENT-ON* */ - } - ldpw->select_vcl = 1; + rv = -1; + goto done; + } + + if (ldp_select_vcl_map_to_libc (ldpw->ex_bitmap, exceptfds)) + { + rv = -1; goto done; } + bits_set = rv; } - else - ldpw->select_vcl = 0; } if (libc_bits) { - struct timespec tspec; - if (readfds) - clib_memcpy_fast (readfds, ldpw->libc_rd_bitmap, - vec_len (ldpw->rd_bitmap) * + clib_memcpy_fast (ldpw->rd_bitmap, ldpw->libc_rd_bitmap, + vec_len (ldpw->libc_rd_bitmap) * sizeof (clib_bitmap_t)); if (writefds) - clib_memcpy_fast (writefds, ldpw->libc_wr_bitmap, - vec_len (ldpw->wr_bitmap) * + clib_memcpy_fast (ldpw->wr_bitmap, ldpw->libc_wr_bitmap, + vec_len (ldpw->libc_wr_bitmap) * sizeof (clib_bitmap_t)); if (exceptfds) - clib_memcpy_fast (exceptfds, ldpw->libc_ex_bitmap, - vec_len (ldpw->ex_bitmap) * + clib_memcpy_fast (ldpw->ex_bitmap, ldpw->libc_ex_bitmap, + vec_len (ldpw->libc_ex_bitmap) * sizeof (clib_bitmap_t)); - tspec.tv_sec = tspec.tv_nsec = 0; + rv = libc_pselect (libc_bits, - readfds ? readfds : NULL, - writefds ? writefds : NULL, - exceptfds ? exceptfds : NULL, &tspec, sigmask); - if (rv != 0) - goto done; + readfds ? (fd_set *) ldpw->rd_bitmap : NULL, + writefds ? (fd_set *) ldpw->wr_bitmap : NULL, + exceptfds ? (fd_set *) ldpw->ex_bitmap : NULL, + &libc_tspec, sigmask); + if (rv > 0) + { + ldp_select_libc_map_merge (ldpw->rd_bitmap, readfds); + ldp_select_libc_map_merge (ldpw->wr_bitmap, writefds); + ldp_select_libc_map_merge (ldpw->ex_bitmap, exceptfds); + bits_set += rv; + } + } + + if (bits_set) + { + rv = bits_set; + goto done; } } while ((time_out == -1) || (clib_time_now (&ldpw->clib_time) < time_out)); @@ -833,13 +863,13 @@ ldp_pselect (int nfds, fd_set * __restrict readfds, done: /* TBD: set timeout to amount of time left */ clib_bitmap_zero (ldpw->rd_bitmap); - clib_bitmap_zero (ldpw->sid_rd_bitmap); + clib_bitmap_zero (ldpw->si_rd_bitmap); clib_bitmap_zero (ldpw->libc_rd_bitmap); clib_bitmap_zero (ldpw->wr_bitmap); - clib_bitmap_zero (ldpw->sid_wr_bitmap); + clib_bitmap_zero (ldpw->si_wr_bitmap); clib_bitmap_zero (ldpw->libc_wr_bitmap); clib_bitmap_zero (ldpw->ex_bitmap); - clib_bitmap_zero (ldpw->sid_ex_bitmap); + clib_bitmap_zero (ldpw->si_ex_bitmap); clib_bitmap_zero (ldpw->libc_ex_bitmap); return rv; @@ -873,6 +903,74 @@ pselect (int nfds, fd_set * __restrict readfds, } #endif +/* If transparent TLS mode is turned on, then ldp will load key and cert. + */ +static int +load_cert_key_pair (void) +{ + char *cert_str = getenv (LDP_ENV_TLS_CERT); + char *key_str = getenv (LDP_ENV_TLS_KEY); + char cert_buf[4096], key_buf[4096]; + int cert_size, key_size; + vppcom_cert_key_pair_t crypto; + int ckp_index; + FILE *fp; + + if (!cert_str || !key_str) + { + LDBG (0, "ERROR: failed to read LDP environment %s\n", + LDP_ENV_TLS_CERT); + return -1; + } + + fp = fopen (cert_str, "r"); + if (fp == NULL) + { + LDBG (0, "ERROR: failed to open cert file %s \n", cert_str); + return -1; + } + cert_size = fread (cert_buf, sizeof (char), sizeof (cert_buf), fp); + fclose (fp); + + fp = fopen (key_str, "r"); + if (fp == NULL) + { + LDBG (0, "ERROR: failed to open key file %s \n", key_str); + return -1; + } + key_size = fread (key_buf, sizeof (char), sizeof (key_buf), fp); + fclose (fp); + + crypto.cert = cert_buf; + crypto.key = key_buf; + crypto.cert_len = cert_size; + crypto.key_len = key_size; + ckp_index = vppcom_add_cert_key_pair (&crypto); + if (ckp_index < 0) + { + LDBG (0, "ERROR: failed to add cert key pair\n"); + return -1; + } + + ldp->ckpair_index = ckp_index; + + return 0; +} + +static int +assign_cert_key_pair (vls_handle_t vlsh) +{ + uint32_t ckp_len; + + if (ldp->ckpair_index == ~0 && load_cert_key_pair () < 0) + return -1; + + ckp_len = sizeof (ldp->ckpair_index); + return vppcom_session_attr (vlsh_to_session_index (vlsh), + VPPCOM_ATTR_SET_CKPAIR, &ldp->ckpair_index, + &ckp_len); +} + int socket (int domain, int type, int protocol) { @@ -880,14 +978,19 @@ socket (int domain, int type, int protocol) u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0; vls_handle_t vlsh; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (((domain == AF_INET) || (domain == AF_INET6)) && ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM))) { - u8 proto = ((sock_type == SOCK_DGRAM) ? - VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP); + u8 proto; + if (ldp->transparent_tls) + { + proto = VPPCOM_PROTO_TLS; + } + else + proto = ((sock_type == SOCK_DGRAM) ? + VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP); LDBG (0, "calling vls_create: proto %u (%s), is_nonblocking %u", proto, vppcom_proto_str (proto), is_nonblocking); @@ -900,6 +1003,11 @@ socket (int domain, int type, int protocol) } else { + if (ldp->transparent_tls) + { + if (assign_cert_key_pair (vlsh) < 0) + return -1; + } rv = ldp_vlsh_to_fd (vlsh); } } @@ -924,8 +1032,7 @@ socketpair (int domain, int type, int protocol, int fds[2]) { int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK); - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (((domain == AF_INET) || (domain == AF_INET6)) && ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM))) @@ -949,8 +1056,7 @@ bind (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1023,8 +1129,7 @@ ldp_copy_ep_to_sockaddr (__SOCKADDR_ARG addr, socklen_t * __restrict len, int rv = 0; int sa_len, copy_len; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (addr && len && ep) { @@ -1068,8 +1173,7 @@ getsockname (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1110,8 +1214,7 @@ connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (!addr) { @@ -1192,8 +1295,7 @@ getpeername (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1233,8 +1335,7 @@ send (int fd, const void *buf, size_t n, int flags) vls_handle_t vlsh = ldp_fd_to_vlsh (fd); ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (vlsh != VLS_INVALID_HANDLE) { @@ -1260,8 +1361,7 @@ sendfile (int out_fd, int in_fd, off_t * offset, size_t len) vls_handle_t vlsh; ssize_t size = 0; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (out_fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1303,7 +1403,7 @@ sendfile (int out_fd, int in_fd, off_t * offset, size_t len) size = vls_attr (vlsh, VPPCOM_ATTR_GET_NWRITE, 0, 0); if (size < 0) { - LDBG (0, "ERROR: fd %d: vls_attr: vlsh %u returned %d (%s)!", + LDBG (0, "ERROR: fd %d: vls_attr: vlsh %u returned %ld (%s)!", out_fd, vlsh, size, vppcom_retval_str (size)); vec_reset_length (ldpw->io_buffer); errno = -size; @@ -1410,15 +1510,17 @@ recv (int fd, void *buf, size_t n, int flags) vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) { size = vls_recvfrom (vlsh, buf, n, flags, NULL); if (size < 0) - errno = -size; + { + errno = -size; + size = -1; + } } else { @@ -1428,6 +1530,69 @@ recv (int fd, void *buf, size_t n, int flags) return size; } +static int +ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n, int flags, + __CONST_SOCKADDR_ARG addr, socklen_t addr_len) +{ + vppcom_endpt_t *ep = 0; + vppcom_endpt_t _ep; + + if (addr) + { + ep = &_ep; + switch (addr->sa_family) + { + case AF_INET: + ep->is_ip4 = VPPCOM_IS_IP4; + ep->ip = + (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr; + ep->port = (uint16_t) ((const struct sockaddr_in *) addr)->sin_port; + break; + + case AF_INET6: + ep->is_ip4 = VPPCOM_IS_IP6; + ep->ip = + (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr; + ep->port = + (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port; + break; + + default: + return EAFNOSUPPORT; + } + } + + return vls_sendto (vlsh, (void *) buf, n, flags, ep); +} + +static int +ldp_vls_recvfrom (vls_handle_t vlsh, void *__restrict buf, size_t n, + int flags, __SOCKADDR_ARG addr, + socklen_t * __restrict addr_len) +{ + u8 src_addr[sizeof (struct sockaddr_in6)]; + vppcom_endpt_t ep; + ssize_t size; + int rv; + + if (addr) + { + ep.ip = src_addr; + size = vls_recvfrom (vlsh, buf, n, flags, &ep); + + if (size > 0) + { + rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep); + if (rv < 0) + size = rv; + } + } + else + size = vls_recvfrom (vlsh, buf, n, flags, NULL); + + return size; +} + ssize_t sendto (int fd, const void *buf, size_t n, int flags, __CONST_SOCKADDR_ARG addr, socklen_t addr_len) @@ -1435,44 +1600,12 @@ sendto (int fd, const void *buf, size_t n, int flags, vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != INVALID_SESSION_ID) { - vppcom_endpt_t *ep = 0; - vppcom_endpt_t _ep; - - if (addr) - { - ep = &_ep; - switch (addr->sa_family) - { - case AF_INET: - ep->is_ip4 = VPPCOM_IS_IP4; - ep->ip = - (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr; - ep->port = - (uint16_t) ((const struct sockaddr_in *) addr)->sin_port; - break; - - case AF_INET6: - ep->is_ip4 = VPPCOM_IS_IP6; - ep->ip = - (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr; - ep->port = - (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port; - break; - - default: - errno = EAFNOSUPPORT; - size = -1; - goto done; - } - } - - size = vls_sendto (vlsh, (void *) buf, n, flags, ep); + size = ldp_vls_sendo (vlsh, buf, n, flags, addr, addr_len); if (size < 0) { errno = -size; @@ -1484,7 +1617,6 @@ sendto (int fd, const void *buf, size_t n, int flags, size = libc_sendto (fd, buf, n, flags, addr, addr_len); } -done: return size; } @@ -1492,29 +1624,15 @@ ssize_t recvfrom (int fd, void *__restrict buf, size_t n, int flags, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len) { - vls_handle_t sid; + vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); - sid = ldp_fd_to_vlsh (fd); - if (sid != VLS_INVALID_HANDLE) + vlsh = ldp_fd_to_vlsh (fd); + if (vlsh != VLS_INVALID_HANDLE) { - vppcom_endpt_t ep; - u8 src_addr[sizeof (struct sockaddr_in6)]; - - if (addr) - { - ep.ip = src_addr; - size = vls_recvfrom (sid, buf, n, flags, &ep); - - if (size > 0) - size = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep); - } - else - size = vls_recvfrom (sid, buf, n, flags, NULL); - + size = ldp_vls_recvfrom (vlsh, buf, n, flags, addr, addr_len); if (size < 0) { errno = -size; @@ -1530,24 +1648,45 @@ recvfrom (int fd, void *__restrict buf, size_t n, int flags, } ssize_t -sendmsg (int fd, const struct msghdr * message, int flags) +sendmsg (int fd, const struct msghdr * msg, int flags) { vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) { - LDBG (0, "LDP-TBD"); - errno = ENOSYS; - size = -1; + struct iovec *iov = msg->msg_iov; + ssize_t total = 0; + int i, rv; + + for (i = 0; i < msg->msg_iovlen; ++i) + { + rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, flags, + msg->msg_name, msg->msg_namelen); + if (rv < 0) + break; + else + { + total += rv; + if (rv < iov[i].iov_len) + break; + } + } + + if (rv < 0 && total == 0) + { + errno = -rv; + size = -1; + } + else + size = total; } else { - size = libc_sendmsg (fd, message, flags); + size = libc_sendmsg (fd, msg, flags); } return size; @@ -1561,8 +1700,7 @@ sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) const char *func_str; u32 sh = ldp_fd_to_vlsh (fd); - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (sh != INVALID_SESSION_ID) { @@ -1602,24 +1740,52 @@ sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) #endif ssize_t -recvmsg (int fd, struct msghdr * message, int flags) +recvmsg (int fd, struct msghdr * msg, int flags) { vls_handle_t vlsh; ssize_t size; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) { - LDBG (0, "LDP-TBD"); - errno = ENOSYS; - size = -1; + struct iovec *iov = msg->msg_iov; + ssize_t max_deq, total = 0; + int i, rv; + + max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0); + if (!max_deq) + return 0; + + for (i = 0; i < msg->msg_iovlen; i++) + { + rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags, + (i == 0 ? msg->msg_name : NULL), + (i == 0 ? &msg->msg_namelen : NULL)); + if (rv <= 0) + break; + else + { + total += rv; + if (rv < iov[i].iov_len) + break; + } + if (total >= max_deq) + break; + } + + if (rv < 0 && total == 0) + { + errno = -rv; + size = -1; + } + else + size = total; } else { - size = libc_recvmsg (fd, message, flags); + size = libc_recvmsg (fd, msg, flags); } return size; @@ -1634,8 +1800,7 @@ recvmmsg (int fd, struct mmsghdr *vmessages, const char *func_str; u32 sh = ldp_fd_to_vlsh (fd); - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (sh != INVALID_SESSION_ID) { @@ -1682,8 +1847,7 @@ getsockopt (int fd, int level, int optname, vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1722,6 +1886,11 @@ getsockopt (int fd, int level, int optname, else rv = -EFAULT; break; + case TCP_CONGESTION: + *optlen = strlen ("cubic"); + strncpy (optval, "cubic", *optlen + 1); + rv = 0; + break; default: LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, " "optname %d unsupported!", fd, vlsh, optname); @@ -1764,9 +1933,15 @@ getsockopt (int fd, int level, int optname, case SO_REUSEADDR: rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen); break; + case SO_REUSEPORT: + rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen); + break; case SO_BROADCAST: rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen); break; + case SO_DOMAIN: + rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen); + break; case SO_ERROR: rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen); break; @@ -1801,8 +1976,7 @@ setsockopt (int fd, int level, int optname, vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1830,6 +2004,11 @@ setsockopt (int fd, int level, int optname, rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL, (void *) optval, &optlen); break; + case TCP_CONGESTION: + case TCP_CORK: + /* Ignore */ + rv = 0; + break; default: LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u" "optname %d unsupported!", fd, vlsh, optname); @@ -1860,10 +2039,17 @@ setsockopt (int fd, int level, int optname, rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR, (void *) optval, &optlen); break; + case SO_REUSEPORT: + rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval, + &optlen); + break; case SO_BROADCAST: rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST, (void *) optval, &optlen); break; + case SO_LINGER: + rv = 0; + break; default: LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u " "optname %d unsupported!", fd, vlsh, optname); @@ -1894,8 +2080,7 @@ listen (int fd, int n) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -1926,8 +2111,7 @@ ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr, vls_handle_t listen_vlsh, accept_vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); listen_vlsh = ldp_fd_to_vlsh (listen_fd); if (listen_vlsh != VLS_INVALID_HANDLE) @@ -1938,7 +2122,7 @@ ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr, ep.ip = src_addr; LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u," - " ep %p, flags 0x%x", listen_fd, listen_vlsh, ep, flags); + " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags); accept_vlsh = vls_accept (listen_vlsh, &ep, flags); if (accept_vlsh < 0) @@ -1994,8 +2178,7 @@ shutdown (int fd, int how) int rv = 0, flags; u32 flags_len = sizeof (flags); - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vlsh = ldp_fd_to_vlsh (fd); if (vlsh != VLS_INVALID_HANDLE) @@ -2016,6 +2199,8 @@ shutdown (int fd, int how) if (flags == SHUT_RDWR) rv = close (fd); + else if (flags == SHUT_WR) + rv = vls_shutdown (vlsh); } else { @@ -2033,11 +2218,16 @@ epoll_create1 (int flags) vls_handle_t vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); - if (ldp->vcl_needs_real_epoll) + if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ()) { + /* Make sure workers have been allocated */ + if (!ldp->workers) + { + ldp_alloc_workers (); + ldpw = ldp_worker_get_current (); + } rv = libc_epoll_create1 (flags); ldp->vcl_needs_real_epoll = 0; ldpw->vcl_mq_epfd = rv; @@ -2071,8 +2261,7 @@ epoll_ctl (int epfd, int op, int fd, struct epoll_event *event) vls_handle_t vep_vlsh, vlsh; int rv; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); vep_vlsh = ldp_fd_to_vlsh (epfd); if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE)) @@ -2097,7 +2286,7 @@ epoll_ctl (int epfd, int op, int fd, struct epoll_event *event) if (vlsh != VLS_INVALID_HANDLE) { LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u," - " event %p", epfd, vep_vlsh, vlsh, event); + " event %p", epfd, vep_vlsh, op, vlsh, event); rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event); if (rv != VPPCOM_OK) @@ -2155,12 +2344,11 @@ ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t * sigmask) { ldp_worker_ctx_t *ldpw = ldp_worker_get_current (); - double time_to_wait = (double) 0, time_out, now = 0; + double time_to_wait = (double) 0, max_time; int libc_epfd, rv = 0; vls_handle_t ep_vlsh; - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); if (PREDICT_FALSE (!events || (timeout < -1))) { @@ -2179,8 +2367,10 @@ ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents, return -1; } + if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0)) + clib_time_init (&ldpw->clib_time); time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0); - time_out = clib_time_now (&ldpw->clib_time) + time_to_wait; + max_time = clib_time_now (&ldpw->clib_time) + time_to_wait; libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0); if (PREDICT_FALSE (libc_epfd < 0)) @@ -2192,8 +2382,7 @@ ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents, LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, " "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh, - libc_epfd, events, maxevents, timeout, sigmask, time_to_wait, - time_out); + libc_epfd, events, maxevents, timeout, sigmask, time_to_wait); do { if (!ldpw->epoll_wait_vcl) @@ -2220,11 +2409,122 @@ ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents, if (rv != 0) goto done; } + } + while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time)); - if (timeout != -1) - now = clib_time_now (&ldpw->clib_time); +done: + return rv; +} + +static inline int +ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events, + int maxevents, int timeout, const sigset_t * sigmask) +{ + ldp_worker_ctx_t *ldpw; + int libc_epfd, rv = 0, num_ev; + vls_handle_t ep_vlsh; + + ldp_init_check (); + + if (PREDICT_FALSE (!events || (timeout < -1))) + { + errno = EFAULT; + return -1; + } + + /* Make sure the vcl worker is valid. Could be that epoll fd was created on + * one thread but it is now used on another */ + if (PREDICT_FALSE (vppcom_worker_index () == ~0)) + vls_register_vcl_worker (); + + ldpw = ldp_worker_get_current (); + if (epfd == ldpw->vcl_mq_epfd) + return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask); + + ep_vlsh = ldp_fd_to_vlsh (epfd); + if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE)) + { + LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh); + errno = EBADFD; + return -1; + } + + libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0); + if (PREDICT_FALSE (!libc_epfd)) + { + u32 size = sizeof (epfd); + + LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: " + "EPOLL_CLOEXEC", epfd, ep_vlsh); + libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC); + if (libc_epfd < 0) + { + rv = libc_epfd; + goto done; + } + + rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size); + if (rv < 0) + { + errno = -rv; + rv = -1; + goto done; + } + } + if (PREDICT_FALSE (libc_epfd <= 0)) + { + errno = -libc_epfd; + rv = -1; + goto done; + } + + if (PREDICT_FALSE (!ldpw->mq_epfd_added)) + { + struct epoll_event e = { 0 }; + e.events = EPOLLIN; + e.data.fd = ldpw->vcl_mq_epfd; + if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) < + 0) + { + LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d", + epfd, ldpw->vcl_mq_epfd, libc_epfd); + rv = -1; + goto done; + } + ldpw->mq_epfd_added = 1; + } + + /* Request to only drain unhandled to prevent libc_epoll_wait starved */ + rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2); + if (rv > 0) + goto done; + else if (PREDICT_FALSE (rv < 0)) + { + errno = -rv; + rv = -1; + goto done; + } + + rv = libc_epoll_pwait (libc_epfd, events, maxevents, timeout, sigmask); + if (rv <= 0) + goto done; + for (int i = 0; i < rv; i++) + { + if (events[i].data.fd == ldpw->vcl_mq_epfd) + { + /* We should remove mq epoll fd from events. */ + rv--; + if (i != rv) + { + events[i].events = events[rv].events; + events[i].data.u64 = events[rv].data.u64; + } + num_ev = vls_epoll_wait (ep_vlsh, &events[rv], maxevents - rv, 0); + if (PREDICT_TRUE (num_ev > 0)) + rv += num_ev; + break; + } } - while (now < time_out); done: return rv; @@ -2234,13 +2534,20 @@ int epoll_pwait (int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t * sigmask) { - return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask); + if (vls_use_eventfd ()) + return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, + sigmask); + else + return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask); } int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout) { - return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL); + if (vls_use_eventfd ()) + return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL); + else + return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL); } int @@ -2250,14 +2557,15 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout) int rv, i, n_revents = 0; vls_handle_t vlsh; vcl_poll_t *vp; - double wait_for_time; + double max_time; - LDBG (3, "fds %p, nfds %d, timeout %d", fds, nfds, timeout); + LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout); - if (timeout >= 0) - wait_for_time = (f64) timeout / 1000; - else - wait_for_time = -1; + if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0)) + clib_time_init (&ldpw->clib_time); + + max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0; + max_time += clib_time_now (&ldpw->clib_time); for (i = 0; i < nfds; i++) { @@ -2317,8 +2625,7 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout) goto done; } } - while ((wait_for_time == -1) || - (clib_time_now (&ldpw->clib_time) < wait_for_time)); + while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time)); rv = 0; done: @@ -2352,8 +2659,7 @@ int ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t * sigmask) { - if ((errno = -ldp_init ())) - return -1; + ldp_init_check (); clib_warning ("LDP<%d>: LDP-TBD", getpid ()); errno = ENOSYS; @@ -2375,8 +2681,11 @@ ldp_constructor (void) { swrap_constructor (); if (ldp_init () != 0) - fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n", - getpid ()); + { + fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n", + getpid ()); + _exit (1); + } else if (LDP_DEBUG > 0) clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ()); } @@ -2387,16 +2696,18 @@ ldp_constructor (void) void ldp_destructor (void) { - swrap_destructor (); - if (ldp->init) - ldp->init = 0; + /* + swrap_destructor (); + if (ldp->init) + ldp->init = 0; + */ /* Don't use clib_warning() here because that calls writev() * which will call ldp_init(). */ if (LDP_DEBUG > 0) - printf ("%s:%d: LDP<%d>: LDP destructor: done!\n", - __func__, __LINE__, getpid ()); + fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n", + __func__, __LINE__, getpid ()); }