libmemif: version 2

Change-Id: Ia2532695aa9199d2a7b684aebef43df0b8235531
Signed-off-by: Jakub Grajciar <jgrajcia@cisco.com>
diff --git a/extras/libmemif/src/libmemif.h b/extras/libmemif/src/libmemif.h
index a14a102..14c4503 100644
--- a/extras/libmemif/src/libmemif.h
+++ b/extras/libmemif/src/libmemif.h
@@ -23,14 +23,12 @@
 #define _LIBMEMIF_H_
 
 /** Libmemif version. */
-#define LIBMEMIF_VERSION "1.0"
+#define LIBMEMIF_VERSION "2.0"
 /** Default name of application using libmemif. */
 #define MEMIF_DEFAULT_APP_NAME "libmemif-app"
 
 #include <inttypes.h>
 
-#include <memif.h>
-
 /*! Error codes */
 typedef enum
 {
@@ -95,10 +93,25 @@
 #define MEMIF_FD_EVENT_MOD   (1 << 4)
 /** @} */
 
-/** *brief Memif connection handle
+/** \brief Memif connection handle
     pointer of type void, pointing to internal structure
 */
 typedef void *memif_conn_handle_t;
+
+/** \brief Memif allocator alloc
+    @param size - requested allocation size
+
+    custom memory allocator: alloc function template
+*/
+typedef void *(memif_alloc_t) (size_t size);
+
+/** \brief Memif allocator free
+    @param size - requested allocation size
+
+    custom memory allocator: free function template
+*/
+typedef void (memif_free_t) (void *ptr);
+
 /**
  * @defgroup CALLBACKS Callback functions definitions
  * @ingroup libmemif
@@ -143,6 +156,15 @@
  * @{
  */
 
+#ifndef _MEMIF_H_
+typedef enum
+{
+  MEMIF_INTERFACE_MODE_ETHERNET = 0,
+  MEMIF_INTERFACE_MODE_IP = 1,
+  MEMIF_INTERFACE_MODE_PUNT_INJECT = 2,
+} memif_interface_mode_t;
+#endif /* _MEMIF_H_ */
+
 /** \brief Memif connection arguments
     @param socket_filename - socket filename
     @param secret - otional parameter used as interface autenthication
@@ -153,7 +175,6 @@
     @param is_master - 0 == master, 1 == slave
     @param interface_id - id used to identify peer connection
     @param interface_name - interface name
-    @param instance_name - application name
     @param mode - 0 == ethernet, 1 == ip , 2 == punt/inject
 */
 typedef struct
@@ -164,12 +185,11 @@
   uint8_t num_s2m_rings;	/*!< default = 1 */
   uint8_t num_m2s_rings;	/*!< default = 1 */
   uint16_t buffer_size;		/*!< default = 2048 */
-  memif_log2_ring_size_t log2_ring_size;	/*!< default = 10 (1024) */
+  uint8_t log2_ring_size;	/*!< default = 10 (1024) */
   uint8_t is_master;
 
-  memif_interface_id_t interface_id;
+  uint32_t interface_id;
   uint8_t interface_name[32];
-  uint8_t instance_name[32];	/*!< deprecated, will be removed in 2.0 */
   memif_interface_mode_t mode:8;
 } memif_conn_args_t;
 
@@ -182,15 +202,16 @@
 
 /** \brief Memif buffer
     @param desc_index - ring descriptor index
-    @param buffer_len - shared meory buffer length
-    @param data_len - data length
+    @param len - buffer length
+    @param flags - memif buffer flags
     @param data - pointer to shared memory data
 */
 typedef struct
 {
   uint16_t desc_index;
-  uint32_t buffer_len;
-  uint32_t data_len;
+  uint32_t len;
+#define MEMIF_BUFFER_FLAG_NEXT (1 << 0)
+  uint8_t flags;
   void *data;
 } memif_buffer_t;
 /** @} */
@@ -266,6 +287,12 @@
  * @{
  */
 
+/** \brief Memif get version
+
+    \return ((MEMIF_VERSION_MAJOR << 8) | MEMIF_VERSION_MINOR)
+*/
+uint16_t memif_get_version ();
+
 /** \biref Memif get queue event file descriptor
     @param conn - memif connection handle
     @param qid - queue id
@@ -309,6 +336,8 @@
 /** \brief Memif initialization
     @param on_control_fd_update - if control fd updates inform user to watch new fd
     @param app_name - application name (will be truncated to 32 chars)
+    @param memif_alloc - cutom memory allocator, NULL = default
+    @param memif_free - custom memory free, NULL = default
 
     if param on_control_fd_update is set to NULL,
     libmemif will handle file descriptor event polling
@@ -323,7 +352,8 @@
     \return memif_err_t
 */
 int memif_init (memif_control_fd_update_t * on_control_fd_update,
-		char *app_name);
+		char *app_name, memif_alloc_t * memif_alloc,
+		memif_free_t * memif_free);
 
 /** \brief Memif cleanup
 
@@ -398,7 +428,7 @@
     @param bufs - memif buffers
     @param count - number of memif buffers to allocate
     @param count_out - returns number of allocated buffers
-    @param size - minimal buffer size, 0 = standard buffer size
+    @param size - buffer size, may return chained buffers if size > buffer_size
 
     \return memif_err_t
 */
@@ -406,18 +436,15 @@
 			memif_buffer_t * bufs, uint16_t count,
 			uint16_t * count_out, uint16_t size);
 
-/** \brief Memif buffer free
+/** \brief Memif refill ring
     @param conn - memif conenction handle
     @param qid - number indentifying queue
-    @param bufs - memif buffers
-    @param count - number of memif buffers to free
-    @param count_out - returns number of freed buffers
+    @param count - number of buffers to be placed on ring
 
     \return memif_err_t
 */
-int memif_buffer_free (memif_conn_handle_t conn, uint16_t qid,
-		       memif_buffer_t * bufs, uint16_t count,
-		       uint16_t * count_out);
+int memif_refill_queue (memif_conn_handle_t conn, uint16_t qid,
+			uint16_t count);
 
 /** \brief Memif transmit buffer burst
     @param conn - memif conenction handle
diff --git a/extras/libmemif/src/main.c b/extras/libmemif/src/main.c
index cb24083..f83f710 100644
--- a/extras/libmemif/src/main.c
+++ b/extras/libmemif/src/main.c
@@ -166,6 +166,12 @@
   return memif_buf;
 }
 
+uint16_t
+memif_get_version ()
+{
+  return MEMIF_VERSION;
+}
+
 #define DBG_TX_BUF (0)
 #define DBG_RX_BUF (1)
 
@@ -191,7 +197,7 @@
 int
 memif_syscall_error_handler (int err_code)
 {
-  DBG_UNIX ("%s", strerror (err_code));
+  DBG ("%s", strerror (err_code));
 
   if (err_code == 0)
     return MEMIF_ERR_SUCCESS;
@@ -401,18 +407,45 @@
   lm->control_fd_update = cb;
 }
 
+static void
+memif_alloc_register (memif_alloc_t * ma)
+{
+  libmemif_main_t *lm = &libmemif_main;
+  lm->alloc = ma;
+}
+
+static void
+memif_free_register (memif_free_t * mf)
+{
+  libmemif_main_t *lm = &libmemif_main;
+  lm->free = mf;
+}
+
 int
-memif_init (memif_control_fd_update_t * on_control_fd_update, char *app_name)
+memif_init (memif_control_fd_update_t * on_control_fd_update, char *app_name,
+	    memif_alloc_t * memif_alloc, memif_free_t * memif_free)
 {
   int err = MEMIF_ERR_SUCCESS;	/* 0 */
   libmemif_main_t *lm = &libmemif_main;
   memset (lm, 0, sizeof (libmemif_main_t));
 
