session: add support for memfd segments

- update segment manager and session api to work with both flavors of
  ssvm segments
- added generic ssvm slave/master init and del functions
- cleanup/refactor tcp_echo
- fixed uses of svm fifo pool as vector

Change-Id: Ieee8b163faa407da6e77e657a2322de213a9d2a0
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c
index 8090e75..13ccdd7 100644
--- a/src/vnet/session/application.c
+++ b/src/vnet/session/application.c
@@ -227,18 +227,56 @@
     clib_warning ("No session reset callback function provided");
 }
 
+/**
+ * Check app config for given segment type
+ *
+ * Returns 1 on success and 0 otherwise
+ */
+static u8
+application_verify_cfg (ssvm_segment_type_t st)
+{
+  u8 is_valid;
+  if (st == SSVM_SEGMENT_MEMFD)
+    {
+      is_valid = (session_manager_get_evt_q_segment () != 0);
+      if (!is_valid)
+	clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
+      return is_valid;
+    }
+  else if (st == SSVM_SEGMENT_SHM)
+    {
+      is_valid = (session_manager_get_evt_q_segment () == 0);
+      if (!is_valid)
+	clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
+      return is_valid;
+    }
+  else
+    return 1;
+}
+
 int
 application_init (application_t * app, u32 api_client_index, u64 * options,
 		  session_cb_vft_t * cb_fns)
 {
-  segment_manager_t *sm;
-  segment_manager_properties_t *props;
+  ssvm_segment_type_t st = SSVM_SEGMENT_MEMFD;
   u32 app_evt_queue_size, first_seg_size;
-  u32 default_rx_fifo_size = 16 << 10, default_tx_fifo_size = 16 << 10;
+  segment_manager_properties_t *props;
+  vl_api_registration_t *reg;
+  segment_manager_t *sm;
   int rv;
 
-  app_evt_queue_size = options[APP_OPTIONS_EVT_QUEUE_SIZE] > 0 ?
-    options[APP_OPTIONS_EVT_QUEUE_SIZE] : default_app_evt_queue_size;
+  /*
+   * Make sure we support the requested configuration
+   */
+  reg = vl_api_client_index_to_registration (api_client_index);
+  if (!reg)
+    return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
+
+  if (vl_api_registration_file_index (reg) == ~0)
+    st = SSVM_SEGMENT_SHM;
+
+  if (!application_verify_cfg (st))
+    return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
 
   /*
    * Setup segment manager
@@ -247,21 +285,27 @@
   sm->app_index = app->index;
   props = segment_manager_properties_alloc ();
   app->sm_properties = segment_manager_properties_index (props);
-  props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
-  props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
-  props->rx_fifo_size =
-    props->rx_fifo_size ? props->rx_fifo_size : default_rx_fifo_size;
-  props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
-  props->tx_fifo_size =
-    props->tx_fifo_size ? props->tx_fifo_size : default_tx_fifo_size;
-  props->add_segment = props->add_segment_size != 0;
+  if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
+    {
+      props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
+      props->add_segment = 1;
+    }
+  if (options[APP_OPTIONS_RX_FIFO_SIZE])
+    props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
+  if (options[APP_OPTIONS_TX_FIFO_SIZE])
+    props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
   props->preallocated_fifo_pairs = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
-  props->use_private_segment = options[APP_OPTIONS_FLAGS]
-    & APP_OPTIONS_FLAGS_IS_BUILTIN;
   props->private_segment_count = options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT];
+  if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN)
+    props->segment_type = SSVM_N_SEGMENT_TYPES;
+  else
+    props->segment_type = st;
 
+  app_evt_queue_size = options[APP_OPTIONS_EVT_QUEUE_SIZE] > 0 ?
+    options[APP_OPTIONS_EVT_QUEUE_SIZE] : default_app_evt_queue_size;
   first_seg_size = options[APP_OPTIONS_SEGMENT_SIZE];
-  if ((rv = segment_manager_init (sm, app->sm_properties, first_seg_size)))
+  if ((rv = segment_manager_init (sm, app->sm_properties, first_seg_size,
+				  app_evt_queue_size)))
     return rv;
   sm->first_is_protected = 1;
 
@@ -478,15 +522,13 @@
 application_add_segment_notify (u32 app_index, u32 fifo_segment_index)
 {
   application_t *app = application_get (app_index);
-  u32 seg_size = 0;
-  u8 *seg_name;
+  svm_fifo_segment_private_t *fs;
 
   /* Send an API message to the external app, to map new segment */
   ASSERT (app->cb_fns.add_segment_callback);
 
-  segment_manager_get_segment_info (fifo_segment_index, &seg_name, &seg_size);
-  return app->cb_fns.add_segment_callback (app->api_client_index, seg_name,
-					   seg_size);
+  fs = segment_manager_get_segment (fifo_segment_index);
+  return app->cb_fns.add_segment_callback (app->api_client_index, &fs->ssvm);
 }
 
 u8
diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h
index fd6454f..afe738f 100644
--- a/src/vnet/session/application.h
+++ b/src/vnet/session/application.h
@@ -30,8 +30,8 @@
 typedef struct _stream_session_cb_vft
 {
   /** Notify server of new segment */
-  int (*add_segment_callback) (u32 api_client_index, const u8 * seg_name,
-			       u32 seg_size);
+  int (*add_segment_callback) (u32 api_client_index,
+			       const ssvm_private_t * ssvm_seg);
 
   /** Notify server of newly accepted session */
   int (*session_accept_callback) (stream_session_t * new_session);
diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c
index ec31789..f2a13be 100644
--- a/src/vnet/session/application_interface.c
+++ b/src/vnet/session/application_interface.c
@@ -413,11 +413,11 @@
 clib_error_t *
 vnet_application_attach (vnet_app_attach_args_t * a)
 {
+  svm_fifo_segment_private_t *fs;
   application_t *app = 0;
   segment_manager_t *sm;
-  u8 *seg_name;
-  u64 secret;
   u32 app_ns_index = 0;
+  u64 secret;
   int rv;
 
   app = application_lookup (a->api_client_index);
@@ -437,16 +437,15 @@
 
   a->app_event_queue_address = pointer_to_uword (app->event_queue);
   sm = segment_manager_get (app->first_segment_manager);
-  segment_manager_get_segment_info (sm->segment_indices[0],
-				    &seg_name, &a->segment_size);
+  fs = segment_manager_get_segment (sm->segment_indices[0]);
 
   if (application_is_proxy (app))
     application_setup_proxy (app);
 
-  a->segment_name_length = vec_len (seg_name);
-  a->segment_name = seg_name;
-  ASSERT (vec_len (a->segment_name) <= 128);
+  ASSERT (vec_len (fs->ssvm.name) <= 128);
+  a->segment = &fs->ssvm;
   a->app_index = app->index;
+
   return 0;
 }
 
diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h
index 68973a9..8db318f 100644
--- a/src/vnet/session/application_interface.h
+++ b/src/vnet/session/application_interface.h
@@ -39,9 +39,7 @@
   /*
    * Results
    */
-  u8 *segment_name;
-  u32 segment_name_length;
-  u32 segment_size;
+  ssvm_private_t *segment;
   u64 app_event_queue_address;
   u32 app_index;
 } vnet_app_attach_args_t;
diff --git a/src/vnet/session/segment_manager.c b/src/vnet/session/segment_manager.c
index dc3e4c9..c3a794b 100644
--- a/src/vnet/session/segment_manager.c
+++ b/src/vnet/session/segment_manager.c
@@ -49,6 +49,9 @@
   segment_manager_properties_t *props;
   pool_get (segment_manager_properties_pool, props);
   memset (props, 0, sizeof (*props));
+  props->add_segment_size = default_segment_size;
+  props->rx_fifo_size = default_fifo_size;
+  props->tx_fifo_size = default_fifo_size;
   return props;
 }
 
@@ -73,53 +76,64 @@
   return p - segment_manager_properties_pool;
 }
 
+svm_fifo_segment_private_t *
+segment_manager_get_segment (u32 segment_index)
+{
+  return svm_fifo_segment_get_segment (segment_index);
+}
+
 void
 segment_manager_get_segment_info (u32 index, u8 ** name, u32 * size)
 {
   svm_fifo_segment_private_t *s;
   s = svm_fifo_segment_get_segment (index);
-  *name = s->h->segment_name;
+  *name = s->ssvm.name;
   *size = s->ssvm.ssvm_size;
 }
 
 always_inline int
