All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] lib/librte_port: enable file descriptor port support
@ 2016-08-05 21:21 Jasvinder Singh
  2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
  0 siblings, 1 reply; 12+ messages in thread
From: Jasvinder Singh @ 2016-08-05 21:21 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This patch adds File Descriptor(FD) port type (e.g. TAP port) to the
packet framework library that allows interface with the kernel network
stack. The FD port APIs are defined that allow port creation, writing
and reading packet from the kernel interface.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_port/Makefile             |   2 +
 lib/librte_port/rte_port_fd.c        | 548 +++++++++++++++++++++++++++++++++++
 lib/librte_port/rte_port_fd.h        | 103 +++++++
 lib/librte_port/rte_port_version.map |   9 +
 4 files changed, 662 insertions(+)
 create mode 100644 lib/librte_port/rte_port_fd.c
 create mode 100644 lib/librte_port/rte_port_fd.h

diff --git a/lib/librte_port/Makefile b/lib/librte_port/Makefile
index 3d84a0e..44fa735 100644
--- a/lib/librte_port/Makefile
+++ b/lib/librte_port/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_frag.c
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_ras.c
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_sched.c
+SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_fd.c
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_kni.c
 endif
@@ -70,6 +71,7 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_frag.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_ras.h
 endif
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_sched.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_fd.h
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_kni.h
 endif