-  if (app_name)
+  if (memif_alloc != NULL)
     {
-      uint8_t len = (strlen (app_name) < MEMIF_NAME_LEN)
-	? MEMIF_NAME_LEN : strlen (app_name);
-      strncpy ((char *) lm->app_name, app_name, strlen (app_name));
+      memif_alloc_register (memif_alloc);
+    }
+  else
+    memif_alloc_register (malloc);
+
+  if (memif_free != NULL)
+    memif_free_register (memif_free);
+  else
+    memif_free_register (free);
+
+  if (app_name != NULL)
+    {
+      uint8_t len = (strlen (app_name) > MEMIF_NAME_LEN)
+	? strlen (app_name) : MEMIF_NAME_LEN;
+      strncpy ((char *) lm->app_name, app_name, len);
     }
   else
     {
@@ -443,13 +476,33 @@
   lm->pending_list_len = 1;
 
   lm->control_list =
-    malloc (sizeof (memif_list_elt_t) * lm->control_list_len);
+    lm->alloc (sizeof (memif_list_elt_t) * lm->control_list_len);
+  if (lm->control_list == NULL)
+    {
+      err = MEMIF_ERR_NOMEM;
+      goto error;
+    }
   lm->interrupt_list =
-    malloc (sizeof (memif_list_elt_t) * lm->interrupt_list_len);
+    lm->alloc (sizeof (memif_list_elt_t) * lm->interrupt_list_len);
+  if (lm->interrupt_list == NULL)
+    {
+      err = MEMIF_ERR_NOMEM;
+      goto error;
+    }
   lm->listener_list =
-    malloc (sizeof (memif_list_elt_t) * lm->listener_list_len);
+    lm->alloc (sizeof (memif_list_elt_t) * lm->listener_list_len);
+  if (lm->listener_list == NULL)
+    {
+      err = MEMIF_ERR_NOMEM;
+      goto error;
+    }
   lm->pending_list =
-    malloc (sizeof (memif_list_elt_t) * lm->pending_list_len);
+    lm->alloc (sizeof (memif_list_elt_t) * lm->pending_list_len);
+  if (lm->pending_list == NULL)
+    {
+      err = MEMIF_ERR_NOMEM;
+      goto error;
+    }
 
   int i;
   for (i = 0; i < lm->control_list_len; i++)
@@ -478,9 +531,8 @@
   lm->timerfd = timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK);
   if (lm->timerfd < 0)
     {
-      err = errno;
-      DBG ("timerfd: %s", strerror (err));
-      return memif_syscall_error_handler (err);
+      err = memif_syscall_error_handler (errno);
+      goto error;
     }
 
   lm->arm.it_value.tv_sec = 2;
@@ -491,10 +543,15 @@
   if (lm->control_fd_update (lm->timerfd, MEMIF_FD_EVENT_READ) < 0)
     {
       DBG ("callback type memif_control_fd_update_t error!");
-      return MEMIF_ERR_CB_FDUPDATE;
+      err = MEMIF_ERR_CB_FDUPDATE;
+      goto error;
     }
 
-  return 0;
+  return err;
+
+error:
+  memif_cleanup ();
+  return err;
 }
 
 static inline memif_ring_t *
@@ -520,8 +577,8 @@
   if (conn == NULL)
     return MEMIF_ERR_NOCONN;
   uint8_t num =
-    (conn->args.is_master) ? conn->run_args.num_s2m_rings : conn->
-    run_args.num_m2s_rings;
+    (conn->args.is_master) ? conn->run_args.num_s2m_rings : conn->run_args.
+    num_m2s_rings;
   if (qid >= num)
     return MEMIF_ERR_QID;
 
@@ -536,6 +593,7 @@
 	      memif_connection_update_t * on_disconnect,
 	      memif_interrupt_t * on_interrupt, void *private_ctx)
 {
+  libmemif_main_t *lm = &libmemif_main;
   int err, i, index, sockfd = -1;
   memif_list_elt_t list_elt;
   memif_connection_t *conn = (memif_connection_t *) * c;
@@ -544,16 +602,14 @@
       DBG ("This handle already points to existing memif.");
       return MEMIF_ERR_CONN;
     }
-  conn = (memif_connection_t *) malloc (sizeof (memif_connection_t));
+  conn = (memif_connection_t *) lm->alloc (sizeof (memif_connection_t));
   if (conn == NULL)
     {
-      err = memif_syscall_error_handler (errno);
+      err = MEMIF_ERR_NOMEM;
       goto error;
     }
   memset (conn, 0, sizeof (memif_connection_t));
 
-  libmemif_main_t *lm = &libmemif_main;
-
   conn->args.interface_id = args->interface_id;
 
   if (args->log2_ring_size == 0)
@@ -591,13 +647,14 @@
   strncpy ((char *) conn->args.interface_name, (char *) args->interface_name,
 	   l);
 
-  l = strlen ((char *) args->instance_name);
-  strncpy ((char *) conn->args.instance_name, (char *) args->instance_name,
-	   l);
-
   /* allocate and initialize socket_filename so it can be copyed to sun_path
      without memory leaks */
-  conn->args.socket_filename = malloc (sizeof (char *) * 108);
+  conn->args.socket_filename = lm->alloc (sizeof (char *) * 108);
+  if (conn->args.socket_filename == NULL)
+    {
+      err = MEMIF_ERR_NOMEM;
+      goto error;
+    }
   memset (conn->args.socket_filename, 0, 108 * sizeof (char *));
 
   if (args->socket_filename)
@@ -668,10 +725,20 @@
 		    return memif_syscall_error_handler (errno);
 		}
 	      DBG ("creating socket file");
-	      ms = malloc (sizeof (memif_socket_t));
+	      ms = lm->alloc (sizeof (memif_socket_t));
+	      if (ms == NULL)
+		{
+		  err = MEMIF_ERR_NOMEM;
+		  goto error;
+		}
 	      ms->filename =
-		malloc (strlen ((char *) conn->args.socket_filename) +
-			sizeof (char));
+		lm->alloc (strlen ((char *) conn->args.socket_filename) +
+			   sizeof (char));
+	      if (ms->filename == NULL)
+		{
+		  err = MEMIF_ERR_NOMEM;
+		  goto error;
+		}
 	      memset (ms->filename, 0,
 		      strlen ((char *) conn->args.socket_filename) +
 		      sizeof (char));
@@ -680,7 +747,13 @@
 		       strlen ((char *) conn->args.socket_filename));
 	      ms->interface_list_len = 1;
 	      ms->interface_list =
-		malloc (sizeof (memif_list_elt_t) * ms->interface_list_len);
+		lm->alloc (sizeof (memif_list_elt_t) *
+			   ms->interface_list_len);
+	      if (ms->interface_list == NULL)
+		{
+		  err = MEMIF_ERR_NOMEM;
+		  goto error;
+		}
 	      ms->interface_list[0].key = -1;
 	      ms->interface_list[0].data_struct = NULL;
 	      struct sockaddr_un un = { 0 };
@@ -772,9 +845,9 @@
     close (sockfd);
   sockfd = -1;
   if (conn->args.socket_filename)
-    free (conn->args.socket_filename);
+    lm->free (conn->args.socket_filename);
   if (conn != NULL)
-    free (conn);
+    lm->free (conn);
   *c = conn = NULL;
   return err;
 }
@@ -855,20 +928,21 @@
 	  if (((memif_connection_t *) e->data_struct)->on_interrupt != NULL)
 	    {
 	      num =
-		(((memif_connection_t *) e->data_struct)->
-		 args.is_master) ? ((memif_connection_t *) e->
-				    data_struct)->run_args.
-		num_s2m_rings : ((memif_connection_t *) e->data_struct)->
-		run_args.num_m2s_rings;
+		(((memif_connection_t *) e->data_struct)->args.
+		 is_master) ? ((memif_connection_t *) e->data_struct)->
+		run_args.num_s2m_rings : ((memif_connection_t *) e->
+					  data_struct)->run_args.
+		num_m2s_rings;
 	      for (i = 0; i < num; i++)
 		{
-		  if (((memif_connection_t *) e->data_struct)->
-		      rx_queues[i].int_fd == fd)
+		  if (((memif_connection_t *) e->data_struct)->rx_queues[i].
+		      int_fd == fd)
 		    {
-		      ((memif_connection_t *) e->data_struct)->
-			on_interrupt ((void *) e->data_struct,
-				      ((memif_connection_t *) e->
-				       data_struct)->private_ctx, i);
+		      ((memif_connection_t *) e->
+		       data_struct)->on_interrupt ((void *) e->data_struct,
+						   ((memif_connection_t *)
+						    e->data_struct)->
+						   private_ctx, i);
 		      return MEMIF_ERR_SUCCESS;
 		    }
 		}
@@ -895,24 +969,24 @@
 	  if (events & MEMIF_FD_EVENT_READ)
 	    {
 	      err =
-		((memif_connection_t *) e->data_struct)->
-		read_fn (e->data_struct);
+		((memif_connection_t *) e->data_struct)->read_fn (e->
+								  data_struct);
 	      if (err != MEMIF_ERR_SUCCESS)
 		return err;
 	    }
 	  if (events & MEMIF_FD_EVENT_WRITE)
 	    {
 	      err =
-		((memif_connection_t *) e->data_struct)->
-		write_fn (e->data_struct);
+		((memif_connection_t *) e->data_struct)->write_fn (e->
+								   data_struct);
 	      if (err != MEMIF_ERR_SUCCESS)
 		return err;
 	    }
 	  if (events & MEMIF_FD_EVENT_ERROR)
 	    {
 	      err =
-		((memif_connection_t *) e->data_struct)->
-		error_fn (e->data_struct);
+		((memif_connection_t *) e->data_struct)->error_fn (e->
+								   data_struct);
 	      if (err != MEMIF_ERR_SUCCESS)
 		return err;
 	    }
@@ -985,12 +1059,12 @@
 }
 
 static void
