diff --git a/configure.ac b/configure.ac
index e486933c..343be2cb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -111,7 +111,7 @@ AS_CASE([$host],
   [ARCH_DIR=undefined]
 )
 AC_SUBST([ARCH_DIR])
-AM_CONDITIONAL([ARCH_X86], [test "x${ARCH_DIR}" = "xx86"])
+AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])
 
 ##########################################################################
 # Warn on the defaults if arch is undefined
@@ -183,13 +183,13 @@ AC_SUBST(SDK_INSTALL_PATH)
 # Run platform specific checks and settings
 ##########################################################################
 IMPLEMENTATION_NAME=""
-AS_IF([test "${with_platform}" == "linux-generic"],
+AS_IF([test "${with_platform}" = "linux-generic"],
          [m4_include([./platform/linux-generic/m4/configure.m4])]
          [m4_include([./test/linux-generic/m4/configure.m4])]
          [IMPLEMENTATION_NAME="linux-generic"]
          [ODP_CFLAGS="$ODP_CFLAGS -std=c99"]
          [ODP_LIB_STR="odp-linux"],
-      [test "${with_platform}" == "linux-dpdk"],
+      [test "${with_platform}" = "linux-dpdk"],
           [m4_include([./platform/linux-dpdk/m4/configure.m4])]
           [m4_include([./test/linux-dpdk/m4/configure.m4])]
           [IMPLEMENTATION_NAME="linux-dpdk"]
@@ -232,7 +232,6 @@ AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ])
 AM_CONDITIONAL([ARCH_IS_ARM], [test "x${ARCH_DIR}" = "xarm"])
 AM_CONDITIONAL([ARCH_IS_MIPS64], [test "x${ARCH_DIR}" = "xmips64"])
 AM_CONDITIONAL([ARCH_IS_POWERPC], [test "x${ARCH_DIR}" = "xpowerpc"])
-AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])
 
 ##########################################################################
 # Setup doxygen documentation
diff --git a/example/Makefile.inc b/example/Makefile.inc
index 88d34d33..55950918 100644
--- a/example/Makefile.inc
+++ b/example/Makefile.inc
@@ -1,6 +1,6 @@
 include $(top_srcdir)/platform/@with_platform@/Makefile.inc
 LIB   = $(top_builddir)/lib
-LDADD = $(LIB)/lib$(ODP_LIB_STR).la $(LIB)/libodphelper.la $(DPDK_PMDS)
+LDADD = $(LIB)/lib$(ODP_LIB_STR).la $(LIB)/libodphelper.la $(DPDK_PMDS) $(OPENSSL_LIBS)
 AM_CFLAGS += \
 	-I$(srcdir) \
 	-I$(top_srcdir)/example \
diff --git a/example/ddf_app/Makefile.am b/example/ddf_app/Makefile.am
index 49f0170f..9b865ce0 100644
--- a/example/ddf_app/Makefile.am
+++ b/example/ddf_app/Makefile.am
@@ -1,7 +1,7 @@
 include $(top_srcdir)/example/Makefile.inc
 
 bin_PROGRAMS = odp_ddf_app$(EXEEXT)
-odp_ddf_app_LDFLAGS = $(AM_LDFLAGS) -static -Wl,--export-dynamic
+odp_ddf_app_LDFLAGS = $(AM_LDFLAGS) $(DPDK_LIBS) -static -Wl,--export-dynamic
 odp_ddf_app_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
 
 noinst_HEADERS = \
diff --git a/pkgconfig/libodp-dpdk.pc.in b/pkgconfig/libodp-dpdk.pc.in
index d3164a61..f22e832c 100644
--- a/pkgconfig/libodp-dpdk.pc.in
+++ b/pkgconfig/libodp-dpdk.pc.in
@@ -6,11 +6,6 @@ includedir=@includedir@
 Name: libodp-dpdk
 Description: The ODP packet processing engine
 Version: @PKGCONFIG_VERSION@
-<<<<<<< HEAD:pkgconfig/libodp-linux.pc.in
-Libs: -L${libdir} -lodp-linux @DPDK_LIBS@
+Libs: -L${libdir} -lodp-dpdk @DPDK_LIBS@
 Libs.private: @OPENSSL_STATIC_LIBS@ @DPDK_PMDS@ @DPDK_LIBS@ @PCAP_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ @LIBCONFIG_LIBS@
-=======
-Libs: -L${libdir} -lodp-dpdk
-Libs.private: @ATOMIC_LIBS@
->>>>>>> odpdpdk/master:pkgconfig/libodp-dpdk.pc.in
 Cflags: -I${includedir}
diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am
index e56dc165..d6fa5f6f 100644
--- a/platform/linux-dpdk/Makefile.am
+++ b/platform/linux-dpdk/Makefile.am
@@ -4,7 +4,7 @@ include $(top_srcdir)/platform/@with_platform@/Makefile.inc
 lib_LTLIBRARIES = $(LIB)/libodp-dpdk.la
 
 PLAT_CFLAGS  =
-if ARCH_X86
+if ARCH_IS_X86
 PLAT_CFLAGS  += -msse4.2
 endif
 
@@ -21,10 +21,16 @@ AM_CFLAGS +=  -I$(top_srcdir)/include/odp/arch/@ARCH_ABI@
 AM_CFLAGS +=  -I$(top_srcdir)/include
 AM_CFLAGS +=  -I$(top_builddir)/include
 AM_CFLAGS +=  -Iinclude
+AM_CFLAGS +=  -DSYSCONFDIR=\"@sysconfdir@\"
+AM_CFLAGS +=  -D_ODP_PKTIO_IPC
+
+AM_CPPFLAGS +=  $(OPENSSL_CPPFLAGS)
+AM_CPPFLAGS +=  $(LIBCONFIG_CFLAGS)
 
 include_HEADERS = \
 		  $(top_srcdir)/include/odp.h \
-		  $(top_srcdir)/include/odp_api.h
+		  $(top_srcdir)/include/odp_api.h \
+		  $(top_srcdir)/include/odp_drv.h
 
 odpincludedir= $(includedir)/odp
 odpinclude_HEADERS = \
@@ -47,6 +53,7 @@ odpapiinclude_HEADERS = \
 		  $(srcdir)/include/odp/api/deprecated.h \
 		  $(srcdir)/include/odp/api/errno.h \
 		  $(srcdir)/include/odp/api/event.h \
+		  $(srcdir)/include/odp/api/feature.h \
 		  $(srcdir)/include/odp/api/hash.h \
 		  $(srcdir)/include/odp/api/hints.h \
 		  $(srcdir)/include/odp/api/init.h \
@@ -66,6 +73,7 @@ odpapiinclude_HEADERS = \
 		  $(srcdir)/include/odp/api/spinlock_recursive.h \
 		  $(srcdir)/include/odp/api/std_clib.h \
 		  $(srcdir)/include/odp/api/std_types.h \
+		  $(srcdir)/include/odp/api/support.h \
 		  $(srcdir)/include/odp/api/sync.h \
 		  $(srcdir)/include/odp/api/system_info.h \
 		  $(srcdir)/include/odp/api/thread.h \
@@ -132,12 +140,36 @@ odpapiplatinclude_HEADERS = \
 
 odpdrvincludedir = $(includedir)/odp/drv
 odpdrvinclude_HEADERS = \
-		  $(srcdir)/include/odp/drv/compiler.h
+		  $(srcdir)/include/odp/drv/align.h \
+		  $(srcdir)/include/odp/drv/atomic.h \
+		  $(srcdir)/include/odp/drv/barrier.h \
+		  $(srcdir)/include/odp/drv/byteorder.h \
+		  $(srcdir)/include/odp/drv/compiler.h \
+		  $(srcdir)/include/odp/drv/driver.h \
+		  $(srcdir)/include/odp/drv/hints.h \
+		  $(srcdir)/include/odp/drv/shm.h \
+		  $(srcdir)/include/odp/drv/spinlock.h \
+		  $(srcdir)/include/odp/drv/std_types.h \
+		  $(srcdir)/include/odp/drv/sync.h
+
+odpdrvplatincludedir = $(includedir)/odp/drv/plat
+odpdrvplatinclude_HEADERS = \
+		  $(srcdir)/include/odp/drv/plat/atomic_types.h \
+		  $(srcdir)/include/odp/drv/plat/barrier_types.h \
+		  $(srcdir)/include/odp/drv/plat/byteorder_types.h \
+		  $(srcdir)/include/odp/drv/compiler.h \
+		  $(srcdir)/include/odp/drv/plat/driver_types.h \
+		  $(srcdir)/include/odp/drv/plat/shm_types.h \
+		  $(srcdir)/include/odp/drv/plat/spinlock_types.h \
+		  $(srcdir)/include/odp/drv/plat/strong_types.h
+
 
 noinst_HEADERS = \
 		  ${top_srcdir}/platform/linux-generic/include/_fdserver_internal.h \
 		  ${top_srcdir}/platform/linux-generic/include/_ishm_internal.h \
 		  ${top_srcdir}/platform/linux-generic/include/_ishmphy_internal.h \
+		  ${top_srcdir}/platform/linux-generic/include/_ishmpool_internal.h \
+		  ${top_srcdir}/platform/linux-generic/include/drv_driver_internal.h\
 		  ${top_srcdir}/platform/linux-generic/include/odp_align_internal.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_atomic_internal.h \
 		  ${srcdir}/include/odp_buffer_inlines.h \
@@ -158,13 +190,13 @@ noinst_HEADERS = \
 		  ${srcdir}/include/odp_packet_io_internal.h \
 		  ${srcdir}/include/odp_errno_define.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_packet_io_ipc_internal.h \
-		  ${top_srcdir}/platform/linux-generic/include/odp_packet_io_queue.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_packet_io_ring_internal.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_packet_socket.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_pkt_queue_internal.h \
 		  ${srcdir}/include/odp_pool_internal.h \
 		  ${srcdir}/include/odp_posix_extensions.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_queue_internal.h \
+		  ${top_srcdir}/platform/linux-generic/include/odp_queue_if.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_ring_internal.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_schedule_if.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_sorted_list_internal.h \
@@ -184,6 +216,8 @@ __LIB__libodp_dpdk_la_SOURCES = \
 			   ../linux-generic/_fdserver.c \
 			   ../linux-generic/_ishm.c \
 			   ../linux-generic/_ishmphy.c \
+			   ../linux-generic/_ishmpool.c \
+			   ../linux-generic/_modules.c \
 			   ../linux-generic/odp_atomic.c \
 			   ../linux-generic/odp_barrier.c \
 			   ../linux-generic/odp_bitmap.c \
@@ -199,6 +233,7 @@ __LIB__libodp_dpdk_la_SOURCES = \
 			   ../linux-generic/odp_hash.c \
 			   odp_init.c \
 			   ../linux-generic/odp_impl.c \
+			   ../linux-generic/odp_ipsec.c \
 			   ../linux-generic/odp_name_table.c \
 			   odp_packet.c \
 			   odp_packet_dpdk.c \
@@ -208,6 +243,7 @@ __LIB__libodp_dpdk_la_SOURCES = \
 			   ../linux-generic/odp_pkt_queue.c \
 			   odp_pool.c \
 			   ../linux-generic/odp_queue.c \
+			   ../linux-generic/odp_queue_if.c \
 			   ../linux-generic/odp_rwlock.c \
 			   ../linux-generic/odp_rwlock_recursive.c \
 			   ../linux-generic/odp_schedule.c \
@@ -253,7 +289,19 @@ __LIB__libodp_dpdk_la_SOURCES += arch/x86/cpu_flags.c \
 				 arch/x86/odp_sysinfo_parse.c
 endif
 
+# Build modular framework into odp-linux library
+modularframeworkdir = $(top_srcdir)/frameworks/modular
+noinst_HEADERS += $(modularframeworkdir)/list.h \
+		  $(modularframeworkdir)/odp_module.h
+
+__LIB__libodp_dpdk_la_SOURCES += ../../frameworks/modular/odp_module.c
+
 __LIB__libodp_dpdk_la_LIBADD = $(ATOMIC_LIBS)
+__LIB__libodp_dpdk_la_LIBADD += $(DPDK_LIBS)
+__LIB__libodp_dpdk_la_LIBADD += $(OPENSSL_LIBS)
+__LIB__libodp_dpdk_la_LIBADD += $(PTHREAD_LIBS)
+__LIB__libodp_dpdk_la_LIBADD += $(TIMER_LIBS)
+__LIB__libodp_dpdk_la_LIBADD += $(LIBCONFIG_LIBS)
 
 # Create symlink for ABI header files. Application does not need to use the arch
 # specific include path for installed files.
diff --git a/platform/linux-dpdk/include/odp/api/feature.h b/platform/linux-dpdk/include/odp/api/feature.h
new file mode 120000
index 00000000..aa1c547f
--- /dev/null
+++ b/platform/linux-dpdk/include/odp/api/feature.h
@@ -0,0 +1 @@
+../../../../linux-generic/include/odp/api/feature.h
\ No newline at end of file
diff --git a/platform/linux-dpdk/include/odp/api/plat/event_types.h b/platform/linux-dpdk/include/odp/api/plat/event_types.h
index 086e83d5..e0f68e34 100644
--- a/platform/linux-dpdk/include/odp/api/plat/event_types.h
+++ b/platform/linux-dpdk/include/odp/api/plat/event_types.h
@@ -44,6 +44,13 @@ typedef enum odp_event_type_t {
 	ODP_EVENT_CRYPTO_COMPL	= 4,
 } odp_event_type_t;
 
+typedef enum odp_event_subtype_t {
+	ODP_EVENT_NO_SUBTYPE   = 0,
+	ODP_EVENT_PACKET_BASIC = 1,
+	ODP_EVENT_PACKET_CRYPTO = 2,
+	ODP_EVENT_PACKET_IPSEC = 3
+}
+
 /**
  * @}
  */
diff --git a/platform/linux-dpdk/include/odp/api/plat/timer_types.h b/platform/linux-dpdk/include/odp/api/plat/timer_types.h
index 8821bed6..c81d7be7 100644
--- a/platform/linux-dpdk/include/odp/api/plat/timer_types.h
+++ b/platform/linux-dpdk/include/odp/api/plat/timer_types.h
@@ -4,7 +4,6 @@
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
-
 /**
  * @file
  *
diff --git a/platform/linux-dpdk/include/odp/api/support.h b/platform/linux-dpdk/include/odp/api/support.h
new file mode 120000
index 00000000..e6196271
--- /dev/null
+++ b/platform/linux-dpdk/include/odp/api/support.h
@@ -0,0 +1 @@
+../../../../linux-generic/include/odp/api/support.h
\ No newline at end of file
diff --git a/platform/linux-dpdk/include/odp_buffer_inlines.h b/platform/linux-dpdk/include/odp_buffer_inlines.h
index c481390b..a2fa502f 100644
--- a/platform/linux-dpdk/include/odp_buffer_inlines.h
+++ b/platform/linux-dpdk/include/odp_buffer_inlines.h
@@ -39,6 +39,16 @@ static inline void _odp_buffer_event_type_set(odp_buffer_t buf, int ev)
 	buf_hdl_to_hdr(buf)->event_type = ev;
 }
 
+static inline odp_event_subtype_t _odp_buffer_event_subtype(odp_buffer_t buf)
+{
+	return buf_hdl_to_hdr(buf)->event_subtype;
+}
+
+static inline void _odp_buffer_event_subtype_set(odp_buffer_t buf, int ev)
+{
+	buf_hdl_to_hdr(buf)->event_subtype = ev;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/linux-dpdk/include/odp_buffer_internal.h b/platform/linux-dpdk/include/odp_buffer_internal.h
index b33a30da..fcb300ab 100644
--- a/platform/linux-dpdk/include/odp_buffer_internal.h
+++ b/platform/linux-dpdk/include/odp_buffer_internal.h
@@ -4,7 +4,6 @@
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
-
 /**
  * @file
  *
@@ -75,6 +74,9 @@ struct odp_buffer_hdr_t {
 	/* Event type. Maybe different than pool type (crypto compl event) */
 	odp_event_type_t         event_type;
 
