xref: /dpdk/drivers/net/null/rte_eth_null.c (revision f30e69b41f949cd4a9afb6ff39de196e661708e2)
16fc581e9SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2b3b413f7SBruce Richardson  * Copyright (C) IGEL Co.,Ltd.
3b3b413f7SBruce Richardson  *  All rights reserved.
4b3b413f7SBruce Richardson  */
5b3b413f7SBruce Richardson 
6b3b413f7SBruce Richardson #include <rte_mbuf.h>
7ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h>
8050fe6e9SJan Blunck #include <rte_ethdev_vdev.h>
9b3b413f7SBruce Richardson #include <rte_malloc.h>
10b3b413f7SBruce Richardson #include <rte_memcpy.h>
11d4a586d2SJianfeng Tan #include <rte_bus_vdev.h>
12b3b413f7SBruce Richardson #include <rte_kvargs.h>
131ccec0a8STomasz Kulasek #include <rte_spinlock.h>
14b3b413f7SBruce Richardson 
15b3b413f7SBruce Richardson #define ETH_NULL_PACKET_SIZE_ARG	"size"
16b3b413f7SBruce Richardson #define ETH_NULL_PACKET_COPY_ARG	"copy"
17f51ecf2fSFerruh Yigit #define ETH_NULL_PACKET_NO_RX_ARG	"no-rx"
18b3b413f7SBruce Richardson 
194df90194SFerruh Yigit static unsigned int default_packet_size = 64;
204df90194SFerruh Yigit static unsigned int default_packet_copy;
21f51ecf2fSFerruh Yigit static unsigned int default_no_rx;
22b3b413f7SBruce Richardson 
23b3b413f7SBruce Richardson static const char *valid_arguments[] = {
24b3b413f7SBruce Richardson 	ETH_NULL_PACKET_SIZE_ARG,
25b3b413f7SBruce Richardson 	ETH_NULL_PACKET_COPY_ARG,
26f51ecf2fSFerruh Yigit 	ETH_NULL_PACKET_NO_RX_ARG,
27b3b413f7SBruce Richardson 	NULL
28b3b413f7SBruce Richardson };
29b3b413f7SBruce Richardson 
30b3b413f7SBruce Richardson struct pmd_internals;
31b3b413f7SBruce Richardson 
32b3b413f7SBruce Richardson struct null_queue {
33b3b413f7SBruce Richardson 	struct pmd_internals *internals;
34b3b413f7SBruce Richardson 
35b3b413f7SBruce Richardson 	struct rte_mempool *mb_pool;
36b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
37b3b413f7SBruce Richardson 
38b3b413f7SBruce Richardson 	rte_atomic64_t rx_pkts;
39b3b413f7SBruce Richardson 	rte_atomic64_t tx_pkts;
40b3b413f7SBruce Richardson };
41b3b413f7SBruce Richardson 
42276bb4ceSFerruh Yigit struct pmd_options {
43276bb4ceSFerruh Yigit 	unsigned int packet_copy;
44276bb4ceSFerruh Yigit 	unsigned int packet_size;
45f51ecf2fSFerruh Yigit 	unsigned int no_rx;
46276bb4ceSFerruh Yigit };
47276bb4ceSFerruh Yigit 
48b3b413f7SBruce Richardson struct pmd_internals {
494df90194SFerruh Yigit 	unsigned int packet_size;
504df90194SFerruh Yigit 	unsigned int packet_copy;
51f51ecf2fSFerruh Yigit 	unsigned int no_rx;
52f8244c63SZhiyong Yang 	uint16_t port_id;
53b3b413f7SBruce Richardson 
54dd7c54a6STomasz Kulasek 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
55dd7c54a6STomasz Kulasek 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
561ccec0a8STomasz Kulasek 
576d13ea8eSOlivier Matz 	struct rte_ether_addr eth_addr;
581ccec0a8STomasz Kulasek 	/** Bit mask of RSS offloads, the bit offset also means flow type */
591ccec0a8STomasz Kulasek 	uint64_t flow_type_rss_offloads;
601ccec0a8STomasz Kulasek 
611ccec0a8STomasz Kulasek 	rte_spinlock_t rss_lock;
621ccec0a8STomasz Kulasek 
631ccec0a8STomasz Kulasek 	uint16_t reta_size;
641ccec0a8STomasz Kulasek 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
651ccec0a8STomasz Kulasek 			RTE_RETA_GROUP_SIZE];
661ccec0a8STomasz Kulasek 
671ccec0a8STomasz Kulasek 	uint8_t rss_key[40];                /**< 40-byte hash key. */
68b3b413f7SBruce Richardson };
69b3b413f7SBruce Richardson static struct rte_eth_link pmd_link = {
7039fd068aSMarc Sune 	.link_speed = ETH_SPEED_NUM_10G,
71b3b413f7SBruce Richardson 	.link_duplex = ETH_LINK_FULL_DUPLEX,
7209419f23SThomas Monjalon 	.link_status = ETH_LINK_DOWN,
7318869f97SFerruh Yigit 	.link_autoneg = ETH_LINK_FIXED,
74b3b413f7SBruce Richardson };
75b3b413f7SBruce Richardson 
769c99878aSJerin Jacob RTE_LOG_REGISTER(eth_null_logtype, pmd.net.null, NOTICE);
77eb16afb9SStephen Hemminger 
78eb16afb9SStephen Hemminger #define PMD_LOG(level, fmt, args...) \
79eb16afb9SStephen Hemminger 	rte_log(RTE_LOG_ ## level, eth_null_logtype, \
80eb16afb9SStephen Hemminger 		"%s(): " fmt "\n", __func__, ##args)
81eb16afb9SStephen Hemminger 
82b3b413f7SBruce Richardson static uint16_t
83b3b413f7SBruce Richardson eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
84b3b413f7SBruce Richardson {
85b3b413f7SBruce Richardson 	int i;
86b3b413f7SBruce Richardson 	struct null_queue *h = q;
874df90194SFerruh Yigit 	unsigned int packet_size;
88b3b413f7SBruce Richardson 
89b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
90b3b413f7SBruce Richardson 		return 0;
91b3b413f7SBruce Richardson 
92b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
934e436ddaSMallesh Koujalagi 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
944e436ddaSMallesh Koujalagi 		return 0;
954e436ddaSMallesh Koujalagi 
96b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
97b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
98b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
995cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
100b3b413f7SBruce Richardson 	}
101b3b413f7SBruce Richardson 
102b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
103b3b413f7SBruce Richardson 
104b3b413f7SBruce Richardson 	return i;
105b3b413f7SBruce Richardson }
106b3b413f7SBruce Richardson 
107b3b413f7SBruce Richardson static uint16_t
108b3b413f7SBruce Richardson eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
109b3b413f7SBruce Richardson {
110b3b413f7SBruce Richardson 	int i;
111b3b413f7SBruce Richardson 	struct null_queue *h = q;
1124df90194SFerruh Yigit 	unsigned int packet_size;
113b3b413f7SBruce Richardson 
114b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
115b3b413f7SBruce Richardson 		return 0;
116b3b413f7SBruce Richardson 
117b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
1184e436ddaSMallesh Koujalagi 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
1194e436ddaSMallesh Koujalagi 		return 0;
1204e436ddaSMallesh Koujalagi 
121b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
122b3b413f7SBruce Richardson 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
123b3b413f7SBruce Richardson 					packet_size);
124b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
125b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
1265cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
127b3b413f7SBruce Richardson 	}
128b3b413f7SBruce Richardson 
129b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
130b3b413f7SBruce Richardson 
131b3b413f7SBruce Richardson 	return i;
132b3b413f7SBruce Richardson }
133b3b413f7SBruce Richardson 
134b3b413f7SBruce Richardson static uint16_t
135f51ecf2fSFerruh Yigit eth_null_no_rx(void *q __rte_unused, struct rte_mbuf **bufs __rte_unused,
136f51ecf2fSFerruh Yigit 		uint16_t nb_bufs __rte_unused)
137f51ecf2fSFerruh Yigit {
138f51ecf2fSFerruh Yigit 	return 0;
139f51ecf2fSFerruh Yigit }
140f51ecf2fSFerruh Yigit 
141f51ecf2fSFerruh Yigit static uint16_t
142b3b413f7SBruce Richardson eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
143b3b413f7SBruce Richardson {
144b3b413f7SBruce Richardson 	int i;
145b3b413f7SBruce Richardson 	struct null_queue *h = q;
146b3b413f7SBruce Richardson 
147b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
148b3b413f7SBruce Richardson 		return 0;
149b3b413f7SBruce Richardson 
150b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++)
151b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
152b3b413f7SBruce Richardson 
153b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
154b3b413f7SBruce Richardson 
155b3b413f7SBruce Richardson 	return i;
156b3b413f7SBruce Richardson }
157b3b413f7SBruce Richardson 
158b3b413f7SBruce Richardson static uint16_t
159b3b413f7SBruce Richardson eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
160b3b413f7SBruce Richardson {
161b3b413f7SBruce Richardson 	int i;
162b3b413f7SBruce Richardson 	struct null_queue *h = q;
1634df90194SFerruh Yigit 	unsigned int packet_size;
164b3b413f7SBruce Richardson 
165b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
166b3b413f7SBruce Richardson 		return 0;
167b3b413f7SBruce Richardson 
168b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
169b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
170b3b413f7SBruce Richardson 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
171b3b413f7SBruce Richardson 					packet_size);
172b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
173b3b413f7SBruce Richardson 	}
174b3b413f7SBruce Richardson 
175b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
176b3b413f7SBruce Richardson 
177b3b413f7SBruce Richardson 	return i;
178b3b413f7SBruce Richardson }
179b3b413f7SBruce Richardson 
180b3b413f7SBruce Richardson static int
181c9634e44SFerruh Yigit eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
182c9634e44SFerruh Yigit {
183dd7c54a6STomasz Kulasek 	return 0;
184dd7c54a6STomasz Kulasek }
185b3b413f7SBruce Richardson 
186b3b413f7SBruce Richardson static int
187b3b413f7SBruce Richardson eth_dev_start(struct rte_eth_dev *dev)
188b3b413f7SBruce Richardson {
189b3b413f7SBruce Richardson 	if (dev == NULL)
190b3b413f7SBruce Richardson 		return -EINVAL;
191b3b413f7SBruce Richardson 
19209419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_UP;
193b3b413f7SBruce Richardson 	return 0;
194b3b413f7SBruce Richardson }
195b3b413f7SBruce Richardson 
19662024eb8SIvan Ilchenko static int
197b3b413f7SBruce Richardson eth_dev_stop(struct rte_eth_dev *dev)
198b3b413f7SBruce Richardson {
199b3b413f7SBruce Richardson 	if (dev == NULL)
20062024eb8SIvan Ilchenko 		return 0;
201b3b413f7SBruce Richardson 
20209419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
20362024eb8SIvan Ilchenko 
20462024eb8SIvan Ilchenko 	return 0;
205b3b413f7SBruce Richardson }
206b3b413f7SBruce Richardson 
207b3b413f7SBruce Richardson static int
208b3b413f7SBruce Richardson eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
209b3b413f7SBruce Richardson 		uint16_t nb_rx_desc __rte_unused,
210b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
211b3b413f7SBruce Richardson 		const struct rte_eth_rxconf *rx_conf __rte_unused,
212b3b413f7SBruce Richardson 		struct rte_mempool *mb_pool)
213b3b413f7SBruce Richardson {
214b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
215b3b413f7SBruce Richardson 	struct pmd_internals *internals;
2164df90194SFerruh Yigit 	unsigned int packet_size;
217b3b413f7SBruce Richardson 
218b3b413f7SBruce Richardson 	if ((dev == NULL) || (mb_pool == NULL))
219b3b413f7SBruce Richardson 		return -EINVAL;
220b3b413f7SBruce Richardson 
221dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
222dd7c54a6STomasz Kulasek 
223c9634e44SFerruh Yigit 	if (rx_queue_id >= dev->data->nb_rx_queues)
224b3b413f7SBruce Richardson 		return -ENODEV;
225b3b413f7SBruce Richardson 
226b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
227b3b413f7SBruce Richardson 
228b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
229b3b413f7SBruce Richardson 	dev->data->rx_queues[rx_queue_id] =
230b3b413f7SBruce Richardson 		&internals->rx_null_queues[rx_queue_id];
231b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
232c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
233b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
234b3b413f7SBruce Richardson 		return -ENOMEM;
235b3b413f7SBruce Richardson 
236b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].internals = internals;
237b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
238b3b413f7SBruce Richardson 
239b3b413f7SBruce Richardson 	return 0;
240b3b413f7SBruce Richardson }
241b3b413f7SBruce Richardson 
242b3b413f7SBruce Richardson static int
243b3b413f7SBruce Richardson eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
244b3b413f7SBruce Richardson 		uint16_t nb_tx_desc __rte_unused,
245b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
246b3b413f7SBruce Richardson 		const struct rte_eth_txconf *tx_conf __rte_unused)
247b3b413f7SBruce Richardson {
248b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
249b3b413f7SBruce Richardson 	struct pmd_internals *internals;
2504df90194SFerruh Yigit 	unsigned int packet_size;
251b3b413f7SBruce Richardson 
252b3b413f7SBruce Richardson 	if (dev == NULL)
253b3b413f7SBruce Richardson 		return -EINVAL;
254b3b413f7SBruce Richardson 
255dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
256dd7c54a6STomasz Kulasek 
257c9634e44SFerruh Yigit 	if (tx_queue_id >= dev->data->nb_tx_queues)
258b3b413f7SBruce Richardson 		return -ENODEV;
259b3b413f7SBruce Richardson 
260b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
261b3b413f7SBruce Richardson 
262b3b413f7SBruce Richardson 	dev->data->tx_queues[tx_queue_id] =
263b3b413f7SBruce Richardson 		&internals->tx_null_queues[tx_queue_id];
264b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
265c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
266b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
267b3b413f7SBruce Richardson 		return -ENOMEM;
268b3b413f7SBruce Richardson 
269b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].internals = internals;
270b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
271b3b413f7SBruce Richardson 
272b3b413f7SBruce Richardson 	return 0;
273b3b413f7SBruce Richardson }
274b3b413f7SBruce Richardson 
275e6acdc77SMallesh Koujalagi static int
276e6acdc77SMallesh Koujalagi eth_mtu_set(struct rte_eth_dev *dev __rte_unused, uint16_t mtu __rte_unused)
277e6acdc77SMallesh Koujalagi {
278e6acdc77SMallesh Koujalagi 	return 0;
279e6acdc77SMallesh Koujalagi }
280b3b413f7SBruce Richardson 
281bdad90d1SIvan Ilchenko static int
282b3b413f7SBruce Richardson eth_dev_info(struct rte_eth_dev *dev,
283b3b413f7SBruce Richardson 		struct rte_eth_dev_info *dev_info)
284b3b413f7SBruce Richardson {
285b3b413f7SBruce Richardson 	struct pmd_internals *internals;
286b3b413f7SBruce Richardson 
287b3b413f7SBruce Richardson 	if ((dev == NULL) || (dev_info == NULL))
288bdad90d1SIvan Ilchenko 		return -EINVAL;
289b3b413f7SBruce Richardson 
290b3b413f7SBruce Richardson 	internals = dev->data->dev_private;
291b3b413f7SBruce Richardson 	dev_info->max_mac_addrs = 1;
292b3b413f7SBruce Richardson 	dev_info->max_rx_pktlen = (uint32_t)-1;
293dd7c54a6STomasz Kulasek 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
294dd7c54a6STomasz Kulasek 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
295b3b413f7SBruce Richardson 	dev_info->min_rx_bufsize = 0;
2961ccec0a8STomasz Kulasek 	dev_info->reta_size = internals->reta_size;
2971ccec0a8STomasz Kulasek 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
298bdad90d1SIvan Ilchenko 
299bdad90d1SIvan Ilchenko 	return 0;
300b3b413f7SBruce Richardson }
301b3b413f7SBruce Richardson 
302d5b0924bSMatan Azrad static int
303b3b413f7SBruce Richardson eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
304b3b413f7SBruce Richardson {
3054df90194SFerruh Yigit 	unsigned int i, num_stats;
3069b6076a6SDavid Marchand 	unsigned long rx_total = 0, tx_total = 0;
307b3b413f7SBruce Richardson 	const struct pmd_internals *internal;
308b3b413f7SBruce Richardson 
309b3b413f7SBruce Richardson 	if ((dev == NULL) || (igb_stats == NULL))
310d5b0924bSMatan Azrad 		return -EINVAL;
311b3b413f7SBruce Richardson 
312b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
3134df90194SFerruh Yigit 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
314c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_rx_queues,
315b34141b2SBruce Richardson 				RTE_DIM(internal->rx_null_queues)));
316b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
317b3b413f7SBruce Richardson 		igb_stats->q_ipackets[i] =
318b3b413f7SBruce Richardson 			internal->rx_null_queues[i].rx_pkts.cnt;
319b3b413f7SBruce Richardson 		rx_total += igb_stats->q_ipackets[i];
320b3b413f7SBruce Richardson 	}
321b3b413f7SBruce Richardson 
3224df90194SFerruh Yigit 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
323c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_tx_queues,
324b34141b2SBruce Richardson 				RTE_DIM(internal->tx_null_queues)));
325b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
326b3b413f7SBruce Richardson 		igb_stats->q_opackets[i] =
327b3b413f7SBruce Richardson 			internal->tx_null_queues[i].tx_pkts.cnt;
328b3b413f7SBruce Richardson 		tx_total += igb_stats->q_opackets[i];
329b3b413f7SBruce Richardson 	}
330b3b413f7SBruce Richardson 
331b3b413f7SBruce Richardson 	igb_stats->ipackets = rx_total;
332b3b413f7SBruce Richardson 	igb_stats->opackets = tx_total;
333d5b0924bSMatan Azrad 
334d5b0924bSMatan Azrad 	return 0;
335b3b413f7SBruce Richardson }
336b3b413f7SBruce Richardson 
3379970a9adSIgor Romanov static int
338b3b413f7SBruce Richardson eth_stats_reset(struct rte_eth_dev *dev)
339b3b413f7SBruce Richardson {
3404df90194SFerruh Yigit 	unsigned int i;
341b3b413f7SBruce Richardson 	struct pmd_internals *internal;
342b3b413f7SBruce Richardson 
343b3b413f7SBruce Richardson 	if (dev == NULL)
3449970a9adSIgor Romanov 		return -EINVAL;
345b3b413f7SBruce Richardson 
346b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
347b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
348b3b413f7SBruce Richardson 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
3499b6076a6SDavid Marchand 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++)
350b3b413f7SBruce Richardson 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
3519970a9adSIgor Romanov 
3529970a9adSIgor Romanov 	return 0;
353b3b413f7SBruce Richardson }
354b3b413f7SBruce Richardson 
355b3b413f7SBruce Richardson static void
356b3b413f7SBruce Richardson eth_queue_release(void *q)
357b3b413f7SBruce Richardson {
358b3b413f7SBruce Richardson 	struct null_queue *nq;
359b3b413f7SBruce Richardson 
360b3b413f7SBruce Richardson 	if (q == NULL)
361b3b413f7SBruce Richardson 		return;
362b3b413f7SBruce Richardson 
363b3b413f7SBruce Richardson 	nq = q;
364b3b413f7SBruce Richardson 	rte_free(nq->dummy_packet);
365b3b413f7SBruce Richardson }
366b3b413f7SBruce Richardson 
367b3b413f7SBruce Richardson static int
368b3b413f7SBruce Richardson eth_link_update(struct rte_eth_dev *dev __rte_unused,
369b3b413f7SBruce Richardson 		int wait_to_complete __rte_unused) { return 0; }
370b3b413f7SBruce Richardson 
3711ccec0a8STomasz Kulasek static int
3721ccec0a8STomasz Kulasek eth_rss_reta_update(struct rte_eth_dev *dev,
3731ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
3741ccec0a8STomasz Kulasek {
3751ccec0a8STomasz Kulasek 	int i, j;
3761ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
3771ccec0a8STomasz Kulasek 
3781ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
3791ccec0a8STomasz Kulasek 		return -EINVAL;
3801ccec0a8STomasz Kulasek 
3811ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
3821ccec0a8STomasz Kulasek 
3831ccec0a8STomasz Kulasek 	/* Copy RETA table */
3841ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
3851ccec0a8STomasz Kulasek 		internal->reta_conf[i].mask = reta_conf[i].mask;
3861ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
3871ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
3881ccec0a8STomasz Kulasek 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
3891ccec0a8STomasz Kulasek 	}
3901ccec0a8STomasz Kulasek 
3911ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
3921ccec0a8STomasz Kulasek 
3931ccec0a8STomasz Kulasek 	return 0;
3941ccec0a8STomasz Kulasek }
3951ccec0a8STomasz Kulasek 
3961ccec0a8STomasz Kulasek static int
3971ccec0a8STomasz Kulasek eth_rss_reta_query(struct rte_eth_dev *dev,
3981ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
3991ccec0a8STomasz Kulasek {
4001ccec0a8STomasz Kulasek 	int i, j;
4011ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4021ccec0a8STomasz Kulasek 
4031ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
4041ccec0a8STomasz Kulasek 		return -EINVAL;
4051ccec0a8STomasz Kulasek 
4061ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4071ccec0a8STomasz Kulasek 
4081ccec0a8STomasz Kulasek 	/* Copy RETA table */
4091ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
4101ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
4111ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
4121ccec0a8STomasz Kulasek 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
4131ccec0a8STomasz Kulasek 	}
4141ccec0a8STomasz Kulasek 
4151ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4161ccec0a8STomasz Kulasek 
4171ccec0a8STomasz Kulasek 	return 0;
4181ccec0a8STomasz Kulasek }
4191ccec0a8STomasz Kulasek 
4201ccec0a8STomasz Kulasek static int
4211ccec0a8STomasz Kulasek eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
4221ccec0a8STomasz Kulasek {
4231ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4241ccec0a8STomasz Kulasek 
4251ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4261ccec0a8STomasz Kulasek 
4271ccec0a8STomasz Kulasek 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
4281ccec0a8STomasz Kulasek 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
4291ccec0a8STomasz Kulasek 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
4301ccec0a8STomasz Kulasek 
4311ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4321ccec0a8STomasz Kulasek 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
4331ccec0a8STomasz Kulasek 
4341ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4351ccec0a8STomasz Kulasek 
4361ccec0a8STomasz Kulasek 	return 0;
4371ccec0a8STomasz Kulasek }
4381ccec0a8STomasz Kulasek 
4391ccec0a8STomasz Kulasek static int
4401ccec0a8STomasz Kulasek eth_rss_hash_conf_get(struct rte_eth_dev *dev,
4411ccec0a8STomasz Kulasek 		struct rte_eth_rss_conf *rss_conf)
4421ccec0a8STomasz Kulasek {
4431ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4441ccec0a8STomasz Kulasek 
4451ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4461ccec0a8STomasz Kulasek 
4471ccec0a8STomasz Kulasek 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
4481ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4491ccec0a8STomasz Kulasek 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
4501ccec0a8STomasz Kulasek 
4511ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4521ccec0a8STomasz Kulasek 
4531ccec0a8STomasz Kulasek 	return 0;
4541ccec0a8STomasz Kulasek }
4551ccec0a8STomasz Kulasek 
456caccf8b3SOlivier Matz static int
457c5ac7748SRadu Nicolau eth_mac_address_set(__rte_unused struct rte_eth_dev *dev,
4586d13ea8eSOlivier Matz 		    __rte_unused struct rte_ether_addr *addr)
459c5ac7748SRadu Nicolau {
460caccf8b3SOlivier Matz 	return 0;
461c5ac7748SRadu Nicolau }
462c5ac7748SRadu Nicolau 
463d2fb7164SThomas Monjalon static int
464d2fb7164SThomas Monjalon eth_dev_close(struct rte_eth_dev *dev)
465d2fb7164SThomas Monjalon {
466d2fb7164SThomas Monjalon 	PMD_LOG(INFO, "Closing null ethdev on NUMA socket %u",
467d2fb7164SThomas Monjalon 			rte_socket_id());
468d2fb7164SThomas Monjalon 
469d2fb7164SThomas Monjalon 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
470d2fb7164SThomas Monjalon 		return 0;
471d2fb7164SThomas Monjalon 
472d2fb7164SThomas Monjalon 	/* mac_addrs must not be freed alone because part of dev_private */
473d2fb7164SThomas Monjalon 	dev->data->mac_addrs = NULL;
474d2fb7164SThomas Monjalon 
475d2fb7164SThomas Monjalon 	return 0;
476d2fb7164SThomas Monjalon }
477d2fb7164SThomas Monjalon 
478b3b413f7SBruce Richardson static const struct eth_dev_ops ops = {
479d2fb7164SThomas Monjalon 	.dev_close = eth_dev_close,
480b3b413f7SBruce Richardson 	.dev_start = eth_dev_start,
481b3b413f7SBruce Richardson 	.dev_stop = eth_dev_stop,
482b3b413f7SBruce Richardson 	.dev_configure = eth_dev_configure,
483b3b413f7SBruce Richardson 	.dev_infos_get = eth_dev_info,
484b3b413f7SBruce Richardson 	.rx_queue_setup = eth_rx_queue_setup,
485b3b413f7SBruce Richardson 	.tx_queue_setup = eth_tx_queue_setup,
486b3b413f7SBruce Richardson 	.rx_queue_release = eth_queue_release,
487b3b413f7SBruce Richardson 	.tx_queue_release = eth_queue_release,
488e6acdc77SMallesh Koujalagi 	.mtu_set = eth_mtu_set,
489b3b413f7SBruce Richardson 	.link_update = eth_link_update,
490c5ac7748SRadu Nicolau 	.mac_addr_set = eth_mac_address_set,
491b3b413f7SBruce Richardson 	.stats_get = eth_stats_get,
492b3b413f7SBruce Richardson 	.stats_reset = eth_stats_reset,
4931ccec0a8STomasz Kulasek 	.reta_update = eth_rss_reta_update,
4941ccec0a8STomasz Kulasek 	.reta_query = eth_rss_reta_query,
4951ccec0a8STomasz Kulasek 	.rss_hash_update = eth_rss_hash_update,
4961ccec0a8STomasz Kulasek 	.rss_hash_conf_get = eth_rss_hash_conf_get
497b3b413f7SBruce Richardson };
498b3b413f7SBruce Richardson 
499c3b047beSJan Blunck static int
500276bb4ceSFerruh Yigit eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
501b3b413f7SBruce Richardson {
5024df90194SFerruh Yigit 	const unsigned int nb_rx_queues = 1;
5034df90194SFerruh Yigit 	const unsigned int nb_tx_queues = 1;
5045f19dee6SJianfeng Tan 	struct rte_eth_dev_data *data;
505b3b413f7SBruce Richardson 	struct pmd_internals *internals = NULL;
506b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
507b3b413f7SBruce Richardson 
5081ccec0a8STomasz Kulasek 	static const uint8_t default_rss_key[40] = {
5091ccec0a8STomasz Kulasek 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
5101ccec0a8STomasz Kulasek 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
5111ccec0a8STomasz Kulasek 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
5121ccec0a8STomasz Kulasek 		0xBE, 0xAC, 0x01, 0xFA
5131ccec0a8STomasz Kulasek 	};
5141ccec0a8STomasz Kulasek 
515050fe6e9SJan Blunck 	if (dev->device.numa_node == SOCKET_ID_ANY)
516050fe6e9SJan Blunck 		dev->device.numa_node = rte_socket_id();
517b3b413f7SBruce Richardson 
518eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
519050fe6e9SJan Blunck 		dev->device.numa_node);
520b3b413f7SBruce Richardson 
5215f19dee6SJianfeng Tan 	eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
5225f19dee6SJianfeng Tan 	if (!eth_dev)
523050fe6e9SJan Blunck 		return -ENOMEM;
524b3b413f7SBruce Richardson 
525b3b413f7SBruce Richardson 	/* now put it all together
526b3b413f7SBruce Richardson 	 * - store queue data in internals,
5278fb9e2bbSBernard Iremonger 	 * - store numa_node info in ethdev data
5288fb9e2bbSBernard Iremonger 	 * - point eth_dev_data to internals
529b3b413f7SBruce Richardson 	 * - and point eth_dev structure to new eth_dev_data structure
530b3b413f7SBruce Richardson 	 */
531b3b413f7SBruce Richardson 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
532b3b413f7SBruce Richardson 	 * so the nulls are local per-process */
533b3b413f7SBruce Richardson 
534050fe6e9SJan Blunck 	internals = eth_dev->data->dev_private;
535276bb4ceSFerruh Yigit 	internals->packet_size = args->packet_size;
536276bb4ceSFerruh Yigit 	internals->packet_copy = args->packet_copy;
537f51ecf2fSFerruh Yigit 	internals->no_rx = args->no_rx;
5385cf86418SSean Harte 	internals->port_id = eth_dev->data->port_id;
539538da7a1SOlivier Matz 	rte_eth_random_addr(internals->eth_addr.addr_bytes);
540b3b413f7SBruce Richardson 
5411ccec0a8STomasz Kulasek 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
5421ccec0a8STomasz Kulasek 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
5431ccec0a8STomasz Kulasek 
5441ccec0a8STomasz Kulasek 	rte_memcpy(internals->rss_key, default_rss_key, 40);
5451ccec0a8STomasz Kulasek 
5465f19dee6SJianfeng Tan 	data = eth_dev->data;
547b3b413f7SBruce Richardson 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
548b3b413f7SBruce Richardson 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
549b3b413f7SBruce Richardson 	data->dev_link = pmd_link;
550c1cd6fb3SMallesh Koujalagi 	data->mac_addrs = &internals->eth_addr;
551f1652103SCiara Power 	data->promiscuous = 1;
552f1652103SCiara Power 	data->all_multicast = 1;
553*f30e69b4SFerruh Yigit 	data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
554b3b413f7SBruce Richardson 
555b3b413f7SBruce Richardson 	eth_dev->dev_ops = &ops;
5566799cfe4SBernard Iremonger 
557b3b413f7SBruce Richardson 	/* finally assign rx and tx ops */
558276bb4ceSFerruh Yigit 	if (internals->packet_copy) {
559b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
560b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
561f51ecf2fSFerruh Yigit 	} else if (internals->no_rx) {
562f51ecf2fSFerruh Yigit 		eth_dev->rx_pkt_burst = eth_null_no_rx;
563f51ecf2fSFerruh Yigit 		eth_dev->tx_pkt_burst = eth_null_tx;
564b3b413f7SBruce Richardson 	} else {
565b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_rx;
566b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_tx;
567b3b413f7SBruce Richardson 	}
568b3b413f7SBruce Richardson 
569fbe90cddSThomas Monjalon 	rte_eth_dev_probing_finish(eth_dev);
570b3b413f7SBruce Richardson 	return 0;
571b3b413f7SBruce Richardson }
572b3b413f7SBruce Richardson 
573b3b413f7SBruce Richardson static inline int
574b3b413f7SBruce Richardson get_packet_size_arg(const char *key __rte_unused,
575b3b413f7SBruce Richardson 		const char *value, void *extra_args)
576b3b413f7SBruce Richardson {
577b3b413f7SBruce Richardson 	const char *a = value;
5784df90194SFerruh Yigit 	unsigned int *packet_size = extra_args;
579b3b413f7SBruce Richardson 
580b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
581b3b413f7SBruce Richardson 		return -EINVAL;
582b3b413f7SBruce Richardson 
5834df90194SFerruh Yigit 	*packet_size = (unsigned int)strtoul(a, NULL, 0);
584b3b413f7SBruce Richardson 	if (*packet_size == UINT_MAX)
585b3b413f7SBruce Richardson 		return -1;
586b3b413f7SBruce Richardson 
587b3b413f7SBruce Richardson 	return 0;
588b3b413f7SBruce Richardson }
589b3b413f7SBruce Richardson 
590b3b413f7SBruce Richardson static inline int
591b3b413f7SBruce Richardson get_packet_copy_arg(const char *key __rte_unused,
592b3b413f7SBruce Richardson 		const char *value, void *extra_args)
593b3b413f7SBruce Richardson {
594b3b413f7SBruce Richardson 	const char *a = value;
5954df90194SFerruh Yigit 	unsigned int *packet_copy = extra_args;
596b3b413f7SBruce Richardson 
597b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
598b3b413f7SBruce Richardson 		return -EINVAL;
599b3b413f7SBruce Richardson 
6004df90194SFerruh Yigit 	*packet_copy = (unsigned int)strtoul(a, NULL, 0);
601b3b413f7SBruce Richardson 	if (*packet_copy == UINT_MAX)
602b3b413f7SBruce Richardson 		return -1;
603b3b413f7SBruce Richardson 
604b3b413f7SBruce Richardson 	return 0;
605b3b413f7SBruce Richardson }
606b3b413f7SBruce Richardson 
607b3b413f7SBruce Richardson static int
608f51ecf2fSFerruh Yigit get_packet_no_rx_arg(const char *key __rte_unused,
609f51ecf2fSFerruh Yigit 		const char *value, void *extra_args)
610f51ecf2fSFerruh Yigit {
611f51ecf2fSFerruh Yigit 	const char *a = value;
612f51ecf2fSFerruh Yigit 	unsigned int no_rx;
613f51ecf2fSFerruh Yigit 
614f51ecf2fSFerruh Yigit 	if (value == NULL || extra_args == NULL)
615f51ecf2fSFerruh Yigit 		return -EINVAL;
616f51ecf2fSFerruh Yigit 
617f51ecf2fSFerruh Yigit 	no_rx = (unsigned int)strtoul(a, NULL, 0);
618f51ecf2fSFerruh Yigit 	if (no_rx != 0 && no_rx != 1)
619f51ecf2fSFerruh Yigit 		return -1;
620f51ecf2fSFerruh Yigit 
621f51ecf2fSFerruh Yigit 	*(unsigned int *)extra_args = no_rx;
622f51ecf2fSFerruh Yigit 	return 0;
623f51ecf2fSFerruh Yigit }
624f51ecf2fSFerruh Yigit 
625f51ecf2fSFerruh Yigit static int
6265d2aa461SJan Blunck rte_pmd_null_probe(struct rte_vdev_device *dev)
627b3b413f7SBruce Richardson {
6285d2aa461SJan Blunck 	const char *name, *params;
629276bb4ceSFerruh Yigit 	struct pmd_options args = {
630276bb4ceSFerruh Yigit 		.packet_copy = default_packet_copy,
631276bb4ceSFerruh Yigit 		.packet_size = default_packet_size,
632f51ecf2fSFerruh Yigit 		.no_rx = default_no_rx,
633276bb4ceSFerruh Yigit 	};
634b3b413f7SBruce Richardson 	struct rte_kvargs *kvlist = NULL;
635ee27edbeSJianfeng Tan 	struct rte_eth_dev *eth_dev;
636b3b413f7SBruce Richardson 	int ret;
637b3b413f7SBruce Richardson 
6385d2aa461SJan Blunck 	if (!dev)
639b3b413f7SBruce Richardson 		return -EINVAL;
640b3b413f7SBruce Richardson 
6415d2aa461SJan Blunck 	name = rte_vdev_device_name(dev);
6425d2aa461SJan Blunck 	params = rte_vdev_device_args(dev);
643eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Initializing pmd_null for %s", name);
644b3b413f7SBruce Richardson 
6454852aa8fSQi Zhang 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
646e2f4b250SFerruh Yigit 		struct pmd_internals *internals;
647ee27edbeSJianfeng Tan 		eth_dev = rte_eth_dev_attach_secondary(name);
648ee27edbeSJianfeng Tan 		if (!eth_dev) {
649eb16afb9SStephen Hemminger 			PMD_LOG(ERR, "Failed to probe %s", name);
650ee27edbeSJianfeng Tan 			return -1;
651ee27edbeSJianfeng Tan 		}
652ee27edbeSJianfeng Tan 		/* TODO: request info from primary to set up Rx and Tx */
653ee27edbeSJianfeng Tan 		eth_dev->dev_ops = &ops;
654d1c3ab22SFerruh Yigit 		eth_dev->device = &dev->device;
655e2f4b250SFerruh Yigit 		internals = eth_dev->data->dev_private;
656e2f4b250SFerruh Yigit 		if (internals->packet_copy) {
657bccc77a6SYasufumi Ogawa 			eth_dev->rx_pkt_burst = eth_null_copy_rx;
658bccc77a6SYasufumi Ogawa 			eth_dev->tx_pkt_burst = eth_null_copy_tx;
659f51ecf2fSFerruh Yigit 		} else if (internals->no_rx) {
660f51ecf2fSFerruh Yigit 			eth_dev->rx_pkt_burst = eth_null_no_rx;
661f51ecf2fSFerruh Yigit 			eth_dev->tx_pkt_burst = eth_null_tx;
662bccc77a6SYasufumi Ogawa 		} else {
663bccc77a6SYasufumi Ogawa 			eth_dev->rx_pkt_burst = eth_null_rx;
664bccc77a6SYasufumi Ogawa 			eth_dev->tx_pkt_burst = eth_null_tx;
665bccc77a6SYasufumi Ogawa 		}
666fbe90cddSThomas Monjalon 		rte_eth_dev_probing_finish(eth_dev);
667ee27edbeSJianfeng Tan 		return 0;
668ee27edbeSJianfeng Tan 	}
669ee27edbeSJianfeng Tan 
670b3b413f7SBruce Richardson 	if (params != NULL) {
671b3b413f7SBruce Richardson 		kvlist = rte_kvargs_parse(params, valid_arguments);
672b3b413f7SBruce Richardson 		if (kvlist == NULL)
673b3b413f7SBruce Richardson 			return -1;
674b3b413f7SBruce Richardson 
675b3b413f7SBruce Richardson 		ret = rte_kvargs_process(kvlist,
676b3b413f7SBruce Richardson 				ETH_NULL_PACKET_SIZE_ARG,
677276bb4ceSFerruh Yigit 				&get_packet_size_arg, &args.packet_size);
678b3b413f7SBruce Richardson 		if (ret < 0)
679b3b413f7SBruce Richardson 			goto free_kvlist;
680b3b413f7SBruce Richardson 
681b3b413f7SBruce Richardson 
682b3b413f7SBruce Richardson 		ret = rte_kvargs_process(kvlist,
683b3b413f7SBruce Richardson 				ETH_NULL_PACKET_COPY_ARG,
684276bb4ceSFerruh Yigit 				&get_packet_copy_arg, &args.packet_copy);
685b3b413f7SBruce Richardson 		if (ret < 0)
686b3b413f7SBruce Richardson 			goto free_kvlist;
687f51ecf2fSFerruh Yigit 
688f51ecf2fSFerruh Yigit 		ret = rte_kvargs_process(kvlist,
689f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_NO_RX_ARG,
690f51ecf2fSFerruh Yigit 				&get_packet_no_rx_arg, &args.no_rx);
691f51ecf2fSFerruh Yigit 		if (ret < 0)
692f51ecf2fSFerruh Yigit 			goto free_kvlist;
693f51ecf2fSFerruh Yigit 
694f51ecf2fSFerruh Yigit 		if (args.no_rx && args.packet_copy) {
695f51ecf2fSFerruh Yigit 			PMD_LOG(ERR,
696f51ecf2fSFerruh Yigit 				"Both %s and %s arguments at the same time not supported",
697f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_COPY_ARG,
698f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_NO_RX_ARG);
699f51ecf2fSFerruh Yigit 			goto free_kvlist;
700f51ecf2fSFerruh Yigit 		}
701b3b413f7SBruce Richardson 	}
702b3b413f7SBruce Richardson 
703eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
704276bb4ceSFerruh Yigit 			"packet copy is %s", args.packet_size,
705276bb4ceSFerruh Yigit 			args.packet_copy ? "enabled" : "disabled");
706b3b413f7SBruce Richardson 
707276bb4ceSFerruh Yigit 	ret = eth_dev_null_create(dev, &args);
708b3b413f7SBruce Richardson 
709b3b413f7SBruce Richardson free_kvlist:
710b3b413f7SBruce Richardson 	if (kvlist)
711b3b413f7SBruce Richardson 		rte_kvargs_free(kvlist);
712b3b413f7SBruce Richardson 	return ret;
713b3b413f7SBruce Richardson }
714b3b413f7SBruce Richardson 
715b3b413f7SBruce Richardson static int
7165d2aa461SJan Blunck rte_pmd_null_remove(struct rte_vdev_device *dev)
717b3b413f7SBruce Richardson {
718b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
719b3b413f7SBruce Richardson 
7205d2aa461SJan Blunck 	if (!dev)
721b3b413f7SBruce Richardson 		return -EINVAL;
722b3b413f7SBruce Richardson 
7236799cfe4SBernard Iremonger 	/* find the ethdev entry */
7245d2aa461SJan Blunck 	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
725b3b413f7SBruce Richardson 	if (eth_dev == NULL)
726d2fb7164SThomas Monjalon 		return 0; /* port already released */
727b3b413f7SBruce Richardson 
728d2fb7164SThomas Monjalon 	eth_dev_close(eth_dev);
729b3b413f7SBruce Richardson 	rte_eth_dev_release_port(eth_dev);
730b3b413f7SBruce Richardson 
731b3b413f7SBruce Richardson 	return 0;
732b3b413f7SBruce Richardson }
733b3b413f7SBruce Richardson 
734fe363dd4SJan Viktorin static struct rte_vdev_driver pmd_null_drv = {
73550a3345fSShreyansh Jain 	.probe = rte_pmd_null_probe,
73650a3345fSShreyansh Jain 	.remove = rte_pmd_null_remove,
737b3b413f7SBruce Richardson };
738b3b413f7SBruce Richardson 
73901f19227SShreyansh Jain RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
7409fa80cb2SJan Blunck RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
74101f19227SShreyansh Jain RTE_PMD_REGISTER_PARAM_STRING(net_null,
74265eca099SPablo de Lara 	"size=<int> "
743f51ecf2fSFerruh Yigit 	"copy=<int> "
744f51ecf2fSFerruh Yigit 	ETH_NULL_PACKET_NO_RX_ARG "=0|1");
745