xref: /dpdk/drivers/net/null/rte_eth_null.c (revision 2b843cac232eb3f2fa79e4254e21766817e2019f)
16fc581e9SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2b3b413f7SBruce Richardson  * Copyright (C) IGEL Co.,Ltd.
3b3b413f7SBruce Richardson  *  All rights reserved.
4b3b413f7SBruce Richardson  */
5b3b413f7SBruce Richardson 
672b452c5SDmitry Kozlyuk #include <stdlib.h>
772b452c5SDmitry Kozlyuk 
8b3b413f7SBruce Richardson #include <rte_mbuf.h>
9df96fd0dSBruce Richardson #include <ethdev_driver.h>
10df96fd0dSBruce Richardson #include <ethdev_vdev.h>
11b3b413f7SBruce Richardson #include <rte_malloc.h>
12b3b413f7SBruce Richardson #include <rte_memcpy.h>
134851ef2bSDavid Marchand #include <bus_vdev_driver.h>
14b3b413f7SBruce Richardson #include <rte_kvargs.h>
151ccec0a8STomasz Kulasek #include <rte_spinlock.h>
16b3b413f7SBruce Richardson 
17b3b413f7SBruce Richardson #define ETH_NULL_PACKET_SIZE_ARG	"size"
18b3b413f7SBruce Richardson #define ETH_NULL_PACKET_COPY_ARG	"copy"
19f51ecf2fSFerruh Yigit #define ETH_NULL_PACKET_NO_RX_ARG	"no-rx"
20b3b413f7SBruce Richardson 
214df90194SFerruh Yigit static unsigned int default_packet_size = 64;
224df90194SFerruh Yigit static unsigned int default_packet_copy;
23f51ecf2fSFerruh Yigit static unsigned int default_no_rx;
24b3b413f7SBruce Richardson 
25b3b413f7SBruce Richardson static const char *valid_arguments[] = {
26b3b413f7SBruce Richardson 	ETH_NULL_PACKET_SIZE_ARG,
27b3b413f7SBruce Richardson 	ETH_NULL_PACKET_COPY_ARG,
28f51ecf2fSFerruh Yigit 	ETH_NULL_PACKET_NO_RX_ARG,
29b3b413f7SBruce Richardson 	NULL
30b3b413f7SBruce Richardson };
31b3b413f7SBruce Richardson 
32b3b413f7SBruce Richardson struct pmd_internals;
33b3b413f7SBruce Richardson 
34b3b413f7SBruce Richardson struct null_queue {
35b3b413f7SBruce Richardson 	struct pmd_internals *internals;
36b3b413f7SBruce Richardson 
37b3b413f7SBruce Richardson 	struct rte_mempool *mb_pool;
38b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
39b3b413f7SBruce Richardson 
40e12a0166STyler Retzlaff 	RTE_ATOMIC(uint64_t) rx_pkts;
41e12a0166STyler Retzlaff 	RTE_ATOMIC(uint64_t) tx_pkts;
42b3b413f7SBruce Richardson };
43b3b413f7SBruce Richardson 
44276bb4ceSFerruh Yigit struct pmd_options {
45276bb4ceSFerruh Yigit 	unsigned int packet_copy;
46276bb4ceSFerruh Yigit 	unsigned int packet_size;
47f51ecf2fSFerruh Yigit 	unsigned int no_rx;
48276bb4ceSFerruh Yigit };
49276bb4ceSFerruh Yigit 
50b3b413f7SBruce Richardson struct pmd_internals {
514df90194SFerruh Yigit 	unsigned int packet_size;
524df90194SFerruh Yigit 	unsigned int packet_copy;
53f51ecf2fSFerruh Yigit 	unsigned int no_rx;
54f8244c63SZhiyong Yang 	uint16_t port_id;
55b3b413f7SBruce Richardson 
56dd7c54a6STomasz Kulasek 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
57dd7c54a6STomasz Kulasek 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
581ccec0a8STomasz Kulasek 
596d13ea8eSOlivier Matz 	struct rte_ether_addr eth_addr;
601ccec0a8STomasz Kulasek 	/** Bit mask of RSS offloads, the bit offset also means flow type */
611ccec0a8STomasz Kulasek 	uint64_t flow_type_rss_offloads;
621ccec0a8STomasz Kulasek 
631ccec0a8STomasz Kulasek 	rte_spinlock_t rss_lock;
641ccec0a8STomasz Kulasek 
651ccec0a8STomasz Kulasek 	uint16_t reta_size;
66295968d1SFerruh Yigit 	struct rte_eth_rss_reta_entry64 reta_conf[RTE_ETH_RSS_RETA_SIZE_128 /
67295968d1SFerruh Yigit 			RTE_ETH_RETA_GROUP_SIZE];
681ccec0a8STomasz Kulasek 
691ccec0a8STomasz Kulasek 	uint8_t rss_key[40];                /**< 40-byte hash key. */
70b3b413f7SBruce Richardson };
71b3b413f7SBruce Richardson static struct rte_eth_link pmd_link = {
72295968d1SFerruh Yigit 	.link_speed = RTE_ETH_SPEED_NUM_10G,
73295968d1SFerruh Yigit 	.link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
74295968d1SFerruh Yigit 	.link_status = RTE_ETH_LINK_DOWN,
75295968d1SFerruh Yigit 	.link_autoneg = RTE_ETH_LINK_FIXED,
76b3b413f7SBruce Richardson };
77b3b413f7SBruce Richardson 
78eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(eth_null_logtype, NOTICE);
79*2b843cacSDavid Marchand #define RTE_LOGTYPE_ETH_NULL eth_null_logtype
80eb16afb9SStephen Hemminger 
81*2b843cacSDavid Marchand #define PMD_LOG(level, ...) \
82*2b843cacSDavid Marchand 	RTE_LOG_LINE_PREFIX(level, ETH_NULL, "%s(): ", __func__, __VA_ARGS__)
83eb16afb9SStephen Hemminger 
84b3b413f7SBruce Richardson static uint16_t
85b3b413f7SBruce Richardson eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
86b3b413f7SBruce Richardson {
87b3b413f7SBruce Richardson 	int i;
88b3b413f7SBruce Richardson 	struct null_queue *h = q;
894df90194SFerruh Yigit 	unsigned int packet_size;
90b3b413f7SBruce Richardson 
91b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
92b3b413f7SBruce Richardson 		return 0;
93b3b413f7SBruce Richardson 
94b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
954e436ddaSMallesh Koujalagi 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
964e436ddaSMallesh Koujalagi 		return 0;
974e436ddaSMallesh Koujalagi 
98b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
99b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
100b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
1015cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
102b3b413f7SBruce Richardson 	}
103b3b413f7SBruce Richardson 
104c8881beeSTyler Retzlaff 	/* NOTE: review for potential ordering optimization */
105e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&h->rx_pkts, i, rte_memory_order_seq_cst);
106b3b413f7SBruce Richardson 
107b3b413f7SBruce Richardson 	return i;
108b3b413f7SBruce Richardson }
109b3b413f7SBruce Richardson 
110b3b413f7SBruce Richardson static uint16_t
111b3b413f7SBruce Richardson eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
112b3b413f7SBruce Richardson {
113b3b413f7SBruce Richardson 	int i;
114b3b413f7SBruce Richardson 	struct null_queue *h = q;
1154df90194SFerruh Yigit 	unsigned int packet_size;
116b3b413f7SBruce Richardson 
117b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
118b3b413f7SBruce Richardson 		return 0;
119b3b413f7SBruce Richardson 
120b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
1214e436ddaSMallesh Koujalagi 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
1224e436ddaSMallesh Koujalagi 		return 0;
1234e436ddaSMallesh Koujalagi 
124b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
125b3b413f7SBruce Richardson 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
126b3b413f7SBruce Richardson 					packet_size);
127b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
128b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
1295cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
130b3b413f7SBruce Richardson 	}
131b3b413f7SBruce Richardson 
132c8881beeSTyler Retzlaff 	/* NOTE: review for potential ordering optimization */
133e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&h->rx_pkts, i, rte_memory_order_seq_cst);
134b3b413f7SBruce Richardson 
135b3b413f7SBruce Richardson 	return i;
136b3b413f7SBruce Richardson }
137b3b413f7SBruce Richardson 
138b3b413f7SBruce Richardson static uint16_t
139f51ecf2fSFerruh Yigit eth_null_no_rx(void *q __rte_unused, struct rte_mbuf **bufs __rte_unused,
140f51ecf2fSFerruh Yigit 		uint16_t nb_bufs __rte_unused)
141f51ecf2fSFerruh Yigit {
142f51ecf2fSFerruh Yigit 	return 0;
143f51ecf2fSFerruh Yigit }
144f51ecf2fSFerruh Yigit 
145f51ecf2fSFerruh Yigit static uint16_t
146b3b413f7SBruce Richardson eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
147b3b413f7SBruce Richardson {
148b3b413f7SBruce Richardson 	int i;
149b3b413f7SBruce Richardson 	struct null_queue *h = q;
150b3b413f7SBruce Richardson 
151b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
152b3b413f7SBruce Richardson 		return 0;
153b3b413f7SBruce Richardson 
154b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++)
155b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
156b3b413f7SBruce Richardson 
157c8881beeSTyler Retzlaff 	/* NOTE: review for potential ordering optimization */
158e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&h->tx_pkts, i, rte_memory_order_seq_cst);
159b3b413f7SBruce Richardson 
160b3b413f7SBruce Richardson 	return i;
161b3b413f7SBruce Richardson }
162b3b413f7SBruce Richardson 
163b3b413f7SBruce Richardson static uint16_t
164b3b413f7SBruce Richardson eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
165b3b413f7SBruce Richardson {
166b3b413f7SBruce Richardson 	int i;
167b3b413f7SBruce Richardson 	struct null_queue *h = q;
1684df90194SFerruh Yigit 	unsigned int packet_size;
169b3b413f7SBruce Richardson 
170b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
171b3b413f7SBruce Richardson 		return 0;
172b3b413f7SBruce Richardson 
173b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
174b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
175b3b413f7SBruce Richardson 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
176b3b413f7SBruce Richardson 					packet_size);
177b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
178b3b413f7SBruce Richardson 	}
179b3b413f7SBruce Richardson 
180c8881beeSTyler Retzlaff 	/* NOTE: review for potential ordering optimization */
181e12a0166STyler Retzlaff 	rte_atomic_fetch_add_explicit(&h->tx_pkts, i, rte_memory_order_seq_cst);
182b3b413f7SBruce Richardson 
183b3b413f7SBruce Richardson 	return i;
184b3b413f7SBruce Richardson }
185b3b413f7SBruce Richardson 
186b3b413f7SBruce Richardson static int
187c9634e44SFerruh Yigit eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
188c9634e44SFerruh Yigit {
189dd7c54a6STomasz Kulasek 	return 0;
190dd7c54a6STomasz Kulasek }
191b3b413f7SBruce Richardson 
192b3b413f7SBruce Richardson static int
193b3b413f7SBruce Richardson eth_dev_start(struct rte_eth_dev *dev)
194b3b413f7SBruce Richardson {
1959b4b368eSJie Hai 	uint16_t i;
1969b4b368eSJie Hai 
197b3b413f7SBruce Richardson 	if (dev == NULL)
198b3b413f7SBruce Richardson 		return -EINVAL;
199b3b413f7SBruce Richardson 
200295968d1SFerruh Yigit 	dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
2019b4b368eSJie Hai 
2029b4b368eSJie Hai 	for (i = 0; i < dev->data->nb_rx_queues; i++)
2039b4b368eSJie Hai 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
2049b4b368eSJie Hai 	for (i = 0; i < dev->data->nb_tx_queues; i++)
2059b4b368eSJie Hai 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
2069b4b368eSJie Hai 
207b3b413f7SBruce Richardson 	return 0;
208b3b413f7SBruce Richardson }
209b3b413f7SBruce Richardson 
21062024eb8SIvan Ilchenko static int
211b3b413f7SBruce Richardson eth_dev_stop(struct rte_eth_dev *dev)
212b3b413f7SBruce Richardson {
2139b4b368eSJie Hai 	uint16_t i;
2149b4b368eSJie Hai 
215b3b413f7SBruce Richardson 	if (dev == NULL)
21662024eb8SIvan Ilchenko 		return 0;
217b3b413f7SBruce Richardson 
218295968d1SFerruh Yigit 	dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
21962024eb8SIvan Ilchenko 
2209b4b368eSJie Hai 	for (i = 0; i < dev->data->nb_rx_queues; i++)
2219b4b368eSJie Hai 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
2229b4b368eSJie Hai 	for (i = 0; i < dev->data->nb_tx_queues; i++)
2239b4b368eSJie Hai 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
2249b4b368eSJie Hai 
22562024eb8SIvan Ilchenko 	return 0;
226b3b413f7SBruce Richardson }
227b3b413f7SBruce Richardson 
228b3b413f7SBruce Richardson static int
229b3b413f7SBruce Richardson eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
230b3b413f7SBruce Richardson 		uint16_t nb_rx_desc __rte_unused,
231b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
232b3b413f7SBruce Richardson 		const struct rte_eth_rxconf *rx_conf __rte_unused,
233b3b413f7SBruce Richardson 		struct rte_mempool *mb_pool)
234b3b413f7SBruce Richardson {
235b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
236b3b413f7SBruce Richardson 	struct pmd_internals *internals;
2374df90194SFerruh Yigit 	unsigned int packet_size;
238b3b413f7SBruce Richardson 
239b3b413f7SBruce Richardson 	if ((dev == NULL) || (mb_pool == NULL))
240b3b413f7SBruce Richardson 		return -EINVAL;
241b3b413f7SBruce Richardson 
242dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
243dd7c54a6STomasz Kulasek 
244c9634e44SFerruh Yigit 	if (rx_queue_id >= dev->data->nb_rx_queues)
245b3b413f7SBruce Richardson 		return -ENODEV;
246b3b413f7SBruce Richardson 
247b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
248b3b413f7SBruce Richardson 
249b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
250b3b413f7SBruce Richardson 	dev->data->rx_queues[rx_queue_id] =
251b3b413f7SBruce Richardson 		&internals->rx_null_queues[rx_queue_id];
252b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
253c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
254b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
255b3b413f7SBruce Richardson 		return -ENOMEM;
256b3b413f7SBruce Richardson 
257b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].internals = internals;
258b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
259b3b413f7SBruce Richardson 
260b3b413f7SBruce Richardson 	return 0;
261b3b413f7SBruce Richardson }
262b3b413f7SBruce Richardson 
263b3b413f7SBruce Richardson static int
264b3b413f7SBruce Richardson eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
265b3b413f7SBruce Richardson 		uint16_t nb_tx_desc __rte_unused,
266b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
267b3b413f7SBruce Richardson 		const struct rte_eth_txconf *tx_conf __rte_unused)
268b3b413f7SBruce Richardson {
269b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
270b3b413f7SBruce Richardson 	struct pmd_internals *internals;
2714df90194SFerruh Yigit 	unsigned int packet_size;
272b3b413f7SBruce Richardson 
273b3b413f7SBruce Richardson 	if (dev == NULL)
274b3b413f7SBruce Richardson 		return -EINVAL;
275b3b413f7SBruce Richardson 
276dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
277dd7c54a6STomasz Kulasek 
278c9634e44SFerruh Yigit 	if (tx_queue_id >= dev->data->nb_tx_queues)
279b3b413f7SBruce Richardson 		return -ENODEV;
280b3b413f7SBruce Richardson 
281b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
282b3b413f7SBruce Richardson 
283b3b413f7SBruce Richardson 	dev->data->tx_queues[tx_queue_id] =
284b3b413f7SBruce Richardson 		&internals->tx_null_queues[tx_queue_id];
285b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
286c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
287b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
288b3b413f7SBruce Richardson 		return -ENOMEM;
289b3b413f7SBruce Richardson 
290b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].internals = internals;
291b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
292b3b413f7SBruce Richardson 
293b3b413f7SBruce Richardson 	return 0;
294b3b413f7SBruce Richardson }
295b3b413f7SBruce Richardson 
296e6acdc77SMallesh Koujalagi static int
297e6acdc77SMallesh Koujalagi eth_mtu_set(struct rte_eth_dev *dev __rte_unused, uint16_t mtu __rte_unused)
298e6acdc77SMallesh Koujalagi {
299e6acdc77SMallesh Koujalagi 	return 0;
300e6acdc77SMallesh Koujalagi }
301b3b413f7SBruce Richardson 
302bdad90d1SIvan Ilchenko static int
303b3b413f7SBruce Richardson eth_dev_info(struct rte_eth_dev *dev,
304b3b413f7SBruce Richardson 		struct rte_eth_dev_info *dev_info)
305b3b413f7SBruce Richardson {
306b3b413f7SBruce Richardson 	struct pmd_internals *internals;
307b3b413f7SBruce Richardson 
308b3b413f7SBruce Richardson 	if ((dev == NULL) || (dev_info == NULL))
309bdad90d1SIvan Ilchenko 		return -EINVAL;
310b3b413f7SBruce Richardson 
311b3b413f7SBruce Richardson 	internals = dev->data->dev_private;
312b3b413f7SBruce Richardson 	dev_info->max_mac_addrs = 1;
313b3b413f7SBruce Richardson 	dev_info->max_rx_pktlen = (uint32_t)-1;
314dd7c54a6STomasz Kulasek 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
315dd7c54a6STomasz Kulasek 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
316b3b413f7SBruce Richardson 	dev_info->min_rx_bufsize = 0;
3171ccec0a8STomasz Kulasek 	dev_info->reta_size = internals->reta_size;
3181ccec0a8STomasz Kulasek 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
319a54db8d3SJie Hai 	dev_info->hash_key_size = sizeof(internals->rss_key);
320bdad90d1SIvan Ilchenko 
321bdad90d1SIvan Ilchenko 	return 0;
322b3b413f7SBruce Richardson }
323b3b413f7SBruce Richardson 
324d5b0924bSMatan Azrad static int
325b3b413f7SBruce Richardson eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
326b3b413f7SBruce Richardson {
3274df90194SFerruh Yigit 	unsigned int i, num_stats;
3289b6076a6SDavid Marchand 	unsigned long rx_total = 0, tx_total = 0;
329b3b413f7SBruce Richardson 	const struct pmd_internals *internal;
330b3b413f7SBruce Richardson 
331b3b413f7SBruce Richardson 	if ((dev == NULL) || (igb_stats == NULL))
332d5b0924bSMatan Azrad 		return -EINVAL;
333b3b413f7SBruce Richardson 
334b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
3354df90194SFerruh Yigit 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
336c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_rx_queues,
337b34141b2SBruce Richardson 				RTE_DIM(internal->rx_null_queues)));
338b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
339c8881beeSTyler Retzlaff 		/* NOTE: review for atomic access */
340b3b413f7SBruce Richardson 		igb_stats->q_ipackets[i] =
341c8881beeSTyler Retzlaff 			internal->rx_null_queues[i].rx_pkts;
342b3b413f7SBruce Richardson 		rx_total += igb_stats->q_ipackets[i];
343b3b413f7SBruce Richardson 	}
344b3b413f7SBruce Richardson 
3454df90194SFerruh Yigit 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
346c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_tx_queues,
347b34141b2SBruce Richardson 				RTE_DIM(internal->tx_null_queues)));
348b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
349c8881beeSTyler Retzlaff 		/* NOTE: review for atomic access */
350b3b413f7SBruce Richardson 		igb_stats->q_opackets[i] =
351c8881beeSTyler Retzlaff 			internal->tx_null_queues[i].tx_pkts;
352b3b413f7SBruce Richardson 		tx_total += igb_stats->q_opackets[i];
353b3b413f7SBruce Richardson 	}
354b3b413f7SBruce Richardson 
355b3b413f7SBruce Richardson 	igb_stats->ipackets = rx_total;
356b3b413f7SBruce Richardson 	igb_stats->opackets = tx_total;
357d5b0924bSMatan Azrad 
358d5b0924bSMatan Azrad 	return 0;
359b3b413f7SBruce Richardson }
360b3b413f7SBruce Richardson 
3619970a9adSIgor Romanov static int
362b3b413f7SBruce Richardson eth_stats_reset(struct rte_eth_dev *dev)
363b3b413f7SBruce Richardson {
3644df90194SFerruh Yigit 	unsigned int i;
365b3b413f7SBruce Richardson 	struct pmd_internals *internal;
366b3b413f7SBruce Richardson 
367b3b413f7SBruce Richardson 	if (dev == NULL)
3689970a9adSIgor Romanov 		return -EINVAL;
369b3b413f7SBruce Richardson 
370b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
371b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
372c8881beeSTyler Retzlaff 		/* NOTE: review for atomic access */
373c8881beeSTyler Retzlaff 		internal->rx_null_queues[i].rx_pkts = 0;
3749b6076a6SDavid Marchand 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++)
375c8881beeSTyler Retzlaff 		/* NOTE: review for atomic access */
376c8881beeSTyler Retzlaff 		internal->tx_null_queues[i].tx_pkts = 0;
3779970a9adSIgor Romanov 
3789970a9adSIgor Romanov 	return 0;
379b3b413f7SBruce Richardson }
380b3b413f7SBruce Richardson 
381b3b413f7SBruce Richardson static void
3827483341aSXueming Li eth_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
383b3b413f7SBruce Richardson {
3847483341aSXueming Li 	struct null_queue *nq = dev->data->rx_queues[qid];
385b3b413f7SBruce Richardson 
3867483341aSXueming Li 	if (nq == NULL)
387b3b413f7SBruce Richardson 		return;
388b3b413f7SBruce Richardson 
3897483341aSXueming Li 	rte_free(nq->dummy_packet);
3907483341aSXueming Li }
3917483341aSXueming Li 
3927483341aSXueming Li static void
3937483341aSXueming Li eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
3947483341aSXueming Li {
3957483341aSXueming Li 	struct null_queue *nq = dev->data->tx_queues[qid];
3967483341aSXueming Li 
3977483341aSXueming Li 	if (nq == NULL)
3987483341aSXueming Li 		return;
3997483341aSXueming Li 
400b3b413f7SBruce Richardson 	rte_free(nq->dummy_packet);
401b3b413f7SBruce Richardson }
402b3b413f7SBruce Richardson 
403b3b413f7SBruce Richardson static int
404b3b413f7SBruce Richardson eth_link_update(struct rte_eth_dev *dev __rte_unused,
405b3b413f7SBruce Richardson 		int wait_to_complete __rte_unused) { return 0; }
406b3b413f7SBruce Richardson 
4071ccec0a8STomasz Kulasek static int
4081ccec0a8STomasz Kulasek eth_rss_reta_update(struct rte_eth_dev *dev,
4091ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
4101ccec0a8STomasz Kulasek {
4111ccec0a8STomasz Kulasek 	int i, j;
4121ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4131ccec0a8STomasz Kulasek 
4141ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
4151ccec0a8STomasz Kulasek 		return -EINVAL;
4161ccec0a8STomasz Kulasek 
4171ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4181ccec0a8STomasz Kulasek 
4191ccec0a8STomasz Kulasek 	/* Copy RETA table */
420295968d1SFerruh Yigit 	for (i = 0; i < (internal->reta_size / RTE_ETH_RETA_GROUP_SIZE); i++) {
4211ccec0a8STomasz Kulasek 		internal->reta_conf[i].mask = reta_conf[i].mask;
422295968d1SFerruh Yigit 		for (j = 0; j < RTE_ETH_RETA_GROUP_SIZE; j++)
4231ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
4241ccec0a8STomasz Kulasek 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
4251ccec0a8STomasz Kulasek 	}
4261ccec0a8STomasz Kulasek 
4271ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4281ccec0a8STomasz Kulasek 
4291ccec0a8STomasz Kulasek 	return 0;
4301ccec0a8STomasz Kulasek }
4311ccec0a8STomasz Kulasek 
4321ccec0a8STomasz Kulasek static int
4331ccec0a8STomasz Kulasek eth_rss_reta_query(struct rte_eth_dev *dev,
4341ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
4351ccec0a8STomasz Kulasek {
4361ccec0a8STomasz Kulasek 	int i, j;
4371ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4381ccec0a8STomasz Kulasek 
4391ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
4401ccec0a8STomasz Kulasek 		return -EINVAL;
4411ccec0a8STomasz Kulasek 
4421ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4431ccec0a8STomasz Kulasek 
4441ccec0a8STomasz Kulasek 	/* Copy RETA table */
445295968d1SFerruh Yigit 	for (i = 0; i < (internal->reta_size / RTE_ETH_RETA_GROUP_SIZE); i++) {
446295968d1SFerruh Yigit 		for (j = 0; j < RTE_ETH_RETA_GROUP_SIZE; j++)
4471ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
4481ccec0a8STomasz Kulasek 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
4491ccec0a8STomasz Kulasek 	}
4501ccec0a8STomasz Kulasek 
4511ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4521ccec0a8STomasz Kulasek 
4531ccec0a8STomasz Kulasek 	return 0;
4541ccec0a8STomasz Kulasek }
4551ccec0a8STomasz Kulasek 
4561ccec0a8STomasz Kulasek static int
4571ccec0a8STomasz Kulasek eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
4581ccec0a8STomasz Kulasek {
4591ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4601ccec0a8STomasz Kulasek 
4611ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4621ccec0a8STomasz Kulasek 
4631ccec0a8STomasz Kulasek 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
4641ccec0a8STomasz Kulasek 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
4651ccec0a8STomasz Kulasek 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
4661ccec0a8STomasz Kulasek 
4671ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4681ccec0a8STomasz Kulasek 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
4691ccec0a8STomasz Kulasek 
4701ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4711ccec0a8STomasz Kulasek 
4721ccec0a8STomasz Kulasek 	return 0;
4731ccec0a8STomasz Kulasek }
4741ccec0a8STomasz Kulasek 
4751ccec0a8STomasz Kulasek static int
4761ccec0a8STomasz Kulasek eth_rss_hash_conf_get(struct rte_eth_dev *dev,
4771ccec0a8STomasz Kulasek 		struct rte_eth_rss_conf *rss_conf)
4781ccec0a8STomasz Kulasek {
4791ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4801ccec0a8STomasz Kulasek 
4811ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4821ccec0a8STomasz Kulasek 
4831ccec0a8STomasz Kulasek 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
4841ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4851ccec0a8STomasz Kulasek 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
4861ccec0a8STomasz Kulasek 
4871ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4881ccec0a8STomasz Kulasek 
4891ccec0a8STomasz Kulasek 	return 0;
4901ccec0a8STomasz Kulasek }
4911ccec0a8STomasz Kulasek 
492caccf8b3SOlivier Matz static int
493c5ac7748SRadu Nicolau eth_mac_address_set(__rte_unused struct rte_eth_dev *dev,
4946d13ea8eSOlivier Matz 		    __rte_unused struct rte_ether_addr *addr)
495c5ac7748SRadu Nicolau {
496caccf8b3SOlivier Matz 	return 0;
497c5ac7748SRadu Nicolau }
498c5ac7748SRadu Nicolau 
499d2fb7164SThomas Monjalon static int
500d2fb7164SThomas Monjalon eth_dev_close(struct rte_eth_dev *dev)
501d2fb7164SThomas Monjalon {
502d2fb7164SThomas Monjalon 	PMD_LOG(INFO, "Closing null ethdev on NUMA socket %u",
503d2fb7164SThomas Monjalon 			rte_socket_id());
504d2fb7164SThomas Monjalon 
505d2fb7164SThomas Monjalon 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
506d2fb7164SThomas Monjalon 		return 0;
507d2fb7164SThomas Monjalon 
508d2fb7164SThomas Monjalon 	/* mac_addrs must not be freed alone because part of dev_private */
509d2fb7164SThomas Monjalon 	dev->data->mac_addrs = NULL;
510d2fb7164SThomas Monjalon 
511d2fb7164SThomas Monjalon 	return 0;
512d2fb7164SThomas Monjalon }
513d2fb7164SThomas Monjalon 
514b3b413f7SBruce Richardson static const struct eth_dev_ops ops = {
515d2fb7164SThomas Monjalon 	.dev_close = eth_dev_close,
516b3b413f7SBruce Richardson 	.dev_start = eth_dev_start,
517b3b413f7SBruce Richardson 	.dev_stop = eth_dev_stop,
518b3b413f7SBruce Richardson 	.dev_configure = eth_dev_configure,
519b3b413f7SBruce Richardson 	.dev_infos_get = eth_dev_info,
520b3b413f7SBruce Richardson 	.rx_queue_setup = eth_rx_queue_setup,
521b3b413f7SBruce Richardson 	.tx_queue_setup = eth_tx_queue_setup,
5227483341aSXueming Li 	.rx_queue_release = eth_rx_queue_release,
5237483341aSXueming Li 	.tx_queue_release = eth_tx_queue_release,
524e6acdc77SMallesh Koujalagi 	.mtu_set = eth_mtu_set,
525b3b413f7SBruce Richardson 	.link_update = eth_link_update,
526c5ac7748SRadu Nicolau 	.mac_addr_set = eth_mac_address_set,
527b3b413f7SBruce Richardson 	.stats_get = eth_stats_get,
528b3b413f7SBruce Richardson 	.stats_reset = eth_stats_reset,
5291ccec0a8STomasz Kulasek 	.reta_update = eth_rss_reta_update,
5301ccec0a8STomasz Kulasek 	.reta_query = eth_rss_reta_query,
5311ccec0a8STomasz Kulasek 	.rss_hash_update = eth_rss_hash_update,
5321ccec0a8STomasz Kulasek 	.rss_hash_conf_get = eth_rss_hash_conf_get
533b3b413f7SBruce Richardson };
534b3b413f7SBruce Richardson 
535c3b047beSJan Blunck static int
536276bb4ceSFerruh Yigit eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
537b3b413f7SBruce Richardson {
5384df90194SFerruh Yigit 	const unsigned int nb_rx_queues = 1;
5394df90194SFerruh Yigit 	const unsigned int nb_tx_queues = 1;
5405f19dee6SJianfeng Tan 	struct rte_eth_dev_data *data;
541b3b413f7SBruce Richardson 	struct pmd_internals *internals = NULL;
542b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
543b3b413f7SBruce Richardson 
5441ccec0a8STomasz Kulasek 	static const uint8_t default_rss_key[40] = {
5451ccec0a8STomasz Kulasek 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
5461ccec0a8STomasz Kulasek 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
5471ccec0a8STomasz Kulasek 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
5481ccec0a8STomasz Kulasek 		0xBE, 0xAC, 0x01, 0xFA
5491ccec0a8STomasz Kulasek 	};
5501ccec0a8STomasz Kulasek 
551050fe6e9SJan Blunck 	if (dev->device.numa_node == SOCKET_ID_ANY)
552050fe6e9SJan Blunck 		dev->device.numa_node = rte_socket_id();
553b3b413f7SBruce Richardson 
554eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
555050fe6e9SJan Blunck 		dev->device.numa_node);
556b3b413f7SBruce Richardson 
5575f19dee6SJianfeng Tan 	eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
5585f19dee6SJianfeng Tan 	if (!eth_dev)
559050fe6e9SJan Blunck 		return -ENOMEM;
560b3b413f7SBruce Richardson 
561b3b413f7SBruce Richardson 	/* now put it all together
562b3b413f7SBruce Richardson 	 * - store queue data in internals,
5638fb9e2bbSBernard Iremonger 	 * - store numa_node info in ethdev data
5648fb9e2bbSBernard Iremonger 	 * - point eth_dev_data to internals
565b3b413f7SBruce Richardson 	 * - and point eth_dev structure to new eth_dev_data structure
566b3b413f7SBruce Richardson 	 */
567b3b413f7SBruce Richardson 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
568b3b413f7SBruce Richardson 	 * so the nulls are local per-process */
569b3b413f7SBruce Richardson 
570050fe6e9SJan Blunck 	internals = eth_dev->data->dev_private;
571276bb4ceSFerruh Yigit 	internals->packet_size = args->packet_size;
572276bb4ceSFerruh Yigit 	internals->packet_copy = args->packet_copy;
573f51ecf2fSFerruh Yigit 	internals->no_rx = args->no_rx;
5745cf86418SSean Harte 	internals->port_id = eth_dev->data->port_id;
575538da7a1SOlivier Matz 	rte_eth_random_addr(internals->eth_addr.addr_bytes);
576b3b413f7SBruce Richardson 
577295968d1SFerruh Yigit 	internals->flow_type_rss_offloads =  RTE_ETH_RSS_PROTO_MASK;
578295968d1SFerruh Yigit 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_ETH_RETA_GROUP_SIZE;
5791ccec0a8STomasz Kulasek 
5801ccec0a8STomasz Kulasek 	rte_memcpy(internals->rss_key, default_rss_key, 40);
5811ccec0a8STomasz Kulasek 
5825f19dee6SJianfeng Tan 	data = eth_dev->data;
583b3b413f7SBruce Richardson 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
584b3b413f7SBruce Richardson 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
585b3b413f7SBruce Richardson 	data->dev_link = pmd_link;
586c1cd6fb3SMallesh Koujalagi 	data->mac_addrs = &internals->eth_addr;
587f1652103SCiara Power 	data->promiscuous = 1;
588f1652103SCiara Power 	data->all_multicast = 1;
589f30e69b4SFerruh Yigit 	data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
590b3b413f7SBruce Richardson 
591b3b413f7SBruce Richardson 	eth_dev->dev_ops = &ops;
5926799cfe4SBernard Iremonger 
593b3b413f7SBruce Richardson 	/* finally assign rx and tx ops */
594276bb4ceSFerruh Yigit 	if (internals->packet_copy) {
595b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
596b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
597f51ecf2fSFerruh Yigit 	} else if (internals->no_rx) {
598f51ecf2fSFerruh Yigit 		eth_dev->rx_pkt_burst = eth_null_no_rx;
599f51ecf2fSFerruh Yigit 		eth_dev->tx_pkt_burst = eth_null_tx;
600b3b413f7SBruce Richardson 	} else {
601b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_rx;
602b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_tx;
603b3b413f7SBruce Richardson 	}
604b3b413f7SBruce Richardson 
605fbe90cddSThomas Monjalon 	rte_eth_dev_probing_finish(eth_dev);
606b3b413f7SBruce Richardson 	return 0;
607b3b413f7SBruce Richardson }
608b3b413f7SBruce Richardson 
609b3b413f7SBruce Richardson static inline int
610b3b413f7SBruce Richardson get_packet_size_arg(const char *key __rte_unused,
611b3b413f7SBruce Richardson 		const char *value, void *extra_args)
612b3b413f7SBruce Richardson {
613b3b413f7SBruce Richardson 	const char *a = value;
6144df90194SFerruh Yigit 	unsigned int *packet_size = extra_args;
615b3b413f7SBruce Richardson 
616b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
617b3b413f7SBruce Richardson 		return -EINVAL;
618b3b413f7SBruce Richardson 
6194df90194SFerruh Yigit 	*packet_size = (unsigned int)strtoul(a, NULL, 0);
620b3b413f7SBruce Richardson 	if (*packet_size == UINT_MAX)
621b3b413f7SBruce Richardson 		return -1;
622b3b413f7SBruce Richardson 
623b3b413f7SBruce Richardson 	return 0;
624b3b413f7SBruce Richardson }
625b3b413f7SBruce Richardson 
626b3b413f7SBruce Richardson static inline int
627b3b413f7SBruce Richardson get_packet_copy_arg(const char *key __rte_unused,
628b3b413f7SBruce Richardson 		const char *value, void *extra_args)
629b3b413f7SBruce Richardson {
630b3b413f7SBruce Richardson 	const char *a = value;
6314df90194SFerruh Yigit 	unsigned int *packet_copy = extra_args;
632b3b413f7SBruce Richardson 
633b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
634b3b413f7SBruce Richardson 		return -EINVAL;
635b3b413f7SBruce Richardson 
6364df90194SFerruh Yigit 	*packet_copy = (unsigned int)strtoul(a, NULL, 0);
637b3b413f7SBruce Richardson 	if (*packet_copy == UINT_MAX)
638b3b413f7SBruce Richardson 		return -1;
639b3b413f7SBruce Richardson 
640b3b413f7SBruce Richardson 	return 0;
641b3b413f7SBruce Richardson }
642b3b413f7SBruce Richardson 
643b3b413f7SBruce Richardson static int
644f51ecf2fSFerruh Yigit get_packet_no_rx_arg(const char *key __rte_unused,
645f51ecf2fSFerruh Yigit 		const char *value, void *extra_args)
646f51ecf2fSFerruh Yigit {
647f51ecf2fSFerruh Yigit 	const char *a = value;
648f51ecf2fSFerruh Yigit 	unsigned int no_rx;
649f51ecf2fSFerruh Yigit 
650f51ecf2fSFerruh Yigit 	if (value == NULL || extra_args == NULL)
651f51ecf2fSFerruh Yigit 		return -EINVAL;
652f51ecf2fSFerruh Yigit 
653f51ecf2fSFerruh Yigit 	no_rx = (unsigned int)strtoul(a, NULL, 0);
654f51ecf2fSFerruh Yigit 	if (no_rx != 0 && no_rx != 1)
655f51ecf2fSFerruh Yigit 		return -1;
656f51ecf2fSFerruh Yigit 
657f51ecf2fSFerruh Yigit 	*(unsigned int *)extra_args = no_rx;
658f51ecf2fSFerruh Yigit 	return 0;
659f51ecf2fSFerruh Yigit }
660f51ecf2fSFerruh Yigit 
661f51ecf2fSFerruh Yigit static int
6625d2aa461SJan Blunck rte_pmd_null_probe(struct rte_vdev_device *dev)
663b3b413f7SBruce Richardson {
6645d2aa461SJan Blunck 	const char *name, *params;
665276bb4ceSFerruh Yigit 	struct pmd_options args = {
666276bb4ceSFerruh Yigit 		.packet_copy = default_packet_copy,
667276bb4ceSFerruh Yigit 		.packet_size = default_packet_size,
668f51ecf2fSFerruh Yigit 		.no_rx = default_no_rx,
669276bb4ceSFerruh Yigit 	};
670b3b413f7SBruce Richardson 	struct rte_kvargs *kvlist = NULL;
671ee27edbeSJianfeng Tan 	struct rte_eth_dev *eth_dev;
672b3b413f7SBruce Richardson 	int ret;
673b3b413f7SBruce Richardson 
6745d2aa461SJan Blunck 	if (!dev)
675b3b413f7SBruce Richardson 		return -EINVAL;
676b3b413f7SBruce Richardson 
6775d2aa461SJan Blunck 	name = rte_vdev_device_name(dev);
6785d2aa461SJan Blunck 	params = rte_vdev_device_args(dev);
679eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Initializing pmd_null for %s", name);
680b3b413f7SBruce Richardson 
6814852aa8fSQi Zhang 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
682e2f4b250SFerruh Yigit 		struct pmd_internals *internals;
683ee27edbeSJianfeng Tan 		eth_dev = rte_eth_dev_attach_secondary(name);
684ee27edbeSJianfeng Tan 		if (!eth_dev) {
685eb16afb9SStephen Hemminger 			PMD_LOG(ERR, "Failed to probe %s", name);
686ee27edbeSJianfeng Tan 			return -1;
687ee27edbeSJianfeng Tan 		}
688ee27edbeSJianfeng Tan 		/* TODO: request info from primary to set up Rx and Tx */
689ee27edbeSJianfeng Tan 		eth_dev->dev_ops = &ops;
690d1c3ab22SFerruh Yigit 		eth_dev->device = &dev->device;
691e2f4b250SFerruh Yigit 		internals = eth_dev->data->dev_private;
692e2f4b250SFerruh Yigit 		if (internals->packet_copy) {
693bccc77a6SYasufumi Ogawa 			eth_dev->rx_pkt_burst = eth_null_copy_rx;
694bccc77a6SYasufumi Ogawa 			eth_dev->tx_pkt_burst = eth_null_copy_tx;
695f51ecf2fSFerruh Yigit 		} else if (internals->no_rx) {
696f51ecf2fSFerruh Yigit 			eth_dev->rx_pkt_burst = eth_null_no_rx;
697f51ecf2fSFerruh Yigit 			eth_dev->tx_pkt_burst = eth_null_tx;
698bccc77a6SYasufumi Ogawa 		} else {
699bccc77a6SYasufumi Ogawa 			eth_dev->rx_pkt_burst = eth_null_rx;
700bccc77a6SYasufumi Ogawa 			eth_dev->tx_pkt_burst = eth_null_tx;
701bccc77a6SYasufumi Ogawa 		}
702fbe90cddSThomas Monjalon 		rte_eth_dev_probing_finish(eth_dev);
703ee27edbeSJianfeng Tan 		return 0;
704ee27edbeSJianfeng Tan 	}
705ee27edbeSJianfeng Tan 
706b3b413f7SBruce Richardson 	if (params != NULL) {
707b3b413f7SBruce Richardson 		kvlist = rte_kvargs_parse(params, valid_arguments);
708b3b413f7SBruce Richardson 		if (kvlist == NULL)
709b3b413f7SBruce Richardson 			return -1;
710b3b413f7SBruce Richardson 
711b3b413f7SBruce Richardson 		ret = rte_kvargs_process(kvlist,
712b3b413f7SBruce Richardson 				ETH_NULL_PACKET_SIZE_ARG,
713276bb4ceSFerruh Yigit 				&get_packet_size_arg, &args.packet_size);
714b3b413f7SBruce Richardson 		if (ret < 0)
715b3b413f7SBruce Richardson 			goto free_kvlist;
716b3b413f7SBruce Richardson 
717b3b413f7SBruce Richardson 
718b3b413f7SBruce Richardson 		ret = rte_kvargs_process(kvlist,
719b3b413f7SBruce Richardson 				ETH_NULL_PACKET_COPY_ARG,
720276bb4ceSFerruh Yigit 				&get_packet_copy_arg, &args.packet_copy);
721b3b413f7SBruce Richardson 		if (ret < 0)
722b3b413f7SBruce Richardson 			goto free_kvlist;
723f51ecf2fSFerruh Yigit 
724f51ecf2fSFerruh Yigit 		ret = rte_kvargs_process(kvlist,
725f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_NO_RX_ARG,
726f51ecf2fSFerruh Yigit 				&get_packet_no_rx_arg, &args.no_rx);
727f51ecf2fSFerruh Yigit 		if (ret < 0)
728f51ecf2fSFerruh Yigit 			goto free_kvlist;
729f51ecf2fSFerruh Yigit 
730f51ecf2fSFerruh Yigit 		if (args.no_rx && args.packet_copy) {
731f51ecf2fSFerruh Yigit 			PMD_LOG(ERR,
732f51ecf2fSFerruh Yigit 				"Both %s and %s arguments at the same time not supported",
733f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_COPY_ARG,
734f51ecf2fSFerruh Yigit 				ETH_NULL_PACKET_NO_RX_ARG);
735f51ecf2fSFerruh Yigit 			goto free_kvlist;
736f51ecf2fSFerruh Yigit 		}
737b3b413f7SBruce Richardson 	}
738b3b413f7SBruce Richardson 
739eb16afb9SStephen Hemminger 	PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
740276bb4ceSFerruh Yigit 			"packet copy is %s", args.packet_size,
741276bb4ceSFerruh Yigit 			args.packet_copy ? "enabled" : "disabled");
742b3b413f7SBruce Richardson 
743276bb4ceSFerruh Yigit 	ret = eth_dev_null_create(dev, &args);
744b3b413f7SBruce Richardson 
745b3b413f7SBruce Richardson free_kvlist:
746b3b413f7SBruce Richardson 	rte_kvargs_free(kvlist);
747b3b413f7SBruce Richardson 	return ret;
748b3b413f7SBruce Richardson }
749b3b413f7SBruce Richardson 
750b3b413f7SBruce Richardson static int
7515d2aa461SJan Blunck rte_pmd_null_remove(struct rte_vdev_device *dev)
752b3b413f7SBruce Richardson {
753b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
754b3b413f7SBruce Richardson 
7555d2aa461SJan Blunck 	if (!dev)
756b3b413f7SBruce Richardson 		return -EINVAL;
757b3b413f7SBruce Richardson 
7586799cfe4SBernard Iremonger 	/* find the ethdev entry */
7595d2aa461SJan Blunck 	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
760b3b413f7SBruce Richardson 	if (eth_dev == NULL)
761d2fb7164SThomas Monjalon 		return 0; /* port already released */
762b3b413f7SBruce Richardson 
763d2fb7164SThomas Monjalon 	eth_dev_close(eth_dev);
764b3b413f7SBruce Richardson 	rte_eth_dev_release_port(eth_dev);
765b3b413f7SBruce Richardson 
766b3b413f7SBruce Richardson 	return 0;
767b3b413f7SBruce Richardson }
768b3b413f7SBruce Richardson 
769fe363dd4SJan Viktorin static struct rte_vdev_driver pmd_null_drv = {
77050a3345fSShreyansh Jain 	.probe = rte_pmd_null_probe,
77150a3345fSShreyansh Jain 	.remove = rte_pmd_null_remove,
772b3b413f7SBruce Richardson };
773b3b413f7SBruce Richardson 
77401f19227SShreyansh Jain RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
7759fa80cb2SJan Blunck RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
77601f19227SShreyansh Jain RTE_PMD_REGISTER_PARAM_STRING(net_null,
77765eca099SPablo de Lara 	"size=<int> "
778f51ecf2fSFerruh Yigit 	"copy=<int> "
779f51ecf2fSFerruh Yigit 	ETH_NULL_PACKET_NO_RX_ARG "=0|1");
780