diff --git a/.gitignore b/.gitignore
index 2b9e4f5..862602e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,4 +44,5 @@ odp_timer_test
 odp_generator
 odp_l2fwd
 odp_ipsec
+odp_buffer
 doxygen-doc
diff --git a/DEPENDENCIES b/DEPENDENCIES
index 3083d09..e75b11d 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -75,3 +75,17 @@ Prerequisites for building the OpenDataPlane (ODP) API
    $ ./configure --host=aarch64-linux-gnu \
      --with-openssl-path=/home/user/src/install-openssl-aarch64
    $ make
+
+4. packages needed to build API tests
+
+4.1 Native compile
+
+   # Debian/Ubuntu
+   $ apt-get install libcunit1-dev
+
+4.2 Cross compile
+
+   $ git svn clone http://svn.code.sf.net/p/cunit/code/trunk cunit-code
+   $ cd cunit-code
+   $ ./bootstrap
+   $ ./configure --host=arm-linux-gnueabihf --prefix=/home/anders/src/install-cunit
diff --git a/configure.ac b/configure.ac
index 102486d..0afa101 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,26 @@ ODP_CFLAGS="$ODP_CFLAGS -DODP_HAVE_NETMAP=1"
 AM_CONDITIONAL([ODP_NETMAP_ENABLED], [test x$netmap_support = xyes ])
 
 ##########################################################################
+# Enable/disable Unit tests
+##########################################################################
+AC_ARG_ENABLE([cunit],
+    [  --enable-cunit         Enable/disable cunit],
+    [if test x$enableval = xyes; then
+        unit_support=yes
+    fi])
+
+AC_ARG_WITH([cunit-path],
+AC_HELP_STRING([--with-cunit-path=DIR Path to Cunit libs and headers],
+               [(or in the default path if not specified).]),
+[CUNIT_PATH=$withval unit_support=yes
+],[ AC_MSG_WARN([Cunit not found - continuing without Cunit support])
+])
+
+AC_SUBST(CUNIT_PATH)
+AM_CONDITIONAL([ODP_UNIT_ENABLED], [test x$unit_support = xyes ])
+
+
+##########################################################################
 # Enable/disable ODP_DEBUG_PRINT
 ##########################################################################
 ODP_DEBUG=1
@@ -162,6 +182,7 @@ AC_CONFIG_FILES([Makefile
 		 example/timer/Makefile
 		 test/Makefile
 		 test/api_test/Makefile
+                 test/unit/Makefile
 		 pkgconfig/libodp.pc])
 
 AC_SEARCH_LIBS([timer_create],[rt posix4])
diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am
index 5c9d503..d892283 100644
--- a/platform/linux-dpdk/Makefile.am
+++ b/platform/linux-dpdk/Makefile.am
@@ -75,6 +75,7 @@ __LIB__libodp_la_SOURCES = \
 			   odp_packet.c \
 			   odp_packet_dpdk.c \
 			   ../linux-generic/odp_packet_flags.c \
+			   ../linux-generic/odp_crypto.c \
 			   odp_packet_io.c \
 			   ../linux-generic/odp_packet_socket.c \
 			   odp_queue.c \