diff --git a/lib/librte_port/rte_port_fd.c b/lib/librte_port/rte_port_fd.c
new file mode 100644
index 0000000..c75b602
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.c
@@ -0,0 +1,548 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+
+#include "rte_port_fd.h"
+
+/*
+ * Port FD Reader
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val) \
+	port->stats.n_pkts_in += val
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val) \
+	port->stats.n_pkts_drop += val
+
+#else
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_reader {
+	struct rte_port_in_stats stats;
+	int fd;
+	uint32_t mtu;
+	struct rte_mempool *mempool;
+};
+
+static void *
+rte_port_fd_reader_create(void *params, int socket_id)
+{
+	struct rte_port_fd_reader_params *conf =
+			(struct rte_port_fd_reader_params *) params;
+	struct rte_port_fd_reader *port;
+
+	/* Check input parameters */
+	if (conf == NULL) {
+		RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
+		return NULL;
+	}
+	if (conf->fd < 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid file descriptor\n", __func__);
+		return NULL;
+	}
+	if (conf->mtu == 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid MTU\n", __func__);
+		return NULL;
+	}
+	if (conf->mempool == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Invalid mempool\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+			RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->mtu = conf->mtu;
+	port->mempool = conf->mempool;
+
+	return port;
+}
+
+static int
+rte_port_fd_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
+{
+	struct rte_port_fd_reader *p = (struct rte_port_fd_reader *) port;
+	uint32_t i;
+
+	if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
+		return 0;
+
+	for (i = 0; i < n_pkts; i++) {
+		rte_mbuf_refcnt_set(pkts[i], 1);
+		rte_pktmbuf_reset(pkts[i]);
+	}
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void *);
+
+		ssize_t n_bytes = read(p->fd, pkt_data, (size_t) p->mtu);
+		if (n_bytes <= 0)
+			break;
+
+		pkt->data_len = n_bytes;
+		pkt->pkt_len = n_bytes;
+	}
+
+	for ( ; i < n_pkts; i++)
+		rte_pktmbuf_free(pkts[i]);
+
+	RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(p, i);
+
+	return n_pkts;
+}
+
+static int
+rte_port_fd_reader_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_reader_stats_read(void *port,
+		struct rte_port_in_stats *stats, int clear)
+{
+	struct rte_port_fd_reader *p =
+			(struct rte_port_fd_reader *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val) \
+	port->stats.n_pkts_in += val
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val) \
+	port->stats.n_pkts_drop += val
+
+#else
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_params *conf =
+		(struct rte_port_fd_writer_params *) params;
+	struct rte_port_fd_writer *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	return port;
+}
+
+static inline void
+send_burst(struct rte_port_fd_writer *p)
+{
+	uint32_t i;
+
+	for (i = 0; i < p->tx_buf_count; i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+
+		ssize_t ret = write(p->fd, pkt_data, n_bytes);
+		if (ret < 0)
+			break;
+	}
+
+	RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_flush(void *port)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_flush(port);
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_writer_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer Nodrop
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val) \
+	port->stats.n_pkts_in += val
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val) \
+	port->stats.n_pkts_drop += val
+
+#else
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer_nodrop {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint64_t n_retries;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_nodrop_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_nodrop_params *conf =
+			(struct rte_port_fd_writer_nodrop_params *) params;
+	struct rte_port_fd_writer_nodrop *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->fd < 0) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	/*
+	 * When n_retries is 0 it means that we should wait for every packet to
+	 * send no matter how many retries should it take. To limit number of
+	 * branches in fast path, we use UINT64_MAX instead of branching.
+	 */
+	port->n_retries = (conf->n_retries == 0) ? UINT64_MAX : conf->n_retries;
+
+	return port;
+}
+
+static inline void
+send_burst_nodrop(struct rte_port_fd_writer_nodrop *p)
+{
+	uint64_t n_retries;
+	uint32_t i;
+
+	n_retries = 0;
+	for (i = 0; (i < p->tx_buf_count) && (n_retries < p->n_retries); i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+
+		for ( ; n_retries < p->n_retries; n_retries++) {
+			ssize_t ret = write(p->fd, pkt_data, n_bytes);
+			if (ret)
+				break;
+		}
+	}
+
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_flush(void *port)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_nodrop_flush(port);
+	rte_free(port);
+
+return 0;
+}
+
+static int rte_port_fd_writer_nodrop_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Summary of port operations
+ */
+struct rte_port_in_ops rte_port_fd_reader_ops = {
+	.f_create = rte_port_fd_reader_create,
+	.f_free = rte_port_fd_reader_free,
+	.f_rx = rte_port_fd_reader_rx,
+	.f_stats = rte_port_fd_reader_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_ops = {
+	.f_create = rte_port_fd_writer_create,
+	.f_free = rte_port_fd_writer_free,
+	.f_tx = rte_port_fd_writer_tx,
+	.f_tx_bulk = rte_port_fd_writer_tx_bulk,
+	.f_flush = rte_port_fd_writer_flush,
+	.f_stats = rte_port_fd_writer_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_nodrop_ops = {
+	.f_create = rte_port_fd_writer_nodrop_create,
+	.f_free = rte_port_fd_writer_nodrop_free,
+	.f_tx = rte_port_fd_writer_nodrop_tx,
+	.f_tx_bulk = rte_port_fd_writer_nodrop_tx_bulk,
+	.f_flush = rte_port_fd_writer_nodrop_flush,
+	.f_stats = rte_port_fd_writer_nodrop_stats_read,
+};
diff --git a/lib/librte_port/rte_port_fd.h b/lib/librte_port/rte_port_fd.h
new file mode 100644
index 0000000..78396c3
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.h
@@ -0,0 +1,103 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_RTE_PORT_FD_H__
+#define __INCLUDE_RTE_PORT_FD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE Port FD Device
+ *
+ * fd_reader: input port built on top of valid non-blocking file descriptor
+ * fd_writer: output port built on top of valid non-blocking file descriptor
+ *
+ ***/
+
+#include <stdint.h>
+
+#include <rte_mempool.h>
+#include "rte_port.h"
+
+/** fd_reader port parameters */
+struct rte_port_fd_reader_params {
+	/** File descriptor */
+	int fd;
+
+	/** Maximum Transfer Unit (MTU) */
+	uint32_t mtu;
+
+	/** Pre-initialized buffer pool */
+	struct rte_mempool *mempool;
+};
+
+/** fd_reader port operations */
+extern struct rte_port_in_ops rte_port_fd_reader_ops;
+
+/** fd_writer port parameters */
+struct rte_port_fd_writer_params {
+	/** File descriptor */
+	int fd;
+
+	/** Recommended write burst size. The actual burst size can be
+	bigger or smaller than this value. */
+	uint32_t tx_burst_sz;
+};
+
+/** fd_writer port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_ops;
+
+/** fd_writer_nodrop port parameters */
+struct rte_port_fd_writer_nodrop_params {
+	/** File descriptor */
+	int fd;
+
+	/** Recommended write burst size. The actual burst size can be
+	bigger or smaller than this value. */
+	uint32_t tx_burst_sz;
+
+	/** Maximum number of retries, 0 for no limit */
+	uint32_t n_retries;
+};
+
+/** fd_writer_nodrop port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_nodrop_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_port/rte_port_version.map b/lib/librte_port/rte_port_version.map
index 048c20d..82151ae 100644
--- a/lib/librte_port/rte_port_version.map
+++ b/lib/librte_port/rte_port_version.map
@@ -42,3 +42,12 @@ DPDK_16.07 {
 	rte_port_kni_writer_nodrop_ops;
 
 } DPDK_2.2;
+
+DPDK_16.11 {
+	global:
+
+	rte_port_fd_reader_ops;
+	rte_port_fd_writer_ops;
+	rte_port_fd_writer_nodrop_ops;
+
+} DPDK_16.07;
\ No newline at end of file
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 1/3] lib/librte_port: enable file descriptor port support
  2016-08-05 21:21 [PATCH 1/3] lib/librte_port: enable file descriptor port support Jasvinder Singh
@ 2016-09-04 14:38 ` Jasvinder Singh
  2016-09-04 14:38   ` [PATCH v2 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
                     ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-09-04 14:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This patch adds File Descriptor(FD) port type (e.g. TAP port) to the
packet framework library that allows interface with the kernel network
stack. The FD port APIs are defined that allow port creation, writing
and reading packet from the kernel interface.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v2:
- fix checkpatch warnings

 lib/librte_port/Makefile             |   2 +
 lib/librte_port/rte_port_fd.c        | 552 +++++++++++++++++++++++++++++++++++
 lib/librte_port/rte_port_fd.h        | 105 +++++++
 lib/librte_port/rte_port_version.map |   9 +
 4 files changed, 668 insertions(+)
 create mode 100644 lib/librte_port/rte_port_fd.c
 create mode 100644 lib/librte_port/rte_port_fd.h

diff --git a/lib/librte_port/Makefile b/lib/librte_port/Makefile
index 3d84a0e..44fa735 100644
--- a/lib/librte_port/Makefile
+++ b/lib/librte_port/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_frag.c
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_ras.c
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_sched.c
+SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_fd.c
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_kni.c
 endif
@@ -70,6 +71,7 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_frag.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_ras.h
 endif
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_sched.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_fd.h
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_kni.h
 endif
diff --git a/lib/librte_port/rte_port_fd.c b/lib/librte_port/rte_port_fd.c
new file mode 100644
index 0000000..4e4e1de
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.c
@@ -0,0 +1,552 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+
+#include "rte_port_fd.h"
+
+/*
+ * Port FD Reader
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val } while (0)
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val } while (0)
+
+#else
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_reader {
+	struct rte_port_in_stats stats;
+	int fd;
+	uint32_t mtu;
+	struct rte_mempool *mempool;
+};
+
+static void *
+rte_port_fd_reader_create(void *params, int socket_id)
+{
+	struct rte_port_fd_reader_params *conf =
+			(struct rte_port_fd_reader_params *) params;
+	struct rte_port_fd_reader *port;
+
+	/* Check input parameters */
+	if (conf == NULL) {
+		RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
+		return NULL;
+	}
+	if (conf->fd < 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid file descriptor\n", __func__);
+		return NULL;
+	}
+	if (conf->mtu == 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid MTU\n", __func__);
+		return NULL;
+	}
+	if (conf->mempool == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Invalid mempool\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+			RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->mtu = conf->mtu;
+	port->mempool = conf->mempool;
+
+	return port;
+}
+
+static int
+rte_port_fd_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
+{
+	struct rte_port_fd_reader *p = (struct rte_port_fd_reader *) port;
+	uint32_t i;
+
+	if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
+		return 0;
+
+	for (i = 0; i < n_pkts; i++) {
+		rte_mbuf_refcnt_set(pkts[i], 1);
+		rte_pktmbuf_reset(pkts[i]);
+	}
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void *);
+		ssize_t n_bytes;
+
+		n_bytes = read(p->fd, pkt_data, (size_t) p->mtu);
+		if (n_bytes <= 0)
+			break;
+
+		pkt->data_len = n_bytes;
+		pkt->pkt_len = n_bytes;
+	}
+
+	for ( ; i < n_pkts; i++)
+		rte_pktmbuf_free(pkts[i]);
+
+	RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(p, i);
+
+	return n_pkts;
+}
+
+static int
+rte_port_fd_reader_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_reader_stats_read(void *port,
+		struct rte_port_in_stats *stats, int clear)
+{
+	struct rte_port_fd_reader *p =
+			(struct rte_port_fd_reader *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val } while (0)
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val } while (0)
+
+#else
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_params *conf =
+		(struct rte_port_fd_writer_params *) params;
+	struct rte_port_fd_writer *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	return port;
+}
+
+static inline void
+send_burst(struct rte_port_fd_writer *p)
+{
+	uint32_t i;
+
+	for (i = 0; i < p->tx_buf_count; i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+		ssize_t ret;
+
+		ret = write(p->fd, pkt_data, n_bytes);
+		if (ret < 0)
+			break;
+	}
+
+	RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_flush(void *port)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_flush(port);
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_writer_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer Nodrop
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val } while (0)
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val } while (0)
+
+#else
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer_nodrop {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint64_t n_retries;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_nodrop_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_nodrop_params *conf =
+			(struct rte_port_fd_writer_nodrop_params *) params;
+	struct rte_port_fd_writer_nodrop *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->fd < 0) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	/*
+	 * When n_retries is 0 it means that we should wait for every packet to
+	 * send no matter how many retries should it take. To limit number of
+	 * branches in fast path, we use UINT64_MAX instead of branching.
+	 */
+	port->n_retries = (conf->n_retries == 0) ? UINT64_MAX : conf->n_retries;
+
+	return port;
+}
+
+static inline void
+send_burst_nodrop(struct rte_port_fd_writer_nodrop *p)
+{
+	uint64_t n_retries;
+	uint32_t i;
+
+	n_retries = 0;
+	for (i = 0; (i < p->tx_buf_count) && (n_retries < p->n_retries); i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+
+		for ( ; n_retries < p->n_retries; n_retries++) {
+			ssize_t ret;
+
+			ret = write(p->fd, pkt_data, n_bytes);
+			if (ret)
+				break;
+		}
+	}
+
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_flush(void *port)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_nodrop_flush(port);
+	rte_free(port);
+
+return 0;
+}
+
+static int rte_port_fd_writer_nodrop_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Summary of port operations
+ */
+struct rte_port_in_ops rte_port_fd_reader_ops = {
+	.f_create = rte_port_fd_reader_create,
+	.f_free = rte_port_fd_reader_free,
+	.f_rx = rte_port_fd_reader_rx,
+	.f_stats = rte_port_fd_reader_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_ops = {
+	.f_create = rte_port_fd_writer_create,
+	.f_free = rte_port_fd_writer_free,
+	.f_tx = rte_port_fd_writer_tx,
+	.f_tx_bulk = rte_port_fd_writer_tx_bulk,
+	.f_flush = rte_port_fd_writer_flush,
+	.f_stats = rte_port_fd_writer_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_nodrop_ops = {
+	.f_create = rte_port_fd_writer_nodrop_create,
+	.f_free = rte_port_fd_writer_nodrop_free,
+	.f_tx = rte_port_fd_writer_nodrop_tx,
+	.f_tx_bulk = rte_port_fd_writer_nodrop_tx_bulk,
+	.f_flush = rte_port_fd_writer_nodrop_flush,
+	.f_stats = rte_port_fd_writer_nodrop_stats_read,
+};
diff --git a/lib/librte_port/rte_port_fd.h b/lib/librte_port/rte_port_fd.h
new file mode 100644
index 0000000..b9ae8e4
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.h
@@ -0,0 +1,105 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_RTE_PORT_FD_H__
+#define __INCLUDE_RTE_PORT_FD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE Port FD Device
+ *
+ * fd_reader: input port built on top of valid non-blocking file descriptor
+ * fd_writer: output port built on top of valid non-blocking file descriptor
+ *
+ ***/
+
+#include <stdint.h>
+
+#include <rte_mempool.h>
+#include "rte_port.h"
+
+/** fd_reader port parameters */
+struct rte_port_fd_reader_params {
+	/** File descriptor */
+	int fd;
+
+	/** Maximum Transfer Unit (MTU) */
+	uint32_t mtu;
+
+	/** Pre-initialized buffer pool */
+	struct rte_mempool *mempool;
+};
+
+/** fd_reader port operations */
+extern struct rte_port_in_ops rte_port_fd_reader_ops;
+
+/** fd_writer port parameters */
+struct rte_port_fd_writer_params {
+	/** File descriptor */
+	int fd;
+
+	/**< Recommended write burst size. The actual burst size can be
+	 * bigger or smaller than this value.
+	 */
+	uint32_t tx_burst_sz;
+};
+
+/** fd_writer port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_ops;
+
+/** fd_writer_nodrop port parameters */
+struct rte_port_fd_writer_nodrop_params {
+	/** File descriptor */
+	int fd;
+
+	/**< Recommended write burst size. The actual burst size can be
+	 * bigger or smaller than this value.
+	 */
+	uint32_t tx_burst_sz;
+
+	/** Maximum number of retries, 0 for no limit */
+	uint32_t n_retries;
+};
+
+/** fd_writer_nodrop port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_nodrop_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_port/rte_port_version.map b/lib/librte_port/rte_port_version.map
index 048c20d..6470629 100644
--- a/lib/librte_port/rte_port_version.map
+++ b/lib/librte_port/rte_port_version.map
@@ -42,3 +42,12 @@ DPDK_16.07 {
 	rte_port_kni_writer_nodrop_ops;
 
 } DPDK_2.2;
+
+DPDK_16.11 {
+	global:
+
+	rte_port_fd_reader_ops;
+	rte_port_fd_writer_ops;
+	rte_port_fd_writer_nodrop_ops;
+
+} DPDK_16.07;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/3] examples/ip_pipeline: integrate TAP port
  2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
@ 2016-09-04 14:38   ` Jasvinder Singh
  2016-09-04 14:38   ` [PATCH v2 3/3] examples/ip_pipeline: add sample config file with TAP port usage Jasvinder Singh
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-09-04 14:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

The TAP port support is added to ip_pipeline app. To parse
configuration file with TAP port entries, parsing function is implemented.
The TAP ports configuration check and initialization routines have been
included in application code.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/app.h                         | 140 +++++++++++++++++++++
 examples/ip_pipeline/config_check.c                |  31 +++++
 examples/ip_pipeline/config_parse.c                | 135 ++++++++++++++++++++
 examples/ip_pipeline/init.c                        |  62 +++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |   1 +
 examples/ip_pipeline/pipeline_be.h                 |  13 ++
 6 files changed, 382 insertions(+)

diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 6a6fdd9..1ab6cf7 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -177,6 +177,16 @@ struct app_pktq_tm_params {
 	uint32_t burst_write;
 };
 
+struct app_pktq_tap_params {
+	char *name;
+	uint32_t parsed;
+	uint32_t burst_read;
+	uint32_t burst_write;
+	uint32_t dropless;
+	uint64_t n_retries;
+	uint32_t mempool_id; /* Position in the app->mempool_params */
+};
+
 struct app_pktq_source_params {
 	char *name;
 	uint32_t parsed;
@@ -204,6 +214,7 @@ enum app_pktq_in_type {
 	APP_PKTQ_IN_HWQ,
 	APP_PKTQ_IN_SWQ,
 	APP_PKTQ_IN_TM,
+	APP_PKTQ_IN_TAP,
 	APP_PKTQ_IN_KNI,
 	APP_PKTQ_IN_SOURCE,
 };
@@ -217,6 +228,7 @@ enum app_pktq_out_type {
 	APP_PKTQ_OUT_HWQ,
 	APP_PKTQ_OUT_SWQ,
 	APP_PKTQ_OUT_TM,
+	APP_PKTQ_OUT_TAP,
 	APP_PKTQ_OUT_KNI,
 	APP_PKTQ_OUT_SINK,
 };
@@ -441,6 +453,10 @@ struct app_eal_params {
 
 #define APP_MAX_PKTQ_TM                          APP_MAX_LINKS
 
+#ifndef APP_MAX_PKTQ_TAP
+#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
+#endif
+
 #define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
 
 #ifndef APP_MAX_PKTQ_SOURCE
@@ -494,6 +510,7 @@ struct app_params {
 	struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT];
 	struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ];
 	struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM];
+	struct app_pktq_tap_params tap_params[APP_MAX_PKTQ_TAP];
 	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
 	struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE];
 	struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK];
