DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v2] PMD for performance measurement
@ 2014-10-01  4:57 ` mukawa
  2014-10-01  4:57   ` [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD mukawa
  0 siblings, 1 reply; 37+ messages in thread
From: mukawa @ 2014-10-01  4:57 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

From: Tetsuya Mukawa <mukawa@igel.co.jp>

Hi,

Here are patches to add the new PMD like '/dev/null'.
This PMD is a driver for virtual device. When an application call rx,
it just allocates mbufs and returns those. Also tx, it just frees mbufs.

Main purpose of the PMD is measuring rough throughputs of a VDEV PMD.
To measure rough throughputs between PMD1 and PMD2, prepare following
environment.

+-------------------------------+
|           testpmd1            |
+-------------+------+----------+
| Target PMD1 |      | null PMD |
+---++--------+      +----------+
    ||
    || Target path
    ||
+---++--------+      +----------+
| Target PMD2 |      | null PMD |
+-------------+------+----------+
|           testpmd2            |
+-------------------------------+

changes from v1:
* change the copyright of Makefile.
* change commit log.
* change config file not to link the PMD statically.

changes from RFC:
* change the copyright of this PMD.
* change commit logs.

Tetsuya Mukawa (1):
  librte_pmd_null: Add null PMD

 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 +++++
 lib/librte_pmd_null/rte_eth_null.c | 474 +++++++++++++++++++++++++++++++++++++
 5 files changed, 543 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

-- 
1.9.1

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

* [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD
  2014-10-01  4:57 ` [dpdk-dev] [PATCH v2] PMD for performance measurement mukawa
@ 2014-10-01  4:57   ` mukawa
  2014-11-13 12:17     ` Thomas Monjalon
  2014-12-16  8:39     ` [dpdk-dev] [PATCH v3] " Tetsuya Mukawa
  0 siblings, 2 replies; 37+ messages in thread
From: mukawa @ 2014-10-01  4:57 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

From: Tetsuya Mukawa <mukawa@igel.co.jp>

'null PMD' is a driver of the virtual device particulary designed to measure
performance of DPDK PMDs. When an application call rx, null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disbaled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 +++++
 lib/librte_pmd_null/rte_eth_null.c | 474 +++++++++++++++++++++++++++++++++++++
 5 files changed, 543 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

diff --git a/config/common_bsdapp b/config/common_bsdapp
index eebd05b..bda37f5 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 4713eb4..66d2ce1 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -252,6 +252,11 @@ CONFIG_RTE_LIBRTE_PMD_BOND=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 10c5bb3..61d6ed1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -50,6 +50,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..0ec4db9
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..7ecdd17
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,474 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (rx_queue_id != 0)
+			return -ENODEV;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (tx_queue_id != 0)
+			return -ENODEV;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q __rte_unused) { ; }
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name __rte_unused,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* Re: [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD
  2014-10-01  4:57   ` [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD mukawa
@ 2014-11-13 12:17     ` Thomas Monjalon
  2014-12-16  8:39     ` [dpdk-dev] [PATCH v3] " Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Thomas Monjalon @ 2014-11-13 12:17 UTC (permalink / raw)
  To: dev; +Cc: nakajima.yoshihiro, masutani.hitoshi

Hi,

2014-10-01 13:57, mukawa@igel.co.jp:
> 'null PMD' is a driver of the virtual device particulary designed to measure
> performance of DPDK PMDs. When an application call rx, null PMD just allocates
> mbufs and returns those. Also tx, the PMD just frees mbufs.
> 
> The PMD has following options.
> - size: specify packe size allocated by RX. Default packet size is 64.
> - copy: specify 1 or 0 to enable or disable copy while RX and TX.
> 	Default value is 0(disbaled).
> 	This option is used for emulating more realistic data transfer.
> 	Copy size is equal to packet size.
> 
> To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
> compile the PMD as shared library. The library can be linked using '-d'
> option when an application invokes.
> 
> Here is an example.
> $ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
> 	--vdev 'eth_null0' --vdev 'eth_null1' -- -i
> 
> If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
> specify more libraries using '-d' option.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>

This patch is still pending because nobody reviewed it.

-- 
Thomas

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

* [dpdk-dev] [PATCH v3] librte_pmd_null: Add null PMD
  2014-10-01  4:57   ` [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD mukawa
  2014-11-13 12:17     ` Thomas Monjalon
@ 2014-12-16  8:39     ` Tetsuya Mukawa
  2014-12-16  8:44       ` Tetsuya Mukawa
  2015-01-20  3:00       ` [dpdk-dev] [PATCH v4 1/2] " Tetsuya Mukawa
  1 sibling, 2 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2014-12-16  8:39 UTC (permalink / raw)
  To: dev

'null PMD' is a driver of the virtual device particulary designed to measure
performance of DPDK PMDs. When an application call rx, null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disbaled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 +++++
 lib/librte_pmd_null/rte_eth_null.c | 474 +++++++++++++++++++++++++++++++++++++
 5 files changed, 543 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 9177db1..fa849be 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2f9643b..808574a 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -232,6 +232,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 0ffc982..d246c53 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..0ec4db9
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..7ecdd17
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,474 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (rx_queue_id != 0)
+			return -ENODEV;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (tx_queue_id != 0)
+			return -ENODEV;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q __rte_unused) { ; }
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name __rte_unused,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* Re: [dpdk-dev] [PATCH v3] librte_pmd_null: Add null PMD
  2014-12-16  8:39     ` [dpdk-dev] [PATCH v3] " Tetsuya Mukawa
@ 2014-12-16  8:44       ` Tetsuya Mukawa
  2014-12-16  8:47         ` Thomas Monjalon
  2015-01-20  3:00       ` [dpdk-dev] [PATCH v4 1/2] " Tetsuya Mukawa
  1 sibling, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2014-12-16  8:44 UTC (permalink / raw)
  To: dev

I've updated the null PMD to apply it to latest DPDK.
Also I've sent a port hotplug patch for null PMD.

Thanks,
Tetsuya

(2014/12/16 17:39), Tetsuya Mukawa wrote:
> 'null PMD' is a driver of the virtual device particulary designed to measure
> performance of DPDK PMDs. When an application call rx, null PMD just allocates
> mbufs and returns those. Also tx, the PMD just frees mbufs.
>
> The PMD has following options.
> - size: specify packe size allocated by RX. Default packet size is 64.
> - copy: specify 1 or 0 to enable or disable copy while RX and TX.
> 	Default value is 0(disbaled).
> 	This option is used for emulating more realistic data transfer.
> 	Copy size is equal to packet size.
>
> To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
> compile the PMD as shared library. The library can be linked using '-d'
> option when an application invokes.
>
> Here is an example.
> $ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
> 	--vdev 'eth_null0' --vdev 'eth_null1' -- -i
>
> If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
> specify more libraries using '-d' option.
>
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> ---
>  config/common_bsdapp               |   5 +
>  config/common_linuxapp             |   5 +
>  lib/Makefile                       |   1 +
>  lib/librte_pmd_null/Makefile       |  58 +++++
>  lib/librte_pmd_null/rte_eth_null.c | 474 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 543 insertions(+)
>  create mode 100644 lib/librte_pmd_null/Makefile
>  create mode 100644 lib/librte_pmd_null/rte_eth_null.c
>
> diff --git a/config/common_bsdapp b/config/common_bsdapp
> index 9177db1..fa849be 100644
> --- a/config/common_bsdapp
> +++ b/config/common_bsdapp
> @@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
>  CONFIG_RTE_LIBRTE_PMD_BOND=y
>  
>  #
> +# Compile null PMD
> +#
> +CONFIG_RTE_LIBRTE_PMD_NULL=y
> +
> +#
>  # Do prefetch of packet data within PMD driver receive function
>  #
>  CONFIG_RTE_PMD_PACKET_PREFETCH=y
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 2f9643b..808574a 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -232,6 +232,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
>  CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
>  
>  #
> +# Compile null PMD
> +#
> +CONFIG_RTE_LIBRTE_PMD_NULL=y
> +
> +#
>  # Do prefetch of packet data within PMD driver receive function
>  #
>  CONFIG_RTE_PMD_PACKET_PREFETCH=y
> diff --git a/lib/Makefile b/lib/Makefile
> index 0ffc982..d246c53 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
>  DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
>  DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
> diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
> new file mode 100644
> index 0000000..0ec4db9
> --- /dev/null
> +++ b/lib/librte_pmd_null/Makefile
> @@ -0,0 +1,58 @@
> +#   BSD LICENSE
> +#
> +#   Copyright (C) IGEL Co.,Ltd.
> +#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_null.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include +=
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
> new file mode 100644
> index 0000000..7ecdd17
> --- /dev/null
> +++ b/lib/librte_pmd_null/rte_eth_null.c
> @@ -0,0 +1,474 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright (C) IGEL Co.,Ltd.
> + *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_dev.h>
> +#include <rte_kvargs.h>
> +
> +#define ETH_NULL_PACKET_SIZE_ARG	"size"
> +#define ETH_NULL_PACKET_COPY_ARG	"copy"
> +
> +static unsigned default_packet_size = 64;
> +static unsigned default_packet_copy;
> +
> +static const char const *valid_arguments[] = {
> +	ETH_NULL_PACKET_SIZE_ARG,
> +	ETH_NULL_PACKET_COPY_ARG,
> +	NULL
> +};
> +
> +struct pmd_internals;
> +
> +struct null_queue {
> +	struct pmd_internals *internals;
> +
> +	struct rte_mempool *mb_pool;
> +	struct rte_mbuf *dummy_packet;
> +
> +	rte_atomic64_t rx_pkts;
> +	rte_atomic64_t tx_pkts;
> +	rte_atomic64_t err_pkts;
> +};
> +
> +struct pmd_internals {
> +	unsigned packet_size;
> +	unsigned packet_copy;
> +	unsigned numa_node;
> +
> +	unsigned nb_rx_queues;
> +	unsigned nb_tx_queues;
> +
> +	struct null_queue rx_null_queues[1];
> +	struct null_queue tx_null_queues[1];
> +};
> +
> +
> +static struct ether_addr eth_addr = { .addr_bytes = {0} };
> +static const char *drivername = "Null PMD";
> +static struct rte_eth_link pmd_link = {
> +	.link_speed = 10000,
> +	.link_duplex = ETH_LINK_FULL_DUPLEX,
> +	.link_status = 0
> +};
> +
> +static uint16_t
> +eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
> +{
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;
> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
> +		if (!bufs[i])
> +			break;
> +		bufs[i]->data_len = (uint16_t)packet_size;
> +		bufs[i]->pkt_len = packet_size;
> +		bufs[i]->nb_segs = 1;
> +		bufs[i]->next = NULL;
> +	}
> +
> +	rte_atomic64_add(&(h->rx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
> +{
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;
> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
> +		if (!bufs[i])
> +			break;
> +		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
> +					packet_size);
> +		bufs[i]->data_len = (uint16_t)packet_size;
> +		bufs[i]->pkt_len = packet_size;
> +		bufs[i]->nb_segs = 1;
> +		bufs[i]->next = NULL;
> +	}
> +
> +	rte_atomic64_add(&(h->rx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t nb_bufs)
> +{
> +	int i;
> +	struct null_queue *h = q;
> +
> +	for (i = 0; i < nb_bufs; i++)
> +		rte_pktmbuf_free(bufs[i]);
> +
> +	rte_atomic64_add(&(h->tx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
> +{
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;
> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
> +					packet_size);
> +		rte_pktmbuf_free(bufs[i]);
> +	}
> +
> +	rte_atomic64_add(&(h->tx_pkts), i);
> +
> +	return i;
> +}
> +
> +static int
> +eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
> +
> +static int
> +eth_dev_start(struct rte_eth_dev *dev)
> +{
> +	dev->data->dev_link.link_status = 1;
> +	return 0;
> +}
> +
> +static void
> +eth_dev_stop(struct rte_eth_dev *dev)
> +{
> +	dev->data->dev_link.link_status = 0;
> +}
> +
> +static int
> +eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
> +		uint16_t nb_rx_desc __rte_unused,
> +		unsigned int socket_id __rte_unused,
> +		const struct rte_eth_rxconf *rx_conf __rte_unused,
> +		struct rte_mempool *mb_pool __rte_unused)
> +{
> +	struct rte_mbuf *dummy_packet;
> +	struct pmd_internals *internals = dev->data->dev_private;
> +	unsigned packet_size = internals->packet_size;
> +
> +	if (rx_queue_id != 0)
> +			return -ENODEV;
> +
> +	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
> +	dev->data->rx_queues[rx_queue_id] =
> +		&internals->rx_null_queues[rx_queue_id];
> +	dummy_packet = rte_zmalloc_socket(NULL,
> +			packet_size, 0, internals->numa_node);
> +	if (dummy_packet == NULL)
> +		return -ENOMEM;
> +
> +	internals->rx_null_queues[rx_queue_id].internals = internals;
> +	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
> +
> +	return 0;
> +}
> +
> +static int
> +eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
> +		uint16_t nb_tx_desc __rte_unused,
> +		unsigned int socket_id __rte_unused,
> +		const struct rte_eth_txconf *tx_conf __rte_unused)
> +{
> +	struct rte_mbuf *dummy_packet;
> +	struct pmd_internals *internals = dev->data->dev_private;
> +	unsigned packet_size = internals->packet_size;
> +
> +	if (tx_queue_id != 0)
> +			return -ENODEV;
> +
> +	dev->data->tx_queues[tx_queue_id] =
> +		&internals->tx_null_queues[tx_queue_id];
> +	dummy_packet = rte_zmalloc_socket(NULL,
> +			packet_size, 0, internals->numa_node);
> +	if (dummy_packet == NULL)
> +		return -ENOMEM;
> +
> +	internals->tx_null_queues[tx_queue_id].internals = internals;
> +	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
> +
> +	return 0;
> +}
> +
> +
> +static void
> +eth_dev_info(struct rte_eth_dev *dev,
> +		struct rte_eth_dev_info *dev_info)
> +{
> +	struct pmd_internals *internals = dev->data->dev_private;
> +
> +	dev_info->driver_name = drivername;
> +	dev_info->max_mac_addrs = 1;
> +	dev_info->max_rx_pktlen = (uint32_t)-1;
> +	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
> +	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
> +	dev_info->min_rx_bufsize = 0;
> +	dev_info->pci_dev = NULL;
> +}
> +
> +static void
> +eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
> +{
> +	unsigned i;
> +	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
> +	const struct pmd_internals *internal = dev->data->dev_private;
> +
> +	memset(igb_stats, 0, sizeof(*igb_stats));
> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> +			i < internal->nb_rx_queues; i++) {
> +		igb_stats->q_ipackets[i] =
> +			internal->rx_null_queues[i].rx_pkts.cnt;
> +		rx_total += igb_stats->q_ipackets[i];
> +	}
> +
> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> +			i < internal->nb_tx_queues; i++) {
> +		igb_stats->q_opackets[i] =
> +			internal->tx_null_queues[i].tx_pkts.cnt;
> +		igb_stats->q_errors[i] =
> +			internal->tx_null_queues[i].err_pkts.cnt;
> +		tx_total += igb_stats->q_opackets[i];
> +		tx_err_total += igb_stats->q_errors[i];
> +	}
> +
> +	igb_stats->ipackets = rx_total;
> +	igb_stats->opackets = tx_total;
> +	igb_stats->oerrors = tx_err_total;
> +}
> +
> +static void
> +eth_stats_reset(struct rte_eth_dev *dev)
> +{
> +	unsigned i;
> +	struct pmd_internals *internal = dev->data->dev_private;
> +
> +	for (i = 0; i < internal->nb_rx_queues; i++)
> +		internal->rx_null_queues[i].rx_pkts.cnt = 0;
> +	for (i = 0; i < internal->nb_tx_queues; i++) {
> +		internal->tx_null_queues[i].tx_pkts.cnt = 0;
> +		internal->tx_null_queues[i].err_pkts.cnt = 0;
> +	}
> +}
> +
> +static void
> +eth_queue_release(void *q __rte_unused) { ; }
> +static int
> +eth_link_update(struct rte_eth_dev *dev __rte_unused,
> +		int wait_to_complete __rte_unused) { return 0; }
> +
> +static struct eth_dev_ops ops = {
> +		.dev_start = eth_dev_start,
> +		.dev_stop = eth_dev_stop,
> +		.dev_configure = eth_dev_configure,
> +		.dev_infos_get = eth_dev_info,
> +		.rx_queue_setup = eth_rx_queue_setup,
> +		.tx_queue_setup = eth_tx_queue_setup,
> +		.rx_queue_release = eth_queue_release,
> +		.tx_queue_release = eth_queue_release,
> +		.link_update = eth_link_update,
> +		.stats_get = eth_stats_get,
> +		.stats_reset = eth_stats_reset,
> +};
> +
> +static int
> +eth_dev_null_create(const char *name __rte_unused,
> +		const unsigned numa_node,
> +		unsigned packet_size,
> +		unsigned packet_copy)
> +{
> +	const unsigned nb_rx_queues = 1;
> +	const unsigned nb_tx_queues = 1;
> +	struct rte_eth_dev_data *data = NULL;
> +	struct rte_pci_device *pci_dev = NULL;
> +	struct pmd_internals *internals = NULL;
> +	struct rte_eth_dev *eth_dev = NULL;
> +
> +	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
> +			numa_node);
> +
> +	/* now do all data allocation - for eth_dev structure, dummy pci driver
> +	 * and internal (private) data
> +	 */
> +	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
> +	if (data == NULL)
> +		goto error;
> +
> +	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
> +	if (pci_dev == NULL)
> +		goto error;
> +
> +	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
> +	if (internals == NULL)
> +		goto error;
> +
> +	/* reserve an ethdev entry */
> +	eth_dev = rte_eth_dev_allocate(name);
> +	if (eth_dev == NULL)
> +		goto error;
> +
> +	/* now put it all together
> +	 * - store queue data in internals,
> +	 * - store numa_node info in pci_driver
> +	 * - point eth_dev_data to internals and pci_driver
> +	 * - and point eth_dev structure to new eth_dev_data structure
> +	 */
> +	/* NOTE: we'll replace the data element, of originally allocated eth_dev
> +	 * so the nulls are local per-process */
> +
> +	internals->nb_rx_queues = nb_rx_queues;
> +	internals->nb_tx_queues = nb_tx_queues;
> +	internals->packet_size = packet_size;
> +	internals->packet_copy = packet_copy;
> +	internals->numa_node = numa_node;
> +
> +	pci_dev->numa_node = numa_node;
> +
> +	data->dev_private = internals;
> +	data->port_id = eth_dev->data->port_id;
> +	data->nb_rx_queues = (uint16_t)nb_rx_queues;
> +	data->nb_tx_queues = (uint16_t)nb_tx_queues;
> +	data->dev_link = pmd_link;
> +	data->mac_addrs = &eth_addr;
> +
> +	eth_dev->data = data;
> +	eth_dev->dev_ops = &ops;
> +	eth_dev->pci_dev = pci_dev;
> +
> +	/* finally assign rx and tx ops */
> +	if (packet_copy) {
> +		eth_dev->rx_pkt_burst = eth_null_copy_rx;
> +		eth_dev->tx_pkt_burst = eth_null_copy_tx;
> +	} else {
> +		eth_dev->rx_pkt_burst = eth_null_rx;
> +		eth_dev->tx_pkt_burst = eth_null_tx;
> +	}
> +
> +	return 0;
> +
> +error:
> +	if (data)
> +		rte_free(data);
> +	if (pci_dev)
> +		rte_free(pci_dev);
> +	if (internals)
> +		rte_free(internals);
> +	return -1;
> +}
> +
> +static inline int
> +get_packet_size_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	const char *a = value;
> +	unsigned *packet_size = extra_args;
> +
> +	*packet_size = (unsigned)strtoul(a, NULL, 0);
> +	if (*packet_size == UINT_MAX)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static inline int
> +get_packet_copy_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	const char *a = value;
> +	unsigned *packet_copy = extra_args;
> +
> +	*packet_copy = (unsigned)strtoul(a, NULL, 0);
> +	if (*packet_copy == UINT_MAX)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int
> +rte_pmd_null_devinit(const char *name, const char *params)
> +{
> +	unsigned numa_node;
> +	unsigned packet_size = default_packet_size;
> +	unsigned packet_copy = default_packet_copy;
> +	struct rte_kvargs *kvlist;
> +	int ret;
> +
> +	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
> +
> +	numa_node = rte_socket_id();
> +
> +	kvlist = rte_kvargs_parse(params, valid_arguments);
> +	if (kvlist == NULL)
> +		return -1;
> +
> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
> +
> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
> +				&get_packet_size_arg, &packet_size);
> +		if (ret < 0)
> +			return -1;
> +	}
> +
> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
> +
> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
> +				&get_packet_copy_arg, &packet_copy);
> +		if (ret < 0)
> +			return -1;
> +	}
> +
> +	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
> +			"packet copy is %s\n", packet_size,
> +			packet_copy ? "enabled" : "disabled");
> +
> +	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
> +}
> +
> +static struct rte_driver pmd_null_drv = {
> +	.name = "eth_null",
> +	.type = PMD_VDEV,
> +	.init = rte_pmd_null_devinit,
> +};
> +
> +PMD_REGISTER_DRIVER(pmd_null_drv);

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

