xref: /dpdk/drivers/net/null/rte_eth_null.c (revision 3e0ceb9f17fff027fc6c8f18de35e11719ffa61e)
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_ethdev_vdev.h>
37 #include <rte_malloc.h>
38 #include <rte_memcpy.h>
39 #include <rte_bus_vdev.h>
40 #include <rte_kvargs.h>
41 #include <rte_spinlock.h>
42 
43 #define ETH_NULL_PACKET_SIZE_ARG	"size"
44 #define ETH_NULL_PACKET_COPY_ARG	"copy"
45 
46 static unsigned default_packet_size = 64;
47 static unsigned default_packet_copy;
48 
49 static const char *valid_arguments[] = {
50 	ETH_NULL_PACKET_SIZE_ARG,
51 	ETH_NULL_PACKET_COPY_ARG,
52 	NULL
53 };
54 
55 struct pmd_internals;
56 
57 struct null_queue {
58 	struct pmd_internals *internals;
59 
60 	struct rte_mempool *mb_pool;
61 	struct rte_mbuf *dummy_packet;
62 
63 	rte_atomic64_t rx_pkts;
64 	rte_atomic64_t tx_pkts;
65 	rte_atomic64_t err_pkts;
66 };
67 
68 struct pmd_internals {
69 	unsigned packet_size;
70 	unsigned packet_copy;
71 	uint16_t port_id;
72 
73 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
74 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
75 
76 	/** Bit mask of RSS offloads, the bit offset also means flow type */
77 	uint64_t flow_type_rss_offloads;
78 
79 	rte_spinlock_t rss_lock;
80 
81 	uint16_t reta_size;
82 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
83 			RTE_RETA_GROUP_SIZE];
84 
85 	uint8_t rss_key[40];                /**< 40-byte hash key. */
86 };
87 
88 
89 static struct ether_addr eth_addr = { .addr_bytes = {0} };
90 static struct rte_eth_link pmd_link = {
91 	.link_speed = ETH_SPEED_NUM_10G,
92 	.link_duplex = ETH_LINK_FULL_DUPLEX,
93 	.link_status = ETH_LINK_DOWN,
94 	.link_autoneg = ETH_LINK_SPEED_AUTONEG,
95 };
96 
97 static uint16_t
98 eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
99 {
100 	int i;
101 	struct null_queue *h = q;
102 	unsigned packet_size;
103 
104 	if ((q == NULL) || (bufs == NULL))
105 		return 0;
106 
107 	packet_size = h->internals->packet_size;
108 	for (i = 0; i < nb_bufs; i++) {
109 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
110 		if (!bufs[i])
111 			break;
112 		bufs[i]->data_len = (uint16_t)packet_size;
113 		bufs[i]->pkt_len = packet_size;
114 		bufs[i]->port = h->internals->port_id;
115 	}
116 
117 	rte_atomic64_add(&(h->rx_pkts), i);
118 
119 	return i;
120 }
121 
122 static uint16_t
123 eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
124 {
125 	int i;
126 	struct null_queue *h = q;
127 	unsigned packet_size;
128 
129 	if ((q == NULL) || (bufs == NULL))
130 		return 0;
131 
132 	packet_size = h->internals->packet_size;
133 	for (i = 0; i < nb_bufs; i++) {
134 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
135 		if (!bufs[i])
136 			break;
137 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
138 					packet_size);
139 		bufs[i]->data_len = (uint16_t)packet_size;
140 		bufs[i]->pkt_len = packet_size;
141 		bufs[i]->port = h->internals->port_id;
142 	}
143 
144 	rte_atomic64_add(&(h->rx_pkts), i);
145 
146 	return i;
147 }
148 
149 static uint16_t
150 eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
151 {
152 	int i;
153 	struct null_queue *h = q;
154 
155 	if ((q == NULL) || (bufs == NULL))
156 		return 0;
157 
158 	for (i = 0; i < nb_bufs; i++)
159 		rte_pktmbuf_free(bufs[i]);
160 
161 	rte_atomic64_add(&(h->tx_pkts), i);
162 
163 	return i;
164 }
165 
166 static uint16_t
167 eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
168 {
169 	int i;
170 	struct null_queue *h = q;
171 	unsigned packet_size;
172 
173 	if ((q == NULL) || (bufs == NULL))
174 		return 0;
175 
176 	packet_size = h->internals->packet_size;
177 	for (i = 0; i < nb_bufs; i++) {
178 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
179 					packet_size);
180 		rte_pktmbuf_free(bufs[i]);
181 	}
182 
183 	rte_atomic64_add(&(h->tx_pkts), i);
184 
185 	return i;
186 }
187 
188 static int
189 eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
190 {
191 	return 0;
192 }
193 
194 static int
195 eth_dev_start(struct rte_eth_dev *dev)
196 {
197 	if (dev == NULL)
198 		return -EINVAL;
199 
200 	dev->data->dev_link.link_status = ETH_LINK_UP;
201 	return 0;
202 }
203 
204 static void
205 eth_dev_stop(struct rte_eth_dev *dev)
206 {
207 	if (dev == NULL)
208 		return;
209 
210 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
211 }
212 
213 static int
214 eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
215 		uint16_t nb_rx_desc __rte_unused,
216 		unsigned int socket_id __rte_unused,
217 		const struct rte_eth_rxconf *rx_conf __rte_unused,
218 		struct rte_mempool *mb_pool)
219 {
220 	struct rte_mbuf *dummy_packet;
221 	struct pmd_internals *internals;
222 	unsigned packet_size;
223 
224 	if ((dev == NULL) || (mb_pool == NULL))
225 		return -EINVAL;
226 
227 	internals = dev->data->dev_private;
228 
229 	if (rx_queue_id >= dev->data->nb_rx_queues)
230 		return -ENODEV;
231 
232 	packet_size = internals->packet_size;
233 
234 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
235 	dev->data->rx_queues[rx_queue_id] =
236 		&internals->rx_null_queues[rx_queue_id];
237 	dummy_packet = rte_zmalloc_socket(NULL,
238 			packet_size, 0, dev->data->numa_node);
239 	if (dummy_packet == NULL)
240 		return -ENOMEM;
241 
242 	internals->rx_null_queues[rx_queue_id].internals = internals;
243 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
244 
245 	return 0;
246 }
247 
248 static int
249 eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
250 		uint16_t nb_tx_desc __rte_unused,
251 		unsigned int socket_id __rte_unused,
252 		const struct rte_eth_txconf *tx_conf __rte_unused)
253 {
254 	struct rte_mbuf *dummy_packet;
255 	struct pmd_internals *internals;
256 	unsigned packet_size;
257 
258 	if (dev == NULL)
259 		return -EINVAL;
260 
261 	internals = dev->data->dev_private;
262 
263 	if (tx_queue_id >= dev->data->nb_tx_queues)
264 		return -ENODEV;
265 
266 	packet_size = internals->packet_size;
267 
268 	dev->data->tx_queues[tx_queue_id] =
269 		&internals->tx_null_queues[tx_queue_id];
270 	dummy_packet = rte_zmalloc_socket(NULL,
271 			packet_size, 0, dev->data->numa_node);
272 	if (dummy_packet == NULL)
273 		return -ENOMEM;
274 
275 	internals->tx_null_queues[tx_queue_id].internals = internals;
276 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
277 
278 	return 0;
279 }
280 
281 
282 static void
283 eth_dev_info(struct rte_eth_dev *dev,
284 		struct rte_eth_dev_info *dev_info)
285 {
286 	struct pmd_internals *internals;
287 
288 	if ((dev == NULL) || (dev_info == NULL))
289 		return;
290 
291 	internals = dev->data->dev_private;
292 	dev_info->max_mac_addrs = 1;
293 	dev_info->max_rx_pktlen = (uint32_t)-1;
294 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
295 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
296 	dev_info->min_rx_bufsize = 0;
297 	dev_info->reta_size = internals->reta_size;
298 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
299 }
300 
301 static int
302 eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
303 {
304 	unsigned i, num_stats;
305 	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
306 	const struct pmd_internals *internal;
307 
308 	if ((dev == NULL) || (igb_stats == NULL))
309 		return -EINVAL;
310 
311 	internal = dev->data->dev_private;
312 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
313 			RTE_MIN(dev->data->nb_rx_queues,
314 				RTE_DIM(internal->rx_null_queues)));
315 	for (i = 0; i < num_stats; i++) {
316 		igb_stats->q_ipackets[i] =
317 			internal->rx_null_queues[i].rx_pkts.cnt;
318 		rx_total += igb_stats->q_ipackets[i];
319 	}
320 
321 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
322 			RTE_MIN(dev->data->nb_tx_queues,
323 				RTE_DIM(internal->tx_null_queues)));
324 	for (i = 0; i < num_stats; i++) {
325 		igb_stats->q_opackets[i] =
326 			internal->tx_null_queues[i].tx_pkts.cnt;
327 		igb_stats->q_errors[i] =
328 			internal->tx_null_queues[i].err_pkts.cnt;
329 		tx_total += igb_stats->q_opackets[i];
330 		tx_err_total += igb_stats->q_errors[i];
331 	}
332 
333 	igb_stats->ipackets = rx_total;
334 	igb_stats->opackets = tx_total;
335 	igb_stats->oerrors = tx_err_total;
336 
337 	return 0;
338 }
339 
340 static void
341 eth_stats_reset(struct rte_eth_dev *dev)
342 {
343 	unsigned i;
344 	struct pmd_internals *internal;
345 
346 	if (dev == NULL)
347 		return;
348 
349 	internal = dev->data->dev_private;
350 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
351 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
352 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) {
353 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
354 		internal->tx_null_queues[i].err_pkts.cnt = 0;
355 	}
356 }
357 
358 static void
359 eth_queue_release(void *q)
360 {
361 	struct null_queue *nq;
362 
363 	if (q == NULL)
364 		return;
365 
366 	nq = q;
367 	rte_free(nq->dummy_packet);
368 }
369 
370 static int
371 eth_link_update(struct rte_eth_dev *dev __rte_unused,
372 		int wait_to_complete __rte_unused) { return 0; }
373 
374 static int
375 eth_rss_reta_update(struct rte_eth_dev *dev,
376 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
377 {
378 	int i, j;
379 	struct pmd_internals *internal = dev->data->dev_private;
380 
381 	if (reta_size != internal->reta_size)
382 		return -EINVAL;
383 
384 	rte_spinlock_lock(&internal->rss_lock);
385 
386 	/* Copy RETA table */
387 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
388 		internal->reta_conf[i].mask = reta_conf[i].mask;
389 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
390 			if ((reta_conf[i].mask >> j) & 0x01)
391 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
392 	}
393 
394 	rte_spinlock_unlock(&internal->rss_lock);
395 
396 	return 0;
397 }
398 
399 static int
400 eth_rss_reta_query(struct rte_eth_dev *dev,
401 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
402 {
403 	int i, j;
404 	struct pmd_internals *internal = dev->data->dev_private;
405 
406 	if (reta_size != internal->reta_size)
407 		return -EINVAL;
408 
409 	rte_spinlock_lock(&internal->rss_lock);
410 
411 	/* Copy RETA table */
412 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
413 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
414 			if ((reta_conf[i].mask >> j) & 0x01)
415 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
416 	}
417 
418 	rte_spinlock_unlock(&internal->rss_lock);
419 
420 	return 0;
421 }
422 
423 static int
424 eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
425 {
426 	struct pmd_internals *internal = dev->data->dev_private;
427 
428 	rte_spinlock_lock(&internal->rss_lock);
429 
430 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
431 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
432 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
433 
434 	if (rss_conf->rss_key)
435 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
436 
437 	rte_spinlock_unlock(&internal->rss_lock);
438 
439 	return 0;
440 }
441 
442 static int
443 eth_rss_hash_conf_get(struct rte_eth_dev *dev,
444 		struct rte_eth_rss_conf *rss_conf)
445 {
446 	struct pmd_internals *internal = dev->data->dev_private;
447 
448 	rte_spinlock_lock(&internal->rss_lock);
449 
450 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
451 	if (rss_conf->rss_key)
452 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
453 
454 	rte_spinlock_unlock(&internal->rss_lock);
455 
456 	return 0;
457 }
458 
459 static const struct eth_dev_ops ops = {
460 	.dev_start = eth_dev_start,
461 	.dev_stop = eth_dev_stop,
462 	.dev_configure = eth_dev_configure,
463 	.dev_infos_get = eth_dev_info,
464 	.rx_queue_setup = eth_rx_queue_setup,
465 	.tx_queue_setup = eth_tx_queue_setup,
466 	.rx_queue_release = eth_queue_release,
467 	.tx_queue_release = eth_queue_release,
468 	.link_update = eth_link_update,
469 	.stats_get = eth_stats_get,
470 	.stats_reset = eth_stats_reset,
471 	.reta_update = eth_rss_reta_update,
472 	.reta_query = eth_rss_reta_query,
473 	.rss_hash_update = eth_rss_hash_update,
474 	.rss_hash_conf_get = eth_rss_hash_conf_get
475 };
476 
477 static struct rte_vdev_driver pmd_null_drv;
478 
479 static int
480 eth_dev_null_create(struct rte_vdev_device *dev,
481 		unsigned packet_size,
482 		unsigned packet_copy)
483 {
484 	const unsigned nb_rx_queues = 1;
485 	const unsigned nb_tx_queues = 1;
486 	struct rte_eth_dev_data *data = NULL;
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 	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
501 		dev->device.numa_node);
502 
503 	/* now do all data allocation - for eth_dev structure, dummy pci driver
504 	 * and internal (private) data
505 	 */
506 	data = rte_zmalloc_socket(rte_vdev_device_name(dev), sizeof(*data), 0,
507 		dev->device.numa_node);
508 	if (!data)
509 		return -ENOMEM;
510 
511 	eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
512 	if (!eth_dev) {
513 		rte_free(data);
514 		return -ENOMEM;
515 	}
516 
517 	/* now put it all together
518 	 * - store queue data in internals,
519 	 * - store numa_node info in ethdev data
520 	 * - point eth_dev_data to internals
521 	 * - and point eth_dev structure to new eth_dev_data structure
522 	 */
523 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
524 	 * so the nulls are local per-process */
525 
526 	internals = eth_dev->data->dev_private;
527 	internals->packet_size = packet_size;
528 	internals->packet_copy = packet_copy;
529 	internals->port_id = eth_dev->data->port_id;
530 
531 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
532 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
533 
534 	rte_memcpy(internals->rss_key, default_rss_key, 40);
535 
536 	rte_memcpy(data, eth_dev->data, sizeof(*data));
537 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
538 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
539 	data->dev_link = pmd_link;
540 	data->mac_addrs = &eth_addr;
541 
542 	eth_dev->data = data;
543 	eth_dev->dev_ops = &ops;
544 
545 	/* finally assign rx and tx ops */
546 	if (packet_copy) {
547 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
548 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
549 	} else {
550 		eth_dev->rx_pkt_burst = eth_null_rx;
551 		eth_dev->tx_pkt_burst = eth_null_tx;
552 	}
553 
554 	return 0;
555 }
556 
557 static inline int
558 get_packet_size_arg(const char *key __rte_unused,
559 		const char *value, void *extra_args)
560 {
561 	const char *a = value;
562 	unsigned *packet_size = extra_args;
563 
564 	if ((value == NULL) || (extra_args == NULL))
565 		return -EINVAL;
566 
567 	*packet_size = (unsigned)strtoul(a, NULL, 0);
568 	if (*packet_size == UINT_MAX)
569 		return -1;
570 
571 	return 0;
572 }
573 
574 static inline int
575 get_packet_copy_arg(const char *key __rte_unused,
576 		const char *value, void *extra_args)
577 {
578 	const char *a = value;
579 	unsigned *packet_copy = extra_args;
580 
581 	if ((value == NULL) || (extra_args == NULL))
582 		return -EINVAL;
583 
584 	*packet_copy = (unsigned)strtoul(a, NULL, 0);
585 	if (*packet_copy == UINT_MAX)
586 		return -1;
587 
588 	return 0;
589 }
590 
591 static int
592 rte_pmd_null_probe(struct rte_vdev_device *dev)
593 {
594 	const char *name, *params;
595 	unsigned packet_size = default_packet_size;
596 	unsigned packet_copy = default_packet_copy;
597 	struct rte_kvargs *kvlist = NULL;
598 	int ret;
599 
600 	if (!dev)
601 		return -EINVAL;
602 
603 	name = rte_vdev_device_name(dev);
604 	params = rte_vdev_device_args(dev);
605 	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
606 
607 	if (params != NULL) {
608 		kvlist = rte_kvargs_parse(params, valid_arguments);
609 		if (kvlist == NULL)
610 			return -1;
611 
612 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
613 
614 			ret = rte_kvargs_process(kvlist,
615 					ETH_NULL_PACKET_SIZE_ARG,
616 					&get_packet_size_arg, &packet_size);
617 			if (ret < 0)
618 				goto free_kvlist;
619 		}
620 
621 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
622 
623 			ret = rte_kvargs_process(kvlist,
624 					ETH_NULL_PACKET_COPY_ARG,
625 					&get_packet_copy_arg, &packet_copy);
626 			if (ret < 0)
627 				goto free_kvlist;
628 		}
629 	}
630 
631 	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
632 			"packet copy is %s\n", packet_size,
633 			packet_copy ? "enabled" : "disabled");
634 
635 	ret = eth_dev_null_create(dev, packet_size, packet_copy);
636 
637 free_kvlist:
638 	if (kvlist)
639 		rte_kvargs_free(kvlist);
640 	return ret;
641 }
642 
643 static int
644 rte_pmd_null_remove(struct rte_vdev_device *dev)
645 {
646 	struct rte_eth_dev *eth_dev = NULL;
647 
648 	if (!dev)
649 		return -EINVAL;
650 
651 	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
652 			rte_socket_id());
653 
654 	/* find the ethdev entry */
655 	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
656 	if (eth_dev == NULL)
657 		return -1;
658 
659 	rte_free(eth_dev->data->dev_private);
660 	rte_free(eth_dev->data);
661 
662 	rte_eth_dev_release_port(eth_dev);
663 
664 	return 0;
665 }
666 
667 static struct rte_vdev_driver pmd_null_drv = {
668 	.probe = rte_pmd_null_probe,
669 	.remove = rte_pmd_null_remove,
670 };
671 
672 RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
673 RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
674 RTE_PMD_REGISTER_PARAM_STRING(net_null,
675 	"size=<int> "
676 	"copy=<int>");
677