@@ -506,6 +523,7 @@ struct app_params {
 	uint32_t n_pktq_hwq_out;
 	uint32_t n_pktq_swq;
 	uint32_t n_pktq_tm;
+	uint32_t n_pktq_tap;
 	uint32_t n_pktq_kni;
 	uint32_t n_pktq_source;
 	uint32_t n_pktq_sink;
@@ -520,6 +538,7 @@ struct app_params {
 	struct app_link_data link_data[APP_MAX_LINKS];
 	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
 	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
+	int tap[APP_MAX_PKTQ_TAP];
 #ifdef RTE_LIBRTE_KNI
 	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
 #endif /* RTE_LIBRTE_KNI */
@@ -786,6 +805,66 @@ app_tm_get_reader(struct app_params *app,
 }
 
 static inline uint32_t
+app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
+{
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_TAP) &&
+				(pktq->id == pos))
+				n_readers++;
+		}
+	}
+
+	return n_readers;
+}
+
+static inline struct app_pipeline_params *
+app_tap_get_reader(struct app_params *app,
+	struct app_pktq_tap_params *tap,
+	uint32_t *pktq_in_id)
+{
+	struct app_pipeline_params *reader = NULL;
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, id = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_TAP) &&
+				(pktq->id == pos)) {
+				n_readers++;
+				reader = p;
+				id = j;
+			}
+		}
+	}
+
+	if (n_readers != 1)
+		return NULL;
+
+	*pktq_in_id = id;
+	return reader;
+}
+
+static inline uint32_t
 app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
 {
 	uint32_t pos = kni - app->kni_params;
@@ -1043,6 +1122,67 @@ app_tm_get_writer(struct app_params *app,
 }
 
 static inline uint32_t
+app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
+{
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
+			(pktq->id == pos))
+			n_writers++;
+		}
+	}
+
+	return n_writers;
+}
+
+static inline struct app_pipeline_params *
+app_tap_get_writer(struct app_params *app,
+	struct app_pktq_tap_params *tap,
+	uint32_t *pktq_out_id)
+{
+	struct app_pipeline_params *writer;
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, id = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
+				(pktq->id == pos))
+				n_writers++;
+				writer = p;
+				id = j;
+		}
+	}
+
+	if (n_writers != 1)
+		return NULL;
+
+	*pktq_out_id = id;
+	return writer;
+}
+
+static inline uint32_t
 app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
 {
 	uint32_t pos = kni - app->kni_params;
diff --git a/examples/ip_pipeline/config_check.c b/examples/ip_pipeline/config_check.c
index af1b628..dd9d4d8 100644
--- a/examples/ip_pipeline/config_check.c
+++ b/examples/ip_pipeline/config_check.c
@@ -316,6 +316,36 @@ check_tms(struct app_params *app)
 }
 
 static void
+check_taps(struct app_params *app)
+{
+	uint32_t i;
+
+	for (i = 0; i < app->n_pktq_tap; i++) {
+		struct app_pktq_tap_params *p = &app->tap_params[i];
+		uint32_t n_readers = app_tap_get_readers(app, p);
+		uint32_t n_writers = app_tap_get_writers(app, p);
+
+		APP_CHECK((n_readers != 0),
+			"%s has no reader\n", p->name);
+
+		APP_CHECK((n_readers == 1),
+			"%s has more than one reader\n", p->name);
+
+		APP_CHECK((n_writers != 0),
+			"%s has no writer\n", p->name);
+
+		APP_CHECK((n_writers == 1),
+			"%s has more than one writer\n", p->name);
+
+		APP_CHECK((p->burst_read > 0),
+			"%s read burst size is 0\n", p->name);
+
+		APP_CHECK((p->burst_write > 0),
+			"%s write burst size is 0\n", p->name);
+	}
+}
+
+static void
 check_knis(struct app_params *app) {
 	uint32_t i;
 
@@ -476,6 +506,7 @@ app_config_check(struct app_params *app)
 	check_txqs(app);
 	check_swqs(app);
 	check_tms(app);
+	check_taps(app);
 	check_knis(app);
 	check_sources(app);
 	check_sinks(app);
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index 8fe8157..4394e5a 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -189,6 +189,15 @@ struct app_pktq_tm_params default_tm_params = {
 	.burst_write = 32,
 };
 
+struct app_pktq_tap_params default_tap_params = {
+	.parsed = 0,
+	.burst_read = 32,
+	.burst_write = 32,
+	.dropless = 0,
+	.n_retries = 0,
+	.mempool_id = 0,
+};
+
 struct app_pktq_kni_params default_kni_params = {
 	.parsed = 0,
 	.socket_id = 0,
@@ -852,6 +861,9 @@ parse_pipeline_pktq_in(struct app_params *app,
 			type = APP_PKTQ_IN_TM;
 			id = APP_PARAM_ADD(app->tm_params, name);
 			APP_PARAM_ADD_LINK_FOR_TM(app, name);
+		} else if (validate_name(name, "TAP", 1) == 0) {
+			type = APP_PKTQ_IN_TAP;
+			id = APP_PARAM_ADD(app->tap_params, name);
 		} else if (validate_name(name, "KNI", 1) == 0) {
 			type = APP_PKTQ_IN_KNI;
 			id = APP_PARAM_ADD(app->kni_params, name);
@@ -901,6 +913,9 @@ parse_pipeline_pktq_out(struct app_params *app,
 			type = APP_PKTQ_OUT_TM;
 			id = APP_PARAM_ADD(app->tm_params, name);
 			APP_PARAM_ADD_LINK_FOR_TM(app, name);
+		} else if (validate_name(name, "TAP", 1) == 0) {
+			type = APP_PKTQ_OUT_TAP;
+			id = APP_PARAM_ADD(app->tap_params, name);
 		} else if (validate_name(name, "KNI", 1) == 0) {
 			type = APP_PKTQ_OUT_KNI;
 			id = APP_PARAM_ADD(app->kni_params, name);
@@ -1896,6 +1911,88 @@ parse_tm(struct app_params *app,
 }
 
 static void
+parse_tap(struct app_params *app,
+	const char *section_name,
+	struct rte_cfgfile *cfg)
+{
+	struct app_pktq_tap_params *param;
+	struct rte_cfgfile_entry *entries;
+	int n_entries, i;
+	ssize_t param_idx;
+
+	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+	PARSE_ERROR_MALLOC(entries != NULL);
+
+	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
+	param = &app->tap_params[param_idx];
+	PARSE_CHECK_DUPLICATE_SECTION(param);
+
+	for (i = 0; i < n_entries; i++) {
+		struct rte_cfgfile_entry *ent = &entries[i];
+
+		if (strcmp(ent->name, "burst_read") == 0) {
+			int status = parser_read_uint32(
+				&param->burst_read, ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "burst_write") == 0) {
+			int status = parser_read_uint32(
+				&param->burst_write, ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "dropless") == 0) {
+			int status = parser_read_arg_bool(ent->value);
+
+			PARSE_ERROR((status != -EINVAL), section_name,
+				ent->name);
+			param->dropless = status;
+			continue;
+		}
+
+		if (strcmp(ent->name, "n_retries") == 0) {
+			int status = parser_read_uint64(&param->n_retries,
+				ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "mempool") == 0) {
+			int status = validate_name(ent->value,
+				"MEMPOOL", 1);
+			ssize_t idx;
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+
+			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
+			param->mempool_id = idx;
+
+			continue;
+		}
+
+		/* unrecognized */
+		PARSE_ERROR_INVALID(0, section_name, ent->name);
+	}
+
+	free(entries);
+}
+
+static void
 parse_kni(struct app_params *app,
 		  const char *section_name,
 		  struct rte_cfgfile *cfg)
@@ -2286,6 +2383,7 @@ static const struct config_section cfg_file_scheme[] = {
 	{"TXQ", 2, parse_txq},
 	{"SWQ", 1, parse_swq},
 	{"TM", 1, parse_tm},
+	{"TAP", 1, parse_tap},
 	{"KNI", 1, parse_kni},
 	{"SOURCE", 1, parse_source},
 	{"SINK", 1, parse_sink},
@@ -2425,6 +2523,7 @@ app_config_parse(struct app_params *app, const char *file_name)
 	APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out);
 	APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq);
 	APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm);
+	APP_PARAM_COUNT(app->tap_params, app->n_pktq_tap);
 	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
 	APP_PARAM_COUNT(app->source_params, app->n_pktq_source);
 	APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink);
@@ -2789,6 +2888,30 @@ save_tm_params(struct app_params *app, FILE *f)
 }
 
 static void
+save_tap_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_tap_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->tap_params);
+	for (i = 0; i < count; i++) {
+		p = &app->tap_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+		fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no");
+		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
+		fprintf(f, "%s = %s\n", "mempool",
+			app->mempool_params[p->mempool_id].name);
+
+		fputc('\n', f);
+	}
+}
+
+static void
 save_kni_params(struct app_params *app, FILE *f)
 {
 	struct app_pktq_kni_params *p;
@@ -2942,6 +3065,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
 				case APP_PKTQ_IN_TM:
 					name = app->tm_params[pp->id].name;
 					break;
+				case APP_PKTQ_IN_TAP:
+					name = app->tap_params[pp->id].name;
+					break;
 				case APP_PKTQ_IN_KNI:
 					name = app->kni_params[pp->id].name;
 					break;
@@ -2979,6 +3105,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
 				case APP_PKTQ_OUT_TM:
 					name = app->tm_params[pp->id].name;
 					break;
+				case APP_PKTQ_OUT_TAP:
+					name = app->tap_params[pp->id].name;
+					break;
 				case APP_PKTQ_OUT_KNI:
 					name = app->kni_params[pp->id].name;
 					break;
@@ -3067,6 +3196,7 @@ app_config_save(struct app_params *app, const char *file_name)
 	save_txq_params(app, file);
 	save_swq_params(app, file);
 	save_tm_params(app, file);
+	save_tap_params(app, file);
 	save_kni_params(app, file);
 	save_source_params(app, file);
 	save_sink_params(app, file);
@@ -3117,6 +3247,11 @@ app_config_init(struct app_params *app)
 			&default_tm_params,
 			sizeof(default_tm_params));
 
