9704895f791131b042ee1981912affd1b53bfdc1
[deb_dpdk.git] / drivers / net / null / rte_eth_null.c
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_vdev.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_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);
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_probe(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_remove(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_vdev_driver pmd_null_drv = {
690         .probe = rte_pmd_null_probe,
691         .remove = rte_pmd_null_remove,
692 };
693
694 RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
695 RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
696 RTE_PMD_REGISTER_PARAM_STRING(net_null,
697         "size=<int> "
698         "copy=<int>");