Shared memory packet interface (memif) library

Change-Id: I5097462ae85acd705f19e92517c01094dba7565f
Signed-off-by: Jakub Grajciar <grajciar.jakub@gmail.com>
diff --git a/extras/libmemif/test/main_test.c b/extras/libmemif/test/main_test.c
new file mode 100644
index 0000000..deb8acb
--- /dev/null
+++ b/extras/libmemif/test/main_test.c
@@ -0,0 +1,1079 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <main_test.h>
+
+#include <memif_private.h>
+
+#define SOCKET_FILENAME "/run/vpp/memif.sock"
+
+uint8_t ready_called;
+#define read_call  (1 << 0)
+#define write_call (1 << 1)
+#define error_call (1 << 2)
+
+int
+read_fn (memif_connection_t * c)
+{
+  ready_called |= read_call;
+  return 0;
+}
+
+int
+write_fn (memif_connection_t * c)
+{
+  ready_called |= write_call;
+  return 0;
+}
+
+int
+error_fn (memif_connection_t * c)
+{
+  ready_called |= error_call;
+  return 0;
+}
+
+static void
+register_fd_ready_fn (memif_connection_t * c,
+		      memif_fn * read_fn, memif_fn * write_fn,
+		      memif_fn * error_fn)
+{
+  c->read_fn = read_fn;
+  c->write_fn = write_fn;
+  c->error_fn = error_fn;
+}
+
+START_TEST (test_init)
+{
+  int err;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  ck_assert_ptr_ne (lm, NULL);
+  ck_assert_ptr_ne (lm->control_fd_update, NULL);
+  ck_assert_int_gt (lm->timerfd, 2);
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+}
+
+END_TEST
+START_TEST (test_init_epoll)
+{
+  int err;
+
+  if ((err = memif_init (NULL, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  ck_assert_ptr_ne (lm, NULL);
+  ck_assert_ptr_ne (lm->control_fd_update, NULL);
+  ck_assert_int_gt (lm->timerfd, 2);
+  ck_assert_int_gt (memif_epfd, -1);
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+}
+
+END_TEST
+START_TEST (test_create)
+{
+  int err;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  ck_assert_ptr_ne (c, NULL);
+
+  ck_assert_uint_eq (c->args.interface_id, args.interface_id);
+  ck_assert_uint_eq (c->args.is_master, args.is_master);
+  ck_assert_uint_eq (c->args.mode, args.mode);
+
+  ck_assert_uint_eq (c->args.num_s2m_rings, MEMIF_DEFAULT_TX_QUEUES);
+  ck_assert_uint_eq (c->args.num_m2s_rings, MEMIF_DEFAULT_RX_QUEUES);
+  ck_assert_uint_eq (c->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  ck_assert_uint_eq (c->args.log2_ring_size, MEMIF_DEFAULT_LOG2_RING_SIZE);
+
+  ck_assert_ptr_eq (c->msg_queue, NULL);
+  ck_assert_ptr_eq (c->regions, NULL);
+  ck_assert_ptr_eq (c->tx_queues, NULL);
+  ck_assert_ptr_eq (c->rx_queues, NULL);
+
+  ck_assert_int_eq (c->fd, -1);
+
+  ck_assert_ptr_ne (c->on_connect, NULL);
+  ck_assert_ptr_ne (c->on_disconnect, NULL);
+  ck_assert_ptr_ne (c->on_interrupt, NULL);
+
+  ck_assert_str_eq (c->args.interface_name, args.interface_name);
+  ck_assert_str_eq (c->args.instance_name, args.instance_name);
+  ck_assert_str_eq (c->args.socket_filename, SOCKET_FILENAME);
+
+  struct itimerspec timer;
+  timerfd_gettime (lm->timerfd, &timer);
+
+  ck_assert_msg (timer.it_interval.tv_sec == lm->arm.it_interval.tv_sec,
+		 "timerfd not armed!");
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_create_master)
+{
+  int err, rv;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.is_master = 1;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  ck_assert_ptr_ne (c, NULL);
+
+  ck_assert_uint_eq (c->args.interface_id, args.interface_id);
+  ck_assert_uint_eq (c->args.is_master, args.is_master);
+  ck_assert_uint_eq (c->args.mode, args.mode);
+
+  ck_assert_uint_eq (c->args.num_s2m_rings, MEMIF_DEFAULT_TX_QUEUES);
+  ck_assert_uint_eq (c->args.num_m2s_rings, MEMIF_DEFAULT_RX_QUEUES);
+  ck_assert_uint_eq (c->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  ck_assert_uint_eq (c->args.log2_ring_size, MEMIF_DEFAULT_LOG2_RING_SIZE);
+
+  ck_assert_ptr_eq (c->msg_queue, NULL);
+  ck_assert_ptr_eq (c->regions, NULL);
+  ck_assert_ptr_eq (c->tx_queues, NULL);
+  ck_assert_ptr_eq (c->rx_queues, NULL);
+
+  ck_assert_int_eq (c->fd, -1);
+
+  ck_assert_ptr_ne (c->on_connect, NULL);
+  ck_assert_ptr_ne (c->on_disconnect, NULL);
+  ck_assert_ptr_ne (c->on_interrupt, NULL);
+
+  ck_assert_str_eq (c->args.interface_name, args.interface_name);
+  ck_assert_str_eq (c->args.instance_name, args.instance_name);
+  ck_assert_str_eq (c->args.socket_filename, SOCKET_FILENAME);
+
+  struct stat file_stat;
+
+  rv = stat (SOCKET_FILENAME, &file_stat);
+  ck_assert_int_eq (rv, 0);
+
+  ck_assert (S_ISSOCK (file_stat.st_mode));
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_create_mult)
+{
+  int err;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_handle_t conn1 = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  args.interface_id = 1;
+
+  if ((err = memif_create (&conn1, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+  memif_connection_t *c1 = (memif_connection_t *) conn1;
+
+  ck_assert_ptr_ne (c, NULL);
+  ck_assert_ptr_ne (c1, NULL);
+
+  ck_assert_uint_eq (c->args.interface_id, 0);
+  ck_assert_uint_eq (c->args.is_master, args.is_master);
+  ck_assert_uint_eq (c->args.mode, args.mode);
+  ck_assert_uint_eq (c1->args.interface_id, 1);
+  ck_assert_uint_eq (c1->args.is_master, args.is_master);
+  ck_assert_uint_eq (c1->args.mode, args.mode);
+
+  ck_assert_uint_eq (c->args.num_s2m_rings, MEMIF_DEFAULT_TX_QUEUES);
+  ck_assert_uint_eq (c->args.num_m2s_rings, MEMIF_DEFAULT_RX_QUEUES);
+  ck_assert_uint_eq (c->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  ck_assert_uint_eq (c->args.log2_ring_size, MEMIF_DEFAULT_LOG2_RING_SIZE);
+  ck_assert_uint_eq (c1->args.num_s2m_rings, MEMIF_DEFAULT_TX_QUEUES);
+  ck_assert_uint_eq (c1->args.num_m2s_rings, MEMIF_DEFAULT_RX_QUEUES);
+  ck_assert_uint_eq (c1->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  ck_assert_uint_eq (c1->args.log2_ring_size, MEMIF_DEFAULT_LOG2_RING_SIZE);
+
+  ck_assert_ptr_eq (c->msg_queue, NULL);
+  ck_assert_ptr_eq (c->regions, NULL);
+  ck_assert_ptr_eq (c->tx_queues, NULL);
+  ck_assert_ptr_eq (c->rx_queues, NULL);
+  ck_assert_ptr_eq (c1->msg_queue, NULL);
+  ck_assert_ptr_eq (c1->regions, NULL);
+  ck_assert_ptr_eq (c1->tx_queues, NULL);
+  ck_assert_ptr_eq (c1->rx_queues, NULL);
+
+  ck_assert_int_eq (c->fd, -1);
+  ck_assert_int_eq (c1->fd, -1);
+
+  ck_assert_ptr_ne (c->on_connect, NULL);
+  ck_assert_ptr_ne (c->on_disconnect, NULL);
+  ck_assert_ptr_ne (c->on_interrupt, NULL);
+  ck_assert_ptr_ne (c1->on_connect, NULL);
+  ck_assert_ptr_ne (c1->on_disconnect, NULL);
+  ck_assert_ptr_ne (c1->on_interrupt, NULL);
+
+  ck_assert_str_eq (c->args.interface_name, args.interface_name);
+  ck_assert_str_eq (c->args.instance_name, args.instance_name);
+  ck_assert_str_eq (c->args.socket_filename, SOCKET_FILENAME);
+  ck_assert_str_eq (c1->args.interface_name, args.interface_name);
+  ck_assert_str_eq (c1->args.instance_name, args.instance_name);
+  ck_assert_str_eq (c1->args.socket_filename, SOCKET_FILENAME);
+
+  struct itimerspec timer;
+  timerfd_gettime (lm->timerfd, &timer);
+
+  ck_assert_msg (timer.it_interval.tv_sec == lm->arm.it_interval.tv_sec,
+		 "timerfd not armed!");
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_control_fd_handler)
+{
+  int err;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  if ((err =
+       memif_control_fd_handler (lm->timerfd,
+				 MEMIF_FD_EVENT_READ)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_NO_FILE, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+
+  register_fd_ready_fn (c, read_fn, write_fn, error_fn);
+  c->fd = 69;
+  lm->control_list[0].key = c->fd;
+  lm->control_list[0].data_struct = c;
+
+  if ((err =
+       memif_control_fd_handler (c->fd,
+				 MEMIF_FD_EVENT_READ)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert (ready_called & read_call);
+
+  if ((err =
+       memif_control_fd_handler (c->fd,
+				 MEMIF_FD_EVENT_WRITE)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert (ready_called & write_call);
+
+  if ((err =
+       memif_control_fd_handler (c->fd,
+				 MEMIF_FD_EVENT_ERROR)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert (ready_called & error_call);
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_buffer_alloc)
+{
+  int err, i;
+  uint8_t qid;
+  uint16_t buf;
+  memif_buffer_t *bufs;
+  uint16_t max_buf = 10;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  c->fd = 69;
+
+  /* test buffer allocation qid 0 (positive) */
+
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  qid = 0;
+  if ((err =
+       memif_buffer_alloc (conn, qid, bufs, max_buf,
+			   &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_uint_eq (bufs[i].buffer_len, MEMIF_DEFAULT_BUFFER_SIZE);
+
+  /* test buffer allocation qid 1 (positive) */
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  qid = 1;
+  if ((err =
+       memif_buffer_alloc (conn, qid, bufs, max_buf,
+			   &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_uint_eq (bufs[i].buffer_len, MEMIF_DEFAULT_BUFFER_SIZE);
+
+  /* test buffer allocation qid 2 (negative) */
+
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  qid = 2;
+  if ((err =
+       memif_buffer_alloc (conn, qid, bufs, max_buf,
+			   &buf)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_QID, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  free (bufs);
+  bufs = NULL;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_tx_burst)
+{
+  int err, i;
+  uint16_t max_buf = 10, buf, tx;
+  uint8_t qid;
+  memif_buffer_t *bufs;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  c->fd = 69;
+
+  /* test transmit qid 0 (positive) */
+
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+  qid = 0;
+  if ((err =
+       memif_buffer_alloc (conn, qid, bufs, max_buf,
+			   &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_uint_eq (bufs[i].buffer_len, MEMIF_DEFAULT_BUFFER_SIZE);
+
+  if ((err =
+       memif_tx_burst (conn, qid, bufs, max_buf, &tx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (tx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_eq (bufs[i].data, NULL);
+
+  /* test transmit qid 1 (positive) */
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+  qid = 1;
+  if ((err =
+       memif_buffer_alloc (conn, qid, bufs, max_buf,
+			   &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_uint_eq (bufs[i].buffer_len, MEMIF_DEFAULT_BUFFER_SIZE);
+
+  if ((err =
+       memif_tx_burst (conn, qid, bufs, max_buf, &tx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (tx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_eq (bufs[i].data, NULL);
+
+  /* test transmit qid 2 (negative) */
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+  qid = 2;
+  if ((err =
+       memif_tx_burst (conn, qid, bufs, max_buf, &tx)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_QID, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+  free (bufs);
+  bufs = NULL;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_rx_burst)
+{
+  int err, i;
+  uint16_t max_buf = 10, buf, rx;
+  uint8_t qid;
+  memif_buffer_t *bufs;
+  memif_queue_t *mq;
+  memif_ring_t *ring;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  c->fd = 69;
+
+  /* test receive qid 0 (positive) */
+  qid = 0;
+  mq = &c->rx_queues[qid];
+  ring = mq->ring;
+  ring->head += max_buf;
+
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_rx_burst (conn, qid, bufs, max_buf, &rx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (rx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_ne (bufs[i].data, NULL);
+
+  /* test receive qid 1 (positive) */
+  qid = 1;
+  mq = &c->rx_queues[qid];
+  ring = mq->ring;
+  ring->head += max_buf;
+
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_rx_burst (conn, qid, bufs, max_buf, &rx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (rx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_ne (bufs[i].data, NULL);
+
+  /* test receive qid 2 (negative) */
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_rx_burst (conn, qid, bufs, max_buf, &rx)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_QID, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+  free (bufs);
+  bufs = NULL;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_buffer_free)
+{
+  int err, i;
+  uint16_t max_buf = 10, buf, rx;
+  uint8_t qid;
+  memif_buffer_t *bufs;
+  memif_queue_t *mq;
+  memif_ring_t *ring;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  c->fd = 69;
+
+  /* test buffer free qid 0 (positive) */
+  qid = 0;
+  mq = &c->rx_queues[qid];
+  ring = mq->ring;
+  ring->head += 10;
+
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_rx_burst (conn, qid, bufs, max_buf, &rx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (rx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_ne (bufs[i].data, NULL);
+
+  if ((err =
+       memif_buffer_free (conn, qid, bufs, max_buf,
+			  &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_eq (bufs[i].data, NULL);
+  ck_assert_uint_eq (ring->head, ring->tail);
+
+  /* test buffer free qid 1 (positive) */
+  qid = 1;
+  mq = &c->rx_queues[qid];
+  ring = mq->ring;
+  ring->head += 10;
+
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_rx_burst (conn, qid, bufs, max_buf, &rx)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (rx, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_ne (bufs[i].data, NULL);
+
+  if ((err =
+       memif_buffer_free (conn, qid, bufs, max_buf,
+			  &buf)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (buf, max_buf);
+  for (i = 0; i < max_buf; i++)
+    ck_assert_ptr_eq (bufs[i].data, NULL);
+  ck_assert_uint_eq (ring->head, ring->tail);
+
+
+  /* test buffer free qid 2 (negative) */
+  qid = 2;
+  free (bufs);
+  bufs = malloc (sizeof (memif_buffer_t) * max_buf);
+
+  if ((err =
+       memif_buffer_free (conn, qid, bufs, max_buf,
+			  &buf)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_QID, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+  free (bufs);
+  bufs = NULL;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_get_details)
+{
+  int err, i;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_details_t md;
+  memset (&md, 0, sizeof (md));
+  ssize_t buflen = 2048;
+  char *buf = malloc (buflen);
+  memset (buf, 0, buflen);
+
+  if ((err = memif_get_details (conn, &md, buf, buflen)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_str_eq (md.if_name, c->args.interface_name);
+  ck_assert_str_eq (md.inst_name, c->args.instance_name);
+  ck_assert_str_eq (md.remote_if_name, c->remote_if_name);
+  ck_assert_str_eq (md.remote_inst_name, c->remote_name);
+  ck_assert_str_eq (md.secret, c->args.secret);
+  ck_assert_str_eq (md.socket_filename, c->args.socket_filename);
+
+  ck_assert_uint_eq (md.id, c->args.interface_id);
+  ck_assert_uint_ne (md.role, c->args.is_master);
+  ck_assert_uint_eq (md.mode, c->args.mode);
+  for (i = 0; i < md.rx_queues_num; i++)
+    {
+      ck_assert_uint_eq (md.rx_queues[i].qid, i);
+      ck_assert_uint_eq (md.rx_queues[i].ring_size,
+			 (1 << c->args.log2_ring_size));
+      ck_assert_uint_eq (md.rx_queues[i].buffer_size, c->args.buffer_size);
+    }
+  for (i = 0; i < md.tx_queues_num; i++)
+    {
+      ck_assert_uint_eq (md.tx_queues[i].qid, i);
+      ck_assert_uint_eq (md.tx_queues[i].ring_size,
+			 (1 << c->args.log2_ring_size));
+      ck_assert_uint_eq (md.tx_queues[i].buffer_size, c->args.buffer_size);
+    }
+  ck_assert_uint_eq (md.link_up_down, 0);
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_init_regions_and_queues)
+{
+  int err;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_ptr_ne (c->regions, NULL);
+  ck_assert_ptr_ne (c->tx_queues, NULL);
+  ck_assert_ptr_ne (c->rx_queues, NULL);
+
+  ck_assert_ptr_ne (c->regions->shm, NULL);
+  ck_assert_ptr_ne (c->tx_queues->ring, NULL);
+  ck_assert_ptr_ne (c->rx_queues->ring, NULL);
+
+  ck_assert_int_ne (c->regions->fd, -1);
+  ck_assert_uint_eq (c->tx_queues->ring->cookie, MEMIF_COOKIE);
+  ck_assert_uint_eq (c->rx_queues->ring->cookie, MEMIF_COOKIE);
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_connect1)
+{
+  int err;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_connect1 (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST
+START_TEST (test_disconnect_internal)
+{
+  int err;
+  ready_called = 0;
+  memif_conn_handle_t conn = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+  args.num_s2m_rings = 2;
+  args.num_m2s_rings = 2;
+
+  libmemif_main_t *lm = &libmemif_main;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  strncpy ((char *) args.interface_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err = memif_create (&conn, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *c = (memif_connection_t *) conn;
+
+  c->run_args.num_s2m_rings = 2;
+  c->run_args.num_m2s_rings = 2;
+  c->run_args.log2_ring_size = 10;
+  c->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_disconnect_internal (c)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_int_eq (c->fd, -1);
+
+  ck_assert_ptr_eq (c->tx_queues, NULL);
+  ck_assert_ptr_eq (c->rx_queues, NULL);
+  ck_assert_ptr_eq (c->regions, NULL);
+  ck_assert_ptr_eq (c->msg_queue, NULL);
+
+  struct itimerspec timer;
+  timerfd_gettime (lm->timerfd, &timer);
+
+  ck_assert_msg (timer.it_interval.tv_sec == lm->arm.it_interval.tv_sec,
+		 "timerfd not armed!");
+
+  if (lm->timerfd > 0)
+    close (lm->timerfd);
+  lm->timerfd = -1;
+
+  memif_delete (&conn);
+  ck_assert_ptr_eq (conn, NULL);
+}
+
+END_TEST Suite * main_suite ()
+{
+  Suite *s;
+
+  TCase *tc_api;
+  TCase *tc_internal;
+
+  /* create main test suite */
+  s = suite_create ("Libmemif main");
+
+  /* create api test case */
+  tc_api = tcase_create ("Api calls");
+  /* add tests to test case */
+  tcase_add_test (tc_api, test_init);
+  tcase_add_test (tc_api, test_init_epoll);
+  tcase_add_test (tc_api, test_create);
+  tcase_add_test (tc_api, test_create_master);
+  tcase_add_test (tc_api, test_create_mult);
+  tcase_add_test (tc_api, test_control_fd_handler);
+  tcase_add_test (tc_api, test_buffer_alloc);
+  tcase_add_test (tc_api, test_tx_burst);
+  tcase_add_test (tc_api, test_rx_burst);
+  tcase_add_test (tc_api, test_buffer_free);
+  tcase_add_test (tc_api, test_get_details);
+
+  /* create internal test case */
+  tc_internal = tcase_create ("Internal");
+  /* add tests to test case */
+  tcase_add_test (tc_internal, test_init_regions_and_queues);
+  tcase_add_test (tc_internal, test_connect1);
+  tcase_add_test (tc_internal, test_disconnect_internal);
+
+  /* add test cases to test suite */
+  suite_add_tcase (s, tc_api);
+  suite_add_tcase (s, tc_internal);
+
+  /* return main test suite to test runner */
+  return s;
+}
diff --git a/extras/libmemif/test/main_test.h b/extras/libmemif/test/main_test.h
new file mode 100644
index 0000000..300d8a8
--- /dev/null
+++ b/extras/libmemif/test/main_test.h
@@ -0,0 +1,25 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef _MAIN_TEST_H_
+#define _MAIN_TEST_H_
+
+#include <unit_test.h>
+
+Suite *main_suite ();
+
+#endif /* _MAIN_TEST_H_ */
diff --git a/extras/libmemif/test/socket_test.c b/extras/libmemif/test/socket_test.c
new file mode 100644
index 0000000..f148495
--- /dev/null
+++ b/extras/libmemif/test/socket_test.c
@@ -0,0 +1,625 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <socket_test.h>
+
+#include <memif_private.h>
+#include <socket.h>
+
+static int
+get_queue_len (memif_msg_queue_elt_t * q)
+{
+  int r = 0;
+  memif_msg_queue_elt_t *c = q;
+  while (c != NULL)
+    {
+      r++;
+      c = c->next;
+    }
+  return r;
+}
+
+static void
+queue_free (memif_msg_queue_elt_t ** e)
+{
+  if (*e == NULL)
+    return;
+  queue_free (&(*e)->next);
+  free (*e);
+  *e = NULL;
+  return;
+}
+
+START_TEST (test_msg_queue)
+{
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+  conn.fd = -1;
+
+  int i, len = 10;
+
+  for (i = 0; i < len; i++)
+    {
+      if (i % 2)
+	memif_msg_enq_ack (&conn);
+      else
+	memif_msg_enq_init (&conn);
+    }
+
+  ck_assert_int_eq (len, get_queue_len (conn.msg_queue));
+
+  int pop = 6;
+
+  for (i = 0; i < pop; i++)
+    {
+      if (i % 2)
+	{
+	  ck_assert_uint_eq (conn.msg_queue->msg.type, MEMIF_MSG_TYPE_ACK);
+	}
+      else
+	{
+	  ck_assert_uint_eq (conn.msg_queue->msg.type, MEMIF_MSG_TYPE_INIT);
+	}
+      conn.flags |= MEMIF_CONNECTION_FLAG_WRITE;
+      /* function will return -1 because no socket is created */
+      memif_conn_fd_write_ready (&conn);
+    }
+
+  ck_assert_int_eq ((len - pop), get_queue_len (conn.msg_queue));
+
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_ack)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+
+  if ((err = memif_msg_enq_ack (&conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ACK);
+  ck_assert_int_eq (e->fd, -1);
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_init)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+
+  conn.args.interface_id = 69;
+  conn.args.mode = 0;
+
+  strncpy ((char *) conn.args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+  strncpy ((char *) conn.args.secret, TEST_SECRET, strlen (TEST_SECRET));
+
+  if ((err = memif_msg_enq_init (&conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_INIT);
+  ck_assert_int_eq (e->fd, -1);
+
+  memif_msg_init_t *i = &e->msg.init;
+
+  ck_assert_uint_eq (i->version, MEMIF_VERSION);
+  ck_assert_uint_eq (i->id, conn.args.interface_id);
+  ck_assert_uint_eq (i->mode, conn.args.mode);
+  ck_assert_str_eq (i->name, conn.args.instance_name);
+  ck_assert_str_eq (i->secret, conn.args.secret);
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_add_region)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+  conn.regions = (memif_region_t *) malloc (sizeof (memif_region_t));
+  memif_region_t *mr = conn.regions;
+  mr->fd = 5;
+  mr->region_size = 2048;
+  uint8_t region_index = 0;
+
+  if ((err =
+       memif_msg_enq_add_region (&conn, region_index)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ADD_REGION);
+  ck_assert_int_eq (e->fd, mr->fd);
+
+  memif_msg_add_region_t *ar = &e->msg.add_region;
+
+  ck_assert_uint_eq (ar->index, region_index);
+  ck_assert_uint_eq (ar->size, mr->region_size);
+
+  free (conn.regions);
+  conn.regions = NULL;
+  mr = NULL;
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_add_ring)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+  conn.rx_queues = (memif_queue_t *) malloc (sizeof (memif_queue_t));
+  conn.tx_queues = (memif_queue_t *) malloc (sizeof (memif_queue_t));
+
+  memif_queue_t *mq = conn.tx_queues;
+  uint8_t dir = MEMIF_RING_S2M;
+  mq->int_fd = 5;
+  mq->offset = 0;
+  mq->log2_ring_size = 10;
+
+  if ((err = memif_msg_enq_add_ring (&conn, 0, dir)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ADD_RING);
+  ck_assert_int_eq (e->fd, mq->int_fd);
+
+  memif_msg_add_ring_t *ar = &e->msg.add_ring;
+
+  ck_assert_uint_eq (ar->index, 0);
+  ck_assert_uint_eq (ar->offset, mq->offset);
+  ck_assert_uint_eq (ar->log2_ring_size, mq->log2_ring_size);
+  ck_assert (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M);
+
+  dir = MEMIF_RING_M2S;
+  if ((err = memif_msg_enq_add_ring (&conn, 0, dir)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_connect)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+  memset (conn.args.interface_name, 0, sizeof (conn.args.interface_name));
+  strncpy ((char *) conn.args.interface_name, TEST_IF_NAME,
+	   strlen (TEST_IF_NAME));
+
+  if ((err = memif_msg_enq_connect (&conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_CONNECT);
+  ck_assert_int_eq (e->fd, -1);
+  ck_assert_str_eq (e->msg.connect.if_name, TEST_IF_NAME);
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_enq_connected)
+{
+  int err;
+  memif_connection_t conn;
+  conn.msg_queue = NULL;
+  memset (conn.args.interface_name, 0, sizeof (conn.args.interface_name));
+  strncpy ((char *) conn.args.interface_name, TEST_IF_NAME,
+	   strlen (TEST_IF_NAME));
+
+  if ((err = memif_msg_enq_connected (&conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_queue_elt_t *e = conn.msg_queue;
+
+  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_CONNECTED);
+  ck_assert_int_eq (e->fd, -1);
+  ck_assert_str_eq (e->msg.connect.if_name, TEST_IF_NAME);
+  queue_free (&conn.msg_queue);
+}
+
+END_TEST
+START_TEST (test_send)
+{
+  int err;
+  int fd = -1, afd = 5;
+  memif_msg_t msg;
+  memset (&msg, 0, sizeof (msg));
+
+  if ((err = memif_msg_send (fd, &msg, afd)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_BAD_FD,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+}
+
+END_TEST
+START_TEST (test_send_hello)
+{
+  int err;
+  memif_connection_t conn;
+  conn.fd = -1;
+  memset (conn.args.instance_name, 0, sizeof (conn.args.instance_name));
+  strncpy ((char *) conn.args.instance_name, TEST_APP_NAME,
+	   strlen (TEST_APP_NAME));
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_msg_send_hello (conn.fd)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_BAD_FD,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+}
+
+END_TEST
+START_TEST (test_send_disconnect)
+{
+  int err;
+  memif_connection_t conn;
+  conn.fd = -1;
+
+  /* only possible fail if memif_msg_send fails...  */
+  /* obsolete without socket */
+  if ((err =
+       memif_msg_send_disconnect (conn.fd, "unit_test_dc",
+				  0)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_BAD_FD, "err code: %u, err msg: %s", err,
+		   memif_strerror (err));
+}
+
+END_TEST
+START_TEST (test_recv_hello)
+{
+  int err;
+  memif_connection_t conn;
+  memif_msg_t msg;
+
+  memif_msg_hello_t *h = &msg.hello;
+
+  msg.type = MEMIF_MSG_TYPE_HELLO;
+
+  h->min_version = MEMIF_VERSION;
+  h->max_version = MEMIF_VERSION;
+  h->max_s2m_ring = 1;
+  h->max_m2s_ring = 1;
+  h->max_log2_ring_size = 14;
+  strncpy ((char *) h->name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  memset (conn.remote_name, 0, sizeof (conn.remote_name));
+
+  conn.args.num_s2m_rings = 4;
+  conn.args.num_m2s_rings = 6;
+  conn.args.log2_ring_size = 10;
+
+  if ((err = memif_msg_receive_hello (&conn, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_uint_eq (conn.run_args.num_s2m_rings, 2);
+  ck_assert_uint_eq (conn.run_args.num_m2s_rings, 2);
+  ck_assert_uint_eq (conn.run_args.log2_ring_size, 10);
+  ck_assert_str_eq (conn.remote_name, TEST_IF_NAME);
+
+  h->max_version = 9;
+  if ((err = memif_msg_receive_hello (&conn, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_PROTO,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+}
+
+END_TEST
+START_TEST (test_recv_init)
+{
+  int err;
+  memif_connection_t conn;
+
+  conn.args.interface_id = 69;
+  conn.args.is_master = 1;
+  conn.fd = -1;
+  conn.args.mode = 0;
+  memset (conn.args.secret, '\0', 24);
+  strncpy ((char *) conn.args.secret, TEST_SECRET, strlen (TEST_SECRET));
+
+  memif_msg_t msg;
+
+  memif_msg_init_t *i = &msg.init;
+
+  msg.type = MEMIF_MSG_TYPE_INIT;
+
+  i->version = MEMIF_VERSION;
+  i->id = 69;
+  i->mode = 0;
+  memset (i->name, '\0', 32);
+  memset (i->secret, '\0', 24);
+  strncpy ((char *) i->name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+  strncpy ((char *) i->secret, TEST_SECRET, strlen (TEST_SECRET));
+
+  memif_socket_t ms;
+  ms.interface_list_len = 1;
+  ms.interface_list = malloc (sizeof (memif_list_elt_t));
+  memif_list_elt_t elt;
+  elt.key = 69;
+  elt.data_struct = &conn;
+  add_list_elt (&elt, &ms.interface_list, &ms.interface_list_len);
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  i->version = 9;
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_PROTO,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+  i->version = MEMIF_VERSION;
+
+  i->id = 78;
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_ID,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+  i->id = 69;
+
+  i->mode = 1;
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_MODE,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+  i->mode = 0;
+
+  i->secret[0] = '\0';
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_SECRET,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+  strncpy ((char *) i->secret, TEST_SECRET, strlen (TEST_SECRET));
+
+  conn.args.is_master = 0;
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_ACCSLAVE,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+  conn.args.is_master = 1;
+
+  conn.fd = 5;
+  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg ((err == MEMIF_ERR_ALRCONN) || (err == MEMIF_ERR_BAD_FD),
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+}
+
+END_TEST
+START_TEST (test_recv_add_region)
+{
+  int err;
+  memif_connection_t conn;
+  conn.regions = NULL;
+  memif_msg_t msg;
+  msg.type = MEMIF_MSG_TYPE_ADD_REGION;
+  msg.add_region.size = 2048;
+  msg.add_region.index = 0;
+
+  int fd = 5;
+
+  if ((err =
+       memif_msg_receive_add_region (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_region_t *mr = conn.regions;
+
+  ck_assert_uint_eq (mr->fd, fd);
+  ck_assert_uint_eq (mr->region_size, 2048);
+  ck_assert_ptr_eq (mr->shm, NULL);
+}
+
+END_TEST
+START_TEST (test_recv_add_ring)
+{
+  int err;
+  memif_connection_t conn;
+  int fd = 5;
+  memif_msg_t msg;
+  conn.args.num_s2m_rings = 2;
+  conn.args.num_m2s_rings = 2;
+  conn.rx_queues = NULL;
+  conn.tx_queues = NULL;
+
+  msg.type = MEMIF_MSG_TYPE_ADD_RING;
+  memif_msg_add_ring_t *ar = &msg.add_ring;
+
+  ar->log2_ring_size = 10;
+  ar->region = 0;
+  ar->offset = 0;
+  ar->flags = 0;
+  ar->flags |= MEMIF_MSG_ADD_RING_FLAG_S2M;
+  ar->index = 1;
+
+  if ((err =
+       memif_msg_receive_add_ring (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+
+  ar->offset = 2048;
+  ar->flags &= ~MEMIF_MSG_ADD_RING_FLAG_S2M;
+
+  if ((err =
+       memif_msg_receive_add_ring (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+}
+
+END_TEST
+START_TEST (test_recv_connect)
+{
+  int err;
+  memif_conn_handle_t c = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+
+  args.interface_id = 0;
+  args.is_master = 0;
+  args.mode = 0;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_create (&c, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *conn = (memif_connection_t *) c;
+
+  conn->run_args.num_s2m_rings = 1;
+  conn->run_args.num_m2s_rings = 1;
+  conn->run_args.log2_ring_size = 10;
+  conn->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_t msg;
+  memset (&msg, 0, sizeof (msg));
+  msg.type = MEMIF_MSG_TYPE_CONNECT;
+
+  memset (msg.connect.if_name, 0, sizeof (msg.connect.if_name));
+  strncpy ((char *) msg.connect.if_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+
+  if ((err = memif_msg_receive_connect (conn, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_str_eq (conn->remote_if_name, TEST_IF_NAME);
+}
+
+END_TEST
+START_TEST (test_recv_connected)
+{
+  int err;
+  memif_conn_handle_t c = NULL;
+  memif_conn_args_t args;
+  memset (&args, 0, sizeof (args));
+
+  args.interface_id = 0;
+  args.is_master = 0;
+  args.mode = 0;
+
+  if ((err =
+       memif_init (control_fd_update, TEST_APP_NAME)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  if ((err = memif_create (&c, &args, on_connect,
+			   on_disconnect, on_interrupt,
+			   NULL)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_connection_t *conn = (memif_connection_t *) c;
+
+  conn->run_args.num_s2m_rings = 1;
+  conn->run_args.num_m2s_rings = 1;
+  conn->run_args.log2_ring_size = 10;
+  conn->run_args.buffer_size = 2048;
+
+  if ((err = memif_init_regions_and_queues (conn)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  memif_msg_t msg;
+  memset (&msg, 0, sizeof (msg));
+  msg.type = MEMIF_MSG_TYPE_CONNECT;
+
+  memset (msg.connect.if_name, 0, sizeof (msg.connect.if_name));
+  strncpy ((char *) msg.connect.if_name, TEST_IF_NAME, strlen (TEST_IF_NAME));
+
+  if ((err = memif_msg_receive_connected (conn, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_str_eq (conn->remote_if_name, TEST_IF_NAME);
+}
+
+END_TEST
+START_TEST (test_recv_disconnect)
+{
+  int err;
+  memif_connection_t conn;
+  memif_msg_t msg;
+  msg.type = MEMIF_MSG_TYPE_DISCONNECT;
+  memset (msg.disconnect.string, 0, sizeof (msg.disconnect.string));
+  strncpy ((char *) msg.disconnect.string, "unit_test_dc", 12);
+
+  if ((err = memif_msg_receive_disconnect (&conn, &msg)) != MEMIF_ERR_SUCCESS)
+    ck_assert_msg (err == MEMIF_ERR_DISCONNECT,
+		   "err code: %u, err msg: %s", err, memif_strerror (err));
+
+  ck_assert_str_eq (conn.remote_disconnect_string, "unit_test_dc");
+}
+
+END_TEST Suite * socket_suite ()
+{
+  Suite *s;
+  TCase *tc_msg_queue;
+  TCase *tc_msg_enq;
+  TCase *tc_msg_send;
+  TCase *tc_msg_recv;
+
+  /* create socket test suite */
+  s = suite_create ("Socket messaging");
+
+  /* create msg queue test case */
+  tc_msg_queue = tcase_create ("Message queue");
+  /* add tests to test case */
+  tcase_add_test (tc_msg_queue, test_msg_queue);
+
+  /* create msg enq test case */
+  tc_msg_enq = tcase_create ("Message enqueue");
+  /* add tests to test case */
+  tcase_add_test (tc_msg_enq, test_enq_ack);
+  tcase_add_test (tc_msg_enq, test_enq_init);
+  tcase_add_test (tc_msg_enq, test_enq_add_region);
+  tcase_add_test (tc_msg_enq, test_enq_add_ring);
+  tcase_add_test (tc_msg_enq, test_enq_connect);
+  tcase_add_test (tc_msg_enq, test_enq_connected);
+
+  /* create msg send test case */
+  tc_msg_send = tcase_create ("Message send");
+  /* add tests to test case */
+  tcase_add_test (tc_msg_send, test_send);
+  tcase_add_test (tc_msg_send, test_send_hello);
+  tcase_add_test (tc_msg_send, test_send_disconnect);
+
+  /* create msg recv test case */
+  tc_msg_recv = tcase_create ("Message receive");
+  /* add tests to test case */
+  tcase_add_test (tc_msg_recv, test_recv_hello);
+  tcase_add_test (tc_msg_recv, test_recv_init);
+  tcase_add_test (tc_msg_recv, test_recv_add_region);
+  tcase_add_test (tc_msg_recv, test_recv_add_ring);
+  tcase_add_test (tc_msg_recv, test_recv_connect);
+  tcase_add_test (tc_msg_recv, test_recv_connected);
+  tcase_add_test (tc_msg_recv, test_recv_disconnect);
+
+  /* add test cases to test suite */
+  suite_add_tcase (s, tc_msg_queue);
+  suite_add_tcase (s, tc_msg_enq);
+  suite_add_tcase (s, tc_msg_send);
+  suite_add_tcase (s, tc_msg_recv);
+
+  /* return socket test suite to test runner */
+  return s;
+}
diff --git a/extras/libmemif/test/socket_test.h b/extras/libmemif/test/socket_test.h
new file mode 100644
index 0000000..02ec69c
--- /dev/null
+++ b/extras/libmemif/test/socket_test.h
@@ -0,0 +1,25 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef _SOCKET_TEST_H_
+#define _SOCKET_TEST_H_
+
+#include <unit_test.h>
+
+Suite *socket_suite ();
+
+#endif /* _SOCKET_TEST_H_ */
diff --git a/extras/libmemif/test/unit_test.c b/extras/libmemif/test/unit_test.c
new file mode 100644
index 0000000..a305de9
--- /dev/null
+++ b/extras/libmemif/test/unit_test.c
@@ -0,0 +1,63 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <main_test.h>
+#include <socket_test.h>
+
+int
+on_connect (memif_conn_handle_t conn, void *ctx)
+{
+  return 0;
+}
+
+int
+on_disconnect (memif_conn_handle_t conn, void *ctx)
+{
+  return 0;
+}
+
+int
+on_interrupt (memif_conn_handle_t conn, void *ctx, uint16_t qid)
+{
+  return 0;
+}
+
+int
+control_fd_update (int fd, uint8_t events)
+{
+  return 0;
+}
+
+int
+main (void)
+{
+  int num_fail;
+  Suite *main, *socket;
+  SRunner *sr;
+
+  main = main_suite ();
+  socket = socket_suite ();
+
+  sr = srunner_create (main);
+
+  srunner_add_suite (sr, socket);
+
+  srunner_run_all (sr, CK_VERBOSE);
+  num_fail = srunner_ntests_failed (sr);
+  srunner_free (sr);
+  return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/extras/libmemif/test/unit_test.h b/extras/libmemif/test/unit_test.h
new file mode 100644
index 0000000..fae3cba
--- /dev/null
+++ b/extras/libmemif/test/unit_test.h
@@ -0,0 +1,38 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef _UNIT_TEST_H_
+#define _UNIT_TEST_H_
+
+#include <stdlib.h>
+#include <check.h>
+
+#include <libmemif.h>
+
+#define TEST_APP_NAME "unit_test_app"
+#define TEST_IF_NAME  "unit_test_if"
+#define TEST_SECRET   "psst"
+
+int on_connect (memif_conn_handle_t conn, void *ctx);
+
+int on_disconnect (memif_conn_handle_t conn, void *ctx);
+
+int on_interrupt (memif_conn_handle_t conn, void *ctx, uint16_t qid);
+
+int control_fd_update (int fd, uint8_t events);
+
+#endif /* _UNIT_TEST_H_ */