+	for (i = 0; i < RTE_DIM(app->tap_params); i++)
+		memcpy(&app->tap_params[i],
+			&default_tap_params,
+			sizeof(default_tap_params));
+
 	for (i = 0; i < RTE_DIM(app->kni_params); i++)
 		memcpy(&app->kni_params[i],
 			   &default_kni_params,
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index cd167f6..fe3d9ef 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -34,6 +34,12 @@
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
 #include <rte_cycles.h>
 #include <rte_ethdev.h>
@@ -1176,6 +1182,34 @@ app_init_tm(struct app_params *app)
 	}
 }
 
+static void
+app_init_tap(struct app_params *app)
+{
+	uint32_t i;
+
+	for (i = 0; i < app->n_pktq_tap; i++) {
+		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
+		struct ifreq ifr;
+		int fd, status;
+
+		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
+
+		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+		if (fd < 0)
+			rte_panic("Cannot open file /dev/net/tun\n");
+
+		memset(&ifr, 0, sizeof(ifr));
+		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
+
+		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+		if (status < 0)
+			rte_panic("TAP setup error\n");
+
+		app->tap[i] = fd;
+	}
+}
+
 #ifdef RTE_LIBRTE_KNI
 static int
 kni_config_network_interface(uint8_t port_id, uint8_t if_up) {
@@ -1392,6 +1426,22 @@ void app_pipeline_params_get(struct app_params *app,
 			out->burst_size = app->tm_params[in->id].burst_read;
 			break;
 		}
+		case APP_PKTQ_IN_TAP:
+		{
+			struct app_pktq_tap_params *tap_params =
+				&app->tap_params[in->id];
+			struct app_mempool_params *mempool_params =
+				&app->mempool_params[tap_params->mempool_id];
+			struct rte_mempool *mempool =
+				app->mempool[tap_params->mempool_id];
+
+			out->type = PIPELINE_PORT_IN_FD_READER;
+			out->params.fd.fd = app->tap[in->id];
+			out->params.fd.mtu = mempool_params->buffer_size;
+			out->params.fd.mempool = mempool;
+			out->burst_size = app->tap_params[in->id].burst_read;
+			break;
+		}
 #ifdef RTE_LIBRTE_KNI
 		case APP_PKTQ_IN_KNI:
 		{
@@ -1536,6 +1586,17 @@ void app_pipeline_params_get(struct app_params *app,
 				app->tm_params[in->id].burst_write;
 			break;
 		}
+		case APP_PKTQ_OUT_TAP:
+		{
+			struct rte_port_fd_writer_params *params =
+				&out->params.fd;
+
+			out->type = PIPELINE_PORT_OUT_FD_WRITER;
+			params->fd = app->tap[in->id];
+			params->tx_burst_sz =
+				app->tap_params[in->id].burst_write;
+			break;
+		}
 #ifdef RTE_LIBRTE_KNI
 		case APP_PKTQ_OUT_KNI:
 		{
@@ -1752,6 +1813,7 @@ int app_init(struct app_params *app)
 	app_init_link(app);
 	app_init_swq(app);
 	app_init_tm(app);
+	app_init_tap(app);
 	app_init_kni(app);
 	app_init_msgq(app);
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index cd1d082..e89326c 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -157,6 +157,7 @@ app_pipeline_track_pktq_out_to_link(struct app_params *app,
 			break;
 		}
 
+		case APP_PKTQ_OUT_TAP:
 		case APP_PKTQ_OUT_SINK:
 		default:
 			return NULL;
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
index b562472..0cfcc80 100644
--- a/examples/ip_pipeline/pipeline_be.h
+++ b/examples/ip_pipeline/pipeline_be.h
@@ -39,6 +39,7 @@
 #include <rte_port_frag.h>
 #include <rte_port_ras.h>
 #include <rte_port_sched.h>
+#include <rte_port_fd.h>
 #include <rte_port_source_sink.h>
 #ifdef RTE_LIBRTE_KNI
 #include <rte_port_kni.h>
@@ -52,6 +53,7 @@ enum pipeline_port_in_type {
 	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
 	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
 	PIPELINE_PORT_IN_SCHED_READER,
+	PIPELINE_PORT_IN_FD_READER,
 	PIPELINE_PORT_IN_KNI_READER,
 	PIPELINE_PORT_IN_SOURCE,
 };
@@ -65,6 +67,7 @@ struct pipeline_port_in_params {
 		struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
 		struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
 		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
 #ifdef RTE_LIBRTE_KNI
 		struct rte_port_kni_reader_params kni;
 #endif
@@ -89,6 +92,8 @@ pipeline_port_in_params_convert(struct pipeline_port_in_params  *p)
 		return (void *) &p->params.ring_ipv6_frag;
 	case PIPELINE_PORT_IN_SCHED_READER:
 		return (void *) &p->params.sched;
+	case PIPELINE_PORT_IN_FD_READER:
+		return (void *) &p->params.fd;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_IN_KNI_READER:
 		return (void *) &p->params.kni;
@@ -116,6 +121,8 @@ pipeline_port_in_params_get_ops(struct pipeline_port_in_params  *p)
 		return &rte_port_ring_reader_ipv6_frag_ops;
 	case PIPELINE_PORT_IN_SCHED_READER:
 		return &rte_port_sched_reader_ops;
+	case PIPELINE_PORT_IN_FD_READER:
+		return &rte_port_fd_reader_ops;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_IN_KNI_READER:
 		return &rte_port_kni_reader_ops;
@@ -137,6 +144,7 @@ enum pipeline_port_out_type {
 	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
 	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
 	PIPELINE_PORT_OUT_SCHED_WRITER,
+	PIPELINE_PORT_OUT_FD_WRITER,
 	PIPELINE_PORT_OUT_KNI_WRITER,
 	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
 	PIPELINE_PORT_OUT_SINK,
@@ -154,6 +162,7 @@ struct pipeline_port_out_params {
 		struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras;
 		struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras;
 		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
 #ifdef RTE_LIBRTE_KNI
 		struct rte_port_kni_writer_params kni;
 		struct rte_port_kni_writer_nodrop_params kni_nodrop;
@@ -184,6 +193,8 @@ pipeline_port_out_params_convert(struct pipeline_port_out_params  *p)
 		return (void *) &p->params.ring_ipv6_ras;
 	case PIPELINE_PORT_OUT_SCHED_WRITER:
 		return (void *) &p->params.sched;
+	case PIPELINE_PORT_OUT_FD_WRITER:
+		return (void *) &p->params.fd;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_OUT_KNI_WRITER:
 		return (void *) &p->params.kni;
@@ -219,6 +230,8 @@ pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
 		return &rte_port_ring_writer_ipv6_ras_ops;
 	case PIPELINE_PORT_OUT_SCHED_WRITER:
 		return &rte_port_sched_writer_ops;
+	case PIPELINE_PORT_OUT_FD_WRITER:
+		return &rte_port_fd_writer_ops;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_OUT_KNI_WRITER:
 		return &rte_port_kni_writer_ops;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/3] examples/ip_pipeline: add sample config file with TAP port usage
  2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
  2016-09-04 14:38   ` [PATCH v2 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
@ 2016-09-04 14:38   ` Jasvinder Singh
       [not found]   ` <20160905101218.GA18384@bricha3-MOBL3>
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-09-04 14:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

To illustrate the TAP port usage, the sample configuration file with
passthrough pipeline connected to TAP interface is added.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/tap.cfg | 64 +++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 examples/ip_pipeline/config/tap.cfg

diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
new file mode 100644
index 0000000..dc72a93
--- /dev/null
+++ b/examples/ip_pipeline/config/tap.cfg
@@ -0,0 +1,64 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ______________          ______________________
+;            |              |  TAP0  |                      |
+; RXQ0.0 --->|              |------->|--+                   |
+;            |              |  TAP1  |  | br0               |
+; TXQ1.0 <---|              |<-------|<-+                   |
+;            | Pass-through |        |     Linux Kernel     |
+;            |     (P1)     |        |     Network Stack    |
+;            |              |  TAP1  |                      |
+; RXQ1.0 --->|              |------->|--+                   |
+;            |              |  TAP0  |  | br0               |
+; TXQ0.0 <---|              |<-------|<-+                   |
+;            |______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ brctl addbr "br0"
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig br0 up
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = PASS-THROUGH
+core = 1
+pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
+pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] lib/librte_port: enable file descriptor port support
       [not found]   ` <20160905101218.GA18384@bricha3-MOBL3>
@ 2016-09-09 21:19     ` Dumitrescu, Cristian
  0 siblings, 0 replies; 12+ messages in thread
From: Dumitrescu, Cristian @ 2016-09-09 21:19 UTC (permalink / raw)
  To: Richardson, Bruce, Singh, Jasvinder; +Cc: dev



> -----Original Message-----
> From: Richardson, Bruce
> Sent: Monday, September 5, 2016 11:12 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v2 1/3] lib/librte_port: enable file descriptor
> port support
> 
> On Sun, Sep 04, 2016 at 03:38:39PM +0100, Jasvinder Singh wrote:
> > This patch adds File Descriptor(FD) port type (e.g. TAP port) to the
> > packet framework library that allows interface with the kernel network
> > stack. The FD port APIs are defined that allow port creation, writing
> > and reading packet from the kernel interface.
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > ---
> > v2:
> > - fix checkpatch warnings
> 
> Rather than adding a special TAP port for use by packet framework alone,
> why not
> create a TAP PMD/ethdev and then it can be used both by regular DPDK
> apps, as well
> as by packet framework too - since packet framework already has an ethdev
> port
> type that presumably works with all ethdevs?
> 
> /Bruce

Great idea, but we don't have the bandwidth to create a TAP PMD right now. Any volunteers?

Please also note that the non-blocking file descriptor is actually significantly more generic/has broader applicability than just the TAP device, as it can be used to interface with any file descriptor, not just a TAP file descriptor, e.g. any Linux kernel character device or sockets (probably a small number of sockets), etc. I am sure it will prove itself useful to more people and we'll probably find even more places to use it going forward. Unfortunately, AFAIK this cannot be fitted as a PMD right now due to EAL limitations, as this would be virtual device and the file descriptor ID would have to be known before the DPDK application is started and passed to the app through the EAL vdev parameter, right?

This being said, I propose we go ahead with this new type of port. Whenever a TAP PMD becomes available, I don't mind changing the IP pipeline app to use it if people would prefer it. Our primary motivation for adding TAP support to IP pipeline app was to serve as a base of performance comparison between TAP and KNI when the same setup is used, but I am sure there are other potential usages for it.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] lib/librte_port: enable file descriptor port support
  2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
                     ` (2 preceding siblings ...)
       [not found]   ` <20160905101218.GA18384@bricha3-MOBL3>
@ 2016-10-12 20:33   ` Thomas Monjalon
  2016-10-12 20:44     ` Dumitrescu, Cristian
  2016-10-13  9:17   ` [PATCH v3 " Jasvinder Singh
  4 siblings, 1 reply; 12+ messages in thread
From: Thomas Monjalon @ 2016-10-12 20:33 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev, cristian.dumitrescu

2016-09-04 15:38, Jasvinder Singh:
> +#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val) \
> +       do { port->stats.n_pkts_in += val } while (0)
> +#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val) \
> +       do { port->stats.n_pkts_drop += val } while (0)
> +

It does not compile because of missing ;

> + *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.

The years seem outdated.

This patchset was probably not tested as it does not compile.
And it could be useless if a TAP PMD is integrated.
I suggest to wait 17.02 cycle and see.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] lib/librte_port: enable file descriptor port support
  2016-10-12 20:33   ` Thomas Monjalon
@ 2016-10-12 20:44     ` Dumitrescu, Cristian
  2016-10-14 15:08       ` Thomas Monjalon
  0 siblings, 1 reply; 12+ messages in thread
From: Dumitrescu, Cristian @ 2016-10-12 20:44 UTC (permalink / raw)
  To: Thomas Monjalon, Singh, Jasvinder; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, October 12, 2016 9:33 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v2 1/3] lib/librte_port: enable file descriptor
> port support
> 
> 2016-09-04 15:38, Jasvinder Singh:
> > +#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val) \
> > +       do { port->stats.n_pkts_in += val } while (0)
> > +#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val) \
> > +       do { port->stats.n_pkts_drop += val } while (0)
> > +
> 
> It does not compile because of missing ;
> 
> > + *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> 
> The years seem outdated.

Will fix immediately.

> 
> This patchset was probably not tested as it does not compile.
> And it could be useless if a TAP PMD is integrated.
> I suggest to wait 17.02 cycle and see.

This patch was tested by me and Jasvinder as well and it works brilliantly.

We did not enable stats when testing, will sort out the missing semicolon issue in the stats macros and resend v3 asap. This is a trivial issue, no need to wait for 17.02.

This is not conflicting with TAP PMD, and as said the scope of this supersedes the TAP PMD.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/3] lib/librte_port: enable file descriptor port support
  2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
                     ` (3 preceding siblings ...)
  2016-10-12 20:33   ` Thomas Monjalon
@ 2016-10-13  9:17   ` Jasvinder Singh
  2016-10-13  9:17     ` [PATCH v3 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
                       ` (2 more replies)
  4 siblings, 3 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-10-13  9:17 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This patch adds File Descriptor(FD) port type (e.g. TAP port) to the
packet framework library that allows interface with the kernel network
stack. The FD port APIs are defined that allow port creation, writing
and reading packet from the kernel interface.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v3:
- fix compilation error when stats collection enabled

v2:
- fix checkpatch warnings

 lib/librte_port/Makefile             |   2 +
 lib/librte_port/rte_port_fd.c        | 552 +++++++++++++++++++++++++++++++++++
 lib/librte_port/rte_port_fd.h        | 105 +++++++
 lib/librte_port/rte_port_version.map |   9 +
 4 files changed, 668 insertions(+)
 create mode 100644 lib/librte_port/rte_port_fd.c
 create mode 100644 lib/librte_port/rte_port_fd.h

diff --git a/lib/librte_port/Makefile b/lib/librte_port/Makefile
index 3d84a0e..44fa735 100644
--- a/lib/librte_port/Makefile
+++ b/lib/librte_port/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_frag.c
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_ras.c
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_sched.c
+SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_fd.c
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_kni.c
 endif
@@ -70,6 +71,7 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_frag.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_ras.h
 endif
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_sched.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_fd.h
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_kni.h
 endif
diff --git a/lib/librte_port/rte_port_fd.c b/lib/librte_port/rte_port_fd.c
new file mode 100644
index 0000000..0d640f3
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.c
@@ -0,0 +1,552 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+
+#include "rte_port_fd.h"
+
+/*
+ * Port FD Reader
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val; } while (0)
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val; } while (0)
+
+#else
+
+#define RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_READER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_reader {
+	struct rte_port_in_stats stats;
+	int fd;
+	uint32_t mtu;
+	struct rte_mempool *mempool;
+};
+
+static void *
+rte_port_fd_reader_create(void *params, int socket_id)
+{
+	struct rte_port_fd_reader_params *conf =
+			(struct rte_port_fd_reader_params *) params;
+	struct rte_port_fd_reader *port;
+
+	/* Check input parameters */
+	if (conf == NULL) {
+		RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
+		return NULL;
+	}
+	if (conf->fd < 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid file descriptor\n", __func__);
+		return NULL;
+	}
+	if (conf->mtu == 0) {
+		RTE_LOG(ERR, PORT, "%s: Invalid MTU\n", __func__);
+		return NULL;
+	}
+	if (conf->mempool == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Invalid mempool\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+			RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->mtu = conf->mtu;
+	port->mempool = conf->mempool;
+
+	return port;
+}
+
+static int
+rte_port_fd_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
+{
+	struct rte_port_fd_reader *p = (struct rte_port_fd_reader *) port;
+	uint32_t i;
+
+	if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
+		return 0;
+
+	for (i = 0; i < n_pkts; i++) {
+		rte_mbuf_refcnt_set(pkts[i], 1);
+		rte_pktmbuf_reset(pkts[i]);
+	}
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void *);
+		ssize_t n_bytes;
+
+		n_bytes = read(p->fd, pkt_data, (size_t) p->mtu);
+		if (n_bytes <= 0)
+			break;
+
+		pkt->data_len = n_bytes;
+		pkt->pkt_len = n_bytes;
+	}
+
+	for ( ; i < n_pkts; i++)
+		rte_pktmbuf_free(pkts[i]);
+
+	RTE_PORT_FD_READER_STATS_PKTS_IN_ADD(p, i);
+
+	return n_pkts;
+}
+
+static int
+rte_port_fd_reader_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_reader_stats_read(void *port,
+		struct rte_port_in_stats *stats, int clear)
+{
+	struct rte_port_fd_reader *p =
+			(struct rte_port_fd_reader *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val; } while (0)
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val; } while (0)
+
+#else
+
+#define RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_params *conf =
+		(struct rte_port_fd_writer_params *) params;
+	struct rte_port_fd_writer *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	return port;
+}
+
+static inline void
+send_burst(struct rte_port_fd_writer *p)
+{
+	uint32_t i;
+
+	for (i = 0; i < p->tx_buf_count; i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+		ssize_t ret;
+
+		ret = write(p->fd, pkt_data, n_bytes);
+		if (ret < 0)
+			break;
+	}
+
+	RTE_PORT_FD_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_flush(void *port)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_flush(port);
+	rte_free(port);
+
+	return 0;
+}
+
+static int rte_port_fd_writer_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer *p =
+		(struct rte_port_fd_writer *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Port FD Writer Nodrop
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val) \
+	do { port->stats.n_pkts_in += val; } while (0)
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val) \
+	do { port->stats.n_pkts_drop += val; } while (0)
+
+#else
+
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_fd_writer_nodrop {
+	struct rte_port_out_stats stats;
+
+	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+	uint32_t tx_burst_sz;
+	uint16_t tx_buf_count;
+	uint64_t n_retries;
+	uint32_t fd;
+};
+
+static void *
+rte_port_fd_writer_nodrop_create(void *params, int socket_id)
+{
+	struct rte_port_fd_writer_nodrop_params *conf =
+			(struct rte_port_fd_writer_nodrop_params *) params;
+	struct rte_port_fd_writer_nodrop *port;
+
+	/* Check input parameters */
+	if ((conf == NULL) ||
+		(conf->fd < 0) ||
+		(conf->tx_burst_sz == 0) ||
+		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+		(!rte_is_power_of_2(conf->tx_burst_sz))) {
+		RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+		return NULL;
+	}
+
+	/* Memory allocation */
+	port = rte_zmalloc_socket("PORT", sizeof(*port),
+		RTE_CACHE_LINE_SIZE, socket_id);
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+		return NULL;
+	}
+
+	/* Initialization */
+	port->fd = conf->fd;
+	port->tx_burst_sz = conf->tx_burst_sz;
+	port->tx_buf_count = 0;
+
+	/*
+	 * When n_retries is 0 it means that we should wait for every packet to
+	 * send no matter how many retries should it take. To limit number of
+	 * branches in fast path, we use UINT64_MAX instead of branching.
+	 */
+	port->n_retries = (conf->n_retries == 0) ? UINT64_MAX : conf->n_retries;
+
+	return port;
+}
+
+static inline void
+send_burst_nodrop(struct rte_port_fd_writer_nodrop *p)
+{
+	uint64_t n_retries;
+	uint32_t i;
+
+	n_retries = 0;
+	for (i = 0; (i < p->tx_buf_count) && (n_retries < p->n_retries); i++) {
+		struct rte_mbuf *pkt = p->tx_buf[i];
+		void *pkt_data = rte_pktmbuf_mtod(pkt, void*);
+		size_t n_bytes = rte_pktmbuf_data_len(pkt);
+
+		for ( ; n_retries < p->n_retries; n_retries++) {
+			ssize_t ret;
+
+			ret = write(p->fd, pkt_data, n_bytes);
+			if (ret)
+				break;
+		}
+	}
+
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - i);
+
+	for (i = 0; i < p->tx_buf_count; i++)
+		rte_pktmbuf_free(p->tx_buf[i]);
+
+	p->tx_buf_count = 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	p->tx_buf[p->tx_buf_count++] = pkt;
+	RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+	if (p->tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_tx_bulk(void *port,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+	uint32_t tx_buf_count = p->tx_buf_count;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++)
+			p->tx_buf[tx_buf_count++] = pkts[i];
+		RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pkt_index;
+			struct rte_mbuf *pkt = pkts[pkt_index];
+
+			p->tx_buf[tx_buf_count++] = pkt;
+			RTE_PORT_FD_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);
+			pkts_mask &= ~pkt_mask;
+		}
+
+	p->tx_buf_count = tx_buf_count;
+	if (tx_buf_count >= p->tx_burst_sz)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_flush(void *port)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (p->tx_buf_count > 0)
+		send_burst_nodrop(p);
+
+	return 0;
+}
+
+static int
+rte_port_fd_writer_nodrop_free(void *port)
+{
+	if (port == NULL) {
+		RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	rte_port_fd_writer_nodrop_flush(port);
+	rte_free(port);
+
+return 0;
+}
+
+static int rte_port_fd_writer_nodrop_stats_read(void *port,
+		struct rte_port_out_stats *stats, int clear)
+{
+	struct rte_port_fd_writer_nodrop *p =
+		(struct rte_port_fd_writer_nodrop *) port;
+
+	if (stats != NULL)
+		memcpy(stats, &p->stats, sizeof(p->stats));
+
+	if (clear)
+		memset(&p->stats, 0, sizeof(p->stats));
+
+	return 0;
+}
+
+/*
+ * Summary of port operations
+ */
+struct rte_port_in_ops rte_port_fd_reader_ops = {
+	.f_create = rte_port_fd_reader_create,
+	.f_free = rte_port_fd_reader_free,
+	.f_rx = rte_port_fd_reader_rx,
+	.f_stats = rte_port_fd_reader_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_ops = {
+	.f_create = rte_port_fd_writer_create,
+	.f_free = rte_port_fd_writer_free,
+	.f_tx = rte_port_fd_writer_tx,
+	.f_tx_bulk = rte_port_fd_writer_tx_bulk,
+	.f_flush = rte_port_fd_writer_flush,
+	.f_stats = rte_port_fd_writer_stats_read,
+};
+
+struct rte_port_out_ops rte_port_fd_writer_nodrop_ops = {
+	.f_create = rte_port_fd_writer_nodrop_create,
+	.f_free = rte_port_fd_writer_nodrop_free,
+	.f_tx = rte_port_fd_writer_nodrop_tx,
+	.f_tx_bulk = rte_port_fd_writer_nodrop_tx_bulk,
+	.f_flush = rte_port_fd_writer_nodrop_flush,
+	.f_stats = rte_port_fd_writer_nodrop_stats_read,
+};
diff --git a/lib/librte_port/rte_port_fd.h b/lib/librte_port/rte_port_fd.h
new file mode 100644
index 0000000..77a2d31
--- /dev/null
+++ b/lib/librte_port/rte_port_fd.h
@@ -0,0 +1,105 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_RTE_PORT_FD_H__
+#define __INCLUDE_RTE_PORT_FD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE Port FD Device
+ *
+ * fd_reader: input port built on top of valid non-blocking file descriptor
+ * fd_writer: output port built on top of valid non-blocking file descriptor
+ *
+ ***/
+
+#include <stdint.h>
+
+#include <rte_mempool.h>
+#include "rte_port.h"
+
+/** fd_reader port parameters */
+struct rte_port_fd_reader_params {
+	/** File descriptor */
+	int fd;
+
+	/** Maximum Transfer Unit (MTU) */
+	uint32_t mtu;
+
+	/** Pre-initialized buffer pool */
+	struct rte_mempool *mempool;
+};
+
+/** fd_reader port operations */
+extern struct rte_port_in_ops rte_port_fd_reader_ops;
+
+/** fd_writer port parameters */
+struct rte_port_fd_writer_params {
+	/** File descriptor */
+	int fd;
+
+	/**< Recommended write burst size. The actual burst size can be
+	 * bigger or smaller than this value.
+	 */
+	uint32_t tx_burst_sz;
+};
+
+/** fd_writer port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_ops;
+
+/** fd_writer_nodrop port parameters */
+struct rte_port_fd_writer_nodrop_params {
+	/** File descriptor */
+	int fd;
+
+	/**< Recommended write burst size. The actual burst size can be
+	 * bigger or smaller than this value.
+	 */
+	uint32_t tx_burst_sz;
+
+	/** Maximum number of retries, 0 for no limit */
+	uint32_t n_retries;
+};
+
+/** fd_writer_nodrop port operations */
+extern struct rte_port_out_ops rte_port_fd_writer_nodrop_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_port/rte_port_version.map b/lib/librte_port/rte_port_version.map
index 048c20d..6470629 100644
--- a/lib/librte_port/rte_port_version.map
+++ b/lib/librte_port/rte_port_version.map
@@ -42,3 +42,12 @@ DPDK_16.07 {
 	rte_port_kni_writer_nodrop_ops;
 
 } DPDK_2.2;
+
+DPDK_16.11 {
+	global:
+
+	rte_port_fd_reader_ops;
+	rte_port_fd_writer_ops;
+	rte_port_fd_writer_nodrop_ops;
+
+} DPDK_16.07;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/3] examples/ip_pipeline: integrate TAP port
  2016-10-13  9:17   ` [PATCH v3 " Jasvinder Singh
@ 2016-10-13  9:17     ` Jasvinder Singh
  2016-10-13  9:17     ` [PATCH v3 3/3] examples/ip_pipeline: add sample config file with TAP port usage Jasvinder Singh
  2016-10-13 12:38     ` [PATCH v3 1/3] lib/librte_port: enable file descriptor port support Thomas Monjalon
  2 siblings, 0 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-10-13  9:17 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

The TAP port support is added to ip_pipeline app. To parse
configuration file with TAP port entries, parsing function is implemented.
The TAP ports configuration check and initialization routines have been
included in application code.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/app.h                         | 140 +++++++++++++++++++++
 examples/ip_pipeline/config_check.c                |  31 +++++
 examples/ip_pipeline/config_parse.c                | 135 ++++++++++++++++++++
 examples/ip_pipeline/init.c                        |  62 +++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |   1 +
 examples/ip_pipeline/pipeline_be.h                 |  13 ++
 6 files changed, 382 insertions(+)

diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 4fdf0d9..564996e 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -177,6 +177,16 @@ struct app_pktq_tm_params {
 	uint32_t burst_write;
 };
 
+struct app_pktq_tap_params {
+	char *name;
+	uint32_t parsed;
+	uint32_t burst_read;
+	uint32_t burst_write;
+	uint32_t dropless;
+	uint64_t n_retries;
+	uint32_t mempool_id; /* Position in the app->mempool_params */
+};
+
 struct app_pktq_source_params {
 	char *name;
 	uint32_t parsed;
@@ -204,6 +214,7 @@ enum app_pktq_in_type {
 	APP_PKTQ_IN_HWQ,
 	APP_PKTQ_IN_SWQ,
 	APP_PKTQ_IN_TM,
+	APP_PKTQ_IN_TAP,
 	APP_PKTQ_IN_KNI,
 	APP_PKTQ_IN_SOURCE,
 };
@@ -217,6 +228,7 @@ enum app_pktq_out_type {
 	APP_PKTQ_OUT_HWQ,
 	APP_PKTQ_OUT_SWQ,
 	APP_PKTQ_OUT_TM,
+	APP_PKTQ_OUT_TAP,
 	APP_PKTQ_OUT_KNI,
 	APP_PKTQ_OUT_SINK,
 };
@@ -441,6 +453,10 @@ struct app_eal_params {
 
 #define APP_MAX_PKTQ_TM                          APP_MAX_LINKS
 
+#ifndef APP_MAX_PKTQ_TAP
+#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
+#endif
+
 #define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
 
 #ifndef APP_MAX_PKTQ_SOURCE
@@ -494,6 +510,7 @@ struct app_params {
 	struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT];
 	struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ];
 	struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM];
+	struct app_pktq_tap_params tap_params[APP_MAX_PKTQ_TAP];
 	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
 	struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE];
 	struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK];