-session_manager_add_segment_i (segment_manager_t * sm, u32 segment_size,
-			       u8 * segment_name)
+segment_manager_add_segment_i (segment_manager_t * sm, u32 segment_size,
+			       u32 protected_space)
 {
-  svm_fifo_segment_create_args_t _ca, *ca = &_ca;
+  svm_fifo_segment_create_args_t _ca = { 0 }, *ca = &_ca;
   segment_manager_properties_t *props;
-  int rv;
 
-  memset (ca, 0, sizeof (*ca));
   props = segment_manager_properties_get (sm->properties_index);
-  if (!props->use_private_segment)
-    {
-      ca->segment_name = (char *) segment_name;
-      ca->segment_size = segment_size;
-      ca->rx_fifo_size = props->rx_fifo_size;
-      ca->tx_fifo_size = props->tx_fifo_size;
-      ca->preallocated_fifo_pairs = props->preallocated_fifo_pairs;
 
-      rv = svm_fifo_segment_create (ca);
-      if (rv)
+  /* Not configured for addition of new segments and not first */
+  if (!props->add_segment && !segment_size)
+    {
+      clib_warning ("cannot allocate new segment");
+      return VNET_API_ERROR_INVALID_VALUE;
+    }
+
+  ca->segment_size = segment_size ? segment_size : props->add_segment_size;
+  ca->rx_fifo_size = props->rx_fifo_size;
+  ca->tx_fifo_size = props->tx_fifo_size;
+  ca->preallocated_fifo_pairs = props->preallocated_fifo_pairs;
+  ca->seg_protected_space = protected_space ? protected_space : 0;
+
+  if (props->segment_type != SSVM_N_SEGMENT_TYPES)
+    {
+      ca->segment_name = (char *) format (0, "%d-%d%c", getpid (),
+					  segment_name_counter++, 0);
+      ca->segment_type = props->segment_type;
+      if (svm_fifo_segment_create (ca))
 	{
 	  clib_warning ("svm_fifo_segment_create ('%s', %d) failed",
 			ca->segment_name, ca->segment_size);
 	  return VNET_API_ERROR_SVM_SEGMENT_CREATE_FAIL;
 	}
+      vec_free (ca->segment_name);
     }
   else
     {
-      u32 rx_fifo_size, tx_fifo_size, rx_rounded_data_size,
-	tx_rounded_data_size;
+      u32 rx_fifo_size, tx_fifo_size;
+      u32 rx_rounded_data_size, tx_rounded_data_size;
       u32 approx_segment_count;
       u64 approx_total_size;
 
       ca->segment_name = "process-private-segment";
-      ca->segment_size = segment_size;
-      ca->rx_fifo_size = props->rx_fifo_size;
-      ca->tx_fifo_size = props->tx_fifo_size;
-      ca->preallocated_fifo_pairs = props->preallocated_fifo_pairs;
       ca->private_segment_count = props->private_segment_count;
 
       /* Calculate space requirements */
@@ -131,61 +145,44 @@
 
       approx_total_size = (u64) ca->preallocated_fifo_pairs
 	* (rx_fifo_size + tx_fifo_size);
-      approx_segment_count = (approx_total_size + (ca->segment_size - 1))
-	/ (u64) ca->segment_size;
+      approx_segment_count = (approx_total_size + protected_space
+			      + (ca->segment_size -
+				 1)) / (u64) ca->segment_size;
 
       /* The user asked us to figure it out... */
-      if (ca->private_segment_count == 0)
+      if (ca->private_segment_count == 0
+	  || approx_segment_count < ca->private_segment_count)
 	{
 	  ca->private_segment_count = approx_segment_count;
 	}
       /* Follow directions, but issue a warning */
-      else if (approx_segment_count != ca->private_segment_count)
+      else if (approx_segment_count < ca->private_segment_count)
 	{
 	  clib_warning ("Honoring segment count %u, calculated count was %u",
 			ca->private_segment_count, approx_segment_count);
 	}
+      else if (approx_segment_count > ca->private_segment_count)
+	{
+	  clib_warning ("Segment count too low %u, calculated %u.",
+			ca->private_segment_count, approx_segment_count);
+	  return VNET_API_ERROR_INVALID_VALUE;
+	}
 
       if (svm_fifo_segment_create_process_private (ca))
 	clib_warning ("Failed to create process private segment");
 
       ASSERT (vec_len (ca->new_segment_indices));
     }
+
   vec_append (sm->segment_indices, ca->new_segment_indices);
   vec_free (ca->new_segment_indices);
   return 0;
 }
 
 int
-session_manager_add_segment (segment_manager_t * sm)
+segment_manager_add_segment (segment_manager_t * sm)
 {
-  svm_fifo_segment_create_args_t _ca, *ca = &_ca;
-  segment_manager_properties_t *props;
-  u32 add_segment_size;
-  u8 *segment_name;
-  int rv;
-
-  memset (ca, 0, sizeof (*ca));
-  props = segment_manager_properties_get (sm->properties_index);
-  segment_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
-  add_segment_size = props->add_segment_size ?
-    props->add_segment_size : default_segment_size;
-
-  rv = session_manager_add_segment_i (sm, add_segment_size, segment_name);
-  vec_free (segment_name);
-  return rv;
-}
-
-int
-session_manager_add_first_segment (segment_manager_t * sm, u32 segment_size)
-{
-  u8 *segment_name;
-  int rv;
-
-  segment_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
-  rv = session_manager_add_segment_i (sm, segment_size, segment_name);
-  vec_free (segment_name);
-  return rv;
+  return segment_manager_add_segment_i (sm, 0, 0);
 }
 
 segment_manager_t *
@@ -203,14 +200,18 @@
  */
 int
 segment_manager_init (segment_manager_t * sm, u32 props_index,
-		      u32 first_seg_size)
+		      u32 first_seg_size, u32 evt_q_size)
 {
+  u32 protected_space;
   int rv;
 
-  /* app allocates these */
   sm->properties_index = props_index;
+
+  protected_space = max_pow2 (sizeof (svm_queue_t)
+			      + evt_q_size * sizeof (session_fifo_event_t));
+  protected_space = round_pow2_u64 (protected_space, CLIB_CACHE_LINE_BYTES);
   first_seg_size = first_seg_size > 0 ? first_seg_size : default_segment_size;
-  rv = session_manager_add_first_segment (sm, first_seg_size);
+  rv = segment_manager_add_segment_i (sm, first_seg_size, protected_space);
   if (rv)
     {
       clib_warning ("Failed to allocate segment");
@@ -257,7 +258,7 @@
   svm_fifo_segment_private_t *fifo_segment;
   u32 svm_segment_index;
   clib_spinlock_lock (&sm->lockp);
-  svm_segment_index = sm->segment_indices[segment_index];
+  svm_segment_index = vec_elt (sm->segment_indices, segment_index);
   fifo_segment = svm_fifo_segment_get_segment (svm_segment_index);
   if (!fifo_segment
       || ((fifo_segment->h->flags & FIFO_SEGMENT_F_IS_PREALLOCATED)
@@ -307,8 +308,7 @@
 	  if (session->session_state != SESSION_STATE_CLOSED)
 	    {
 	      session->session_state = SESSION_STATE_CLOSED;
-	      session_send_session_evt_to_thread (session_handle
-						  (session),
+	      session_send_session_evt_to_thread (session_handle (session),
 						  FIFO_EVENT_DISCONNECT,
 						  thread_index);
 	    }
@@ -371,8 +371,8 @@
 
 int
 segment_manager_alloc_session_fifos (segment_manager_t * sm,
-				     svm_fifo_t ** server_rx_fifo,
-				     svm_fifo_t ** server_tx_fifo,
+				     svm_fifo_t ** rx_fifo,
+				     svm_fifo_t ** tx_fifo,
 				     u32 * fifo_segment_index)
 {
   svm_fifo_segment_private_t *fifo_segment;
@@ -392,39 +392,37 @@
 again:
   for (i = 0; i < vec_len (sm->segment_indices); i++)
     {
-      *fifo_segment_index = sm->segment_indices[i];
+      *fifo_segment_index = vec_elt (sm->segment_indices, i);
       fifo_segment = svm_fifo_segment_get_segment (*fifo_segment_index);
 
       fifo_size = props->rx_fifo_size;
       fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
-      *server_rx_fifo =
-	svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
-				     FIFO_SEGMENT_RX_FREELIST);
+      *rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
+					      FIFO_SEGMENT_RX_FREELIST);
 
       fifo_size = props->tx_fifo_size;
       fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
-      *server_tx_fifo =
-	svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
-				     FIFO_SEGMENT_TX_FREELIST);
+      *tx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
+					      FIFO_SEGMENT_TX_FREELIST);
 
-      if (*server_rx_fifo == 0)
+      if (*rx_fifo == 0)
 	{
 	  /* This would be very odd, but handle it... */
-	  if (*server_tx_fifo != 0)
+	  if (*tx_fifo != 0)
 	    {
-	      svm_fifo_segment_free_fifo (fifo_segment, *server_tx_fifo,
+	      svm_fifo_segment_free_fifo (fifo_segment, *tx_fifo,
 					  FIFO_SEGMENT_TX_FREELIST);
-	      *server_tx_fifo = 0;
+	      *tx_fifo = 0;
 	    }
 	  continue;
 	}
-      if (*server_tx_fifo == 0)
+      if (*tx_fifo == 0)
 	{
-	  if (*server_rx_fifo != 0)
+	  if (*rx_fifo != 0)
 	    {
-	      svm_fifo_segment_free_fifo (fifo_segment, *server_rx_fifo,
+	      svm_fifo_segment_free_fifo (fifo_segment, *rx_fifo,
 					  FIFO_SEGMENT_RX_FREELIST);
-	      *server_rx_fifo = 0;
+	      *rx_fifo = 0;
 	    }
 	  continue;
 	}
@@ -432,9 +430,9 @@
     }
 
   /* See if we're supposed to create another segment */
-  if (*server_rx_fifo == 0)
+  if (*rx_fifo == 0)
     {
-      if (props->add_segment && !props->use_private_segment)
+      if (props->add_segment && !props->segment_type)
 	{
 	  if (added_a_segment)
 	    {
@@ -443,7 +441,7 @@
 	      return SESSION_ERROR_NEW_SEG_NO_SPACE;
 	    }
 
-	  if (session_manager_add_segment (sm))
+	  if (segment_manager_add_segment (sm))
 	    {
 	      clib_spinlock_unlock (&sm->lockp);
 	      return VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
@@ -462,8 +460,8 @@
 
   /* Backpointers to segment manager */
   sm_index = segment_manager_index (sm);
-  (*server_tx_fifo)->segment_manager = sm_index;
-  (*server_rx_fifo)->segment_manager = sm_index;
+  (*tx_fifo)->segment_manager = sm_index;
+  (*rx_fifo)->segment_manager = sm_index;
 
   clib_spinlock_unlock (&sm->lockp);
 
@@ -577,14 +575,12 @@
 {
   svm_fifo_segment_private_t *segments, *seg;
   segment_manager_t *sm;
-  u8 show_segments = 0, verbose = 0, *name;
+  u8 show_segments = 0, verbose = 0;
   uword address;
   u64 size;
   u32 active_fifos;
   u32 free_fifos;
 
-  mheap_t *heap_header;
-
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "segments"))
@@ -615,37 +611,20 @@
       segments = svm_fifo_segment_segments_pool ();
       vlib_cli_output (vm, "%d svm fifo segments allocated",
 		       pool_elts (segments));
-      vlib_cli_output (vm, "%-25s%15s%16s%16s%16s", "Name",
+      vlib_cli_output (vm, "%-15s%10s%15s%15s%15s%15s", "Name", "Type",
 		       "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
 
       /* *INDENT-OFF* */
       pool_foreach (seg, segments, ({
-	if (seg->h->flags & FIFO_SEGMENT_F_IS_PRIVATE)
-	  {
-	    address = pointer_to_uword (seg->ssvm.sh->heap);
-	    if (seg->h->flags & FIFO_SEGMENT_F_IS_MAIN_HEAP)
-	      name = format (0, "main heap");
-	    else
-	      name = format (0, "private heap");
-	    heap_header = mheap_header (seg->ssvm.sh->heap);
-	    size = heap_header->max_size;
-	  }
-	else
-	  {
-	    address =  seg->ssvm.sh->ssvm_va;
-	    size = seg->ssvm.ssvm_size;
-	    name = seg->ssvm.sh->name;
-	  }
+	svm_fifo_segment_info (seg, &address, &size);
 	active_fifos = svm_fifo_segment_num_fifos (seg);
         free_fifos = svm_fifo_segment_num_free_fifos (seg, ~0 /* size */);
-	vlib_cli_output (vm, "%-25v%15llu%16u%16u%16llx",
-                         name, size >> 20ULL, active_fifos, free_fifos,
-			 address);
+	vlib_cli_output (vm, "%-15v%10U%15llu%15u%15u%15llx",
+	                 ssvm_name (&seg->ssvm), format_svm_fifo_segment_type,
+	                 seg, size >> 20ULL, active_fifos, free_fifos,
+	                 address);
         if (verbose)
-          vlib_cli_output (vm, "%U",
-                           format_svm_fifo_segment, seg, verbose);
-	if (seg->h->flags & FIFO_SEGMENT_F_IS_PRIVATE)
-	  vec_free (name);
+          vlib_cli_output (vm, "%U", format_svm_fifo_segment, seg, verbose);
       }));
       /* *INDENT-ON* */
 
diff --git a/src/vnet/session/segment_manager.h b/src/vnet/session/segment_manager.h
index 41e2308..b2a792d 100644
--- a/src/vnet/session/segment_manager.h
+++ b/src/vnet/session/segment_manager.h
@@ -36,8 +36,8 @@
   /** Flag that indicates if additional segments should be created */
   u8 add_segment;
 
-  /** Use private memory segment instead of shared memory */
-  u8 use_private_segment;
+  /** Segment type: if set to SSVM_N_TYPES, private segments are used */
+  ssvm_segment_type_t segment_type;
 
   /** Use one or more private mheaps, instead of the global heap */
   u32 private_segment_count;
@@ -93,13 +93,13 @@
 }
 
 segment_manager_t *segment_manager_new ();
-int
-segment_manager_init (segment_manager_t * sm, u32 props_index, u32 seg_size);
+int segment_manager_init (segment_manager_t * sm, u32 props_index,
+			  u32 seg_size, u32 evt_queue_size);
 
-void segment_manager_get_segment_info (u32 index, u8 ** name, u32 * size);
-int
-session_manager_add_first_segment (segment_manager_t * sm, u32 segment_size);
-int session_manager_add_segment (segment_manager_t * sm);
+svm_fifo_segment_private_t *segment_manager_get_segment (u32 segment_index);
+int segment_manager_add_first_segment (segment_manager_t * sm,
+				       u32 segment_size);
+int segment_manager_add_segment (segment_manager_t * sm);
 void segment_manager_del_sessions (segment_manager_t * sm);
 void segment_manager_del (segment_manager_t * sm);
 void segment_manager_init_del (segment_manager_t * sm);
@@ -112,8 +112,8 @@
 void
 segment_manager_dealloc_fifos (u32 svm_segment_index, svm_fifo_t * rx_fifo,
 			       svm_fifo_t * tx_fifo);
-svm_queue_t *segment_manager_alloc_queue (segment_manager_t *
-					  sm, u32 queue_size);
+svm_queue_t *segment_manager_alloc_queue (segment_manager_t * sm,
+					  u32 queue_size);
 void segment_manager_dealloc_queue (segment_manager_t * sm, svm_queue_t * q);
 void segment_manager_app_detach (segment_manager_t * sm);
 
diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c
index adcbb29..be98e71 100644
--- a/src/vnet/session/session.c
+++ b/src/vnet/session/session.c
@@ -961,32 +961,66 @@
 }
 
 /**
- * Allocate vpp event queue (once) per worker thread
+ * Allocate event queues in the shared-memory segment
+ *
+ * That can either be a newly created memfd segment, that will need to be
+ * mapped by all stack users, or the binary api's svm region. The latter is
+ * assumed to be already mapped. NOTE that this assumption DOES NOT hold if
+ * api clients bootstrap shm api over sockets (i.e. use memfd segments) and
+ * vpp uses api svm region for event queues.
  */
 void
-session_vpp_event_queue_allocate (session_manager_main_t * smm,
-				  u32 thread_index)
+session_vpp_event_queues_allocate (session_manager_main_t * smm)
 {
+  u32 evt_q_length = 2048, evt_size = sizeof (session_fifo_event_t);
+  ssvm_private_t *eqs = &smm->evt_qs_segment;
   api_main_t *am = &api_main;
+  u64 eqs_size = 64 << 20;
+  pid_t vpp_pid = getpid ();
   void *oldheap;
-  u32 event_queue_length = 2048;
+  int i;
 
-  if (smm->vpp_event_queues[thread_index] == 0)
+  if (smm->configured_event_queue_length)
+    evt_q_length = smm->configured_event_queue_length;
+
+  if (smm->evt_qs_use_memfd_seg)
     {
-      /* Allocate event fifo in the /vpe-api shared-memory segment */
-      oldheap = svm_push_data_heap (am->vlib_rp);
+      if (smm->evt_qs_segment_size)
+	eqs_size = smm->evt_qs_segment_size;
 
-      if (smm->configured_event_queue_length)
-	event_queue_length = smm->configured_event_queue_length;
+      eqs->ssvm_size = eqs_size;
+      eqs->i_am_master = 1;
+      eqs->my_pid = vpp_pid;
+      eqs->name = format (0, "%s%c", "evt-qs-segment", 0);
+      eqs->requested_va = smm->session_baseva;
 
-      smm->vpp_event_queues[thread_index] =
-	svm_queue_init
-	(event_queue_length,
-	 sizeof (session_fifo_event_t), 0 /* consumer pid */ ,
-	 0 /* (do not) send signal when queue non-empty */ );
-
-      svm_pop_heap (oldheap);
+      ssvm_master_init (eqs, SSVM_SEGMENT_MEMFD);
     }
+
+  if (smm->evt_qs_use_memfd_seg)
+    oldheap = ssvm_push_heap (eqs->sh);
+  else
+    oldheap = svm_push_data_heap (am->vlib_rp);
+
+  for (i = 0; i < vec_len (smm->vpp_event_queues); i++)
+    {
+      smm->vpp_event_queues[i] = svm_queue_init (evt_q_length, evt_size,
+						 vpp_pid, 0);
+    }
+
+  if (smm->evt_qs_use_memfd_seg)
+    ssvm_pop_heap (oldheap);
+  else
+    svm_pop_heap (oldheap);
+}
+
+ssvm_private_t *
+session_manager_get_evt_q_segment (void)
+{
+  session_manager_main_t *smm = &session_manager_main;
+  if (smm->evt_qs_use_memfd_seg)
+    return &smm->evt_qs_segment;
+  return 0;
 }
 
 /**
@@ -1076,10 +1110,6 @@
   if (num_threads < 1)
     return clib_error_return (0, "n_thread_stacks not set");
 
-  /* $$$ config parameters */
-  svm_fifo_segment_init (0x200000000ULL /* first segment base VA */ ,
-			 20 /* timeout in seconds */ );
-
   /* configure per-thread ** vectors */
   vec_validate (smm->sessions, num_threads - 1);
   vec_validate (smm->tx_buffers, num_threads - 1);
@@ -1117,9 +1147,12 @@
   vec_validate (smm->last_event_poll_by_thread, num_threads - 1);
 #endif
 
-  /* Allocate vpp event queues */
-  for (i = 0; i < vec_len (smm->vpp_event_queues); i++)
-    session_vpp_event_queue_allocate (smm, i);
+  /* Allocate vpp event queues segment and queue */
+  session_vpp_event_queues_allocate (smm);
+
+  /* Initialize fifo segment main baseva and timeout */
+  svm_fifo_segment_init (smm->session_baseva + smm->evt_qs_segment_size,
+			 smm->segment_timeout);
 
   /* Preallocate sessions */
   if (smm->preallocated_sessions)
@@ -1192,6 +1225,9 @@
 session_manager_main_init (vlib_main_t * vm)
 {
   session_manager_main_t *smm = &session_manager_main;
+  smm->session_baseva = 0x200000000ULL;
+  smm->segment_timeout = 20;
+  smm->evt_qs_segment_size = 64 << 20;
   smm->is_enabled = 0;
   return 0;
 }
@@ -1272,6 +1308,8 @@
       else if (unformat (input, "local-endpoints-table-buckets %d",
 			 &smm->local_endpoints_table_buckets))
 	;
+      else if (unformat (input, "evt_qs_memfd_seg"))
+	smm->evt_qs_use_memfd_seg = 1;
       else
 	return clib_error_return (0, "unknown input `%U'",
 				  format_unformat_error, input);
diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h
index 5e017c6..98e8acb 100644
--- a/src/vnet/session/session.h
+++ b/src/vnet/session/session.h
@@ -149,6 +149,9 @@
   /** vpp fifo event queue */
   svm_queue_t **vpp_event_queues;
 
+  /** Event queues memfd segment initialized only if so configured */
+  ssvm_private_t evt_qs_segment;
+
   /** Unique segment name counter */
   u32 unique_segment_name_counter;
 
@@ -170,7 +173,13 @@
    * Config parameters
    */
 
-  /** session table size parameters */
+  /** Session ssvm segment configs*/
+  uword session_baseva;
+  u32 segment_timeout;
+  u32 evt_qs_segment_size;
+  u8 evt_qs_use_memfd_seg;
+
+  /** Session table size parameters */
   u32 configured_v4_session_table_buckets;
   u32 configured_v4_session_table_memory;
   u32 configured_v4_halfopen_table_buckets;
@@ -443,6 +452,7 @@
 void session_send_session_evt_to_thread (u64 session_handle,
 					 fifo_event_type_t evt_type,
 					 u32 thread_index);
+ssvm_private_t *session_manager_get_evt_q_segment (void);
 
 u8 *format_stream_session (u8 * s, va_list * args);
 uword unformat_stream_session (unformat_input_t * input, va_list * args);
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index eeda839..5201ec6 100755
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -58,25 +58,54 @@
 _(SESSION_RULES_DUMP, session_rules_dump)				\
 
 static int
-send_add_segment_callback (u32 api_client_index, const u8 * segment_name,
-			   u32 segment_size)
+session_send_memfd_fd (vl_api_registration_t * reg, const ssvm_private_t * sp)
+{
+  clib_error_t *error;
+  if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
+    {
+      clib_warning ("can't send memfd fd");
+      return -1;
+    }
+  error = vl_api_send_fd_msg (reg, sp->fd);
+  if (error)
+    {
+      clib_error_report (error);
+      return -1;
+    }
+  return 0;
+}
+
+static int
+send_add_segment_callback (u32 api_client_index, const ssvm_private_t * sp)
 {
   vl_api_map_another_segment_t *mp;
-  svm_queue_t *q;
+  vl_api_registration_t *reg;
 
-  q = vl_api_client_index_to_input_queue (api_client_index);
+  reg = vl_mem_api_client_index_to_registration (api_client_index);
+  if (!reg)
+    {
+      clib_warning ("no registration: %u", api_client_index);
+      return -1;
+    }
 
-  if (!q)
-    return -1;
+  if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD
+      && vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
+    {
+      clib_warning ("can't send memfd fd");
+      return -1;
+    }
 
   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
   memset (mp, 0, sizeof (*mp));
   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
-  mp->segment_size = segment_size;
-  strncpy ((char *) mp->segment_name, (char *) segment_name,
+  mp->segment_size = sp->ssvm_size;
+  strncpy ((char *) mp->segment_name, (char *) sp->name,
 	   sizeof (mp->segment_name) - 1);
 
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
+
+  if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
+    return session_send_memfd_fd (reg, sp);
 
   return 0;
 }
@@ -84,20 +113,23 @@
 static int
 send_session_accept_callback (stream_session_t * s)
 {
-  vl_api_accept_session_t *mp;
-  svm_queue_t *q, *vpp_queue;
   application_t *server = application_get (s->app_index);
-  transport_connection_t *tc;
   transport_proto_vft_t *tp_vft;
+  vl_api_accept_session_t *mp;
+  vl_api_registration_t *reg;
+  transport_connection_t *tc;
   stream_session_t *listener;
+  svm_queue_t *vpp_queue;
 
-  q = vl_api_client_index_to_input_queue (server->api_client_index);
   vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
+  reg = vl_mem_api_client_index_to_registration (server->api_client_index);
+  if (!reg)
+    {
+      clib_warning ("no registration: %u", server->api_client_index);
+      return -1;
+    }
 
-  if (!q)
-    return -1;
-
-  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
+  mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
   memset (mp, 0, sizeof (*mp));
 
   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION);
@@ -123,7 +155,7 @@
   mp->port = tc->rmt_port;
   mp->is_ip4 = tc->is_ip4;
   clib_memcpy (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
 
   return 0;
 }
@@ -131,39 +163,43 @@
 static void
 send_session_disconnect_callback (stream_session_t * s)
 {
-  vl_api_disconnect_session_t *mp;
-  svm_queue_t *q;
   application_t *app = application_get (s->app_index);
+  vl_api_disconnect_session_t *mp;
+  vl_api_registration_t *reg;
 
-  q = vl_api_client_index_to_input_queue (app->api_client_index);
+  reg = vl_mem_api_client_index_to_registration (app->api_client_index);
+  if (!reg)
+    {
+      clib_warning ("no registration: %u", app->api_client_index);
+      return;
+    }
 
-  if (!q)
-    return;
-
-  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
+  mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
   memset (mp, 0, sizeof (*mp));
   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
   mp->handle = session_handle (s);
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
 }
 
 static void
 send_session_reset_callback (stream_session_t * s)
 {
-  vl_api_reset_session_t *mp;
-  svm_queue_t *q;
   application_t *app = application_get (s->app_index);
+  vl_api_registration_t *reg;
+  vl_api_reset_session_t *mp;
 
-  q = vl_api_client_index_to_input_queue (app->api_client_index);
+  reg = vl_mem_api_client_index_to_registration (app->api_client_index);
+  if (!reg)
+    {
+      clib_warning ("no registration: %u", app->api_client_index);
+      return;
+    }
 
-  if (!q)
-    return;
-
-  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
+  mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
   memset (mp, 0, sizeof (*mp));
   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SESSION);
   mp->handle = session_handle (s);
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
 }
 
 int
@@ -171,18 +207,20 @@
 				 stream_session_t * s, u8 is_fail)
 {
   vl_api_connect_session_reply_t *mp;
-  svm_queue_t *q;
-  application_t *app;
-  svm_queue_t *vpp_queue;
   transport_connection_t *tc;
+  vl_api_registration_t *reg;
+  svm_queue_t *vpp_queue;
+  application_t *app;
 
   app = application_get (app_index);
-  q = vl_api_client_index_to_input_queue (app->api_client_index);
+  reg = vl_mem_api_client_index_to_registration (app->api_client_index);
+  if (!reg)
+    {
+      clib_warning ("no registration: %u", app->api_client_index);
+      return -1;
+    }
 
-  if (!q)
-    return -1;
-
-  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
+  mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SESSION_REPLY);
   mp->context = api_context;
 
@@ -208,7 +246,7 @@
 done:
   mp->retval = is_fail ?
     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
-  vl_msg_api_send_shmem (q, (u8 *) & mp);
+  vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
   return 0;
 }
 
@@ -310,7 +348,9 @@
 vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
 {
   vl_api_application_attach_reply_t *rmp;
+  ssvm_private_t *segp, *evt_q_segment;
   vnet_app_attach_args_t _a, *a = &_a;
+  vl_api_registration_t *reg;
   clib_error_t *error = 0;
   int rv = 0;
 
@@ -354,18 +394,30 @@
   REPLY_MACRO2 (VL_API_APPLICATION_ATTACH_REPLY, ({
     if (!rv)
       {
+	segp = a->segment;
 	rmp->segment_name_length = 0;
-	rmp->segment_size = a->segment_size;
-	if (a->segment_name_length)
+	rmp->segment_size = segp->ssvm_size;
+	if (vec_len (segp->name))
 	  {
-	    memcpy (rmp->segment_name, a->segment_name,
-		    a->segment_name_length);
-	    rmp->segment_name_length = a->segment_name_length;
+	    memcpy (rmp->segment_name, segp->name, vec_len (segp->name));
+	    rmp->segment_name_length = vec_len (segp->name);
 	  }
 	rmp->app_event_queue_address = a->app_event_queue_address;
       }
   }));
   /* *INDENT-ON* */
+
+  if (rv)
+    return;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+
+  /* Send fifo segment fd if needed */
+  if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
+    session_send_memfd_fd (reg, a->segment);
+  /* Send event queues segment */
+  if ((evt_q_segment = session_manager_get_evt_q_segment ()))
+    session_send_memfd_fd (reg, evt_q_segment);
 }
 
 static void
diff --git a/src/vnet/session/session_test.c b/src/vnet/session/session_test.c
index 64657c1..a9a902d 100644
--- a/src/vnet/session/session_test.c
+++ b/src/vnet/session/session_test.c
@@ -103,7 +103,6 @@
 {
   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
   u64 options[APP_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
-  u8 segment_name[128];
   clib_error_t *error = 0;
   u32 server_index;
 
@@ -117,7 +116,6 @@
     .options = options,
     .namespace_id = 0,
     .session_cb_vft = &dummy_session_cbs,
-    .segment_name = segment_name,
   };
 
   error = vnet_application_attach (&attach_args);
@@ -178,7 +176,6 @@
   clib_error_t *error = 0;
   u8 *ns_id = format (0, "appns1"), intf_mac[6];
   app_namespace_t *app_ns;
-  u8 segment_name[128];
   application_t *server;
   stream_session_t *s;
   int code;
@@ -197,7 +194,6 @@
     .options = options,
     .namespace_id = 0,
     .session_cb_vft = &dummy_session_cbs,
-    .segment_name = segment_name,
   };
 
   vnet_bind_args_t bind_args = {
@@ -781,7 +777,7 @@
   transport_connection_t *tc;
   u32 dummy_port = 1111;
   clib_error_t *error = 0;
-  u8 segment_name[128], is_filtered = 0, *ns_id = format (0, "appns1");
+  u8 is_filtered = 0, *ns_id = format (0, "appns1");
   stream_session_t *listener, *s;
   app_namespace_t *default_ns = app_namespace_get_default ();
   u32 local_ns_index = default_ns->local_table_index;
@@ -809,7 +805,6 @@
     .options = options,
     .namespace_id = 0,
     .session_cb_vft = &dummy_session_cbs,
-    .segment_name = segment_name,
   };
 
   vnet_bind_args_t bind_args = {
@@ -1342,7 +1337,7 @@
   u32 server_index, app_index;
   u32 dummy_server_api_index = ~0, sw_if_index = 0;
   clib_error_t *error = 0;
-  u8 segment_name[128], intf_mac[6], sst, is_filtered = 0;
+  u8 intf_mac[6], sst, is_filtered = 0;
   stream_session_t *s;
   transport_connection_t *tc;
   u16 lcl_port = 1234, rmt_port = 4321;
@@ -1407,7 +1402,6 @@
     .options = options,
     .namespace_id = 0,
     .session_cb_vft = &dummy_session_cbs,
-    .segment_name = segment_name,
   };
 
   attach_args.api_client_index = dummy_server_api_index;