dpdk/drivers/net/ring/rte_eth_ring.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2015 Intel Corporation
   3 */
   4
   5#include "rte_eth_ring.h"
   6#include <rte_mbuf.h>
   7#include <ethdev_driver.h>
   8#include <rte_malloc.h>
   9#include <rte_memcpy.h>
  10#include <rte_string_fns.h>
  11#include <rte_bus_vdev.h>
  12#include <rte_kvargs.h>
  13#include <rte_errno.h>
  14
  15#define ETH_RING_NUMA_NODE_ACTION_ARG   "nodeaction"
  16#define ETH_RING_ACTION_CREATE          "CREATE"
  17#define ETH_RING_ACTION_ATTACH          "ATTACH"
  18#define ETH_RING_INTERNAL_ARG           "internal"
  19#define ETH_RING_INTERNAL_ARG_MAX_LEN   19 /* "0x..16chars..\0" */
  20
  21static const char *valid_arguments[] = {
  22        ETH_RING_NUMA_NODE_ACTION_ARG,
  23        ETH_RING_INTERNAL_ARG,
  24        NULL
  25};
  26
  27struct ring_internal_args {
  28        struct rte_ring * const *rx_queues;
  29        const unsigned int nb_rx_queues;
  30        struct rte_ring * const *tx_queues;
  31        const unsigned int nb_tx_queues;
  32        const unsigned int numa_node;
  33        void *addr; /* self addr for sanity check */
  34};
  35
  36enum dev_action {
  37        DEV_CREATE,
  38        DEV_ATTACH
  39};
  40
  41struct ring_queue {
  42        struct rte_ring *rng;
  43        rte_atomic64_t rx_pkts;
  44        rte_atomic64_t tx_pkts;
  45};
  46
  47struct pmd_internals {
  48        unsigned int max_rx_queues;
  49        unsigned int max_tx_queues;
  50
  51        struct ring_queue rx_ring_queues[RTE_PMD_RING_MAX_RX_RINGS];
  52        struct ring_queue tx_ring_queues[RTE_PMD_RING_MAX_TX_RINGS];
  53
  54        struct rte_ether_addr address;
  55        enum dev_action action;
  56};
  57
  58static struct rte_eth_link pmd_link = {
  59        .link_speed = ETH_SPEED_NUM_10G,
  60        .link_duplex = ETH_LINK_FULL_DUPLEX,
  61        .link_status = ETH_LINK_DOWN,
  62        .link_autoneg = ETH_LINK_FIXED,
  63};
  64
  65RTE_LOG_REGISTER_DEFAULT(eth_ring_logtype, NOTICE);
  66
  67#define PMD_LOG(level, fmt, args...) \
  68        rte_log(RTE_LOG_ ## level, eth_ring_logtype, \
  69                "%s(): " fmt "\n", __func__, ##args)
  70
  71static uint16_t
  72eth_ring_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
  73{
  74        void **ptrs = (void *)&bufs[0];
  75        struct ring_queue *r = q;
  76        const uint16_t nb_rx = (uint16_t)rte_ring_dequeue_burst(r->rng,
  77                        ptrs, nb_bufs, NULL);
  78        if (r->rng->flags & RING_F_SC_DEQ)
  79                r->rx_pkts.cnt += nb_rx;
  80        else
  81                rte_atomic64_add(&(r->rx_pkts), nb_rx);
  82        return nb_rx;
  83}
  84
  85static uint16_t
  86eth_ring_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
  87{
  88        void **ptrs = (void *)&bufs[0];
  89        struct ring_queue *r = q;
  90        const uint16_t nb_tx = (uint16_t)rte_ring_enqueue_burst(r->rng,
  91                        ptrs, nb_bufs, NULL);
  92        if (r->rng->flags & RING_F_SP_ENQ)
  93                r->tx_pkts.cnt += nb_tx;
  94        else
  95                rte_atomic64_add(&(r->tx_pkts), nb_tx);
  96        return nb_tx;
  97}
  98
  99static int
 100eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
 101
 102static int
 103eth_dev_start(struct rte_eth_dev *dev)
 104{
 105        dev->data->dev_link.link_status = ETH_LINK_UP;
 106        return 0;
 107}
 108
 109static int
 110eth_dev_stop(struct rte_eth_dev *dev)
 111{
 112        dev->data->dev_started = 0;
 113        dev->data->dev_link.link_status = ETH_LINK_DOWN;
 114        return 0;
 115}
 116
 117static int
 118eth_dev_set_link_down(struct rte_eth_dev *dev)
 119{
 120        dev->data->dev_link.link_status = ETH_LINK_DOWN;
 121        return 0;
 122}
 123
 124static int
 125eth_dev_set_link_up(struct rte_eth_dev *dev)
 126{
 127        dev->data->dev_link.link_status = ETH_LINK_UP;
 128        return 0;
 129}
 130
 131static int
 132eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 133                                    uint16_t nb_rx_desc __rte_unused,
 134                                    unsigned int socket_id __rte_unused,
 135                                    const struct rte_eth_rxconf *rx_conf __rte_unused,
 136                                    struct rte_mempool *mb_pool __rte_unused)
 137{
 138        struct pmd_internals *internals = dev->data->dev_private;
 139
 140        dev->data->rx_queues[rx_queue_id] = &internals->rx_ring_queues[rx_queue_id];
 141        return 0;
 142}
 143
 144static int
 145eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
 146                                    uint16_t nb_tx_desc __rte_unused,
 147                                    unsigned int socket_id __rte_unused,
 148                                    const struct rte_eth_txconf *tx_conf __rte_unused)
 149{
 150        struct pmd_internals *internals = dev->data->dev_private;
 151
 152        dev->data->tx_queues[tx_queue_id] = &internals->tx_ring_queues[tx_queue_id];
 153        return 0;
 154}
 155
 156
 157static int
 158eth_dev_info(struct rte_eth_dev *dev,
 159             struct rte_eth_dev_info *dev_info)
 160{
 161        struct pmd_internals *internals = dev->data->dev_private;
 162
 163        dev_info->max_mac_addrs = 1;
 164        dev_info->max_rx_pktlen = (uint32_t)-1;
 165        dev_info->max_rx_queues = (uint16_t)internals->max_rx_queues;
 166        dev_info->rx_offload_capa = DEV_RX_OFFLOAD_SCATTER;
 167        dev_info->tx_offload_capa = DEV_TX_OFFLOAD_MULTI_SEGS;
 168        dev_info->max_tx_queues = (uint16_t)internals->max_tx_queues;
 169        dev_info->min_rx_bufsize = 0;
 170
 171        return 0;
 172}
 173
 174static int
 175eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 176{
 177        unsigned int i;
 178        unsigned long rx_total = 0, tx_total = 0;
 179        const struct pmd_internals *internal = dev->data->dev_private;
 180
 181        for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
 182                        i < dev->data->nb_rx_queues; i++) {
 183                stats->q_ipackets[i] = internal->rx_ring_queues[i].rx_pkts.cnt;
 184                rx_total += stats->q_ipackets[i];
 185        }
 186
 187        for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
 188                        i < dev->data->nb_tx_queues; i++) {
 189                stats->q_opackets[i] = internal->tx_ring_queues[i].tx_pkts.cnt;
 190                tx_total += stats->q_opackets[i];
 191        }
 192
 193        stats->ipackets = rx_total;
 194        stats->opackets = tx_total;
 195
 196        return 0;
 197}
 198
 199static int
 200eth_stats_reset(struct rte_eth_dev *dev)
 201{
 202        unsigned int i;
 203        struct pmd_internals *internal = dev->data->dev_private;
 204
 205        for (i = 0; i < dev->data->nb_rx_queues; i++)
 206                internal->rx_ring_queues[i].rx_pkts.cnt = 0;
 207        for (i = 0; i < dev->data->nb_tx_queues; i++)
 208                internal->tx_ring_queues[i].tx_pkts.cnt = 0;
 209
 210        return 0;
 211}
 212
 213static void
 214eth_mac_addr_remove(struct rte_eth_dev *dev __rte_unused,
 215        uint32_t index __rte_unused)
 216{
 217}
 218
 219static int
 220eth_mac_addr_add(struct rte_eth_dev *dev __rte_unused,
 221        struct rte_ether_addr *mac_addr __rte_unused,
 222        uint32_t index __rte_unused,
 223        uint32_t vmdq __rte_unused)
 224{
 225        return 0;
 226}
 227
 228static void
 229eth_queue_release(void *q __rte_unused) { ; }
 230static int
 231eth_link_update(struct rte_eth_dev *dev __rte_unused,
 232                int wait_to_complete __rte_unused) { return 0; }
 233
 234static int
 235eth_dev_close(struct rte_eth_dev *dev)
 236{
 237        struct pmd_internals *internals = NULL;
 238        struct ring_queue *r = NULL;
 239        uint16_t i;
 240        int ret;
 241
 242        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 243                return 0;
 244
 245        ret = eth_dev_stop(dev);
 246
 247        internals = dev->data->dev_private;
 248        if (internals->action == DEV_CREATE) {
 249                /*
 250                 * it is only necessary to delete the rings in rx_queues because
 251                 * they are the same used in tx_queues
 252                 */
 253                for (i = 0; i < dev->data->nb_rx_queues; i++) {
 254                        r = dev->data->rx_queues[i];
 255                        rte_ring_free(r->rng);
 256                }
 257        }
 258
 259        /* mac_addrs must not be freed alone because part of dev_private */
 260        dev->data->mac_addrs = NULL;
 261
 262        return ret;
 263}
 264
 265static const struct eth_dev_ops ops = {
 266        .dev_close = eth_dev_close,
 267        .dev_start = eth_dev_start,
 268        .dev_stop = eth_dev_stop,
 269        .dev_set_link_up = eth_dev_set_link_up,
 270        .dev_set_link_down = eth_dev_set_link_down,
 271        .dev_configure = eth_dev_configure,
 272        .dev_infos_get = eth_dev_info,
 273        .rx_queue_setup = eth_rx_queue_setup,
 274        .tx_queue_setup = eth_tx_queue_setup,
 275        .rx_queue_release = eth_queue_release,
 276        .tx_queue_release = eth_queue_release,
 277        .link_update = eth_link_update,
 278        .stats_get = eth_stats_get,
 279        .stats_reset = eth_stats_reset,
 280        .mac_addr_remove = eth_mac_addr_remove,
 281        .mac_addr_add = eth_mac_addr_add,
 282};
 283
 284static int
 285do_eth_dev_ring_create(const char *name,
 286                struct rte_vdev_device *vdev,
 287                struct rte_ring * const rx_queues[],
 288                const unsigned int nb_rx_queues,
 289                struct rte_ring *const tx_queues[],
 290                const unsigned int nb_tx_queues,
 291                const unsigned int numa_node, enum dev_action action,
 292                struct rte_eth_dev **eth_dev_p)
 293{
 294        struct rte_eth_dev_data *data = NULL;
 295        struct pmd_internals *internals = NULL;
 296        struct rte_eth_dev *eth_dev = NULL;
 297        void **rx_queues_local = NULL;
 298        void **tx_queues_local = NULL;
 299        unsigned int i;
 300
 301        PMD_LOG(INFO, "Creating rings-backed ethdev on numa socket %u",
 302                        numa_node);
 303
 304        rx_queues_local = rte_calloc_socket(name, nb_rx_queues,
 305                                            sizeof(void *), 0, numa_node);
 306        if (rx_queues_local == NULL) {
 307                rte_errno = ENOMEM;
 308                goto error;
 309        }
 310
 311        tx_queues_local = rte_calloc_socket(name, nb_tx_queues,
 312                                            sizeof(void *), 0, numa_node);
 313        if (tx_queues_local == NULL) {
 314                rte_errno = ENOMEM;
 315                goto error;
 316        }
 317
 318        internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
 319        if (internals == NULL) {
 320                rte_errno = ENOMEM;
 321                goto error;
 322        }
 323
 324        /* reserve an ethdev entry */
 325        eth_dev = rte_eth_dev_allocate(name);
 326        if (eth_dev == NULL) {
 327                rte_errno = ENOSPC;
 328                goto error;
 329        }
 330
 331        /* now put it all together
 332         * - store EAL device in eth_dev,
 333         * - store queue data in internals,
 334         * - store numa_node info in eth_dev_data
 335         * - point eth_dev_data to internals
 336         * - and point eth_dev structure to new eth_dev_data structure
 337         */
 338
 339        eth_dev->device = &vdev->device;
 340
 341        data = eth_dev->data;
 342        data->rx_queues = rx_queues_local;
 343        data->tx_queues = tx_queues_local;
 344
 345        internals->action = action;
 346        internals->max_rx_queues = nb_rx_queues;
 347        internals->max_tx_queues = nb_tx_queues;
 348        for (i = 0; i < nb_rx_queues; i++) {
 349                internals->rx_ring_queues[i].rng = rx_queues[i];
 350                data->rx_queues[i] = &internals->rx_ring_queues[i];
 351        }
 352        for (i = 0; i < nb_tx_queues; i++) {
 353                internals->tx_ring_queues[i].rng = tx_queues[i];
 354                data->tx_queues[i] = &internals->tx_ring_queues[i];
 355        }
 356
 357        data->dev_private = internals;
 358        data->nb_rx_queues = (uint16_t)nb_rx_queues;
 359        data->nb_tx_queues = (uint16_t)nb_tx_queues;
 360        data->dev_link = pmd_link;
 361        data->mac_addrs = &internals->address;
 362        data->promiscuous = 1;
 363        data->all_multicast = 1;
 364        data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
 365
 366        eth_dev->dev_ops = &ops;
 367        data->numa_node = numa_node;
 368
 369        /* finally assign rx and tx ops */
 370        eth_dev->rx_pkt_burst = eth_ring_rx;
 371        eth_dev->tx_pkt_burst = eth_ring_tx;
 372
 373        rte_eth_dev_probing_finish(eth_dev);
 374        *eth_dev_p = eth_dev;
 375
 376        return data->port_id;
 377
 378error:
 379        rte_free(rx_queues_local);
 380        rte_free(tx_queues_local);
 381        rte_free(internals);
 382
 383        return -1;
 384}
 385
 386int
 387rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
 388                const unsigned int nb_rx_queues,
 389                struct rte_ring *const tx_queues[],
 390                const unsigned int nb_tx_queues,
 391                const unsigned int numa_node)
 392{
 393        struct ring_internal_args args = {
 394                .rx_queues = rx_queues,
 395                .nb_rx_queues = nb_rx_queues,
 396                .tx_queues = tx_queues,
 397                .nb_tx_queues = nb_tx_queues,
 398                .numa_node = numa_node,
 399                .addr = &args,
 400        };
 401        char args_str[32];
 402        char ring_name[RTE_RING_NAMESIZE];
 403        uint16_t port_id = RTE_MAX_ETHPORTS;
 404        int ret;
 405
 406        /* do some parameter checking */
 407        if (rx_queues == NULL && nb_rx_queues > 0) {
 408                rte_errno = EINVAL;
 409                return -1;
 410        }
 411        if (tx_queues == NULL && nb_tx_queues > 0) {
 412                rte_errno = EINVAL;
 413                return -1;
 414        }
 415        if (nb_rx_queues > RTE_PMD_RING_MAX_RX_RINGS) {
 416                rte_errno = EINVAL;
 417                return -1;
 418        }
 419
 420        snprintf(args_str, sizeof(args_str), "%s=%p",
 421                 ETH_RING_INTERNAL_ARG, &args);
 422
 423        ret = snprintf(ring_name, sizeof(ring_name), "net_ring_%s", name);
 424        if (ret >= (int)sizeof(ring_name)) {
 425                rte_errno = ENAMETOOLONG;
 426                return -1;
 427        }
 428
 429        ret = rte_vdev_init(ring_name, args_str);
 430        if (ret) {
 431                rte_errno = EINVAL;
 432                return -1;
 433        }
 434
 435        ret = rte_eth_dev_get_port_by_name(ring_name, &port_id);
 436        if (ret) {
 437                rte_errno = ENODEV;
 438                return -1;
 439        }
 440
 441        return port_id;
 442}
 443
 444int
 445rte_eth_from_ring(struct rte_ring *r)
 446{
 447        return rte_eth_from_rings(r->name, &r, 1, &r, 1,
 448                        r->memzone ? r->memzone->socket_id : SOCKET_ID_ANY);
 449}
 450
 451static int
 452eth_dev_ring_create(const char *name,
 453                struct rte_vdev_device *vdev,
 454                const unsigned int numa_node,
 455                enum dev_action action, struct rte_eth_dev **eth_dev)
 456{
 457        /* rx and tx are so-called from point of view of first port.
 458         * They are inverted from the point of view of second port
 459         */
 460        struct rte_ring *rxtx[RTE_PMD_RING_MAX_RX_RINGS];
 461        unsigned int i;
 462        char rng_name[RTE_RING_NAMESIZE];
 463        unsigned int num_rings = RTE_MIN(RTE_PMD_RING_MAX_RX_RINGS,
 464                        RTE_PMD_RING_MAX_TX_RINGS);
 465
 466        for (i = 0; i < num_rings; i++) {
 467                int cc;
 468
 469                cc = snprintf(rng_name, sizeof(rng_name),
 470                              "ETH_RXTX%u_%s", i, name);
 471                if (cc >= (int)sizeof(rng_name)) {
 472                        rte_errno = ENAMETOOLONG;
 473                        return -1;
 474                }
 475
 476                rxtx[i] = (action == DEV_CREATE) ?
 477                                rte_ring_create(rng_name, 1024, numa_node,
 478                                                RING_F_SP_ENQ|RING_F_SC_DEQ) :
 479                                rte_ring_lookup(rng_name);
 480                if (rxtx[i] == NULL)
 481                        return -1;
 482        }
 483
 484        if (do_eth_dev_ring_create(name, vdev, rxtx, num_rings, rxtx, num_rings,
 485                numa_node, action, eth_dev) < 0)
 486                return -1;
 487
 488        return 0;
 489}
 490
 491struct node_action_pair {
 492        char name[PATH_MAX];
 493        unsigned int node;
 494        enum dev_action action;
 495};
 496
 497struct node_action_list {
 498        unsigned int total;
 499        unsigned int count;
 500        struct node_action_pair *list;
 501};
 502
 503static int parse_kvlist(const char *key __rte_unused,
 504                        const char *value, void *data)
 505{
 506        struct node_action_list *info = data;
 507        int ret;
 508        char *name;
 509        char *action;
 510        char *node;
 511        char *end;
 512
 513        name = strdup(value);
 514
 515        ret = -EINVAL;
 516
 517        if (!name) {
 518                PMD_LOG(WARNING, "command line parameter is empty for ring pmd!");
 519                goto out;
 520        }
 521
 522        node = strchr(name, ':');
 523        if (!node) {
 524                PMD_LOG(WARNING, "could not parse node value from %s",
 525                        name);
 526                goto out;
 527        }
 528
 529        *node = '\0';
 530        node++;
 531
 532        action = strchr(node, ':');
 533        if (!action) {
 534                PMD_LOG(WARNING, "could not parse action value from %s",
 535                        node);
 536                goto out;
 537        }
 538
 539        *action = '\0';
 540        action++;
 541
 542        /*
 543         * Need to do some sanity checking here
 544         */
 545
 546        if (strcmp(action, ETH_RING_ACTION_ATTACH) == 0)
 547                info->list[info->count].action = DEV_ATTACH;
 548        else if (strcmp(action, ETH_RING_ACTION_CREATE) == 0)
 549                info->list[info->count].action = DEV_CREATE;
 550        else
 551                goto out;
 552
 553        errno = 0;
 554        info->list[info->count].node = strtol(node, &end, 10);
 555
 556        if ((errno != 0) || (*end != '\0')) {
 557                PMD_LOG(WARNING,
 558                        "node value %s is unparseable as a number", node);
 559                goto out;
 560        }
 561
 562        strlcpy(info->list[info->count].name, name,
 563                sizeof(info->list[info->count].name));
 564
 565        info->count++;
 566
 567        ret = 0;
 568out:
 569        free(name);
 570        return ret;
 571}
 572
 573static int
 574parse_internal_args(const char *key __rte_unused, const char *value,
 575                void *data)
 576{
 577        struct ring_internal_args **internal_args = data;
 578        void *args;
 579        int ret, n;
 580
 581        /* make sure 'value' is valid pointer length */
 582        if (strnlen(value, ETH_RING_INTERNAL_ARG_MAX_LEN) >=
 583                        ETH_RING_INTERNAL_ARG_MAX_LEN) {
 584                PMD_LOG(ERR, "Error parsing internal args, argument is too long");
 585                return -1;
 586        }
 587
 588        ret = sscanf(value, "%p%n", &args, &n);
 589        if (ret == 0 || (size_t)n != strlen(value)) {
 590                PMD_LOG(ERR, "Error parsing internal args");
 591
 592                return -1;
 593        }
 594
 595        *internal_args = args;
 596
 597        if ((*internal_args)->addr != args)
 598                return -1;
 599
 600        return 0;
 601}
 602
 603static int
 604rte_pmd_ring_probe(struct rte_vdev_device *dev)
 605{
 606        const char *name, *params;
 607        struct rte_kvargs *kvlist = NULL;
 608        int ret = 0;
 609        struct node_action_list *info = NULL;
 610        struct rte_eth_dev *eth_dev = NULL;
 611        struct ring_internal_args *internal_args;
 612
 613        name = rte_vdev_device_name(dev);
 614        params = rte_vdev_device_args(dev);
 615
 616        PMD_LOG(INFO, "Initializing pmd_ring for %s", name);
 617
 618        if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
 619                eth_dev = rte_eth_dev_attach_secondary(name);
 620                if (!eth_dev) {
 621                        PMD_LOG(ERR, "Failed to probe %s", name);
 622                        return -1;
 623                }
 624                eth_dev->dev_ops = &ops;
 625                eth_dev->device = &dev->device;
 626
 627                eth_dev->rx_pkt_burst = eth_ring_rx;
 628                eth_dev->tx_pkt_burst = eth_ring_tx;
 629
 630                rte_eth_dev_probing_finish(eth_dev);
 631
 632                return 0;
 633        }
 634
 635        if (params == NULL || params[0] == '\0') {
 636                ret = eth_dev_ring_create(name, dev, rte_socket_id(), DEV_CREATE,
 637                                &eth_dev);
 638                if (ret == -1) {
 639                        PMD_LOG(INFO,
 640                                "Attach to pmd_ring for %s", name);
 641                        ret = eth_dev_ring_create(name, dev, rte_socket_id(),
 642                                                  DEV_ATTACH, &eth_dev);
 643                }
 644        } else {
 645                kvlist = rte_kvargs_parse(params, valid_arguments);
 646
 647                if (!kvlist) {
 648                        PMD_LOG(INFO,
 649                                "Ignoring unsupported parameters when creating rings-backed ethernet device");
 650                        ret = eth_dev_ring_create(name, dev, rte_socket_id(),
 651                                                  DEV_CREATE, &eth_dev);
 652                        if (ret == -1) {
 653                                PMD_LOG(INFO,
 654                                        "Attach to pmd_ring for %s",
 655                                        name);
 656                                ret = eth_dev_ring_create(name, dev, rte_socket_id(),
 657                                                          DEV_ATTACH, &eth_dev);
 658                        }
 659
 660                        return ret;
 661                }
 662
 663                if (rte_kvargs_count(kvlist, ETH_RING_INTERNAL_ARG) == 1) {
 664                        ret = rte_kvargs_process(kvlist, ETH_RING_INTERNAL_ARG,
 665                                                 parse_internal_args,
 666                                                 &internal_args);
 667                        if (ret < 0)
 668                                goto out_free;
 669
 670                        ret = do_eth_dev_ring_create(name, dev,
 671                                internal_args->rx_queues,
 672                                internal_args->nb_rx_queues,
 673                                internal_args->tx_queues,
 674                                internal_args->nb_tx_queues,
 675                                internal_args->numa_node,
 676                                DEV_ATTACH,
 677                                &eth_dev);
 678                        if (ret >= 0)
 679                                ret = 0;
 680                } else {
 681                        ret = rte_kvargs_count(kvlist, ETH_RING_NUMA_NODE_ACTION_ARG);
 682                        info = rte_zmalloc("struct node_action_list",
 683                                           sizeof(struct node_action_list) +
 684                                           (sizeof(struct node_action_pair) * ret),
 685                                           0);
 686                        if (!info)
 687                                goto out_free;
 688
 689                        info->total = ret;
 690                        info->list = (struct node_action_pair *)(info + 1);
 691
 692                        ret = rte_kvargs_process(kvlist, ETH_RING_NUMA_NODE_ACTION_ARG,
 693                                                 parse_kvlist, info);
 694
 695                        if (ret < 0)
 696                                goto out_free;
 697
 698                        for (info->count = 0; info->count < info->total; info->count++) {
 699                                ret = eth_dev_ring_create(info->list[info->count].name,
 700                                                          dev,
 701                                                          info->list[info->count].node,
 702                                                          info->list[info->count].action,
 703                                                          &eth_dev);
 704                                if ((ret == -1) &&
 705                                    (info->list[info->count].action == DEV_CREATE)) {
 706                                        PMD_LOG(INFO,
 707                                                "Attach to pmd_ring for %s",
 708                                                name);
 709                                        ret = eth_dev_ring_create(name, dev,
 710                                                        info->list[info->count].node,
 711                                                        DEV_ATTACH,
 712                                                        &eth_dev);
 713                                }
 714                        }
 715                }
 716        }
 717
 718out_free:
 719        rte_kvargs_free(kvlist);
 720        rte_free(info);
 721        return ret;
 722}
 723
 724static int
 725rte_pmd_ring_remove(struct rte_vdev_device *dev)
 726{
 727        const char *name = rte_vdev_device_name(dev);
 728        struct rte_eth_dev *eth_dev = NULL;
 729
 730        PMD_LOG(INFO, "Un-Initializing pmd_ring for %s", name);
 731
 732        if (name == NULL)
 733                return -EINVAL;
 734
 735        /* find an ethdev entry */
 736        eth_dev = rte_eth_dev_allocated(name);
 737        if (eth_dev == NULL)
 738                return 0; /* port already released */
 739
 740        eth_dev_close(eth_dev);
 741        rte_eth_dev_release_port(eth_dev);
 742        return 0;
 743}
 744
 745static struct rte_vdev_driver pmd_ring_drv = {
 746        .probe = rte_pmd_ring_probe,
 747        .remove = rte_pmd_ring_remove,
 748};
 749
 750RTE_PMD_REGISTER_VDEV(net_ring, pmd_ring_drv);
 751RTE_PMD_REGISTER_ALIAS(net_ring, eth_ring);
 752RTE_PMD_REGISTER_PARAM_STRING(net_ring,
 753        ETH_RING_NUMA_NODE_ACTION_ARG "=name:node:action(ATTACH|CREATE)");
 754