@@ -506,6 +523,7 @@ struct app_params {
 	uint32_t n_pktq_hwq_out;
 	uint32_t n_pktq_swq;
 	uint32_t n_pktq_tm;
+	uint32_t n_pktq_tap;
 	uint32_t n_pktq_kni;
 	uint32_t n_pktq_source;
 	uint32_t n_pktq_sink;
@@ -520,6 +538,7 @@ struct app_params {
 	struct app_link_data link_data[APP_MAX_LINKS];
 	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
 	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
+	int tap[APP_MAX_PKTQ_TAP];
 #ifdef RTE_LIBRTE_KNI
 	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
 #endif /* RTE_LIBRTE_KNI */
@@ -786,6 +805,66 @@ app_tm_get_reader(struct app_params *app,
 }
 
 static inline uint32_t
+app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
+{
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_TAP) &&
+				(pktq->id == pos))
+				n_readers++;
+		}
+	}
+
+	return n_readers;
+}
+
+static inline struct app_pipeline_params *
+app_tap_get_reader(struct app_params *app,
+	struct app_pktq_tap_params *tap,
+	uint32_t *pktq_in_id)
+{
+	struct app_pipeline_params *reader = NULL;
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_readers = 0, id = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_in; j++) {
+			struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+			if ((pktq->type == APP_PKTQ_IN_TAP) &&
+				(pktq->id == pos)) {
+				n_readers++;
+				reader = p;
+				id = j;
+			}
+		}
+	}
+
+	if (n_readers != 1)
+		return NULL;
+
+	*pktq_in_id = id;
+	return reader;
+}
+
+static inline uint32_t
 app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
 {
 	uint32_t pos = kni - app->kni_params;
@@ -1043,6 +1122,67 @@ app_tm_get_writer(struct app_params *app,
 }
 
 static inline uint32_t
+app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
+{
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
+			(pktq->id == pos))
+			n_writers++;
+		}
+	}
+
+	return n_writers;
+}
+
+static inline struct app_pipeline_params *
+app_tap_get_writer(struct app_params *app,
+	struct app_pktq_tap_params *tap,
+	uint32_t *pktq_out_id)
+{
+	struct app_pipeline_params *writer;
+	uint32_t pos = tap - app->tap_params;
+	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+		RTE_DIM(app->pipeline_params));
+	uint32_t n_writers = 0, id = 0, i;
+
+	for (i = 0; i < n_pipelines; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+			RTE_DIM(p->pktq_out));
+		uint32_t j;
+
+		for (j = 0; j < n_pktq_out; j++) {
+			struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
+				(pktq->id == pos))
+				n_writers++;
+				writer = p;
+				id = j;
+		}
+	}
+
+	if (n_writers != 1)
+		return NULL;
+
+	*pktq_out_id = id;
+	return writer;
+}
+
+static inline uint32_t
 app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
 {
 	uint32_t pos = kni - app->kni_params;
diff --git a/examples/ip_pipeline/config_check.c b/examples/ip_pipeline/config_check.c
index af1b628..dd9d4d8 100644
--- a/examples/ip_pipeline/config_check.c
+++ b/examples/ip_pipeline/config_check.c
@@ -316,6 +316,36 @@ check_tms(struct app_params *app)
 }
 
 static void