diff --git a/test/Makefile.am b/test/Makefile.am
index 9bd7db1..dda7d5e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1 +1 @@
-SUBDIRS = api_test
+SUBDIRS = api_test unit
diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am
new file mode 100644
index 0000000..9554ed9
--- /dev/null
+++ b/test/unit/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/test/Makefile.inc
+
+AM_CFLAGS += -I$(CUNIT_PATH)/include
+AM_LDFLAGS += -L$(CUNIT_PATH)/lib
+
+if ODP_UNIT_ENABLED
+bin_PROGRAMS = odp_buffer
+odp_buffer_LDFLAGS = $(AM_LDFLAGS) -static -lcunit
+endif
+
+dist_odp_buffer_SOURCES = odp_buffer_test.c
diff --git a/test/unit/odp_buffer_test.c b/test/unit/odp_buffer_test.c
new file mode 100644
index 0000000..38f5538
--- /dev/null
+++ b/test/unit/odp_buffer_test.c
@@ -0,0 +1,261 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "odp.h"
+#include "CUnit/Basic.h"
+
+#define DEFAULT_MSG_POOL_SIZE         (4*1024*1024)
+#define DEFAULT_MSG_SIZE         (8)
+#define ODP_SHM_RESERVE_DEFAULT_FLAG  (0)
+
+static void test_odp_buffer_addr(void)
+{
+	void *startaddress;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* start address is correct */
+	shm = odp_shm_reserve("msg_pool1",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool1", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	startaddress = odp_buffer_addr(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE(startaddress != NULL);
+}
+
+static void test_odp_buffer_size(void)
+{
+	size_t size;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* buffer size is correct */
+	shm = odp_shm_reserve("msg_pool2",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool2", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	size = odp_buffer_size(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE(size == DEFAULT_MSG_SIZE);
+	/* bad buffer size */
+	msg_pool = odp_buffer_pool_create("msg_pool2_1", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  -1,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	CU_ASSERT_TRUE(msg_pool == ODP_BUFFER_POOL_INVALID);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	size = odp_buffer_size(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE(size == ODP_BUFFER_INVALID);
+}
+
+static void test_odp_buffer_type(int type_in)
+{
+	int type;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	char pool_name[32];
+	/* valid buffer types are correct */
+	sprintf(pool_name, "mag_pool_%d", type_in);
+	shm = odp_shm_reserve(pool_name,
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create(pool_name, pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE, type_in);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	type = odp_buffer_type(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE(type == type_in);
+}
+
+static void test_odp_buffer_type_valid(void)
+{
+	test_odp_buffer_type(ODP_BUFFER_TYPE_ANY);
+	test_odp_buffer_type(ODP_BUFFER_TYPE_RAW);
+	test_odp_buffer_type(ODP_BUFFER_TYPE_PACKET);
+	test_odp_buffer_type(ODP_BUFFER_TYPE_TIMEOUT);
+}
+
+static void test_odp_buffer_type_invalid(void)
+{
+	int type;
+	int type_in = ODP_BUFFER_TYPE_INVALID;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* in valid buffer type */
+	shm = odp_shm_reserve("msg_pool4",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool4", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE, type_in);
+	/* msg_pool should fail */
+	CU_ASSERT_TRUE(msg_pool == ODP_BUFFER_POOL_INVALID);
+	/* mybuffer should fail */
+	mybuffer = odp_buffer_alloc(msg_pool);
+	CU_ASSERT_TRUE(mybuffer ==  ODP_BUFFER_INVALID);
+	/* type should fail */
+	type = odp_buffer_type(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE(type == type_in);
+}
+
+static void test_odp_is_scatter(void)
+{
+	int is_scatter;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* scatter correct */
+	shm = odp_shm_reserve("msg_pool5",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool5", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	is_scatter = odp_buffer_size(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_TRUE((is_scatter < 0) || (is_scatter > 1));
+}
+
+static void test_odp_is_valid(void)
+{
+	int is_valid;
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* valid is correct */
+	shm = odp_shm_reserve("msg_pool6",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool6", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	is_valid = odp_buffer_is_valid(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_ASSERT_FALSE((is_valid < 0) || (is_valid > 1));
+}
+
+static void test_odp_buffer_print(void)
+{
+	odp_buffer_pool_t msg_pool;
+	odp_buffer_t mybuffer;
+	odp_shm_t shm;
+	void *pool_base;
+	/* print works */
+	shm = odp_shm_reserve("msg_pool8",
+				    DEFAULT_MSG_POOL_SIZE,
+				    ODP_CACHE_LINE_SIZE,
+				    ODP_SHM_RESERVE_DEFAULT_FLAG);
+	pool_base = odp_shm_addr(shm);
+	msg_pool = odp_buffer_pool_create("msg_pool8", pool_base,
+					  DEFAULT_MSG_POOL_SIZE,
+					  DEFAULT_MSG_SIZE,
+					  ODP_CACHE_LINE_SIZE,
+					  ODP_BUFFER_TYPE_RAW);
+	mybuffer = odp_buffer_alloc(msg_pool);
+	odp_buffer_print(mybuffer);
+	odp_buffer_free(mybuffer);
+	odp_buffer_pool_delete(msg_pool);
+	CU_PASS("test_odp_buffer_print");
+}
+
+static int init_suite1(void)
+{
+	int thr_id;
+	odp_init_global();
+
+	/*
+	 *      * Init this thread. It makes also ODP calls when
+	 *           * setting up resources for worker threads.
+	 *                */
+	thr_id = odp_thread_create(0);
+	odp_init_local(thr_id);
+	return 0;
+}
+
+static int clean_suite1(void)
+{
+	return 0;
+}
+
+int main(void)
+{
+	CU_pSuite pSuite = NULL;
+	/* initialize the CUnit test registry */
+	if (CUE_SUCCESS != CU_initialize_registry())
+		return CU_get_error();
+	/* add a suite to the registry */
+	pSuite = CU_add_suite("odp_buffer_pool", init_suite1, clean_suite1);
+	if (NULL == pSuite) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	/* add the tests to the suite */
+	if ((NULL == CU_ADD_TEST(pSuite, test_odp_buffer_size)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_buffer_addr)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_buffer_type_valid)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_buffer_type_invalid)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_is_valid)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_is_scatter)) ||
+	    (NULL == CU_ADD_TEST(pSuite, test_odp_buffer_print))) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+	/* Run all tests using the CUnit Basic interface */
+	CU_basic_set_mode(CU_BRM_VERBOSE);
+	CU_basic_run_tests();
+	CU_cleanup_registry();
+	return CU_get_error();
+}
