xref: /dpdk/drivers/net/null/rte_eth_null.c (revision e11bdd37745229bf26b557305c07d118c3dbaad7)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (C) IGEL Co.,Ltd.
3  *  All rights reserved.
4  */
5 
6 #include <rte_mbuf.h>
7 #include <rte_ethdev_driver.h>
8 #include <rte_ethdev_vdev.h>
9 #include <rte_malloc.h>
10 #include <rte_memcpy.h>
11 #include <rte_bus_vdev.h>
12 #include <rte_kvargs.h>
13 #include <rte_spinlock.h>
14 
15 #define ETH_NULL_PACKET_SIZE_ARG	"size"
16 #define ETH_NULL_PACKET_COPY_ARG	"copy"
17 #define ETH_NULL_PACKET_NO_RX_ARG	"no-rx"
18 
19 static unsigned int default_packet_size = 64;
20 static unsigned int default_packet_copy;
21 static unsigned int default_no_rx;
22 
23 static const char *valid_arguments[] = {
24 	ETH_NULL_PACKET_SIZE_ARG,
25 	ETH_NULL_PACKET_COPY_ARG,
26 	ETH_NULL_PACKET_NO_RX_ARG,
27 	NULL
28 };
29 
30 struct pmd_internals;
31 
32 struct null_queue {
33 	struct pmd_internals *internals;
34 
35 	struct rte_mempool *mb_pool;
36 	struct rte_mbuf *dummy_packet;
37 
38 	rte_atomic64_t rx_pkts;
39 	rte_atomic64_t tx_pkts;
40 };
41 
42 struct pmd_options {
43 	unsigned int packet_copy;
44 	unsigned int packet_size;
45 	unsigned int no_rx;
46 };
47 
48 struct pmd_internals {
49 	unsigned int packet_size;
50 	unsigned int packet_copy;
51 	unsigned int no_rx;
52 	uint16_t port_id;
53 
54 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
55 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
56 
57 	struct rte_ether_addr eth_addr;
58 	/** Bit mask of RSS offloads, the bit offset also means flow type */
59 	uint64_t flow_type_rss_offloads;
60 
61 	rte_spinlock_t rss_lock;
62 
63 	uint16_t reta_size;
64 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
65 			RTE_RETA_GROUP_SIZE];
66 
67 	uint8_t rss_key[40];                /**< 40-byte hash key. */
68 };
69 static struct rte_eth_link pmd_link = {
70 	.link_speed = ETH_SPEED_NUM_10G,
71 	.link_duplex = ETH_LINK_FULL_DUPLEX,
72 	.link_status = ETH_LINK_DOWN,
73 	.link_autoneg = ETH_LINK_FIXED,
74 };
75 
76 static int eth_null_logtype;
77 
78 #define PMD_LOG(level, fmt, args...) \
79 	rte_log(RTE_LOG_ ## level, eth_null_logtype, \
80 		"%s(): " fmt "\n", __func__, ##args)
81 
82 static uint16_t
83 eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
84 {
85 	int i;
86 	struct null_queue *h = q;
87 	unsigned int packet_size;
88 
89 	if ((q == NULL) || (bufs == NULL))
90 		return 0;
91 
92 	packet_size = h->internals->packet_size;
93 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
94 		return 0;
95 
96 	for (i = 0; i < nb_bufs; i++) {
97 		bufs[i]->data_len = (uint16_t)packet_size;
98 		bufs[i]->pkt_len = packet_size;
99 		bufs[i]->port = h->internals->port_id;
100 	}
101 
102 	rte_atomic64_add(&(h->rx_pkts), i);
103 
104 	return i;
105 }
106 
107 static uint16_t
108 eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
109 {
110 	int i;
111 	struct null_queue *h = q;
112 	unsigned int packet_size;
113 
114 	if ((q == NULL) || (bufs == NULL))
115 		return 0;
116 
117 	packet_size = h->internals->packet_size;
118 	if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
119 		return 0;
120 
121 	for (i = 0; i < nb_bufs; i++) {
122 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
123 					packet_size);
124 		bufs[i]->data_len = (uint16_t)packet_size;
125 		bufs[i]->pkt_len = packet_size;
126 		bufs[i]->port = h->internals->port_id;
127 	}
128 
129 	rte_atomic64_add(&(h->rx_pkts), i);
130 
131 	return i;
132 }
133 
134 static uint16_t
135 eth_null_no_rx(void *q __rte_unused, struct rte_mbuf **bufs __rte_unused,
136 		uint16_t nb_bufs __rte_unused)
137 {
138 	return 0;
139 }
140 
141 static uint16_t
142 eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
143 {
144 	int i;
145 	struct null_queue *h = q;
146 
147 	if ((q == NULL) || (bufs == NULL))
148 		return 0;
149 
150 	for (i = 0; i < nb_bufs; i++)
151 		rte_pktmbuf_free(bufs[i]);
152 
153 	rte_atomic64_add(&(h->tx_pkts), i);
154 
155 	return i;
156 }
157 
158 static uint16_t
159 eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
160 {
161 	int i;
162 	struct null_queue *h = q;
163 	unsigned int packet_size;
164 
165 	if ((q == NULL) || (bufs == NULL))
166 		return 0;
167 
168 	packet_size = h->internals->packet_size;
169 	for (i = 0; i < nb_bufs; i++) {
170 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
171 					packet_size);
172 		rte_pktmbuf_free(bufs[i]);
173 	}
174 
175 	rte_atomic64_add(&(h->tx_pkts), i);
176 
177 	return i;
178 }
179 
180 static int
181 eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
182 {
183 	return 0;
184 }
185 
186 static int
187 eth_dev_start(struct rte_eth_dev *dev)
188 {
189 	if (dev == NULL)
190 		return -EINVAL;
191 
192 	dev->data->dev_link.link_status = ETH_LINK_UP;
193 	return 0;
194 }
195 
196 static void
197 eth_dev_stop(struct rte_eth_dev *dev)
198 {
199 	if (dev == NULL)
200 		return;
201 
202 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
203 }
204 
205 static int
206 eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
207 		uint16_t nb_rx_desc __rte_unused,
208 		unsigned int socket_id __rte_unused,
209 		const struct rte_eth_rxconf *rx_conf __rte_unused,
210 		struct rte_mempool *mb_pool)
211 {
212 	struct rte_mbuf *dummy_packet;
213 	struct pmd_internals *internals;
214 	unsigned int packet_size;
215 
216 	if ((dev == NULL) || (mb_pool == NULL))
217 		return -EINVAL;
218 
219 	internals = dev->data->dev_private;
220 
221 	if (rx_queue_id >= dev->data->nb_rx_queues)
222 		return -ENODEV;
223 
224 	packet_size = internals->packet_size;
225 
226 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
227 	dev->data->rx_queues[rx_queue_id] =
228 		&internals->rx_null_queues[rx_queue_id];
229 	dummy_packet = rte_zmalloc_socket(NULL,
230 			packet_size, 0, dev->data->numa_node);
231 	if (dummy_packet == NULL)
232 		return -ENOMEM;
233 
234 	internals->rx_null_queues[rx_queue_id].internals = internals;
235 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
236 
237 	return 0;
238 }
239 
240 static int
241 eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
242 		uint16_t nb_tx_desc __rte_unused,
243 		unsigned int socket_id __rte_unused,
244 		const struct rte_eth_txconf *tx_conf __rte_unused)
245 {
246 	struct rte_mbuf *dummy_packet;
247 	struct pmd_internals *internals;
248 	unsigned int packet_size;
249 
250 	if (dev == NULL)
251 		return -EINVAL;
252 
253 	internals = dev->data->dev_private;
254 
255 	if (tx_queue_id >= dev->data->nb_tx_queues)
256 		return -ENODEV;
257 
258 	packet_size = internals->packet_size;
259 
260 	dev->data->tx_queues[tx_queue_id] =
261 		&internals->tx_null_queues[tx_queue_id];
262 	dummy_packet = rte_zmalloc_socket(NULL,
263 			packet_size, 0, dev->data->numa_node);
264 	if (dummy_packet == NULL)
265 		return -ENOMEM;
266 
267 	internals->tx_null_queues[tx_queue_id].internals = internals;
268 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
269 
270 	return 0;
271 }
272 
273 static int
274 eth_mtu_set(struct rte_eth_dev *dev __rte_unused, uint16_t mtu __rte_unused)
275 {
276 	return 0;
277 }
278 
279 static int
280 eth_dev_info(struct rte_eth_dev *dev,
281 		struct rte_eth_dev_info *dev_info)
282 {
283 	struct pmd_internals *internals;
284 
285 	if ((dev == NULL) || (dev_info == NULL))
286 		return -EINVAL;
287 
288 	internals = dev->data->dev_private;
289 	dev_info->max_mac_addrs = 1;
290 	dev_info->max_rx_pktlen = (uint32_t)-1;
291 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
292 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
293 	dev_info->min_rx_bufsize = 0;
294 	dev_info->reta_size = internals->reta_size;
295 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
296 
297 	return 0;
298 }
299 
300 static int
301 eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
302 {
303 	unsigned int i, num_stats;
304 	unsigned long rx_total = 0, tx_total = 0;
305 	const struct pmd_internals *internal;
306 
307 	if ((dev == NULL) || (igb_stats == NULL))
308 		return -EINVAL;
309 
310 	internal = dev->data->dev_private;
311 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
312 			RTE_MIN(dev->data->nb_rx_queues,
313 				RTE_DIM(internal->rx_null_queues)));
314 	for (i = 0; i < num_stats; i++) {
315 		igb_stats->q_ipackets[i] =
316 			internal->rx_null_queues[i].rx_pkts.cnt;
317 		rx_total += igb_stats->q_ipackets[i];
318 	}
319 
320 	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
321 			RTE_MIN(dev->data->nb_tx_queues,
322 				RTE_DIM(internal->tx_null_queues)));
323 	for (i = 0; i < num_stats; i++) {
324 		igb_stats->q_opackets[i] =
325 			internal->tx_null_queues[i].tx_pkts.cnt;
326 		tx_total += igb_stats->q_opackets[i];
327 	}
328 
329 	igb_stats->ipackets = rx_total;
330 	igb_stats->opackets = tx_total;
331 
332 	return 0;
333 }
334 
335 static int
336 eth_stats_reset(struct rte_eth_dev *dev)
337 {
338 	unsigned int i;
339 	struct pmd_internals *internal;
340 
341 	if (dev == NULL)
342 		return -EINVAL;
343 
344 	internal = dev->data->dev_private;
345 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
346 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
347 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++)
348 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
349 
350 	return 0;
351 }
352 
353 static void
354 eth_queue_release(void *q)
355 {
356 	struct null_queue *nq;
357 
358 	if (q == NULL)
359 		return;
360 
361 	nq = q;
362 	rte_free(nq->dummy_packet);
363 }
364 
365 static int
366 eth_link_update(struct rte_eth_dev *dev __rte_unused,
367 		int wait_to_complete __rte_unused) { return 0; }
368 
369 static int
370 eth_rss_reta_update(struct rte_eth_dev *dev,
371 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
372 {
373 	int i, j;
374 	struct pmd_internals *internal = dev->data->dev_private;
375 
376 	if (reta_size != internal->reta_size)
377 		return -EINVAL;
378 
379 	rte_spinlock_lock(&internal->rss_lock);
380 
381 	/* Copy RETA table */
382 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
383 		internal->reta_conf[i].mask = reta_conf[i].mask;
384 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
385 			if ((reta_conf[i].mask >> j) & 0x01)
386 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
387 	}
388 
389 	rte_spinlock_unlock(&internal->rss_lock);
390 
391 	return 0;
392 }
393 
394 static int
395 eth_rss_reta_query(struct rte_eth_dev *dev,
396 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
397 {
398 	int i, j;
399 	struct pmd_internals *internal = dev->data->dev_private;
400 
401 	if (reta_size != internal->reta_size)
402 		return -EINVAL;
403 
404 	rte_spinlock_lock(&internal->rss_lock);
405 
406 	/* Copy RETA table */
407 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
408 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
409 			if ((reta_conf[i].mask >> j) & 0x01)
410 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
411 	}
412 
413 	rte_spinlock_unlock(&internal->rss_lock);
414 
415 	return 0;
416 }
417 
418 static int
419 eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
420 {
421 	struct pmd_internals *internal = dev->data->dev_private;
422 
423 	rte_spinlock_lock(&internal->rss_lock);
424 
425 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
426 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
427 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
428 
429 	if (rss_conf->rss_key)
430 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
431 
432 	rte_spinlock_unlock(&internal->rss_lock);
433 
434 	return 0;
435 }
436 
437 static int
438 eth_rss_hash_conf_get(struct rte_eth_dev *dev,
439 		struct rte_eth_rss_conf *rss_conf)
440 {
441 	struct pmd_internals *internal = dev->data->dev_private;
442 
443 	rte_spinlock_lock(&internal->rss_lock);
444 
445 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
446 	if (rss_conf->rss_key)
447 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
448 
449 	rte_spinlock_unlock(&internal->rss_lock);
450 
451 	return 0;
452 }
453 
454 static int
455 eth_mac_address_set(__rte_unused struct rte_eth_dev *dev,
456 		    __rte_unused struct rte_ether_addr *addr)
457 {
458 	return 0;
459 }
460 
461 static const struct eth_dev_ops ops = {
462 	.dev_start = eth_dev_start,
463 	.dev_stop = eth_dev_stop,
464 	.dev_configure = eth_dev_configure,
465 	.dev_infos_get = eth_dev_info,
466 	.rx_queue_setup = eth_rx_queue_setup,
467 	.tx_queue_setup = eth_tx_queue_setup,
468 	.rx_queue_release = eth_queue_release,
469 	.tx_queue_release = eth_queue_release,
470 	.mtu_set = eth_mtu_set,
471 	.link_update = eth_link_update,
472 	.mac_addr_set = eth_mac_address_set,
473 	.stats_get = eth_stats_get,
474 	.stats_reset = eth_stats_reset,
475 	.reta_update = eth_rss_reta_update,
476 	.reta_query = eth_rss_reta_query,
477 	.rss_hash_update = eth_rss_hash_update,
478 	.rss_hash_conf_get = eth_rss_hash_conf_get
479 };
480 
481 static int
482 eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
483 {
484 	const unsigned int nb_rx_queues = 1;
485 	const unsigned int nb_tx_queues = 1;
486 	struct rte_eth_dev_data *data;
487 	struct pmd_internals *internals = NULL;
488 	struct rte_eth_dev *eth_dev = NULL;
489 
490 	static const uint8_t default_rss_key[40] = {
491 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
492 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
493 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
494 		0xBE, 0xAC, 0x01, 0xFA
495 	};
496 
497 	if (dev->device.numa_node == SOCKET_ID_ANY)
498 		dev->device.numa_node = rte_socket_id();
499 
500 	PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
501 		dev->device.numa_node);
502 
503 	eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
504 	if (!eth_dev)
505 		return -ENOMEM;
506 
507 	/* now put it all together
508 	 * - store queue data in internals,
509 	 * - store numa_node info in ethdev data
510 	 * - point eth_dev_data to internals
511 	 * - and point eth_dev structure to new eth_dev_data structure
512 	 */
513 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
514 	 * so the nulls are local per-process */
515 
516 	internals = eth_dev->data->dev_private;
517 	internals->packet_size = args->packet_size;
518 	internals->packet_copy = args->packet_copy;
519 	internals->no_rx = args->no_rx;
520 	internals->port_id = eth_dev->data->port_id;
521 	rte_eth_random_addr(internals->eth_addr.addr_bytes);
522 
523 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
524 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
525 
526 	rte_memcpy(internals->rss_key, default_rss_key, 40);
527 
528 	data = eth_dev->data;
529 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
530 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
531 	data->dev_link = pmd_link;
532 	data->mac_addrs = &internals->eth_addr;
533 	data->promiscuous = 1;
534 	data->all_multicast = 1;
535 
536 	eth_dev->dev_ops = &ops;
537 
538 	/* finally assign rx and tx ops */
539 	if (internals->packet_copy) {
540 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
541 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
542 	} else if (internals->no_rx) {
543 		eth_dev->rx_pkt_burst = eth_null_no_rx;
544 		eth_dev->tx_pkt_burst = eth_null_tx;
545 	} else {
546 		eth_dev->rx_pkt_burst = eth_null_rx;
547 		eth_dev->tx_pkt_burst = eth_null_tx;
548 	}
549 
550 	rte_eth_dev_probing_finish(eth_dev);
551 	return 0;
552 }
553 
554 static inline int
555 get_packet_size_arg(const char *key __rte_unused,
556 		const char *value, void *extra_args)
557 {
558 	const char *a = value;
559 	unsigned int *packet_size = extra_args;
560 
561 	if ((value == NULL) || (extra_args == NULL))
562 		return -EINVAL;
563 
564 	*packet_size = (unsigned int)strtoul(a, NULL, 0);
565 	if (*packet_size == UINT_MAX)
566 		return -1;
567 
568 	return 0;
569 }
570 
571 static inline int
572 get_packet_copy_arg(const char *key __rte_unused,
573 		const char *value, void *extra_args)
574 {
575 	const char *a = value;
576 	unsigned int *packet_copy = extra_args;
577 
578 	if ((value == NULL) || (extra_args == NULL))
579 		return -EINVAL;
580 
581 	*packet_copy = (unsigned int)strtoul(a, NULL, 0);
582 	if (*packet_copy == UINT_MAX)
583 		return -1;
584 
585 	return 0;
586 }
587 
588 static int
589 get_packet_no_rx_arg(const char *key __rte_unused,
590 		const char *value, void *extra_args)
591 {
592 	const char *a = value;
593 	unsigned int no_rx;
594 
595 	if (value == NULL || extra_args == NULL)
596 		return -EINVAL;
597 
598 	no_rx = (unsigned int)strtoul(a, NULL, 0);
599 	if (no_rx != 0 && no_rx != 1)
600 		return -1;
601 
602 	*(unsigned int *)extra_args = no_rx;
603 	return 0;
604 }
605 
606 static int
607 rte_pmd_null_probe(struct rte_vdev_device *dev)
608 {
609 	const char *name, *params;
610 	struct pmd_options args = {
611 		.packet_copy = default_packet_copy,
612 		.packet_size = default_packet_size,
613 		.no_rx = default_no_rx,
614 	};
615 	struct rte_kvargs *kvlist = NULL;
616 	struct rte_eth_dev *eth_dev;
617 	int ret;
618 
619 	if (!dev)
620 		return -EINVAL;
621 
622 	name = rte_vdev_device_name(dev);
623 	params = rte_vdev_device_args(dev);
624 	PMD_LOG(INFO, "Initializing pmd_null for %s", name);
625 
626 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
627 		struct pmd_internals *internals;
628 		eth_dev = rte_eth_dev_attach_secondary(name);
629 		if (!eth_dev) {
630 			PMD_LOG(ERR, "Failed to probe %s", name);
631 			return -1;
632 		}
633 		/* TODO: request info from primary to set up Rx and Tx */
634 		eth_dev->dev_ops = &ops;
635 		eth_dev->device = &dev->device;
636 		internals = eth_dev->data->dev_private;
637 		if (internals->packet_copy) {
638 			eth_dev->rx_pkt_burst = eth_null_copy_rx;
639 			eth_dev->tx_pkt_burst = eth_null_copy_tx;
640 		} else if (internals->no_rx) {
641 			eth_dev->rx_pkt_burst = eth_null_no_rx;
642 			eth_dev->tx_pkt_burst = eth_null_tx;
643 		} else {
644 			eth_dev->rx_pkt_burst = eth_null_rx;
645 			eth_dev->tx_pkt_burst = eth_null_tx;
646 		}
647 		rte_eth_dev_probing_finish(eth_dev);
648 		return 0;
649 	}
650 
651 	if (params != NULL) {
652 		kvlist = rte_kvargs_parse(params, valid_arguments);
653 		if (kvlist == NULL)
654 			return -1;
655 
656 		ret = rte_kvargs_process(kvlist,
657 				ETH_NULL_PACKET_SIZE_ARG,
658 				&get_packet_size_arg, &args.packet_size);
659 		if (ret < 0)
660 			goto free_kvlist;
661 
662 
663 		ret = rte_kvargs_process(kvlist,
664 				ETH_NULL_PACKET_COPY_ARG,
665 				&get_packet_copy_arg, &args.packet_copy);
666 		if (ret < 0)
667 			goto free_kvlist;
668 
669 		ret = rte_kvargs_process(kvlist,
670 				ETH_NULL_PACKET_NO_RX_ARG,
671 				&get_packet_no_rx_arg, &args.no_rx);
672 		if (ret < 0)
673 			goto free_kvlist;
674 
675 		if (args.no_rx && args.packet_copy) {
676 			PMD_LOG(ERR,
677 				"Both %s and %s arguments at the same time not supported",
678 				ETH_NULL_PACKET_COPY_ARG,
679 				ETH_NULL_PACKET_NO_RX_ARG);
680 			goto free_kvlist;
681 		}
682 	}
683 
684 	PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
685 			"packet copy is %s", args.packet_size,
686 			args.packet_copy ? "enabled" : "disabled");
687 
688 	ret = eth_dev_null_create(dev, &args);
689 
690 free_kvlist:
691 	if (kvlist)
692 		rte_kvargs_free(kvlist);
693 	return ret;
694 }
695 
696 static int
697 rte_pmd_null_remove(struct rte_vdev_device *dev)
698 {
699 	struct rte_eth_dev *eth_dev = NULL;
700 
701 	if (!dev)
702 		return -EINVAL;
703 
704 	PMD_LOG(INFO, "Closing null ethdev on numa socket %u",
705 			rte_socket_id());
706 
707 	/* find the ethdev entry */
708 	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
709 	if (eth_dev == NULL)
710 		return -1;
711 
712 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
713 		/* mac_addrs must not be freed alone because part of dev_private */
714 		eth_dev->data->mac_addrs = NULL;
715 
716 	rte_eth_dev_release_port(eth_dev);
717 
718 	return 0;
719 }
720 
721 static struct rte_vdev_driver pmd_null_drv = {
722 	.probe = rte_pmd_null_probe,
723 	.remove = rte_pmd_null_remove,
724 };
725 
726 RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
727 RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
728 RTE_PMD_REGISTER_PARAM_STRING(net_null,
729 	"size=<int> "
730 	"copy=<int> "
731 	ETH_NULL_PACKET_NO_RX_ARG "=0|1");
732 
733 RTE_INIT(eth_null_init_log)
734 {
735 	eth_null_logtype = rte_log_register("pmd.net.null");
736 	if (eth_null_logtype >= 0)
737 		rte_log_set_level(eth_null_logtype, RTE_LOG_NOTICE);
738 }
739