+check_taps(struct app_params *app)
+{
+	uint32_t i;
+
+	for (i = 0; i < app->n_pktq_tap; i++) {
+		struct app_pktq_tap_params *p = &app->tap_params[i];
+		uint32_t n_readers = app_tap_get_readers(app, p);
+		uint32_t n_writers = app_tap_get_writers(app, p);
+
+		APP_CHECK((n_readers != 0),
+			"%s has no reader\n", p->name);
+
+		APP_CHECK((n_readers == 1),
+			"%s has more than one reader\n", p->name);
+
+		APP_CHECK((n_writers != 0),
+			"%s has no writer\n", p->name);
+
+		APP_CHECK((n_writers == 1),
+			"%s has more than one writer\n", p->name);
+
+		APP_CHECK((p->burst_read > 0),
+			"%s read burst size is 0\n", p->name);
+
+		APP_CHECK((p->burst_write > 0),
+			"%s write burst size is 0\n", p->name);
+	}
+}
+
+static void
 check_knis(struct app_params *app) {
 	uint32_t i;
 
@@ -476,6 +506,7 @@ app_config_check(struct app_params *app)
 	check_txqs(app);
 	check_swqs(app);
 	check_tms(app);
+	check_taps(app);
 	check_knis(app);
 	check_sources(app);
 	check_sinks(app);
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index 48c9923..8b372e9 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -189,6 +189,15 @@ struct app_pktq_tm_params default_tm_params = {
 	.burst_write = 32,
 };
 
+struct app_pktq_tap_params default_tap_params = {
+	.parsed = 0,
+	.burst_read = 32,
+	.burst_write = 32,
+	.dropless = 0,
+	.n_retries = 0,
+	.mempool_id = 0,
+};
+
 struct app_pktq_kni_params default_kni_params = {
 	.parsed = 0,
 	.socket_id = 0,
@@ -852,6 +861,9 @@ parse_pipeline_pktq_in(struct app_params *app,
 			type = APP_PKTQ_IN_TM;
 			id = APP_PARAM_ADD(app->tm_params, name);
 			APP_PARAM_ADD_LINK_FOR_TM(app, name);
+		} else if (validate_name(name, "TAP", 1) == 0) {
+			type = APP_PKTQ_IN_TAP;
+			id = APP_PARAM_ADD(app->tap_params, name);
 		} else if (validate_name(name, "KNI", 1) == 0) {
 			type = APP_PKTQ_IN_KNI;
 			id = APP_PARAM_ADD(app->kni_params, name);
@@ -901,6 +913,9 @@ parse_pipeline_pktq_out(struct app_params *app,
 			type = APP_PKTQ_OUT_TM;
 			id = APP_PARAM_ADD(app->tm_params, name);
 			APP_PARAM_ADD_LINK_FOR_TM(app, name);
+		} else if (validate_name(name, "TAP", 1) == 0) {
+			type = APP_PKTQ_OUT_TAP;
+			id = APP_PARAM_ADD(app->tap_params, name);
 		} else if (validate_name(name, "KNI", 1) == 0) {
 			type = APP_PKTQ_OUT_KNI;
 			id = APP_PARAM_ADD(app->kni_params, name);
@@ -1896,6 +1911,88 @@ parse_tm(struct app_params *app,
 }
 
 static void
+parse_tap(struct app_params *app,
+	const char *section_name,
+	struct rte_cfgfile *cfg)
+{
+	struct app_pktq_tap_params *param;
+	struct rte_cfgfile_entry *entries;
+	int n_entries, i;
+	ssize_t param_idx;
+
+	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+	PARSE_ERROR_MALLOC(entries != NULL);
+
+	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
+	param = &app->tap_params[param_idx];
+	PARSE_CHECK_DUPLICATE_SECTION(param);
+
+	for (i = 0; i < n_entries; i++) {
+		struct rte_cfgfile_entry *ent = &entries[i];
+
+		if (strcmp(ent->name, "burst_read") == 0) {
+			int status = parser_read_uint32(
+				&param->burst_read, ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "burst_write") == 0) {
+			int status = parser_read_uint32(
+				&param->burst_write, ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "dropless") == 0) {
+			int status = parser_read_arg_bool(ent->value);
+
+			PARSE_ERROR((status != -EINVAL), section_name,
+				ent->name);
+			param->dropless = status;
+			continue;
+		}
+
+		if (strcmp(ent->name, "n_retries") == 0) {
+			int status = parser_read_uint64(&param->n_retries,
+				ent->value);
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+			continue;
+		}
+
+		if (strcmp(ent->name, "mempool") == 0) {
+			int status = validate_name(ent->value,
+				"MEMPOOL", 1);
+			ssize_t idx;
+
+			PARSE_ERROR((status == 0), section_name,
+				ent->name);
+
+			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
+			param->mempool_id = idx;
+
+			continue;
+		}
+
+		/* unrecognized */
+		PARSE_ERROR_INVALID(0, section_name, ent->name);
+	}
+
+	free(entries);
+}
+
+static void
 parse_kni(struct app_params *app,
 		  const char *section_name,
 		  struct rte_cfgfile *cfg)
@@ -2286,6 +2383,7 @@ static const struct config_section cfg_file_scheme[] = {
 	{"TXQ", 2, parse_txq},
 	{"SWQ", 1, parse_swq},
 	{"TM", 1, parse_tm},
+	{"TAP", 1, parse_tap},
 	{"KNI", 1, parse_kni},
 	{"SOURCE", 1, parse_source},
 	{"SINK", 1, parse_sink},
@@ -2425,6 +2523,7 @@ app_config_parse(struct app_params *app, const char *file_name)
 	APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out);
 	APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq);
 	APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm);
+	APP_PARAM_COUNT(app->tap_params, app->n_pktq_tap);
 	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
 	APP_PARAM_COUNT(app->source_params, app->n_pktq_source);
 	APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink);
@@ -2789,6 +2888,30 @@ save_tm_params(struct app_params *app, FILE *f)
 }
 
 static void
