summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/defconfig_i686-default-linuxapp-gcc7
-rw-r--r--config/defconfig_i686-default-linuxapp-icc7
-rw-r--r--config/defconfig_x86_64-default-linuxapp-gcc7
-rw-r--r--config/defconfig_x86_64-default-linuxapp-icc7
-rw-r--r--lib/Makefile1
-rw-r--r--lib/librte_eal/common/eal_common_nonpci_devs.c9
-rw-r--r--lib/librte_eal/common/eal_common_whitelist.c6
-rw-r--r--lib/librte_eal/linuxapp/eal/Makefile1
-rw-r--r--lib/librte_eal/linuxapp/eal/eal.c1
-rw-r--r--lib/librte_pmd_ring/Makefile56
-rw-r--r--lib/librte_pmd_ring/rte_eth_ring.c395
-rw-r--r--lib/librte_pmd_ring/rte_eth_ring.h64
-rw-r--r--mk/rte.app.mk4
13 files changed, 565 insertions, 0 deletions
diff --git a/config/defconfig_i686-default-linuxapp-gcc b/config/defconfig_i686-default-linuxapp-gcc
index 666aa7b..3d23f4c 100644
--- a/config/defconfig_i686-default-linuxapp-gcc
+++ b/config/defconfig_i686-default-linuxapp-gcc
@@ -169,6 +169,13 @@ CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
CONFIG_RTE_PMD_PACKET_PREFETCH=y
#
+# Compile example software rings based PMD
+#
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+
+#
# Compile librte_ring
#
CONFIG_RTE_LIBRTE_RING=y
diff --git a/config/defconfig_i686-default-linuxapp-icc b/config/defconfig_i686-default-linuxapp-icc
index 8b512af..4fd26b7 100644
--- a/config/defconfig_i686-default-linuxapp-icc
+++ b/config/defconfig_i686-default-linuxapp-icc
@@ -170,6 +170,13 @@ CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
CONFIG_RTE_PMD_PACKET_PREFETCH=y
#
+# Compile example software rings based PMD
+#
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+
+#
# Compile librte_ring
#
CONFIG_RTE_LIBRTE_RING=y
diff --git a/config/defconfig_x86_64-default-linuxapp-gcc b/config/defconfig_x86_64-default-linuxapp-gcc
index e29f3bc..077ad81 100644
--- a/config/defconfig_x86_64-default-linuxapp-gcc
+++ b/config/defconfig_x86_64-default-linuxapp-gcc
@@ -176,6 +176,13 @@ CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=y
CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
#
+# Compile example software rings based PMD
+#
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+
+#
# Do prefetch of packet data within PMD driver receive function
#
CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/defconfig_x86_64-default-linuxapp-icc b/config/defconfig_x86_64-default-linuxapp-icc
index c864c01..418f0ad 100644
--- a/config/defconfig_x86_64-default-linuxapp-icc
+++ b/config/defconfig_x86_64-default-linuxapp-icc
@@ -165,6 +165,13 @@ CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=y
CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
#
+# Compile example software rings based PMD
+#
+CONFIG_RTE_LIBRTE_PMD_RING=y
+CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16
+CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
+
+#
# Do prefetch of packet data within PMD driver receive function
#
CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/lib/Makefile b/lib/Makefile
index 779c53f..d0931e3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -42,6 +42,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += librte_pmd_e1000
DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += librte_pmd_ixgbe
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += librte_pmd_ring
DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_eal/common/eal_common_nonpci_devs.c b/lib/librte_eal/common/eal_common_nonpci_devs.c
index ecce5b9..e4ef25b 100644
--- a/lib/librte_eal/common/eal_common_nonpci_devs.c
+++ b/lib/librte_eal/common/eal_common_nonpci_devs.c
@@ -33,6 +33,9 @@
#include <inttypes.h>
#include <rte_string_fns.h>
+#ifdef RTE_LIBRTE_PMD_RING
+#include <rte_eth_ring.h>
+#endif
#include "eal_private.h"
struct device_init {
@@ -42,6 +45,12 @@ struct device_init {
#define NUM_DEV_TYPES (sizeof(dev_types)/sizeof(dev_types[0]))
struct device_init dev_types[] = {
+#ifdef RTE_LIBRTE_PMD_RING
+ {
+ .dev_prefix = RTE_ETH_RING_PARAM_NAME,
+ .init_fn = rte_pmd_ring_init
+ },
+#endif
{
.dev_prefix = "-nodev-",
.init_fn = NULL
diff --git a/lib/librte_eal/common/eal_common_whitelist.c b/lib/librte_eal/common/eal_common_whitelist.c
index ddd4a6f..d5fdd3e 100644
--- a/lib/librte_eal/common/eal_common_whitelist.c
+++ b/lib/librte_eal/common/eal_common_whitelist.c
@@ -45,6 +45,9 @@
#include <rte_debug.h>
#include <rte_pci.h>
#include <ctype.h>
+#ifdef RTE_LIBRTE_PMD_RING
+#include <rte_eth_ring.h>
+#endif
#include "eal_private.h"
static char dev_list_str[4096];
@@ -91,6 +94,9 @@ is_valid_wl_entry(const char *device_str, size_t dev_buf_len)
{
#define NUM_PREFIXES (sizeof(non_pci_prefixes)/sizeof(non_pci_prefixes[0]))
static const char *non_pci_prefixes[] = {
+#ifdef RTE_LIBRTE_PMD_RING
+ RTE_ETH_RING_PARAM_NAME,
+#endif
"-nodev-" /* dummy value to prevent compiler warnings */
};
static uint8_t prefix_counts[NUM_PREFIXES] = {0};
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 306b6ad..b1f6e03 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -41,6 +41,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_ring
CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
CFLAGS += -I$(RTE_SDK)/lib/librte_malloc
CFLAGS += -I$(RTE_SDK)/lib/librte_ether
+CFLAGS += -I$(RTE_SDK)/lib/librte_pmd_ring
CFLAGS += $(WERROR_FLAGS) -O3
# specific to linuxapp exec-env
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 46a0139..f1d3a55 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -71,6 +71,7 @@
#include <rte_version.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
+#include <rte_eth_ring.h>
#include "eal_private.h"
#include "eal_thread.h"
diff --git a/lib/librte_pmd_ring/Makefile b/lib/librte_pmd_ring/Makefile
new file mode 100644
index 0000000..b2e09c7
--- /dev/null
+++ b/lib/librte_pmd_ring/Makefile
@@ -0,0 +1,56 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_ring.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += rte_eth_ring.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_eth_ring.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += lib/librte_eal lib/librte_ring
+DEPDIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += lib/librte_mbuf lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
new file mode 100644
index 0000000..d9667c0
--- /dev/null
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -0,0 +1,395 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rte_eth_ring.h"
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_string_fns.h>
+
+struct ring_queue {
+ struct rte_ring *rng;
+ volatile unsigned long rx_pkts;
+ volatile unsigned long tx_pkts;
+ volatile unsigned long err_pkts;
+};
+
+struct pmd_internals {
+ unsigned nb_rx_queues;
+ unsigned nb_tx_queues;
+
+ struct ring_queue rx_ring_queues[RTE_PMD_RING_MAX_RX_RINGS];
+ struct ring_queue tx_ring_queues[RTE_PMD_RING_MAX_TX_RINGS];
+};
+
+
+static struct ether_addr eth_addr = { .addr_bytes = {0} };
+static const char *drivername = "Rings PMD";
+static struct rte_eth_link pmd_link = {
+ .link_speed = 10000,
+ .link_duplex = ETH_LINK_FULL_DUPLEX,
+ .link_status = 0
+};
+
+static uint16_t
+eth_ring_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ void **ptrs = (void *)&bufs[0];
+ struct ring_queue *r = q;
+ const uint16_t nb_rx = (uint16_t)rte_ring_dequeue_burst(r->rng,
+ ptrs, nb_bufs);
+ if (r->rng->flags & RING_F_SC_DEQ)
+ r->rx_pkts += nb_rx;
+ else
+ __sync_fetch_and_add(&r->rx_pkts, nb_rx);
+ return nb_rx;
+}
+
+static uint16_t
+eth_ring_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ void **ptrs = (void *)&bufs[0];
+ struct ring_queue *r = q;
+ const uint16_t nb_tx = (uint16_t)rte_ring_enqueue_burst(r->rng,
+ ptrs, nb_bufs);
+ if (r->rng->flags & RING_F_SP_ENQ) {
+ r->tx_pkts += nb_tx;
+ r->err_pkts += nb_bufs - nb_tx;
+ } else {
+ __sync_fetch_and_add(&r->tx_pkts, nb_tx);
+ __sync_fetch_and_add(&r->err_pkts, nb_bufs - nb_tx);
+ }
+ return nb_tx;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { return 0; }
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 1;
+ return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_rx_queue_setup(struct rte_eth_dev *dev,uint16_t rx_queue_id,
+ uint16_t nb_rx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_rxconf *rx_conf __rte_unused,
+ struct rte_mempool *mb_pool __rte_unused)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ dev->data->rx_queues[rx_queue_id] = &internals->rx_ring_queues[rx_queue_id];
+ return 0;
+}
+
+static int
+eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+ uint16_t nb_tx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ dev->data->tx_queues[tx_queue_id] = &internals->tx_ring_queues[tx_queue_id];
+ return 0;
+}
+
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ dev_info->driver_name = drivername;
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+ dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+ dev_info->min_rx_bufsize = 0;
+ dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
+{
+ unsigned i;
+ unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+ const struct pmd_internals *internal = dev->data->dev_private;
+
+ memset(igb_stats, 0, sizeof(*igb_stats));
+ for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+ i < internal->nb_rx_queues; i++) {
+ igb_stats->q_ipackets[i] = internal->rx_ring_queues[i].rx_pkts;
+ rx_total += igb_stats->q_ipackets[i];
+ }
+
+ for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+ i < internal->nb_tx_queues; i++) {
+ igb_stats->q_opackets[i] = internal->tx_ring_queues[i].tx_pkts;
+ igb_stats->q_errors[i] = internal->tx_ring_queues[i].err_pkts;
+ tx_total += igb_stats->q_opackets[i];
+ tx_err_total += igb_stats->q_errors[i];
+ }
+
+ igb_stats->ipackets = rx_total;
+ igb_stats->opackets = tx_total;
+ igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+ unsigned i;
+ struct pmd_internals *internal = dev->data->dev_private;
+ for (i = 0; i < internal->nb_rx_queues; i++)
+ internal->rx_ring_queues[i].rx_pkts = 0;
+ for (i = 0; i < internal->nb_tx_queues; i++) {
+ internal->tx_ring_queues[i].tx_pkts = 0;
+ internal->tx_ring_queues[i].err_pkts = 0;
+ }
+}
+
+static void
+eth_queue_release(void *q __rte_unused) { ; }
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+ int wait_to_complete __rte_unused) { return 0; }
+
+static struct eth_dev_ops ops = {
+ .dev_start = eth_dev_start,
+ .dev_stop = eth_dev_stop,
+ .dev_configure = eth_dev_configure,
+ .dev_infos_get = eth_dev_info,
+ .rx_queue_setup = eth_rx_queue_setup,
+ .tx_queue_setup = eth_tx_queue_setup,
+ .rx_queue_release = eth_queue_release,
+ .tx_queue_release = eth_queue_release,
+ .link_update = eth_link_update,
+ .stats_get = eth_stats_get,
+ .stats_reset = eth_stats_reset,
+};
+
+int
+rte_eth_from_rings(struct rte_ring *const rx_queues[],
+ const unsigned nb_rx_queues,
+ struct rte_ring *const tx_queues[],
+ const unsigned nb_tx_queues,
+ const unsigned numa_node)
+{
+ struct rte_eth_dev_data *data = NULL;
+ struct rte_pci_device *pci_dev = NULL;
+ struct pmd_internals *internals = NULL;
+ struct rte_eth_dev *eth_dev = NULL;
+ unsigned i;
+
+ RTE_LOG(INFO, PMD, "Creating rings-backed ethdev on numa socket %u\n",
+ numa_node);
+
+ /* do some paramter checking */
+ if (rx_queues == NULL && nb_rx_queues > 0)
+ goto error;
+ if (tx_queues == NULL && nb_tx_queues > 0)
+ goto error;
+
+ /* now do all data allocation - for eth_dev structure, dummy pci driver
+ * and internal (private) data
+ */
+ data = rte_zmalloc_socket(NULL, sizeof(*data), 0, numa_node);
+ if (data == NULL)
+ goto error;
+
+ pci_dev = rte_zmalloc_socket(NULL, sizeof(*pci_dev), 0, numa_node);
+ if (pci_dev == NULL)
+ goto error;
+
+ internals = rte_zmalloc_socket(NULL, sizeof(*internals), 0, numa_node);
+ if (internals == NULL)
+ goto error;
+
+ /* reserve an ethdev entry */
+ eth_dev = rte_eth_dev_allocate();
+ if (eth_dev == NULL)
+ goto error;
+
+ /* now put it all together
+ * - store queue data in internals,
+ * - store numa_node info in pci_driver
+ * - point eth_dev_data to internals and pci_driver
+ * - and point eth_dev structure to new eth_dev_data structure
+ */
+ /* NOTE: we'll replace the data element, of originally allocated eth_dev
+ * so the rings are local per-process */
+
+ internals->nb_rx_queues = nb_rx_queues;
+ internals->nb_tx_queues = nb_tx_queues;
+ for (i = 0; i < nb_rx_queues; i++) {
+ internals->rx_ring_queues[i].rng = rx_queues[i];
+ }
+ for (i = 0; i < nb_tx_queues; i++) {
+ internals->tx_ring_queues[i].rng = tx_queues[i];
+ }
+
+ pci_dev->numa_node = numa_node;
+
+ data->dev_private = internals;
+ data->port_id = eth_dev->data->port_id;
+ data->nb_rx_queues = (uint16_t)nb_rx_queues;
+ data->nb_tx_queues = (uint16_t)nb_tx_queues;
+ data->dev_link = pmd_link;
+ data->mac_addrs = &eth_addr;
+
+ eth_dev ->data = data;
+ eth_dev ->dev_ops = &ops;
+ eth_dev ->pci_dev = pci_dev;
+
+ /* finally assign rx and tx ops */
+ eth_dev->rx_pkt_burst = eth_ring_rx;
+ eth_dev->tx_pkt_burst = eth_ring_tx;
+
+ return 0;
+
+error:
+ if (data)
+ rte_free(data);
+ if (pci_dev)
+ rte_free(pci_dev);
+ if (internals)
+ rte_free(internals);
+ return -1;
+}
+
+enum dev_action{
+ DEV_CREATE,
+ DEV_ATTACH
+};
+
+static int
+eth_dev_ring_create(const char *name, const unsigned numa_node,
+ enum dev_action action)
+{
+ /* rx and tx are so-called from point of view of first port.
+ * They are inverted from the point of view of second port
+ */
+ struct rte_ring *rxtx[RTE_PMD_RING_MAX_RX_RINGS];
+ unsigned i;
+ char rng_name[RTE_RING_NAMESIZE];
+ unsigned num_rings = RTE_MIN(RTE_PMD_RING_MAX_RX_RINGS,
+ RTE_PMD_RING_MAX_TX_RINGS);
+
+ for (i = 0; i < num_rings; i++) {
+ rte_snprintf(rng_name, sizeof(rng_name), "ETH_RXTX%u_%s", i, name);
+ rxtx[i] = (action == DEV_CREATE) ?
+ rte_ring_create(rng_name, 1024, numa_node,
+ RING_F_SP_ENQ|RING_F_SC_DEQ) :
+ rte_ring_lookup(rng_name);
+ if (rxtx[i] == NULL)
+ return -1;
+ }
+
+ if (rte_eth_from_rings(rxtx, num_rings, rxtx, num_rings, numa_node))
+ return -1;
+
+ return 0;
+}
+
+
+static int
+eth_dev_ring_pair_create(const char *name, const unsigned numa_node,
+ enum dev_action action)
+{
+ /* rx and tx are so-called from point of view of first port.
+ * They are inverted from the point of view of second port
+ */
+ struct rte_ring *rx[RTE_PMD_RING_MAX_RX_RINGS];
+ struct rte_ring *tx[RTE_PMD_RING_MAX_TX_RINGS];
+ unsigned i;
+ char rng_name[RTE_RING_NAMESIZE];
+ unsigned num_rings = RTE_MIN(RTE_PMD_RING_MAX_RX_RINGS,
+ RTE_PMD_RING_MAX_TX_RINGS);
+
+ for (i = 0; i < num_rings; i++) {
+ rte_snprintf(rng_name, sizeof(rng_name), "ETH_RX%u_%s", i, name);
+ rx[i] = (action == DEV_CREATE) ?
+ rte_ring_create(rng_name, 1024, numa_node,
+ RING_F_SP_ENQ|RING_F_SC_DEQ) :
+ rte_ring_lookup(rng_name);
+ if (rx[i] == NULL)
+ return -1;
+ rte_snprintf(rng_name, sizeof(rng_name), "ETH_TX%u_%s", i, name);
+ tx[i] = (action == DEV_CREATE) ?
+ rte_ring_create(rng_name, 1024, numa_node,
+ RING_F_SP_ENQ|RING_F_SC_DEQ):
+ rte_ring_lookup(rng_name);
+ if (tx[i] == NULL)
+ return -1;
+ }
+
+ if (rte_eth_from_rings(rx, num_rings, tx, num_rings, numa_node) ||
+ rte_eth_from_rings(tx, num_rings, rx, num_rings, numa_node) )
+ return -1;
+
+ return 0;
+}
+
+int
+rte_eth_ring_pair_create(const char *name, const unsigned numa_node)
+{
+ return eth_dev_ring_pair_create(name, numa_node, DEV_CREATE);
+}
+
+int
+rte_eth_ring_pair_attach(const char *name, const unsigned numa_node)
+{
+ return eth_dev_ring_pair_create(name, numa_node, DEV_ATTACH);
+}
+
+int
+rte_pmd_ring_init(const char *name, const char *params)
+{
+ if (params == NULL)
+ eth_dev_ring_create(name, rte_socket_id(), DEV_CREATE);
+ else {
+ RTE_LOG(INFO, PMD, "Ignoring unsupported parameters when creating"
+ " rings-backed ethernet device\n");
+ eth_dev_ring_create(name, rte_socket_id(), DEV_CREATE);
+ }
+ return 0;
+}
diff --git a/lib/librte_pmd_ring/rte_eth_ring.h b/lib/librte_pmd_ring/rte_eth_ring.h
new file mode 100644
index 0000000..d5b2573
--- /dev/null
+++ b/lib/librte_pmd_ring/rte_eth_ring.h
@@ -0,0 +1,64 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_RING_H_
+#define _RTE_ETH_RING_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ring.h>
+
+#define RTE_ETH_RING_PARAM_NAME "eth_ring"
+
+int rte_eth_from_rings(struct rte_ring * const rx_queues[],
+ const unsigned nb_rx_queues,
+ struct rte_ring *const tx_queues[],
+ const unsigned nb_tx_queues,
+ const unsigned numa_node);
+
+int rte_eth_ring_pair_create(const char *name, const unsigned numa_node);
+int rte_eth_ring_pair_attach(const char *name, const unsigned numa_node);
+
+/**
+ * For use by the EAL only. Called as part of EAL init to set up any dummy NICs
+ * configured on command line.
+ */
+int rte_pmd_ring_init(const char *name, const char *params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a282ea5..ea861cf 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -116,6 +116,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_ETHER),y)
LDLIBS += -lethdev
endif
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
+LDLIBS += -lrte_pmd_ring
+endif
+
ifeq ($(CONFIG_RTE_LIBRTE_MALLOC),y)
LDLIBS += -lrte_malloc
endif