From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id BF90F1F7 for ; Fri, 6 Feb 2015 12:32:39 +0100 (CET) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP; 06 Feb 2015 03:32:38 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.09,529,1418112000"; d="scan'208";a="662516149" Received: from irsmsx110.ger.corp.intel.com ([163.33.3.25]) by fmsmga001.fm.intel.com with ESMTP; 06 Feb 2015 03:32:37 -0800 Received: from irsmsx108.ger.corp.intel.com ([169.254.11.64]) by irsmsx110.ger.corp.intel.com ([169.254.15.8]) with mapi id 14.03.0195.001; Fri, 6 Feb 2015 11:32:35 +0000 From: "Iremonger, Bernard" To: Tetsuya Mukawa , "dev@dpdk.org" Thread-Topic: [PATCH v6 1/2] librte_pmd_null: Add null PMD Thread-Index: AQHQQcbMx3pimIvCNUyJUghPUvqAkZzjdihg Date: Fri, 6 Feb 2015 11:32:34 +0000 Message-ID: <8CEF83825BEC744B83065625E567D7C2049DDE4A@IRSMSX108.ger.corp.intel.com> References: <1421722821-18158-2-git-send-email-mukawa@igel.co.jp> <1423197495-1758-1-git-send-email-mukawa@igel.co.jp> In-Reply-To: <1423197495-1758-1-git-send-email-mukawa@igel.co.jp> Accept-Language: en-GB, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [163.33.239.180] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v6 1/2] 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: Fri, 06 Feb 2015 11:32:40 -0000 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 >=20 > 'null PMD' is a driver of the virtual device particulary designed to meas= ure performance of DPDK > PMDs. When an application call rx, null PMD just allocates mbufs and retu= rns those. Also tx, the PMD > just frees mbufs. >=20 > 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. >=20 > To use the PMD, enable CONFIG_RTE_BUILD_SHARED_LIB in config file. Then c= ompile the PMD as > shared library. The library can be linked using '-d' > option when an application invokes. >=20 > 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 >=20 > If testpmd is compiled with CONFIG_RTE_BUILD_SHARED_LIB, it may need to s= pecify more libraries > using '-d' option. >=20 > v4: > - Fix memory leak. > (Thanks to Iremonger, Bernard) >=20 > 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 | 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 >=20 > diff --git a/config/common_bsdapp b/config/common_bsdapp index 9177db1..f= a849be 100644 > --- a/config/common_bsdapp > +++ b/config/common_bsdapp > @@ -224,6 +224,11 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=3Dy CONFIG_RTE_LIBRTE_PM= D_BOND=3Dy >=20 > # > +# Compile null PMD > +# > +CONFIG_RTE_LIBRTE_PMD_NULL=3Dy > + > +# > # Do prefetch of packet data within PMD driver receive function # > CONFIG_RTE_PMD_PACKET_PREFETCH=3Dy 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=3Dy > CONFIG_RTE_LIBRTE_PMD_XENVIRT=3Dn >=20 > # > +# Compile null PMD > +# > +CONFIG_RTE_LIBRTE_PMD_NULL=3Dy > + > +# > # Do prefetch of packet data within PMD driver receive function # > CONFIG_RTE_PMD_PACKET_PREFETCH=3Dy diff --git a/lib/Makefile b/lib/Makefi= le index > 0ffc982..d246c53 100644 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -52,6 +52,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) +=3D librte_pmd_vi= rtio > DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) +=3D librte_pmd_vmxnet3 > DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) +=3D librte_pmd_xenvirt > DIRS-$(CONFIG_RTE_LIBRTE_VHOST) +=3D librte_vhost > +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D librte_pmd_null > DIRS-$(CONFIG_RTE_LIBRTE_HASH) +=3D librte_hash > DIRS-$(CONFIG_RTE_LIBRTE_LPM) +=3D librte_lpm > DIRS-$(CONFIG_RTE_LIBRTE_ACL) +=3D librte_acl diff --git a/lib/librte_pm= d_null/Makefile > b/lib/librte_pmd_null/Makefile new file mode 100644 index 0000000..0ec4db= 9 > --- /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 copyrigh= t > +# 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 FO= R > +# 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 AN= Y > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE US= E > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB =3D librte_pmd_null.a > + > +CFLAGS +=3D -O3 > +CFLAGS +=3D $(WERROR_FLAGS) > + > +# > +# all source are stored in SRCS-y > +# > +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D rte_eth_null.c > + > +# > +# Export include files > +# > +SYMLINK-y-include +=3D > + > +# this lib depends upon: > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D lib/librte_mbuf > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D lib/librte_ether > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D lib/librte_malloc > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) +=3D 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 copyrig= ht > + * 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 F= OR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGH= T > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTA= L, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF US= E, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON A= NY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE U= SE > + * 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 =3D 64; static unsigned > +default_packet_copy; > + > +static const char const *valid_arguments[] =3D { > + 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 =3D { .addr_bytes =3D {0} }; static co= nst > +char *drivername =3D "Null PMD"; static struct rte_eth_link pmd_link =3D= { > + .link_speed =3D 10000, > + .link_duplex =3D ETH_LINK_FULL_DUPLEX, > + .link_status =3D 0 > +}; > + > +static uint16_t > +eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) { > + int i; > + struct null_queue *h =3D q; > + unsigned packet_size =3D h->internals->packet_size; > + > + for (i =3D 0; i < nb_bufs; i++) { > + bufs[i] =3D rte_pktmbuf_alloc(h->mb_pool); > + if (!bufs[i]) > + break; Should the code return an error here rather than break? > + bufs[i]->data_len =3D (uint16_t)packet_size; > + bufs[i]->pkt_len =3D packet_size; > + bufs[i]->nb_segs =3D 1; > + bufs[i]->next =3D 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 =3D q; > + unsigned packet_size =3D h->internals->packet_size; > + > + for (i =3D 0; i < nb_bufs; i++) { > + bufs[i] =3D 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 =3D (uint16_t)packet_size; > + bufs[i]->pkt_len =3D packet_size; > + bufs[i]->nb_segs =3D 1; > + bufs[i]->next =3D 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 =3D q; Input parameters q and bufs should be checked. > + > + for (i =3D 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 =3D q; > + unsigned packet_size =3D h->internals->packet_size; Input parameters q and bufs should be checked. > + > + for (i =3D 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 =3D 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 =3D 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 =3D dev->data->dev_private; > + unsigned packet_size =3D internals->packet_size; > + Input parameter dev should be checked. > + if (rx_queue_id !=3D 0) > + return -ENODEV; > + > + internals->rx_null_queues[rx_queue_id].mb_pool =3D mb_pool; > + dev->data->rx_queues[rx_queue_id] =3D > + &internals->rx_null_queues[rx_queue_id]; > + dummy_packet =3D rte_zmalloc_socket(NULL, > + packet_size, 0, internals->numa_node); > + if (dummy_packet =3D=3D NULL) > + return -ENOMEM; > + > + internals->rx_null_queues[rx_queue_id].internals =3D internals; > + internals->rx_null_queues[rx_queue_id].dummy_packet =3D 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 =3D dev->data->dev_private; > + unsigned packet_size =3D internals->packet_size; > + Input parameter dev should be checked. > + if (tx_queue_id !=3D 0) > + return -ENODEV; > + > + dev->data->tx_queues[tx_queue_id] =3D > + &internals->tx_null_queues[tx_queue_id]; > + dummy_packet =3D rte_zmalloc_socket(NULL, > + packet_size, 0, internals->numa_node); > + if (dummy_packet =3D=3D NULL) > + return -ENOMEM; > + > + internals->tx_null_queues[tx_queue_id].internals =3D internals; > + internals->tx_null_queues[tx_queue_id].dummy_packet =3D 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 =3D dev->data->dev_private; Input parameters dev and dev_info should be checked. > + > + dev_info->driver_name =3D drivername; > + dev_info->max_mac_addrs =3D 1; > + dev_info->max_rx_pktlen =3D (uint32_t)-1; > + dev_info->max_rx_queues =3D (uint16_t)internals->nb_rx_queues; > + dev_info->max_tx_queues =3D (uint16_t)internals->nb_tx_queues; > + dev_info->min_rx_bufsize =3D 0; > + dev_info->pci_dev =3D NULL; > +} > + > +static void > +eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats) > +{ > + unsigned i; > + unsigned long rx_total =3D 0, tx_total =3D 0, tx_err_total =3D 0; > + const struct pmd_internals *internal =3D dev->data->dev_private; Input parameters dev and igb_stats should be checked. > + > + memset(igb_stats, 0, sizeof(*igb_stats)); > + for (i =3D 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS && > + i < internal->nb_rx_queues; i++) { > + igb_stats->q_ipackets[i] =3D > + internal->rx_null_queues[i].rx_pkts.cnt; > + rx_total +=3D igb_stats->q_ipackets[i]; > + } > + > + for (i =3D 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS && > + i < internal->nb_tx_queues; i++) { > + igb_stats->q_opackets[i] =3D > + internal->tx_null_queues[i].tx_pkts.cnt; > + igb_stats->q_errors[i] =3D > + internal->tx_null_queues[i].err_pkts.cnt; > + tx_total +=3D igb_stats->q_opackets[i]; > + tx_err_total +=3D igb_stats->q_errors[i]; > + } > + > + igb_stats->ipackets =3D rx_total; > + igb_stats->opackets =3D tx_total; > + igb_stats->oerrors =3D tx_err_total; > +} > + > +static void > +eth_stats_reset(struct rte_eth_dev *dev) { > + unsigned i; > + struct pmd_internals *internal =3D dev->data->dev_private; Input parameter dev should be checked. > + > + for (i =3D 0; i < internal->nb_rx_queues; i++) > + internal->rx_null_queues[i].rx_pkts.cnt =3D 0; > + for (i =3D 0; i < internal->nb_tx_queues; i++) { > + internal->tx_null_queues[i].tx_pkts.cnt =3D 0; > + internal->tx_null_queues[i].err_pkts.cnt =3D 0; > + } > +} > + > +static void > +eth_queue_release(void *q) > +{ > + struct null_queue *nq; > + > + if (q =3D=3D NULL) > + return; > + > + nq =3D 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 =3D { > + .dev_start =3D eth_dev_start, > + .dev_stop =3D eth_dev_stop, > + .dev_configure =3D eth_dev_configure, > + .dev_infos_get =3D eth_dev_info, > + .rx_queue_setup =3D eth_rx_queue_setup, > + .tx_queue_setup =3D eth_tx_queue_setup, > + .rx_queue_release =3D eth_queue_release, > + .tx_queue_release =3D eth_queue_release, > + .link_update =3D eth_link_update, > + .stats_get =3D eth_stats_get, > + .stats_reset =3D 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 =3D 1; > + const unsigned nb_tx_queues =3D 1; > + struct rte_eth_dev_data *data =3D NULL; > + struct rte_pci_device *pci_dev =3D NULL; > + struct pmd_internals *internals =3D NULL; > + struct rte_eth_dev *eth_dev =3D 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 =3D rte_zmalloc_socket(name, sizeof(*data), 0, numa_node); > + if (data =3D=3D NULL) > + goto error; > + > + pci_dev =3D rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node); > + if (pci_dev =3D=3D NULL) > + goto error; > + > + internals =3D rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node= ); > + if (internals =3D=3D NULL) > + goto error; > + > + /* reserve an ethdev entry */ > + eth_dev =3D rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL); > + if (eth_dev =3D=3D 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_de= v > + * so the nulls are local per-process */ > + > + internals->nb_rx_queues =3D nb_rx_queues; > + internals->nb_tx_queues =3D nb_tx_queues; > + internals->packet_size =3D packet_size; > + internals->packet_copy =3D packet_copy; > + internals->numa_node =3D numa_node; > + > + pci_dev->numa_node =3D numa_node; > + > + data->dev_private =3D internals; > + data->port_id =3D eth_dev->data->port_id; > + data->nb_rx_queues =3D (uint16_t)nb_rx_queues; > + data->nb_tx_queues =3D (uint16_t)nb_tx_queues; > + data->dev_link =3D pmd_link; > + data->mac_addrs =3D ð_addr; > + > + eth_dev->data =3D data; > + eth_dev->dev_ops =3D &ops; > + eth_dev->pci_dev =3D pci_dev; > + > + /* finally assign rx and tx ops */ > + if (packet_copy) { > + eth_dev->rx_pkt_burst =3D eth_null_copy_rx; > + eth_dev->tx_pkt_burst =3D eth_null_copy_tx; > + } else { > + eth_dev->rx_pkt_burst =3D eth_null_rx; > + eth_dev->tx_pkt_burst =3D 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 =3D value; > + unsigned *packet_size =3D extra_args; Parameters value and extra_args should be checked. > + > + *packet_size =3D (unsigned)strtoul(a, NULL, 0); > + if (*packet_size =3D=3D 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 =3D value; > + unsigned *packet_copy =3D extra_args; Parameters value and extra_args should be checked. > + > + *packet_copy =3D (unsigned)strtoul(a, NULL, 0); > + if (*packet_copy =3D=3D UINT_MAX) > + return -1; > + > + return 0; > +} > + > +static int > +rte_pmd_null_devinit(const char *name, const char *params) { > + unsigned numa_node; > + unsigned packet_size =3D default_packet_size; > + unsigned packet_copy =3D 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 =3D rte_socket_id(); > + > + kvlist =3D rte_kvargs_parse(params, valid_arguments); > + if (kvlist =3D=3D NULL) > + return -1; > + > + if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) =3D=3D 1) { > + > + ret =3D 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) =3D=3D 1) { > + > + ret =3D 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 =3D { > + .name =3D "eth_null", > + .type =3D PMD_VDEV, > + .init =3D rte_pmd_null_devinit, > +}; > + > +PMD_REGISTER_DRIVER(pmd_null_drv); > -- > 1.9.1 Regards, Bernard.