+save_tap_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_tap_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->tap_params);
+	for (i = 0; i < count; i++) {
+		p = &app->tap_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+		fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no");
+		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
+		fprintf(f, "%s = %s\n", "mempool",
+			app->mempool_params[p->mempool_id].name);
+
+		fputc('\n', f);
+	}
+}
+
+static void
 save_kni_params(struct app_params *app, FILE *f)
 {
 	struct app_pktq_kni_params *p;
@@ -2942,6 +3065,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
 				case APP_PKTQ_IN_TM:
 					name = app->tm_params[pp->id].name;
 					break;
+				case APP_PKTQ_IN_TAP:
+					name = app->tap_params[pp->id].name;
+					break;
 				case APP_PKTQ_IN_KNI:
 					name = app->kni_params[pp->id].name;
 					break;
@@ -2979,6 +3105,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
 				case APP_PKTQ_OUT_TM:
 					name = app->tm_params[pp->id].name;
 					break;
+				case APP_PKTQ_OUT_TAP:
+					name = app->tap_params[pp->id].name;
+					break;
 				case APP_PKTQ_OUT_KNI:
 					name = app->kni_params[pp->id].name;
 					break;
@@ -3067,6 +3196,7 @@ app_config_save(struct app_params *app, const char *file_name)
 	save_txq_params(app, file);
 	save_swq_params(app, file);
 	save_tm_params(app, file);
+	save_tap_params(app, file);
 	save_kni_params(app, file);
 	save_source_params(app, file);
 	save_sink_params(app, file);
@@ -3113,6 +3243,11 @@ app_config_init(struct app_params *app)
 			&default_tm_params,
 			sizeof(default_tm_params));
 
+	for (i = 0; i < RTE_DIM(app->tap_params); i++)
+		memcpy(&app->tap_params[i],
+			&default_tap_params,
+			sizeof(default_tap_params));
+
 	for (i = 0; i < RTE_DIM(app->kni_params); i++)
 		memcpy(&app->kni_params[i],
 			   &default_kni_params,
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index d580ddf..4fed474 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -34,6 +34,12 @@
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
 #include <rte_cycles.h>
 #include <rte_ethdev.h>
@@ -1154,6 +1160,34 @@ app_init_tm(struct app_params *app)
 	}
 }
 
