From 99a0ba8f4cee4131ee4c716d05221350f097769e Mon Sep 17 00:00:00 2001 From: Cristian Dumitrescu Date: Thu, 1 Oct 2020 11:19:31 +0100 Subject: [PATCH] pipeline: add SWX pipeline output port Add output 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 TX interface is single packet, with packet batching internally for performance. Signed-off-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_pipeline_version.map | 2 + lib/librte_pipeline/rte_swx_pipeline.c | 200 +++++++++++++++++++ lib/librte_pipeline/rte_swx_pipeline.h | 50 +++++ lib/librte_port/rte_swx_port.h | 84 ++++++++ 4 files changed, 336 insertions(+) diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 72a31a6552..5ec98d5ca9 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -65,4 +65,6 @@ EXPERIMENTAL { rte_swx_pipeline_free; rte_swx_pipeline_port_in_config; rte_swx_pipeline_port_in_type_register; + rte_swx_pipeline_port_out_config; + rte_swx_pipeline_port_out_type_register; }; diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index 5b15592090..7aeac8cc8c 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -45,16 +45,46 @@ struct port_in_runtime { void *obj; }; +/* + * Output port. + */ +struct port_out_type { + TAILQ_ENTRY(port_out_type) node; + char name[RTE_SWX_NAME_SIZE]; + struct rte_swx_port_out_ops ops; +}; + +TAILQ_HEAD(port_out_type_tailq, port_out_type); + +struct port_out { + TAILQ_ENTRY(port_out) node; + struct port_out_type *type; + void *obj; + uint32_t id; +}; + +TAILQ_HEAD(port_out_tailq, port_out); + +struct port_out_runtime { + rte_swx_port_out_pkt_tx_t pkt_tx; + rte_swx_port_out_flush_t flush; + void *obj; +}; + /* * Pipeline. */ struct rte_swx_pipeline { struct port_in_type_tailq port_in_types; struct port_in_tailq ports_in; + struct port_out_type_tailq port_out_types; + struct port_out_tailq ports_out; struct port_in_runtime *in; + struct port_out_runtime *out; uint32_t n_ports_in; + uint32_t n_ports_out; int build_done; int numa_node; }; @@ -221,6 +251,168 @@ port_in_free(struct rte_swx_pipeline *p) } } +/* + * Output port. + */ +static struct port_out_type * +port_out_type_find(struct rte_swx_pipeline *p, const char *name) +{ + struct port_out_type *elem; + + if (!name) + return NULL; + + TAILQ_FOREACH(elem, &p->port_out_types, node) + if (!strcmp(elem->name, name)) + return elem; + + return NULL; +} + +int +rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p, + const char *name, + struct rte_swx_port_out_ops *ops) +{ + struct port_out_type *elem; + + CHECK(p, EINVAL); + CHECK_NAME(name, EINVAL); + CHECK(ops, EINVAL); + CHECK(ops->create, EINVAL); + CHECK(ops->free, EINVAL); + CHECK(ops->pkt_tx, EINVAL); + CHECK(ops->stats_read, EINVAL); + + CHECK(!port_out_type_find(p, name), EEXIST); + + /* Node allocation. */ + elem = calloc(1, sizeof(struct port_out_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_out_types, elem, node); + + return 0; +} + +static struct port_out * +port_out_find(struct rte_swx_pipeline *p, uint32_t port_id) +{ + struct port_out *port; + + TAILQ_FOREACH(port, &p->ports_out, node) + if (port->id == port_id) + return port; + + return NULL; +} + +int +rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p, + uint32_t port_id, + const char *port_type_name, + void *args) +{ + struct port_out_type *type = NULL; + struct port_out *port = NULL; + void *obj = NULL; + + CHECK(p, EINVAL); + + CHECK(!port_out_find(p, port_id), EINVAL); + + CHECK_NAME(port_type_name, EINVAL); + type = port_out_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_out)); + CHECK(port, ENOMEM); + + /* Node initialization. */ + port->type = type; + port->obj = obj; + port->id = port_id; + + /* Node add to tailq. */ + TAILQ_INSERT_TAIL(&p->ports_out, port, node); + if (p->n_ports_out < port_id + 1) + p->n_ports_out = port_id + 1; + + return 0; +} + +static int +port_out_build(struct rte_swx_pipeline *p) +{ + struct port_out *port; + uint32_t i; + + CHECK(p->n_ports_out, EINVAL); + + for (i = 0; i < p->n_ports_out; i++) + CHECK(port_out_find(p, i), EINVAL); + + p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime)); + CHECK(p->out, ENOMEM); + + TAILQ_FOREACH(port, &p->ports_out, node) { + struct port_out_runtime *out = &p->out[port->id]; + + out->pkt_tx = port->type->ops.pkt_tx; + out->flush = port->type->ops.flush; + out->obj = port->obj; + } + + return 0; +} + +static void +port_out_build_free(struct rte_swx_pipeline *p) +{ + free(p->out); + p->out = NULL; +} + +static void +port_out_free(struct rte_swx_pipeline *p) +{ + port_out_build_free(p); + + /* Output ports. */ + for ( ; ; ) { + struct port_out *port; + + port = TAILQ_FIRST(&p->ports_out); + if (!port) + break; + + TAILQ_REMOVE(&p->ports_out, port, node); + port->type->ops.free(port->obj); + free(port); + } + + /* Output port types. */ + for ( ; ; ) { + struct port_out_type *elem; + + elem = TAILQ_FIRST(&p->port_out_types); + if (!elem) + break; + + TAILQ_REMOVE(&p->port_out_types, elem, node); + free(elem); + } +} + /* * Pipeline. */ @@ -239,6 +431,8 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) /* Initialization. */ TAILQ_INIT(&pipeline->port_in_types); TAILQ_INIT(&pipeline->ports_in); + TAILQ_INIT(&pipeline->port_out_types); + TAILQ_INIT(&pipeline->ports_out); pipeline->numa_node = numa_node; @@ -252,6 +446,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p) if (!p) return; + port_out_free(p); port_in_free(p); free(p); @@ -269,10 +464,15 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) if (status) goto error; + status = port_out_build(p); + if (status) + goto error; + p->build_done = 1; return 0; error: + port_out_build_free(p); 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 3dbe7ce0b3..2be83bd358 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.h +++ b/lib/librte_pipeline/rte_swx_pipeline.h @@ -97,6 +97,56 @@ rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p, uint32_t port_id, const char *port_type_name, void *args); + +/* + * Pipeline output ports + */ + +/** + * Pipeline output port type register + * + * @param[in] p + * Pipeline handle. + * @param[in] name + * Output port type name. + * @param[in] ops + * Output port type operations. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -EEXIST: Output port type with this name already exists. + */ +__rte_experimental +int +rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p, + const char *name, + struct rte_swx_port_out_ops *ops); + +/** + * Pipeline output port configure + * + * @param[in] p + * Pipeline handle. + * @param[in] port_id + * Output port ID. + * @param[in] port_type_name + * Existing output port type name. + * @param[in] args + * Output port creation arguments. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -ENODEV: Output port object creation error. + */ +__rte_experimental +int +rte_swx_pipeline_port_out_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/rte_swx_port.h b/lib/librte_port/rte_swx_port.h index a6f80de9af..4beb59991f 100644 --- a/lib/librte_port/rte_swx_port.h +++ b/lib/librte_port/rte_swx_port.h @@ -111,6 +111,90 @@ struct rte_swx_port_in_ops { rte_swx_port_in_stats_read_t stats_read; }; +/* + * Output port + */ + +/** + * Output port create + * + * @param[in] args + * Arguments for output port creation. Format specific to each port type. + * @return + * Handle to output port instance on success, NULL on error. + */ +typedef void * +(*rte_swx_port_out_create_t)(void *args); + +/** + * Output port free + * + * @param[in] args + * Output port handle. + */ +typedef void +(*rte_swx_port_out_free_t)(void *port); + +/** + * Output port packet transmit + * + * @param[in] port + * Output port handle. + * @param[in] pkt + * Packet to be transmitted. + */ +typedef void +(*rte_swx_port_out_pkt_tx_t)(void *port, + struct rte_swx_pkt *pkt); + +/** + * Output port flush + * + * @param[in] port + * Output port handle. + */ +typedef void +(*rte_swx_port_out_flush_t)(void *port); + +/** Output port statistics counters. */ +struct rte_swx_port_out_stats { + /** Number of packets. */ + uint64_t n_pkts; + + /** Number of bytes. */ + uint64_t n_bytes; +}; + +/** + * Output port statistics counters read + * + * @param[in] port + * Output port handle. + * @param[out] stats + * Output port statistics counters. Must point to valid memory. + */ +typedef void +(*rte_swx_port_out_stats_read_t)(void *port, + struct rte_swx_port_out_stats *stats); + +/** Output port operations. */ +struct rte_swx_port_out_ops { + /** Create. Must be non-NULL. */ + rte_swx_port_out_create_t create; + + /** Free. Must be non-NULL. */ + rte_swx_port_out_free_t free; + + /** Packet transmission. Must be non-NULL. */ + rte_swx_port_out_pkt_tx_t pkt_tx; + + /** Flush. May be NULL. */ + rte_swx_port_out_flush_t flush; + + /** Statistics counters read. Must be non-NULL. */ + rte_swx_port_out_stats_read_t stats_read; +}; + #ifdef __cplusplus } #endif -- 2.20.1