aboutsummaryrefslogtreecommitdiffstats
path: root/vpp_patches/vcl/0001-ngxvcl-api.patch
diff options
context:
space:
mode:
authorXiaolong Jiang <xiaolongx.jiang@intel.com>2020-09-23 09:29:24 +0800
committerXiaolong Jiang <xiaolongx.jiang@intel.com>2020-11-03 14:53:04 +0800
commit26f546256d5f9c981224b30f6b9988941d76d018 (patch)
tree65623bab67a135bc3f50d8406c1e4725bdc128e0 /vpp_patches/vcl/0001-ngxvcl-api.patch
parent20e5bc31904d25e44cda5ef675d4ab1e86795bdb (diff)
modify vcl patch and remove ldp-lock patch
Signed-off-by: Xiaolong Jiang <xiaolongx.jiang@intel.com> Change-Id: I4fe5f4dc2121d952bd0a4394afe0b18ce6f93516
Diffstat (limited to 'vpp_patches/vcl/0001-ngxvcl-api.patch')
-rw-r--r--vpp_patches/vcl/0001-ngxvcl-api.patch1713
1 files changed, 0 insertions, 1713 deletions
diff --git a/vpp_patches/vcl/0001-ngxvcl-api.patch b/vpp_patches/vcl/0001-ngxvcl-api.patch
deleted file mode 100644
index f294b36..0000000
--- a/vpp_patches/vcl/0001-ngxvcl-api.patch
+++ /dev/null
@@ -1,1713 +0,0 @@
-From 1c07c530f6308362f32c686a571a577380a1b7d8 Mon Sep 17 00:00:00 2001
-From: Zeyu Zhang <zeyu.zhang@intel.com>
-Date: Wed, 16 Oct 2019 16:51:22 +0800
-Subject: [PATCH] ngxvcl
-
----
- src/vcl/CMakeLists.txt | 10 +-
- src/vcl/ngxvcl.c | 1590 ++++++++++++++++++++++++++++++++++++++++
- src/vcl/ngxvcl.h | 70 ++
- 3 files changed, 1669 insertions(+), 1 deletion(-)
- create mode 100644 src/vcl/ngxvcl.c
- create mode 100644 src/vcl/ngxvcl.h
-
-diff --git a/src/vcl/CMakeLists.txt b/src/vcl/CMakeLists.txt
-index ab0a6ad6a..1b6a9f351 100644
---- a/src/vcl/CMakeLists.txt
-+++ b/src/vcl/CMakeLists.txt
-@@ -38,10 +38,18 @@ add_vpp_library(vcl_ldpreload
- vppinfra svm vlibmemoryclient rt pthread vppcom dl
- )
-
-+add_vpp_library(ngxvcl
-+ SOURCES
-+ ngxvcl.c
-+
-+ LINK_LIBRARIES
-+ vppinfra svm vlibmemoryclient rt pthread vppcom dl
-+)
-+
- add_vpp_headers(vcl
- ldp.h
- ldp_glibc_socket.h
- vppcom.h
- vcl_locked.h
- ldp_socket_wrapper.h
--)
-\ No newline at end of file
-+)
-diff --git a/src/vcl/ngxvcl.c b/src/vcl/ngxvcl.c
-new file mode 100644
-index 000000000..157c05246
---- /dev/null
-+++ b/src/vcl/ngxvcl.c
-@@ -0,0 +1,1590 @@
-+#include <vcl/ngxvcl.h>
-+#include <vcl/vcl_private.h>
-+
-+#define MAX_NGX_WORKERS 100
-+#define VFD_OFFSET 0X003F3F3F
-+#define NGXVCL_TLS_ON "NGXVCL_TLS_ON"
-+#define NGXVCL_TLS_CERT "NGXVCL_TLS_CERT"
-+#define NGXVCL_TLS_KEY "NGXVCL_TLS_KEY"
-+
-+typedef unsigned char u8;
-+typedef unsigned short u16;
-+typedef unsigned int u32;
-+
-+typedef struct ngxvcl_main_t_
-+{
-+ u32 listen_session_index;
-+ u32 master_worker_index;
-+ /** Not include master worker index. */
-+ u32 *workers_subscribed_by_ls;
-+ clib_bitmap_t *listeners;
-+ uword *worker_index_by_pid;
-+ int wait_vep_only;
-+ int intercepted_sigchld;
-+ u8 transparent_tls;
-+} ngxvcl_main_t;
-+
-+static ngxvcl_main_t *nvm = NULL;
-+
-+static u8 *sendfile_io_buffer = NULL;
-+
-+static int epoll_fd_for_evtfd = 0;
-+
-+static u8 use_mq_eventfd = 0;
-+
-+static int wait_kep_next = 0;
-+
-+static inline _Bool is_offset_vfd(int fd)
-+{
-+ return fd >= VFD_OFFSET;
-+}
-+static inline int vfd_to_offset_vfd(int vfd)
-+{
-+ return vfd + VFD_OFFSET;
-+}
-+static inline int offset_vfd_to_vfd(int offset_fd)
-+{
-+ int vfd = offset_fd - VFD_OFFSET;
-+
-+ return (vcl_get_worker_index () << 24) | (vfd & 0X00FFFFFF);
-+}
-+
-+static int copy_ep_to_sockaddr(struct sockaddr *addr, socklen_t *len,
-+ vppcom_endpt_t *ep)
-+{
-+ int rv = 0;
-+ int sa_len, copy_len;
-+
-+ if (addr && len && ep)
-+ {
-+ addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
-+
-+ switch (addr->sa_family)
-+ {
-+ case AF_INET:
-+ ((struct sockaddr_in *)addr)->sin_port = ep->port;
-+ if (*len > sizeof(struct sockaddr_in))
-+ *len = sizeof(struct sockaddr_in);
-+ sa_len = sizeof(struct sockaddr_in) - sizeof(struct in_addr);
-+ copy_len = *len - sa_len;
-+ if (copy_len > 0)
-+ memcpy(&((struct sockaddr_in *)addr)->sin_addr, ep->ip,
-+ copy_len);
-+ break;
-+
-+ case AF_INET6:
-+ ((struct sockaddr_in6 *)addr)->sin6_port = ep->port;
-+ if (*len > sizeof(struct sockaddr_in6))
-+ *len = sizeof(struct sockaddr_in6);
-+ sa_len = sizeof(struct sockaddr_in6) - sizeof(struct in6_addr);
-+ copy_len = *len - sa_len;
-+ if (copy_len > 0)
-+ memcpy(
-+ ((struct sockaddr_in6 *)addr)->sin6_addr.__in6_u.__u6_addr8,
-+ ep->ip, copy_len);
-+ break;
-+
-+ default:
-+ /* Not possible */
-+ rv = -EAFNOSUPPORT;
-+ break;
-+ }
-+ }
-+
-+ return rv;
-+}
-+
-+static void listener_wrk_stop_listen(u32 wrk_index) {
-+ vcl_worker_t *wrk;
-+ vcl_session_t *s;
-+
-+ wrk = vcl_worker_get(wrk_index);
-+ s = vcl_session_get (wrk, nvm->listen_session_index);
-+ if (s->session_state != STATE_LISTEN)
-+ return;
-+ vcl_send_session_unlisten(wrk, s);
-+ s->session_state = STATE_LISTEN_NO_MQ;
-+ clib_bitmap_set(nvm->listeners, wrk_index, 0);
-+}
-+
-+static void
-+share_listen_session (vcl_worker_t * wrk)
-+{
-+ vcl_session_t *s;
-+
-+ s = vcl_session_get (wrk, nvm->listen_session_index);
-+ s->session_state = STATE_LISTEN_NO_MQ;
-+ vppcom_session_listen((vcl_get_worker_index() << 24 | nvm->listen_session_index), ~0);
-+ clib_bitmap_set(nvm->listeners, vcl_get_worker_index(), 1);
-+ if (clib_bitmap_get(nvm->listeners, 0) == 1)
-+ listener_wrk_stop_listen (0);
-+ vec_add1 (nvm->workers_subscribed_by_ls, wrk->wrk_index);
-+}
-+
-+static void
-+worker_copy_on_fork (vcl_worker_t * parent_wrk)
-+{
-+ vcl_worker_t *wrk = vcl_worker_get_current ();
-+
-+ wrk->vpp_event_queues = vec_dup (parent_wrk->vpp_event_queues);
-+ wrk->sessions = pool_dup (parent_wrk->sessions);
-+ wrk->session_index_by_vpp_handles =
-+ hash_dup (parent_wrk->session_index_by_vpp_handles);
-+
-+ share_listen_session (wrk);
-+}
-+
-+static void
-+ngxvcl_cleanup_child_worker (u32 child_wrk_index)
-+{
-+ vcl_worker_t *child_wrk = vcl_worker_get(child_wrk_index);
-+ vcl_session_t *s;
-+
-+ /** Unshare listen session. */
-+ s = vcl_session_get (child_wrk, nvm->listen_session_index);
-+ clib_bitmap_set (nvm->listeners, child_wrk_index, 0);
-+ vec_del1 (nvm->workers_subscribed_by_ls, child_wrk_index);
-+ vcl_session_cleanup (child_wrk, s, vcl_session_handle (s), 1);
-+
-+ hash_unset (nvm->worker_index_by_pid, child_wrk->current_pid);
-+ vcl_worker_cleanup (child_wrk, 1 /* notify vpp */);
-+}
-+
-+static struct sigaction old_sa;
-+
-+static void
-+ngxvcl_intercept_sigchld_handler (int signum, siginfo_t * si, void *uc)
-+{
-+ vcl_worker_t *wrk;
-+ u32 child_wrk_index;
-+
-+ if (vcl_get_worker_index () == ~0)
-+ return;
-+
-+ if (sigaction (SIGCHLD, &old_sa, 0))
-+ {
-+ VERR ("couldn't restore sigchld");
-+ exit (-1);
-+ }
-+
-+ wrk = vcl_worker_get_current ();
-+ child_wrk_index = *(hash_get (nvm->worker_index_by_pid, si->si_pid));
-+
-+ if (si->si_pid != vcl_worker_get(child_wrk_index)->current_pid)
-+ {
-+ VDBG (0, "unexpected child pid %u", si->si_pid);
-+ goto done;
-+ }
-+
-+ ngxvcl_cleanup_child_worker (child_wrk_index);
-+ wrk->forked_child = ~0;
-+
-+done:
-+ if (old_sa.sa_flags & SA_SIGINFO)
-+ {
-+ void (*fn) (int, siginfo_t *, void *) = old_sa.sa_sigaction;
-+ fn (signum, si, uc);
-+ }
-+ else
-+ {
-+ void (*fn) (int) = old_sa.sa_handler;
-+ if (fn)
-+ fn (signum);
-+ }
-+}
-+
-+static void
-+ngxvcl_incercept_sigchld ()
-+{
-+ if (!nvm->intercepted_sigchld)
-+ {
-+ struct sigaction sa;
-+ clib_memset (&sa, 0, sizeof (sa));
-+ sa.sa_sigaction = ngxvcl_intercept_sigchld_handler;
-+ sa.sa_flags = SA_SIGINFO;
-+ if (sigaction (SIGCHLD, &sa, &old_sa))
-+ {
-+ VERR ("couldn't intercept sigchld");
-+ exit (-1);
-+ }
-+ nvm->intercepted_sigchld = 1;
-+ }
-+}
-+
-+static void
-+app_pre_fork (void)
-+{
-+ ngxvcl_incercept_sigchld ();
-+ vcl_flush_mq_events ();
-+}
-+
-+static void
-+app_fork_parent_handler (void)
-+{
-+ vcm->forking = 1;
-+ while (vcm->forking)
-+ ;
-+}
-+
-+static void
-+app_fork_child_handler (void)
-+{
-+ vcl_worker_t *parent_wrk;
-+ int rv, parent_wrk_index;
-+ u8 *child_name;
-+
-+ parent_wrk_index = vcl_get_worker_index ();
-+ VDBG (0, "initializing forked child %u with parent wrk %u", getpid (),
-+ parent_wrk_index);
-+
-+ /*
-+ * Allocate worker
-+ */
-+ vcl_set_worker_index (~0);
-+ if (!vcl_worker_alloc_and_init ())
-+ VERR ("couldn't allocate new worker");
-+
-+ /*
-+ * Attach to binary api
-+ */
-+ child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0);
-+ vcl_cleanup_bapi ();
-+ vppcom_api_hookup ();
-+ vcm->app_state = STATE_APP_START;
-+ rv = vppcom_connect_to_vpp ((char *) child_name);
-+ vec_free (child_name);
-+ if (rv)
-+ {
-+ VERR ("couldn't connect to VPP!");
-+ return;
-+ }
-+
-+ /*
-+ * Register worker with vpp and share listen session
-+ */
-+ vcl_worker_register_with_vpp ();
-+ parent_wrk = vcl_worker_get (parent_wrk_index);
-+ worker_copy_on_fork (parent_wrk);
-+ hash_set(nvm->worker_index_by_pid, getpid(), vcl_get_worker_index());
-+ parent_wrk->forked_child = vcl_get_worker_index ();
-+
-+ sendfile_io_buffer = NULL;
-+
-+ VDBG (0, "forked child main worker initialized");
-+ vcm->forking = 0;
-+}
-+
-+static void
-+sendfile_io_buffer_free (void)
-+{
-+ vec_free (sendfile_io_buffer);
-+}
-+
-+void ngxvcl_wait_vep_only()
-+{
-+ if (use_mq_eventfd)
-+ return;
-+ nvm->wait_vep_only = 1;
-+}
-+
-+void ngxvcl_wait_kep_and_vep()
-+{
-+ if (use_mq_eventfd)
-+ return;
-+ nvm->wait_vep_only = 0;
-+}
-+
-+void ngxvcl_app_create(char *app_name)
-+{
-+ int rv = vppcom_app_create(app_name);
-+
-+ if (rv)
-+ {
-+ errno = -rv;
-+ perror("ERROR when calling ngxvcl_app_create()!");
-+ fprintf(stderr, "\nERROR: ngxvcl_app_create() failed (errno = %d)!\n", -rv);
-+ exit(1);
-+ }
-+
-+ pthread_atfork(app_pre_fork, app_fork_parent_handler,
-+ app_fork_child_handler);
-+ atexit(sendfile_io_buffer_free);
-+
-+ nvm = clib_mem_alloc (sizeof (ngxvcl_main_t));
-+ if (!nvm)
-+ {
-+ clib_warning ("NgxVCL<%d>: ERROR: clib_mem_alloc() failed!", getpid ());
-+ ASSERT (nvm);
-+ return;
-+ }
-+ clib_memset(nvm, 0, sizeof(ngxvcl_main_t));
-+ clib_bitmap_validate(nvm->listeners, MAX_NGX_WORKERS + 1);
-+ clib_bitmap_set(nvm->listeners, vcl_get_worker_index(), 1);
-+ hash_set(nvm->worker_index_by_pid, getpid(), vcl_get_worker_index());
-+
-+ if (getenv (NGXVCL_TLS_ON))
-+ nvm->transparent_tls = 1;
-+
-+ use_mq_eventfd = vcm->cfg.use_mq_eventfd;
-+}
-+
-+void ngxvcl_app_destroy(void)
-+{
-+ vec_free(nvm->workers_subscribed_by_ls);
-+ clib_bitmap_free(nvm->listeners);
-+ hash_free(nvm->worker_index_by_pid);
-+ clib_mem_free(nvm);
-+ vppcom_app_destroy();
-+}
-+
-+static int
-+ngxvcl_load_tls_cert (uint32_t sh)
-+{
-+ char *env_var_str = getenv (NGXVCL_TLS_CERT);
-+ char inbuf[4096];
-+ char *tls_cert;
-+ int cert_size;
-+ FILE *fp;
-+
-+ if (env_var_str)
-+ {
-+ fp = fopen (env_var_str, "r");
-+ if (fp == NULL)
-+ {
-+ VDBG (0, "ERROR: failed to open cert file %s \n", env_var_str);
-+ return -1;
-+ }
-+ cert_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
-+ tls_cert = inbuf;
-+ vppcom_session_tls_add_cert (sh, tls_cert,
-+ cert_size);
-+ fclose (fp);
-+ }
-+ else
-+ {
-+ VDBG (0, "ERROR: failed to read LDP environment %s\n",
-+ NGXVCL_TLS_CERT);
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static int
-+ngxvcl_load_tls_key (uint32_t sh)
-+{
-+ char *env_var_str = getenv (NGXVCL_TLS_KEY);
-+ char inbuf[4096];
-+ char *tls_key;
-+ int key_size;
-+ FILE *fp;
-+
-+ if (env_var_str)
-+ {
-+ fp = fopen (env_var_str, "r");
-+ if (fp == NULL)
-+ {
-+ VDBG (0, "ERROR: failed to open key file %s \n", env_var_str);
-+ return -1;
-+ }
-+ key_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
-+ tls_key = inbuf;
-+ vppcom_session_tls_add_key (sh, tls_key,
-+ key_size);
-+ fclose (fp);
-+ }
-+ else
-+ {
-+ VDBG (0, "ERROR: failed to read NGXVCL environment %s\n", NGXVCL_TLS_KEY);
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+int ngxvcl_socket(int domain, int type, int protocol)
-+{
-+ int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
-+ u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0;
-+
-+ if (((domain == AF_INET) || (domain == AF_INET6)) &&
-+ ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
-+ {
-+ u8 proto;
-+
-+ if (nvm->transparent_tls)
-+ proto = VPPCOM_PROTO_TLS;
-+ else
-+ proto = ((sock_type == SOCK_DGRAM) ? VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
-+
-+ rv = vppcom_session_create(proto, is_nonblocking);
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ else {
-+ if (nvm->transparent_tls)
-+ if (ngxvcl_load_tls_cert (rv) < 0 || ngxvcl_load_tls_key (rv) < 0)
-+ return -1;
-+
-+ rv = vfd_to_offset_vfd(rv);
-+ }
-+ }
-+ else
-+ {
-+ rv = -1;
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_close(int offset_vfd)
-+{
-+ int rv, epfd, vfd = offset_vfd_to_vfd(offset_vfd);
-+
-+ epfd = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
-+ if (epfd > 0) {
-+ rv = close(epfd);
-+ if (rv < 0) {
-+ u32 size = sizeof(epfd);
-+ epfd = 0;
-+ vppcom_session_attr(vfd, VPPCOM_ATTR_SET_LIBC_EPFD, &epfd, &size);
-+ }
-+ }
-+ else if (epfd < 0) {
-+ errno = -epfd;
-+ rv = -1;
-+ return rv;
-+ }
-+
-+ rv = vppcom_session_close(offset_vfd_to_vfd(offset_vfd));
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_close(int fd)
-+{
-+ int rv;
-+
-+ if (is_offset_vfd(fd))
-+ rv = ngxvcl_close(fd);
-+ else
-+ rv = close(fd);
-+
-+ return rv;
-+}
-+
-+int ngxvcl_bind(int offset_vfd, const struct sockaddr *addr, socklen_t addrlen)
-+{
-+ int rv;
-+ vppcom_endpt_t ep;
-+
-+ switch (addr->sa_family)
-+ {
-+ case AF_INET:
-+ if (addrlen != sizeof(struct sockaddr_in))
-+ {
-+ errno = EINVAL;
-+ rv = -1;
-+ goto done;
-+ }
-+ ep.is_ip4 = VPPCOM_IS_IP4;
-+ ep.ip = (u8 *)&((const struct sockaddr_in *)addr)->sin_addr;
-+ ep.port = (u16)((const struct sockaddr_in *)addr)->sin_port;
-+ break;
-+ case AF_INET6:
-+ if (addrlen != sizeof(struct sockaddr_in6))
-+ {
-+ errno = EINVAL;
-+ rv = -1;
-+ goto done;
-+ }
-+ ep.is_ip4 = VPPCOM_IS_IP6;
-+ ep.ip = (u8 *)&((const struct sockaddr_in6 *)addr)->sin6_addr;
-+ ep.port = (u16)((const struct sockaddr_in6 *)addr)->sin6_port;
-+ break;
-+ default:
-+ errno = EAFNOSUPPORT;
-+ rv = -1;
-+ goto done;
-+ }
-+
-+ rv = vppcom_session_bind(offset_vfd_to_vfd(offset_vfd), &ep);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ goto done;
-+ }
-+
-+ nvm->master_worker_index = offset_vfd_to_vfd(offset_vfd) >> 24;
-+ nvm->listen_session_index = offset_vfd_to_vfd(offset_vfd) & 0X00FFFFFF;
-+
-+done:
-+ return rv;
-+}
-+
-+int ngxvcl_listen(int offset_vfd, int backlog)
-+{
-+ int rv;
-+
-+ ASSERT((u32)(offset_vfd_to_vfd(offset_vfd) & 0X00FFFFFF) == nvm->listen_session_index);
-+
-+ rv = vppcom_session_listen(offset_vfd_to_vfd(offset_vfd), backlog);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_accept4(int offset_vfd, struct sockaddr *addr, socklen_t *addrlen,
-+ int flags)
-+{
-+ int accepted_fd, rv;
-+ vppcom_endpt_t ep;
-+ u8 src_addr[sizeof(struct sockaddr_in6)];
-+ memset(&ep, 0, sizeof(ep));
-+ ep.ip = src_addr;
-+
-+ accepted_fd = vppcom_session_accept(offset_vfd_to_vfd(offset_vfd), &ep, flags);
-+
-+ if (accepted_fd < 0)
-+ {
-+ errno = -accepted_fd;
-+ rv = -1;
-+ }
-+ else
-+ {
-+ rv = copy_ep_to_sockaddr(addr, addrlen, &ep);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ (void)vppcom_session_close(accepted_fd);
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ else
-+ {
-+ rv = vfd_to_offset_vfd(accepted_fd);
-+ }
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_accept(int offset_vfd, struct sockaddr *addr, socklen_t *addrlen)
-+{
-+ return ngxvcl_accept4(offset_vfd, addr, addrlen, 0);
-+}
-+
-+int ngxvcl_connect(int offset_vfd, const struct sockaddr *addr, socklen_t addrlen)
-+{
-+ int rv;
-+
-+ if (!addr)
-+ {
-+ errno = EINVAL;
-+ rv = -1;
-+ goto done;
-+ }
-+
-+ vppcom_endpt_t ep;
-+
-+ switch (addr->sa_family)
-+ {
-+ case AF_INET:
-+ if (addrlen != sizeof(struct sockaddr_in))
-+ {
-+ errno = EINVAL;
-+ rv = -1;
-+ goto done;
-+ }
-+ ep.is_ip4 = VPPCOM_IS_IP4;
-+ ep.ip = (u8 *)&((const struct sockaddr_in *)addr)->sin_addr;
-+ ep.port = (u16)((const struct sockaddr_in *)addr)->sin_port;
-+ break;
-+ case AF_INET6:
-+ if (addrlen != sizeof(struct sockaddr_in6))
-+ {
-+ errno = EINVAL;
-+ rv = -1;
-+ goto done;
-+ }
-+ ep.is_ip4 = VPPCOM_IS_IP6;
-+ ep.ip = (u8 *)&((const struct sockaddr_in6 *)addr)->sin6_addr;
-+ ep.port = (u16)((const struct sockaddr_in6 *)addr)->sin6_port;
-+ break;
-+ default:
-+ errno = EAFNOSUPPORT;
-+ rv = -1;
-+ goto done;
-+ }
-+
-+ rv = vppcom_session_connect(offset_vfd_to_vfd(offset_vfd), &ep);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+
-+done:
-+ return rv;
-+}
-+
-+int ngxvcl_read(int offset_vfd, void *buf, size_t count)
-+{
-+ ssize_t size;
-+
-+ size = vppcom_session_read(offset_vfd_to_vfd(offset_vfd), buf, count);
-+
-+ if (size < 0)
-+ {
-+ errno = -size;
-+ size = -1;
-+ }
-+
-+ return size;
-+}
-+
-+int ngxvcl_write(int offset_vfd, const void *buf, size_t count)
-+{
-+ ssize_t size = 0;
-+
-+ size = vppcom_session_write_msg(offset_vfd_to_vfd(offset_vfd), (void *)buf, count);
-+
-+ if (size < 0)
-+ {
-+ errno = -size;
-+ size = -1;
-+ }
-+
-+ return size;
-+}
-+
-+int ngxvcl_epoll_create(int size)
-+{
-+ int rv, vepfd;
-+
-+ rv = vppcom_epoll_create();
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ return -1;
-+ }
-+ else
-+ vepfd = rv;
-+
-+ if (use_mq_eventfd) {
-+ int libc_epfd;
-+ u32 size = sizeof (u32);
-+ struct epoll_event e = { 0 };
-+
-+ libc_epfd = epoll_create1 (EPOLL_CLOEXEC);
-+ if (libc_epfd < 0)
-+ return libc_epfd;
-+ rv = vppcom_session_attr (vepfd, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ return -1;
-+ }
-+ e.events = EPOLLIN;
-+ if (epoll_ctl (libc_epfd, EPOLL_CTL_ADD, vcl_worker_get_current ()->app_event_queue->q->consumer_evtfd, &e) < 0)
-+ return -1;
-+ epoll_fd_for_evtfd = libc_epfd;
-+ }
-+
-+ return vfd_to_offset_vfd (vepfd);
-+}
-+
-+int ngxvcl_kvfd_epoll_ctl(int offset_vepfd, int op, int fd, struct epoll_event *event)
-+{
-+ int rv, vepfd = offset_vfd_to_vfd(offset_vepfd);
-+
-+ if (is_offset_vfd(fd)) {
-+ rv = vppcom_epoll_ctl(vepfd, op, offset_vfd_to_vfd(fd),
-+ event);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ else {
-+ int libc_epfd;
-+ u32 size = sizeof (vepfd);
-+
-+ libc_epfd = vppcom_session_attr (vepfd, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
-+ if (!libc_epfd) {
-+ libc_epfd = epoll_create1 (EPOLL_CLOEXEC);
-+ if (libc_epfd < 0)
-+ {
-+ rv = libc_epfd;
-+ return rv;
-+ }
-+ rv = vppcom_session_attr (vepfd, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ return rv;
-+ }
-+ }
-+ else if (libc_epfd < 0) {
-+ errno = -vepfd;
-+ rv = -1;
-+ return rv;
-+ }
-+
-+ rv = epoll_ctl (libc_epfd, op, fd, event);
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_epoll_wait(int offset_vepfd, struct epoll_event *events, int maxevents,
-+ int timeout)
-+{
-+ int rv = 0, vepfd = offset_vfd_to_vfd (offset_vepfd);
-+
-+ if (use_mq_eventfd) {
-+ int i, n_evts = 0, veprv;
-+ struct epoll_event temp_evts[2];
-+
-+again:
-+ rv = epoll_wait (epoll_fd_for_evtfd, temp_evts, 2, timeout);
-+
-+ if (PREDICT_TRUE (rv > 0))
-+ for (i = 0; i < rv; i++) {
-+ if (PREDICT_FALSE (n_evts == maxevents))
-+ return n_evts;
-+ if (PREDICT_TRUE (temp_evts[i].data.u32 == 0)) {
-+ veprv = vppcom_epoll_wait(vepfd, events + n_evts, maxevents - n_evts, 0);
-+ if (PREDICT_FALSE (veprv < 0)) {
-+ errno = -veprv;
-+ return -1;
-+ }
-+ n_evts += veprv;
-+ }
-+ else {
-+ events[n_evts] = temp_evts[i];
-+ n_evts += 1;
-+ }
-+ }
-+
-+ if (PREDICT_FALSE (!n_evts && rv > 0))
-+ goto again;
-+
-+ return n_evts;
-+ }
-+
-+ if (nvm->wait_vep_only)
-+ {
-+ rv = vppcom_epoll_wait(vepfd, events, maxevents, timeout);
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+
-+ return rv;
-+ }
-+ else
-+ {
-+ double time_to_wait = (double) 0, max_time;
-+ int libc_epfd;
-+ clib_time_t clib_time = {};
-+
-+ if (clib_time.init_cpu_time == 0)
-+ clib_time_init (&clib_time);
-+ time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
-+ max_time = clib_time_now (&clib_time) + time_to_wait;
-+
-+ libc_epfd = vppcom_session_attr (vepfd, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
-+ if (libc_epfd < 0)
-+ {
-+ errno = -libc_epfd;
-+ rv = -1;
-+ return rv;
-+ }
-+
-+ do {
-+ if (nvm->wait_vep_only) {
-+ int time_remained = 0;
-+ if (timeout > 0) {
-+ time_remained = (int)(1000 * (max_time - clib_time_now (&clib_time)));
-+ }
-+ else
-+ time_remained = timeout;
-+ rv = vppcom_epoll_wait(vepfd, events, maxevents, time_remained);
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ return rv;
-+ }
-+
-+ if (!wait_kep_next)
-+ {
-+ rv = vppcom_epoll_wait(vepfd, events, maxevents, 0);
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ return rv;
-+ }
-+ else if (rv > 0)
-+ {
-+ wait_kep_next = 1;
-+ return rv;
-+ }
-+ }
-+ else
-+ wait_kep_next = 0;
-+
-+ if (libc_epfd > 0) {
-+ rv = epoll_wait(libc_epfd, events, maxevents, 0);
-+ if (rv != 0)
-+ return rv;
-+ }
-+ } while ((timeout == -1) || (clib_time_now (&clib_time) < max_time));
-+
-+ return rv;
-+ }
-+}
-+
-+ssize_t ngxvcl_readv(int offset_vfd, const struct iovec *iov, int iovcnt)
-+{
-+ int rv = 0, i, total = 0;
-+ ssize_t size = 0;
-+
-+ do
-+ {
-+ for (i = 0; i < iovcnt; ++i)
-+ {
-+ rv = vppcom_session_read(offset_vfd_to_vfd(offset_vfd), iov[i].iov_base,
-+ iov[i].iov_len);
-+ if (rv < 0)
-+ break;
-+ else
-+ {
-+ total += rv;
-+ if ((size_t)rv < iov[i].iov_len)
-+ break;
-+ }
-+ }
-+ } while ((rv >= 0) && (total == 0));
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ size = -1;
-+ }
-+ else
-+ size = total;
-+
-+ return size;
-+}
-+
-+ssize_t ngxvcl_writev(int offset_vfd, const struct iovec *iov, int iovcnt)
-+{
-+ ssize_t size = 0, total = 0;
-+ int i, rv = 0;
-+
-+ do
-+ {
-+ for (i = 0; i < iovcnt; ++i)
-+ {
-+ rv = vppcom_session_write_msg(offset_vfd_to_vfd(offset_vfd),
-+ iov[i].iov_base, iov[i].iov_len);
-+ if (rv < 0)
-+ break;
-+ else
-+ {
-+ total += rv;
-+ if ((size_t)rv < iov[i].iov_len)
-+ break;
-+ }
-+ }
-+ } while ((rv >= 0) && (total == 0));
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ size = -1;
-+ }
-+ else
-+ size = total;
-+
-+ return size;
-+}
-+
-+int ngxvcl_kvfd_fcntl(int fd, int cmd, ...)
-+{
-+ int rv = 0;
-+ va_list ap;
-+
-+ va_start(ap, cmd);
-+
-+ if (is_offset_vfd(fd))
-+ {
-+ int flags = va_arg(ap, int), vfd = offset_vfd_to_vfd(fd);
-+ u32 size;
-+
-+ size = sizeof(flags);
-+ rv = -EOPNOTSUPP;
-+
-+ switch (cmd)
-+ {
-+ case F_SETFL:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
-+ break;
-+ case F_GETFL:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
-+ if (rv == VPPCOM_OK)
-+ rv = flags;
-+ break;
-+ case F_SETFD:
-+ /* TODO handle this */
-+ rv = 0;
-+ break;
-+ default:
-+ rv = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ else
-+ {
-+ long int args[4];
-+
-+ for (int i = 0; i < 4; i++)
-+ args[i] = va_arg(ap, long int);
-+
-+ rv = fcntl(fd, cmd, args[0], args[1], args[2], args[3]);
-+ }
-+
-+ va_end(ap);
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_ioctl(int fd, unsigned long int cmd, ...)
-+{
-+ va_list ap;
-+ int rv;
-+
-+ va_start(ap, cmd);
-+
-+ if (is_offset_vfd(fd))
-+ {
-+ int vfd = offset_vfd_to_vfd(fd);
-+
-+ switch (cmd)
-+ {
-+ case FIONREAD:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_NREAD, 0, 0);
-+ break;
-+
-+ case FIONBIO:
-+ {
-+ u32 flags = va_arg(ap, int) ? O_NONBLOCK : 0;
-+ u32 size = sizeof(flags);
-+
-+ /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
-+ * non-blocking, the flags should be read here and merged
-+ * with O_NONBLOCK.
-+ */
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
-+ }
-+ break;
-+
-+ default:
-+ rv = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if (rv < 0)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ else
-+ {
-+ long int args[4];
-+
-+ for (int i = 0; i < 4; i++)
-+ args[i] = va_arg(ap, long int);
-+
-+ rv = ioctl(fd, cmd, args[0], args[1], args[2], args[3]);
-+ }
-+
-+ va_end(ap);
-+
-+ return rv;
-+}
-+
-+int ngxvcl_socketpair(int domain, int type, int protocol, int fds[2])
-+{
-+ int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
-+
-+ if (((domain == AF_INET) || (domain == AF_INET6)) &&
-+ ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
-+ {
-+ errno = ENOSYS;
-+ rv = -1;
-+ }
-+ else
-+ {
-+ rv = socketpair(domain, type, protocol, fds);
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_getsockname(int fd, struct sockaddr *addr, socklen_t *len)
-+{
-+ int rv;
-+
-+ if (is_offset_vfd(fd))
-+ {
-+ vppcom_endpt_t ep;
-+ u8 addr_buf[sizeof(struct in6_addr)];
-+ u32 size = sizeof(ep);
-+
-+ ep.ip = addr_buf;
-+
-+ rv = vppcom_session_attr(offset_vfd_to_vfd(fd),
-+ VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ else
-+ {
-+ rv = copy_ep_to_sockaddr(addr, len, &ep);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ rv = getsockname(fd, addr, len);
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_getsockopt(int fd, int level, int optname, void *optval,
-+ socklen_t *optlen)
-+{
-+ int rv;
-+
-+ if (is_offset_vfd(fd))
-+ {
-+ int vfd = offset_vfd_to_vfd(fd);
-+
-+ rv = -EOPNOTSUPP;
-+
-+ switch (level)
-+ {
-+ case SOL_TCP:
-+ switch (optname)
-+ {
-+ case TCP_NODELAY:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_TCP_NODELAY,
-+ optval, optlen);
-+ break;
-+ case TCP_MAXSEG:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_TCP_USER_MSS,
-+ optval, optlen);
-+ break;
-+ case TCP_KEEPIDLE:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
-+ optval, optlen);
-+ break;
-+ case TCP_KEEPINTVL:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
-+ optval, optlen);
-+ break;
-+ case TCP_INFO:
-+ if (optval && optlen && (*optlen == sizeof(struct tcp_info)))
-+ {
-+ memset(optval, 0, *optlen);
-+ rv = VPPCOM_OK;
-+ }
-+ else
-+ rv = -EFAULT;
-+ break;
-+ case TCP_CONGESTION:
-+ strcpy(optval, "cubic");
-+ *optlen = strlen("cubic");
-+ rv = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SOL_IPV6:
-+ switch (optname)
-+ {
-+ case IPV6_V6ONLY:
-+ rv =
-+ vppcom_session_attr(vfd, VPPCOM_ATTR_GET_V6ONLY,
-+ optval, optlen);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SOL_SOCKET:
-+ switch (optname)
-+ {
-+ case SO_ACCEPTCONN:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_LISTEN,
-+ optval, optlen);
-+ break;
-+ case SO_KEEPALIVE:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_KEEPALIVE,
-+ optval, optlen);
-+ break;
-+ case SO_PROTOCOL:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_PROTOCOL,
-+ optval, optlen);
-+ *(int *)optval = *(int *)optval ? SOCK_DGRAM : SOCK_STREAM;
-+ break;
-+ case SO_SNDBUF:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_TX_FIFO_LEN,
-+ optval, optlen);
-+ break;
-+ case SO_RCVBUF:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_RX_FIFO_LEN,
-+ optval, optlen);
-+ break;
-+ case SO_REUSEADDR:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_REUSEADDR,
-+ optval, optlen);
-+ break;
-+ case SO_BROADCAST:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_BROADCAST,
-+ optval, optlen);
-+ break;
-+ case SO_ERROR:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_GET_ERROR,
-+ optval, optlen);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ else
-+ {
-+ rv = getsockopt(fd, level, optname, optval, optlen);
-+ }
-+
-+ return rv;
-+}
-+
-+int ngxvcl_kvfd_setsockopt(int fd, int level, int optname, const void *optval,
-+ socklen_t optlen)
-+{
-+ int rv;
-+
-+ if (is_offset_vfd(fd))
-+ {
-+ int vfd = offset_vfd_to_vfd(fd);
-+
-+ rv = -EOPNOTSUPP;
-+
-+ switch (level)
-+ {
-+ case SOL_TCP:
-+ switch (optname)
-+ {
-+ case TCP_NODELAY:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_TCP_NODELAY,
-+ (void *)optval, &optlen);
-+ break;
-+ case TCP_MAXSEG:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_TCP_USER_MSS,
-+ (void *)optval, &optlen);
-+ break;
-+ case TCP_KEEPIDLE:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
-+ (void *)optval, &optlen);
-+ break;
-+ case TCP_KEEPINTVL:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
-+ (void *)optval, &optlen);
-+ break;
-+ case TCP_CONGESTION:
-+ case TCP_CORK:
-+ /* Ignore */
-+ rv = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SOL_IPV6:
-+ switch (optname)
-+ {
-+ case IPV6_V6ONLY:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_V6ONLY,
-+ (void *)optval, &optlen);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SOL_SOCKET:
-+ switch (optname)
-+ {
-+ case SO_KEEPALIVE:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_KEEPALIVE,
-+ (void *)optval, &optlen);
-+ break;
-+ case SO_REUSEADDR:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_REUSEADDR,
-+ (void *)optval, &optlen);
-+ break;
-+ case SO_BROADCAST:
-+ rv = vppcom_session_attr(vfd, VPPCOM_ATTR_SET_BROADCAST,
-+ (void *)optval, &optlen);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ errno = -rv;
-+ rv = -1;
-+ }
-+ }
-+ else
-+ {
-+ rv = setsockopt(fd, level, optname, optval, optlen);
-+ }
-+
-+ return rv;
-+}
-+
-+ssize_t ngxvcl_send(int offset_vfd, const void *buf, size_t n, int flags)
-+{
-+ ssize_t size;
-+
-+ size = vppcom_session_sendto(offset_vfd_to_vfd(offset_vfd), (void *)buf,
-+ n, flags, NULL);
-+
-+ if (size < VPPCOM_OK)
-+ {
-+ errno = -size;
-+ size = -1;
-+ }
-+
-+ return size;
-+}
-+
-+ssize_t ngxvcl_sendfile(int out_offset_vfd, int in_kfd, off_t *offset, size_t len)
-+{
-+ ssize_t size = 0;
-+ int rv, out_vfd = offset_vfd_to_vfd(out_offset_vfd);
-+ ssize_t results = 0;
-+ size_t n_bytes_left = len;
-+ size_t bytes_to_read;
-+ int nbytes;
-+ u8 eagain = 0;
-+ u32 flags, flags_len = sizeof(flags);
-+
-+ rv = vppcom_session_attr(out_vfd, VPPCOM_ATTR_GET_FLAGS, &flags,
-+ &flags_len);
-+
-+ if (rv != VPPCOM_OK)
-+ {
-+ vec_reset_length (sendfile_io_buffer);
-+ errno = -rv;
-+ size = -1;
-+ goto done;
-+ }
-+
-+ if (offset)
-+ {
-+ off_t off = lseek(in_kfd, *offset, SEEK_SET);
-+
-+ if (off == -1)
-+ {
-+ size = -1;
-+ goto done;
-+ }
-+ }
-+
-+ do
-+ {
-+ size = vppcom_session_attr(out_vfd, VPPCOM_ATTR_GET_NWRITE, 0, 0);
-+
-+ if (size < 0)
-+ {
-+ vec_reset_length (sendfile_io_buffer);
-+ errno = -size;
-+ size = -1;
-+ goto done;
-+ }
-+
-+ bytes_to_read = size;
-+
-+ if (bytes_to_read == 0)
-+ {
-+ if (flags & O_NONBLOCK)
-+ {
-+ if (!results)
-+ eagain = 1;
-+ goto update_offset;
-+ }
-+ else
-+ continue;
-+ }
-+
-+ bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
-+ vec_validate (sendfile_io_buffer, bytes_to_read);
-+ nbytes = read (in_kfd, sendfile_io_buffer, bytes_to_read);
-+
-+ if (nbytes < 0)
-+ {
-+ if (results == 0)
-+ {
-+ vec_reset_length (sendfile_io_buffer);
-+ size = -1;
-+ goto done;
-+ }
-+ goto update_offset;
-+ }
-+
-+ size = vppcom_session_write(out_vfd, sendfile_io_buffer, nbytes);
-+
-+ if (size < 0)
-+ {
-+ if (size == VPPCOM_EAGAIN)
-+ {
-+ if (flags & O_NONBLOCK)
-+ {
-+ if (!results)
-+ eagain = 1;
-+ goto update_offset;
-+ }
-+ else
-+ continue;
-+ }
-+ if (results == 0)
-+ {
-+ vec_reset_length (sendfile_io_buffer);
-+ errno = -size;
-+ size = -1;
-+ goto done;
-+ }
-+ goto update_offset;
-+ }
-+
-+ results += nbytes;
-+ n_bytes_left = n_bytes_left - nbytes;
-+ } while (n_bytes_left > 0);
-+
-+update_offset:
-+ vec_reset_length (sendfile_io_buffer);
-+ if (offset)
-+ {
-+ off_t off = lseek(in_kfd, *offset, SEEK_SET);
-+
-+ if (off == -1)
-+ {
-+ size = -1;
-+ goto done;
-+ }
-+
-+ *offset += results + 1;
-+ }
-+ if (eagain)
-+ {
-+ errno = EAGAIN;
-+ size = -1;
-+ }
-+ else
-+ size = results;
-+
-+done:
-+ return size;
-+}
-+
-+ssize_t ngxvcl_recv(int offset_vfd, void *buf, size_t n, int flags)
-+{
-+ ssize_t size;
-+
-+ size = vppcom_session_recvfrom(offset_vfd_to_vfd(offset_vfd), buf, n, flags, NULL);
-+
-+ if (size < 0)
-+ errno = -size;
-+
-+ return size;
-+}
-+
-+ssize_t ngxvcl_sendto(int offset_vfd, const void *buf, size_t n, int flags,
-+ const struct sockaddr *addr, socklen_t addr_len)
-+{
-+ ssize_t size;
-+
-+ 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 = vppcom_session_sendto(offset_vfd_to_vfd(offset_vfd), (void *)buf, n, flags, ep);
-+
-+ if (size < 0)
-+ {
-+ errno = -size;
-+ size = -1;
-+ }
-+
-+done:
-+ return size;
-+}
-+
-+ssize_t ngxvcl_recvfrom(int offset_vfd, void *buf, size_t n, int flags,
-+ struct sockaddr *addr, socklen_t *addr_len)
-+{
-+ int vfd = offset_vfd_to_vfd(offset_vfd);
-+ ssize_t size, rv;
-+
-+ vppcom_endpt_t ep;
-+ u8 src_addr[sizeof(struct sockaddr_in6)];
-+
-+ if (addr)
-+ {
-+ ep.ip = src_addr;
-+ size = vppcom_session_recvfrom(vfd, buf, n, flags, &ep);
-+
-+ if (size > 0)
-+ {
-+ rv = copy_ep_to_sockaddr(addr, addr_len, &ep);
-+
-+ if (rv < 0)
-+ size = rv;
-+ }
-+ }
-+ else
-+ size = vppcom_session_recvfrom(vfd, buf, n, flags, NULL);
-+
-+ if (size < 0)
-+ {
-+ errno = -size;
-+ size = -1;
-+ }
-+
-+ return size;
-+}
-+
-+ssize_t ngxvcl_sendmsg(int offset_vfd, const struct msghdr *message, int flags)
-+{
-+ ssize_t size;
-+
-+ errno = ENOSYS;
-+ size = -1;
-+
-+ return size;
-+}
-+
-+ssize_t ngxvcl_recvmsg(int offset_vfd, struct msghdr *message, int flags)
-+{
-+ ssize_t size;
-+
-+ errno = ENOSYS;
-+ size = -1;
-+
-+ return size;
-+}
-+
-+int ngxvcl_shutdown(int offset_vfd, int how)
-+{
-+ int rv = 0, flags, vfd = offset_vfd_to_vfd(offset_vfd);
-+ u32 flags_len = sizeof(flags);
-+
-+ if (vppcom_session_attr(vfd, VPPCOM_ATTR_SET_SHUT, &how, &flags_len))
-+ {
-+ vppcom_session_close(vfd);
-+ return -1;
-+ }
-+
-+ if (vppcom_session_attr(vfd, VPPCOM_ATTR_GET_SHUT, &flags, &flags_len))
-+ {
-+ vppcom_session_close(vfd);
-+ return -1;
-+ }
-+
-+ if (flags == SHUT_RDWR)
-+ rv = vppcom_session_close(vfd);
-+
-+ return rv;
-+}
-diff --git a/src/vcl/ngxvcl.h b/src/vcl/ngxvcl.h
-new file mode 100644
-index 000000000..60b5116a8
---- /dev/null
-+++ b/src/vcl/ngxvcl.h
-@@ -0,0 +1,70 @@
-+#ifndef _NGXVCL_H_
-+#define _NGXVCL_H_
-+
-+#define _GNU_SOURCE
-+#include <arpa/inet.h>
-+#include <fcntl.h>
-+#include <netinet/tcp.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <sys/errno.h>
-+#include <sys/ioctl.h>
-+#include <sys/sendfile.h>
-+#include <sys/socket.h>
-+#include <sys/uio.h>
-+#include <unistd.h>
-+#include <vcl/vppcom.h>
-+
-+void ngxvcl_wait_vep_only();
-+void ngxvcl_wait_kep_and_vep();
-+
-+void ngxvcl_app_create(char *app_name);
-+void ngxvcl_app_destroy(void);
-+
-+int ngxvcl_socket(int domain, int type, int protocol);
-+int ngxvcl_close(int offset_vfd);
-+int ngxvcl_kvfd_close(int fd);
-+int ngxvcl_bind(int offset_vfd, const struct sockaddr *addr, socklen_t addrlen);
-+int ngxvcl_listen(int offset_vfd, int backlog);
-+
-+int ngxvcl_accept4(int offset_vfd, struct sockaddr *addr, socklen_t *addrlen,
-+ int flags);
-+int ngxvcl_accept(int offset_vfd, struct sockaddr *addr, socklen_t *addrlen);
-+
-+int ngxvcl_connect(int offset_vfd, const struct sockaddr *addr, socklen_t addrlen);
-+int ngxvcl_read(int offset_vfd, void *buf, size_t count);
-+int ngxvcl_write(int offset_vfd, const void *buf, size_t count);
-+
-+int ngxvcl_epoll_create(int size);
-+int ngxvcl_kvfd_epoll_ctl(int offset_vepfd, int op, int fd, struct epoll_event *event);
-+int ngxvcl_kvfd_epoll_wait(int offset_vepfd, struct epoll_event *events, int maxevents,
-+ int timeout);
-+
-+ssize_t ngxvcl_readv(int offset_vfd, const struct iovec *iov, int iovcnt);
-+ssize_t ngxvcl_writev(int offset_vfd, const struct iovec *iov, int iovcnt);
-+
-+int ngxvcl_kvfd_fcntl(int fd, int cmd, ...);
-+int ngxvcl_kvfd_ioctl(int fd, unsigned long int cmd, ...);
-+
-+int ngxvcl_socketpair(int domain, int type, int protocol, int fds[2]);
-+int ngxvcl_kvfd_getsockname(int fd, struct sockaddr *addr, socklen_t *len);
-+int ngxvcl_kvfd_getsockopt(int fd, int level, int optname, void *optval,
-+ socklen_t *optlen);
-+int ngxvcl_kvfd_setsockopt(int fd, int level, int optname, const void *optval,
-+ socklen_t optlen);
-+
-+ssize_t ngxvcl_send(int fd, const void *buf, size_t n, int flags);
-+ssize_t ngxvcl_sendfile(int out_offset_vfd, int in_kfd, off_t *offset, size_t len);
-+ssize_t ngxvcl_recv(int offset_vfd, void *buf, size_t n, int flags);
-+ssize_t ngxvcl_sendto(int offset_vfd, const void *buf, size_t n, int flags,
-+ const struct sockaddr *addr, socklen_t addr_len);
-+ssize_t ngxvcl_recvfrom(int offset_vfd, void *buf, size_t n, int flags,
-+ struct sockaddr *addr, socklen_t *addr_len);
-+ssize_t ngxvcl_sendmsg(int offset_vfd, const struct msghdr *message, int flags);
-+ssize_t ngxvcl_recvmsg(int offset_vfd, struct msghdr *message, int flags);
-+
-+int ngxvcl_shutdown(int offset_vfd, int how);
-+
-+#endif
---
-2.17.1
-