dpdk/drivers/net/null/rte_eth_null.c
<<
>>
Prefs
   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
  19static unsigned int default_packet_size = 64;
  20static unsigned int default_packet_copy;
  21static unsigned int default_no_rx;
  22
  23static 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
  30struct pmd_internals;
  31
  32struct 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
  42struct pmd_options {
  43        unsigned int packet_copy;
  44        unsigned int packet_size;
  45        unsigned int no_rx;
  46};
  47
  48struct 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};
  69static 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
  76RTE_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
  82static uint16_t
  83eth_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
 107static uint16_t
 108eth_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
 134static uint16_t
 135eth_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
 141static uint16_t
 142eth_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
 158static uint16_t
 159eth_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
 180static int
 181eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
 182{
 183        return 0;
 184}
 185
 186static int
 187eth_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
 196static int
 197eth_dev_stop(struct rte_eth_dev *dev)
 198{
 199        if (dev == NULL)
 200                return 0;
 201
 202        dev->data->dev_link.link_status = ETH_LINK_DOWN;
 203
 204        return 0;
 205}
 206
 207static int
 208eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 209                uint16_t nb_rx_desc __rte_unused,
 210                unsigned int socket_id __rte_unused,
 211                const struct rte_eth_rxconf *rx_conf __rte_unused,
 212                struct rte_mempool *mb_pool)
 213{
 214        struct rte_mbuf *dummy_packet;
 215        struct pmd_internals *internals;
 216        unsigned int packet_size;
 217
 218        if ((dev == NULL) || (mb_pool == NULL))
 219                return -EINVAL;
 220
 221        internals = dev->data->dev_private;
 222
 223        if (rx_queue_id >= dev->data->nb_rx_queues)
 224                return -ENODEV;
 225
 226        packet_size = internals->packet_size;
 227
 228        internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
 229        dev->data->rx_queues[rx_queue_id] =
 230                &internals->rx_null_queues[rx_queue_id];
 231        dummy_packet = rte_zmalloc_socket(NULL,
 232                        packet_size, 0, dev->data->numa_node);
 233        if (dummy_packet == NULL)
 234                return -ENOMEM;
 235
 236        internals->rx_null_queues[rx_queue_id].internals = internals;
 237        internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
 238
 239        return 0;
 240}
 241
 242static int
 243eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
 244                uint16_t nb_tx_desc __rte_unused,
 245                unsigned int socket_id __rte_unused,
 246                const struct rte_eth_txconf *tx_conf __rte_unused)
 247{
 248        struct rte_mbuf *dummy_packet;
 249        struct pmd_internals *internals;
 250        unsigned int packet_size;
 251
 252        if (dev == NULL)
 253                return -EINVAL;
 254
 255        internals = dev->data->dev_private;
 256
 257        if (tx_queue_id >= dev->data->nb_tx_queues)
 258                return -ENODEV;
 259
 260        packet_size = internals->packet_size;
 261
 262        dev->data->tx_queues[tx_queue_id] =
 263                &internals->tx_null_queues[tx_queue_id];
 264        dummy_packet = rte_zmalloc_socket(NULL,
 265                        packet_size, 0, dev->data->numa_node);
 266        if (dummy_packet == NULL)
 267                return -ENOMEM;
 268
 269        internals->tx_null_queues[tx_queue_id].internals = internals;
 270        internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
 271
 272        return 0;
 273}
 274
 275static int
 276eth_mtu_set(struct rte_eth_dev *dev __rte_unused, uint16_t mtu __rte_unused)
 277{
 278        return 0;
 279}
 280
 281static int
 282eth_dev_info(struct rte_eth_dev *dev,
 283                struct rte_eth_dev_info *dev_info)
 284{
 285        struct pmd_internals *internals;
 286
 287        if ((dev == NULL) || (dev_info == NULL))
 288                return -EINVAL;
 289
 290        internals = dev->data->dev_private;
 291        dev_info->max_mac_addrs = 1;
 292        dev_info->max_rx_pktlen = (uint32_t)-1;
 293        dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
 294        dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
 295        dev_info->min_rx_bufsize = 0;
 296        dev_info->reta_size = internals->reta_size;
 297        dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
 298
 299        return 0;
 300}
 301
 302static int
 303eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
 304{
 305        unsigned int i, num_stats;
 306        unsigned long rx_total = 0, tx_total = 0;
 307        const struct pmd_internals *internal;
 308
 309        if ((dev == NULL) || (igb_stats == NULL))
 310                return -EINVAL;
 311
 312        internal = dev->data->dev_private;
 313        num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
 314                        RTE_MIN(dev->data->nb_rx_queues,
 315                                RTE_DIM(internal->rx_null_queues)));
 316        for (i = 0; i < num_stats; i++) {
 317                igb_stats->q_ipackets[i] =
 318                        internal->rx_null_queues[i].rx_pkts.cnt;
 319                rx_total += igb_stats->q_ipackets[i];
 320        }
 321
 322        num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
 323                        RTE_MIN(dev->data->nb_tx_queues,
 324                                RTE_DIM(internal->tx_null_queues)));
 325        for (i = 0; i < num_stats; i++) {
 326                igb_stats->q_opackets[i] =
 327                        internal->tx_null_queues[i].tx_pkts.cnt;
 328                tx_total += igb_stats->q_opackets[i];
 329        }
 330
 331        igb_stats->ipackets = rx_total;
 332        igb_stats->opackets = tx_total;
 333
 334        return 0;
 335}
 336
 337static int
 338eth_stats_reset(struct rte_eth_dev *dev)
 339{
 340        unsigned int i;
 341        struct pmd_internals *internal;
 342
 343        if (dev == NULL)
 344                return -EINVAL;
 345
 346        internal = dev->data->dev_private;
 347        for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
 348                internal->rx_null_queues[i].rx_pkts.cnt = 0;
 349        for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++)
 350                internal->tx_null_queues[i].tx_pkts.cnt = 0;
 351
 352        return 0;
 353}
 354
 355static void
 356eth_queue_release(void *q)
 357{
 358        struct null_queue *nq;
 359
 360        if (q == NULL)
 361                return;
 362
 363        nq = q;
 364        rte_free(nq->dummy_packet);
 365}
 366
 367static int
 368eth_link_update(struct rte_eth_dev *dev __rte_unused,
 369                int wait_to_complete __rte_unused) { return 0; }
 370
 371static int
 372eth_rss_reta_update(struct rte_eth_dev *dev,
 373                struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
 374{
 375        int i, j;
 376        struct pmd_internals *internal = dev->data->dev_private;
 377
 378        if (reta_size != internal->reta_size)
 379                return -EINVAL;
 380
 381        rte_spinlock_lock(&internal->rss_lock);
 382
 383        /* Copy RETA table */
 384        for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
 385                internal->reta_conf[i].mask = reta_conf[i].mask;
 386                for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
 387                        if ((reta_conf[i].mask >> j) & 0x01)
 388                                internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
 389        }
 390
 391        rte_spinlock_unlock(&internal->rss_lock);
 392
 393        return 0;
 394}
 395
 396static int
 397eth_rss_reta_query(struct rte_eth_dev *dev,
 398                struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
 399{
 400        int i, j;
 401        struct pmd_internals *internal = dev->data->dev_private;
 402
 403        if (reta_size != internal->reta_size)
 404                return -EINVAL;
 405
 406        rte_spinlock_lock(&internal->rss_lock);
 407
 408        /* Copy RETA table */
 409        for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
 410                for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
 411                        if ((reta_conf[i].mask >> j) & 0x01)
 412                                reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
 413        }
 414
 415        rte_spinlock_unlock(&internal->rss_lock);
 416
 417        return 0;
 418}
 419
 420static int
 421eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
 422{
 423        struct pmd_internals *internal = dev->data->dev_private;
 424
 425        rte_spinlock_lock(&internal->rss_lock);
 426
 427        if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
 428                dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
 429                                rss_conf->rss_hf & internal->flow_type_rss_offloads;
 430
 431        if (rss_conf->rss_key)
 432                rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
 433
 434        rte_spinlock_unlock(&internal->rss_lock);
 435
 436        return 0;
 437}
 438
 439static int
 440eth_rss_hash_conf_get(struct rte_eth_dev *dev,
 441                struct rte_eth_rss_conf *rss_conf)
 442{
 443        struct pmd_internals *internal = dev->data->dev_private;
 444
 445        rte_spinlock_lock(&internal->rss_lock);
 446
 447        rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
 448        if (rss_conf->rss_key)
 449                rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
 450
 451        rte_spinlock_unlock(&internal->rss_lock);
 452
 453        return 0;
 454}
 455
 456static int
 457eth_mac_address_set(__rte_unused struct rte_eth_dev *dev,
 458                    __rte_unused struct rte_ether_addr *addr)
 459{
 460        return 0;
 461}
 462
 463static int
 464eth_dev_close(struct rte_eth_dev *dev)
 465{
 466        PMD_LOG(INFO, "Closing null ethdev on NUMA socket %u",
 467                        rte_socket_id());
 468
 469        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 470                return 0;
 471
 472        /* mac_addrs must not be freed alone because part of dev_private */
 473        dev->data->mac_addrs = NULL;
 474
 475        return 0;
 476}
 477
 478static const struct eth_dev_ops ops = {
 479        .dev_close = eth_dev_close,
 480        .dev_start = eth_dev_start,
 481        .dev_stop = eth_dev_stop,
 482        .dev_configure = eth_dev_configure,
 483        .dev_infos_get = eth_dev_info,
 484        .rx_queue_setup = eth_rx_queue_setup,
 485        .tx_queue_setup = eth_tx_queue_setup,
 486        .rx_queue_release = eth_queue_release,
 487        .tx_queue_release = eth_queue_release,
 488        .mtu_set = eth_mtu_set,
 489        .link_update = eth_link_update,
 490        .mac_addr_set = eth_mac_address_set,
 491        .stats_get = eth_stats_get,
 492        .stats_reset = eth_stats_reset,
 493        .reta_update = eth_rss_reta_update,
 494        .reta_query = eth_rss_reta_query,
 495        .rss_hash_update = eth_rss_hash_update,
 496        .rss_hash_conf_get = eth_rss_hash_conf_get
 497};
 498
 499static int
 500eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
 501{
 502        const unsigned int nb_rx_queues = 1;
 503        const unsigned int nb_tx_queues = 1;
 504        struct rte_eth_dev_data *data;
 505        struct pmd_internals *internals = NULL;
 506        struct rte_eth_dev *eth_dev = NULL;
 507
 508        static const uint8_t default_rss_key[40] = {
 509                0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
 510                0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
 511                0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
 512                0xBE, 0xAC, 0x01, 0xFA
 513        };
 514
 515        if (dev->device.numa_node == SOCKET_ID_ANY)
 516                dev->device.numa_node = rte_socket_id();
 517
 518        PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
 519                dev->device.numa_node);
 520
 521        eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
 522        if (!eth_dev)
 523                return -ENOMEM;
 524
 525        /* now put it all together
 526         * - store queue data in internals,
 527         * - store numa_node info in ethdev data
 528         * - point eth_dev_data to internals
 529         * - and point eth_dev structure to new eth_dev_data structure
 530         */
 531        /* NOTE: we'll replace the data element, of originally allocated eth_dev
 532         * so the nulls are local per-process */
 533
 534        internals = eth_dev->data->dev_private;
 535        internals->packet_size = args->packet_size;
 536        internals->packet_copy = args->packet_copy;
 537        internals->no_rx = args->no_rx;
 538        internals->port_id = eth_dev->data->port_id;
 539        rte_eth_random_addr(internals->eth_addr.addr_bytes);
 540
 541        internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
 542        internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
 543
 544        rte_memcpy(internals->rss_key, default_rss_key, 40);
 545
 546        data = eth_dev->data;
 547        data->nb_rx_queues = (uint16_t)nb_rx_queues;
 548        data->nb_tx_queues = (uint16_t)nb_tx_queues;
 549        data->dev_link = pmd_link;
 550        data->mac_addrs = &internals->eth_addr;
 551        data->promiscuous = 1;
 552        data->all_multicast = 1;
 553        data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
 554
 555        eth_dev->dev_ops = &ops;
 556
 557        /* finally assign rx and tx ops */
 558        if (internals->packet_copy) {
 559                eth_dev->rx_pkt_burst = eth_null_copy_rx;
 560                eth_dev->tx_pkt_burst = eth_null_copy_tx;
 561        } else if (internals->no_rx) {
 562                eth_dev->rx_pkt_burst = eth_null_no_rx;
 563                eth_dev->tx_pkt_burst = eth_null_tx;
 564        } else {
 565                eth_dev->rx_pkt_burst = eth_null_rx;
 566                eth_dev->tx_pkt_burst = eth_null_tx;
 567        }
 568
 569        rte_eth_dev_probing_finish(eth_dev);
 570        return 0;
 571}
 572
 573static inline int
 574get_packet_size_arg(const char *key __rte_unused,
 575                const char *value, void *extra_args)
 576{
 577        const char *a = value;
 578        unsigned int *packet_size = extra_args;
 579
 580        if ((value == NULL) || (extra_args == NULL))
 581                return -EINVAL;
 582
 583        *packet_size = (unsigned int)strtoul(a, NULL, 0);
 584        if (*packet_size == UINT_MAX)
 585                return -1;
 586
 587        return 0;
 588}
 589
 590static inline int
 591get_packet_copy_arg(const char *key __rte_unused,
 592                const char *value, void *extra_args)
 593{
 594        const char *a = value;
 595        unsigned int *packet_copy = extra_args;
 596
 597        if ((value == NULL) || (extra_args == NULL))
 598                return -EINVAL;
 599
 600        *packet_copy = (unsigned int)strtoul(a, NULL, 0);
 601        if (*packet_copy == UINT_MAX)
 602                return -1;
 603
 604        return 0;
 605}
 606
 607static int
 608get_packet_no_rx_arg(const char *key __rte_unused,
 609                const char *value, void *extra_args)
 610{
 611        const char *a = value;
 612        unsigned int no_rx;
 613
 614        if (value == NULL || extra_args == NULL)
 615                return -EINVAL;
 616
 617        no_rx = (unsigned int)strtoul(a, NULL, 0);
 618        if (no_rx != 0 && no_rx != 1)
 619                return -1;
 620
 621        *(unsigned int *)extra_args = no_rx;
 622        return 0;
 623}
 624
 625static int
 626rte_pmd_null_probe(struct rte_vdev_device *dev)
 627{
 628        const char *name, *params;
 629        struct pmd_options args = {
 630                .packet_copy = default_packet_copy,
 631                .packet_size = default_packet_size,
 632                .no_rx = default_no_rx,
 633        };
 634        struct rte_kvargs *kvlist = NULL;
 635        struct rte_eth_dev *eth_dev;
 636        int ret;
 637
 638        if (!dev)
 639                return -EINVAL;
 640
 641        name = rte_vdev_device_name(dev);
 642        params = rte_vdev_device_args(dev);
 643        PMD_LOG(INFO, "Initializing pmd_null for %s", name);
 644
 645        if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
 646                struct pmd_internals *internals;
 647                eth_dev = rte_eth_dev_attach_secondary(name);
 648                if (!eth_dev) {
 649                        PMD_LOG(ERR, "Failed to probe %s", name);
 650                        return -1;
 651                }
 652                /* TODO: request info from primary to set up Rx and Tx */
 653                eth_dev->dev_ops = &ops;
 654                eth_dev->device = &dev->device;
 655                internals = eth_dev->data->dev_private;
 656                if (internals->packet_copy) {
 657                        eth_dev->rx_pkt_burst = eth_null_copy_rx;
 658                        eth_dev->tx_pkt_burst = eth_null_copy_tx;
 659                } else if (internals->no_rx) {
 660                        eth_dev->rx_pkt_burst = eth_null_no_rx;
 661                        eth_dev->tx_pkt_burst = eth_null_tx;
 662                } else {
 663                        eth_dev->rx_pkt_burst = eth_null_rx;
 664                        eth_dev->tx_pkt_burst = eth_null_tx;
 665                }
 666                rte_eth_dev_probing_finish(eth_dev);
 667                return 0;
 668        }
 669
 670        if (params != NULL) {
 671                kvlist = rte_kvargs_parse(params, valid_arguments);
 672                if (kvlist == NULL)
 673                        return -1;
 674
 675                ret = rte_kvargs_process(kvlist,
 676                                ETH_NULL_PACKET_SIZE_ARG,
 677                                &get_packet_size_arg, &args.packet_size);
 678                if (ret < 0)
 679                        goto free_kvlist;
 680
 681
 682                ret = rte_kvargs_process(kvlist,
 683                                ETH_NULL_PACKET_COPY_ARG,
 684                                &get_packet_copy_arg, &args.packet_copy);
 685                if (ret < 0)
 686                        goto free_kvlist;
 687
 688                ret = rte_kvargs_process(kvlist,
 689                                ETH_NULL_PACKET_NO_RX_ARG,
 690                                &get_packet_no_rx_arg, &args.no_rx);
 691                if (ret < 0)
 692                        goto free_kvlist;
 693
 694                if (args.no_rx && args.packet_copy) {
 695                        PMD_LOG(ERR,
 696                                "Both %s and %s arguments at the same time not supported",
 697                                ETH_NULL_PACKET_COPY_ARG,
 698                                ETH_NULL_PACKET_NO_RX_ARG);
 699                        goto free_kvlist;
 700                }
 701        }
 702
 703        PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
 704                        "packet copy is %s", args.packet_size,
 705                        args.packet_copy ? "enabled" : "disabled");
 706
 707        ret = eth_dev_null_create(dev, &args);
 708
 709free_kvlist:
 710        if (kvlist)
 711                rte_kvargs_free(kvlist);
 712        return ret;
 713}
 714
 715static int
 716rte_pmd_null_remove(struct rte_vdev_device *dev)
 717{
 718        struct rte_eth_dev *eth_dev = NULL;
 719
 720        if (!dev)
 721                return -EINVAL;
 722
 723        /* find the ethdev entry */
 724        eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
 725        if (eth_dev == NULL)
 726                return 0; /* port already released */
 727
 728        eth_dev_close(eth_dev);
 729        rte_eth_dev_release_port(eth_dev);
 730
 731        return 0;
 732}
 733
 734static struct rte_vdev_driver pmd_null_drv = {
 735        .probe = rte_pmd_null_probe,
 736        .remove = rte_pmd_null_remove,
 737};
 738
 739RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
 740RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
 741RTE_PMD_REGISTER_PARAM_STRING(net_null,
 742        "size=<int> "
 743        "copy=<int> "
 744        ETH_NULL_PACKET_NO_RX_ARG "=0|1");
 745