port: add file descriptor SWX port
authorVenkata Suresh Kumar P <venkata.suresh.kumar.p@intel.com>
Tue, 23 Mar 2021 18:05:03 +0000 (14:05 -0400)
committerThomas Monjalon <thomas@monjalon.net>
Tue, 23 Mar 2021 18:50:44 +0000 (19:50 +0100)
Add the file descriptor input/output port type for the SWX pipeline.
File descriptor port type provides interface with the kernel network
stack. Example file descriptor port is TAP device.

Signed-off-by: Venkata Suresh Kumar P <venkata.suresh.kumar.p@intel.com>
Signed-off-by: Churchill Khangar <churchill.khangar@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
doc/api/doxy-api-index.md
examples/pipeline/cli.c
examples/pipeline/obj.c
examples/pipeline/obj.h
lib/librte_port/meson.build
lib/librte_port/rte_swx_port_fd.c [new file with mode: 0644]
lib/librte_port/rte_swx_port_fd.h [new file with mode: 0644]
lib/librte_port/version.map

index f4ca3e4..f3d5d46 100644 (file)
@@ -186,6 +186,7 @@ The public API headers are grouped by topics:
   * SWX port:
     [port]             (@ref rte_swx_port.h),
     [ethdev]           (@ref rte_swx_port_ethdev.h),
+    [fd]               (@ref rte_swx_port_fd.h),
     [ring]             (@ref rte_swx_port_ring.h),
     [src/sink]         (@ref rte_swx_port_source_sink.h)
   * SWX table:
index 01a2db7..ae06658 100644 (file)
@@ -12,6 +12,7 @@
 #include <rte_swx_port_ethdev.h>
 #include <rte_swx_port_ring.h>
 #include <rte_swx_port_source_sink.h>
+#include <rte_swx_port_fd.h>
 #include <rte_swx_pipeline.h>
 #include <rte_swx_ctl.h>
 
@@ -493,6 +494,32 @@ cmd_ring(char **tokens,
        }
 }
 
+static const char cmd_tap_help[] =
+"tap <tap_name>\n";
+
+static void
+cmd_tap(char **tokens,
+       uint32_t n_tokens,
+       char *out,
+       size_t out_size,
+       void *obj)
+{
+       struct tap *tap;
+       char *name;
+
+       if (n_tokens < 2) {
+               snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+               return;
+       }
+       name = tokens[1];
+
+       tap = tap_create(obj, name);
+       if (tap == NULL) {
+               snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+               return;
+       }
+}
+
 static const char cmd_pipeline_create_help[] =
 "pipeline <pipeline_name> create <numa_node>\n";
 
@@ -530,7 +557,8 @@ static const char cmd_pipeline_port_in_help[] =
 "pipeline <pipeline_name> port in <port_id>\n"
 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
 "   ring <ring_name> bsz <burst_size>\n"
