xref: /dpdk/drivers/net/null/rte_eth_null.c (revision a5d7a3f77ddc3c3ae18bce04d7555b458360cc65)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) IGEL Co.,Ltd.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of IGEL Co.,Ltd. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <rte_mbuf.h>
35 #include <rte_ethdev.h>
36 #include <rte_malloc.h>
37 #include <rte_memcpy.h>
38 #include <rte_dev.h>
39 #include <rte_kvargs.h>
40 #include <rte_spinlock.h>
41 
42 #include "rte_eth_null.h"
43 
44 #define ETH_NULL_PACKET_SIZE_ARG	"size"
45 #define ETH_NULL_PACKET_COPY_ARG	"copy"
46 
47 static unsigned default_packet_size = 64;
48 static unsigned default_packet_copy;
49 
50 static const char *valid_arguments[] = {
51 	ETH_NULL_PACKET_SIZE_ARG,
52 	ETH_NULL_PACKET_COPY_ARG,
53 	NULL
54 };
55 
56 struct pmd_internals;
57 
58 struct null_queue {
59 	struct pmd_internals *internals;
60 
61 	struct rte_mempool *mb_pool;
62 	struct rte_mbuf *dummy_packet;
63 
64 	rte_atomic64_t rx_pkts;
65 	rte_atomic64_t tx_pkts;
66 	rte_atomic64_t err_pkts;
67 };
68 
69 struct pmd_internals {
70 	unsigned packet_size;
71 	unsigned packet_copy;
72 	uint8_t port_id;
73 
74 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
75 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
76 
77 	/** Bit mask of RSS offloads, the bit offset also means flow type */
78 	uint64_t flow_type_rss_offloads;
79 
80 	rte_spinlock_t rss_lock;
81 
82 	uint16_t reta_size;
83 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
84 			RTE_RETA_GROUP_SIZE];
85 
86 	uint8_t rss_key[40];                /**< 40-byte hash key. */
87 };
88 
89 
90 static struct ether_addr eth_addr = { .addr_bytes = {0} };
91 static const char *drivername = "Null PMD";
92 static struct rte_eth_link pmd_link = {
93 	.link_speed = ETH_SPEED_NUM_10G,
94 	.link_duplex = ETH_LINK_FULL_DUPLEX,
95 	.link_status = ETH_LINK_DOWN,
96 	.link_autoneg = ETH_LINK_SPEED_AUTONEG,
97 };
98 
99 static uint16_t
100 eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
101 {
102 	int i;
103 	struct null_queue *h = q;
104 	unsigned packet_size;
105 
106 	if ((q == NULL) || (bufs == NULL))
107 		return 0;
108 
109 	packet_size = h->internals->packet_size;
110 	for (i = 0; i < nb_bufs; i++) {
111 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
112 		if (!bufs[i])
113 			break;
114 		bufs[i]->data_len = (uint16_t)packet_size;
115 		bufs[i]->pkt_len = packet_size;
116 		bufs[i]->nb_segs = 1;
117 		bufs[i]->next = NULL;
118 		bufs[i]->port = h->internals->port_id;
119 	}
120 
121 	rte_atomic64_add(&(h->rx_pkts), i);
122 
123 	return i;
124 }
125 
126 static uint16_t
127 eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
128 {
129 	int i;
130 	struct null_queue *h = q;
131 	unsigned packet_size;
132 
133 	if ((q == NULL) || (bufs == NULL))
134 		return 0;
135 
136 	packet_size = h->internals->packet_size;
137 	for (i = 0; i < nb_bufs; i++) {
138 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
139 		if (!bufs[i])
140 			break;
141 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
142 					packet_size);
143 		bufs[i]->data_len = (uint16_t)packet_size;
144 		bufs[i]->pkt_len = packet_size;
145 		bufs[i]->nb_segs = 1;
146 		bufs[i]->next = NULL;
147 		bufs[i]->port = h->internals->port_id;
148 	}
149 
150 	rte_atomic64_add(&(h->rx_pkts), i);
151 
152 	return i;
153 }
154 
155 static uint16_t
156 eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
157 {
158 	int i;
159 	struct null_queue *h = q;
160 
161 	if ((q == NULL) || (bufs == NULL))
162 		return 0;
163 
164 	for (i = 0; i < nb_bufs; i++)
165 		rte_pktmbuf_free(bufs[i]);
166 
167 	rte_atomic64_add(&(h->tx_pkts), i);
168 
169 	return i;
170 }
171 
172 static uint16_t
173 eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
174 {
175 	int i;
176 	struct null_queue *h = q;
177 	unsigned packet_size;
178 
179 	if ((q == NULL) || (bufs == NULL))
180 		return 0;
181 
182 	packet_size = h->internals->packet_size;
183 	for (i = 0; i < nb_bufs; i++) {
184 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
185 					packet_size);
186 		rte_pktmbuf_free(bufs[i]);
187 	}
188 
189 	rte_atomic64_add(&(h->tx_pkts), i);
190 
191 	return i;
192 }
193 
194 static int
195 eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
196 {
197 	return 0;
198 }
199 
200 static int
201 eth_dev_start(struct rte_eth_dev *dev)
202 {
203 	if (dev == NULL)
204 		return -EINVAL;
205 
206 	dev->data->dev_link.link_status = ETH_LINK_UP;
207 	return 0;
208 }
209 
210 static void
211 eth_dev_stop(struct rte_eth_dev *dev)
212 {
213 	if (dev == NULL)
214 		return;
215 
216 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
217 }
218 
219 static int
220 eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
221 		uint16_t nb_rx_desc __rte_unused,
222 		unsigned int socket_id __rte_unused,
223 		const struct rte_eth_rxconf *rx_conf __rte_unused,
224 		struct rte_mempool *mb_pool)
225 {
226 	struct rte_mbuf *dummy_packet;
227 	struct pmd_internals *internals;
228 	unsigned packet_size;
229 
230 	if ((dev == NULL) || (mb_pool == NULL))
231 		return -EINVAL;
232 
233 	internals = dev->data->dev_private;
234 
235 	if (rx_queue_id >= dev->data->nb_rx_queues)
236 		return -ENODEV;
237 
238 	packet_size = internals->packet_size;
239 
240 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
241 	dev->data->rx_queues[rx_queue_id] =
242 		&internals->rx_null_queues[rx_queue_id];
243 	dummy_packet = rte_zmalloc_socket(NULL,
244 			packet_size, 0, dev->data->numa_node);
245 	if (dummy_packet == NULL)
246 		return -ENOMEM;
247 
248 	internals->rx_null_queues[rx_queue_id].internals = internals;
249 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
250 
251 	return 0;
252 }
253 
254 static int
255 eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
256 		uint16_t nb_tx_desc __rte_unused,
257 		unsigned int socket_id __rte_unused,
258 		const struct rte_eth_txconf *tx_conf __rte_unused)
259 {
260 	struct rte_mbuf *dummy_packet;
261 	struct pmd_internals *internals;
262 	unsigned packet_size;
263 
264 	if (dev == NULL)
265 		return -EINVAL;
266 
267 	internals = dev->data->dev_private;
268 
269 	if (tx_queue_id >= dev->data->nb_tx_queues)
270 		return -ENODEV;
271 
272 	packet_size = internals->packet_size;
273 
274 	dev->data->tx_queues[tx_queue_id] =
275 		&internals->tx_null_queues[tx_queue_id];
276 	dummy_packet = rte_zmalloc_socket(NULL,
277 			packet_size, 0, dev->data->numa_node);
278 	if (dummy_packet == NULL)
279 		return -ENOMEM;
280 
281 	internals->tx_null_queues[tx_queue_id].internals = internals;
282 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
283 
284 	return 0;
285 }
286 
287 
288 static void
289 eth_dev_info(struct rte_eth_dev *dev,
290 		struct rte_eth_dev_info *dev_info)
291 {
292 	struct pmd_internals *internals;
293 
294 	if ((dev == NULL) || (dev_info == NULL))
295 		return;
296 
297 	internals = dev->data->dev_private;
298 	dev_info->driver_name = drivername;
299 	dev_info->max_mac_addrs = 1;
300 	dev_info->max_rx_pktlen = (uint32_t)-1;
301 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
302 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
303 	dev_info->min_rx_bufsize = 0;
304 	dev_info->pci_dev = NULL;
305 	dev_info->reta_size = internals->reta_size;
306 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
307 }
308 
309 static void
310 eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
311 {
312 	unsigned i, num_stats;
313 	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
314 	const struct pmd_internals *internal;
315 
316 	if ((dev == NULL) || (igb_stats == NULL))
317 		return;
318 
319 	internal = dev->data->dev_private;
320 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
321 			RTE_MIN(dev->data->nb_rx_queues,
322 				RTE_DIM(internal->rx_null_queues)));
323 	for (i = 0; i < num_stats; i++) {
324 		igb_stats->q_ipackets[i] =
325 			internal->rx_null_queues[i].rx_pkts.cnt;
326 		rx_total += igb_stats->q_ipackets[i];
327 	}
328 
329 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
330 			RTE_MIN(dev->data->nb_tx_queues,
331 				RTE_DIM(internal->tx_null_queues)));
332 	for (i = 0; i < num_stats; i++) {
333 		igb_stats->q_opackets[i] =
334 			internal->tx_null_queues[i].tx_pkts.cnt;
335 		igb_stats->q_errors[i] =
336 			internal->tx_null_queues[i].err_pkts.cnt;
337 		tx_total += igb_stats->q_opackets[i];
338 		tx_err_total += igb_stats->q_errors[i];
339 	}
340 
341 	igb_stats->ipackets = rx_total;
342 	igb_stats->opackets = tx_total;
343 	igb_stats->oerrors = tx_err_total;
344 }
345 
346 static void
347 eth_stats_reset(struct rte_eth_dev *dev)
348 {
349 	unsigned i;
350 	struct pmd_internals *internal;
351 
352 	if (dev == NULL)
353 		return;
354 
355 	internal = dev->data->dev_private;
356 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
357 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
358 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) {
359 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
360 		internal->tx_null_queues[i].err_pkts.cnt = 0;
361 	}
362 }
363 
364 static void
365 eth_queue_release(void *q)
366 {
367 	struct null_queue *nq;
368 
369 	if (q == NULL)
370 		return;
371 
372 	nq = q;
373 	rte_free(nq->dummy_packet);
374 }
375 
376 static int
377 eth_link_update(struct rte_eth_dev *dev __rte_unused,
378 		int wait_to_complete __rte_unused) { return 0; }
379 
380 static int
381 eth_rss_reta_update(struct rte_eth_dev *dev,
382 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
383 {
384 	int i, j;
385 	struct pmd_internals *internal = dev->data->dev_private;
386 
387 	if (reta_size != internal->reta_size)
388 		return -EINVAL;
389 
390 	rte_spinlock_lock(&internal->rss_lock);
391 
392 	/* Copy RETA table */
393 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
394 		internal->reta_conf[i].mask = reta_conf[i].mask;
395 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
396 			if ((reta_conf[i].mask >> j) & 0x01)
397 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
398 	}
399 
400 	rte_spinlock_unlock(&internal->rss_lock);
401 
402 	return 0;
403 }
404 
405 static int
406 eth_rss_reta_query(struct rte_eth_dev *dev,
407 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
408 {
409 	int i, j;
410 	struct pmd_internals *internal = dev->data->dev_private;
411 
412 	if (reta_size != internal->reta_size)
413 		return -EINVAL;
414 
415 	rte_spinlock_lock(&internal->rss_lock);
416 
417 	/* Copy RETA table */
418 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
419 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
420 			if ((reta_conf[i].mask >> j) & 0x01)
421 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
422 	}
423 
424 	rte_spinlock_unlock(&internal->rss_lock);
425 
426 	return 0;
427 }
428 
429 static int
430 eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
431 {
432 	struct pmd_internals *internal = dev->data->dev_private;
433 
434 	rte_spinlock_lock(&internal->rss_lock);
435 
436 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
437 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
438 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
439 
440 	if (rss_conf->rss_key)
441 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
442 
443 	rte_spinlock_unlock(&internal->rss_lock);
444 
445 	return 0;
446 }
447 
448 static int
449 eth_rss_hash_conf_get(struct rte_eth_dev *dev,
450 		struct rte_eth_rss_conf *rss_conf)
451 {
452 	struct pmd_internals *internal = dev->data->dev_private;
453 
454 	rte_spinlock_lock(&internal->rss_lock);
455 
456 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
457 	if (rss_conf->rss_key)
458 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
459 
460 	rte_spinlock_unlock(&internal->rss_lock);
461 
462 	return 0;
463 }
464 
465 static const struct eth_dev_ops ops = {
466 	.dev_start = eth_dev_start,
467 	.dev_stop = eth_dev_stop,
468 	.dev_configure = eth_dev_configure,
469 	.dev_infos_get = eth_dev_info,
470 	.rx_queue_setup = eth_rx_queue_setup,
471 	.tx_queue_setup = eth_tx_queue_setup,
472 	.rx_queue_release = eth_queue_release,
473 	.tx_queue_release = eth_queue_release,
474 	.link_update = eth_link_update,
475 	.stats_get = eth_stats_get,
476 	.stats_reset = eth_stats_reset,
477 	.reta_update = eth_rss_reta_update,
478 	.reta_query = eth_rss_reta_query,
479 	.rss_hash_update = eth_rss_hash_update,
480 	.rss_hash_conf_get = eth_rss_hash_conf_get
481 };
482 
483 int
484 eth_dev_null_create(const char *name,
485 		const unsigned numa_node,
486 		unsigned packet_size,
487 		unsigned packet_copy)
488 {
489 	const unsigned nb_rx_queues = 1;
490 	const unsigned nb_tx_queues = 1;
491 	struct rte_eth_dev_data *data = NULL;
492 	struct pmd_internals *internals = NULL;
493 	struct rte_eth_dev *eth_dev = NULL;
494 
495 	static const uint8_t default_rss_key[40] = {
496 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
497 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
498 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
499 		0xBE, 0xAC, 0x01, 0xFA
500 	};
501 
502 	if (name == NULL)
503 		return -EINVAL;
504 
505 	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
506 			numa_node);
507 
508 	/* now do all data allocation - for eth_dev structure, dummy pci driver
509 	 * and internal (private) data
510 	 */
511 	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
512 	if (data == NULL)
513 		goto error;
514 
515 	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
516 	if (internals == NULL)
517 		goto error;
518 
519 	/* reserve an ethdev entry */
520 	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
521 	if (eth_dev == NULL)
522 		goto error;
523 
524 	/* now put it all together
525 	 * - store queue data in internals,
526 	 * - store numa_node info in ethdev data
527 	 * - point eth_dev_data to internals
528 	 * - and point eth_dev structure to new eth_dev_data structure
529 	 */
530 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
531 	 * so the nulls are local per-process */
532 
533 	internals->packet_size = packet_size;
534 	internals->packet_copy = packet_copy;
535 	internals->port_id = eth_dev->data->port_id;
536 
537 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
538 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
539 
540 	rte_memcpy(internals->rss_key, default_rss_key, 40);
541 
542 	data->dev_private = internals;
543 	data->port_id = eth_dev->data->port_id;
544 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
545 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
546 	data->dev_link = pmd_link;
547 	data->mac_addrs = &eth_addr;
548 	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
549 
550 	eth_dev->data = data;
551 	eth_dev->dev_ops = &ops;
552 
553 	TAILQ_INIT(&eth_dev->link_intr_cbs);
554 
555 	eth_dev->driver = NULL;
556 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
557 	data->kdrv = RTE_KDRV_NONE;
558 	data->drv_name = drivername;
559 	data->numa_node = numa_node;
560 
561 	/* finally assign rx and tx ops */
562 	if (packet_copy) {
563 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
564 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
565 	} else {
566 		eth_dev->rx_pkt_burst = eth_null_rx;
567 		eth_dev->tx_pkt_burst = eth_null_tx;
568 	}
569 
570 	return 0;
571 
572 error:
573 	rte_free(data);
574 	rte_free(internals);
575 
576 	return -1;
577 }
578 
579 static inline int
580 get_packet_size_arg(const char *key __rte_unused,
581 		const char *value, void *extra_args)
582 {
583 	const char *a = value;
584 	unsigned *packet_size = extra_args;
585 
586 	if ((value == NULL) || (extra_args == NULL))
587 		return -EINVAL;
588 
589 	*packet_size = (unsigned)strtoul(a, NULL, 0);
590 	if (*packet_size == UINT_MAX)
591 		return -1;
592 
593 	return 0;
594 }
595 
596 static inline int
597 get_packet_copy_arg(const char *key __rte_unused,
598 		const char *value, void *extra_args)
599 {
600 	const char *a = value;
601 	unsigned *packet_copy = extra_args;
602 
603 	if ((value == NULL) || (extra_args == NULL))
604 		return -EINVAL;
605 
606 	*packet_copy = (unsigned)strtoul(a, NULL, 0);
607 	if (*packet_copy == UINT_MAX)
608 		return -1;
609 
610 	return 0;
611 }
612 
613 static int
614 rte_pmd_null_devinit(const char *name, const char *params)
615 {
616 	unsigned numa_node;
617 	unsigned packet_size = default_packet_size;
618 	unsigned packet_copy = default_packet_copy;
619 	struct rte_kvargs *kvlist = NULL;
620 	int ret;
621 
622 	if (name == NULL)
623 		return -EINVAL;
624 
625 	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
626 
627 	numa_node = rte_socket_id();
628 
629 	if (params != NULL) {
630 		kvlist = rte_kvargs_parse(params, valid_arguments);
631 		if (kvlist == NULL)
632 			return -1;
633 
634 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
635 
636 			ret = rte_kvargs_process(kvlist,
637 					ETH_NULL_PACKET_SIZE_ARG,
638 					&get_packet_size_arg, &packet_size);
639 			if (ret < 0)
640 				goto free_kvlist;
641 		}
642 
643 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
644 
645 			ret = rte_kvargs_process(kvlist,
646 					ETH_NULL_PACKET_COPY_ARG,
647 					&get_packet_copy_arg, &packet_copy);
648 			if (ret < 0)
649 				goto free_kvlist;
650 		}
651 	}
652 
653 	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
654 			"packet copy is %s\n", packet_size,
655 			packet_copy ? "enabled" : "disabled");
656 
657 	ret = eth_dev_null_create(name, numa_node, packet_size, packet_copy);
658 
659 free_kvlist:
660 	if (kvlist)
661 		rte_kvargs_free(kvlist);
662 	return ret;
663 }
664 
665 static int
666 rte_pmd_null_devuninit(const char *name)
667 {
668 	struct rte_eth_dev *eth_dev = NULL;
669 
670 	if (name == NULL)
671 		return -EINVAL;
672 
673 	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
674 			rte_socket_id());
675 
676 	/* find the ethdev entry */
677 	eth_dev = rte_eth_dev_allocated(name);
678 	if (eth_dev == NULL)
679 		return -1;
680 
681 	rte_free(eth_dev->data->dev_private);
682 	rte_free(eth_dev->data);
683 
684 	rte_eth_dev_release_port(eth_dev);
685 
686 	return 0;
687 }
688 
689 static struct rte_driver pmd_null_drv = {
690 	.type = PMD_VDEV,
691 	.init = rte_pmd_null_devinit,
692 	.uninit = rte_pmd_null_devuninit,
693 };
694 
695 PMD_REGISTER_DRIVER(pmd_null_drv, eth_null);
696 DRIVER_REGISTER_PARAM_STRING(eth_null,
697 	"size=<int> "
698 	"copy=<int>");
699