port: add ethernet device SWX port
authorCristian Dumitrescu <cristian.dumitrescu@intel.com>
Thu, 1 Oct 2020 10:20:01 +0000 (11:20 +0100)
committerDavid Marchand <david.marchand@redhat.com>
Thu, 1 Oct 2020 16:43:08 +0000 (18:43 +0200)
Add the Ethernet device input/output port type for the SWX pipeline.
Used under the hood by the pipeline rx and tx instructions.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
doc/api/doxy-api-index.md
lib/librte_port/meson.build
lib/librte_port/rte_port_version.map
lib/librte_port/rte_swx_port_ethdev.c [new file with mode: 0644]
lib/librte_port/rte_swx_port_ethdev.h [new file with mode: 0644]

index ace8ec6..9b3b038 100644 (file)
@@ -171,7 +171,8 @@ The public API headers are grouped by topics:
     [extern]           (@ref rte_swx_extern.h),
     [pipeline]         (@ref rte_swx_pipeline.h)
   * SWX port:
-    [port]             (@ref rte_swx_port.h)
+    [port]             (@ref rte_swx_port.h),
+    [ethdev]           (@ref rte_swx_port_ethdev.h)
   * SWX table:
     [table]            (@ref rte_swx_table.h)
   * [graph]            (@ref rte_graph.h):
index 5b5fbf6..3d7f309 100644 (file)
@@ -10,7 +10,8 @@ sources = files(
        'rte_port_sched.c',
        'rte_port_source_sink.c',
        'rte_port_sym_crypto.c',
-       'rte_port_eventdev.c')
+       'rte_port_eventdev.c',
+       'rte_swx_port_ethdev.c',)
 headers = files(
        'rte_port_ethdev.h',
        'rte_port_fd.h',
@@ -22,7 +23,8 @@ headers = files(
        'rte_port_source_sink.h',
        'rte_port_sym_crypto.h',
        'rte_port_eventdev.h',
-       'rte_swx_port.h',)
+       'rte_swx_port.h',
+       'rte_swx_port_ethdev.h',)
 deps += ['ethdev', 'sched', 'ip_frag', 'cryptodev', 'eventdev']
 
 if dpdk_conf.has('RTE_PORT_PCAP')