* Re: [dpdk-dev] [PATCH v3] librte_pmd_null: Add null PMD
  2014-12-16  8:44       ` Tetsuya Mukawa
@ 2014-12-16  8:47         ` Thomas Monjalon
  2014-12-16  8:49           ` Tetsuya Mukawa
  0 siblings, 1 reply; 37+ messages in thread
From: Thomas Monjalon @ 2014-12-16  8:47 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev

2014-12-16 17:44, Tetsuya Mukawa:
> I've updated the null PMD to apply it to latest DPDK.
> Also I've sent a port hotplug patch for null PMD.

As explained in http://dpdk.org/dev#send, do not hesitate to
use --annotate to add this kind of changelog when sending patch.
Example:
	http://dpdk.org/ml/archives/dev/2014-December/010060.html

Thanks
-- 
Thomas

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

* Re: [dpdk-dev] [PATCH v3] librte_pmd_null: Add null PMD
  2014-12-16  8:47         ` Thomas Monjalon
@ 2014-12-16  8:49           ` Tetsuya Mukawa
  0 siblings, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2014-12-16  8:49 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

(2014/12/16 17:47), Thomas Monjalon wrote:
> 2014-12-16 17:44, Tetsuya Mukawa:
>> I've updated the null PMD to apply it to latest DPDK.
>> Also I've sent a port hotplug patch for null PMD.
> As explained in http://dpdk.org/dev#send, do not hesitate to
> use --annotate to add this kind of changelog when sending patch.
> Example:
> 	http://dpdk.org/ml/archives/dev/2014-December/010060.html
>
> Thanks

Thanks, I will do it next time.

Regards,
Tetsuya

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

* [dpdk-dev] [PATCH v4 1/2] librte_pmd_null: Add null PMD
  2014-12-16  8:39     ` [dpdk-dev] [PATCH v3] " Tetsuya Mukawa
  2014-12-16  8:44       ` Tetsuya Mukawa
@ 2015-01-20  3:00       ` Tetsuya Mukawa
  2015-01-20  3:00         ` [dpdk-dev] [PATCH v4 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  1 sibling, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-01-20  3:00 UTC (permalink / raw)
  To: dev

'null PMD' is a driver of the virtual device particulary designed to measure
performance of DPDK PMDs. When an application call rx, null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disbaled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 +++++
 lib/librte_pmd_null/rte_eth_null.c | 485 +++++++++++++++++++++++++++++++++++++
 5 files changed, 554 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 9177db1..fa849be 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 27d05be..456fbfe 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 0ffc982..d246c53 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..0ec4db9
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..c54e90b
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,485 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (rx_queue_id != 0)
+			return -ENODEV;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (tx_queue_id != 0)
+			return -ENODEV;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name __rte_unused,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v4 2/2] librte_pmd_null: Support port hotplug function
  2015-01-20  3:00       ` [dpdk-dev] [PATCH v4 1/2] " Tetsuya Mukawa