+	/* Event subtype. Should be ODP_EVENT_NO_SUBTYPE except packets. */
+	odp_event_type_t         event_subtype;
+
 	/* Burst table */
 	struct odp_buffer_hdr_t *burst[BUFFER_BURST_SIZE];
 
diff --git a/platform/linux-dpdk/include/odp_config_internal.h b/platform/linux-dpdk/include/odp_config_internal.h
index 21db09b8..ea469ee4 100644
--- a/platform/linux-dpdk/include/odp_config_internal.h
+++ b/platform/linux-dpdk/include/odp_config_internal.h
@@ -132,6 +132,12 @@ extern "C" {
  */
 #define ODP_CONFIG_ISHM_VA_PREALLOC_SZ (536870912L)
 
+/* Maximum number of shared memory blocks available on the driver interface.
+ *
+ * This the the number of separate SHM areas that can be reserved concurrently
+ */
+#define ODPDRV_CONFIG_SHM_BLOCKS 48
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/linux-dpdk/include/odp_packet_internal.h b/platform/linux-dpdk/include/odp_packet_internal.h
index 481e4afb..fc1f9e5f 100644
--- a/platform/linux-dpdk/include/odp_packet_internal.h
+++ b/platform/linux-dpdk/include/odp_packet_internal.h
@@ -4,7 +4,6 @@
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
-
 /**
  * @file
  *
@@ -30,6 +29,7 @@ extern "C" {
 #include <odp_crypto_internal.h>
 #include <protocols/eth.h>
 #include <odp/api/plat/packet_types.h>
+#include <odp_queue_if.h>
 
 #include <rte_acl_osdep.h>
 
@@ -126,10 +126,10 @@ typedef struct {
 	odp_time_t timestamp;
 
 	/* Classifier destination queue */
-	odp_queue_t dst_queue;
+	queue_t dst_queue;
 
-	/* Result for crypto */
-	odp_crypto_generic_op_result_t op_result;
+	/* Result for crypto packet op */
+	odp_crypto_packet_result_t crypto_op_result;
 } odp_packet_hdr_t __rte_cache_aligned;
 
 /**
@@ -145,6 +145,21 @@ static inline struct rte_mbuf *pkt_to_mbuf(odp_packet_hdr_t *pkt_hdr)
 	return &pkt_hdr->buf_hdr.mb;
 }
 
+static inline odp_buffer_hdr_t *packet_to_buf_hdr(odp_packet_t pkt)
+{
+	return &odp_packet_hdr(pkt)->buf_hdr;
+}
+
+static inline odp_packet_t packet_from_buf_hdr(odp_buffer_hdr_t *buf_hdr)
+{
+	return (odp_packet_t)(odp_packet_hdr_t *)buf_hdr;
+}
+
+static inline odp_buffer_t packet_to_buffer(odp_packet_t pkt)
+{
+	return (odp_buffer_t)pkt;
+}
+
 static inline void copy_packet_parser_metadata(odp_packet_hdr_t *src_hdr,
 					       odp_packet_hdr_t *dst_hdr)
 {
@@ -157,7 +172,6 @@ static inline void copy_packet_cls_metadata(odp_packet_hdr_t *src_hdr,
 	dst_hdr->p = src_hdr->p;
 	dst_hdr->dst_queue = src_hdr->dst_queue;
 	dst_hdr->timestamp = src_hdr->timestamp;
-	dst_hdr->op_result = src_hdr->op_result;
 }
 
 static inline uint32_t packet_len(odp_packet_hdr_t *pkt_hdr)
@@ -189,11 +203,8 @@ static inline void packet_parse_reset(odp_packet_hdr_t *pkt_hdr)
 	pkt_hdr->p.l4_offset        = ODP_PACKET_OFFSET_INVALID;
 }
 
-/* Convert a packet handle to a buffer handle */
-odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);
-
 /* Convert a buffer handle to a packet handle */
-odp_packet_t _odp_packet_from_buffer(odp_buffer_t buf);
+odp_packet_t _odp_packet_from_buf_hdr(odp_buffer_hdr_t *buf_hdr);
 
 static inline int packet_hdr_has_l2(odp_packet_hdr_t *pkt_hdr)
 {
diff --git a/platform/linux-dpdk/include/odp_packet_io_internal.h b/platform/linux-dpdk/include/odp_packet_io_internal.h
index 9dc420c4..8e158dc9 100644
--- a/platform/linux-dpdk/include/odp_packet_io_internal.h
+++ b/platform/linux-dpdk/include/odp_packet_io_internal.h
@@ -4,7 +4,6 @@
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
-
 /**
  * @file
  *
@@ -23,6 +22,7 @@ extern "C" {
 #include <odp_classification_datamodel.h>
 #include <odp_align_internal.h>
 #include <odp_debug_internal.h>
+#include <odp_queue_if.h>
 
 #include <odp_config_internal.h>
 #include <odp/api/hints.h>
@@ -106,6 +106,7 @@ struct pktio_entry {
 
 	struct {
 		odp_queue_t        queue;
+		queue_t            queue_int;
 		odp_pktin_queue_t  pktin;
 	} in_queue[PKTIO_MAX_QUEUES];
 
@@ -193,7 +194,6 @@ static inline void pktio_cls_enabled_set(pktio_entry_t *entry, int ena)
 /*
  * Dummy single queue implementations of multi-queue API
  */
-int single_capability(odp_pktio_capability_t *capa);
 int single_input_queues_config(pktio_entry_t *entry,
 			       const odp_pktin_queue_param_t *param);
 int single_output_queues_config(pktio_entry_t *entry,
diff --git a/platform/linux-dpdk/m4/configure.m4 b/platform/linux-dpdk/m4/configure.m4
index 230ef6ef..428ecc82 100644
--- a/platform/linux-dpdk/m4/configure.m4
+++ b/platform/linux-dpdk/m4/configure.m4
@@ -28,6 +28,9 @@ AC_LINK_IFELSE(
     echo "Use newer version. For gcc > 4.7.0"
     exit -1)
 
+dnl Check for libconfig (required)
+PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.3.2])
+
 dnl Check whether -latomic is needed
 use_libatomic=no
 
@@ -76,8 +79,13 @@ AC_SUBST([ATOMIC_LIBS])
 # linux-generic PCAP support is not relevant as the code doesn't use
 # linux-generic pktio at all. And DPDK has its own PCAP support anyway
 AM_CONDITIONAL([HAVE_PCAP], [false])
+AM_CONDITIONAL([netmap_support], [false])
+AM_CONDITIONAL([PKTIO_DPDK], [false])
 m4_include([platform/linux-dpdk/m4/odp_pthread.m4])