+static void
+app_init_tap(struct app_params *app)
+{
+	uint32_t i;
+
+	for (i = 0; i < app->n_pktq_tap; i++) {
+		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
+		struct ifreq ifr;
+		int fd, status;
+
+		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
+
+		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+		if (fd < 0)
+			rte_panic("Cannot open file /dev/net/tun\n");
+
+		memset(&ifr, 0, sizeof(ifr));
+		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
+
+		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+		if (status < 0)
+			rte_panic("TAP setup error\n");
+
+		app->tap[i] = fd;
+	}
+}
+
 #ifdef RTE_LIBRTE_KNI
 static int
 kni_config_network_interface(uint8_t port_id, uint8_t if_up) {
@@ -1370,6 +1404,22 @@ void app_pipeline_params_get(struct app_params *app,
 			out->burst_size = app->tm_params[in->id].burst_read;
 			break;
 		}
+		case APP_PKTQ_IN_TAP:
+		{
+			struct app_pktq_tap_params *tap_params =
+				&app->tap_params[in->id];
+			struct app_mempool_params *mempool_params =
+				&app->mempool_params[tap_params->mempool_id];
+			struct rte_mempool *mempool =
+				app->mempool[tap_params->mempool_id];
+
+			out->type = PIPELINE_PORT_IN_FD_READER;
+			out->params.fd.fd = app->tap[in->id];
+			out->params.fd.mtu = mempool_params->buffer_size;
+			out->params.fd.mempool = mempool;
+			out->burst_size = app->tap_params[in->id].burst_read;
+			break;
+		}
 #ifdef RTE_LIBRTE_KNI
 		case APP_PKTQ_IN_KNI:
 		{
@@ -1514,6 +1564,17 @@ void app_pipeline_params_get(struct app_params *app,
 				app->tm_params[in->id].burst_write;
 			break;
 		}
+		case APP_PKTQ_OUT_TAP:
+		{
+			struct rte_port_fd_writer_params *params =
+				&out->params.fd;
+
+			out->type = PIPELINE_PORT_OUT_FD_WRITER;
+			params->fd = app->tap[in->id];
+			params->tx_burst_sz =
+				app->tap_params[in->id].burst_write;
+			break;
+		}
 #ifdef RTE_LIBRTE_KNI
 		case APP_PKTQ_OUT_KNI:
 		{
@@ -1730,6 +1791,7 @@ int app_init(struct app_params *app)
 	app_init_link(app);
 	app_init_swq(app);
 	app_init_tm(app);
+	app_init_tap(app);
 	app_init_kni(app);
 	app_init_msgq(app);
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index 7e41071..7521187 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -156,6 +156,7 @@ app_pipeline_track_pktq_out_to_link(struct app_params *app,
 			break;
 		}
 
+		case APP_PKTQ_OUT_TAP:
 		case APP_PKTQ_OUT_SINK:
 		default:
 			return NULL;
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
index b562472..0cfcc80 100644
--- a/examples/ip_pipeline/pipeline_be.h
+++ b/examples/ip_pipeline/pipeline_be.h
@@ -39,6 +39,7 @@
 #include <rte_port_frag.h>
 #include <rte_port_ras.h>
 #include <rte_port_sched.h>
+#include <rte_port_fd.h>
 #include <rte_port_source_sink.h>
 #ifdef RTE_LIBRTE_KNI
 #include <rte_port_kni.h>
@@ -52,6 +53,7 @@ enum pipeline_port_in_type {
 	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
 	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
 	PIPELINE_PORT_IN_SCHED_READER,
+	PIPELINE_PORT_IN_FD_READER,
 	PIPELINE_PORT_IN_KNI_READER,
 	PIPELINE_PORT_IN_SOURCE,
 };
@@ -65,6 +67,7 @@ struct pipeline_port_in_params {
 		struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
 		struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
 		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
 #ifdef RTE_LIBRTE_KNI
 		struct rte_port_kni_reader_params kni;
 #endif
@@ -89,6 +92,8 @@ pipeline_port_in_params_convert(struct pipeline_port_in_params  *p)
 		return (void *) &p->params.ring_ipv6_frag;
 	case PIPELINE_PORT_IN_SCHED_READER:
 		return (void *) &p->params.sched;
+	case PIPELINE_PORT_IN_FD_READER:
+		return (void *) &p->params.fd;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_IN_KNI_READER:
 		return (void *) &p->params.kni;
@@ -116,6 +121,8 @@ pipeline_port_in_params_get_ops(struct pipeline_port_in_params  *p)
 		return &rte_port_ring_reader_ipv6_frag_ops;
 	case PIPELINE_PORT_IN_SCHED_READER:
 		return &rte_port_sched_reader_ops;
+	case PIPELINE_PORT_IN_FD_READER:
+		return &rte_port_fd_reader_ops;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_IN_KNI_READER:
 		return &rte_port_kni_reader_ops;
@@ -137,6 +144,7 @@ enum pipeline_port_out_type {
 	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
 	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
 	PIPELINE_PORT_OUT_SCHED_WRITER,
+	PIPELINE_PORT_OUT_FD_WRITER,
 	PIPELINE_PORT_OUT_KNI_WRITER,
 	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
 	PIPELINE_PORT_OUT_SINK,
@@ -154,6 +162,7 @@ struct pipeline_port_out_params {
 		struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras;
 		struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras;
 		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
 #ifdef RTE_LIBRTE_KNI
 		struct rte_port_kni_writer_params kni;
 		struct rte_port_kni_writer_nodrop_params kni_nodrop;
@@ -184,6 +193,8 @@ pipeline_port_out_params_convert(struct pipeline_port_out_params  *p)
 		return (void *) &p->params.ring_ipv6_ras;
 	case PIPELINE_PORT_OUT_SCHED_WRITER:
 		return (void *) &p->params.sched;
+	case PIPELINE_PORT_OUT_FD_WRITER:
+		return (void *) &p->params.fd;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_OUT_KNI_WRITER:
 		return (void *) &p->params.kni;
@@ -219,6 +230,8 @@ pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
 		return &rte_port_ring_writer_ipv6_ras_ops;
 	case PIPELINE_PORT_OUT_SCHED_WRITER:
 		return &rte_port_sched_writer_ops;
+	case PIPELINE_PORT_OUT_FD_WRITER:
+		return &rte_port_fd_writer_ops;
 #ifdef RTE_LIBRTE_KNI
 	case PIPELINE_PORT_OUT_KNI_WRITER:
 		return &rte_port_kni_writer_ops;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/3] examples/ip_pipeline: add sample config file with TAP port usage
  2016-10-13  9:17   ` [PATCH v3 " Jasvinder Singh
  2016-10-13  9:17     ` [PATCH v3 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
@ 2016-10-13  9:17     ` Jasvinder Singh
  2016-10-13 12:38     ` [PATCH v3 1/3] lib/librte_port: enable file descriptor port support Thomas Monjalon
  2 siblings, 0 replies; 12+ messages in thread
From: Jasvinder Singh @ 2016-10-13  9:17 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

To illustrate the TAP port usage, the sample configuration file with
passthrough pipeline connected to TAP interface is added.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/config/tap.cfg | 64 +++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 examples/ip_pipeline/config/tap.cfg

diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
new file mode 100644
index 0000000..10d35eb
--- /dev/null
+++ b/examples/ip_pipeline/config/tap.cfg
@@ -0,0 +1,64 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2016 Intel Corporation. All rights reserved.
+;   All rights reserved.
+;
+;   Redistribution and use in source and binary forms, with or without
+;   modification, are permitted provided that the following conditions
+;   are met:
+;
+;     * Redistributions of source code must retain the above copyright
+;       notice, this list of conditions and the following disclaimer.
+;     * Redistributions in binary form must reproduce the above copyright
+;       notice, this list of conditions and the following disclaimer in
+;       the documentation and/or other materials provided with the
+;       distribution.
+;     * Neither the name of Intel Corporation nor the names of its
+;       contributors may be used to endorse or promote products derived
+;       from this software without specific prior written permission.
+;
+;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;             ______________          ______________________
+;            |              |  TAP0  |                      |
+; RXQ0.0 --->|              |------->|--+                   |
+;            |              |  TAP1  |  | br0               |
+; TXQ1.0 <---|              |<-------|<-+                   |
+;            | Pass-through |        |     Linux Kernel     |
+;            |     (P1)     |        |     Network Stack    |
+;            |              |  TAP1  |                      |
+; RXQ1.0 --->|              |------->|--+                   |
+;            |              |  TAP0  |  | br0               |
+; TXQ0.0 <---|              |<-------|<-+                   |
+;            |______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ brctl addbr "br0"
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig br0 up
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = PASS-THROUGH
+core = 1
+pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
+pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/3] lib/librte_port: enable file descriptor port support
  2016-10-13  9:17   ` [PATCH v3 " Jasvinder Singh
  2016-10-13  9:17     ` [PATCH v3 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
  2016-10-13  9:17     ` [PATCH v3 3/3] examples/ip_pipeline: add sample config file with TAP port usage Jasvinder Singh
@ 2016-10-13 12:38     ` Thomas Monjalon
  2 siblings, 0 replies; 12+ messages in thread
From: Thomas Monjalon @ 2016-10-13 12:38 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev, cristian.dumitrescu

2016-10-13 10:17, Jasvinder Singh:
> This patch adds File Descriptor(FD) port type (e.g. TAP port) to the
> packet framework library that allows interface with the kernel network
> stack. The FD port APIs are defined that allow port creation, writing
> and reading packet from the kernel interface.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Series applied, thanks

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] lib/librte_port: enable file descriptor port support
  2016-10-12 20:44     ` Dumitrescu, Cristian
@ 2016-10-14 15:08       ` Thomas Monjalon
  0 siblings, 0 replies; 12+ messages in thread
From: Thomas Monjalon @ 2016-10-14 15:08 UTC (permalink / raw)
  To: Dumitrescu, Cristian; +Cc: Singh, Jasvinder, dev

2016-10-12 20:44, Dumitrescu, Cristian:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > This patchset was probably not tested as it does not compile.
> > And it could be useless if a TAP PMD is integrated.
> > I suggest to wait 17.02 cycle and see.
> 
> This patch was tested by me and Jasvinder as well and it works brilliantly.
> 
> We did not enable stats when testing, will sort out the missing semicolon issue in the stats macros and resend v3 asap. This is a trivial issue, no need to wait for 17.02.

So the stats were not tested.

> This is not conflicting with TAP PMD, and as said the scope of this supersedes the TAP PMD.

The v3 has been applied and it breaks FreeBSD compilation now.

I felt it was not ready but you won with the words "it works brilliantly" ;)
(sorry I have not resisted to make the joke)

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2016-10-14 15:08 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-05 21:21 [PATCH 1/3] lib/librte_port: enable file descriptor port support Jasvinder Singh
2016-09-04 14:38 ` [PATCH v2 " Jasvinder Singh
2016-09-04 14:38   ` [PATCH v2 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
2016-09-04 14:38   ` [PATCH v2 3/3] examples/ip_pipeline: add sample config file with TAP port usage Jasvinder Singh
     [not found]   ` <20160905101218.GA18384@bricha3-MOBL3>
2016-09-09 21:19     ` [PATCH v2 1/3] lib/librte_port: enable file descriptor port support Dumitrescu, Cristian
2016-10-12 20:33   ` Thomas Monjalon
2016-10-12 20:44     ` Dumitrescu, Cristian
2016-10-14 15:08       ` Thomas Monjalon
2016-10-13  9:17   ` [PATCH v3 " Jasvinder Singh
2016-10-13  9:17     ` [PATCH v3 2/3] examples/ip_pipeline: integrate TAP port Jasvinder Singh
2016-10-13  9:17     ` [PATCH v3 3/3] examples/ip_pipeline: add sample config file with TAP port usage Jasvinder Singh
2016-10-13 12:38     ` [PATCH v3 1/3] lib/librte_port: enable file descriptor port support Thomas Monjalon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.