diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index 92d81972ab..e631dfff30 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -295,6 +295,13 @@ rte_mbuf_to_priv(struct rte_mbuf *m)
 }
 
 /**
+ * When set pktmbuf mempool will hold only mbufs with pinned external buffer.
+ * The external buffer will be attached on the mbuf creation and will not be
+ * detached by the mbuf free calls.
+ * mbuf should not contain any room for data after the mbuf structure.
+ */
+#define RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF (1 << 0)
+/**
  * Private data in case of pktmbuf pool.
  *
  * A structure that contains some pktmbuf_pool-specific data that are
@@ -303,6 +310,7 @@ rte_mbuf_to_priv(struct rte_mbuf *m)
 struct rte_pktmbuf_pool_private {
 	uint16_t mbuf_data_room_size; /**< Size of data space in each mbuf. */
 	uint16_t mbuf_priv_size;      /**< Size of private area in each mbuf. */
+	uint32_t flags;		      /**< Use RTE_PKTMMBUF_POOL_F_*. */
 };
 
 #ifdef RTE_LIBRTE_MBUF_DEBUG
@@ -660,6 +668,50 @@ rte_pktmbuf_pool_create(const char *name, unsigned n,
 	int socket_id);
 
 /**
+ * Create a mbuf pool with pinned external buffers.
+ *
+ * This function creates and initializes a packet mbuf pool that contains
+ * only mbufs with external buffer. It is a wrapper to rte_mempool functions.
+ *
+ * @param name
+ *   The name of the mbuf pool.
+ * @param n
+ *   The number of elements in the mbuf pool. The optimum size (in terms
+ *   of memory usage) for a mempool is when n is a power of two minus one:
+ *   n = (2^q - 1).
+ * @param cache_size
+ *   Size of the per-core object cache. See rte_mempool_create() for
+ *   details.
+ * @param priv_size
+ *   Size of application private are between the rte_mbuf structure
+ *   and the data buffer. This value must be aligned to RTE_MBUF_PRIV_ALIGN.
+ * @param socket_id
+ *   The socket identifier where the mempool memory should be allocated. The
+ *   value can be *SOCKET_ID_ANY* if there is no NUMA constraint for the
+ *   reserved zone.
+ * @param buffers
+ *   Array of buffers to be attached to the mbufs in the pool.
+ *   Array size should be n.
+ * @param buffers_len
+ *   Array of buffer length. buffers_len[i] describes the length of a buffer
+ *   pointed by buffer[i].
+ * @return
+ *   The pointer to the new allocated mempool, on success. NULL on error
+ *   with rte_errno set appropriately. Possible rte_errno values include:
+ *    - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure
+ *    - E_RTE_SECONDARY - function was called from a secondary process instance
+ *    - EINVAL - cache size provided is too large, or priv_size is not aligned.
+ *    - ENOSPC - the maximum number of memzones has already been allocated
+ *    - EEXIST - a memzone with the same name already exists
+ *    - ENOMEM - no appropriate memory area found in which to create memzone
+ */
+struct rte_mempool *
+rte_pktmbuf_ext_buffer_pool_create(const char *name, unsigned n,
+				   unsigned cache_size, uint16_t priv_size,
+				   int socket_id, void **buffers,
+				   uint16_t *buffer_len);
+
+/**
  * Create a mbuf pool with a given mempool ops name
  *
  * This function creates and initializes a packet mbuf pool. It is
@@ -1137,25 +1189,36 @@ __rte_pktmbuf_free_direct(struct rte_mbuf *m)
 static inline void rte_pktmbuf_detach(struct rte_mbuf *m)
 {
 	struct rte_mempool *mp = m->pool;
+	struct rte_pktmbuf_pool_private *priv =
+		(struct rte_pktmbuf_pool_private *)rte_mempool_get_priv(mp);
+	uint8_t pinned_ext_mbuf = priv->flags &
+				  RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF;
 	uint32_t mbuf_size, buf_len;
 	uint16_t priv_size;
 
-	if (RTE_MBUF_HAS_EXTBUF(m))
-		__rte_pktmbuf_free_extbuf(m);
-	else
+	if (RTE_MBUF_HAS_EXTBUF(m)) {
+		if (pinned_ext_mbuf) {
+			m->ol_flags = EXT_ATTACHED_MBUF;
+			goto reset_data;
+		} else {
+			__rte_pktmbuf_free_extbuf(m);
+		}
+	} else {
 		__rte_pktmbuf_free_direct(m);
+	}
 
-	priv_size = rte_pktmbuf_priv_size(mp);
+	priv_size = priv->mbuf_priv_size;
 	mbuf_size = (uint32_t)(sizeof(struct rte_mbuf) + priv_size);
-	buf_len = rte_pktmbuf_data_room_size(mp);
+	buf_len = priv->mbuf_data_room_size;
 
 	m->priv_size = priv_size;
 	m->buf_addr = (char *)m + mbuf_size;
 	m->buf_iova = rte_mempool_virt2iova(m) + mbuf_size;
 	m->buf_len = (uint16_t)buf_len;
+	m->ol_flags = 0;
+reset_data:
 	rte_pktmbuf_reset_headroom(m);
 	m->data_len = 0;
-	m->ol_flags = 0;
 }
 
 /**
