pipeline: add SWX pipeline input port
authorCristian Dumitrescu <cristian.dumitrescu@intel.com>
Thu, 1 Oct 2020 10:19:30 +0000 (11:19 +0100)
committerDavid Marchand <david.marchand@redhat.com>
Thu, 1 Oct 2020 16:43:07 +0000 (18:43 +0200)
Add input ports to the newly introduced SWX pipeline type. Each port
instantiates a port type that defines the port operations, e.g. ethdev
port, PCAP port, etc. The RX interface is single packet, with packet
batching internally for performance.

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

index a522e47..f1979a3 100644 (file)
@@ -168,6 +168,8 @@ The public API headers are grouped by topics:
     [table_action]     (@ref rte_table_action.h)
   * SWX pipeline:
     [pipeline]         (@ref rte_swx_pipeline.h)
+  * SWX port:
+    [port]             (@ref rte_swx_port.h)
   * [graph]            (@ref rte_graph.h):
     [graph_worker]     (@ref rte_graph_worker.h)
   * graph_nodes:
index 2b0650a..72a31a6 100644 (file)
@@ -63,4 +63,6 @@ EXPERIMENTAL {
        rte_swx_pipeline_build;
        rte_swx_pipeline_config;
        rte_swx_pipeline_free;
+       rte_swx_pipeline_port_in_config;
+       rte_swx_pipeline_port_in_type_register;
 };