-memif_msg_queue_free (memif_msg_queue_elt_t ** e)
+memif_msg_queue_free (libmemif_main_t * lm, memif_msg_queue_elt_t ** e)
 {
   if (*e == NULL)
     return;
-  memif_msg_queue_free (&(*e)->next);
-  free (*e);
+  memif_msg_queue_free (lm, &(*e)->next);
+  lm->free (*e);
   *e = NULL;
   return;
 }
@@ -1029,8 +1103,8 @@
   if (c->tx_queues != NULL)
     {
       num =
-	(c->args.is_master) ? c->run_args.num_m2s_rings : c->
-	run_args.num_s2m_rings;
+	(c->args.is_master) ? c->run_args.num_m2s_rings : c->run_args.
+	num_s2m_rings;
       for (i = 0; i < num; i++)
 	{
 	  mq = &c->tx_queues[i];
@@ -1043,15 +1117,15 @@
 	      mq->int_fd = -1;
 	    }
 	}
-      free (c->tx_queues);
+      lm->free (c->tx_queues);
       c->tx_queues = NULL;
     }
 
   if (c->rx_queues != NULL)
     {
       num =
-	(c->args.is_master) ? c->run_args.num_s2m_rings : c->
-	run_args.num_m2s_rings;
+	(c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+	num_m2s_rings;
       for (i = 0; i < num; i++)
 	{
 	  mq = &c->rx_queues[i];
@@ -1068,7 +1142,7 @@
 	      mq->int_fd = -1;
 	    }
 	}
-      free (c->rx_queues);
+      lm->free (c->rx_queues);
       c->rx_queues = NULL;
     }
 
@@ -1079,13 +1153,13 @@
       if (c->regions[0].fd > 0)
 	close (c->regions[0].fd);
       c->regions[0].fd = -1;
-      free (c->regions);
+      lm->free (c->regions);
       c->regions = NULL;
     }
 
   memset (&c->run_args, 0, sizeof (memif_conn_run_args_t));
 
-  memif_msg_queue_free (&c->msg_queue);
+  memif_msg_queue_free (lm, &c->msg_queue);
 
   if (!(c->args.is_master))
     {
@@ -1094,7 +1168,7 @@
 	  if (timerfd_settime (lm->timerfd, 0, &lm->arm, NULL) < 0)
 	    {
 	      err = memif_syscall_error_handler (errno);
-	      DBG_UNIX ("timerfd_settime: arm");
+	      DBG ("timerfd_settime: arm");
 	    }
 	}
       lm->disconn_slaves++;
@@ -1145,11 +1219,11 @@
 			     c->listener_fd);
 	      close (c->listener_fd);
 	      c->listener_fd = ms->fd = -1;
-	      free (ms->interface_list);
+	      lm->free (ms->interface_list);
 	      ms->interface_list = NULL;
-	      free (ms->filename);
+	      lm->free (ms->filename);
 	      ms->filename = NULL;
-	      free (ms);
+	      lm->free (ms);
 	      ms = NULL;
 	    }
 	}
@@ -1168,10 +1242,10 @@
     }
 
   if (c->args.socket_filename)
-    free (c->args.socket_filename);
+    lm->free (c->args.socket_filename);
   c->args.socket_filename = NULL;
 
-  free (c);
+  lm->free (c);
   c = NULL;
 
   *conn = c;
@@ -1203,8 +1277,8 @@
     }
 
   num =
-    (c->args.is_master) ? c->run_args.num_m2s_rings : c->
-    run_args.num_s2m_rings;
+    (c->args.is_master) ? c->run_args.num_m2s_rings : c->run_args.
+    num_s2m_rings;
   for (i = 0; i < num; i++)
     {
       mq = &c->tx_queues[i];
@@ -1221,8 +1295,8 @@
 	}
     }
   num =
-    (c->args.is_master) ? c->run_args.num_s2m_rings : c->
-    run_args.num_m2s_rings;
+    (c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+    num_m2s_rings;
   for (i = 0; i < num; i++)
     {
       mq = &c->rx_queues[i];
@@ -1254,9 +1328,9 @@
   libmemif_main_t *lm = &libmemif_main;
   memif_list_elt_t e;
 
-  conn->regions = (memif_region_t *) malloc (sizeof (memif_region_t));
+  conn->regions = (memif_region_t *) lm->alloc (sizeof (memif_region_t));
   if (conn->regions == NULL)
-    return memif_syscall_error_handler (errno);
+    return MEMIF_ERR_NOMEM;
   r = conn->regions;
 
   buffer_offset =
@@ -1269,12 +1343,13 @@
     conn->run_args.buffer_size * (1 << conn->run_args.log2_ring_size) *
     (conn->run_args.num_s2m_rings + conn->run_args.num_m2s_rings);
 
-  if ((r->fd = memfd_create ("memif region 0", MFD_ALLOW_SEALING)) == -1)
+  if ((r->fd =
+       memif_memfd_create ("memif region 0", MFD_ALLOW_SEALING)) == -1)
     return memif_syscall_error_handler (errno);
-/*
-    if ((fcntl (r->fd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1)
-        return memif_syscall_error_handler (errno);
-*/
+
+  if ((fcntl (r->fd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1)
+    return memif_syscall_error_handler (errno);
+
   if ((ftruncate (r->fd, r->region_size)) == -1)
     return memif_syscall_error_handler (errno);
 
@@ -1295,7 +1370,7 @@
 	  ring->desc[j].region = 0;
 	  ring->desc[j].offset = buffer_offset +
 	    (uint32_t) (slot * conn->run_args.buffer_size);
-	  ring->desc[j].buffer_length = conn->run_args.buffer_size;
+	  ring->desc[j].length = conn->run_args.buffer_size;
 	}
     }
   for (i = 0; i < conn->run_args.num_m2s_rings; i++)
@@ -1314,15 +1389,15 @@
 	  ring->desc[j].region = 0;
 	  ring->desc[j].offset = buffer_offset +
 	    (uint32_t) (slot * conn->run_args.buffer_size);
-	  ring->desc[j].buffer_length = conn->run_args.buffer_size;
+	  ring->desc[j].length = conn->run_args.buffer_size;
 	}
     }
   memif_queue_t *mq;
   mq =
-    (memif_queue_t *) malloc (sizeof (memif_queue_t) *
-			      conn->run_args.num_s2m_rings);
+    (memif_queue_t *) lm->alloc (sizeof (memif_queue_t) *
+				 conn->run_args.num_s2m_rings);
   if (mq == NULL)
-    return memif_syscall_error_handler (errno);
+    return MEMIF_ERR_NOMEM;
   int x;
   for (x = 0; x < conn->run_args.num_s2m_rings; x++)
     {
@@ -1340,15 +1415,16 @@
       mq[x].offset =
 	(void *) mq[x].ring - (void *) conn->regions[mq->region].shm;
       mq[x].last_head = 0;
+      mq[x].last_tail = 0;
       mq[x].alloc_bufs = 0;
     }
   conn->tx_queues = mq;
 
   mq =
-    (memif_queue_t *) malloc (sizeof (memif_queue_t) *
-			      conn->run_args.num_m2s_rings);
+    (memif_queue_t *) lm->alloc (sizeof (memif_queue_t) *
+				 conn->run_args.num_m2s_rings);
   if (mq == NULL)
-    return memif_syscall_error_handler (errno);
+    return MEMIF_ERR_NOMEM;
   for (x = 0; x < conn->run_args.num_m2s_rings; x++)
     {
       if ((mq[x].int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
@@ -1365,6 +1441,7 @@
       mq[x].offset =
 	(void *) mq[x].ring - (void *) conn->regions[mq->region].shm;
       mq[x].last_head = 0;
+      mq[x].last_tail = 0;
       mq[x].alloc_bufs = 0;
     }
   conn->rx_queues = mq;
@@ -1378,101 +1455,102 @@
 		    uint16_t * count_out, uint16_t size)
 {
   memif_connection_t *c = (memif_connection_t *) conn;
-  if (c == NULL)
+  if (EXPECT_FALSE (c == NULL))
     return MEMIF_ERR_NOCONN;
-  if (c->fd < 0)
+  if (EXPECT_FALSE (c->fd < 0))
     return MEMIF_ERR_DISCONNECTED;
   uint8_t num =
-    (c->args.is_master) ? c->run_args.num_m2s_rings : c->
-    run_args.num_s2m_rings;
-  if (qid >= num)
+    (c->args.is_master) ? c->run_args.num_m2s_rings : c->run_args.
+    num_s2m_rings;
+  if (EXPECT_FALSE (qid >= num))
     return MEMIF_ERR_QID;
+  if (EXPECT_FALSE (!count_out))
+    return MEMIF_ERR_INVAL_ARG;
+
   memif_queue_t *mq = &c->tx_queues[qid];
   memif_ring_t *ring = mq->ring;
   memif_buffer_t *b0, *b1;
-  uint8_t chain_buf = 1;
   uint16_t mask = (1 << mq->log2_ring_size) - 1;
-  uint16_t head = ring->head;
-  uint16_t tail = ring->tail;
   uint16_t ring_size;
-  uint16_t s0, s1, ns;
-  *count_out = 0;
+  uint16_t slot, ns;
   int i, err = MEMIF_ERR_SUCCESS;	/* 0 */
+  uint16_t dst_left, src_left;
+  uint16_t saved_count;
+  memif_buffer_t *saved_b;
+  *count_out = 0;
 
   ring_size = (1 << mq->log2_ring_size);
-  ns = ring_size - head + tail;
+  ns = ring->tail - mq->last_tail;
+  mq->last_tail += ns;
+  slot = (c->args.is_master) ? ring->tail : ring->head;
+  slot += mq->alloc_bufs;
 
-  /* calculate number of chain buffers */
-  if (size > ring->desc[0].buffer_length)
-    {
-      chain_buf = size / ring->desc[0].buffer_length;
-      if (((size % ring->desc[0].buffer_length) != 0) || (size == 0))
-	chain_buf++;
-    }
+  if (c->args.is_master)
+    ns = ring->head + mq->alloc_bufs - ring->tail;
+  else
+    ns = ring_size - ring->head + mq->alloc_bufs + mq->last_tail;
 
   while (count && ns)
     {
-      while ((count > 2) && (ns > 2))
-	{
-	  s0 = (ring->head + mq->alloc_bufs) & mask;
-	  s1 = (ring->head + mq->alloc_bufs + chain_buf) & mask;
-
-	  if ((2 * chain_buf) > ns)
-	    break;
-
-	  b0 = (bufs + *count_out);
-	  b1 = (bufs + *count_out + 1);
-
-	  b0->desc_index = head + mq->alloc_bufs;
-	  b1->desc_index = head + mq->alloc_bufs + chain_buf;
-	  ring->desc[s0].flags = 0;
-	  ring->desc[s1].flags = 0;
-	  b0->buffer_len = ring->desc[s0].buffer_length * chain_buf;
-	  b1->buffer_len = ring->desc[s1].buffer_length * chain_buf;
-	  /* TODO: support multiple regions -> ring descriptor contains region index */
-	  b0->data = c->regions->shm + ring->desc[s0].offset;
-	  b1->data = c->regions->shm + ring->desc[s1].offset;
-
-	  for (i = 0; i < (chain_buf - 1); i++)
-	    {
-	      ring->desc[(s0 + i) & mask].flags |= MEMIF_DESC_FLAG_NEXT;
-	      ring->desc[(s1 + i) & mask].flags |= MEMIF_DESC_FLAG_NEXT;
-	      DBG ("allocating chained buffers");
-	    }
-
-	  mq->alloc_bufs += 2 * chain_buf;
-
-	  DBG ("allocated ring slots %u, %u", s0, s1);
-	  count -= 2;
-	  ns -= (2 * chain_buf);
-	  *count_out += 2;
-	}
-      s0 = (ring->head + mq->alloc_bufs) & mask;
-
       b0 = (bufs + *count_out);
 
-      if (chain_buf > ns)
-	break;
+      saved_b = b0;
+      saved_count = count;
 
-      b0->desc_index = head + mq->alloc_bufs;
-      ring->desc[s0].flags = 0;
-      b0->buffer_len = ring->desc[s0].buffer_length * chain_buf;
-      b0->data = c->regions->shm + ring->desc[s0].offset;
+      b0->desc_index = slot;
+      ring->desc[slot & mask].flags = 0;
 
-      for (i = 0; i < (chain_buf - 1); i++)
+      /* slave can produce buffer with original length */
+      dst_left = (c->args.is_master) ? ring->desc[slot & mask].length : c->run_args.buffer_size;	/* - headroom */
+      src_left = size;
+
+      while (src_left)
 	{
-	  ring->desc[(s0 + i) & mask].flags |= MEMIF_DESC_FLAG_NEXT;
-	  DBG ("allocating chained buffers");
+	  if (dst_left == 0)
+	    {
+	      if (count && ns)
+		{
+		  slot++;
+		  *count_out += 1;
+		  mq->alloc_bufs++;
+		  ns--;
+		  count--;
+
+		  ring->desc[b0->desc_index & mask].flags |=
+		    MEMIF_DESC_FLAG_NEXT;
+		  b0->flags |= MEMIF_BUFFER_FLAG_NEXT;
+
+		  b0 = (bufs + *count_out);
+		  b0->desc_index = slot;
+		  dst_left = (c->args.is_master) ? ring->desc[slot & mask].length : c->run_args.buffer_size;	/* - headroom */
+		  ring->desc[slot & mask].flags = 0;
+		}
+	      else
+		{
+		  /* rollback allocated chain buffers */
+		  memset (saved_b, 0, sizeof (memif_buffer_t)
+			  * (saved_count - count + 1));
+		  *count_out -= saved_count - count;
+		  mq->alloc_bufs = saved_count - count;
+		  goto no_ns;
+		}
+	    }
+	  b0->len = memif_min (dst_left, src_left);
+	  b0->data = memif_get_buffer (c, ring, slot & mask);
+
+	  src_left -= b0->len;
+	  dst_left -= b0->len;
 	}
 
-      mq->alloc_bufs += chain_buf;
-
-      DBG ("allocated ring slot %u", s0);
-      count--;
-      ns -= chain_buf;
+      slot++;
       *count_out += 1;
+      mq->alloc_bufs++;
+      ns--;
+      count--;
     }
 
+no_ns:
+
   DBG ("allocated: %u/%u bufs. Total %u allocated bufs", *count_out, count,
        mq->alloc_bufs);
 
@@ -1486,72 +1564,37 @@
 }
 
 int
-memif_buffer_free (memif_conn_handle_t conn, uint16_t qid,
-		   memif_buffer_t * bufs, uint16_t count,
-		   uint16_t * count_out)
+memif_refill_queue (memif_conn_handle_t conn, uint16_t qid, uint16_t count)
 {
   memif_connection_t *c = (memif_connection_t *) conn;
-  if (c == NULL)
+  if (EXPECT_FALSE (c == NULL))
     return MEMIF_ERR_NOCONN;
-  if (c->fd < 0)
+  if (EXPECT_FALSE (c->fd < 0))
     return MEMIF_ERR_DISCONNECTED;
   uint8_t num =
-    (c->args.is_master) ? c->run_args.num_s2m_rings : c->
-    run_args.num_m2s_rings;
-  if (qid >= num)
+    (c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+    num_m2s_rings;
+  if (EXPECT_FALSE (qid >= num))
     return MEMIF_ERR_QID;
   libmemif_main_t *lm = &libmemif_main;
   memif_queue_t *mq = &c->rx_queues[qid];
   memif_ring_t *ring = mq->ring;
-  uint16_t tail = ring->tail;
-  uint16_t mask = (1 << mq->log2_ring_size) - 1;
-  uint8_t chain_buf0, chain_buf1;
-  memif_buffer_t *b0, *b1;
-  *count_out = 0;
 
-  if (mq->alloc_bufs < count)
-    count = mq->alloc_bufs;
-
-  while (count)
+  if (c->args.is_master)
     {
-      while (count > 2)
-	{
-	  b0 = (bufs + *count_out);
-	  b1 = (bufs + *count_out + 1);
-	  chain_buf0 =
-	    b0->buffer_len / ring->desc[b0->desc_index & mask].buffer_length;
-	  if ((b0->buffer_len %
-	       ring->desc[b0->desc_index & mask].buffer_length) != 0)
-	    chain_buf0++;
-	  chain_buf1 =
-	    b1->buffer_len / ring->desc[b1->desc_index & mask].buffer_length;
-	  if ((b1->buffer_len %
-	       ring->desc[b1->desc_index & mask].buffer_length) != 0)
-	    chain_buf1++;
-	  tail = b1->desc_index + chain_buf1;
-	  b0->data = NULL;
-	  b1->data = NULL;
-
-	  count -= 2;
-	  *count_out += 2;
-	  mq->alloc_bufs -= chain_buf0 + chain_buf1;
-	}
-      b0 = (bufs + *count_out);
-      chain_buf0 =
-	b0->buffer_len / ring->desc[b0->desc_index & mask].buffer_length;
-      if ((b0->buffer_len %
-	   ring->desc[b0->desc_index & mask].buffer_length) != 0)
-	chain_buf0++;
-      tail = b0->desc_index + chain_buf0;
-      b0->data = NULL;
-
-      count--;
-      *count_out += 1;
-      mq->alloc_bufs -= chain_buf0;
+      MEMIF_MEMORY_BARRIER ();
+      ring->tail =
+	(ring->tail + count <=
+	 mq->last_head) ? ring->tail + count : mq->last_head;
     }
-  MEMIF_MEMORY_BARRIER ();
-  ring->tail = tail;
-  DBG ("tail: %u", ring->tail);
+  else
+    {
+      uint16_t head = ring->head;
+      uint16_t ns = (1 << mq->log2_ring_size) - head + mq->last_tail;
+      head += ns;
+      MEMIF_MEMORY_BARRIER ();
+      ring->head = (ring->head + count <= head) ? ring->head + count : head;
+    }
 
   return MEMIF_ERR_SUCCESS;	/* 0 */
 }
@@ -1561,213 +1604,49 @@
 		memif_buffer_t * bufs, uint16_t count, uint16_t * tx)
 {
   memif_connection_t *c = (memif_connection_t *) conn;
-  if (c == NULL)
+  if (EXPECT_FALSE (c == NULL))
     return MEMIF_ERR_NOCONN;
-  if (c->fd < 0)
+  if (EXPECT_FALSE (c->fd < 0))
     return MEMIF_ERR_DISCONNECTED;
   uint8_t num =
-    (c->args.is_master) ? c->run_args.num_m2s_rings : c->
-    run_args.num_s2m_rings;
-  if (qid >= num)
+    (c->args.is_master) ? c->run_args.num_m2s_rings : c->run_args.
+    num_s2m_rings;
+  if (EXPECT_FALSE (qid >= num))
     return MEMIF_ERR_QID;
+  if (EXPECT_FALSE (!tx))
+    return MEMIF_ERR_INVAL_ARG;
+
   memif_queue_t *mq = &c->tx_queues[qid];
   memif_ring_t *ring = mq->ring;
-  uint16_t head = ring->head;
-  uint16_t mask = (1 << mq->log2_ring_size) - 1;
-  uint8_t chain_buf0, chain_buf1;
-  *tx = 0;
+  uint16_t slot;
+
+  slot = (c->args.is_master) ? ring->tail : ring->head;
+  *tx = (count <= mq->alloc_bufs) ? count : mq->alloc_bufs;
+
+#ifdef MEMIF_DBG_SHM
   uint16_t curr_buf = 0;
-  memif_buffer_t *b0, *b1;
-  int i;
-
-  while (count)
+  uint16_t mask = (1 << mq->log2_ring_size) - 1;
+  memif_buffer_t *b0;
+  for (curr_buf = 0; curr_buf < count; curr_buf++)
     {
-      while (count > 2)
-	{
-	  b0 = (bufs + curr_buf);
-	  b1 = (bufs + curr_buf + 1);
-	  chain_buf0 =
-	    b0->buffer_len / ring->desc[b0->desc_index & mask].buffer_length;
-	  if ((b0->buffer_len %
-	       ring->desc[b0->desc_index & mask].buffer_length) != 0)
-	    chain_buf0++;
-
-	  chain_buf1 =
-	    b1->buffer_len / ring->desc[b1->desc_index & mask].buffer_length;
-	  if ((b1->buffer_len %
-	       ring->desc[b1->desc_index & mask].buffer_length) != 0)
-	    chain_buf1++;
-
-	  for (i = 0; i < memif_min (chain_buf0, chain_buf1); i++)
-	    {
-	      /* b0 */
-	      if (b0->data_len >
-		  ring->desc[(b0->desc_index + i) & mask].buffer_length)
-		{
-		  b0->data_len -=
-		    ring->desc[(b0->desc_index + i) & mask].length =
-		    ring->desc[(b0->desc_index + i) & mask].buffer_length;
-		}
-	      else
-		{
-		  ring->desc[(b0->desc_index + i) & mask].length =
-		    b0->data_len;
-		  b0->data_len = 0;
-		}
-	      /* b1 */
-	      if (b1->data_len >
-		  ring->desc[(b1->desc_index + i) & mask].buffer_length)
-		{
-		  b1->data_len -=
-		    ring->desc[(b1->desc_index + i) & mask].length =
-		    ring->desc[(b1->desc_index + i) & mask].buffer_length;
-		}
-	      else
-		{
-		  ring->desc[(b1->desc_index + i) & mask].length =
-		    b1->data_len;
-		  b1->data_len = 0;
-		}
-#ifdef MEMIF_DBG_SHM
-	      print_bytes (b0->data +
-			   ring->desc[(b0->desc_index +
-				       i) & mask].buffer_length *
-			   (chain_buf0 - 1),
-			   ring->desc[(b0->desc_index +
-				       i) & mask].buffer_length, DBG_TX_BUF);
-	      print_bytes (b1->data +
-			   ring->desc[(b1->desc_index +
-				       i) & mask].buffer_length *
-			   (chain_buf1 - 1),
-			   ring->desc[(b1->desc_index +
-				       i) & mask].buffer_length, DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	    }
-
-	  if (chain_buf0 > chain_buf1)
-	    {
-	      for (; i < chain_buf0; i++)
-		{
-		  if (b0->data_len >
-		      ring->desc[(b0->desc_index + i) & mask].buffer_length)
-		    {
-		      b0->data_len -=
-			ring->desc[(b0->desc_index + i) & mask].length =
-			ring->desc[(b0->desc_index + i) & mask].buffer_length;
-		    }
-		  else
-		    {
-		      ring->desc[(b0->desc_index + i) & mask].length =
-			b0->data_len;
-		      b0->data_len = 0;
-		    }
-#ifdef MEMIF_DBG_SHM
-		  print_bytes (b0->data +
-			       ring->desc[(b0->desc_index +
-					   i) & mask].buffer_length *
-			       (chain_buf0 - 1),
-			       ring->desc[(b0->desc_index +
-					   i) & mask].buffer_length,
-			       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-		}
-	    }
-	  else
-	    {
-	      for (; i < chain_buf1; i++)
-		{
-		  if (b1->data_len >
-		      ring->desc[(b1->desc_index + i) & mask].buffer_length)
-		    {
-		      b1->data_len -=
-			ring->desc[(b1->desc_index + i) & mask].length =
-			ring->desc[(b1->desc_index + i) & mask].buffer_length;
-		    }
-		  else
-		    {
-		      ring->desc[(b1->desc_index + i) & mask].length =
-			b1->data_len;
-		      b1->data_len = 0;
-		    }
-#ifdef MEMIF_DBG_SHM
-		  print_bytes (b1->data +
-			       ring->desc[(b1->desc_index +
-					   i) & mask].buffer_length *
-			       (chain_buf1 - 1),
-			       ring->desc[(b1->desc_index +
-					   i) & mask].buffer_length,
-			       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-		}
-	    }
-
-	  head = b1->desc_index + chain_buf1;
-
-	  b0->data = NULL;
-#ifdef MEMIF_DBG
-	  if (b0->data_len != 0)
-	    DBG ("invalid b0 data length!");
-#endif /* MEMIF_DBG */
-	  b1->data = NULL;
-#ifdef MEMIF_DBG
-	  if (b1->data_len != 0)
-	    DBG ("invalid b1 data length!");
-#endif /* MEMIF_DBG */
-
-	  count -= 2;
-	  *tx += chain_buf0 + chain_buf1;
-	  curr_buf += 2;
-	}
-
       b0 = (bufs + curr_buf);
-      chain_buf0 =
-	b0->buffer_len / ring->desc[b0->desc_index & mask].buffer_length;
-      if ((b0->buffer_len %
-	   ring->desc[b0->desc_index & mask].buffer_length) != 0)
-	chain_buf0++;
+      print_bytes (memif_get_buffer (c, ring, b0->desc_index & mask),
+		   ring->desc[b0->desc_index & mask].length, DBG_TX_BUF);
 
-      for (i = 0; i < chain_buf0; i++)
-	{
-	  if (b0->data_len >
-	      ring->desc[(b0->desc_index + i) & mask].buffer_length)
-	    {
-	      b0->data_len -= ring->desc[(b0->desc_index + i) & mask].length =
-		ring->desc[(b0->desc_index + i) & mask].buffer_length;
-	    }
-	  else
-	    {
-	      ring->desc[(b0->desc_index + i) & mask].length = b0->data_len;
-	      b0->data_len = 0;
-	    }
-#ifdef MEMIF_DBG_SHM
-	  print_bytes (b0->data +
-		       ring->desc[(b0->desc_index + i) & mask].buffer_length *
-		       (chain_buf0 - 1),
-		       ring->desc[(b0->desc_index + i) & mask].buffer_length,
-		       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	}
-
-      head = b0->desc_index + chain_buf0;
-
-      b0->data = NULL;
-#ifdef MEMIF_DBG
-      if (b0->data_len != 0)
-	DBG ("invalid b0 data length!");
-#endif /* MEMIF_DBG */
-
-      count--;
-      *tx += chain_buf0;
-      curr_buf++;
     }
+#endif /* MEMIF_DBG_SHM */
+
   MEMIF_MEMORY_BARRIER ();
-  ring->head = head;
+  if (c->args.is_master)
+    ring->tail = slot + *tx;
+  else
+    ring->head = slot + *tx;
+
+  /* zero out buffer fields so the client cant modify transmitted data */
+  memset (bufs, 0, sizeof (memif_buffer_t) * *tx);
 
   mq->alloc_bufs -= *tx;
 
-  /* TODO: return num of buffers and packets */
-  *tx = curr_buf;
-
   if ((ring->flags & MEMIF_RING_FLAG_MASK_INT) == 0)
     {
       uint64_t a = 1;
@@ -1784,154 +1663,70 @@
 		memif_buffer_t * bufs, uint16_t count, uint16_t * rx)
 {
   memif_connection_t *c = (memif_connection_t *) conn;
-  if (c == NULL)
+  if (EXPECT_FALSE (c == NULL))
     return MEMIF_ERR_NOCONN;
-  if (c->fd < 0)
+  if (EXPECT_FALSE (c->fd < 0))
     return MEMIF_ERR_DISCONNECTED;
   uint8_t num =
-    (c->args.is_master) ? c->run_args.num_s2m_rings : c->
-    run_args.num_m2s_rings;
-  if (qid >= num)
+    (c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+    num_m2s_rings;
+  if (EXPECT_FALSE (qid >= num))
     return MEMIF_ERR_QID;
+  if (EXPECT_FALSE (!rx))
+    return MEMIF_ERR_INVAL_ARG;
+
   memif_queue_t *mq = &c->rx_queues[qid];
   memif_ring_t *ring = mq->ring;
-  uint16_t head = ring->head;
+  uint16_t cur_slot, last_slot;
   uint16_t ns;
   uint16_t mask = (1 << mq->log2_ring_size) - 1;
   memif_buffer_t *b0, *b1;
-  uint16_t curr_buf = 0;
   *rx = 0;
-#ifdef MEMIF_DBG_SHM
-  int i;
-#endif /* MEMIF_DBG_SHM */
 
   uint64_t b;
   ssize_t r = read (mq->int_fd, &b, sizeof (b));
   if ((r == -1) && (errno != EAGAIN))
     return memif_syscall_error_handler (errno);
 
-  if (head == mq->last_head)
-    return 0;
+  cur_slot = (c->args.is_master) ? mq->last_head : mq->last_tail;
+  last_slot = (c->args.is_master) ? ring->head : ring->tail;
+  if (cur_slot == last_slot)
+    return MEMIF_ERR_SUCCESS;
 
-  ns = head - mq->last_head;
+  ns = last_slot - cur_slot;
 
   while (ns && count)
     {
-      while ((ns > 2) && (count > 2))
+      b0 = (bufs + *rx);
+
+      b0->desc_index = cur_slot;
+      b0->data = memif_get_buffer (c, ring, cur_slot & mask);
+      b0->len = ring->desc[cur_slot & mask].length;
+      /* slave resets buffer length */
+      if (c->args.is_master == 0)
 	{
-	  b0 = (bufs + curr_buf);
-	  b1 = (bufs + curr_buf + 1);
-
-	  b0->desc_index = mq->last_head;
-	  b0->data = memif_get_buffer (conn, ring, mq->last_head & mask);
-	  b0->data_len = ring->desc[mq->last_head & mask].length;
-	  b0->buffer_len = ring->desc[mq->last_head & mask].buffer_length;
-#ifdef MEMIF_DBG_SHM
-	  i = 0;
-	  print_bytes (b0->data +
-		       ring->desc[b0->desc_index & mask].buffer_length * i++,
-		       ring->desc[b0->desc_index & mask].buffer_length,
-		       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	  ns--;
-	  *rx += 1;
-	  while (ring->desc[mq->last_head & mask].
-		 flags & MEMIF_DESC_FLAG_NEXT)
-	    {
-	      ring->desc[mq->last_head & mask].flags &= ~MEMIF_DESC_FLAG_NEXT;
-	      mq->last_head++;
-	      b0->data_len += ring->desc[mq->last_head & mask].length;
-	      b0->buffer_len +=
-		ring->desc[mq->last_head & mask].buffer_length;
-#ifdef MEMIF_DBG_SHM
-	      print_bytes (b0->data +
-			   ring->desc[b0->desc_index & mask].buffer_length *
-			   i++,
-			   ring->desc[b0->desc_index & mask].buffer_length,
-			   DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	      ns--;
-	      *rx += 1;
-	    }
-	  mq->last_head++;
-
-	  b1->desc_index = mq->last_head;
-	  b1->data = memif_get_buffer (conn, ring, mq->last_head & mask);
-	  b1->data_len = ring->desc[mq->last_head & mask].length;
-	  b1->buffer_len = ring->desc[mq->last_head & mask].buffer_length;
-#ifdef MEMIF_DBG_SHM
-	  i = 0;
-	  print_bytes (b1->data +
-		       ring->desc[b1->desc_index & mask].buffer_length * i++,
-		       ring->desc[b1->desc_index & mask].buffer_length,
-		       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	  ns--;
-	  *rx += 1;
-	  while (ring->desc[mq->last_head & mask].
-		 flags & MEMIF_DESC_FLAG_NEXT)
-	    {
-	      ring->desc[mq->last_head & mask].flags &= ~MEMIF_DESC_FLAG_NEXT;
-	      mq->last_head++;
-	      b1->data_len += ring->desc[mq->last_head & mask].length;
-	      b1->buffer_len +=
-		ring->desc[mq->last_head & mask].buffer_length;
-#ifdef MEMIF_DBG_SHM
-	      print_bytes (b1->data +
-			   ring->desc[b1->desc_index & mask].buffer_length *
-			   i++,
-			   ring->desc[b1->desc_index & mask].buffer_length,
-			   DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	      ns--;
-	      *rx += 1;
-	    }
-	  mq->last_head++;
-
-	  count -= 2;
-	  curr_buf += 2;
+	  ring->desc[cur_slot & mask].length = c->run_args.buffer_size;
 	}
-      b0 = (bufs + curr_buf);
+      if (ring->desc[cur_slot & mask].flags & MEMIF_DESC_FLAG_NEXT)
+	{
+	  b0->flags = MEMIF_BUFFER_FLAG_NEXT;
+	  ring->desc[cur_slot & mask].flags &= ~MEMIF_DESC_FLAG_NEXT;
+	}
 
-      b0->desc_index = mq->last_head;
-      b0->data = memif_get_buffer (conn, ring, mq->last_head & mask);
-      b0->data_len = ring->desc[mq->last_head & mask].length;
-      b0->buffer_len = ring->desc[mq->last_head & mask].buffer_length;
 #ifdef MEMIF_DBG_SHM
-      i = 0;
-      print_bytes (b0->data +
-		   ring->desc[b0->desc_index & mask].buffer_length * i++,
-		   ring->desc[b0->desc_index & mask].buffer_length,
-		   DBG_TX_BUF);
+      print_bytes (b0->data, b0->len, DBG_RX_BUF);
 #endif /* MEMIF_DBG_SHM */
       ns--;
       *rx += 1;
 
-      while (ring->desc[mq->last_head & mask].flags & MEMIF_DESC_FLAG_NEXT)
-	{
-	  ring->desc[mq->last_head & mask].flags &= ~MEMIF_DESC_FLAG_NEXT;
-	  mq->last_head++;
-	  b0->data_len += ring->desc[mq->last_head & mask].length;
-	  b0->buffer_len += ring->desc[mq->last_head & mask].buffer_length;
-#ifdef MEMIF_DBG_SHM
-	  print_bytes (b0->data +
-		       ring->desc[b0->desc_index & mask].buffer_length * i++,
-		       ring->desc[b0->desc_index & mask].buffer_length,
-		       DBG_TX_BUF);
-#endif /* MEMIF_DBG_SHM */
-	  ns--;
-	  *rx += 1;
-	}
-      mq->last_head++;
-
       count--;
-      curr_buf++;
+      cur_slot++;
     }
 
-  mq->alloc_bufs += *rx;
-
-  /* TODO: return num of buffers and packets */
-  *rx = curr_buf;
+  if (c->args.is_master)
+    mq->last_head = cur_slot;
+  else
+    mq->last_tail = cur_slot;
 
   if (ns)
     {
@@ -1946,6 +1741,7 @@
 memif_get_details (memif_conn_handle_t conn, memif_details_t * md,
 		   char *buf, ssize_t buflen)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_connection_t *c = (memif_connection_t *) conn;
   if (c == NULL)
     return MEMIF_ERR_NOCONN;
@@ -1963,10 +1759,10 @@
   else
     err = MEMIF_ERR_NOBUF_DET;
 
-  l1 = strlen ((char *) c->args.instance_name);
+  l1 = strlen ((char *) lm->app_name);
   if (l0 + l1 < buflen)
     {
-      md->inst_name = strcpy (buf + l0, (char *) c->args.instance_name);
+      md->inst_name = strcpy (buf + l0, (char *) lm->app_name);
       l0 += l1 + 1;
     }
   else
@@ -2018,8 +1814,8 @@
     err = MEMIF_ERR_NOBUF_DET;
 
   md->rx_queues_num =
-    (c->args.is_master) ? c->run_args.num_s2m_rings : c->
-    run_args.num_m2s_rings;
+    (c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+    num_m2s_rings;
 
   l1 = sizeof (memif_queue_details_t) * md->rx_queues_num;
   if (l0 + l1 <= buflen)
@@ -2041,8 +1837,8 @@
     }
 
   md->tx_queues_num =
-    (c->args.is_master) ? c->run_args.num_m2s_rings : c->
-    run_args.num_s2m_rings;
+    (c->args.is_master) ? c->run_args.num_m2s_rings : c->run_args.
+    num_s2m_rings;
 
   l1 = sizeof (memif_queue_details_t) * md->tx_queues_num;
   if (l0 + l1 <= buflen)
@@ -2078,8 +1874,8 @@
   if (c->fd < 0)
     return MEMIF_ERR_DISCONNECTED;
   uint8_t num =
-    (c->args.is_master) ? c->run_args.num_s2m_rings : c->
-    run_args.num_m2s_rings;
+    (c->args.is_master) ? c->run_args.num_s2m_rings : c->run_args.
+    num_m2s_rings;
   if (qid >= num)
     return MEMIF_ERR_QID;
 
@@ -2093,16 +1889,16 @@
 {
   libmemif_main_t *lm = &libmemif_main;
   if (lm->control_list)
-    free (lm->control_list);
+    lm->free (lm->control_list);
   lm->control_list = NULL;
   if (lm->interrupt_list)
-    free (lm->interrupt_list);
+    lm->free (lm->interrupt_list);
   lm->interrupt_list = NULL;
   if (lm->listener_list)
-    free (lm->listener_list);
+    lm->free (lm->listener_list);
   lm->listener_list = NULL;
   if (lm->pending_list)
-    free (lm->pending_list);
+    lm->free (lm->pending_list);
   lm->pending_list = NULL;
   if (poll_cancel_fd != -1)
     close (poll_cancel_fd);
diff --git a/extras/libmemif/src/memif.h b/extras/libmemif/src/memif.h
index 11918ea..38b5402 100644
--- a/extras/libmemif/src/memif.h
+++ b/extras/libmemif/src/memif.h
@@ -22,8 +22,8 @@
 #define MEMIF_CACHELINE_SIZE 64
 #endif
 
-#define MEMIF_COOKIE		0x3E31F10
-#define MEMIF_VERSION_MAJOR	1
+#define MEMIF_COOKIE		0x3E31F20
+#define MEMIF_VERSION_MAJOR	2
 #define MEMIF_VERSION_MINOR	0
 #define MEMIF_VERSION		((MEMIF_VERSION_MAJOR << 8) | MEMIF_VERSION_MINOR)
 
@@ -58,7 +58,7 @@
 } memif_interface_mode_t;
 
 typedef uint16_t memif_region_index_t;
-typedef uint64_t memif_region_offset_t;
+typedef uint32_t memif_region_offset_t;
 typedef uint64_t memif_region_size_t;
 typedef uint16_t memif_ring_index_t;
 typedef uint32_t memif_interface_id_t;
@@ -148,15 +148,13 @@
   uint16_t flags;
 #define MEMIF_DESC_FLAG_NEXT (1 << 0)
   memif_region_index_t region;
-  uint32_t buffer_length;
   uint32_t length;
-  uint8_t reserved[4];
   memif_region_offset_t offset;
-  uint64_t metadata;
+  uint32_t metadata;
 } memif_desc_t;
 
-_Static_assert (sizeof (memif_desc_t) == 32,
-		"Size of memif_dsct_t must be 32");
+_Static_assert (sizeof (memif_desc_t) == 16,
+		"Size of memif_dsct_t must be 16 bytes");
 
 #define MEMIF_CACHELINE_ALIGN_MARK(mark) \
   uint8_t mark[0] __attribute__((aligned(MEMIF_CACHELINE_SIZE)))
diff --git a/extras/libmemif/src/memif_private.h b/extras/libmemif/src/memif_private.h
index a512ed4..b1039f9 100644
--- a/extras/libmemif/src/memif_private.h
+++ b/extras/libmemif/src/memif_private.h
@@ -28,6 +28,7 @@
 #include <sys/timerfd.h>
 #include <string.h>
 
+#include <memif.h>
 #include <libmemif.h>
 
 #define MEMIF_NAME_LEN 32
@@ -45,43 +46,23 @@
 #define MEMIF_MAX_M2S_RING		255
 #define MEMIF_MAX_S2M_RING		255
 #define MEMIF_MAX_REGION		255
-#define MEMIF_MAX_LOG2_RING_SIZE	15
+#define MEMIF_MAX_LOG2_RING_SIZE	14
 
 #define MEMIF_MAX_FDS 512
 
 #define memif_min(a,b) (((a) < (b)) ? (a) : (b))
 
+#define EXPECT_TRUE(x) __builtin_expect((x),1)
+#define EXPECT_FALSE(x) __builtin_expect((x),0)
+
 #ifdef MEMIF_DBG
 #define DBG(...) do {                                                             \
                         printf("MEMIF_DEBUG:%s:%s:%d: ", __FILE__, __func__, __LINE__);  \
                         printf(__VA_ARGS__);                                            \
                         printf("\n");                                                   \
                         } while (0)
-
-#define DBG_UNIX(...) do {                                                        \
-                      printf("MEMIF_DEBUG_UNIX:%s:%s:%d: ", __FILE__, __func__, __LINE__);  \
-                      printf(__VA_ARGS__);                                    \
-                      printf("\n");                                           \
-                      } while (0)
-
-#define error_return_unix(...) do {                                             \
-                                DBG_UNIX(__VA_ARGS__);                          \
-                                return -1;                                      \
-                                } while (0)
-#define error_return(...) do {                                                  \
-                            DBG(__VA_ARGS__);                                   \
-                            return -1;                                          \
-                            } while (0)
 #else
 #define DBG(...)
-#define DBG_UNIX(...)
-#define error_return_unix(...) do {                                             \
-                                return -1;                                      \
-                                } while (0)
-#define error_return(...) do {                                                  \
-                            return -1;                                          \
-                            } while (0)
-
 #endif /* MEMIF_DBG */
 
 typedef struct
@@ -160,18 +141,12 @@
 #define MEMIF_CONNECTION_FLAG_WRITE (1 << 0)
 } memif_connection_t;
 
-/*
- * WIP
- */
 typedef struct
 {
-  int key;			/* fd or id */
+  int key;
   void *data_struct;
 } memif_list_elt_t;
 
-/*
- * WIP
- */
 typedef struct
 {
   int fd;
@@ -181,10 +156,6 @@
   memif_list_elt_t *interface_list;	/* memif master interfaces listening on this socket */
 } memif_socket_t;
 
-/*
- * WIP
- */
-/* probably function like memif_cleanup () will need to be called to close timerfd */
 typedef struct
 {
   memif_control_fd_update_t *control_fd_update;
@@ -193,8 +164,8 @@
   uint16_t disconn_slaves;
   uint8_t app_name[MEMIF_NAME_LEN];
 
-  /* master implementation... */
-  memif_socket_t ms;
+  memif_alloc_t *alloc;
+  memif_free_t *free;
 
   uint16_t control_list_len;
   uint16_t interrupt_list_len;
@@ -244,7 +215,7 @@
 
 #ifndef HAVE_MEMFD_CREATE
 static inline int
-memfd_create (const char *name, unsigned int flags)
+memif_memfd_create (const char *name, unsigned int flags)
 {
   return syscall (__NR_memfd_create, name, flags);
 }
diff --git a/extras/libmemif/src/socket.c b/extras/libmemif/src/socket.c
index 2be40f8..8f18d89 100644
--- a/extras/libmemif/src/socket.c
+++ b/extras/libmemif/src/socket.c
@@ -32,6 +32,7 @@
 
 #include <socket.h>
 #include <memif.h>
+#include <memif_private.h>
 
 /* sends msg to socket */
 static_fn int
@@ -70,8 +71,9 @@
 static_fn int
 memif_msg_enq_ack (memif_connection_t * c)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
 
@@ -121,8 +123,9 @@
 static_fn int
 memif_msg_enq_init (memif_connection_t * c)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
   memset (e, 0, sizeof (memif_msg_queue_elt_t));
@@ -136,8 +139,8 @@
   i->id = c->args.interface_id;
   i->mode = c->args.mode;
 
-  strncpy ((char *) i->name, (char *) c->args.instance_name,
-	   strlen ((char *) c->args.instance_name));
+  strncpy ((char *) i->name, (char *) lm->app_name,
+	   strlen ((char *) lm->app_name));
   if (c->args.secret)
     strncpy ((char *) i->secret, (char *) c->args.secret, sizeof (i->secret));
 
@@ -162,11 +165,12 @@
 static_fn int
 memif_msg_enq_add_region (memif_connection_t * c, uint8_t region_index)
 {
+  libmemif_main_t *lm = &libmemif_main;
   /* maybe check if region is valid? */
   memif_region_t *mr = &c->regions[region_index];
 
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
 
@@ -199,8 +203,9 @@
 static_fn int
 memif_msg_enq_add_ring (memif_connection_t * c, uint8_t index, uint8_t dir)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
 
@@ -244,8 +249,9 @@
 static_fn int
 memif_msg_enq_connect (memif_connection_t * c)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
 
@@ -278,8 +284,9 @@
 static_fn int
 memif_msg_enq_connected (memif_connection_t * c)
 {
+  libmemif_main_t *lm = &libmemif_main;
   memif_msg_queue_elt_t *e =
-    (memif_msg_queue_elt_t *) malloc (sizeof (memif_msg_queue_elt_t));
+    (memif_msg_queue_elt_t *) lm->alloc (sizeof (memif_msg_queue_elt_t));
   if (e == NULL)
     return memif_syscall_error_handler (errno);
 
@@ -519,7 +526,7 @@
       mq =
 	(memif_queue_t *) realloc (c->rx_queues,
 				   sizeof (memif_queue_t) * (ar->index + 1));
-	memset(mq, 0, sizeof (memif_queue_t) * (ar->index + 1));
+      memset (mq, 0, sizeof (memif_queue_t) * (ar->index + 1));
       if (mq == NULL)
 	return memif_syscall_error_handler (errno);
       c->rx_queues = mq;
@@ -539,7 +546,7 @@
       mq =
 	(memif_queue_t *) realloc (c->tx_queues,
 				   sizeof (memif_queue_t) * (ar->index + 1));
-	memset(mq, 0, sizeof (memif_queue_t) * (ar->index + 1));
+      memset (mq, 0, sizeof (memif_queue_t) * (ar->index + 1));
       if (mq == NULL)
 	return memif_syscall_error_handler (errno);
       c->tx_queues = mq;
@@ -579,6 +586,9 @@
 	  add_list_elt (&elt, &lm->interrupt_list, &lm->interrupt_list_len);
 
 	  lm->control_fd_update (c->rx_queues[i].int_fd, MEMIF_FD_EVENT_READ);
+
+	  /* refill ring buffers */
+	  memif_refill_queue ((void *) c, i, -1);
 	}
 
     }
@@ -607,7 +617,12 @@
   if (c->on_interrupt != NULL)
     {
       for (i = 0; i < c->run_args.num_s2m_rings; i++)
-	lm->control_fd_update (c->rx_queues[i].int_fd, MEMIF_FD_EVENT_READ);
+	{
+	  lm->control_fd_update (c->rx_queues[i].int_fd, MEMIF_FD_EVENT_READ);
+
+	  /* refill ring buffers */
+	  memif_refill_queue ((void *) c, i, -1);
+	}
     }
 
   c->on_connect ((void *) c, c->private_ctx);
@@ -814,6 +829,7 @@
 int
 memif_conn_fd_write_ready (memif_connection_t * c)
 {
+  libmemif_main_t *lm = &libmemif_main;
   int err = MEMIF_ERR_SUCCESS;	/* 0 */
 
 
@@ -834,7 +850,7 @@
         MEMIF_FD_EVENT_READ | MEMIF_FD_EVENT_WRITE | MEMIF_FD_EVENT_MOD);
 */
   err = memif_msg_send (c->fd, &e->msg, e->fd);
-  free (e);
+  lm->free (e);
   goto done;
 
 done: