diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am
index 587d4836f..83931d27a 100644
--- a/platform/linux-dpdk/Makefile.am
+++ b/platform/linux-dpdk/Makefile.am
@@ -189,6 +189,7 @@ noinst_HEADERS = \
 		  ${top_srcdir}/platform/linux-generic/include/odp_internal.h \
 		  ${srcdir}/include/odp_packet_dpdk.h \
 		  ${srcdir}/include/odp_packet_internal.h \
+		  ${top_srcdir}/platform/linux-generic/include/odp_pktio_ops_subsystem.h \
 		  ${top_srcdir}/platform/linux-generic/include/odp_name_table_internal.h \
 		  ${srcdir}/include/odp_packet_io_internal.h \
 		  ${srcdir}/include/odp_errno_define.h \
@@ -242,6 +243,7 @@ __LIB__libodp_dpdk_la_SOURCES = \
 			   ../linux-generic/odp_name_table.c \
 			   odp_packet.c \
 			   odp_packet_dpdk.c \
+			   pktio/subsystem.c \
 			   odp_packet_flags.c \
 			   ../linux-generic/odp_packet_io.c \
 			   ../linux-generic/pktio/loop.c \
diff --git a/platform/linux-dpdk/include/odp_packet_io_internal.h b/platform/linux-dpdk/include/odp_packet_io_internal.h
index 14b6a8d3b..fde172fc5 100644
--- a/platform/linux-dpdk/include/odp_packet_io_internal.h
+++ b/platform/linux-dpdk/include/odp_packet_io_internal.h
@@ -31,13 +31,16 @@ extern "C" {
 #include <linux/if_ether.h>
 #include <odp_packet_dpdk.h>
 
+/* Forward declaration */
+typedef union pktio_entry_u pktio_entry_t;
+#include <odp_pktio_ops_subsystem.h>
+
 #define PKTIO_NAME_LEN 256
 
 #define PKTIN_INVALID  ((odp_pktin_queue_t) {ODP_PKTIO_INVALID, 0})
 #define PKTOUT_INVALID ((odp_pktout_queue_t) {ODP_PKTIO_INVALID, 0})
 
 /* Forward declaration */
-struct pktio_if_ops;
 struct pkt_dpdk_t;
 
 typedef struct {
@@ -63,7 +66,7 @@ typedef struct {
 } pkt_dpdk_t;
 
 struct pktio_entry {
-	const struct pktio_if_ops *ops; /**< Implementation specific methods */
+	const pktio_ops_module_t *ops;	/**< Implementation specific methods */
 	/* These two locks together lock the whole pktio device */
 	odp_ticketlock_t rxl;		/**< RX ticketlock */
 	odp_ticketlock_t txl;		/**< TX ticketlock */
@@ -116,50 +119,16 @@ struct pktio_entry {
 	} out_queue[PKTIO_MAX_QUEUES];
 };
 
-typedef union {
+union pktio_entry_u {
 	struct pktio_entry s;
 	uint8_t pad[ROUNDUP_CACHE_LINE(sizeof(struct pktio_entry))];
-} pktio_entry_t;
+};
 
 typedef struct {
 	odp_spinlock_t lock;
 	pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES];
 } pktio_table_t;
 
-typedef struct pktio_if_ops {
-	const char *name;
-	void (*print)(pktio_entry_t *pktio_entry);
-	int (*init_global)(void);
-	int (*init_local)(void);
-	int (*term)(void);
-	int (*open)(odp_pktio_t pktio, pktio_entry_t *pktio_entry,
-		    const char *devname, odp_pool_t pool);
-	int (*close)(pktio_entry_t *pktio_entry);
-	int (*start)(pktio_entry_t *pktio_entry);
-	int (*stop)(pktio_entry_t *pktio_entry);
-	int (*stats)(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats);
-	int (*stats_reset)(pktio_entry_t *pktio_entry);
-	uint64_t (*pktin_ts_res)(pktio_entry_t *pktio_entry);
-	odp_time_t (*pktin_ts_from_ns)(pktio_entry_t *pktio_entry, uint64_t ns);
-	int (*recv)(pktio_entry_t *entry, int index, odp_packet_t packets[],
-		    int num);
-	int (*send)(pktio_entry_t *entry, int index,
-		    const odp_packet_t packets[], int num);
-	uint32_t (*mtu_get)(pktio_entry_t *pktio_entry);
-	int (*promisc_mode_set)(pktio_entry_t *pktio_entry,  int enable);
-	int (*promisc_mode_get)(pktio_entry_t *pktio_entry);
-	int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr);
-	int (*link_status)(pktio_entry_t *pktio_entry);
-	int (*capability)(pktio_entry_t *pktio_entry,
-			  odp_pktio_capability_t *capa);
-	int (*config)(pktio_entry_t *pktio_entry,
-		      const odp_pktio_config_t *config);
-	int (*input_queues_config)(pktio_entry_t *pktio_entry,
-				   const odp_pktin_queue_param_t *param);
-	int (*output_queues_config)(pktio_entry_t *pktio_entry,
-				    const odp_pktout_queue_param_t *p);
-} pktio_if_ops_t;
-
 extern void *pktio_entry_ptr[];
 
 static inline int pktio_to_id(odp_pktio_t pktio)
@@ -203,10 +172,6 @@ int single_recv_queue(pktio_entry_t *entry, int index, odp_packet_t packets[],
 int single_send_queue(pktio_entry_t *entry, int index,
 		      const odp_packet_t packets[], int num);
 
-extern const pktio_if_ops_t loopback_pktio_ops;
-extern const pktio_if_ops_t dpdk_pktio_ops;
-extern const pktio_if_ops_t * const pktio_if_ops[];
-
 int pktin_poll(int pktio_index, int num_queue, int index[]);
 void pktio_stop_finalize(int pktio_index);
 
diff --git a/platform/linux-dpdk/odp_packet_dpdk.c b/platform/linux-dpdk/odp_packet_dpdk.c
index d808f130f..214116b76 100644
--- a/platform/linux-dpdk/odp_packet_dpdk.c
+++ b/platform/linux-dpdk/odp_packet_dpdk.c
@@ -32,18 +32,11 @@
 #include <net/if.h>
 #include <math.h>
 
-/* Ops for all implementation of pktio.
- * Order matters. The first implementation to setup successfully
- * will be picked.
- * Array must be NULL terminated */
-const pktio_if_ops_t * const pktio_if_ops[]  = {
-	&loopback_pktio_ops,
-	&dpdk_pktio_ops,
-	NULL
-};
-
 pktio_table_t *pktio_tbl;
 
+/* Forward declaration */
+static pktio_ops_module_t dpdk_pktio_ops;
+
 static uint32_t mtu_get_pkt_dpdk(pktio_entry_t *pktio_entry);
 
 /* Test if s has only digits or not. Dpdk pktio uses only digits.*/
@@ -686,12 +679,15 @@ static int stats_reset_pkt_dpdk(pktio_entry_t *pktio_entry)
 	return 0;
 }
 
-const pktio_if_ops_t dpdk_pktio_ops = {
-	.name = "odp-dpdk",
+static pktio_ops_module_t dpdk_pktio_ops = {
+	.base = {
+		.name = "dpdk",
+		.init_local = NULL,
+		.init_global = NULL,
+		.term_local = NULL,
+		.term_global = NULL,
+	},
 	.print = NULL,
-	.init_global = NULL,
-	.init_local = NULL,
-	.term = NULL,
 	.open = setup_pkt_dpdk,
 	.close = close_pkt_dpdk,
 	.start = start_pkt_dpdk,
@@ -712,3 +708,16 @@ const pktio_if_ops_t dpdk_pktio_ops = {
 	.recv = recv_pkt_dpdk,
 	.send = send_pkt_dpdk
 };
+
+ODP_MODULE_CONSTRUCTOR(dpdk_pktio_ops)
+{
+	odp_module_constructor(&dpdk_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &dpdk_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_dpdk_pktio_ops = 0;
+
diff --git a/platform/linux-dpdk/pktio/subsystem.c b/platform/linux-dpdk/pktio/subsystem.c
new file mode 100644
index 000000000..4ff15c814
--- /dev/null
+++ b/platform/linux-dpdk/pktio/subsystem.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp_debug_internal.h>
+#include <odp_packet_io_internal.h>
+
+#define SUBSYSTEM_VERSION 0x00010000UL
+ODP_SUBSYSTEM_DEFINE(pktio_ops, "packet IO operations", SUBSYSTEM_VERSION);
+
+/* Instantiate init and term functions */
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, init_global, ODP_ERR)
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, init_local, ODP_ERR)
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, term_global, ODP_ABORT)
+
+/* Temporary variable to enable link modules,
+ * will remove in Makefile scheme changes.
+ */
+extern int enable_link_dpdk_pktio_ops;
+extern int enable_link_loopback_pktio_ops;
+
+ODP_SUBSYSTEM_CONSTRUCTOR(pktio_ops)
+{
+	odp_subsystem_constructor(pktio_ops);
+
+	/* Further initialization per subsystem */
+	enable_link_dpdk_pktio_ops = 1;
+	enable_link_loopback_pktio_ops = 1;
+}
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index cbbefa4e6..ff08a6ef4 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -191,6 +191,7 @@ noinst_HEADERS = \
 		  ${srcdir}/include/odp_packet_dpdk.h \
 		  ${srcdir}/include/odp_packet_socket.h \
 		  ${srcdir}/include/odp_packet_tap.h \
+		  ${srcdir}/include/odp_pktio_ops_subsystem.h \
 		  ${srcdir}/include/odp_pkt_queue_internal.h \
 		  ${srcdir}/include/odp_pool_internal.h \
 		  ${srcdir}/include/odp_pool_subsystem.h \
@@ -262,7 +263,7 @@ __LIB__libodp_linux_la_SOURCES = \
 			   odp_packet_flags.c \
 			   odp_packet_io.c \
 			   pktio/ethtool.c \
-			   pktio/io_ops.c \
+			   pktio/subsystem.c \
 			   pktio/ipc.c \
 			   pktio/pktio_common.c \
 			   pktio/loop.c \
diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h
index dc049f467..589148400 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -36,6 +36,10 @@ extern "C" {
 #include <odp_packet_tap.h>
 #include <odp_packet_dpdk.h>
 
+/* Forward declaration */
+typedef union pktio_entry_u pktio_entry_t;
+#include <odp_pktio_ops_subsystem.h>
+
 #define PKTIO_NAME_LEN 256
 
 #define PKTIN_INVALID  ((odp_pktin_queue_t) {ODP_PKTIO_INVALID, 0})
@@ -47,9 +51,6 @@ extern "C" {
  *  requested number of packets were not handled. */
 #define SOCK_ERR_REPORT(e) (e != EAGAIN && e != EWOULDBLOCK && e != EINTR)
 
-/* Forward declaration */
-struct pktio_if_ops;
-
 typedef struct {
 	odp_queue_t loopq;		/**< loopback queue for "loop" device */
 	odp_bool_t promisc;		/**< promiscuous mode state */
@@ -109,7 +110,7 @@ typedef	struct {
 } _ipc_pktio_t;
 
 struct pktio_entry {
-	const struct pktio_if_ops *ops; /**< Implementation specific methods */
+	const pktio_ops_module_t *ops;	/**< Implementation specific methods */
 	/* These two locks together lock the whole pktio device */
 	odp_ticketlock_t rxl;		/**< RX ticketlock */
 	odp_ticketlock_t txl;		/**< TX ticketlock */
@@ -177,50 +178,16 @@ struct pktio_entry {
 	} out_queue[PKTIO_MAX_QUEUES];
 };
 
-typedef union {
+union pktio_entry_u {
 	struct pktio_entry s;
 	uint8_t pad[ROUNDUP_CACHE_LINE(sizeof(struct pktio_entry))];
-} pktio_entry_t;
+};
 
 typedef struct {
 	odp_spinlock_t lock;
 	pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES];
 } pktio_table_t;
 
-typedef struct pktio_if_ops {
-	const char *name;
-	void (*print)(pktio_entry_t *pktio_entry);
-	int (*init_global)(void);
-	int (*init_local)(void);
-	int (*term)(void);
-	int (*open)(odp_pktio_t pktio, pktio_entry_t *pktio_entry,
-		    const char *devname, odp_pool_t pool);
-	int (*close)(pktio_entry_t *pktio_entry);
-	int (*start)(pktio_entry_t *pktio_entry);
-	int (*stop)(pktio_entry_t *pktio_entry);
-	int (*stats)(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats);
-	int (*stats_reset)(pktio_entry_t *pktio_entry);
-	uint64_t (*pktin_ts_res)(pktio_entry_t *pktio_entry);
-	odp_time_t (*pktin_ts_from_ns)(pktio_entry_t *pktio_entry, uint64_t ns);
-	int (*recv)(pktio_entry_t *entry, int index, odp_packet_t packets[],
-		    int num);
-	int (*send)(pktio_entry_t *entry, int index,
-		    const odp_packet_t packets[], int num);
-	uint32_t (*mtu_get)(pktio_entry_t *pktio_entry);
-	int (*promisc_mode_set)(pktio_entry_t *pktio_entry,  int enable);
-	int (*promisc_mode_get)(pktio_entry_t *pktio_entry);
-	int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr);
-	int (*link_status)(pktio_entry_t *pktio_entry);
-	int (*capability)(pktio_entry_t *pktio_entry,
-			  odp_pktio_capability_t *capa);
-	int (*config)(pktio_entry_t *pktio_entry,
-		      const odp_pktio_config_t *config);
-	int (*input_queues_config)(pktio_entry_t *pktio_entry,
-				   const odp_pktin_queue_param_t *param);
-	int (*output_queues_config)(pktio_entry_t *pktio_entry,
-				    const odp_pktout_queue_param_t *p);
-} pktio_if_ops_t;
-
 extern void *pktio_entry_ptr[];
 
 static inline int pktio_to_id(odp_pktio_t pktio)
@@ -252,18 +219,6 @@ static inline void pktio_cls_enabled_set(pktio_entry_t *entry, int ena)
 	entry->s.cls_enabled = ena;
 }
 
-extern const pktio_if_ops_t netmap_pktio_ops;
-extern const pktio_if_ops_t dpdk_pktio_ops;
-extern const pktio_if_ops_t sock_mmsg_pktio_ops;
-extern const pktio_if_ops_t sock_mmap_pktio_ops;
-extern const pktio_if_ops_t loopback_pktio_ops;
-#ifdef HAVE_PCAP
-extern const pktio_if_ops_t pcap_pktio_ops;
-#endif
-extern const pktio_if_ops_t tap_pktio_ops;
-extern const pktio_if_ops_t ipc_pktio_ops;
-extern const pktio_if_ops_t * const pktio_if_ops[];
-
 int sysfs_stats(pktio_entry_t *pktio_entry,
 		odp_pktio_stats_t *stats);
 int sock_stats_fd(pktio_entry_t *pktio_entry,
diff --git a/platform/linux-generic/include/odp_pktio_ops_subsystem.h b/platform/linux-generic/include/odp_pktio_ops_subsystem.h
new file mode 100644
index 000000000..ff497a2ac
--- /dev/null
+++ b/platform/linux-generic/include/odp_pktio_ops_subsystem.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ODP_PKTIO_OPS_SUBSYSTEM_H_
+#define ODP_PKTIO_OPS_SUBSYSTEM_H_
+
+#include <odp_module.h>
+#include <odp/api/packet_io.h>
+
+/* ODP packet IO operations subsystem declaration */
+ODP_SUBSYSTEM_DECLARE(pktio_ops);
+
+/* Subsystem APIs declarations */
+ODP_SUBSYSTEM_API(pktio_ops, int, open, odp_pktio_t,
+		  pktio_entry_t *, const char *, odp_pool_t);
+ODP_SUBSYSTEM_API(pktio_ops, int, close, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, start, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, stop, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, stats, pktio_entry_t *,
+		  odp_pktio_stats_t *stats);
+ODP_SUBSYSTEM_API(pktio_ops, int, stats_reset, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, uint64_t, pktin_ts_res, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, odp_time_t, pktin_ts_from_ns,
+		  pktio_entry_t *, uint64_t ns);
+ODP_SUBSYSTEM_API(pktio_ops, int, recv, pktio_entry_t *,
+		  int index, odp_packet_t packets[], int count);
+ODP_SUBSYSTEM_API(pktio_ops, int, send, pktio_entry_t *,
+		  int index, const odp_packet_t packets[], int count);
+ODP_SUBSYSTEM_API(pktio_ops, uint32_t, mtu_get, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, promisc_mode_set,
+		  pktio_entry_t *, int enable);
+ODP_SUBSYSTEM_API(pktio_ops, int, promisc_mode_get, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, mac_get, pktio_entry_t *, void *);
+ODP_SUBSYSTEM_API(pktio_ops, int, link_status, pktio_entry_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, capability, pktio_entry_t *,
+		  odp_pktio_capability_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, config, pktio_entry_t *,
+		  const odp_pktio_config_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, input_queues_config,
+		  pktio_entry_t *, const odp_pktin_queue_param_t *);
+ODP_SUBSYSTEM_API(pktio_ops, int, output_queues_config,
+		  pktio_entry_t *, const odp_pktout_queue_param_t *);
+ODP_SUBSYSTEM_API(pktio_ops, void, print, pktio_entry_t *);
+
+/* Declare subsystem init and term routines */
+ODP_SUBSYSTEM_API(pktio_ops, int, init_global, bool);
+ODP_SUBSYSTEM_API(pktio_ops, int, init_local, bool);
+ODP_SUBSYSTEM_API(pktio_ops, int, term_global, bool);
+ODP_SUBSYSTEM_API(pktio_ops, int, term_local, bool);
+
+typedef ODP_MODULE_CLASS(pktio_ops) {
+	odp_module_base_t base;
+
+	odp_api_proto(pktio_ops, open) open;
+	odp_api_proto(pktio_ops, close) close;
+	odp_api_proto(pktio_ops, start) start;
+	odp_api_proto(pktio_ops, stop) stop;
+	odp_api_proto(pktio_ops, stats) stats;
+	odp_api_proto(pktio_ops, stats_reset) stats_reset;
+	odp_api_proto(pktio_ops, pktin_ts_res) pktin_ts_res;
+	odp_api_proto(pktio_ops, pktin_ts_from_ns) pktin_ts_from_ns;
+	odp_api_proto(pktio_ops, recv) recv;
+	odp_api_proto(pktio_ops, send) send;
+	odp_api_proto(pktio_ops, mtu_get) mtu_get;
+	odp_api_proto(pktio_ops, promisc_mode_set) promisc_mode_set;
+	odp_api_proto(pktio_ops, promisc_mode_get) promisc_mode_get;
+	odp_api_proto(pktio_ops, mac_get) mac_get;
+	odp_api_proto(pktio_ops, link_status) link_status;
+	odp_api_proto(pktio_ops, capability) capability;
+	odp_api_proto(pktio_ops, config) config;
+	odp_api_proto(pktio_ops, input_queues_config) input_queues_config;
+	odp_api_proto(pktio_ops, output_queues_config) output_queues_config;
+	odp_api_proto(pktio_ops, print) print;
+} pktio_ops_module_t;
+
+#endif
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index e78c712e4..d8dcc45da 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -51,7 +51,6 @@ int odp_pktio_init_global(void)
 	pktio_entry_t *pktio_entry;
 	int i;
 	odp_shm_t shm;
-	int pktio_if;
 
 	shm = odp_shm_reserve("odp_pktio_entries",
 			      sizeof(pktio_table_t),
@@ -76,32 +75,12 @@ int odp_pktio_init_global(void)
 		pktio_entry_ptr[i] = pktio_entry;
 	}
 
-	for (pktio_if = 0; pktio_if_ops[pktio_if]; ++pktio_if) {
-		if (pktio_if_ops[pktio_if]->init_global)
-			if (pktio_if_ops[pktio_if]->init_global()) {
-				ODP_ERR("failed to initialized pktio type %d",
-					pktio_if);
-				return -1;
-			}
-	}
-
-	return 0;
+	return odp_pktio_ops_init_global(true);
 }
 
 int odp_pktio_init_local(void)
 {
-	int pktio_if;
-
-	for (pktio_if = 0; pktio_if_ops[pktio_if]; ++pktio_if) {
-		if (pktio_if_ops[pktio_if]->init_local)
-			if (pktio_if_ops[pktio_if]->init_local()) {
-				ODP_ERR("failed to initialized pktio type %d",
-					pktio_if);
-				return -1;
-			}
-	}
-
-	return 0;
+	return odp_pktio_ops_init_local(true);
 }
 
 static inline int is_free(pktio_entry_t *entry)
@@ -181,8 +160,7 @@ static odp_pktio_t setup_pktio_entry(const char *name, odp_pool_t pool,
 {
 	odp_pktio_t hdl;
 	pktio_entry_t *pktio_entry;
-	int ret = -1;
-	int pktio_if;
+	pktio_ops_module_t *mod;
 
 	if (strlen(name) >= PKTIO_NAME_LEN - 1) {
 		/* ioctl names limitation */
@@ -202,25 +180,24 @@ static odp_pktio_t setup_pktio_entry(const char *name, odp_pool_t pool,
 	if (!pktio_entry)
 		return ODP_PKTIO_INVALID;
 
+	pktio_entry->s.ops = NULL; /* Reset stale ops */
 	pktio_entry->s.pool = pool;
 	memcpy(&pktio_entry->s.param, param, sizeof(odp_pktio_param_t));
 	pktio_entry->s.handle = hdl;
 
 	odp_pktio_config_init(&pktio_entry->s.config);
 
-	for (pktio_if = 0; pktio_if_ops[pktio_if]; ++pktio_if) {
-		ret = pktio_if_ops[pktio_if]->open(hdl, pktio_entry, name,
-						   pool);
-
-		if (!ret) {
-			pktio_entry->s.ops = pktio_if_ops[pktio_if];
-			ODP_DBG("%s uses %s\n",
-				name, pktio_if_ops[pktio_if]->name);
+	odp_subsystem_lock(read, pktio_ops);
+	odp_subsystem_foreach_module(pktio_ops, mod) {
+		if (0 == mod->open(hdl, pktio_entry, name, pool)) {
+			pktio_entry->s.ops = mod;
+			ODP_DBG("%s uses %s\n", name, mod->base.name);
 			break;
 		}
 	}
+	odp_subsystem_unlock(read, pktio_ops);
 
-	if (ret != 0) {
+	if (pktio_entry->s.ops == NULL) {
 		pktio_entry->s.state = PKTIO_STATE_FREE;
 		hdl = ODP_PKTIO_INVALID;
 		ODP_ERR("Unable to init any I/O type.\n");
@@ -913,7 +890,7 @@ int odp_pktio_info(odp_pktio_t hdl, odp_pktio_info_t *info)
 
 	memset(info, 0, sizeof(odp_pktio_info_t));
 	info->name = entry->s.name;
-	info->drv_name = entry->s.ops->name;
+	info->drv_name = entry->s.ops->base.name;
 	info->pool = entry->s.pool;
 	memcpy(&info->param, &entry->s.param, sizeof(odp_pktio_param_t));
 
@@ -988,7 +965,7 @@ void odp_pktio_print(odp_pktio_t hdl)
 	len += snprintf(&str[len], n - len,
 			"  name              %s\n", entry->s.name);
 	len += snprintf(&str[len], n - len,
-			"  type              %s\n", entry->s.ops->name);
+			"  type              %s\n", entry->s.ops->base.name);
 	len += snprintf(&str[len], n - len,
 			"  state             %s\n",
 			entry->s.state ==  PKTIO_STATE_STARTED ? "start" :
@@ -1030,7 +1007,6 @@ int odp_pktio_term_global(void)
 {
 	int ret = 0;
 	int i;
-	int pktio_if;
 
 	for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) {
 		pktio_entry_t *pktio_entry;
@@ -1056,12 +1032,7 @@ int odp_pktio_term_global(void)
 		unlock_entry(pktio_entry);
 	}
 
-	for (pktio_if = 0; pktio_if_ops[pktio_if]; ++pktio_if) {
-		if (pktio_if_ops[pktio_if]->term)
-			if (pktio_if_ops[pktio_if]->term())
-				ODP_ABORT("failed to terminate pktio type %d",
-					  pktio_if);
-	}
+	ret = odp_pktio_ops_term_global(false);
 
 	ret = odp_shm_free(odp_shm_lookup("odp_pktio_entries"));
 	if (ret != 0)
diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c
index 9e3e583da..e72a76371 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -1290,30 +1290,46 @@ static int dpdk_stats_reset(pktio_entry_t *pktio_entry)
 	return 0;
 }
 
-const pktio_if_ops_t dpdk_pktio_ops = {
-	.name = "dpdk",
-	.init_global = dpdk_pktio_init_global,
-	.init_local = dpdk_pktio_init_local,
-	.term = NULL,
+static pktio_ops_module_t dpdk_pktio_ops = {
+	.base = {
+		.name = "dpdk",
+		.init_local = dpdk_pktio_init_local,
+		.init_global = dpdk_pktio_init_global,
+		.term_local = NULL,
+		.term_global = NULL,
+	},
 	.open = dpdk_open,
 	.close = dpdk_close,
 	.start = dpdk_start,
 	.stop = dpdk_stop,
 	.stats = dpdk_stats,
 	.stats_reset = dpdk_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = dpdk_recv,
 	.send = dpdk_send,
-	.link_status = dpdk_link_status,
 	.mtu_get = dpdk_mtu_get,
 	.promisc_mode_set = dpdk_promisc_mode_set,
 	.promisc_mode_get = dpdk_promisc_mode_get,
 	.mac_get = dpdk_mac_addr_get,
+	.link_status = dpdk_link_status,
 	.capability = dpdk_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = dpdk_input_queues_config,
-	.output_queues_config = dpdk_output_queues_config
+	.output_queues_config = dpdk_output_queues_config,
+	.print = NULL,
 };
 
+ODP_MODULE_CONSTRUCTOR(dpdk_pktio_ops)
+{
+	odp_module_constructor(&dpdk_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &dpdk_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_dpdk_pktio_ops = 0;
+
 #endif /* ODP_PKTIO_DPDK */
diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c
deleted file mode 100644
index fbf30ca7a..000000000
--- a/platform/linux-generic/pktio/io_ops.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2013, Linaro Limited
- * All rights reserved.
- *
- * SPDX-License-Identifier:     BSD-3-Clause
- */
-
-#include <odp_packet_io_internal.h>
-
-/* Ops for all implementation of pktio.
- * Order matters. The first implementation to setup successfully
- * will be picked.
- * Array must be NULL terminated */
-const pktio_if_ops_t * const pktio_if_ops[]  = {
-	&loopback_pktio_ops,
-#ifdef ODP_PKTIO_DPDK
-	&dpdk_pktio_ops,
-#endif
-#ifdef ODP_NETMAP
-	&netmap_pktio_ops,
-#endif
-#ifdef HAVE_PCAP
-	&pcap_pktio_ops,
-#endif
-#ifdef _ODP_PKTIO_IPC
-	&ipc_pktio_ops,
-#endif
-	&tap_pktio_ops,
-	&sock_mmap_pktio_ops,
-	&sock_mmsg_pktio_ops,
-	NULL
-};
diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c
index 8c7db84e6..984f0ab44 100644
--- a/platform/linux-generic/pktio/ipc.c
+++ b/platform/linux-generic/pktio/ipc.c
@@ -771,23 +771,44 @@ static int ipc_pktio_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t ipc_pktio_ops = {
-	.name = "ipc",
-	.print = NULL,
-	.init_global = ipc_pktio_init_global,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t ipc_pktio_ops = {
+	.base = {
+		.name = "ipc",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = ipc_pktio_init_global,
+		.term_global = NULL,
+	},
 	.open = ipc_pktio_open,
 	.close = ipc_close,
-	.recv =  ipc_pktio_recv,
-	.send = ipc_pktio_send,
 	.start = ipc_start,
 	.stop = ipc_stop,
+	.stats = NULL,
+	.stats_reset = NULL,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
+	.recv = ipc_pktio_recv,
+	.send = ipc_pktio_send,
 	.mtu_get = ipc_mtu_get,
 	.promisc_mode_set = NULL,
 	.promisc_mode_get = NULL,
 	.mac_get = ipc_mac_addr_get,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
-	.config = NULL
+	.link_status = NULL,
+	.capability = NULL,
+	.config = NULL,
+	.input_queues_config = NULL,
+	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(ipc_pktio_ops)
+{
+	odp_module_constructor(&ipc_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &ipc_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_ipc_pktio_ops = 0;
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index c825393ac..39718a892 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -251,18 +251,22 @@ static int loop_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t loopback_pktio_ops = {
-	.name = "loop",
-	.print = NULL,
-	.init_global = loop_init_global,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t loopback_pktio_ops = {
+	.base = {
+		.name = "loopback",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = loop_init_global,
+		.term_global = NULL,
+	},
 	.open = loopback_open,
 	.close = loopback_close,
 	.start = NULL,
 	.stop = NULL,
 	.stats = loopback_stats,
 	.stats_reset = loopback_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = loopback_recv,
 	.send = loopback_send,
 	.mtu_get = loopback_mtu_get,
@@ -271,9 +275,20 @@ const pktio_if_ops_t loopback_pktio_ops = {
 	.mac_get = loopback_mac_addr_get,
 	.link_status = loopback_link_status,
 	.capability = loopback_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(loopback_pktio_ops)
+{
+	odp_module_constructor(&loopback_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &loopback_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_loopback_pktio_ops = 0;
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c
index 928bb00af..c75f8be97 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -943,31 +943,46 @@ static int netmap_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t netmap_pktio_ops = {
-	.name = "netmap",
-	.print = netmap_print,
-	.init_global = netmap_init_global,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t netmap_pktio_ops = {
+	.base = {
+		.name = "netmap",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = netmap_init_global,
+		.term_global = NULL,
+	},
 	.open = netmap_open,
 	.close = netmap_close,
 	.start = netmap_start,
 	.stop = netmap_stop,
-	.link_status = netmap_link_status,
 	.stats = netmap_stats,
 	.stats_reset = netmap_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
+	.recv = netmap_recv,
+	.send = netmap_send,
 	.mtu_get = netmap_mtu_get,
 	.promisc_mode_set = netmap_promisc_mode_set,
 	.promisc_mode_get = netmap_promisc_mode_get,
 	.mac_get = netmap_mac_addr_get,
+	.link_status = netmap_link_status,
 	.capability = netmap_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = netmap_input_queues_config,
 	.output_queues_config = netmap_output_queues_config,
-	.recv = netmap_recv,
-	.send = netmap_send
+	.print = netmap_print,
 };
 
+ODP_MODULE_CONSTRUCTOR(netmap_pktio_ops)
+{
+	odp_module_constructor(&netmap_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &netmap_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_netmap_pktio_ops = 0;
+
 #endif /* ODP_NETMAP */
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
index a467b6402..98f810898 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -423,25 +423,44 @@ static int pcapif_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t pcap_pktio_ops = {
-	.name = "pcap",
-	.print = NULL,
-	.init_global = pcapif_init_global,
-	.init_local = NULL,
+static pktio_ops_module_t pcap_pktio_ops = {
+	.base = {
+		.name = "pcap",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = pcapif_init_global,
+		.term_global = NULL,
+	},
 	.open = pcapif_init,
 	.close = pcapif_close,
+	.start = NULL,
+	.stop = NULL,
 	.stats = pcapif_stats,
 	.stats_reset = pcapif_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = pcapif_recv_pkt,
 	.send = pcapif_send_pkt,
 	.mtu_get = pcapif_mtu_get,
 	.promisc_mode_set = pcapif_promisc_mode_set,
 	.promisc_mode_get = pcapif_promisc_mode_get,
 	.mac_get = pcapif_mac_addr_get,
+	.link_status = NULL,
 	.capability = pcapif_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(pcap_pktio_ops)
+{
+	odp_module_constructor(&pcap_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &pcap_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_pcap_pktio_ops = 0;
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index a383adc6a..8b8ccf033 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -853,18 +853,22 @@ static int sock_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t sock_mmsg_pktio_ops = {
-	.name = "socket",
-	.print = NULL,
-	.init_global = sock_init_global,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t socket_pktio_ops = {
+	.base = {
+		.name = "socket",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = sock_init_global,
+		.term_global = NULL,
+	},
 	.open = sock_mmsg_open,
 	.close = sock_close,
 	.start = NULL,
 	.stop = NULL,
 	.stats = sock_stats,
 	.stats_reset = sock_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = sock_mmsg_recv,
 	.send = sock_mmsg_send,
 	.mtu_get = sock_mtu_get,
@@ -873,9 +877,20 @@ const pktio_if_ops_t sock_mmsg_pktio_ops = {
 	.mac_get = sock_mac_addr_get,
 	.link_status = sock_link_status,
 	.capability = sock_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(socket_pktio_ops)
+{
+	odp_module_constructor(&socket_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &socket_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_socket_pktio_ops = 0;
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index 6fc4b4ccf..0a27316f2 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -710,18 +710,22 @@ static int sock_mmap_init_global(void)
 	return 0;
 }
 
-const pktio_if_ops_t sock_mmap_pktio_ops = {
-	.name = "socket_mmap",
-	.print = NULL,
-	.init_global = sock_mmap_init_global,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t socket_mmap_pktio_ops = {
+	.base = {
+		.name = "socket mmap",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = sock_mmap_init_global,
+		.term_global = NULL,
+	},
 	.open = sock_mmap_open,
 	.close = sock_mmap_close,
 	.start = NULL,
 	.stop = NULL,
 	.stats = sock_mmap_stats,
 	.stats_reset = sock_mmap_stats_reset,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = sock_mmap_recv,
 	.send = sock_mmap_send,
 	.mtu_get = sock_mmap_mtu_get,
@@ -730,9 +734,20 @@ const pktio_if_ops_t sock_mmap_pktio_ops = {
 	.mac_get = sock_mmap_mac_addr_get,
 	.link_status = sock_mmap_link_status,
 	.capability = sock_mmap_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(socket_mmap_pktio_ops)
+{
+	odp_module_constructor(&socket_mmap_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &socket_mmap_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_socket_mmap_pktio_ops = 0;
diff --git a/platform/linux-generic/pktio/subsystem.c b/platform/linux-generic/pktio/subsystem.c
new file mode 100644
index 000000000..fbcf22d77
--- /dev/null
+++ b/platform/linux-generic/pktio/subsystem.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp_debug_internal.h>
+#include <odp_packet_io_internal.h>
+
+#define SUBSYSTEM_VERSION 0x00010000UL
+ODP_SUBSYSTEM_DEFINE(pktio_ops, "packet IO operations", SUBSYSTEM_VERSION);
+
+/* Instantiate init and term functions */
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, init_global, ODP_ERR)
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, init_local, ODP_ERR)
+ODP_SUBSYSTEM_FOREACH_TEMPLATE(pktio_ops, term_global, ODP_ABORT)
+
+/* Temporary variable to enable link modules,
+ * will remove in Makefile scheme changes.
+ */
+#ifdef ODP_PKTIO_DPDK
+extern int enable_link_dpdk_pktio_ops;
+#endif
+extern int enable_link_ipc_pktio_ops;
+extern int enable_link_loopback_pktio_ops;
+#ifdef ODP_NETMAP
+extern int enable_link_netmap_pktio_ops;
+#endif
+#ifdef HAVE_PCAP
+extern int enable_link_pcap_pktio_ops;
+#endif
+extern int enable_link_socket_pktio_ops;
+extern int enable_link_socket_mmap_pktio_ops;
+extern int enable_link_tap_pktio_ops;
+
+ODP_SUBSYSTEM_CONSTRUCTOR(pktio_ops)
+{
+	odp_subsystem_constructor(pktio_ops);
+
+	/* Further initialization per subsystem */
+
+#ifdef ODP_PKTIO_DPDK
+	enable_link_dpdk_pktio_ops = 1;
+#endif
+	enable_link_ipc_pktio_ops = 1;
+	enable_link_loopback_pktio_ops = 1;
+#ifdef ODP_NETMAP
+	enable_link_netmap_pktio_ops = 1;
+#endif
+#ifdef HAVE_PCAP
+	enable_link_pcap_pktio_ops = 1;
+#endif
+	enable_link_socket_pktio_ops = 1;
+	enable_link_socket_mmap_pktio_ops = 1;
+	enable_link_tap_pktio_ops = 1;
+}
diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c
index 650c12a77..bfe412390 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -373,24 +373,44 @@ static int tap_capability(pktio_entry_t *pktio_entry ODP_UNUSED,
 	return 0;
 }
 
-const pktio_if_ops_t tap_pktio_ops = {
-	.name = "tap",
-	.print = NULL,
-	.init_global = NULL,
-	.init_local = NULL,
-	.term = NULL,
+static pktio_ops_module_t tap_pktio_ops = {
+	.base = {
+		.name = "tap",
+		.init_local = NULL,
+		.term_local = NULL,
+		.init_global = NULL,
+		.term_global = NULL,
+	},
 	.open = tap_pktio_open,
 	.close = tap_pktio_close,
 	.start = NULL,
 	.stop = NULL,
+	.stats = NULL,
+	.stats_reset = NULL,
+	.pktin_ts_res = NULL,
+	.pktin_ts_from_ns = NULL,
 	.recv = tap_pktio_recv,
 	.send = tap_pktio_send,
 	.mtu_get = tap_mtu_get,
 	.promisc_mode_set = tap_promisc_mode_set,
 	.promisc_mode_get = tap_promisc_mode_get,
 	.mac_get = tap_mac_addr_get,
+	.link_status = NULL,
 	.capability = tap_capability,
-	.pktin_ts_res = NULL,
-	.pktin_ts_from_ns = NULL,
-	.config = NULL
+	.config = NULL,
+	.input_queues_config = NULL,
+	.output_queues_config = NULL,
+	.print = NULL,
 };
+
+ODP_MODULE_CONSTRUCTOR(tap_pktio_ops)
+{
+	odp_module_constructor(&tap_pktio_ops);
+
+	odp_subsystem_register_module(pktio_ops, &tap_pktio_ops);
+}
+
+/* Temporary variable to enable link this module,
+ * will remove in Makefile scheme changes.
+ */
+int enable_link_tap_pktio_ops = 0;