+m4_include([platform/linux-dpdk/m4/odp_timer.m4])
 m4_include([platform/linux-dpdk/m4/odp_openssl.m4])
+m4_include([platform/linux-dpdk/m4/odp_modules.m4])
+m4_include([platform/linux-dpdk/m4/odp_schedule.m4])
 
 ##########################################################################
 # DPDK build variables
@@ -98,7 +106,6 @@ AC_ARG_ENABLE([shared-dpdk],
 	[if test "x$enableval" = "xyes"; then
 		shared_dpdk=true
 	fi])
-AM_CONDITIONAL([SHARED_DPDK], [test x$shared_dpdk = xtrue])
 
 ##########################################################################
 # Save and set temporary compilation flags
@@ -106,7 +113,7 @@ AM_CONDITIONAL([SHARED_DPDK], [test x$shared_dpdk = xtrue])
 OLD_LDFLAGS=$LDFLAGS
 OLD_CPPFLAGS=$CPPFLAGS
 LDFLAGS="$AM_LDFLAGS $LDFLAGS"
-CPPFLAGS="$AM_CPPFLAGS $CPPFLAGS"
+CPPFLAGS="$AM_CPPFLAGS $CPPFLAGS -pthread"
 
 ##########################################################################
 # Check for DPDK availability
