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;
};
}
}
+/*
+ * 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.
*/
/* 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;
if (!p)
return;
+ port_out_free(p);
port_in_free(p);
free(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;
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
*
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