net/bnxt: consolidate template table processing
[dpdk.git] / drivers / net / null / rte_eth_null.c
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 RTE_LOG_REGISTER(eth_null_logtype, pmd.net.null, NOTICE);
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 int
462 eth_dev_close(struct rte_eth_dev *dev)
463 {
464         PMD_LOG(INFO, "Closing null ethdev on NUMA socket %u",
465                         rte_socket_id());
466
467         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
468                 return 0;
469
470         /* mac_addrs must not be freed alone because part of dev_private */
471         dev->data->mac_addrs = NULL;
472
473         return 0;
474 }
475
476 static const struct eth_dev_ops ops = {
477         .dev_close = eth_dev_close,
478         .dev_start = eth_dev_start,
479         .dev_stop = eth_dev_stop,
480         .dev_configure = eth_dev_configure,
481         .dev_infos_get = eth_dev_info,
482         .rx_queue_setup = eth_rx_queue_setup,
483         .tx_queue_setup = eth_tx_queue_setup,
484         .rx_queue_release = eth_queue_release,
485         .tx_queue_release = eth_queue_release,
486         .mtu_set = eth_mtu_set,
487         .link_update = eth_link_update,
488         .mac_addr_set = eth_mac_address_set,
489         .stats_get = eth_stats_get,
490         .stats_reset = eth_stats_reset,
491         .reta_update = eth_rss_reta_update,
492         .reta_query = eth_rss_reta_query,
493         .rss_hash_update = eth_rss_hash_update,
494         .rss_hash_conf_get = eth_rss_hash_conf_get
495 };
496
497 static int
498 eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
499 {
500         const unsigned int nb_rx_queues = 1;
501         const unsigned int nb_tx_queues = 1;
502         struct rte_eth_dev_data *data;
503         struct pmd_internals *internals = NULL;
504         struct rte_eth_dev *eth_dev = NULL;
505
506         static const uint8_t default_rss_key[40] = {
507                 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
508                 0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
509                 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
510                 0xBE, 0xAC, 0x01, 0xFA
511         };
512
513         if (dev->device.numa_node == SOCKET_ID_ANY)
514                 dev->device.numa_node = rte_socket_id();
515
516         PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
517                 dev->device.numa_node);
518
519         eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
520         if (!eth_dev)
521                 return -ENOMEM;
522
523         /* now put it all together
524          * - store queue data in internals,
525          * - store numa_node info in ethdev data
526          * - point eth_dev_data to internals
527          * - and point eth_dev structure to new eth_dev_data structure
528          */
529         /* NOTE: we'll replace the data element, of originally allocated eth_dev
530          * so the nulls are local per-process */
531
532         internals = eth_dev->data->dev_private;
533         internals->packet_size = args->packet_size;
534         internals->packet_copy = args->packet_copy;
535         internals->no_rx = args->no_rx;
536         internals->port_id = eth_dev->data->port_id;
537         rte_eth_random_addr(internals->eth_addr.addr_bytes);
538
539         internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
540         internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
541
542         rte_memcpy(internals->rss_key, default_rss_key, 40);
543
544         data = eth_dev->data;
545         data->nb_rx_queues = (uint16_t)nb_rx_queues;
546         data->nb_tx_queues = (uint16_t)nb_tx_queues;
547         data->dev_link = pmd_link;
548         data->mac_addrs = &internals->eth_addr;
549         data->promiscuous = 1;
550         data->all_multicast = 1;
551
552         eth_dev->dev_ops = &ops;
553
554         /* finally assign rx and tx ops */
555         if (internals->packet_copy) {
556                 eth_dev->rx_pkt_burst = eth_null_copy_rx;
557                 eth_dev->tx_pkt_burst = eth_null_copy_tx;
558         } else if (internals->no_rx) {
559                 eth_dev->rx_pkt_burst = eth_null_no_rx;
560                 eth_dev->tx_pkt_burst = eth_null_tx;
561         } else {
562                 eth_dev->rx_pkt_burst = eth_null_rx;
563                 eth_dev->tx_pkt_burst = eth_null_tx;
564         }
565
566         rte_eth_dev_probing_finish(eth_dev);
567         return 0;
568 }
569
570 static inline int
571 get_packet_size_arg(const char *key __rte_unused,
572                 const char *value, void *extra_args)
573 {
574         const char *a = value;
575         unsigned int *packet_size = extra_args;
576
577         if ((value == NULL) || (extra_args == NULL))
578                 return -EINVAL;
579
580         *packet_size = (unsigned int)strtoul(a, NULL, 0);
581         if (*packet_size == UINT_MAX)
582                 return -1;
583
584         return 0;
585 }
586
587 static inline int
588 get_packet_copy_arg(const char *key __rte_unused,
589                 const char *value, void *extra_args)
590 {
591         const char *a = value;
592         unsigned int *packet_copy = extra_args;
593
594         if ((value == NULL) || (extra_args == NULL))
595                 return -EINVAL;
596
597         *packet_copy = (unsigned int)strtoul(a, NULL, 0);
598         if (*packet_copy == UINT_MAX)
599                 return -1;
600
601         return 0;
602 }
603
604 static int
605 get_packet_no_rx_arg(const char *key __rte_unused,
606                 const char *value, void *extra_args)
607 {
608         const char *a = value;
609         unsigned int no_rx;
610
611         if (value == NULL || extra_args == NULL)
612                 return -EINVAL;
613
614         no_rx = (unsigned int)strtoul(a, NULL, 0);
615         if (no_rx != 0 && no_rx != 1)
616                 return -1;
617
618         *(unsigned int *)extra_args = no_rx;
619         return 0;
620 }
621
622 static int
623 rte_pmd_null_probe(struct rte_vdev_device *dev)
624 {
625         const char *name, *params;
626         struct pmd_options args = {
627                 .packet_copy = default_packet_copy,
628                 .packet_size = default_packet_size,
629                 .no_rx = default_no_rx,
630         };
631         struct rte_kvargs *kvlist = NULL;
632         struct rte_eth_dev *eth_dev;
633         int ret;
634
635         if (!dev)
636                 return -EINVAL;
637
638         name = rte_vdev_device_name(dev);
639         params = rte_vdev_device_args(dev);
640         PMD_LOG(INFO, "Initializing pmd_null for %s", name);
641
642         if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
643                 struct pmd_internals *internals;
644                 eth_dev = rte_eth_dev_attach_secondary(name);
645                 if (!eth_dev) {
646                         PMD_LOG(ERR, "Failed to probe %s", name);
647                         return -1;
648                 }
649                 /* TODO: request info from primary to set up Rx and Tx */
650                 eth_dev->dev_ops = &ops;
651                 eth_dev->device = &dev->device;
652                 internals = eth_dev->data->dev_private;
653                 if (internals->packet_copy) {
654                         eth_dev->rx_pkt_burst = eth_null_copy_rx;
655                         eth_dev->tx_pkt_burst = eth_null_copy_tx;
656                 } else if (internals->no_rx) {
657                         eth_dev->rx_pkt_burst = eth_null_no_rx;
658                         eth_dev->tx_pkt_burst = eth_null_tx;
659                 } else {
660                         eth_dev->rx_pkt_burst = eth_null_rx;
661                         eth_dev->tx_pkt_burst = eth_null_tx;
662                 }
663                 rte_eth_dev_probing_finish(eth_dev);
664                 return 0;
665         }
666
667         if (params != NULL) {
668                 kvlist = rte_kvargs_parse(params, valid_arguments);
669                 if (kvlist == NULL)
670                         return -1;
671
672                 ret = rte_kvargs_process(kvlist,
673                                 ETH_NULL_PACKET_SIZE_ARG,
674                                 &get_packet_size_arg, &args.packet_size);
675                 if (ret < 0)
676                         goto free_kvlist;
677
678
679                 ret = rte_kvargs_process(kvlist,
680                                 ETH_NULL_PACKET_COPY_ARG,
681                                 &get_packet_copy_arg, &args.packet_copy);
682                 if (ret < 0)
683                         goto free_kvlist;
684
685                 ret = rte_kvargs_process(kvlist,
686                                 ETH_NULL_PACKET_NO_RX_ARG,
687                                 &get_packet_no_rx_arg, &args.no_rx);
688                 if (ret < 0)
689                         goto free_kvlist;
690
691                 if (args.no_rx && args.packet_copy) {
692                         PMD_LOG(ERR,
693                                 "Both %s and %s arguments at the same time not supported",
694                                 ETH_NULL_PACKET_COPY_ARG,
695                                 ETH_NULL_PACKET_NO_RX_ARG);
696                         goto free_kvlist;
697                 }
698         }
699
700         PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
701                         "packet copy is %s", args.packet_size,
702                         args.packet_copy ? "enabled" : "disabled");
703
704         ret = eth_dev_null_create(dev, &args);
705
706 free_kvlist:
707         if (kvlist)
708                 rte_kvargs_free(kvlist);
709         return ret;
710 }
711
712 static int
713 rte_pmd_null_remove(struct rte_vdev_device *dev)
714 {
715         struct rte_eth_dev *eth_dev = NULL;
716
717         if (!dev)
718                 return -EINVAL;
719
720         /* find the ethdev entry */
721         eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
722         if (eth_dev == NULL)
723                 return 0; /* port already released */
724
725         eth_dev_close(eth_dev);
726         rte_eth_dev_release_port(eth_dev);
727
728         return 0;
729 }
730
731 static struct rte_vdev_driver pmd_null_drv = {
732         .probe = rte_pmd_null_probe,
733         .remove = rte_pmd_null_remove,
734 };
735
736 RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
737 RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
738 RTE_PMD_REGISTER_PARAM_STRING(net_null,
739         "size=<int> "
740         "copy=<int> "
741         ETH_NULL_PACKET_NO_RX_ARG "=0|1");