vcl: support for eventfd mq signaling

- support eventfd based mq signaling. Based on configuration, vcl
epoll/select can use either condvars or epoll on mq eventfds.
- add vcl support for memfd segments
- vpp explicitly registers cut-through segments with apps/vcl
- if using eventfd, make ldp allow one call to libc_epoll_create. Needed
for the message queue epfd
- update svm_queue_t to allow blocking calls with eventfd signaling.

Change-Id: I064151ac370bbe29bb16c968bf4e3659c8286bea
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/tests/vnet/session/tcp_echo.c b/src/tests/vnet/session/tcp_echo.c
index f37a727..140a198 100644
--- a/src/tests/vnet/session/tcp_echo.c
+++ b/src/tests/vnet/session/tcp_echo.c
@@ -263,7 +263,7 @@
 	return -1;
       if (em->time_to_stop == 1)
 	return 0;
-      if (!em->our_event_queue)
+      if (!em->our_event_queue || em->state < STATE_ATTACHED)
 	continue;
 
       if (svm_msg_q_sub (em->our_event_queue, &msg, SVM_Q_NOWAIT, 0))
@@ -347,44 +347,17 @@
 }
 
 static int
-memfd_segment_attach (void)
-{
-  ssvm_private_t _ssvm = { 0 }, *ssvm = &_ssvm;
-  clib_error_t *error;
-  int rv;
-
-  if ((error = vl_socket_client_recv_fd_msg (&ssvm->fd, 1, 5)))
-    {
-      clib_error_report (error);
-      return -1;
-    }
-
-  if ((rv = ssvm_slave_init_memfd (ssvm)))
-    return rv;
-
-  return 0;
-}
-
-static int
-fifo_segment_attach (char *name, u32 size, ssvm_segment_type_t type)
+ssvm_segment_attach (char *name, ssvm_segment_type_t type, int fd)
 {
   svm_fifo_segment_create_args_t _a, *a = &_a;
-  clib_error_t *error;
   int rv;
 
   memset (a, 0, sizeof (*a));
   a->segment_name = (char *) name;
-  a->segment_size = size;
   a->segment_type = type;
 
   if (type == SSVM_SEGMENT_MEMFD)
-    {
-      if ((error = vl_socket_client_recv_fd_msg (&a->memfd_fd, 1, 5)))
-	{
-	  clib_error_report (error);
-	  return -1;
-	}
-    }
+    a->memfd_fd = fd;
 
   if ((rv = svm_fifo_segment_attach (a)))
     {
@@ -392,6 +365,7 @@
       return rv;
     }
 
+  vec_reset_length (a->new_segment_indices);
   return 0;
 }
 
@@ -400,47 +374,57 @@
 					   mp)
 {
   echo_main_t *em = &echo_main;
-  ssvm_segment_type_t seg_type;
+  int *fds = 0;
+  u32 n_fds = 0;
 
   if (mp->retval)
     {
       clib_warning ("attach failed: %U", format_api_error,
 		    clib_net_to_host_u32 (mp->retval));
-      em->state = STATE_FAILED;
-      return;
+      goto failed;
     }
 
   if (mp->segment_name_length == 0)
     {
       clib_warning ("segment_name_length zero");
-      return;
-    }
-
-  seg_type = em->use_sock_api ? SSVM_SEGMENT_MEMFD : SSVM_SEGMENT_SHM;
-
-  /* Attach to fifo segment */
-  if (fifo_segment_attach ((char *) mp->segment_name, mp->segment_size,
-			   seg_type))
-    {
-      em->state = STATE_FAILED;
-      return;
-    }
-
-  /* If we're using memfd segments, read and attach to event qs segment */
-  if (seg_type == SSVM_SEGMENT_MEMFD)
-    {
-      if (memfd_segment_attach ())
-	{
-	  clib_warning ("failed to attach to evt q segment");
-	  em->state = STATE_FAILED;
-	  return;
-	}
+      goto failed;
     }
 
   ASSERT (mp->app_event_queue_address);
   em->our_event_queue = uword_to_pointer (mp->app_event_queue_address,
 					  svm_msg_q_t *);
+
+  if (mp->n_fds)
+    {
+      vec_validate (fds, mp->n_fds);
+      vl_socket_client_recv_fd_msg (fds, mp->n_fds, 5);
+
+      if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
+	if (ssvm_segment_attach (0, SSVM_SEGMENT_MEMFD, fds[n_fds++]))
+	  goto failed;
+
+      if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
+	if (ssvm_segment_attach ((char *) mp->segment_name,
+				 SSVM_SEGMENT_MEMFD, fds[n_fds++]))
+	  goto failed;
+
+      if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
+	svm_msg_q_set_consumer_eventfd (em->our_event_queue, fds[n_fds++]);
+
+      vec_free (fds);
+    }
+  else
+    {
+      if (ssvm_segment_attach ((char *) mp->segment_name, SSVM_SEGMENT_SHM,
+			       -1))
+	goto failed;
+    }
+
   em->state = STATE_ATTACHED;
+  return;
+failed:
+  em->state = STATE_FAILED;
+  return;
 }
 
 static void