diff --git a/configure.ac b/configure.ac
index 3a20959..e2b4f9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,7 +55,7 @@ AC_PROG_MAKE_SET
 
 AM_PROG_AR
 #Use libtool
-LT_INIT([])
+LT_INIT([dlopen])
 AC_SUBST([LIBTOOL_DEPS])
 AM_PROG_LIBTOOL
 
@@ -66,7 +66,7 @@ AC_CHECK_FUNCS([bzero clock_gettime gethostbyname getpagesize gettimeofday memse
 
 # Checks for header files.
 AC_HEADER_RESOLV
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h dlfcn.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_STDBOOL
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 2d92c97..855f04e 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -176,6 +176,7 @@ __LIB__libodp_linux_la_SOURCES = \
 			   _ishm.c \
 			   _ishmphy.c \
 			   _ishmpool.c \
+			   _modules.c \
 			   odp_atomic.c \
 			   odp_barrier.c \
 			   odp_bitmap.c \
diff --git a/platform/linux-generic/_modules.c b/platform/linux-generic/_modules.c
new file mode 100644
index 0000000..6bb854e
--- /dev/null
+++ b/platform/linux-generic/_modules.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <odp_config_internal.h>
+
+#include <odp/api/std_types.h>
+#include <odp/api/debug.h>
+#include <odp_debug_internal.h>
+#include <libconfig.h>
+#include <dlfcn.h>
+
+static int load_modules(void)
+{
+	config_t *cf;
+	const config_setting_t *modules_section;
+	int module_count;
+	int i;
+	const char *module_name;
+
+	cf = &odp_global_data.configuration;
+	modules_section = config_lookup(cf, "module.modules");
+	if (!modules_section)
+		return 0;
+
+	module_count = config_setting_length(modules_section);
+	if (!module_count)
+		return 0;
+
+	for (i = 0; i < module_count; i++) {
+		module_name = config_setting_get_string_elem(modules_section,
+							     i);
+		if (dlopen(module_name, RTLD_NOW) == NULL) {
+			ODP_ERR("dlopen failed for %s: %s\n",
+				module_name, dlerror());
+			return -1;
+		}
+		ODP_DBG("module %s loaded.\n", module_name);
+	}
+
+	return 0;
+}
+
+int _odp_modules_init_global(void)
+{
+	/* load modules (enumerator and drivers...) */
+	if (load_modules())
+		return -1;
+
+	return 0;
+}
diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h
index 9d1fc58..05c8a42 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -71,6 +71,7 @@ enum init_stage {
 	CLASSIFICATION_INIT,
 	TRAFFIC_MNGR_INIT,
 	NAME_TABLE_INIT,
+	MODULES_INIT,
 	ALL_INIT      /* All init stages completed */
 };
 
@@ -129,6 +130,8 @@ int _odp_ishm_init_local(void);
 int _odp_ishm_term_global(void);
 int _odp_ishm_term_local(void);
 
+int _odp_modules_init_global(void);
+
 int cpuinfo_parser(FILE *file, system_info_t *sysinfo);
 uint64_t odp_cpu_hz_current(int id);
 
diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
index 5fab0cc..f5f076a 100644
--- a/platform/linux-generic/m4/configure.m4
+++ b/platform/linux-generic/m4/configure.m4
@@ -42,6 +42,7 @@ fi
 m4_include([platform/linux-generic/m4/odp_pthread.m4])
 m4_include([platform/linux-generic/m4/odp_openssl.m4])
 m4_include([platform/linux-generic/m4/odp_pcap.m4])
+m4_include([platform/linux-generic/m4/odp_modules.m4])
 m4_include([platform/linux-generic/m4/odp_netmap.m4])
 m4_include([platform/linux-generic/m4/odp_dpdk.m4])
 m4_include([platform/linux-generic/m4/odp_ipc.m4])
diff --git a/platform/linux-generic/m4/odp_modules.m4 b/platform/linux-generic/m4/odp_modules.m4
new file mode 100644
index 0000000..03f61f8
--- /dev/null
+++ b/platform/linux-generic/m4/odp_modules.m4
@@ -0,0 +1,11 @@
+##########################################################################
+# Check for dlopen and lt equivalent availability
+##########################################################################
+
+AC_SEARCH_LIBS([dlopen], [dl dld],
+    [
+       AM_LDFLAGS="$AM_LDFLAGS -ldl"
+    ],
+    [
+       AC_MSG_ERROR([Error! dlopen not available!])
+    ])
diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c
index 0e9167c..2cd8fe3 100644
--- a/platform/linux-generic/odp_init.c
+++ b/platform/linux-generic/odp_init.c
@@ -259,6 +259,12 @@ int odp_init_global(odp_instance_t *instance,
 		ODP_ERR("ODP name table init failed\n");
 		goto init_failed;
 	}
+	stage = NAME_TABLE_INIT;
+
+	if (_odp_modules_init_global()) {
+		ODP_ERR("ODP modules init failed\n");
+		goto init_failed;
+	}
 
 	*instance = (odp_instance_t)odp_global_data.main_pid;
 
@@ -284,6 +290,7 @@ int _odp_term_global(enum init_stage stage)
 
 	switch (stage) {
 	case ALL_INIT:
+	case MODULES_INIT:
 	case NAME_TABLE_INIT:
 		if (_odp_int_name_tbl_term_global()) {
 			ODP_ERR("Name table term failed.\n");