@ 2015-01-20  3:00         ` Tetsuya Mukawa
  2015-02-06  4:38           ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Tetsuya Mukawa
  0 siblings, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-01-20  3:00 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to null PMD.

v4:
- Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index c54e90b..e9b1eee 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -292,6 +292,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -382,10 +389,12 @@ eth_dev_null_create(const char *name __rte_unused,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -476,10 +485,33 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(name);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD
  2015-01-20  3:00         ` [dpdk-dev] [PATCH v4 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-06  4:38           ` Tetsuya Mukawa
  2015-02-06  4:38             ` [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
                               ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-06  4:38 UTC (permalink / raw)
  To: dev

'null PMD' is a driver of the virtual device particulary designed to measure
performance of DPDK PMDs. When an application call rx, null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disbaled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 +++++
 lib/librte_pmd_null/rte_eth_null.c | 485 +++++++++++++++++++++++++++++++++++++
 5 files changed, 554 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 9177db1..fa849be 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 27d05be..456fbfe 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 0ffc982..d246c53 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..0ec4db9
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..c54e90b
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,485 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (rx_queue_id != 0)
+			return -ENODEV;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals = dev->data->dev_private;
+	unsigned packet_size = internals->packet_size;
+
+	if (tx_queue_id != 0)
+			return -ENODEV;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name __rte_unused,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function
  2015-02-06  4:38           ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Tetsuya Mukawa
@ 2015-02-06  4:38             ` Tetsuya Mukawa
  2015-02-06 11:37               ` Iremonger, Bernard
  2015-02-06 11:32             ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Iremonger, Bernard
  2015-02-12  2:44             ` [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2 siblings, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-06  4:38 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to null PMD.

v6:
 - Fix a paramter of rte_eth_dev_free().
v4:
- Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index c54e90b..6add7ce 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -292,6 +292,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -382,10 +389,12 @@ eth_dev_null_create(const char *name __rte_unused,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -476,10 +485,33 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* Re: [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD
  2015-02-06  4:38           ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Tetsuya Mukawa
  2015-02-06  4:38             ` [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-06 11:32             ` Iremonger, Bernard
  2015-02-09  8:54               ` Tetsuya Mukawa
  2015-02-12  2:44             ` [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2 siblings, 1 reply; 37+ messages in thread
From: Iremonger, Bernard @ 2015-02-06 11:32 UTC (permalink / raw)
  To: Tetsuya Mukawa, dev

Hi Tetsuya,

My comments are in line below.

> -----Original Message-----
> From: Tetsuya Mukawa [mailto:mukawa@igel.co.jp]
> Sent: Friday, February 6, 2015 4:38 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard; Tetsuya Mukawa
> Subject: [PATCH v6 1/2] librte_pmd_null: Add null PMD
> 
> 'null PMD' is a driver of the virtual device particulary designed to measure performance of DPDK
> PMDs. When an application call rx, null PMD just allocates mbufs and returns those. Also tx, the PMD
> just frees mbufs.
> 
> The PMD has following options.
> - size: specify packe size allocated by RX. Default packet size is 64.
> - copy: specify 1 or 0 to enable or disable copy while RX and TX.
> 	Default value is 0(disbaled).
> 	This option is used for emulating more realistic data transfer.
> 	Copy size is equal to packet size.
> 
> To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then compile the PMD as
> shared library. The library can be linked using '-d'
> option when an application invokes.
> 
> Here is an example.
> $ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
> 	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx
> 
> If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to specify more libraries
> using '-d' option.
> 
> v4:
>  - Fix memory leak.
>    (Thanks to Iremonger, Bernard)
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> ---
>  config/common_bsdapp               |   5 +
>  config/common_linuxapp             |   5 +
>  lib/Makefile                       |   1 +
>  lib/librte_pmd_null/Makefile       |  58 +++++
>  lib/librte_pmd_null/rte_eth_null.c | 485 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 554 insertions(+)
>  create mode 100644 lib/librte_pmd_null/Makefile  create mode 100644
> lib/librte_pmd_null/rte_eth_null.c
> 
> diff --git a/config/common_bsdapp b/config/common_bsdapp index 9177db1..fa849be 100644
> --- a/config/common_bsdapp
> +++ b/config/common_bsdapp
> @@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y  CONFIG_RTE_LIBRTE_PMD_BOND=y
> 
>  #
> +# Compile null PMD
> +#
> +CONFIG_RTE_LIBRTE_PMD_NULL=y
> +
> +#
>  # Do prefetch of packet data within PMD driver receive function  #
> CONFIG_RTE_PMD_PACKET_PREFETCH=y diff --git a/config/common_linuxapp
> b/config/common_linuxapp index 27d05be..456fbfe 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
> CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
> 
>  #
> +# Compile null PMD
> +#
> +CONFIG_RTE_LIBRTE_PMD_NULL=y
> +
> +#
>  # Do prefetch of packet data within PMD driver receive function  #
> CONFIG_RTE_PMD_PACKET_PREFETCH=y diff --git a/lib/Makefile b/lib/Makefile index
> 0ffc982..d246c53 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
>  DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
>  DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl diff --git a/lib/librte_pmd_null/Makefile
> b/lib/librte_pmd_null/Makefile new file mode 100644 index 0000000..0ec4db9
> --- /dev/null
> +++ b/lib/librte_pmd_null/Makefile
> @@ -0,0 +1,58 @@
> +#   BSD LICENSE
> +#
> +#   Copyright (C) IGEL Co.,Ltd.
> +#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_null.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include +=
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
> new file mode 100644
> index 0000000..c54e90b
> --- /dev/null
> +++ b/lib/librte_pmd_null/rte_eth_null.c
> @@ -0,0 +1,485 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright (C) IGEL Co.,Ltd.
> + *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_dev.h>
> +#include <rte_kvargs.h>
> +
> +#define ETH_NULL_PACKET_SIZE_ARG	"size"
> +#define ETH_NULL_PACKET_COPY_ARG	"copy"
> +
> +static unsigned default_packet_size = 64; static unsigned
> +default_packet_copy;
> +
> +static const char const *valid_arguments[] = {
> +	ETH_NULL_PACKET_SIZE_ARG,
> +	ETH_NULL_PACKET_COPY_ARG,
> +	NULL
> +};
> +
> +struct pmd_internals;
> +
> +struct null_queue {
> +	struct pmd_internals *internals;
> +
> +	struct rte_mempool *mb_pool;
> +	struct rte_mbuf *dummy_packet;
> +
> +	rte_atomic64_t rx_pkts;
> +	rte_atomic64_t tx_pkts;
> +	rte_atomic64_t err_pkts;
> +};
> +
> +struct pmd_internals {
> +	unsigned packet_size;
> +	unsigned packet_copy;
> +	unsigned numa_node;
> +
> +	unsigned nb_rx_queues;
> +	unsigned nb_tx_queues;
> +
> +	struct null_queue rx_null_queues[1];
> +	struct null_queue tx_null_queues[1];
> +};
> +
> +
> +static struct ether_addr eth_addr = { .addr_bytes = {0} }; static const
> +char *drivername = "Null PMD"; static struct rte_eth_link pmd_link = {
> +	.link_speed = 10000,
> +	.link_duplex = ETH_LINK_FULL_DUPLEX,
> +	.link_status = 0
> +};
> +
> +static uint16_t
> +eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;
> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
> +		if (!bufs[i])
> +			break;

Should the code return an error here rather than break?

> +		bufs[i]->data_len = (uint16_t)packet_size;
> +		bufs[i]->pkt_len = packet_size;
> +		bufs[i]->nb_segs = 1;
> +		bufs[i]->next = NULL;
> +	}
> +
> +	rte_atomic64_add(&(h->rx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;
> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
> +		if (!bufs[i])
> +			break;

Should the code return an error here rather than break?

> +		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
> +					packet_size);
> +		bufs[i]->data_len = (uint16_t)packet_size;
> +		bufs[i]->pkt_len = packet_size;
> +		bufs[i]->nb_segs = 1;
> +		bufs[i]->next = NULL;
> +	}
> +
> +	rte_atomic64_add(&(h->rx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t
> +nb_bufs) {
> +	int i;
> +	struct null_queue *h = q;

Input parameters q and bufs should be checked.

> +
> +	for (i = 0; i < nb_bufs; i++)
> +		rte_pktmbuf_free(bufs[i]);
> +
> +	rte_atomic64_add(&(h->tx_pkts), i);
> +
> +	return i;
> +}
> +
> +static uint16_t
> +eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
> +	int i;
> +	struct null_queue *h = q;
> +	unsigned packet_size = h->internals->packet_size;

Input parameters q and bufs should be checked.

> +
> +	for (i = 0; i < nb_bufs; i++) {
> +		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
> +					packet_size);
> +		rte_pktmbuf_free(bufs[i]);
> +	}
> +
> +	rte_atomic64_add(&(h->tx_pkts), i);
> +
> +	return i;
> +}
> +
> +static int
> +eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
> +
> +static int
> +eth_dev_start(struct rte_eth_dev *dev)
> +{

Input parameter dev should be checked.

> +	dev->data->dev_link.link_status = 1;
> +	return 0;
> +}
> +
> +static void
> +eth_dev_stop(struct rte_eth_dev *dev)
> +{

Input parameter dev should be checked.

> +	dev->data->dev_link.link_status = 0;
> +}
> +
> +static int
> +eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
> +		uint16_t nb_rx_desc __rte_unused,
> +		unsigned int socket_id __rte_unused,
> +		const struct rte_eth_rxconf *rx_conf __rte_unused,
> +		struct rte_mempool *mb_pool __rte_unused) {
> +	struct rte_mbuf *dummy_packet;
> +	struct pmd_internals *internals = dev->data->dev_private;
> +	unsigned packet_size = internals->packet_size;
> +

Input parameter dev should be checked.

> +	if (rx_queue_id != 0)
> +			return -ENODEV;
> +
> +	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
> +	dev->data->rx_queues[rx_queue_id] =
> +		&internals->rx_null_queues[rx_queue_id];
> +	dummy_packet = rte_zmalloc_socket(NULL,
> +			packet_size, 0, internals->numa_node);
> +	if (dummy_packet == NULL)
> +		return -ENOMEM;
> +
> +	internals->rx_null_queues[rx_queue_id].internals = internals;
> +	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
> +
> +	return 0;
> +}
> +
> +static int
> +eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
> +		uint16_t nb_tx_desc __rte_unused,
> +		unsigned int socket_id __rte_unused,
> +		const struct rte_eth_txconf *tx_conf __rte_unused) {
> +	struct rte_mbuf *dummy_packet;
> +	struct pmd_internals *internals = dev->data->dev_private;
> +	unsigned packet_size = internals->packet_size;
> +

Input parameter dev should be checked.

> +	if (tx_queue_id != 0)
> +			return -ENODEV;
> +
> +	dev->data->tx_queues[tx_queue_id] =
> +		&internals->tx_null_queues[tx_queue_id];
> +	dummy_packet = rte_zmalloc_socket(NULL,
> +			packet_size, 0, internals->numa_node);
> +	if (dummy_packet == NULL)
> +		return -ENOMEM;
> +
> +	internals->tx_null_queues[tx_queue_id].internals = internals;
> +	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
> +
> +	return 0;
> +}
> +
> +
> +static void
> +eth_dev_info(struct rte_eth_dev *dev,
> +		struct rte_eth_dev_info *dev_info)
> +{
> +	struct pmd_internals *internals = dev->data->dev_private;

Input parameters dev and dev_info should be checked.

> +
> +	dev_info->driver_name = drivername;
> +	dev_info->max_mac_addrs = 1;
> +	dev_info->max_rx_pktlen = (uint32_t)-1;
> +	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
> +	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
> +	dev_info->min_rx_bufsize = 0;
> +	dev_info->pci_dev = NULL;
> +}
> +
> +static void
> +eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
> +{
> +	unsigned i;
> +	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
> +	const struct pmd_internals *internal = dev->data->dev_private;

Input parameters dev and igb_stats should be checked.

> +
> +	memset(igb_stats, 0, sizeof(*igb_stats));
> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> +			i < internal->nb_rx_queues; i++) {
> +		igb_stats->q_ipackets[i] =
> +			internal->rx_null_queues[i].rx_pkts.cnt;
> +		rx_total += igb_stats->q_ipackets[i];
> +	}
> +
> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
> +			i < internal->nb_tx_queues; i++) {
> +		igb_stats->q_opackets[i] =
> +			internal->tx_null_queues[i].tx_pkts.cnt;
> +		igb_stats->q_errors[i] =
> +			internal->tx_null_queues[i].err_pkts.cnt;
> +		tx_total += igb_stats->q_opackets[i];
> +		tx_err_total += igb_stats->q_errors[i];
> +	}
> +
> +	igb_stats->ipackets = rx_total;
> +	igb_stats->opackets = tx_total;
> +	igb_stats->oerrors = tx_err_total;
> +}
> +
> +static void
> +eth_stats_reset(struct rte_eth_dev *dev) {
> +	unsigned i;
> +	struct pmd_internals *internal = dev->data->dev_private;

Input parameter dev should be checked.

> +
> +	for (i = 0; i < internal->nb_rx_queues; i++)
> +		internal->rx_null_queues[i].rx_pkts.cnt = 0;
> +	for (i = 0; i < internal->nb_tx_queues; i++) {
> +		internal->tx_null_queues[i].tx_pkts.cnt = 0;
> +		internal->tx_null_queues[i].err_pkts.cnt = 0;
> +	}
> +}
> +
> +static void
> +eth_queue_release(void *q)
> +{
> +	struct null_queue *nq;
> +
> +	if (q == NULL)
> +		return;
> +
> +	nq = q;
> +	if (nq->dummy_packet)
> +		rte_free(nq->dummy_packet);
> +}
> +
> +static int
> +eth_link_update(struct rte_eth_dev *dev __rte_unused,
> +		int wait_to_complete __rte_unused) { return 0; }
> +
> +static struct eth_dev_ops ops = {
> +		.dev_start = eth_dev_start,
> +		.dev_stop = eth_dev_stop,
> +		.dev_configure = eth_dev_configure,
> +		.dev_infos_get = eth_dev_info,
> +		.rx_queue_setup = eth_rx_queue_setup,
> +		.tx_queue_setup = eth_tx_queue_setup,
> +		.rx_queue_release = eth_queue_release,
> +		.tx_queue_release = eth_queue_release,
> +		.link_update = eth_link_update,
> +		.stats_get = eth_stats_get,
> +		.stats_reset = eth_stats_reset,
> +};
> +
> +static int
> +eth_dev_null_create(const char *name __rte_unused,
> +		const unsigned numa_node,
> +		unsigned packet_size,
> +		unsigned packet_copy)
> +{
> +	const unsigned nb_rx_queues = 1;
> +	const unsigned nb_tx_queues = 1;
> +	struct rte_eth_dev_data *data = NULL;
> +	struct rte_pci_device *pci_dev = NULL;
> +	struct pmd_internals *internals = NULL;
> +	struct rte_eth_dev *eth_dev = NULL;
> +
> +	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
> +			numa_node);
> +
> +	/* now do all data allocation - for eth_dev structure, dummy pci driver
> +	 * and internal (private) data
> +	 */
> +	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
> +	if (data == NULL)
> +		goto error;
> +
> +	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
> +	if (pci_dev == NULL)
> +		goto error;
> +
> +	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
> +	if (internals == NULL)
> +		goto error;
> +
> +	/* reserve an ethdev entry */
> +	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
> +	if (eth_dev == NULL)
> +		goto error;
> +
> +	/* now put it all together
> +	 * - store queue data in internals,
> +	 * - store numa_node info in pci_driver
> +	 * - point eth_dev_data to internals and pci_driver
> +	 * - and point eth_dev structure to new eth_dev_data structure
> +	 */
> +	/* NOTE: we'll replace the data element, of originally allocated eth_dev
> +	 * so the nulls are local per-process */
> +
> +	internals->nb_rx_queues = nb_rx_queues;
> +	internals->nb_tx_queues = nb_tx_queues;
> +	internals->packet_size = packet_size;
> +	internals->packet_copy = packet_copy;
> +	internals->numa_node = numa_node;
> +
> +	pci_dev->numa_node = numa_node;
> +
> +	data->dev_private = internals;
> +	data->port_id = eth_dev->data->port_id;
> +	data->nb_rx_queues = (uint16_t)nb_rx_queues;
> +	data->nb_tx_queues = (uint16_t)nb_tx_queues;
> +	data->dev_link = pmd_link;
> +	data->mac_addrs = &eth_addr;
> +
> +	eth_dev->data = data;
> +	eth_dev->dev_ops = &ops;
> +	eth_dev->pci_dev = pci_dev;
> +
> +	/* finally assign rx and tx ops */
> +	if (packet_copy) {
> +		eth_dev->rx_pkt_burst = eth_null_copy_rx;
> +		eth_dev->tx_pkt_burst = eth_null_copy_tx;
> +	} else {
> +		eth_dev->rx_pkt_burst = eth_null_rx;
> +		eth_dev->tx_pkt_burst = eth_null_tx;
> +	}
> +
> +	return 0;
> +
> +error:
> +	if (data)
> +		rte_free(data);
> +	if (pci_dev)
> +		rte_free(pci_dev);
> +	if (internals)
> +		rte_free(internals);
> +	return -1;
> +}
> +
> +static inline int
> +get_packet_size_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	const char *a = value;
> +	unsigned *packet_size = extra_args;

Parameters value and  extra_args should be checked.

> +
> +	*packet_size = (unsigned)strtoul(a, NULL, 0);
> +	if (*packet_size == UINT_MAX)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static inline int
> +get_packet_copy_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	const char *a = value;
> +	unsigned *packet_copy = extra_args;

Parameters value and  extra_args should be checked.

> +
> +	*packet_copy = (unsigned)strtoul(a, NULL, 0);
> +	if (*packet_copy == UINT_MAX)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int
> +rte_pmd_null_devinit(const char *name, const char *params) {
> +	unsigned numa_node;
> +	unsigned packet_size = default_packet_size;
> +	unsigned packet_copy = default_packet_copy;
> +	struct rte_kvargs *kvlist;
> +	int ret;
> +

Input parameters name and params should be checked.

> +	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
> +
> +	numa_node = rte_socket_id();
> +
> +	kvlist = rte_kvargs_parse(params, valid_arguments);
> +	if (kvlist == NULL)
> +		return -1;
> +
> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
> +
> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
> +				&get_packet_size_arg, &packet_size);
> +		if (ret < 0)
> +			return -1;
> +	}
> +
> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
> +
> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
> +				&get_packet_copy_arg, &packet_copy);
> +		if (ret < 0)
> +			return -1;
> +	}
> +
> +	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
> +			"packet copy is %s\n", packet_size,
> +			packet_copy ? "enabled" : "disabled");
> +
> +	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
> +}
> +
> +static struct rte_driver pmd_null_drv = {
> +	.name = "eth_null",
> +	.type = PMD_VDEV,
> +	.init = rte_pmd_null_devinit,
> +};
> +
> +PMD_REGISTER_DRIVER(pmd_null_drv);
> --
> 1.9.1
Regards,

Bernard.

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

* Re: [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function
  2015-02-06  4:38             ` [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-06 11:37               ` Iremonger, Bernard
  0 siblings, 0 replies; 37+ messages in thread
From: Iremonger, Bernard @ 2015-02-06 11:37 UTC (permalink / raw)
  To: Tetsuya Mukawa, dev

Hi Tetsuya,

My comments are inline below.

> -----Original Message-----
> From: Tetsuya Mukawa [mailto:mukawa@igel.co.jp]
> Sent: Friday, February 6, 2015 4:38 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard; Tetsuya Mukawa
> Subject: [PATCH v6 2/2] librte_pmd_null: Support port hotplug function
> 
> This patch adds port hotplug support to null PMD.
> 
> v6:
>  - Fix a paramter of rte_eth_dev_free().
> v4:
> - Fix commit title.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> ---
>  lib/librte_pmd_null/rte_eth_null.c | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
> index c54e90b..6add7ce 100644
> --- a/lib/librte_pmd_null/rte_eth_null.c
> +++ b/lib/librte_pmd_null/rte_eth_null.c
> @@ -292,6 +292,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
>  	}
>  }
> 
> +static struct eth_driver rte_null_pmd = {
> +	.pci_drv = {
> +		.name = "rte_null_pmd",
> +		.drv_flags = RTE_PCI_DRV_DETACHABLE,
> +	},
> +};
> +
>  static void
>  eth_queue_release(void *q)
>  {
> @@ -382,10 +389,12 @@ eth_dev_null_create(const char *name __rte_unused,
>  	data->nb_tx_queues = (uint16_t)nb_tx_queues;
>  	data->dev_link = pmd_link;
>  	data->mac_addrs = &eth_addr;
> +	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
> 
>  	eth_dev->data = data;
>  	eth_dev->dev_ops = &ops;
>  	eth_dev->pci_dev = pci_dev;
> +	eth_dev->driver = &rte_null_pmd;
> 
>  	/* finally assign rx and tx ops */
>  	if (packet_copy) {
> @@ -476,10 +485,33 @@ rte_pmd_null_devinit(const char *name, const char *params)
>  	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);  }
> 
> +static int
> +rte_pmd_null_devuninit(const char *name, const char *params
> +__rte_unused) {
> +	struct rte_eth_dev *eth_dev = NULL;

Input parameter name should be checked.

> +
> +	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
> +			rte_socket_id());
> +
> +	/* reserve an ethdev entry */
> +	eth_dev = rte_eth_dev_allocated(name);
> +	if (eth_dev == NULL)
> +		return -1;
> +
> +	rte_free(eth_dev->data->dev_private);
> +	rte_free(eth_dev->data);
> +	rte_free(eth_dev->pci_dev);
> +
> +	rte_eth_dev_free(eth_dev);
> +
> +	return 0;
> +}
> +
>  static struct rte_driver pmd_null_drv = {
>  	.name = "eth_null",
>  	.type = PMD_VDEV,
>  	.init = rte_pmd_null_devinit,
> +	.uninit = rte_pmd_null_devuninit,
>  };
> 
>  PMD_REGISTER_DRIVER(pmd_null_drv);
> --
> 1.9.1

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

* Re: [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD
  2015-02-06 11:32             ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Iremonger, Bernard
@ 2015-02-09  8:54               ` Tetsuya Mukawa
  0 siblings, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-09  8:54 UTC (permalink / raw)
  To: Iremonger, Bernard, dev

On 2015/02/06 20:32, Iremonger, Bernard wrote:
> Hi Tetsuya,
>
> My comments are in line below.
>
>> -----Original Message-----
>> From: Tetsuya Mukawa [mailto:mukawa@igel.co.jp]
>> Sent: Friday, February 6, 2015 4:38 AM
>> To: dev@dpdk.org
>> Cc: Iremonger, Bernard; Tetsuya Mukawa
>> Subject: [PATCH v6 1/2] librte_pmd_null: Add null PMD
>>
>> 'null PMD' is a driver of the virtual device particulary designed to measure performance of DPDK
>> PMDs. When an application call rx, null PMD just allocates mbufs and returns those. Also tx, the PMD
>> just frees mbufs.
>>
>> The PMD has following options.
>> - size: specify packe size allocated by RX. Default packet size is 64.
>> - copy: specify 1 or 0 to enable or disable copy while RX and TX.
>> 	Default value is 0(disbaled).
>> 	This option is used for emulating more realistic data transfer.
>> 	Copy size is equal to packet size.
>>
>> To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then compile the PMD as
>> shared library. The library can be linked using '-d'
>> option when an application invokes.
>>
>> Here is an example.
>> $ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
>> 	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx
>>
>> If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to specify more libraries
>> using '-d' option.
>>
>> v4:
>>  - Fix memory leak.
>>    (Thanks to Iremonger, Bernard)
>>
>> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
>> ---
>>  config/common_bsdapp               |   5 +
>>  config/common_linuxapp             |   5 +
>>  lib/Makefile                       |   1 +
>>  lib/librte_pmd_null/Makefile       |  58 +++++
>>  lib/librte_pmd_null/rte_eth_null.c | 485 +++++++++++++++++++++++++++++++++++++
>>  5 files changed, 554 insertions(+)
>>  create mode 100644 lib/librte_pmd_null/Makefile  create mode 100644
>> lib/librte_pmd_null/rte_eth_null.c
>>
>> diff --git a/config/common_bsdapp b/config/common_bsdapp index 9177db1..fa849be 100644
>> --- a/config/common_bsdapp
>> +++ b/config/common_bsdapp
>> @@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y  CONFIG_RTE_LIBRTE_PMD_BOND=y
>>
>>  #
>> +# Compile null PMD
>> +#
>> +CONFIG_RTE_LIBRTE_PMD_NULL=y
>> +
>> +#
>>  # Do prefetch of packet data within PMD driver receive function  #
>> CONFIG_RTE_PMD_PACKET_PREFETCH=y diff --git a/config/common_linuxapp
>> b/config/common_linuxapp index 27d05be..456fbfe 100644
>> --- a/config/common_linuxapp
>> +++ b/config/common_linuxapp
>> @@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
>> CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
>>
>>  #
>> +# Compile null PMD
>> +#
>> +CONFIG_RTE_LIBRTE_PMD_NULL=y
>> +
>> +#
>>  # Do prefetch of packet data within PMD driver receive function  #
>> CONFIG_RTE_PMD_PACKET_PREFETCH=y diff --git a/lib/Makefile b/lib/Makefile index
>> 0ffc982..d246c53 100644
>> --- a/lib/Makefile
>> +++ b/lib/Makefile
>> @@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
>>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
>>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
>>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
>> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
>>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
>>  DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
>>  DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl diff --git a/lib/librte_pmd_null/Makefile
>> b/lib/librte_pmd_null/Makefile new file mode 100644 index 0000000..0ec4db9
>> --- /dev/null
>> +++ b/lib/librte_pmd_null/Makefile
>> @@ -0,0 +1,58 @@
>> +#   BSD LICENSE
>> +#
>> +#   Copyright (C) IGEL Co.,Ltd.
>> +#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
>> +
>> +#
>> +# library name
>> +#
>> +LIB = librte_pmd_null.a
>> +
>> +CFLAGS += -O3
>> +CFLAGS += $(WERROR_FLAGS)
>> +
>> +#
>> +# all source are stored in SRCS-y
>> +#
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
>> +
>> +#
>> +# Export include files
>> +#
>> +SYMLINK-y-include +=
>> +
>> +# this lib depends upon:
>> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
>> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
>> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
>> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
>> +
>> +include $(RTE_SDK)/mk/rte.lib.mk
>> diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
>> new file mode 100644
>> index 0000000..c54e90b
>> --- /dev/null
>> +++ b/lib/librte_pmd_null/rte_eth_null.c
>> @@ -0,0 +1,485 @@
>> +/*-
>> + *   BSD LICENSE
>> + *
>> + *   Copyright (C) IGEL Co.,Ltd.
>> + *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
>> +#include <rte_ethdev.h>
>> +#include <rte_malloc.h>
>> +#include <rte_memcpy.h>
>> +#include <rte_dev.h>
>> +#include <rte_kvargs.h>
>> +
>> +#define ETH_NULL_PACKET_SIZE_ARG	"size"
>> +#define ETH_NULL_PACKET_COPY_ARG	"copy"
>> +
>> +static unsigned default_packet_size = 64; static unsigned
>> +default_packet_copy;
>> +
>> +static const char const *valid_arguments[] = {
>> +	ETH_NULL_PACKET_SIZE_ARG,
>> +	ETH_NULL_PACKET_COPY_ARG,
>> +	NULL
>> +};
>> +
>> +struct pmd_internals;
>> +
>> +struct null_queue {
>> +	struct pmd_internals *internals;
>> +
>> +	struct rte_mempool *mb_pool;
>> +	struct rte_mbuf *dummy_packet;
>> +
>> +	rte_atomic64_t rx_pkts;
>> +	rte_atomic64_t tx_pkts;
>> +	rte_atomic64_t err_pkts;
>> +};
>> +
>> +struct pmd_internals {
>> +	unsigned packet_size;
>> +	unsigned packet_copy;
>> +	unsigned numa_node;
>> +
>> +	unsigned nb_rx_queues;
>> +	unsigned nb_tx_queues;
>> +
>> +	struct null_queue rx_null_queues[1];
>> +	struct null_queue tx_null_queues[1];
>> +};
>> +
>> +
>> +static struct ether_addr eth_addr = { .addr_bytes = {0} }; static const
>> +char *drivername = "Null PMD"; static struct rte_eth_link pmd_link = {
>> +	.link_speed = 10000,
>> +	.link_duplex = ETH_LINK_FULL_DUPLEX,
>> +	.link_status = 0
>> +};
>> +
>> +static uint16_t
>> +eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
>> +	int i;
>> +	struct null_queue *h = q;
>> +	unsigned packet_size = h->internals->packet_size;
>> +
>> +	for (i = 0; i < nb_bufs; i++) {
>> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
>> +		if (!bufs[i])
>> +			break;
> Should the code return an error here rather than break?

Hi Bernard,

I appreciate for your comments.

I guess it's not an error.
The function should return the number of packets actually allocated.

>
>> +		bufs[i]->data_len = (uint16_t)packet_size;
>> +		bufs[i]->pkt_len = packet_size;
>> +		bufs[i]->nb_segs = 1;
>> +		bufs[i]->next = NULL;
>> +	}
>> +
>> +	rte_atomic64_add(&(h->rx_pkts), i);
>> +
>> +	return i;
>> +}
>> +
>> +static uint16_t
>> +eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
>> +	int i;
>> +	struct null_queue *h = q;
>> +	unsigned packet_size = h->internals->packet_size;
>> +
>> +	for (i = 0; i < nb_bufs; i++) {
>> +		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
>> +		if (!bufs[i])
>> +			break;
> Should the code return an error here rather than break?

Also, the function should return the number of packets actually sent.

>> +		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
>> +					packet_size);
>> +		bufs[i]->data_len = (uint16_t)packet_size;
>> +		bufs[i]->pkt_len = packet_size;
>> +		bufs[i]->nb_segs = 1;
>> +		bufs[i]->next = NULL;
>> +	}
>> +
>> +	rte_atomic64_add(&(h->rx_pkts), i);
>> +
>> +	return i;
>> +}
>> +
>> +static uint16_t
>> +eth_null_tx(void *q, struct rte_mbuf **bufs __rte_unused, uint16_t
>> +nb_bufs) {
>> +	int i;
>> +	struct null_queue *h = q;
> Input parameters q and bufs should be checked.

Thanks, I will fix these suggestions.

Regards,
Tetsuya

>> +
>> +	for (i = 0; i < nb_bufs; i++)
>> +		rte_pktmbuf_free(bufs[i]);
>> +
>> +	rte_atomic64_add(&(h->tx_pkts), i);
>> +
>> +	return i;
>> +}
>> +
>> +static uint16_t
>> +eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) {
>> +	int i;
>> +	struct null_queue *h = q;
>> +	unsigned packet_size = h->internals->packet_size;
> Input parameters q and bufs should be checked.
>
>> +
>> +	for (i = 0; i < nb_bufs; i++) {
>> +		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
>> +					packet_size);
>> +		rte_pktmbuf_free(bufs[i]);
>> +	}
>> +
>> +	rte_atomic64_add(&(h->tx_pkts), i);
>> +
>> +	return i;
>> +}
>> +
>> +static int
>> +eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
>> +
>> +static int
>> +eth_dev_start(struct rte_eth_dev *dev)
>> +{
> Input parameter dev should be checked.
>
>> +	dev->data->dev_link.link_status = 1;
>> +	return 0;
>> +}
>> +
>> +static void
>> +eth_dev_stop(struct rte_eth_dev *dev)
>> +{
> Input parameter dev should be checked.
>
>> +	dev->data->dev_link.link_status = 0;
>> +}
>> +
>> +static int
>> +eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
>> +		uint16_t nb_rx_desc __rte_unused,
>> +		unsigned int socket_id __rte_unused,
>> +		const struct rte_eth_rxconf *rx_conf __rte_unused,
>> +		struct rte_mempool *mb_pool __rte_unused) {
>> +	struct rte_mbuf *dummy_packet;
>> +	struct pmd_internals *internals = dev->data->dev_private;
>> +	unsigned packet_size = internals->packet_size;
>> +
> Input parameter dev should be checked.
>
>> +	if (rx_queue_id != 0)
>> +			return -ENODEV;
>> +
>> +	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
>> +	dev->data->rx_queues[rx_queue_id] =
>> +		&internals->rx_null_queues[rx_queue_id];
>> +	dummy_packet = rte_zmalloc_socket(NULL,
>> +			packet_size, 0, internals->numa_node);
>> +	if (dummy_packet == NULL)
>> +		return -ENOMEM;
>> +
>> +	internals->rx_null_queues[rx_queue_id].internals = internals;
>> +	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
>> +		uint16_t nb_tx_desc __rte_unused,
>> +		unsigned int socket_id __rte_unused,
>> +		const struct rte_eth_txconf *tx_conf __rte_unused) {
>> +	struct rte_mbuf *dummy_packet;
>> +	struct pmd_internals *internals = dev->data->dev_private;
>> +	unsigned packet_size = internals->packet_size;
>> +
> Input parameter dev should be checked.
>
>> +	if (tx_queue_id != 0)
>> +			return -ENODEV;
>> +
>> +	dev->data->tx_queues[tx_queue_id] =
>> +		&internals->tx_null_queues[tx_queue_id];
>> +	dummy_packet = rte_zmalloc_socket(NULL,
>> +			packet_size, 0, internals->numa_node);
>> +	if (dummy_packet == NULL)
>> +		return -ENOMEM;
>> +
>> +	internals->tx_null_queues[tx_queue_id].internals = internals;
>> +	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static void
>> +eth_dev_info(struct rte_eth_dev *dev,
>> +		struct rte_eth_dev_info *dev_info)
>> +{
>> +	struct pmd_internals *internals = dev->data->dev_private;
> Input parameters dev and dev_info should be checked.
>
>> +
>> +	dev_info->driver_name = drivername;
>> +	dev_info->max_mac_addrs = 1;
>> +	dev_info->max_rx_pktlen = (uint32_t)-1;
>> +	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
>> +	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
>> +	dev_info->min_rx_bufsize = 0;
>> +	dev_info->pci_dev = NULL;
>> +}
>> +
>> +static void
>> +eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
>> +{
>> +	unsigned i;
>> +	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
>> +	const struct pmd_internals *internal = dev->data->dev_private;
> Input parameters dev and igb_stats should be checked.
>
>> +
>> +	memset(igb_stats, 0, sizeof(*igb_stats));
>> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
>> +			i < internal->nb_rx_queues; i++) {
>> +		igb_stats->q_ipackets[i] =
>> +			internal->rx_null_queues[i].rx_pkts.cnt;
>> +		rx_total += igb_stats->q_ipackets[i];
>> +	}
>> +
>> +	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
>> +			i < internal->nb_tx_queues; i++) {
>> +		igb_stats->q_opackets[i] =
>> +			internal->tx_null_queues[i].tx_pkts.cnt;
>> +		igb_stats->q_errors[i] =
>> +			internal->tx_null_queues[i].err_pkts.cnt;
>> +		tx_total += igb_stats->q_opackets[i];
>> +		tx_err_total += igb_stats->q_errors[i];
>> +	}
>> +
>> +	igb_stats->ipackets = rx_total;
>> +	igb_stats->opackets = tx_total;
>> +	igb_stats->oerrors = tx_err_total;
>> +}
>> +
>> +static void
>> +eth_stats_reset(struct rte_eth_dev *dev) {
>> +	unsigned i;
>> +	struct pmd_internals *internal = dev->data->dev_private;
> Input parameter dev should be checked.
>
>> +
>> +	for (i = 0; i < internal->nb_rx_queues; i++)
>> +		internal->rx_null_queues[i].rx_pkts.cnt = 0;
>> +	for (i = 0; i < internal->nb_tx_queues; i++) {
>> +		internal->tx_null_queues[i].tx_pkts.cnt = 0;
>> +		internal->tx_null_queues[i].err_pkts.cnt = 0;
>> +	}
>> +}
>> +
>> +static void
>> +eth_queue_release(void *q)
>> +{
>> +	struct null_queue *nq;
>> +
>> +	if (q == NULL)
>> +		return;
>> +
>> +	nq = q;
>> +	if (nq->dummy_packet)
>> +		rte_free(nq->dummy_packet);
>> +}
>> +
>> +static int
>> +eth_link_update(struct rte_eth_dev *dev __rte_unused,
>> +		int wait_to_complete __rte_unused) { return 0; }
>> +
>> +static struct eth_dev_ops ops = {
>> +		.dev_start = eth_dev_start,
>> +		.dev_stop = eth_dev_stop,
>> +		.dev_configure = eth_dev_configure,
>> +		.dev_infos_get = eth_dev_info,
>> +		.rx_queue_setup = eth_rx_queue_setup,
>> +		.tx_queue_setup = eth_tx_queue_setup,
>> +		.rx_queue_release = eth_queue_release,
>> +		.tx_queue_release = eth_queue_release,
>> +		.link_update = eth_link_update,
>> +		.stats_get = eth_stats_get,
>> +		.stats_reset = eth_stats_reset,
>> +};
>> +
>> +static int
>> +eth_dev_null_create(const char *name __rte_unused,
>> +		const unsigned numa_node,
>> +		unsigned packet_size,
>> +		unsigned packet_copy)
>> +{
>> +	const unsigned nb_rx_queues = 1;
>> +	const unsigned nb_tx_queues = 1;
>> +	struct rte_eth_dev_data *data = NULL;
>> +	struct rte_pci_device *pci_dev = NULL;
>> +	struct pmd_internals *internals = NULL;
>> +	struct rte_eth_dev *eth_dev = NULL;
>> +
>> +	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
>> +			numa_node);
>> +
>> +	/* now do all data allocation - for eth_dev structure, dummy pci driver
>> +	 * and internal (private) data
>> +	 */
>> +	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
>> +	if (data == NULL)
>> +		goto error;
>> +
>> +	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
>> +	if (pci_dev == NULL)
>> +		goto error;
>> +
>> +	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
>> +	if (internals == NULL)
>> +		goto error;
>> +
>> +	/* reserve an ethdev entry */
>> +	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
>> +	if (eth_dev == NULL)
>> +		goto error;
>> +
>> +	/* now put it all together
>> +	 * - store queue data in internals,
>> +	 * - store numa_node info in pci_driver
>> +	 * - point eth_dev_data to internals and pci_driver
>> +	 * - and point eth_dev structure to new eth_dev_data structure
>> +	 */
>> +	/* NOTE: we'll replace the data element, of originally allocated eth_dev
>> +	 * so the nulls are local per-process */
>> +
>> +	internals->nb_rx_queues = nb_rx_queues;
>> +	internals->nb_tx_queues = nb_tx_queues;
>> +	internals->packet_size = packet_size;
>> +	internals->packet_copy = packet_copy;
>> +	internals->numa_node = numa_node;
>> +
>> +	pci_dev->numa_node = numa_node;
>> +
>> +	data->dev_private = internals;
>> +	data->port_id = eth_dev->data->port_id;
>> +	data->nb_rx_queues = (uint16_t)nb_rx_queues;
>> +	data->nb_tx_queues = (uint16_t)nb_tx_queues;
>> +	data->dev_link = pmd_link;
>> +	data->mac_addrs = &eth_addr;
>> +
>> +	eth_dev->data = data;
>> +	eth_dev->dev_ops = &ops;
>> +	eth_dev->pci_dev = pci_dev;
>> +
>> +	/* finally assign rx and tx ops */
>> +	if (packet_copy) {
>> +		eth_dev->rx_pkt_burst = eth_null_copy_rx;
>> +		eth_dev->tx_pkt_burst = eth_null_copy_tx;
>> +	} else {
>> +		eth_dev->rx_pkt_burst = eth_null_rx;
>> +		eth_dev->tx_pkt_burst = eth_null_tx;
>> +	}
>> +
>> +	return 0;
>> +
>> +error:
>> +	if (data)
>> +		rte_free(data);
>> +	if (pci_dev)
>> +		rte_free(pci_dev);
>> +	if (internals)
>> +		rte_free(internals);
>> +	return -1;
>> +}
>> +
>> +static inline int
>> +get_packet_size_arg(const char *key __rte_unused,
>> +		const char *value, void *extra_args)
>> +{
>> +	const char *a = value;
>> +	unsigned *packet_size = extra_args;
> Parameters value and  extra_args should be checked.
>
>> +
>> +	*packet_size = (unsigned)strtoul(a, NULL, 0);
>> +	if (*packet_size == UINT_MAX)
>> +		return -1;
>> +
>> +	return 0;
>> +}
>> +
>> +static inline int
>> +get_packet_copy_arg(const char *key __rte_unused,
>> +		const char *value, void *extra_args)
>> +{
>> +	const char *a = value;
>> +	unsigned *packet_copy = extra_args;
> Parameters value and  extra_args should be checked.
>
>> +
>> +	*packet_copy = (unsigned)strtoul(a, NULL, 0);
>> +	if (*packet_copy == UINT_MAX)
>> +		return -1;
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +rte_pmd_null_devinit(const char *name, const char *params) {
>> +	unsigned numa_node;
>> +	unsigned packet_size = default_packet_size;
>> +	unsigned packet_copy = default_packet_copy;
>> +	struct rte_kvargs *kvlist;
>> +	int ret;
>> +
> Input parameters name and params should be checked.
>
>> +	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
>> +
>> +	numa_node = rte_socket_id();
>> +
>> +	kvlist = rte_kvargs_parse(params, valid_arguments);
>> +	if (kvlist == NULL)
>> +		return -1;
>> +
>> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
>> +
>> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
>> +				&get_packet_size_arg, &packet_size);
>> +		if (ret < 0)
>> +			return -1;
>> +	}
>> +
>> +	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
>> +
>> +		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
>> +				&get_packet_copy_arg, &packet_copy);
>> +		if (ret < 0)
>> +			return -1;
>> +	}
>> +
>> +	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
>> +			"packet copy is %s\n", packet_size,
>> +			packet_copy ? "enabled" : "disabled");
>> +
>> +	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
>> +}
>> +
>> +static struct rte_driver pmd_null_drv = {
>> +	.name = "eth_null",
>> +	.type = PMD_VDEV,
>> +	.init = rte_pmd_null_devinit,
>> +};
>> +
>> +PMD_REGISTER_DRIVER(pmd_null_drv);
>> --
>> 1.9.1
> Regards,
>
> Bernard.
>

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