index bd1fbb6..0d1c520 100644 (file)
@@ -34,8 +34,12 @@ DPDK_21 {
 EXPERIMENTAL {
        global:
 
+       # added in 19.11
        rte_port_eventdev_reader_ops;
-       rte_port_eventdev_writer_ops;
        rte_port_eventdev_writer_nodrop_ops;
+       rte_port_eventdev_writer_ops;
 
+       # added in 20.11
+       rte_swx_port_ethdev_reader_ops;
+       rte_swx_port_ethdev_writer_ops;
 };
diff --git a/lib/librte_port/rte_swx_port_ethdev.c b/lib/librte_port/rte_swx_port_ethdev.c
new file mode 100644 (file)
index 0000000..18d1c0b
--- /dev/null
@@ -0,0 +1,313 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_hexdump.h>
+
+#include "rte_swx_port_ethdev.h"
+
+#define CHECK(condition)                                                       \
+do {                                                                           \
+       if (!(condition))                                                      \
+               return NULL;                                                   \
+} while (0)
+
+#ifndef TRACE_LEVEL
+#define TRACE_LEVEL 0
+#endif
+
+#if TRACE_LEVEL
+#define TRACE(...) printf(__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+/*
+ * Port ETHDEV Reader
+ */
+struct reader {
+       struct {
+               uint16_t port_id;
+               uint16_t queue_id;
+               uint32_t burst_size;
+       } params;
+       struct rte_swx_port_in_stats stats;
+       struct rte_mbuf **pkts;
+       int n_pkts;
+       int pos;
+};
+
+static void *
+reader_create(void *args)
+{
+       struct rte_eth_dev_info info;
+       struct rte_swx_port_ethdev_reader_params *params = args;
+       struct reader *p;
+       int status;
+       uint16_t port_id;
+
+       /* Check input parameters. */
+       CHECK(params);
+
+       CHECK(params->dev_name);
+       status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id);
+       CHECK(!status);
+
+       status = rte_eth_dev_info_get(port_id, &info);
+       CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_rx_queues));
+
+       CHECK(params->burst_size);
+
+       /* Memory allocation. */
+       p = calloc(1, sizeof(struct reader));
+       CHECK(p);
+
+       p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *));
+       if (!p->pkts) {
+               free(p);
+               CHECK(0);
+       }
+
+       /* Initialization. */
+       p->params.port_id = port_id;
+       p->params.queue_id = params->queue_id;
+       p->params.burst_size = params->burst_size;
+
+       return p;
+}
+
+static int
+reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
+{
+       struct reader *p = port;
+       struct rte_mbuf *m;
+
+       if (p->pos == p->n_pkts) {
+               int n_pkts;
+
+               n_pkts = rte_eth_rx_burst(p->params.port_id,
+                                         p->params.queue_id,
+                                         p->pkts,
+                                         p->params.burst_size);
+               if (!n_pkts) {
+                       p->stats.n_empty++;
+                       return 0;
+               }
+
+               TRACE("[Ethdev RX port %u queue %u] %d packets in\n",
+                     (uint32_t)p->params.port_id,
+                     (uint32_t)p->params.queue_id,
+                     n_pkts);
+
+               p->n_pkts = n_pkts;
+               p->pos = 0;
+       }
+
+       m = p->pkts[p->pos++];
+       pkt->handle = m;
+       pkt->pkt = m->buf_addr;
+       pkt->offset = m->data_off;
+       pkt->length = m->pkt_len;
+
+       TRACE("[Ethdev RX port %u queue %u] Pkt %d (%u bytes at offset %u)\n",
+             (uint32_t)p->params.port_id,
+             (uint32_t)p->params.queue_id,
+             p->pos - 1,
+             pkt->length,
+             pkt->offset);
+       if (TRACE_LEVEL)
+               rte_hexdump(stdout,
+                           NULL,
+                           &((uint8_t *)m->buf_addr)[m->data_off],
+                           m->data_len);
+
+       p->stats.n_pkts++;
+       p->stats.n_bytes += pkt->length;
+
+       return 1;
+}
+
+static void
+reader_free(void *port)
+{
+       struct reader *p = port;
+       int i;
+
+       if (!p)
+               return;
+
+       for (i = 0; i < p->n_pkts; i++) {
+               struct rte_mbuf *pkt = p->pkts[i];
+
+               rte_pktmbuf_free(pkt);
+       }
+
+       free(p->pkts);
+       free(p);
+}
+
+static void
+reader_stats_read(void *port, struct rte_swx_port_in_stats *stats)
+{
+       struct reader *p = port;
+
+       memcpy(stats, &p->stats, sizeof(p->stats));
+}
+
+/*
+ * Port ETHDEV Writer
+ */
+struct writer {
+       struct {
+               uint16_t port_id;
+               uint16_t queue_id;
+               uint32_t burst_size;
+       } params;
+       struct rte_swx_port_out_stats stats;
+
+       struct rte_mbuf **pkts;
+       int n_pkts;
+};
+
+static void *
+writer_create(void *args)
+{
+       struct rte_eth_dev_info info;
+       struct rte_swx_port_ethdev_writer_params *params = args;
+       struct writer *p;
+       int status;
+       uint16_t port_id;
+
+       /* Check input parameters. */
+       CHECK(params);
+
+       CHECK(params->dev_name);
+       status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id);
+       CHECK(!status);
+
+       status = rte_eth_dev_info_get(port_id, &info);
+       CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_tx_queues));
+
+       CHECK(params->burst_size);
+
+       /* Memory allocation. */
+       p = calloc(1, sizeof(struct writer));
+       CHECK(p);
+
+       p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *));
+       if (!p->pkts) {
+               free(p);
+               CHECK(0);
+       }
+
+       /* Initialization. */
+       p->params.port_id = port_id;
+       p->params.queue_id = params->queue_id;
+       p->params.burst_size = params->burst_size;
+
+       return p;
+}
+
+static void
+__writer_flush(struct writer *p)
+{
+       int n_pkts;
+
+       for (n_pkts = 0; ; ) {
+               n_pkts += rte_eth_tx_burst(p->params.port_id,
+                                          p->params.queue_id,
+                                          p->pkts + n_pkts,
+                                          p->n_pkts - n_pkts);
+
+               TRACE("[Ethdev TX port %u queue %u] %d packets out\n",
+                     (uint32_t)p->params.port_id,
+                     (uint32_t)p->params.queue_id,
+                     n_pkts);
+
+               if (n_pkts == p->n_pkts)
+                       break;
+       }
+
+       p->n_pkts = 0;
+}
+
+static void
+writer_pkt_tx(void *port, struct rte_swx_pkt *pkt)
+{
+       struct writer *p = port;
+       struct rte_mbuf *m = pkt->handle;
+
+       TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u)\n",
+             (uint32_t)p->params.port_id,
+             (uint32_t)p->params.queue_id,
+             p->n_pkts - 1,
+             pkt->length,
+             pkt->offset);
+       if (TRACE_LEVEL)
+               rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
+
+       m->pkt_len = pkt->length;
+       m->data_len = (uint16_t)pkt->length;
+       m->data_off = (uint16_t)pkt->offset;
+
+       p->stats.n_pkts++;
+       p->stats.n_bytes += pkt->length;
+
+       p->pkts[p->n_pkts++] = m;
+       if (p->n_pkts ==  (int)p->params.burst_size)
+               __writer_flush(p);
+}
+
+static void
+writer_flush(void *port)
+{
+       struct writer *p = port;
+
+       if (p->n_pkts)
+               __writer_flush(p);
+}
+
+static void
+writer_free(void *port)
+{
+       struct writer *p = port;
+
+       if (!p)
+               return;
+
+       writer_flush(p);
+       free(p->pkts);
+       free(port);
+}
+
+static void
+writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
+{
+       struct writer *p = port;
+
+       memcpy(stats, &p->stats, sizeof(p->stats));
+}
+
+/*
+ * Summary of port operations
+ */
+struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops = {
+       .create = reader_create,
+       .free = reader_free,
+       .pkt_rx = reader_pkt_rx,
+       .stats_read = reader_stats_read,
+};
+
+struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = {
+       .create = writer_create,
+       .free = writer_free,
+       .pkt_tx = writer_pkt_tx,
+       .flush = writer_flush,
+       .stats_read = writer_stats_read,
+};
diff --git a/lib/librte_port/rte_swx_port_ethdev.h b/lib/librte_port/rte_swx_port_ethdev.h
new file mode 100644 (file)
index 0000000..cbc2d7b
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#ifndef __INCLUDE_RTE_SWX_PORT_ETHDEV_H__
+#define __INCLUDE_RTE_SWX_PORT_ETHDEV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE SWX Ethernet Device Input and Output Ports
+ */
+
+#include <stdint.h>
+
+#include "rte_swx_port.h"
+
+/** Ethernet device input port (reader) creation parameters. */
+struct rte_swx_port_ethdev_reader_params {
+       /** Name of a valid and fully configured Ethernet device. */
+       const char *dev_name;
+
+       /** Ethernet device receive queue ID. */
+       uint16_t queue_id;
+
+       /** Ethernet device receive burst size. */
+       uint32_t burst_size;
+};
+
+/** Ethernet device reader operations. */
+extern struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops;
+
+/** Ethernet device output port (writer) creation parameters. */
+struct rte_swx_port_ethdev_writer_params {
+       /** Name of a valid and fully configured Ethernet device. */
+       const char *dev_name;
+
+       /** Ethernet device transmit queue ID. */
+       uint16_t queue_id;
+
+       /** Ethernet device transmit burst size. */
+       uint32_t burst_size;
+};
+
+/** Ethernet device writer operations. */
+extern struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif