From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pd0-f178.google.com (mail-pd0-f178.google.com [209.85.192.178]) by dpdk.org (Postfix) with ESMTP id 38774683A for ; Tue, 16 Dec 2014 09:44:28 +0100 (CET) Received: by mail-pd0-f178.google.com with SMTP id r10so13394143pdi.23 for ; Tue, 16 Dec 2014 00:44:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type :content-transfer-encoding; bh=zWpcX5UPzCcSxTH6Z3Eg1KpFCgjciSfIvcAeJdCKMjA=; b=krCKRPtCSHTI+lRpuKHs8pJDGxAOF1HXsPB5VCxn3El8sLgjTc00h98anu0PbfQZ2y NLDKnbuu09TNLSWum47Y9kLkC7RmI3nDsE79PvNPjdSHCwMV5AmvNZEhS4OON9KflZjw TEJ/dHnjoxyW3QgjS0CXKusLUPf/WL4lZT2gb3dNLBQ1ZeWjkXkOi1i8S0ZwVABMxgQ2 gMllykWJqDm0aPyOwa0Y4T7Ncq8nEhy+29ckHUf/YCzW2QeJ7VPOCYPuZjegpmjYS8cR Wl1La7I+XK4tnCKYnZQL3bFizYHNj9O6XDLvnqwEdrcAHI9bizS5hcWvpIkObLy3M3n0 X09Q== X-Gm-Message-State: ALoCoQled1VQzHGTiyDY8mA3s9/OYn4voHiYZZY+FbeYJgdx2xuF7/vuVlHDW4TaDj2CMxYC1Tl1 X-Received: by 10.68.232.104 with SMTP id tn8mr58646073pbc.31.1418719467334; Tue, 16 Dec 2014 00:44:27 -0800 (PST) Received: from [10.16.129.101] (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id bn13sm288959pdb.4.2014.12.16.00.44.25 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 16 Dec 2014 00:44:26 -0800 (PST) Message-ID: <548FF0EA.3010501@igel.co.jp> Date: Tue, 16 Dec 2014 17:44:26 +0900 From: Tetsuya Mukawa User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: dev@dpdk.org References: <1412139437-26749-2-git-send-email-mukawa@igel.co.jp> <1418719167-8235-1-git-send-email-mukawa@igel.co.jp> In-Reply-To: <1418719167-8235-1-git-send-email-mukawa@igel.co.jp> Content-Type: text/plain; charset=ISO-2022-JP Content-Transfer-Encoding: 7bit Subject: Re: [dpdk-dev] [PATCH v3] librte_pmd_null: Add null PMD X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Dec 2014 08:44:28 -0000 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 > --- > 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 > +#include > +#include > +#include > +#include > +#include > + > +#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 = ð_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);