-"   | source <mempool_name> <file_name>\n";
+"   | source <mempool_name> <file_name>\n"
+"   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
 
 static void
 cmd_pipeline_port_in(char **tokens,
@@ -678,6 +706,68 @@ cmd_pipeline_port_in(char **tokens,
                        port_id,
                        "source",
                        &params);
+       } else if (strcmp(tokens[t0], "tap") == 0) {
+               struct rte_swx_port_fd_reader_params params;
+               struct tap *tap;
+               struct mempool *mp;
+
+               if (n_tokens < t0 + 8) {
+                       snprintf(out, out_size, MSG_ARG_MISMATCH,
+                               "pipeline port in tap");
+                       return;
+               }
+
+               tap = tap_find(obj, tokens[t0 + 1]);
+               if (!tap) {
+                       snprintf(out, out_size, MSG_ARG_INVALID,
+                               "tap_name");
+                       return;
+               }
+               params.fd = tap->fd;
+
+               if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+                       snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+                               "mempool");
+                       return;
+               }
+
+               mp = mempool_find(obj, tokens[t0 + 3]);
+               if (!mp) {
+                       snprintf(out, out_size, MSG_ARG_INVALID,
+                               "mempool_name");
+                       return;
+               }
+               params.mempool = mp->m;
+
+               if (strcmp(tokens[t0 + 4], "mtu") != 0) {
+                       snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+                               "mtu");
+                       return;
+               }
+
+               if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
+                       snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+                       return;
+               }
+
+               if (strcmp(tokens[t0 + 6], "bsz") != 0) {
+                       snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+                       return;
+               }
+
+               if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
+                       snprintf(out, out_size, MSG_ARG_INVALID,
+                               "burst_size");
+                       return;
+               }
+
+               t0 += 8;
+
+               status = rte_swx_pipeline_port_in_config(p->p,
+                       port_id,
+                       "fd",
+                       &params);
+
        } else {
                snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
                return;
@@ -698,7 +788,8 @@ static const char cmd_pipeline_port_out_help[] =
 "pipeline <pipeline_name> port out <port_id>\n"
 "   link <link_name> txq <txq_id> bsz <burst_size>\n"
 "   ring <ring_name> bsz <burst_size>\n"
-"   | sink <file_name> | none\n";
+"   | sink <file_name> | none\n"
+"   | tap <tap_name> bsz <burst_size>\n";
 
 static void
 cmd_pipeline_port_out(char **tokens,
@@ -832,6 +923,41 @@ cmd_pipeline_port_out(char **tokens,
                        port_id,
                        "sink",
                        &params);
+       } else if (strcmp(tokens[t0], "tap") == 0) {
+               struct rte_swx_port_fd_writer_params params;
+               struct tap *tap;
+
+               if (n_tokens < t0 + 4) {
+                       snprintf(out, out_size, MSG_ARG_MISMATCH,
+                               "pipeline port out tap");
+                       return;
+               }
+
+               tap = tap_find(obj, tokens[t0 + 1]);
+               if (!tap) {
+                       snprintf(out, out_size, MSG_ARG_INVALID,
+                               "tap_name");
+                       return;
+               }
+               params.fd = tap->fd;
+
+               if (strcmp(tokens[t0 + 2], "bsz") != 0) {
+                       snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+                       return;
+               }
+
+               if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
+                       snprintf(out, out_size, MSG_ARG_INVALID,
+                               "burst_size");
+                       return;
+               }
+
+               t0 += 4;
+
+               status = rte_swx_pipeline_port_out_config(p->p,
+                       port_id,
+                       "fd",
+                       &params);
        } else {
                snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
                return;
@@ -1318,6 +1444,7 @@ cmd_help(char **tokens,
                        "List of commands:\n"
                        "\tmempool\n"
                        "\tlink\n"
+                       "\ttap\n"
                        "\tpipeline create\n"
                        "\tpipeline port in\n"
                        "\tpipeline port out\n"
@@ -1344,6 +1471,11 @@ cmd_help(char **tokens,
                return;
        }
 
+       if (strcmp(tokens[0], "tap") == 0) {
+               snprintf(out, out_size, "\n%s\n", cmd_tap_help);
+               return;
+       }
+
        if ((strcmp(tokens[0], "pipeline") == 0) &&
                (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
                snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
@@ -1449,6 +1581,11 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
                return;
        }
 
+       if (strcmp(tokens[0], "tap") == 0) {
+               cmd_tap(tokens, n_tokens, out, out_size, obj);
+               return;
+       }
+
        if (strcmp(tokens[0], "pipeline") == 0) {
                if ((n_tokens >= 3) &&
                        (strcmp(tokens[2], "create") == 0)) {
index 0e05583..467cda5 100644 (file)
@@ -4,11 +4,20 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <netinet/in.h>
+#ifdef RTE_EXEC_ENV_LINUX
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
 #include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_fd.h>
 #include <rte_swx_port_ring.h>
 #include <rte_swx_port_source_sink.h>
 #include <rte_swx_table_em.h>
@@ -33,6 +42,11 @@ TAILQ_HEAD(link_list, link);
  */
 TAILQ_HEAD(ring_list, ring);
 
+/*
+ * tap
+ */
+TAILQ_HEAD(tap_list, tap);
+
 /*
  * pipeline
  */
@@ -46,6 +60,7 @@ struct obj {
        struct link_list link_list;
        struct ring_list ring_list;
        struct pipeline_list pipeline_list;
+       struct tap_list tap_list;
 };
 
 /*
@@ -422,6 +437,88 @@ ring_find(struct obj *obj, const char *name)
        return NULL;
 }
 
+/*
+ * tap
+ */
+#define TAP_DEV                "/dev/net/tun"
+
+struct tap *
+tap_find(struct obj *obj, const char *name)
+{
+       struct tap *tap;
+
+       if (!obj || !name)
+               return NULL;
+
+       TAILQ_FOREACH(tap, &obj->tap_list, node)
+               if (strcmp(tap->name, name) == 0)
+                       return tap;
+
+       return NULL;
+}
+
+struct tap *
+tap_next(struct obj *obj, struct tap *tap)
+{
+       return (tap == NULL) ?
+               TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
+}
+
+#ifndef RTE_EXEC_ENV_LINUX
+
+struct tap *
+tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
+{
+       return NULL;
+}
+
+#else
+
+struct tap *
+tap_create(struct obj *obj, const char *name)
+{
+       struct tap *tap;
+       struct ifreq ifr;
+       int fd, status;
+
+       /* Check input params */
+       if ((name == NULL) ||
+               tap_find(obj, name))
+               return NULL;
+
+       /* Resource create */
+       fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
+       if (fd < 0)
+               return NULL;
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+       strlcpy(ifr.ifr_name, name, IFNAMSIZ);
+
+       status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+       if (status < 0) {
+               close(fd);
+               return NULL;
+       }
+
+       /* Node allocation */
+       tap = calloc(1, sizeof(struct tap));
+       if (tap == NULL) {
+               close(fd);
+               return NULL;
+       }
+       /* Node fill in */
+       strlcpy(tap->name, name, sizeof(tap->name));
+       tap->fd = fd;
+
+       /* Node add to list */
+       TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
+
+       return tap;
+}
+
+#endif
+
 /*
  * pipeline
  */
@@ -484,6 +581,18 @@ pipeline_create(struct obj *obj, const char *name, int numa_node)
        if (status)
                goto error;
 
+       status = rte_swx_pipeline_port_in_type_register(p,
+               "fd",
+               &rte_swx_port_fd_reader_ops);
+       if (status)
+               goto error;
+
+       status = rte_swx_pipeline_port_out_type_register(p,
+               "fd",
+               &rte_swx_port_fd_writer_ops);
+       if (status)
+               goto error;
+
        status = rte_swx_pipeline_table_type_register(p,
                "exact",
                RTE_SWX_TABLE_MATCH_EXACT,
@@ -549,6 +658,7 @@ obj_init(void)
        TAILQ_INIT(&obj->link_list);
        TAILQ_INIT(&obj->ring_list);
        TAILQ_INIT(&obj->pipeline_list);
+       TAILQ_INIT(&obj->tap_list);
 
        return obj;
 }
index 1aab2a3..b921610 100644 (file)
@@ -125,6 +125,24 @@ ring_create(struct obj *obj,
 struct ring *
 ring_find(struct obj *obj, const char *name);
 
+/*
+ * tap
+ */
+struct tap {
+       TAILQ_ENTRY(tap) node;
+       char name[NAME_SIZE];
+       int fd;
+};
+
+struct tap *
+tap_find(struct obj *obj, const char *name);
+
+struct tap *
+tap_next(struct obj *obj, struct tap *tap);
+
+struct tap *
+tap_create(struct obj *obj, const char *name);
+
 /*
  * pipeline
  */
index 9fcd62c..435b64a 100644 (file)
@@ -12,6 +12,7 @@ sources = files(
        'rte_port_sym_crypto.c',
        'rte_port_eventdev.c',
        'rte_swx_port_ethdev.c',
+       'rte_swx_port_fd.c',
        'rte_swx_port_ring.c',
        'rte_swx_port_source_sink.c',
        )
@@ -28,6 +29,7 @@ headers = files(
        'rte_port_eventdev.h',
        'rte_swx_port.h',
        'rte_swx_port_ethdev.h',
+       'rte_swx_port_fd.h',
        'rte_swx_port_ring.h',
        'rte_swx_port_source_sink.h',
        )
diff --git a/lib/librte_port/rte_swx_port_fd.c b/lib/librte_port/rte_swx_port_fd.c
new file mode 100644 (file)
index 0000000..aa7315a
--- /dev/null
@@ -0,0 +1,299 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Intel Corporation
+ */
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_hexdump.h>
+
+#include "rte_swx_port_fd.h"
+
+#ifndef TRACE_LEVEL
+#define TRACE_LEVEL 0
+#endif
+
+#if TRACE_LEVEL
+#define TRACE(...) printf(__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+/*
+ * FD Reader
+ */
+struct reader {
+       struct {
+               int fd;
+               uint32_t mtu;
+               uint32_t burst_size;
+               struct rte_mempool *mempool;
+       } params;
+
+       struct rte_swx_port_in_stats stats;
+       struct rte_mbuf **pkts;
+       uint32_t n_pkts;
+       uint32_t pos;
+};
+
+static void *
+reader_create(void *args)
+{
+       struct rte_swx_port_fd_reader_params *conf = args;
+       struct reader *p;
+
+       /* Check input parameters. */
+       if (!conf || conf->fd < 0 || conf->mtu == 0 || !conf->mempool)
+               return NULL;
+
+       /* Memory allocation. */
+       p = calloc(1, sizeof(struct reader));
+       if (!p)
+               return NULL;
+
+       p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
+       if (!p->pkts) {
+               free(p);
+               return NULL;
+       }
+
+       /* Initialization. */
+       p->params.fd = conf->fd;
+       p->params.mtu = conf->mtu;
+       p->params.burst_size = conf->burst_size;
+       p->params.mempool = conf->mempool;
+
+       return p;
+}
+
+static void
+reader_free(void *port)
+{
+       struct reader *p = port;
+       uint32_t i;
+
+       if (!p)
+               return;
+
+       for (i = 0; i < p->n_pkts; i++)
+               rte_pktmbuf_free(p->pkts[i]);
+
+       free(p->pkts);
+       free(p);
+}
+
+static int
+reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
+{
+       struct reader *p = port;
+       struct rte_mbuf *m;
+       void *pkt_data;
+       ssize_t n_bytes;
+       uint32_t i, j;
+
+       if (p->n_pkts == p->pos) {
+               if (rte_pktmbuf_alloc_bulk(p->params.mempool, p->pkts, p->params.burst_size) != 0)
+                       return 0;
+
+               for (i = 0; i < p->params.burst_size; i++) {
+                       m = p->pkts[i];
+                       pkt_data = rte_pktmbuf_mtod(m, void *);
+                       n_bytes = read(p->params.fd, pkt_data, (size_t) p->params.mtu);
+
+                       if (n_bytes <= 0)
+                               break;
+
+                       m->data_len = n_bytes;
+                       m->pkt_len = n_bytes;
+
+                       p->stats.n_pkts++;
+                       p->stats.n_bytes += n_bytes;
+               }
+
+               for (j = i; j < p->params.burst_size; j++)
+                       rte_pktmbuf_free(p->pkts[j]);
+
+               p->n_pkts = i;
+               p->pos = 0;
+
+               if (!p->n_pkts)
+                       return 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("[FD %u] Pkt %d (%u bytes at offset %u)\n",
+               (uint32_t)p->params.fd,
+               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);
+
+       return 1;
+}
+
+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));
+}
+
+/*
+ * FD Writer
+ */
+struct writer {
+       struct {
+               int fd;
+               uint32_t mtu;
+               uint32_t burst_size;
+               struct rte_mempool *mempool;
+       } params;
+
+       struct rte_swx_port_out_stats stats;
+       struct rte_mbuf **pkts;
+       uint32_t n_pkts;
+};
+
+static void *
+writer_create(void *args)
+{
+       struct rte_swx_port_fd_writer_params *conf = args;
+       struct writer *p;
+
+       /* Check input parameters. */
+       if (!conf)
+               return NULL;
+
+       /* Memory allocation. */
+       p = calloc(1, sizeof(struct writer));
+       if (!p)
+               return NULL;
+
+
+       p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
+       if (!p->pkts) {
+               free(p);
+               return NULL;
+       }
+
+       /* Initialization. */
+       p->params.fd = conf->fd;
+       p->params.burst_size = conf->burst_size;
+
+       return p;
+}
+
+static void
+__writer_flush(struct writer *p)
+{
+       struct rte_mbuf *pkt;
+       void *pkt_data;
+       size_t n_bytes;
+       ssize_t ret;
+       uint32_t i;
+
+       for (i = 0; i < p->n_pkts; i++) {
+               pkt = p->pkts[i];
+               pkt_data = rte_pktmbuf_mtod(pkt, void*);
+               n_bytes = rte_pktmbuf_data_len(pkt);
+
+               ret = write(p->params.fd, pkt_data, n_bytes);
+               if (ret < 0)
+                       break;
+       }
+
+       TRACE("[FD %u] %u packets out\n",
+               (uint32_t)p->params.fd,
+               p->n_pkts);
+
+       for (i = 0; i < p->n_pkts; i++)
+               rte_pktmbuf_free(p->pkts[i]);
+
+       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("[FD %u] Pkt %u (%u bytes at offset %u)\n",
+               (uint32_t)p->params.fd,
+               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 == 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(p);
+}
+
+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_fd_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_fd_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_fd.h b/lib/librte_port/rte_swx_port_fd.h
new file mode 100644 (file)
index 0000000..ecf3349
--- /dev/null
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_SWX_PORT_FD_H__
+#define __INCLUDE_RTE_SWX_PORT_FD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE SWX FD Input and Output Ports
+ *
+ ***/
+#include <stdint.h>
+
+#include <rte_mempool.h>
+
+#include "rte_swx_port.h"
+
+/** fd_reader port parameters */
+struct rte_swx_port_fd_reader_params {
+       /** File descriptor. Must be valid and opened in non-blocking mode. */
+       int fd;
+
+       /** Maximum Transfer Unit (MTU) */
+       uint32_t mtu;
+
+       /** Pre-initialized buffer pool */
+       struct rte_mempool *mempool;
+
+       /** RX burst size */
+       uint32_t burst_size;
+};
+
+/** fd_reader port operations */
+extern struct rte_swx_port_in_ops rte_swx_port_fd_reader_ops;
+
+/** fd_writer port parameters */
+struct rte_swx_port_fd_writer_params {
+       /** File descriptor. Must be valid and opened in non-blocking mode. */
+       int fd;
+
+       /** TX burst size */
+       uint32_t burst_size;
+};
+
+/** fd_writer port operations */
+extern struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_SWX_PORT_FD_H__ */
index e6f35e6..70922e1 100644 (file)
@@ -46,6 +46,8 @@ EXPERIMENTAL {
        rte_swx_port_source_ops;
 
        # added in 21.05
+       rte_swx_port_fd_reader_ops;
+       rte_swx_port_fd_writer_ops;
        rte_swx_port_ring_reader_ops;
        rte_swx_port_ring_writer_ops;
 };