diff --git a/platform/linux-netmap/include/odp_packet_netmap.h b/platform/linux-netmap/include/odp_packet_netmap.h
index 2ac10d2..0e4fb09 100644
--- a/platform/linux-netmap/include/odp_packet_netmap.h
+++ b/platform/linux-netmap/include/odp_packet_netmap.h
@@ -23,6 +23,16 @@
 
 #define NETMAP_BLOCKING_IO
 
+/* Since we allow more than one thread to open the same device
+ * this struct uinquely identifies a device so that proper locking
+ * can be implemented
+ */
+typedef struct {
+	char ifname[IFNAMSIZ];
+	odp_spinlock_t rx_lock;
+	odp_spinlock_t tx_lock;
+} netmap_dev_t;
+
 /** Packet socket using netmap mmaped rings for both Rx and Tx */
 typedef struct {
 	odp_buffer_pool_t pool;
@@ -34,7 +44,7 @@ typedef struct {
 	uint32_t if_flags;
 	odp_packet_t *pkt_table;	/**< Used by recv_pkt_netmap */
 	int nb_rx;			/**< Used by recv_pkt_netmap */
-	char ifname[IFNAMSIZ];
+	netmap_dev_t *nm_dev;
 } pkt_netmap_t;
 
 /**
diff --git a/platform/linux-netmap/odp_packet_netmap.c b/platform/linux-netmap/odp_packet_netmap.c
index 37e574b..8c56a66 100644
--- a/platform/linux-netmap/odp_packet_netmap.c
+++ b/platform/linux-netmap/odp_packet_netmap.c
@@ -58,11 +58,17 @@
 static struct nm_desc mmap_desc;	/** Used to store the mmap address;
 					  filled in first time, used for
 					  subsequent calls to nm_open */
-static odp_spinlock_t mmap_desc_lock;
+static odp_spinlock_t nm_global_lock;	/** Global lock for mmap addr and
+					  dev lookup */
+
+#define MAX_DEVS	32
+static netmap_dev_t netmap_devs[MAX_DEVS];
+static int nm_dev_cnt;
 
 int odp_netmap_init_global(void)
 {
-	odp_spinlock_init(&mmap_desc_lock);
+	odp_spinlock_init(&nm_global_lock);
+	memset(netmap_devs, 0, sizeof(netmap_devs));
 	return 0;
 }
 
@@ -81,7 +87,7 @@ static int nm_do_ioctl(pkt_netmap_t * const pkt_nm, unsigned long cmd,
 	}
 
 	memset(&ifr, 0, sizeof(ifr));
-	strncpy(ifr.ifr_name, pkt_nm->ifname, sizeof(ifr.ifr_name));
+	strncpy(ifr.ifr_name, pkt_nm->nm_dev->ifname, sizeof(ifr.ifr_name));
 
 	switch (cmd) {
 	case SIOCSIFFLAGS:
@@ -125,7 +131,12 @@ int setup_pkt_netmap(pkt_netmap_t * const pkt_nm, const char *netdev,
 	odp_packet_t pkt;
 	uint8_t *pkt_buf;
 	uint8_t *l2_hdr;
-	int ret;
+	int i, ret;
+
+	if (nm_dev_cnt == MAX_DEVS) {
+		ODP_ERR("Maximum number of devices reached: %d\n", nm_dev_cnt);
+		return -1;
+	}
 
 	if (pool == ODP_BUFFER_POOL_INVALID)
 		return -1;
@@ -146,10 +157,9 @@ int setup_pkt_netmap(pkt_netmap_t * const pkt_nm, const char *netdev,
 
 	odph_packet_free(pkt);
 
-	snprintf(pkt_nm->ifname, sizeof(pkt_nm->ifname), "%s", netdev);
 	snprintf(ifname, sizeof(ifname), "netmap:%s", netdev);
 
-	odp_spinlock_lock(&mmap_desc_lock);
+	odp_spinlock_lock(&nm_global_lock);
 	ODP_DBG("[%04d] Initial mmap addr: %p\n",
 		odp_thread_id(),
 		mmap_desc.mem);
@@ -162,7 +172,7 @@ int setup_pkt_netmap(pkt_netmap_t * const pkt_nm, const char *netdev,
 
 	if (pkt_nm->desc == NULL) {
 		ODP_ERR("Error opening nm interface: %s\n", strerror(errno));
-		odp_spinlock_unlock(&mmap_desc_lock);
+		odp_spinlock_unlock(&nm_global_lock);
 		return -1;
 	}
 
@@ -170,7 +180,23 @@ int setup_pkt_netmap(pkt_netmap_t * const pkt_nm, const char *netdev,
 		mmap_desc.mem = pkt_nm->desc->mem;
 		mmap_desc.memsize = pkt_nm->desc->memsize;
 	}
-	odp_spinlock_unlock(&mmap_desc_lock);
+
+	/* Lookup dev */
+	for (i = 0; i < nm_dev_cnt; i++) {
+		if (!strcmp(netmap_devs[i].ifname, netdev)) {
+			pkt_nm->nm_dev = &netmap_devs[i];
+			break;
+		}
+	}
+	if (i == nm_dev_cnt) {
+		nm_dev_cnt++;
+		snprintf(netmap_devs[i].ifname, sizeof(netmap_devs[i].ifname),
+			 "%s", netdev);
+		odp_spinlock_init(&netmap_devs[i].rx_lock);
+		odp_spinlock_init(&netmap_devs[i].tx_lock);
+		pkt_nm->nm_dev = &netmap_devs[i];
+	}
+	odp_spinlock_unlock(&nm_global_lock);
 
 	ODP_DBG("[%04d] mmap addr %p\n",
 		odp_thread_id(),
@@ -182,7 +208,7 @@ int setup_pkt_netmap(pkt_netmap_t * const pkt_nm, const char *netdev,
 	if ((pkt_nm->if_flags & IFF_UP) == 0) {
 		ODP_DBG("[%04d] %s is down, bringing up...\n",
 			odp_thread_id(),
-			pkt_nm->ifname);
+			pkt_nm->nm_dev->ifname);
 		pkt_nm->if_flags |= IFF_UP;
 	}
 	if (ETH_PROMISC) {
@@ -293,7 +319,10 @@ int recv_pkt_netmap(pkt_netmap_t * const pkt_nm, odp_packet_t pkt_table[],
 
 	pkt_nm->pkt_table = pkt_table;
 	pkt_nm->nb_rx = 0;
+
+	odp_spinlock_lock(&pkt_nm->nm_dev->rx_lock);
 	nm_dispatch(pkt_nm->desc, len, nm_recv_cb, (uint8_t *)pkt_nm);
+	odp_spinlock_unlock(&pkt_nm->nm_dev->rx_lock);
 
 	if (pkt_nm->nb_rx)
 		ODP_DBG("[%04d] <=== rcvd %03u frames from netmap adapter\n",
@@ -322,6 +351,7 @@ int send_pkt_netmap(pkt_netmap_t * const pkt_nm, odp_packet_t pkt_table[],
 	ioctl(fd, NIOCTXSYNC, NULL);
 #endif
 
+	odp_spinlock_lock(&pkt_nm->nm_dev->tx_lock);
 	for (nb_tx = 0; nb_tx < len; nb_tx++) {
 		odp_packet_t pkt = pkt_table[nb_tx];
 		uint8_t *frame = odp_packet_l2(pkt);
@@ -329,6 +359,7 @@ int send_pkt_netmap(pkt_netmap_t * const pkt_nm, odp_packet_t pkt_table[],
 		if (nm_inject(pkt_nm->desc, frame, frame_len))
 			break;
 	}
+	odp_spinlock_unlock(&pkt_nm->nm_dev->tx_lock);
 
 	if (nb_tx)
 		ODP_DBG("[%04d] ===> sent %03u frames to netmap adapter\n",