@@ -125,21 +132,23 @@ AC_SEARCH_LIBS([rte_eal_init], [dpdk], [],
 if test "x$shared_dpdk" = "xtrue"; then
     LIBS="$LIBS -Wl,--no-as-needed,-ldpdk,-as-needed -ldl -lm -lpcap"
 else
-    DPDK_PMD=--whole-archive,
-    for filename in $DPDK_DRIVER_DIR/*.a; do
-        cur_driver=`echo $(basename "$filename" .a) | \
-            sed -n 's/^\(librte_pmd_\)/-lrte_pmd_/p' | sed -n 's/$/,/p'`
+
+    AS_VAR_SET([DPDK_PMDS], [-Wl,--whole-archive,])
+    for filename in $DPDK_DRIVER_DIR/librte_pmd_*.a; do
+        cur_driver=`basename "$filename" .a | sed -e 's/^lib//'`
         # rte_pmd_nfp has external dependencies which break linking
-        if test "$cur_driver" = "-lrte_pmd_nfp,"; then
+        if test "$cur_driver" = "rte_pmd_nfp"; then
             echo "skip linking rte_pmd_nfp"
         else
-            DPDK_PMD+=$cur_driver
+            AS_VAR_APPEND([DPDK_PMDS], [-l$cur_driver,])
         fi
     done
-    DPDK_PMD+=--no-whole-archive
+    AS_VAR_APPEND([DPDK_PMDS], [--no-whole-archive])
 
-    LIBS="$LIBS -ldpdk -ldl -lm -lpcap"
-    AM_LDFLAGS="$AM_LDFLAGS -Wl,$DPDK_PMD"
+    DPDK_LIBS="-L$DPDK_DRIVER_DIR -ldpdk -lpthread -ldl -lm -lpcap"
+    AC_SUBST([DPDK_CPPFLAGS])
+    AC_SUBST([DPDK_LIBS])
+    AC_SUBST([DPDK_PMDS])
 fi
 
 ##########################################################################
diff --git a/platform/linux-dpdk/m4/odp_modules.m4 b/platform/linux-dpdk/m4/odp_modules.m4
new file mode 120000
index 00000000..3f60e2bd
--- /dev/null
+++ b/platform/linux-dpdk/m4/odp_modules.m4
@@ -0,0 +1 @@
+../../linux-generic/m4/odp_modules.m4
\ No newline at end of file
diff --git a/platform/linux-dpdk/m4/odp_schedule.m4 b/platform/linux-dpdk/m4/odp_schedule.m4
new file mode 120000
index 00000000..7b211bd8
--- /dev/null
+++ b/platform/linux-dpdk/m4/odp_schedule.m4
@@ -0,0 +1 @@
+../../linux-generic/m4/odp_schedule.m4
\ No newline at end of file
diff --git a/platform/linux-dpdk/m4/odp_timer.m4 b/platform/linux-dpdk/m4/odp_timer.m4
new file mode 120000
index 00000000..2a909824
--- /dev/null
+++ b/platform/linux-dpdk/m4/odp_timer.m4
@@ -0,0 +1 @@
+../../linux-generic/m4/odp_timer.m4
\ No newline at end of file
diff --git a/platform/linux-dpdk/odp_crypto.c b/platform/linux-dpdk/odp_crypto.c
index d95b1578..8235e1bd 100644
--- a/platform/linux-dpdk/odp_crypto.c
+++ b/platform/linux-dpdk/odp_crypto.c
@@ -32,6 +32,7 @@
 typedef struct crypto_session_entry_s crypto_session_entry_t;
 struct crypto_session_entry_s {
 		struct crypto_session_entry_s *next;
+		odp_crypto_session_param_t p;
 		uint64_t rte_session;
 		odp_bool_t do_cipher_first;
 		struct rte_crypto_sym_xform cipher_xform;
@@ -40,9 +41,6 @@ struct crypto_session_entry_s {
 			uint8_t *data;
 			uint16_t length;
 		} iv;
-		odp_queue_t compl_queue; /**< Async mode completion
-					      event queue */
-		odp_pool_t output_pool;  /**< Output buffer pool */
 };
 
 struct crypto_global_s {
@@ -59,11 +57,6 @@ typedef struct crypto_global_s crypto_global_t;
 static crypto_global_t *global;
 static odp_shm_t crypto_global_shm;
 
-static odp_crypto_generic_op_result_t *get_op_result_from_event(odp_event_t ev)
-{
-	return &(odp_packet_hdr(odp_packet_from_event(ev))->op_result);
-}
-
 static inline int is_valid_size(uint16_t length, uint16_t min,
 				uint16_t max, uint16_t increment)
 {
@@ -807,6 +800,9 @@ int odp_crypto_session_create(odp_crypto_session_param_t *param,
 		return -1;
 	}
 
+	/* Copy parameters */
+	entry->p = *param;
+
 	/* Default to successful result */
 	*status = ODP_CRYPTO_SES_CREATE_ERR_NONE;
 
@@ -911,8 +907,6 @@ int odp_crypto_session_create(odp_crypto_session_param_t *param,
 	entry->auth_xform = auth_xform;
 	entry->iv.length = param->iv.length;
 	entry->iv.data = param->iv.data;
-	entry->output_pool = param->output_pool;
-	entry->compl_queue = param->compl_queue;
 
 	/* We're happy */
 	*session_out = (intptr_t)entry;
@@ -948,18 +942,226 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 			 odp_bool_t *posted,
 			 odp_crypto_op_result_t *result)
 {
+	odp_crypto_packet_op_param_t packet_param;
+	odp_packet_t out_pkt = param->out_pkt;
+	odp_crypto_packet_result_t packet_result;
+	odp_crypto_op_result_t local_result;
+	int rc;
+
+	packet_param.session = param->session;
+	packet_param.override_iv_ptr = param->override_iv_ptr;
+	packet_param.hash_result_offset = param->hash_result_offset;
+	packet_param.aad.ptr = param->aad.ptr;
+	packet_param.aad.length = param->aad.length;
+	packet_param.cipher_range = param->cipher_range;
+	packet_param.auth_range = param->auth_range;
+
+	rc = odp_crypto_op(&param->pkt, &out_pkt, &packet_param, 1);
+	if (rc < 0)
+		return rc;
+
+	rc = odp_crypto_result(&packet_result, out_pkt);
+	if (rc < 0)
+		return rc;
+
+	/* Indicate to caller operation was sync */
+	*posted = 0;
+
+	_odp_buffer_event_subtype_set(packet_to_buffer(out_pkt),
+				      ODP_EVENT_PACKET_BASIC);
+
+	/* Fill in result */
+	local_result.ctx = param->ctx;
+	local_result.pkt = out_pkt;
+	local_result.cipher_status = packet_result.cipher_status;
+	local_result.auth_status = packet_result.auth_status;
+	local_result.ok = packet_result.ok;
+
+	/*
+	 * Be bug-to-bug compatible. Return output packet also through params.
+	 */
+	param->out_pkt = out_pkt;
+
+	*result = local_result;
+
+	return 0;
+}
+
+int odp_crypto_term_global(void)
+{
+	int rc = 0;
+	int ret;
+	int count = 0;
+	crypto_session_entry_t *session;
+
+	odp_spinlock_init(&global->lock);
+	odp_spinlock_lock(&global->lock);
+	for (session = global->free; session != NULL; session = session->next)
+		count++;
+	if (count != MAX_SESSIONS) {
+		ODP_ERR("crypto sessions still active\n");
+		rc = -1;
+	}
+
+	if (global->crypto_op_pool != NULL)
+		rte_mempool_free(global->crypto_op_pool);
+
+	odp_spinlock_unlock(&global->lock);
+
+	ret = odp_shm_free(crypto_global_shm);
+	if (ret < 0) {
+		ODP_ERR("shm free failed for crypto_pool\n");
+		rc = -1;
+	}
+
+	return rc;
+}
+
+odp_random_kind_t odp_random_max_kind(void)
+{
+	return ODP_RANDOM_CRYPTO;
+}
+
+int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
+{
+	int rc;
+
+	switch (kind) {
+	case ODP_RANDOM_BASIC:
+		RAND_pseudo_bytes(buf, len);
+		return len;
+
+	case ODP_RANDOM_CRYPTO:
+		rc = RAND_bytes(buf, len);
+		return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;
+
+	case ODP_RANDOM_TRUE:
+	default:
+		return -1;
+	}
+}
+
+int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
+{
+	union {
+		uint32_t rand_word;
+		uint8_t rand_byte[4];
+	} u;
+	uint32_t i = 0, j;
+	uint32_t seed32 = (*seed) & 0xffffffff;
+
+	while (i < len) {
+		u.rand_word = rand_r(&seed32);
+
+		for (j = 0; j < 4 && i < len; j++, i++)
+			*buf++ = u.rand_byte[j];
+	}
+
+	*seed = seed32;
+	return len;
+}
+
+odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)
+{
+	/* This check not mandated by the API specification */
+	if (odp_event_type(ev) != ODP_EVENT_CRYPTO_COMPL)
+		ODP_ABORT("Event not a crypto completion");
+	return (odp_crypto_compl_t)ev;
+}
+
+odp_event_t odp_crypto_compl_to_event(odp_crypto_compl_t completion_event)
+{
+	return (odp_event_t)completion_event;
+}
+
+void odp_crypto_compl_result(odp_crypto_compl_t completion_event,
+			     odp_crypto_op_result_t *result)
+{
+	(void)completion_event;
+	(void)result;
+
+	/* We won't get such events anyway, so there can be no result */
+	ODP_ASSERT(0);
+}
+
+void odp_crypto_compl_free(odp_crypto_compl_t completion_event)
+{
+	odp_event_t ev = odp_crypto_compl_to_event(completion_event);
+
+	odp_buffer_free(odp_buffer_from_event(ev));
+}
+
+void odp_crypto_session_param_init(odp_crypto_session_param_t *param)
+{
+	memset(param, 0, sizeof(odp_crypto_session_param_t));
+}
+
+uint64_t odp_crypto_session_to_u64(odp_crypto_session_t hdl)
+{
+	return (uint64_t)hdl;
+}
+
+uint64_t odp_crypto_compl_to_u64(odp_crypto_compl_t hdl)
+{
+	return _odp_pri(hdl);
+}
+
+odp_packet_t odp_crypto_packet_from_event(odp_event_t ev)
+{
+	/* This check not mandated by the API specification */
+	ODP_ASSERT(odp_event_type(ev) == ODP_EVENT_PACKET);
+	ODP_ASSERT(odp_event_subtype(ev) == ODP_EVENT_PACKET_CRYPTO);
+
+	return odp_packet_from_event(ev);
+}
+
+odp_event_t odp_crypto_packet_to_event(odp_packet_t pkt)
+{
+	return odp_packet_to_event(pkt);
+}
+
+static
+odp_crypto_packet_result_t *get_op_result_from_packet(odp_packet_t pkt)
+{
+	odp_packet_hdr_t *hdr = odp_packet_hdr(pkt);
+
+	return &hdr->crypto_op_result;
+}
+
+int odp_crypto_result(odp_crypto_packet_result_t *result,
+		      odp_packet_t packet)
+{
+	odp_crypto_packet_result_t *op_result;
+
+	ODP_ASSERT(odp_event_subtype(odp_packet_to_event(packet)) ==
+		   ODP_EVENT_PACKET_CRYPTO);
+
+	op_result = get_op_result_from_packet(packet);
+
+	memcpy(result, op_result, sizeof(*result));
+
+	return 0;
+}
+
+static
+int odp_crypto_int(odp_packet_t pkt_in,
+		   odp_packet_t *pkt_out,
+		   const odp_crypto_packet_op_param_t *param)
+{
+	crypto_session_entry_t *entry;
+	odp_crypto_packet_result_t local_result;
 	odp_crypto_alg_err_t rc_cipher = ODP_CRYPTO_ALG_ERR_NONE;
 	odp_crypto_alg_err_t rc_auth = ODP_CRYPTO_ALG_ERR_NONE;
 	struct rte_crypto_sym_xform cipher_xform;
 	struct rte_crypto_sym_xform auth_xform;
 	struct rte_cryptodev_sym_session *rte_session = NULL;
-	odp_crypto_op_result_t local_result;
-	crypto_session_entry_t *entry;
 	uint8_t *data_addr, *aad_head;
 	struct rte_crypto_op *op;
-	uint16_t rc;
 	uint32_t aad_len;
 	odp_bool_t allocated = false;
+	odp_packet_t out_pkt = *pkt_out;
+	odp_crypto_packet_result_t *op_result;
+	uint16_t rc;
 
 	entry = (crypto_session_entry_t *)(intptr_t)param->session;
 	if (entry == NULL)
@@ -976,32 +1178,32 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 	auth_xform = entry->auth_xform;
 
 	/* Resolve output buffer */
-	if (ODP_PACKET_INVALID == param->out_pkt &&
-	    ODP_POOL_INVALID != entry->output_pool) {
-		param->out_pkt = odp_packet_alloc(entry->output_pool,
-						   odp_packet_len(param->pkt));
+	if (ODP_PACKET_INVALID == out_pkt &&
+	    ODP_POOL_INVALID != entry->p.output_pool) {
+		out_pkt = odp_packet_alloc(entry->p.output_pool,
+					   odp_packet_len(pkt_in));
 		allocated = true;
 	}
 
-	if (param->pkt != param->out_pkt) {
-		if (odp_unlikely(ODP_PACKET_INVALID == param->out_pkt))
+	if (pkt_in != out_pkt) {
+		if (odp_unlikely(ODP_PACKET_INVALID == out_pkt))
 			ODP_ABORT();
 		int ret;
 
-		ret = odp_packet_copy_from_pkt(param->out_pkt,
+		ret = odp_packet_copy_from_pkt(out_pkt,
 					       0,
-					       param->pkt,
+					       pkt_in,
 					       0,
-					       odp_packet_len(param->pkt));
+					       odp_packet_len(pkt_in));
 		if (odp_unlikely(ret < 0))
 			goto err;
 
-		_odp_packet_copy_md_to_packet(param->pkt, param->out_pkt);
-		odp_packet_free(param->pkt);
-		param->pkt = ODP_PACKET_INVALID;
+		_odp_packet_copy_md_to_packet(pkt_in, out_pkt);
+		odp_packet_free(pkt_in);
+		pkt_in = ODP_PACKET_INVALID;
 	}
 
-	data_addr = odp_packet_data(param->out_pkt);
+	data_addr = odp_packet_data(out_pkt);
 
 	odp_spinlock_init(&global->lock);
 	odp_spinlock_lock(&global->lock);
@@ -1018,8 +1220,8 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 	rte_crypto_op_attach_sym_session(op, rte_session);
 	op->sym->auth.digest.data = data_addr + param->hash_result_offset;
 	op->sym->auth.digest.phys_addr =
-		rte_pktmbuf_mtophys_offset((struct rte_mbuf *)param->out_pkt,
-					   odp_packet_len(param->out_pkt) -
+		rte_pktmbuf_mtophys_offset((struct rte_mbuf *)out_pkt,
+					   odp_packet_len(out_pkt) -
 					   auth_xform.auth.digest_length);
 	op->sym->auth.digest.length = auth_xform.auth.digest_length;
 
@@ -1092,7 +1294,7 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 	    rc_auth == ODP_CRYPTO_ALG_ERR_NONE) {
 		int queue_pair = odp_cpu_id();
 
-		op->sym->m_src = (struct rte_mbuf *)param->out_pkt;
+		op->sym->m_src = (struct rte_mbuf *)out_pkt;
 		rc = rte_cryptodev_enqueue_burst(rte_session->dev_id,
 						 queue_pair, &op, 1);
 		if (rc == 0) {
@@ -1110,12 +1312,10 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 			goto err;
 		}
 
-		param->out_pkt = (odp_packet_t)op->sym->m_src;
+		out_pkt = (odp_packet_t)op->sym->m_src;
 	}
 
 	/* Fill in result */
-	local_result.ctx = param->ctx;
-	local_result.pkt = param->out_pkt;
 	local_result.cipher_status.alg_err = rc_cipher;
 	local_result.cipher_status.hw_err = ODP_CRYPTO_HW_ERR_NONE;
 	local_result.auth_status.alg_err = rc_auth;
@@ -1124,167 +1324,73 @@ int odp_crypto_operation(odp_crypto_op_param_t *param,
 		(rc_cipher == ODP_CRYPTO_ALG_ERR_NONE) &&
 		(rc_auth == ODP_CRYPTO_ALG_ERR_NONE);
 
+	_odp_buffer_event_subtype_set(packet_to_buffer(out_pkt),
+				      ODP_EVENT_PACKET_BASIC);
+	op_result = get_op_result_from_packet(out_pkt);
+	*op_result = local_result;
+
 	rte_crypto_op_free(op);
 
-	/* If specified during creation post event to completion queue */
-	if (ODP_QUEUE_INVALID != entry->compl_queue) {
-		odp_event_t completion_event;
-		odp_crypto_generic_op_result_t *op_result;
-
-		completion_event = odp_packet_to_event(param->out_pkt);
-		_odp_buffer_event_type_set(
-			odp_buffer_from_event(completion_event),
-			ODP_EVENT_CRYPTO_COMPL);
-		/* Asynchronous, build result (no HW so no errors) and send it*/
-		op_result = get_op_result_from_event(completion_event);
-		op_result->magic = OP_RESULT_MAGIC;
-		op_result->result = local_result;
-		if (odp_queue_enq(entry->compl_queue, completion_event)) {
-			odp_event_free(completion_event);
-			goto err;
-		}
+	/* Synchronous, simply return results */
+	*pkt_out = out_pkt;
 
-		/* Indicate to caller operation was async */
-		*posted = 1;
-	} else {
-		/* Synchronous, simply return results */
-		if (!result)
-			goto err;
-		*result = local_result;
-
-		/* Indicate to caller operation was sync */
-		*posted = 0;
-	}
 	return 0;
 
 err:
 	if (allocated) {
-		odp_packet_free(param->out_pkt);
-		param->out_pkt = ODP_PACKET_INVALID;
+		odp_packet_free(out_pkt);
+		out_pkt = ODP_PACKET_INVALID;
 	}
 
 	return -1;
 }
 
-int odp_crypto_term_global(void)
+int odp_crypto_op(const odp_packet_t pkt_in[],
+		  odp_packet_t pkt_out[],
+		  const odp_crypto_packet_op_param_t param[],
+		  int num_pkt)
 {
-	int rc = 0;
-	int ret;
-	int count = 0;
-	crypto_session_entry_t *session;
-
-	odp_spinlock_init(&global->lock);
-	odp_spinlock_lock(&global->lock);
-	for (session = global->free; session != NULL; session = session->next)
-		count++;
-	if (count != MAX_SESSIONS) {
-		ODP_ERR("crypto sessions still active\n");
-		rc = -1;
-	}
-
-	if (global->crypto_op_pool != NULL)
-		rte_mempool_free(global->crypto_op_pool);
+	crypto_session_entry_t *entry;
+	int i, rc;
 
-	odp_spinlock_unlock(&global->lock);
+	entry = (crypto_session_entry_t *)(intptr_t)param->session;
+	ODP_ASSERT(ODP_CRYPTO_SYNC == entry->p.op_mode);
 
-	ret = odp_shm_free(crypto_global_shm);
-	if (ret < 0) {
-		ODP_ERR("shm free failed for crypto_pool\n");
-		rc = -1;
+	for (i = 0; i < num_pkt; i++) {
+		rc = odp_crypto_int(pkt_in[i], &pkt_out[i], &param[i]);
+		if (rc < 0)
+			break;
 	}
 
-	return rc;
+	return i;
 }
 
-odp_random_kind_t odp_random_max_kind(void)
-{
-	return ODP_RANDOM_CRYPTO;
-}
-
-int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
+int odp_crypto_op_enq(const odp_packet_t pkt_in[],
+		      const odp_packet_t pkt_out[],
+		      const odp_crypto_packet_op_param_t param[],
+		      int num_pkt)
 {
-	int rc;
-
-	switch (kind) {
-	case ODP_RANDOM_BASIC:
-		RAND_pseudo_bytes(buf, len);
-		return len;
-
-	case ODP_RANDOM_CRYPTO:
-		rc = RAND_bytes(buf, len);
-		return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;
-
-	case ODP_RANDOM_TRUE:
-	default:
-		return -1;
-	}
-}
-
-int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
-{
-	union {
-		uint32_t rand_word;
-		uint8_t rand_byte[4];
-	} u;
-	uint32_t i = 0, j;
-	uint32_t seed32 = (*seed) & 0xffffffff;
-
-	while (i < len) {
-		u.rand_word = rand_r(&seed32);
+	odp_packet_t pkt;
+	odp_event_t event;
+	crypto_session_entry_t *entry;
+	int i, rc;
 
-		for (j = 0; j < 4 && i < len; j++, i++)
-			*buf++ = u.rand_byte[j];
+	entry = (crypto_session_entry_t *)(intptr_t)param->session;
+	ODP_ASSERT(ODP_CRYPTO_ASYNC == entry->p.op_mode);
+	ODP_ASSERT(ODP_QUEUE_INVALID != entry->p.compl_queue);
+
+	for (i = 0; i < num_pkt; i++) {
+		pkt = pkt_out[i];
+		rc = odp_crypto_int(pkt_in[i], &pkt, &param[i]);
+		if (rc < 0)
+			break;
+
+		event = odp_packet_to_event(pkt);
+		if (odp_queue_enq(entry->p.compl_queue, event)) {
+			odp_event_free(event);
+			break;
+		}
 	}
 
-	*seed = seed32;
-	return len;
-}
-
-odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)
-{
-	/* This check not mandated by the API specification */
-	if (odp_event_type(ev) != ODP_EVENT_CRYPTO_COMPL)
-		ODP_ABORT("Event not a crypto completion");
-	return (odp_crypto_compl_t)ev;
-}
-
-odp_event_t odp_crypto_compl_to_event(odp_crypto_compl_t completion_event)
-{
-	return (odp_event_t)completion_event;
-}
-
-void odp_crypto_compl_result(odp_crypto_compl_t completion_event,
-			     odp_crypto_op_result_t *result)
-{
-	odp_event_t ev = odp_crypto_compl_to_event(completion_event);
-	odp_crypto_generic_op_result_t *op_result;
-
-	op_result = get_op_result_from_event(ev);
-
-	if (OP_RESULT_MAGIC != op_result->magic)
-		ODP_ABORT();
-
-	memcpy(result, &op_result->result, sizeof(*result));
-}
-
-void odp_crypto_compl_free(odp_crypto_compl_t completion_event)
-{
-	_odp_buffer_event_type_set(
-		odp_buffer_from_event((odp_event_t)completion_event),
-		ODP_EVENT_PACKET);
-}
-
-void odp_crypto_session_param_init(odp_crypto_session_param_t *param)
-{
-	memset(param, 0, sizeof(odp_crypto_session_param_t));
-}
-
-uint64_t odp_crypto_session_to_u64(odp_crypto_session_t hdl)
-{
-	return (uint64_t)hdl;
-}
-
-uint64_t odp_crypto_compl_to_u64(odp_crypto_compl_t hdl)
-{
-	return _odp_pri(hdl);
+	return i;
 }
diff --git a/platform/linux-dpdk/odp_init.c b/platform/linux-dpdk/odp_init.c
index 6cea393b..96c535ba 100644
--- a/platform/linux-dpdk/odp_init.c
+++ b/platform/linux-dpdk/odp_init.c
@@ -12,6 +12,8 @@
 #include <unistd.h>
 #include <odp_internal.h>
 #include <odp_schedule_if.h>
+#include <libconfig.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <linux/limits.h>
@@ -23,6 +25,15 @@
 #define _ODP_FILES_FMT "odp-%d-"
 #define _ODP_TMPDIR    "/tmp"
 
+/* the name of the ODP configuration file: */
+#define CONFIGURATION_FILE_ENV_NONE "none"
+#define CONFIGURATION_FILE "odp.conf"
+#define CONFIGURATION_FILE_USR ("." CONFIGURATION_FILE)
+#define CONFIGURATION_FILE_SYS (SYSCONFDIR "/" CONFIGURATION_FILE)
+
+/* the ODP configuration file name can also be oveerwritten by env. variable: */
+#define ODP_SYSCONFIG_FILE_ENV "ODP_SYSCONFIG_FILE"
+
 #define MEMPOOL_OPS(hdl) extern void mp_hdlr_init_##hdl(void);
 MEMPOOL_OPS(ops_mp_mc)
 MEMPOOL_OPS(ops_sp_sc)
@@ -189,6 +200,82 @@ static int cleanup_files(const char *dirpath, int odp_pid)
 	return 0;
 }
 
+/* read the odp configuration file
+ *
+ * the configuration file is read from:
+ * 1) Wherever env variable ODP_SYSCONFIG_FILE says (or "none")
+ * 2) ./odp.conf
+ * 3) the @sysconfig@/odp.conf
+ * (checked in reverse order overwriting each-other)
+ * So the environment variable setting supperseeds any other file.
+ * If the environment variable exists and set to the string "none"
+ * the configuration file reading is inibited (used to prevent
+ * test which do not need a file to read the user or system files)
+ */
+static int read_configfile(void)
+{
+	config_t *cf;
+	const char *config_filename;
+	char user_config_filename[PATH_MAX];
+	char *env_config_filename;
+
+	/* initialize and read the configuration file if any: */
+	cf = &odp_global_data.configuration;
+	config_init(cf);
+	config_filename = NULL;
+	/* check if the system config file can be reached :*/
+	if (access(CONFIGURATION_FILE_SYS, R_OK) != -1)
+		config_filename = CONFIGURATION_FILE_SYS;
+	/* check if the user config file can be reached (overwrite if so) :*/
+	strncpy(user_config_filename, getenv("HOME"), PATH_MAX);
+	if (user_config_filename[0]) {
+		strncat(user_config_filename, "/", PATH_MAX);
+		strncat(user_config_filename, CONFIGURATION_FILE_USR, PATH_MAX);
+		if ((access(user_config_filename, R_OK) != -1))
+			config_filename = user_config_filename;
+	}
+	/* check if other config file is specified via env (overwrite if so):*/
+	env_config_filename = getenv(ODP_SYSCONFIG_FILE_ENV);
+	if (env_config_filename) {
+		/* none means "read no file": */
+		if (!strcmp(env_config_filename, CONFIGURATION_FILE_ENV_NONE))
+			return 0;
+		if (access(env_config_filename, R_OK) != -1) {
+			config_filename = env_config_filename;
+		} else {
+			ODP_ERR("Cannot read ODP configurattion file %s "
+				"(set by env variable "
+				ODP_SYSCONFIG_FILE_ENV ")\n",
+				env_config_filename);
+			config_filename = NULL;
+			return -1;
+		}
+	}
+	if (config_filename) {
+		ODP_DBG("Reading configuration file: %s\n", config_filename);
+		if (!config_read_file(cf, config_filename)) {
+#if defined(LIBCONFIG_VER_MAJOR) && LIBCONFIG_VER_MAJOR >= 1 && \
+				    LIBCONFIG_VER_MINOR >= 4
+			ODP_ERR("%s:%d - %s\n",
+				config_error_file(cf),
+				config_error_line(cf),
+				config_error_text(cf));
+#else
+			ODP_ERR("config_read_file\n");
+#endif
+			config_destroy(cf);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void odp_init_param_init(odp_init_t *param)
+{
+	memset(param, 0, sizeof(odp_init_t));
+}
+
 int odp_init_global(odp_instance_t *instance,
 		    const odp_init_t *params,
 		    const odp_platform_init_t *platform_params)
@@ -211,6 +298,9 @@ int odp_init_global(odp_instance_t *instance,
 
 	cleanup_files(_ODP_TMPDIR, odp_global_data.main_pid);
 
+	if (read_configfile())
+		goto init_failed;
+
 	if (odp_cpumask_init_global(params)) {
 		ODP_ERR("ODP cpumask init failed.\n");
 		goto init_failed;
@@ -238,18 +328,18 @@ int odp_init_global(odp_instance_t *instance,
 		cleanup_files(hpdir, odp_global_data.main_pid);
 	stage = SYSINFO_INIT;
 
-	if (_odp_fdserver_init_global()) {
-		ODP_ERR("ODP fdserver init failed.\n");
-		goto init_failed;
-	}
-	stage = FDSERVER_INIT;
-
 	if (_odp_ishm_init_global()) {
 		ODP_ERR("ODP ishm init failed.\n");
 		goto init_failed;
 	}
 	stage = ISHM_INIT;
 
+	if (_odp_fdserver_init_global()) {
+		ODP_ERR("ODP fdserver init failed.\n");
+		goto init_failed;
+	}
+	stage = FDSERVER_INIT;
+
 	if (odp_thread_init_global()) {
 		ODP_ERR("ODP thread init failed.\n");
 		goto init_failed;
@@ -262,7 +352,7 @@ int odp_init_global(odp_instance_t *instance,
 	}
 	stage = POOL_INIT;
 
-	if (odp_queue_init_global()) {
+	if (queue_fn->init_global()) {
 		ODP_ERR("ODP queue init failed.\n");
 		goto init_failed;
 	}
@@ -280,7 +370,7 @@ int odp_init_global(odp_instance_t *instance,
 	}
 	stage = PKTIO_INIT;
 
-	if (odp_timer_init_global()) {
+	if (odp_timer_init_global(params)) {
 		ODP_ERR("ODP timer init failed.\n");
 		goto init_failed;
 	}
@@ -308,6 +398,19 @@ int odp_init_global(odp_instance_t *instance,
 		ODP_ERR("ODP name table init failed\n");
 		goto init_failed;
 	}
+	stage = NAME_TABLE_INIT;
+
+	if (_odpdrv_driver_init_global()) {
+		ODP_ERR("ODP drivers init failed\n");
+		goto init_failed;
+	}
+	stage = DRIVER_INIT;
+
+	if (_odp_modules_init_global()) {
+		ODP_ERR("ODP modules init failed\n");
+		goto init_failed;
+	}
+	/* stage = DRIVER_INIT; */
 
 	/* Dummy support for single instance */
 	*instance = (odp_instance_t)odp_global_data.main_pid;
@@ -334,6 +437,14 @@ int _odp_term_global(enum init_stage stage)
 
 	switch (stage) {
 	case ALL_INIT:
+	case MODULES_INIT:
+	case DRIVER_INIT:
+		if (_odpdrv_driver_term_global()) {
+			ODP_ERR("driver term failed.\n");
+			rc = -1;
+		}
+		/* Fall through */
+
 	case NAME_TABLE_INIT:
 		if (_odp_int_name_tbl_term_global()) {
 			ODP_ERR("Name table term failed.\n");
@@ -384,7 +495,7 @@ int _odp_term_global(enum init_stage stage)
 		/* Fall through */
 
 	case QUEUE_INIT:
-		if (odp_queue_term_global()) {
+		if (queue_fn->term_global()) {
 			ODP_ERR("ODP queue term failed.\n");
 			rc = -1;
 		}
@@ -404,16 +515,16 @@ int _odp_term_global(enum init_stage stage)
 		}
 		/* Fall through */
 
-	case ISHM_INIT:
-		if (_odp_ishm_term_global()) {
-			ODP_ERR("ODP ishm term failed.\n");
+	case FDSERVER_INIT:
+		if (_odp_fdserver_term_global()) {
+			ODP_ERR("ODP fdserver term failed.\n");
 			rc = -1;
 		}
 		/* Fall through */
 
-	case FDSERVER_INIT:
-		if (_odp_fdserver_term_global()) {
-			ODP_ERR("ODP fdserver term failed.\n");
+	case ISHM_INIT:
+		if (_odp_ishm_term_global()) {
+			ODP_ERR("ODP ishm term failed.\n");
 			rc = -1;
 		}
 		/* Fall through */
diff --git a/platform/linux-dpdk/odp_packet.c b/platform/linux-dpdk/odp_packet.c
index 0d05e23f..af4f8259 100644
--- a/platform/linux-dpdk/odp_packet.c
+++ b/platform/linux-dpdk/odp_packet.c
@@ -191,6 +191,7 @@ int odp_packet_reset(odp_packet_t pkt, uint32_t len)
 	pkt_hdr->buf_hdr.next = NULL;
 
 	pkt_hdr->input = ODP_PKTIO_INVALID;
+	pkt_hdr->buf_hdr.event_subtype = ODP_EVENT_PACKET_BASIC;
 
 	mb->port = 0xff;
 	mb->pkt_len = len;
@@ -217,20 +218,9 @@ int odp_packet_reset(odp_packet_t pkt, uint32_t len)
 	return 0;
 }
 
-odp_packet_t _odp_packet_from_buffer(odp_buffer_t buf)
+odp_packet_t _odp_packet_from_buf_hdr(odp_buffer_hdr_t *buf_hdr)
 {
-	if (odp_unlikely(buf == ODP_BUFFER_INVALID))
-		return ODP_PACKET_INVALID;
-
-	return (odp_packet_t)buf_to_packet_hdr(buf);
-}
-
-odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt)
-{
-	if (odp_unlikely(pkt == ODP_PACKET_INVALID))
-		return ODP_BUFFER_INVALID;
-
-	return buffer_handle(odp_packet_hdr(pkt));
+	return (odp_packet_t)buf_hdr;
 }
 
 odp_packet_t odp_packet_from_event(odp_event_t ev)
@@ -1007,7 +997,7 @@ void odp_packet_print(odp_packet_t pkt)
 	int len = 0;
 	int n = max_len - 1;
 	odp_packet_hdr_t *hdr = odp_packet_hdr(pkt);
-	odp_buffer_t buf      = _odp_packet_to_buffer(pkt);
+	odp_buffer_t buf      = packet_to_buffer(pkt);
 
 	len += snprintf(&str[len], n - len, "Packet ");
 	len += odp_buffer_snprint(&str[len], n - len, buf);
@@ -1062,7 +1052,7 @@ void odp_packet_print(odp_packet_t pkt)
 
 int odp_packet_is_valid(odp_packet_t pkt)
 {
-	odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+	odp_buffer_t buf = packet_to_buffer(pkt);
 
 	return odp_buffer_is_valid(buf);
 }
diff --git a/platform/linux-dpdk/odp_packet_dpdk.c b/platform/linux-dpdk/odp_packet_dpdk.c
index d056a824..649fbf4b 100644
--- a/platform/linux-dpdk/odp_packet_dpdk.c
+++ b/platform/linux-dpdk/odp_packet_dpdk.c
@@ -42,7 +42,7 @@ const pktio_if_ops_t * const pktio_if_ops[]  = {
 	NULL
 };
 
-extern pktio_table_t *pktio_tbl;
+pktio_table_t *pktio_tbl;
 
 static uint32_t mtu_get_pkt_dpdk(pktio_entry_t *pktio_entry);
 
diff --git a/platform/linux-dpdk/odp_pool.c b/platform/linux-dpdk/odp_pool.c
index 0821cdca..b67c2aa8 100644
--- a/platform/linux-dpdk/odp_pool.c
+++ b/platform/linux-dpdk/odp_pool.c
@@ -226,6 +226,7 @@ odp_dpdk_mbuf_ctor(struct rte_mempool *mp,
 	buf_hdr->pool_hdl = mbp_ctor_arg->pool_hdl;
 	buf_hdr->type = mb_ctor_arg->type;
 	buf_hdr->event_type = mb_ctor_arg->type;
+	buf_hdr->event_subtype = ODP_EVENT_NO_SUBTYPE;
 }
 
 #define CHECK_U16_OVERFLOW(X)	do {			\
diff --git a/test/linux-dpdk/Makefile.inc b/test/linux-dpdk/Makefile.inc
index a24b9362..25493d86 100644
--- a/test/linux-dpdk/Makefile.inc
+++ b/test/linux-dpdk/Makefile.inc
@@ -4,6 +4,8 @@
 
 AM_LDFLAGS += -static
 
+AM_CPPFLAGS += $(CUNIT_CPPFLAGS)
+
 LIBCUNIT_COMMON = $(top_builddir)/test/common_plat/common/libcunit_common.la
 LIB   = $(top_builddir)/lib
 LIBODP = $(LIB)/libodphelper.la $(LIB)/libodp-dpdk.la