index 2319d45..5b15592 100644 (file)
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 
@@ -19,14 +20,206 @@ do {                                                                           \
 #define CHECK_NAME(name, err_code)                                             \
        CHECK((name) && (name)[0], err_code)
 
+/*
+ * Input port.
+ */
+struct port_in_type {
+       TAILQ_ENTRY(port_in_type) node;
+       char name[RTE_SWX_NAME_SIZE];
+       struct rte_swx_port_in_ops ops;
+};
+
+TAILQ_HEAD(port_in_type_tailq, port_in_type);
+
+struct port_in {
+       TAILQ_ENTRY(port_in) node;
+       struct port_in_type *type;
+       void *obj;
+       uint32_t id;
+};
+
+TAILQ_HEAD(port_in_tailq, port_in);
+
+struct port_in_runtime {
+       rte_swx_port_in_pkt_rx_t pkt_rx;
+       void *obj;
+};
+
 /*
  * Pipeline.
  */
 struct rte_swx_pipeline {
+       struct port_in_type_tailq port_in_types;
+       struct port_in_tailq ports_in;
+
+       struct port_in_runtime *in;
+
+       uint32_t n_ports_in;
        int build_done;
        int numa_node;
 };
 
+/*
+ * Input port.
+ */
+static struct port_in_type *
+port_in_type_find(struct rte_swx_pipeline *p, const char *name)
+{
+       struct port_in_type *elem;
+
+       if (!name)
+               return NULL;
+
+       TAILQ_FOREACH(elem, &p->port_in_types, node)
+               if (strcmp(elem->name, name) == 0)
+                       return elem;
+
+       return NULL;
+}
+
+int
+rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
+                                      const char *name,
+                                      struct rte_swx_port_in_ops *ops)
+{
+       struct port_in_type *elem;
+
+       CHECK(p, EINVAL);
+       CHECK_NAME(name, EINVAL);
+       CHECK(ops, EINVAL);
+       CHECK(ops->create, EINVAL);
+       CHECK(ops->free, EINVAL);
+       CHECK(ops->pkt_rx, EINVAL);
+       CHECK(ops->stats_read, EINVAL);
+
+       CHECK(!port_in_type_find(p, name), EEXIST);
+
+       /* Node allocation. */
+       elem = calloc(1, sizeof(struct port_in_type));
+       CHECK(elem, ENOMEM);
+
+       /* Node initialization. */
+       strcpy(elem->name, name);
+       memcpy(&elem->ops, ops, sizeof(*ops));
+
+       /* Node add to tailq. */
+       TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
+
+       return 0;
+}
+
+static struct port_in *
+port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
+{
+       struct port_in *port;
+
+       TAILQ_FOREACH(port, &p->ports_in, node)
+               if (port->id == port_id)
+                       return port;
+
+       return NULL;
+}
+
+int
+rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
+                               uint32_t port_id,
+                               const char *port_type_name,
+                               void *args)
+{
+       struct port_in_type *type = NULL;
+       struct port_in *port = NULL;
+       void *obj = NULL;
+
+       CHECK(p, EINVAL);
+
+       CHECK(!port_in_find(p, port_id), EINVAL);
+
+       CHECK_NAME(port_type_name, EINVAL);
+       type = port_in_type_find(p, port_type_name);
+       CHECK(type, EINVAL);
+
+       obj = type->ops.create(args);
+       CHECK(obj, ENODEV);
+
+       /* Node allocation. */
+       port = calloc(1, sizeof(struct port_in));
+       CHECK(port, ENOMEM);
+
+       /* Node initialization. */
+       port->type = type;
+       port->obj = obj;
+       port->id = port_id;
+
+       /* Node add to tailq. */
+       TAILQ_INSERT_TAIL(&p->ports_in, port, node);
+       if (p->n_ports_in < port_id + 1)
+               p->n_ports_in = port_id + 1;
+
+       return 0;
+}
+
+static int
+port_in_build(struct rte_swx_pipeline *p)
+{
+       struct port_in *port;
+       uint32_t i;
+
+       CHECK(p->n_ports_in, EINVAL);
+       CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
+
+       for (i = 0; i < p->n_ports_in; i++)
+               CHECK(port_in_find(p, i), EINVAL);
+
+       p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
+       CHECK(p->in, ENOMEM);
+
+       TAILQ_FOREACH(port, &p->ports_in, node) {
+               struct port_in_runtime *in = &p->in[port->id];
+
+               in->pkt_rx = port->type->ops.pkt_rx;
+               in->obj = port->obj;
+       }
+
+       return 0;
+}
+
+static void
+port_in_build_free(struct rte_swx_pipeline *p)
+{
+       free(p->in);
+       p->in = NULL;
+}
+
+static void
+port_in_free(struct rte_swx_pipeline *p)
+{
+       port_in_build_free(p);
+
+       /* Input ports. */
+       for ( ; ; ) {
+               struct port_in *port;
+
+               port = TAILQ_FIRST(&p->ports_in);
+               if (!port)
+                       break;
+
+               TAILQ_REMOVE(&p->ports_in, port, node);
+               port->type->ops.free(port->obj);
+               free(port);
+       }
+
+       /* Input port types. */
+       for ( ; ; ) {
+               struct port_in_type *elem;
+
+               elem = TAILQ_FIRST(&p->port_in_types);
+               if (!elem)
+                       break;
+
+               TAILQ_REMOVE(&p->port_in_types, elem, node);
+               free(elem);
+       }
+}
 
 /*
  * Pipeline.
@@ -44,6 +237,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
        CHECK(pipeline, ENOMEM);
 
        /* Initialization. */
+       TAILQ_INIT(&pipeline->port_in_types);
+       TAILQ_INIT(&pipeline->ports_in);
+
        pipeline->numa_node = numa_node;
 
        *p = pipeline;
@@ -56,15 +252,28 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
        if (!p)
                return;
 
+       port_in_free(p);
+
        free(p);
 }
 
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
+       int status;
+
        CHECK(p, EINVAL);
        CHECK(p->build_done == 0, EEXIST);
 
+       status = port_in_build(p);
+       if (status)
+               goto error;
+
        p->build_done = 1;
        return 0;
+
+error:
+       port_in_build_free(p);
+
+       return status;
 }
