From: Cristian Dumitrescu Date: Thu, 1 Oct 2020 10:19:30 +0000 (+0100) Subject: pipeline: add SWX pipeline input port X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=6e0ca01c9344b042a49a595c7e446d907ad3dde9;p=dpdk.git pipeline: add SWX pipeline input port 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 --- diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index a522e47302..f1979a36ca 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -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: diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 2b0650a748..72a31a6552 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -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; }; diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index 2319d45709..5b15592090 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -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; } diff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h index ded26a4e49..3dbe7ce0b3 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.h +++ b/lib/librte_pipeline/rte_swx_pipeline.h @@ -18,6 +18,12 @@ extern "C" { #include +#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 * diff --git a/lib/librte_port/meson.build b/lib/librte_port/meson.build index 0d5ede44a0..5b5fbf6c40 100644 --- a/lib/librte_port/meson.build +++ b/lib/librte_port/meson.build @@ -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 index 0000000000..a6f80de9af --- /dev/null +++ b/lib/librte_port/rte_swx_port.h @@ -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 + +/** 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