* [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD
  2015-02-06  4:38           ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Tetsuya Mukawa
  2015-02-06  4:38             ` [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  2015-02-06 11:32             ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Iremonger, Bernard
@ 2015-02-12  2:44             ` Tetsuya Mukawa
  2015-02-12  2:44               ` [dpdk-dev] [PATCH v7 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2 siblings, 2 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-12  2:44 UTC (permalink / raw)
  To: dev

Null PMD is a driver of the virtual device particularly designed to measure
performance of DPDK PMDs. When an application call rx, Null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disabled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
 - Remove needless "__rte_unused".
v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp               |   5 +
 config/common_linuxapp             |   5 +
 lib/Makefile                       |   1 +
 lib/librte_pmd_null/Makefile       |  58 ++++
 lib/librte_pmd_null/rte_eth_null.c | 541 +++++++++++++++++++++++++++++++++++++
 5 files changed, 610 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 57bacb8..8b4a684 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 81055f8..4ab31e8 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index d617d81..2fc098b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..0ec4db9
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..779db63
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,541 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if ((dev == NULL) || (mb_pool == NULL))
+		return -EINVAL;
+
+	if (rx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (tx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals;
+
+	if ((dev == NULL) || (dev_info == NULL))
+		return;
+
+	internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal;
+
+	if ((dev == NULL) || (igb_stats == NULL))
+		return;
+
+	internal = dev->data->dev_private;
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal;
+
+	if (dev == NULL)
+		return;
+
+	internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if ((name == NULL) || (params == NULL))
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v7 2/2] librte_pmd_null: Support port hotplug function
  2015-02-12  2:44             ` [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
@ 2015-02-12  2:44               ` Tetsuya Mukawa
  2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-12  2:44 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to Null PMD.

v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
v6:
 - Fix a parameter of rte_eth_dev_free().
v4:
 - Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index 779db63..1bc4ef3 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -336,6 +336,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -429,10 +436,12 @@ eth_dev_null_create(const char *name,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -532,10 +541,36 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD
  2015-02-12  2:44             ` [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2015-02-12  2:44               ` [dpdk-dev] [PATCH v7 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-16  4:19               ` Tetsuya Mukawa
  2015-02-16  4:19                 ` [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
                                   ` (2 more replies)
  1 sibling, 3 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-16  4:19 UTC (permalink / raw)
  To: dev

Null PMD is a driver of the virtual device particularly designed to measure
performance of DPDK PMDs. When an application call rx, Null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disabled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v8:
 - Fix Makefile and add version map file.
   (Thanks to Qiu, Michael and Iremonger, Bernard)
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
 - Remove needless "__rte_unused".
v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp                         |   5 +
 config/common_linuxapp                       |   5 +
 lib/Makefile                                 |   1 +
 lib/librte_pmd_null/Makefile                 |  62 +++
 lib/librte_pmd_null/rte_eth_null.c           | 541 +++++++++++++++++++++++++++
 lib/librte_pmd_null/rte_pmd_null_version.map |   4 +
 6 files changed, 618 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c
 create mode 100644 lib/librte_pmd_null/rte_pmd_null_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 57bacb8..8b4a684 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 81055f8..4ab31e8 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -237,6 +237,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index d617d81..2fc098b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..6472015
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_null_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..779db63
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,541 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if ((dev == NULL) || (mb_pool == NULL))
+		return -EINVAL;
+
+	if (rx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (tx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals;
+
+	if ((dev == NULL) || (dev_info == NULL))
+		return;
+
+	internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal;
+
+	if ((dev == NULL) || (igb_stats == NULL))
+		return;
+
+	internal = dev->data->dev_private;
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal;
+
+	if (dev == NULL)
+		return;
+
+	internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if ((name == NULL) || (params == NULL))
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
diff --git a/lib/librte_pmd_null/rte_pmd_null_version.map b/lib/librte_pmd_null/rte_pmd_null_version.map
new file mode 100644
index 0000000..ef35398
--- /dev/null
+++ b/lib/librte_pmd_null/rte_pmd_null_version.map
@@ -0,0 +1,4 @@
+DPDK_2.0 {
+
+	local: *;
+};
-- 
1.9.1

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

* [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function
  2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
@ 2015-02-16  4:19                 ` Tetsuya Mukawa
  2015-02-16 16:38                   ` Iremonger, Bernard
  2015-02-16 16:38                 ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Iremonger, Bernard
  2015-02-19 10:41                 ` [dpdk-dev] [PATCH v9 " Tetsuya Mukawa
  2 siblings, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-16  4:19 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to Null PMD.

v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
v6:
 - Fix a parameter of rte_eth_dev_free().
v4:
 - Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index 779db63..1bc4ef3 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -336,6 +336,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -429,10 +436,12 @@ eth_dev_null_create(const char *name,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -532,10 +541,36 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name, const char *params __rte_unused)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_free(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* Re: [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD
  2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2015-02-16  4:19                 ` [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-16 16:38                 ` Iremonger, Bernard
  2015-02-19 10:41                 ` [dpdk-dev] [PATCH v9 " Tetsuya Mukawa
  2 siblings, 0 replies; 37+ messages in thread
From: Iremonger, Bernard @ 2015-02-16 16:38 UTC (permalink / raw)
  To: Tetsuya Mukawa, dev

> -----Original Message-----
> From: Tetsuya Mukawa [mailto:mukawa@igel.co.jp]
> Sent: Monday, February 16, 2015 4:19 AM
> To: dev@dpdk.org
> Cc: Qiu, Michael; Iremonger, Bernard; Tetsuya Mukawa
> Subject: [PATCH v8 1/2] librte_pmd_null: Add Null PMD
> 
> Null PMD is a driver of the virtual device particularly designed to measure performance of DPDK PMDs.
> When an application call rx, Null PMD just allocates mbufs and returns those. Also tx, the PMD just
> frees mbufs.
> 
> The PMD has following options.
> - size: specify packe size allocated by RX. Default packet size is 64.
> - copy: specify 1 or 0 to enable or disable copy while RX and TX.
> 	Default value is 0(disabled).
> 	This option is used for emulating more realistic data transfer.
> 	Copy size is equal to packet size.
> 
> To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then compile the PMD as
> shared library. The library can be linked using '-d'
> option when an application invokes.
> 
> Here is an example.
> $ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
> 	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx
> 
> If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to specify more libraries
> using '-d' option.
> 
> v8:
>  - Fix Makefile and add version map file.
>    (Thanks to Qiu, Michael and Iremonger, Bernard)
> v7:
>  - Add parameter checkings.
>    (Thanks to Iremonger, Bernard)
>  - Remove needless "__rte_unused".
> v4:
>  - Fix memory leak.
>    (Thanks to Iremonger, Bernard)
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>

Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>

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

* Re: [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function
  2015-02-16  4:19                 ` [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-16 16:38                   ` Iremonger, Bernard
  0 siblings, 0 replies; 37+ messages in thread
From: Iremonger, Bernard @ 2015-02-16 16:38 UTC (permalink / raw)
  To: Tetsuya Mukawa, dev

> -----Original Message-----
> From: Tetsuya Mukawa [mailto:mukawa@igel.co.jp]
> Sent: Monday, February 16, 2015 4:19 AM
> To: dev@dpdk.org
> Cc: Qiu, Michael; Iremonger, Bernard; Tetsuya Mukawa
> Subject: [PATCH v8 2/2] librte_pmd_null: Support port hotplug function
> 
> This patch adds port hotplug support to Null PMD.
> 
> v7:
>  - Add parameter checkings.
>    (Thanks to Iremonger, Bernard)
> v6:
>  - Fix a parameter of rte_eth_dev_free().
> v4:
>  - Fix commit title.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>

Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>

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

* [dpdk-dev] [PATCH v9 1/2] librte_pmd_null: Add Null PMD
  2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2015-02-16  4:19                 ` [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  2015-02-16 16:38                 ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Iremonger, Bernard
@ 2015-02-19 10:41                 ` Tetsuya Mukawa
  2015-02-19 10:41                   ` [dpdk-dev] [PATCH v9 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  2015-02-20  6:41                   ` [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2 siblings, 2 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-19 10:41 UTC (permalink / raw)
  To: dev

Null PMD is a driver of the virtual device particularly designed to measure
performance of DPDK PMDs. When an application call rx, Null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disabled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v8:
 - Fix Makefile and add version map file.
   (Thanks to Qiu, Michael and Iremonger, Bernard)
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
 - Remove needless "__rte_unused".
v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp                         |   5 +
 config/common_linuxapp                       |   5 +
 lib/Makefile                                 |   1 +
 lib/librte_pmd_null/Makefile                 |  62 +++
 lib/librte_pmd_null/rte_eth_null.c           | 541 +++++++++++++++++++++++++++
 lib/librte_pmd_null/rte_pmd_null_version.map |   4 +
 6 files changed, 618 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c
 create mode 100644 lib/librte_pmd_null/rte_pmd_null_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index e9d07e4..d019edb 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -241,6 +241,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 5f7fe28..ed749f2 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -248,6 +248,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 6575a4e..5fcbb3c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -54,6 +54,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..6472015
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_null_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..779db63
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,541 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if ((dev == NULL) || (mb_pool == NULL))
+		return -EINVAL;
+
+	if (rx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (tx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals;
+
+	if ((dev == NULL) || (dev_info == NULL))
+		return;
+
+	internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal;
+
+	if ((dev == NULL) || (igb_stats == NULL))
+		return;
+
+	internal = dev->data->dev_private;
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal;
+
+	if (dev == NULL)
+		return;
+
+	internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if ((name == NULL) || (params == NULL))
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+				&get_packet_size_arg, &packet_size);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+		ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+				&get_packet_copy_arg, &packet_copy);
+		if (ret < 0)
+			return -1;
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
diff --git a/lib/librte_pmd_null/rte_pmd_null_version.map b/lib/librte_pmd_null/rte_pmd_null_version.map
new file mode 100644
index 0000000..ef35398
--- /dev/null
+++ b/lib/librte_pmd_null/rte_pmd_null_version.map
@@ -0,0 +1,4 @@
+DPDK_2.0 {
+
+	local: *;
+};
-- 
1.9.1

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

* [dpdk-dev] [PATCH v9 2/2] librte_pmd_null: Support port hotplug function
  2015-02-19 10:41                 ` [dpdk-dev] [PATCH v9 " Tetsuya Mukawa
@ 2015-02-19 10:41                   ` Tetsuya Mukawa
  2015-02-20  6:41                   ` [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-19 10:41 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to Null PMD.

v9:
 - Use rte_eth_dev_release_port() instead of rte_eth_dev_free().
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
v6:
 - Fix a parameter of rte_eth_dev_free().
v4:
 - Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index 779db63..5cf40f4 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -336,6 +336,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -429,10 +436,12 @@ eth_dev_null_create(const char *name,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -532,10 +541,36 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_release_port(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD
  2015-02-19 10:41                 ` [dpdk-dev] [PATCH v9 " Tetsuya Mukawa
  2015-02-19 10:41                   ` [dpdk-dev] [PATCH v9 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-20  6:41                   ` Tetsuya Mukawa
  2015-02-20  6:41                     ` [dpdk-dev] [PATCH v10 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  2015-02-23  5:12                     ` [dpdk-dev] [PATCH v11 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  1 sibling, 2 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-20  6:41 UTC (permalink / raw)
  To: dev

Null PMD is a driver of the virtual device particularly designed to measure
performance of DPDK PMDs. When an application call rx, Null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disabled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v10:
- Fix driver initilization code not to return error when param is NULL.
v8:
 - Fix Makefile and add version map file.
   (Thanks to Qiu, Michael and Iremonger, Bernard)
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
 - Remove needless "__rte_unused".
v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp                         |   5 +
 config/common_linuxapp                       |   5 +
 lib/Makefile                                 |   1 +
 lib/librte_pmd_null/Makefile                 |  62 +++
 lib/librte_pmd_null/rte_eth_null.c           | 543 +++++++++++++++++++++++++++
 lib/librte_pmd_null/rte_pmd_null_version.map |   4 +
 6 files changed, 620 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c
 create mode 100644 lib/librte_pmd_null/rte_pmd_null_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index e9d07e4..d019edb 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -241,6 +241,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=y
 CONFIG_RTE_LIBRTE_PMD_BOND=y
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 5f7fe28..ed749f2 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -248,6 +248,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 6575a4e..5fcbb3c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -54,6 +54,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..6472015
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_null_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..7c6e583
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,543 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	if ((q ==NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if ((dev == NULL) || (mb_pool == NULL))
+		return -EINVAL;
+
+	if (rx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (tx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals;
+
+	if ((dev == NULL) || (dev_info == NULL))
+		return;
+
+	internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal;
+
+	if ((dev == NULL) || (igb_stats == NULL))
+		return;
+
+	internal = dev->data->dev_private;
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal;
+
+	if (dev == NULL)
+		return;
+
+	internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	if (params != NULL) {
+		kvlist = rte_kvargs_parse(params, valid_arguments);
+		if (kvlist == NULL)
+			return -1;
+
+		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+			ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_SIZE_ARG,
+					&get_packet_size_arg, &packet_size);
+			if (ret < 0)
+				return -1;
+		}
+
+		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+			ret = rte_kvargs_process(kvlist, ETH_NULL_PACKET_COPY_ARG,
+					&get_packet_copy_arg, &packet_copy);
+			if (ret < 0)
+				return -1;
+		}
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
diff --git a/lib/librte_pmd_null/rte_pmd_null_version.map b/lib/librte_pmd_null/rte_pmd_null_version.map
new file mode 100644
index 0000000..ef35398
--- /dev/null
+++ b/lib/librte_pmd_null/rte_pmd_null_version.map
@@ -0,0 +1,4 @@
+DPDK_2.0 {
+
+	local: *;
+};
-- 
1.9.1

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

* [dpdk-dev] [PATCH v10 2/2] librte_pmd_null: Support port hotplug function
  2015-02-20  6:41                   ` [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
@ 2015-02-20  6:41                     ` Tetsuya Mukawa
  2015-02-23  5:12                     ` [dpdk-dev] [PATCH v11 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-20  6:41 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to Null PMD.

v9:
 - Use rte_eth_dev_release_port() instead of rte_eth_dev_free().
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
v6:
 - Fix a parameter of rte_eth_dev_free().
v4:
 - Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index 7c6e583..94961bd 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -336,6 +336,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -429,10 +436,12 @@ eth_dev_null_create(const char *name,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -534,10 +543,36 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_release_port(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* [dpdk-dev] [PATCH v11 1/2] librte_pmd_null: Add Null PMD
  2015-02-20  6:41                   ` [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
  2015-02-20  6:41                     ` [dpdk-dev] [PATCH v10 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-23  5:12                     ` Tetsuya Mukawa
  2015-02-23  5:12                       ` [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
  1 sibling, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-23  5:12 UTC (permalink / raw)
  To: dev

Null PMD is a driver of the virtual device particularly designed to measure
performance of DPDK PMDs. When an application call rx, Null PMD just allocates
mbufs and returns those. Also tx, the PMD just frees mbufs.

The PMD has following options.
- size: specify packe size allocated by RX. Default packet size is 64.
- copy: specify 1 or 0 to enable or disable copy while RX and TX.
	Default value is 0(disabled).
	This option is used for emulating more realistic data transfer.
	Copy size is equal to packet size.

To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then
compile the PMD as shared library. The library can be linked using '-d'
option when an application invokes.

Here is an example.
$ sudo ./testpmd -c f -n 4 -d librte_pmd_null.so \
	--vdev 'eth_null0' --vdev 'eth_null1' -- -i --no-flush-rx

If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to
specify more libraries using '-d' option.

v11:
- Fix warning of checkpatch.pl.
v10:
- Fix driver initilization code not to return error when param is NULL.
v8:
 - Fix Makefile and add version map file.
   (Thanks to Qiu, Michael and Iremonger, Bernard)
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
 - Remove needless "__rte_unused".
v4:
 - Fix memory leak.
   (Thanks to Iremonger, Bernard)

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 config/common_bsdapp                         |   5 +
 config/common_linuxapp                       |   5 +
 lib/Makefile                                 |   1 +
 lib/librte_pmd_null/Makefile                 |  62 +++
 lib/librte_pmd_null/rte_eth_null.c           | 545 +++++++++++++++++++++++++++
 lib/librte_pmd_null/rte_pmd_null_version.map |   4 +
 6 files changed, 622 insertions(+)
 create mode 100644 lib/librte_pmd_null/Makefile
 create mode 100644 lib/librte_pmd_null/rte_eth_null.c
 create mode 100644 lib/librte_pmd_null/rte_pmd_null_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index c24f687..50189d6 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -243,6 +243,11 @@ CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
 CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index d66b008..9ddd056 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -250,6 +250,11 @@ CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
+# Compile null PMD
+#
+CONFIG_RTE_LIBRTE_PMD_NULL=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 6575a4e..5fcbb3c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -54,6 +54,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += librte_pmd_null
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
diff --git a/lib/librte_pmd_null/Makefile b/lib/librte_pmd_null/Makefile
new file mode 100644
index 0000000..6472015
--- /dev/null
+++ b/lib/librte_pmd_null/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (C) IGEL Co.,Ltd.
+#   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 IGEL Co.,Ltd. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_null.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_null_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += rte_eth_null.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
new file mode 100644
index 0000000..aaa0839
--- /dev/null
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -0,0 +1,545 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) IGEL Co.,Ltd.
+ *   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 IGEL Co.,Ltd. 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 <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+
+#define ETH_NULL_PACKET_SIZE_ARG	"size"
+#define ETH_NULL_PACKET_COPY_ARG	"copy"
+
+static unsigned default_packet_size = 64;
+static unsigned default_packet_copy;
+
+static const char const *valid_arguments[] = {
+	ETH_NULL_PACKET_SIZE_ARG,
+	ETH_NULL_PACKET_COPY_ARG,
+	NULL
+};
+
+struct pmd_internals;
+
+struct null_queue {
+	struct pmd_internals *internals;
+
+	struct rte_mempool *mb_pool;
+	struct rte_mbuf *dummy_packet;
+
+	rte_atomic64_t rx_pkts;
+	rte_atomic64_t tx_pkts;
+	rte_atomic64_t err_pkts;
+};
+
+struct pmd_internals {
+	unsigned packet_size;
+	unsigned packet_copy;
+	unsigned numa_node;
+
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+
+	struct null_queue rx_null_queues[1];
+	struct null_queue tx_null_queues[1];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Null PMD";
+static struct rte_eth_link pmd_link = {
+	.link_speed = 10000,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = 0
+};
+
+static uint16_t
+eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q == NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size;
+
+	if ((q == NULL) || (bufs == NULL))
+		return 0;
+
+	packet_size = h->internals->packet_size;
+	for (i = 0; i < nb_bufs; i++) {
+		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
+		if (!bufs[i])
+			break;
+		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
+					packet_size);
+		bufs[i]->data_len = (uint16_t)packet_size;
+		bufs[i]->pkt_len = packet_size;
+		bufs[i]->nb_segs = 1;
+		bufs[i]->next = NULL;
+	}
+
+	rte_atomic64_add(&(h->rx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+
+	if ((q == NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++)
+		rte_pktmbuf_free(bufs[i]);
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static uint16_t
+eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	int i;
+	struct null_queue *h = q;
+	unsigned packet_size = h->internals->packet_size;
+
+	if ((q == NULL) || (bufs == NULL))
+		return 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
+					packet_size);
+		rte_pktmbuf_free(bufs[i]);
+	}
+
+	rte_atomic64_add(&(h->tx_pkts), i);
+
+	return i;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	if (dev == NULL)
+		return;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if ((dev == NULL) || (mb_pool == NULL))
+		return -EINVAL;
+
+	if (rx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] =
+		&internals->rx_null_queues[rx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->rx_null_queues[rx_queue_id].internals = internals;
+	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct rte_mbuf *dummy_packet;
+	struct pmd_internals *internals;
+	unsigned packet_size;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (tx_queue_id != 0)
+		return -ENODEV;
+
+	internals = dev->data->dev_private;
+	packet_size = internals->packet_size;
+
+	dev->data->tx_queues[tx_queue_id] =
+		&internals->tx_null_queues[tx_queue_id];
+	dummy_packet = rte_zmalloc_socket(NULL,
+			packet_size, 0, internals->numa_node);
+	if (dummy_packet == NULL)
+		return -ENOMEM;
+
+	internals->tx_null_queues[tx_queue_id].internals = internals;
+	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
+
+	return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals;
+
+	if ((dev == NULL) || (dev_info == NULL))
+		return;
+
+	internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	const struct pmd_internals *internal;
+
+	if ((dev == NULL) || (igb_stats == NULL))
+		return;
+
+	internal = dev->data->dev_private;
+	memset(igb_stats, 0, sizeof(*igb_stats));
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] =
+			internal->rx_null_queues[i].rx_pkts.cnt;
+		rx_total += igb_stats->q_ipackets[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] =
+			internal->tx_null_queues[i].tx_pkts.cnt;
+		igb_stats->q_errors[i] =
+			internal->tx_null_queues[i].err_pkts.cnt;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal;
+
+	if (dev == NULL)
+		return;
+
+	internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++)
+		internal->rx_null_queues[i].rx_pkts.cnt = 0;
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_null_queues[i].tx_pkts.cnt = 0;
+		internal->tx_null_queues[i].err_pkts.cnt = 0;
+	}
+}
+
+static void
+eth_queue_release(void *q)
+{
+	struct null_queue *nq;
+
+	if (q == NULL)
+		return;
+
+	nq = q;
+	if (nq->dummy_packet)
+		rte_free(nq->dummy_packet);
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+		.dev_start = eth_dev_start,
+		.dev_stop = eth_dev_stop,
+		.dev_configure = eth_dev_configure,
+		.dev_infos_get = eth_dev_info,
+		.rx_queue_setup = eth_rx_queue_setup,
+		.tx_queue_setup = eth_tx_queue_setup,
+		.rx_queue_release = eth_queue_release,
+		.tx_queue_release = eth_queue_release,
+		.link_update = eth_link_update,
+		.stats_get = eth_stats_get,
+		.stats_reset = eth_stats_reset,
+};
+
+static int
+eth_dev_null_create(const char *name,
+		const unsigned numa_node,
+		unsigned packet_size,
+		unsigned packet_copy)
+{
+	const unsigned nb_rx_queues = 1;
+	const unsigned nb_tx_queues = 1;
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
+			numa_node);
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (eth_dev == NULL)
+		goto error;
+
+	/* now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 */
+	/* NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the nulls are local per-process */
+
+	internals->nb_rx_queues = nb_rx_queues;
+	internals->nb_tx_queues = nb_tx_queues;
+	internals->packet_size = packet_size;
+	internals->packet_copy = packet_copy;
+	internals->numa_node = numa_node;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &ops;
+	eth_dev->pci_dev = pci_dev;
+
+	/* finally assign rx and tx ops */
+	if (packet_copy) {
+		eth_dev->rx_pkt_burst = eth_null_copy_rx;
+		eth_dev->tx_pkt_burst = eth_null_copy_tx;
+	} else {
+		eth_dev->rx_pkt_burst = eth_null_rx;
+		eth_dev->tx_pkt_burst = eth_null_tx;
+	}
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+get_packet_size_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_size = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_size = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_size == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+get_packet_copy_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	const char *a = value;
+	unsigned *packet_copy = extra_args;
+
+	if ((value == NULL) || (extra_args == NULL))
+		return -EINVAL;
+
+	*packet_copy = (unsigned)strtoul(a, NULL, 0);
+	if (*packet_copy == UINT_MAX)
+		return -1;
+
+	return 0;
+}
+
+static int
+rte_pmd_null_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	unsigned packet_size = default_packet_size;
+	unsigned packet_copy = default_packet_copy;
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	if (params != NULL) {
+		kvlist = rte_kvargs_parse(params, valid_arguments);
+		if (kvlist == NULL)
+			return -1;
+
+		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
+
+			ret = rte_kvargs_process(kvlist,
+					ETH_NULL_PACKET_SIZE_ARG,
+					&get_packet_size_arg, &packet_size);
+			if (ret < 0)
+				return -1;
+		}
+
+		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
+
+			ret = rte_kvargs_process(kvlist,
+					ETH_NULL_PACKET_COPY_ARG,
+					&get_packet_copy_arg, &packet_copy);
+			if (ret < 0)
+				return -1;
+		}
+	}
+
+	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
+			"packet copy is %s\n", packet_size,
+			packet_copy ? "enabled" : "disabled");
+
+	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
+}
+
+static struct rte_driver pmd_null_drv = {
+	.name = "eth_null",
+	.type = PMD_VDEV,
+	.init = rte_pmd_null_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_null_drv);
diff --git a/lib/librte_pmd_null/rte_pmd_null_version.map b/lib/librte_pmd_null/rte_pmd_null_version.map
new file mode 100644
index 0000000..ef35398
--- /dev/null
+++ b/lib/librte_pmd_null/rte_pmd_null_version.map
@@ -0,0 +1,4 @@
+DPDK_2.0 {
+
+	local: *;
+};
-- 
1.9.1

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

* [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-23  5:12                     ` [dpdk-dev] [PATCH v11 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
@ 2015-02-23  5:12                       ` Tetsuya Mukawa
  2015-02-25 23:35                         ` Thomas Monjalon
  0 siblings, 1 reply; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-23  5:12 UTC (permalink / raw)
  To: dev

This patch adds port hotplug support to Null PMD.

v9:
 - Use rte_eth_dev_release_port() instead of rte_eth_dev_free().
v7:
 - Add parameter checkings.
   (Thanks to Iremonger, Bernard)
v6:
 - Fix a parameter of rte_eth_dev_free().
v4:
 - Fix commit title.

Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_pmd_null/rte_eth_null.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index aaa0839..bb10276 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -336,6 +336,13 @@ eth_stats_reset(struct rte_eth_dev *dev)
 	}
 }
 
+static struct eth_driver rte_null_pmd = {
+	.pci_drv = {
+		.name = "rte_null_pmd",
+		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+	},
+};
+
 static void
 eth_queue_release(void *q)
 {
@@ -429,10 +436,12 @@ eth_dev_null_create(const char *name,
 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
 	data->dev_link = pmd_link;
 	data->mac_addrs = &eth_addr;
+	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
 
 	eth_dev->data = data;
 	eth_dev->dev_ops = &ops;
 	eth_dev->pci_dev = pci_dev;
+	eth_dev->driver = &rte_null_pmd;
 
 	/* finally assign rx and tx ops */
 	if (packet_copy) {
@@ -536,10 +545,36 @@ rte_pmd_null_devinit(const char *name, const char *params)
 	return eth_dev_null_create(name, numa_node, packet_size, packet_copy);
 }
 
+static int
+rte_pmd_null_devuninit(const char *name)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
+			rte_socket_id());
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+	rte_free(eth_dev->pci_dev);
+
+	rte_eth_dev_release_port(eth_dev);
+
+	return 0;
+}
+
 static struct rte_driver pmd_null_drv = {
 	.name = "eth_null",
 	.type = PMD_VDEV,
 	.init = rte_pmd_null_devinit,
+	.uninit = rte_pmd_null_devuninit,
 };
 
 PMD_REGISTER_DRIVER(pmd_null_drv);
-- 
1.9.1

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-23  5:12                       ` [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
@ 2015-02-25 23:35                         ` Thomas Monjalon
  2015-02-26  0:49                           ` Stephen Hemminger
  0 siblings, 1 reply; 37+ messages in thread
From: Thomas Monjalon @ 2015-02-25 23:35 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev

> This patch adds port hotplug support to Null PMD.
> 
> v9:
>  - Use rte_eth_dev_release_port() instead of rte_eth_dev_free().
> v7:
>  - Add parameter checkings.
>    (Thanks to Iremonger, Bernard)
> v6:
>  - Fix a parameter of rte_eth_dev_free().
> v4:
>  - Fix commit title.
> 
> Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp>

Applied, thanks

I assumed you are OK to be the maintainer of Null PMD.

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-25 23:35                         ` Thomas Monjalon
@ 2015-02-26  0:49                           ` Stephen Hemminger
  2015-02-26  7:03                             ` Thomas Monjalon
  0 siblings, 1 reply; 37+ messages in thread
From: Stephen Hemminger @ 2015-02-26  0:49 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Build fails if HOTPLUG is disabled

== Build lib/librte_ether
  CC rte_ethdev.o
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:430:1: error: ‘rte_eth_dev_get_device_type’ defined but not used [-Werror=unused-function]
 rte_eth_dev_get_device_type(uint8_t port_id)
 ^
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:438:1: error: ‘rte_eth_dev_save’ defined but not used [-Werror=unused-function]
 rte_eth_dev_save(struct rte_eth_dev *devs, size_t size)
 ^
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:450:1: error: ‘rte_eth_dev_get_changed_port’ defined but not used [-Werror=unused-function]
 rte_eth_dev_get_changed_port(struct rte_eth_dev *devs, uint8_t *port_id)
 ^
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:464:1: error: ‘rte_eth_dev_get_addr_by_port’ defined but not used [-Werror=unused-function]
 rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
 ^
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:481:1: error: ‘rte_eth_dev_get_name_by_port’ defined but not used [-Werror=unused-function]
 rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
 ^
/var/src/dpdk/lib/librte_ether/rte_ethdev.c:503:1: error: ‘rte_eth_dev_is_detachable’ defined but not used [-Werror=unused-function]
 rte_eth_dev_is_detachable(uint8_t port_id)
 ^
cc1: all warnings being treated as errors

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26  0:49                           ` Stephen Hemminger
@ 2015-02-26  7:03                             ` Thomas Monjalon
  2015-02-26  9:06                               ` Tetsuya Mukawa
  0 siblings, 1 reply; 37+ messages in thread
From: Thomas Monjalon @ 2015-02-26  7:03 UTC (permalink / raw)
  To: Stephen Hemminger, Tetsuya Mukawa; +Cc: dev

2015-02-25 16:49, Stephen Hemminger:
> Build fails if HOTPLUG is disabled

OK thanks for reporting.
Actually there is no good reason to disable hotplug on Linux.
Though it means that it's impossible to build on FreeBSD.

Tetsuya, the right fix is to remove this option.
You should manage to graceful degrades hotplug in not supported
cases supported: devices cannot be detachable in case of VFIO or nic_uio.
What about uio_pci_generic?

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26  7:03                             ` Thomas Monjalon
@ 2015-02-26  9:06                               ` Tetsuya Mukawa
  2015-02-26 10:57                                 ` Thomas Monjalon
  2015-02-26 12:21                                 ` Mcnamara, John
  0 siblings, 2 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-26  9:06 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

2015-02-26 16:03 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> 2015-02-25 16:49, Stephen Hemminger:
>> Build fails if HOTPLUG is disabled

Hi Stephen,

I appreciate for you reporting.

>
> OK thanks for reporting.
> Actually there is no good reason to disable hotplug on Linux.
> Though it means that it's impossible to build on FreeBSD.
>
> Tetsuya, the right fix is to remove this option.

Hi Thomas,

Yes, I agree with it. I will add some codes to remove the option.
Please let me have a few days, I need to prepare BSD machine for compile test.

> You should manage to graceful degrades hotplug in not supported
> cases supported: devices cannot be detachable in case of VFIO or nic_uio.
> What about uio_pci_generic?

We cannot detach a vfio device so far. But we can detach a igb_uio and
uio_pci_generic device.
About a vfio ddevice, I haven't checked related code yet, but I guess
I will submit code to detach a vfio device in post-rc1.

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26  9:06                               ` Tetsuya Mukawa
@ 2015-02-26 10:57                                 ` Thomas Monjalon
  2015-02-26 11:50                                   ` Tetsuya Mukawa
  2015-03-04  3:37                                   ` Tetsuya Mukawa
  2015-02-26 12:21                                 ` Mcnamara, John
  1 sibling, 2 replies; 37+ messages in thread
From: Thomas Monjalon @ 2015-02-26 10:57 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev

2015-02-26 18:06, Tetsuya Mukawa:
> 2015-02-26 16:03 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> > 2015-02-25 16:49, Stephen Hemminger:
> >> Build fails if HOTPLUG is disabled
> 
> Hi Stephen,
> 
> I appreciate for you reporting.
> 
> >
> > OK thanks for reporting.
> > Actually there is no good reason to disable hotplug on Linux.
> > Though it means that it's impossible to build on FreeBSD.
> >
> > Tetsuya, the right fix is to remove this option.
> 
> Hi Thomas,
> 
> Yes, I agree with it. I will add some codes to remove the option.
> Please let me have a few days, I need to prepare BSD machine for compile test.
> 
> > You should manage to graceful degrades hotplug in not supported
> > cases supported: devices cannot be detachable in case of VFIO or nic_uio.
> > What about uio_pci_generic?
> 
> We cannot detach a vfio device so far. But we can detach a igb_uio and
> uio_pci_generic device.
> About a vfio ddevice, I haven't checked related code yet, but I guess
> I will submit code to detach a vfio device in post-rc1.

OK thanks.
I made a quick fix (moving #ifdef) waiting the option removal:
	http://dpdk.org/browse/dpdk/commit/?id=7609e6609350

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26 10:57                                 ` Thomas Monjalon
@ 2015-02-26 11:50                                   ` Tetsuya Mukawa
  2015-03-04  3:37                                   ` Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-26 11:50 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

2015-02-26 19:57 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> 2015-02-26 18:06, Tetsuya Mukawa:
>> 2015-02-26 16:03 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
>> > 2015-02-25 16:49, Stephen Hemminger:
>> >> Build fails if HOTPLUG is disabled
>>
>> Hi Stephen,
>>
>> I appreciate for you reporting.
>>
>> >
>> > OK thanks for reporting.
>> > Actually there is no good reason to disable hotplug on Linux.
>> > Though it means that it's impossible to build on FreeBSD.
>> >
>> > Tetsuya, the right fix is to remove this option.
>>
>> Hi Thomas,
>>
>> Yes, I agree with it. I will add some codes to remove the option.
>> Please let me have a few days, I need to prepare BSD machine for compile test.
>>
>> > You should manage to graceful degrades hotplug in not supported
>> > cases supported: devices cannot be detachable in case of VFIO or nic_uio.
>> > What about uio_pci_generic?
>>
>> We cannot detach a vfio device so far. But we can detach a igb_uio and
>> uio_pci_generic device.
>> About a vfio ddevice, I haven't checked related code yet, but I guess
>> I will submit code to detach a vfio device in post-rc1.
>
> OK thanks.
> I made a quick fix (moving #ifdef) waiting the option removal:
>         http://dpdk.org/browse/dpdk/commit/?id=7609e6609350
>

Thank you so much for that.

Tetsuya,

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26  9:06                               ` Tetsuya Mukawa
  2015-02-26 10:57                                 ` Thomas Monjalon
@ 2015-02-26 12:21                                 ` Mcnamara, John
  2015-02-26 15:36                                   ` Mcnamara, John
  2015-02-27 23:29                                   ` Thomas Monjalon
  1 sibling, 2 replies; 37+ messages in thread
From: Mcnamara, John @ 2015-02-26 12:21 UTC (permalink / raw)
  To: Tetsuya Mukawa, Thomas Monjalon; +Cc: dev

Hi,

The HEAD doesn't compile with gcc 4.7.2:

    $ git clone http://dpdk.org/git/dpdk
    $ cd dpdk
    $ make T=x86_64-native-linuxapp-gcc -j install 

    ...
    == Build lib/librte_pipeline
      SYMLINK-FILE include/rte_pipeline.h
      CC rte_pipeline.o
    /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c: In function 'eth_stats_get':

    /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28:
        error: array subscript is above array bounds [-Werror=array-bounds]
    /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28: 
        error: array subscript is above array bounds [-Werror=array-bounds]
    /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28: 
        error: array subscript is above array bounds [-Werror=array-bounds]
    ...

    cc1: all warnings being treated as errors
    make[5]: *** [rte_eth_null.o] Error 1
    make[4]: *** [librte_pmd_null] Error 2


The following commit introduced this issue:

    $ git bisect good                              
    c743e50c475f73edf78e5ba26445d7c6ea217f40 is the first bad commit
    commit c743e50c475f73edf78e5ba26445d7c6ea217f40
    Author: Tetsuya Mukawa <mukawa@igel.co.jp>
    Date:   Mon Feb 23 14:12:34 2015 +0900

        null: new poll mode driver

        
I don't see the issue with gcc 4.9.

Regards,

John

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26 12:21                                 ` Mcnamara, John
@ 2015-02-26 15:36                                   ` Mcnamara, John
  2015-02-27  1:31                                     ` Tetsuya Mukawa
  2015-02-27 23:29                                   ` Thomas Monjalon
  1 sibling, 1 reply; 37+ messages in thread
From: Mcnamara, John @ 2015-02-26 15:36 UTC (permalink / raw)
  To: Mcnamara, John, Tetsuya Mukawa, Thomas Monjalon; +Cc: dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Mcnamara, John
> Sent: Thursday, February 26, 2015 12:21 PM
> To: Tetsuya Mukawa; Thomas Monjalon
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port
> hotplug function
> 
> The following commit introduced this issue:
> 
>     $ git bisect good
>     c743e50c475f73edf78e5ba26445d7c6ea217f40 is the first bad commit
>     commit c743e50c475f73edf78e5ba26445d7c6ea217f40

Hi,

The above commit also has throws a warning with ICC:

    lib/librte_pmd_null/rte_eth_null.c(47): error #83:
        type qualifier specified more than once

      static const char const *valid_arguments[] = {
                        ^

                        
An earlier commit also throws a warning with ICC:
             

    lib/librte_pmd_null/rte_eth_null.c(47): error #83: 
            type qualifier specified more than once

            static const char const *valid_arguments[] = {
            ^                        

Commit:

    92d94d3744d7760d8d5e490be810612cf4a9cfb0 is the first bad commit
    commit 92d94d3744d7760d8d5e490be810612cf4a9cfb0
    Author: Tetsuya Mukawa <mukawa@igel.co.jp>
    Date:   Thu Feb 26 04:32:26 2015 +0900

        ethdev: attach or detach port


I applied the following patch to fix these issues, (in order to test with the HEAD). You can review them to see if they are valid and apply something similar:

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index bb94ccb..6ea7a17 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -433,7 +433,7 @@ static enum rte_eth_dev_type
 rte_eth_dev_get_device_type(uint8_t port_id)
 {
        if (!rte_eth_dev_is_valid_port(port_id))
-               return -1;
+               return RTE_ETH_DEV_UNKNOWN;
        return rte_eth_devices[port_id].dev_type;
 }
 
diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
index bb10276..3ef5842 100644
--- a/lib/librte_pmd_null/rte_eth_null.c
+++ b/lib/librte_pmd_null/rte_eth_null.c
@@ -44,7 +44,7 @@
 static unsigned default_packet_size = 64;
 static unsigned default_packet_copy;
 
-static const char const *valid_arguments[] = {
+static const char *valid_arguments[] = {
        ETH_NULL_PACKET_SIZE_ARG,
        ETH_NULL_PACKET_COPY_ARG,
        NULL

       
John.
-- 

        
                        
                        
                        
                        

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26 15:36                                   ` Mcnamara, John
@ 2015-02-27  1:31                                     ` Tetsuya Mukawa
  0 siblings, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-02-27  1:31 UTC (permalink / raw)
  To: Mcnamara, John, Thomas Monjalon; +Cc: dev

On 2015/02/27 0:36, Mcnamara, John wrote:
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Mcnamara, John
>> Sent: Thursday, February 26, 2015 12:21 PM
>> To: Tetsuya Mukawa; Thomas Monjalon
>> Cc: dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port
>> hotplug function
>>
>> The following commit introduced this issue:
>>
>>     $ git bisect good
>>     c743e50c475f73edf78e5ba26445d7c6ea217f40 is the first bad commit
>>     commit c743e50c475f73edf78e5ba26445d7c6ea217f40
> Hi,
>
> The above commit also has throws a warning with ICC:
>
>     lib/librte_pmd_null/rte_eth_null.c(47): error #83:
>         type qualifier specified more than once
>
>       static const char const *valid_arguments[] = {
>                         ^
>
>                         
> An earlier commit also throws a warning with ICC:
>              
>
>     lib/librte_pmd_null/rte_eth_null.c(47): error #83: 
>             type qualifier specified more than once
>
>             static const char const *valid_arguments[] = {
>             ^                        
>
> Commit:
>
>     92d94d3744d7760d8d5e490be810612cf4a9cfb0 is the first bad commit
>     commit 92d94d3744d7760d8d5e490be810612cf4a9cfb0
>     Author: Tetsuya Mukawa <mukawa@igel.co.jp>
>     Date:   Thu Feb 26 04:32:26 2015 +0900
>
>         ethdev: attach or detach port
>
>
> I applied the following patch to fix these issues, (in order to test with the HEAD). You can review them to see if they are valid and apply something similar:
>
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index bb94ccb..6ea7a17 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -433,7 +433,7 @@ static enum rte_eth_dev_type
>  rte_eth_dev_get_device_type(uint8_t port_id)
>  {
>         if (!rte_eth_dev_is_valid_port(port_id))
> -               return -1;
> +               return RTE_ETH_DEV_UNKNOWN;
>         return rte_eth_devices[port_id].dev_type;
>  }
>  
> diff --git a/lib/librte_pmd_null/rte_eth_null.c b/lib/librte_pmd_null/rte_eth_null.c
> index bb10276..3ef5842 100644
> --- a/lib/librte_pmd_null/rte_eth_null.c
> +++ b/lib/librte_pmd_null/rte_eth_null.c
> @@ -44,7 +44,7 @@
>  static unsigned default_packet_size = 64;
>  static unsigned default_packet_copy;
>  
> -static const char const *valid_arguments[] = {
> +static const char *valid_arguments[] = {
>         ETH_NULL_PACKET_SIZE_ARG,
>         ETH_NULL_PACKET_COPY_ARG,
>         NULL
>
>        
> John.

Hi Mcnamara and Stephen,

I appreciate for reporting.
I start checking all compile issues of null pmd.

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26 12:21                                 ` Mcnamara, John
  2015-02-26 15:36                                   ` Mcnamara, John
@ 2015-02-27 23:29                                   ` Thomas Monjalon
  1 sibling, 0 replies; 37+ messages in thread
From: Thomas Monjalon @ 2015-02-27 23:29 UTC (permalink / raw)
  To: Mcnamara, John; +Cc: dev

2015-02-26 12:21, Mcnamara, John:
> Hi,
> 
> The HEAD doesn't compile with gcc 4.7.2:
> 
>     $ git clone http://dpdk.org/git/dpdk
>     $ cd dpdk
>     $ make T=x86_64-native-linuxapp-gcc -j install 
> 
>     ...
>     == Build lib/librte_pipeline
>       SYMLINK-FILE include/rte_pipeline.h
>       CC rte_pipeline.o
>     /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c: In function 'eth_stats_get':
> 
>     /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28:
>         error: array subscript is above array bounds [-Werror=array-bounds]
>     /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28: 
>         error: array subscript is above array bounds [-Werror=array-bounds]
>     /tmp/dpdk/lib/librte_pmd_null/rte_eth_null.c:302:28: 
>         error: array subscript is above array bounds [-Werror=array-bounds]
>     ...
> 
>     cc1: all warnings being treated as errors
>     make[5]: *** [rte_eth_null.o] Error 1
>     make[4]: *** [librte_pmd_null] Error 2
> 
> 
> The following commit introduced this issue:
> 
>     $ git bisect good                              
>     c743e50c475f73edf78e5ba26445d7c6ea217f40 is the first bad commit
>     commit c743e50c475f73edf78e5ba26445d7c6ea217f40
>     Author: Tetsuya Mukawa <mukawa@igel.co.jp>
>     Date:   Mon Feb 23 14:12:34 2015 +0900
> 
>         null: new poll mode driver
> 
>         
> I don't see the issue with gcc 4.9.

Fixed: http://dpdk.org/browse/dpdk/commit/?id=e34550c8b97826

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

* Re: [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function
  2015-02-26 10:57                                 ` Thomas Monjalon
  2015-02-26 11:50                                   ` Tetsuya Mukawa
@ 2015-03-04  3:37                                   ` Tetsuya Mukawa
  1 sibling, 0 replies; 37+ messages in thread
From: Tetsuya Mukawa @ 2015-03-04  3:37 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

2015-02-26 19:57 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> 2015-02-26 18:06, Tetsuya Mukawa:
>> 2015-02-26 16:03 GMT+09:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
>> > 2015-02-25 16:49, Stephen Hemminger:
>> >> Build fails if HOTPLUG is disabled
>>
>> Hi Stephen,
>>
>> I appreciate for you reporting.
>>
>> >
>> > OK thanks for reporting.
>> > Actually there is no good reason to disable hotplug on Linux.
>> > Though it means that it's impossible to build on FreeBSD.
>> >
>> > Tetsuya, the right fix is to remove this option.
>>
>> Hi Thomas,
>>
>> Yes, I agree with it. I will add some codes to remove the option.
>> Please let me have a few days, I need to prepare BSD machine for compile test.
>>
>> > You should manage to graceful degrades hotplug in not supported
>> > cases supported: devices cannot be detachable in case of VFIO or nic_uio.
>> > What about uio_pci_generic?
>>
>> We cannot detach a vfio device so far. But we can detach a igb_uio and
>> uio_pci_generic device.
>> About a vfio ddevice, I haven't checked related code yet, but I guess
>> I will submit code to detach a vfio device in post-rc1.
>
> OK thanks.
> I made a quick fix (moving #ifdef) waiting the option removal:
>         http://dpdk.org/browse/dpdk/commit/?id=7609e6609350
>

Hi Thomas,

I submit the patches to remove HOTPLUG config macro.

Thanks,
Tetsuya

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

end of thread, other threads:[~2015-03-04  3:37 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <mukawa@igel.co.jp>
2014-10-01  4:57 ` [dpdk-dev] [PATCH v2] PMD for performance measurement mukawa
2014-10-01  4:57   ` [dpdk-dev] [PATCH v2] librte_pmd_null: Add null PMD mukawa
2014-11-13 12:17     ` Thomas Monjalon
2014-12-16  8:39     ` [dpdk-dev] [PATCH v3] " Tetsuya Mukawa
2014-12-16  8:44       ` Tetsuya Mukawa
2014-12-16  8:47         ` Thomas Monjalon
2014-12-16  8:49           ` Tetsuya Mukawa
2015-01-20  3:00       ` [dpdk-dev] [PATCH v4 1/2] " Tetsuya Mukawa
2015-01-20  3:00         ` [dpdk-dev] [PATCH v4 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-06  4:38           ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Tetsuya Mukawa
2015-02-06  4:38             ` [dpdk-dev] [PATCH v6 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-06 11:37               ` Iremonger, Bernard
2015-02-06 11:32             ` [dpdk-dev] [PATCH v6 1/2] librte_pmd_null: Add null PMD Iremonger, Bernard
2015-02-09  8:54               ` Tetsuya Mukawa
2015-02-12  2:44             ` [dpdk-dev] [PATCH v7 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
2015-02-12  2:44               ` [dpdk-dev] [PATCH v7 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-16  4:19               ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
2015-02-16  4:19                 ` [dpdk-dev] [PATCH v8 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-16 16:38                   ` Iremonger, Bernard
2015-02-16 16:38                 ` [dpdk-dev] [PATCH v8 1/2] librte_pmd_null: Add Null PMD Iremonger, Bernard
2015-02-19 10:41                 ` [dpdk-dev] [PATCH v9 " Tetsuya Mukawa
2015-02-19 10:41                   ` [dpdk-dev] [PATCH v9 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-20  6:41                   ` [dpdk-dev] [PATCH v10 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
2015-02-20  6:41                     ` [dpdk-dev] [PATCH v10 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-23  5:12                     ` [dpdk-dev] [PATCH v11 1/2] librte_pmd_null: Add Null PMD Tetsuya Mukawa
2015-02-23  5:12                       ` [dpdk-dev] [PATCH v11 2/2] librte_pmd_null: Support port hotplug function Tetsuya Mukawa
2015-02-25 23:35                         ` Thomas Monjalon
2015-02-26  0:49                           ` Stephen Hemminger
2015-02-26  7:03                             ` Thomas Monjalon
2015-02-26  9:06                               ` Tetsuya Mukawa
2015-02-26 10:57                                 ` Thomas Monjalon
2015-02-26 11:50                                   ` Tetsuya Mukawa
2015-03-04  3:37                                   ` Tetsuya Mukawa
2015-02-26 12:21                                 ` Mcnamara, John
2015-02-26 15:36                                   ` Mcnamara, John
2015-02-27  1:31                                     ` Tetsuya Mukawa
2015-02-27 23:29                                   ` Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).