index ded26a4..3dbe7ce 100644 (file)
@@ -18,6 +18,12 @@ extern "C" {
 
 #include <rte_compat.h>
 
+#include "rte_swx_port.h"
+
+/** Name size. */
+#ifndef RTE_SWX_NAME_SIZE
+#define RTE_SWX_NAME_SIZE 64
+#endif
 /*
  * Pipeline setup and operation
  */
@@ -43,6 +49,54 @@ int
 rte_swx_pipeline_config(struct rte_swx_pipeline **p,
                        int numa_node);
 
+/*
+ * Pipeline input ports
+ */
+
+/**
+ * Pipeline input port type register
+ *
+ * @param[in] p
+ *   Pipeline handle.
+ * @param[in] name
+ *   Input port type name.
+ * @param[in] ops
+ *   Input port type operations.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Input port type with this name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
+                                      const char *name,
+                                      struct rte_swx_port_in_ops *ops);
+
+/**
+ * Pipeline input port configure
+ *
+ * @param[in] p
+ *   Pipeline handle.
+ * @param[in] port_id
+ *   Input port ID.
+ * @param[in] port_type_name
+ *   Existing input port type name.
+ * @param[in] args
+ *   Input port creation arguments.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -ENODEV: Input port object creation error.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
+                               uint32_t port_id,
+                               const char *port_type_name,
+                               void *args);
 /**
  * Pipeline build
  *
index 0d5ede4..5b5fbf6 100644 (file)
@@ -21,7 +21,8 @@ headers = files(
        'rte_port_sched.h',
        'rte_port_source_sink.h',
        'rte_port_sym_crypto.h',
-       'rte_port_eventdev.h')
+       'rte_port_eventdev.h',
+       'rte_swx_port.h',)
 deps += ['ethdev', 'sched', 'ip_frag', 'cryptodev', 'eventdev']
 
 if dpdk_conf.has('RTE_PORT_PCAP')
diff --git a/lib/librte_port/rte_swx_port.h b/lib/librte_port/rte_swx_port.h
new file mode 100644 (file)
index 0000000..a6f80de
--- /dev/null
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#ifndef __INCLUDE_RTE_SWX_PORT_H__
+#define __INCLUDE_RTE_SWX_PORT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE SWX Port
+ *
+ * Packet I/O port interface.
+ */
+
+#include <stdint.h>
+
+/** Packet. */
+struct rte_swx_pkt {
+       /** Opaque packet handle. */
+       void *handle;
+
+       /** Buffer where the packet is stored. */
+       uint8_t *pkt;
+
+       /** Packet buffer offset of the first packet byte. */
+       uint32_t offset;
+
+       /** Packet length in bytes. */
+       uint32_t length;
+};
+
+/*
+ * Input port
+ */
+
+/**
+ * Input port create
+ *
+ * @param[in] args
+ *   Arguments for input port creation. Format specific to each port type.
+ * @return
+ *   Handle to input port instance on success, NULL on error.
+ */
+typedef void *
+(*rte_swx_port_in_create_t)(void *args);
+
+/**
+ * Input port free
+ *
+ * @param[in] args
+ *   Input port handle.
+ */
+typedef void
+(*rte_swx_port_in_free_t)(void *port);
+
+/**
+ * Input port packet receive
+ *
+ * @param[in] port
+ *   Input port handle.
+ * @param[out] pkt
+ *   Received packet. Only valid when the function returns 1. Must point to
+ *   valid memory.
+ * @return
+ *   0 when no packet was received, 1 when a packet was received. No other
+ *   return values are allowed.
+ */
+typedef int
+(*rte_swx_port_in_pkt_rx_t)(void *port,
+                           struct rte_swx_pkt *pkt);
+
+/** Input port statistics counters. */
+struct rte_swx_port_in_stats {
+       /** Number of packets. */
+       uint64_t n_pkts;
+
+       /** Number of bytes. */
+       uint64_t n_bytes;
+
+       /** Number of empty polls. */
+       uint64_t n_empty;
+};
+
+/**
+ * Input port statistics counters read
+ *
+ * @param[in] port
+ *   Input port handle.
+ * @param[out] stats
+ *   Input port statistics counters. Must point to valid memory.
+ */
+typedef void
+(*rte_swx_port_in_stats_read_t)(void *port,
+                               struct rte_swx_port_in_stats *stats);
+
+/** Input port operations. */
+struct rte_swx_port_in_ops {
+       /** Create. Must be non-NULL. */
+       rte_swx_port_in_create_t create;
+
+       /** Free. Must be non-NULL. */
+       rte_swx_port_in_free_t free;
+
+       /** Packet reception. Must be non-NULL. */
+       rte_swx_port_in_pkt_rx_t pkt_rx;
+
+       /** Statistics counters read. Must be non-NULL. */
+       rte_swx_port_in_stats_read_t stats_read;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif