#define CHECK_NAME(name, err_code) \
CHECK((name) && (name)[0], err_code)
+/*
+ * Struct.
+ */
+struct field {
+ char name[RTE_SWX_NAME_SIZE];
+ uint32_t n_bits;
+ uint32_t offset;
+};
+
+struct struct_type {
+ TAILQ_ENTRY(struct_type) node;
+ char name[RTE_SWX_NAME_SIZE];
+ struct field *fields;
+ uint32_t n_fields;
+ uint32_t n_bits;
+};
+
+TAILQ_HEAD(struct_type_tailq, struct_type);
+
/*
* Input port.
*/
void *obj;
};
+/*
+ * Header.
+ */
+struct header {
+ TAILQ_ENTRY(header) node;
+ char name[RTE_SWX_NAME_SIZE];
+ struct struct_type *st;
+ uint32_t struct_id;
+ uint32_t id;
+};
+
+TAILQ_HEAD(header_tailq, header);
+
+struct header_runtime {
+ uint8_t *ptr0;
+};
+
+struct header_out_runtime {
+ uint8_t *ptr0;
+ uint8_t *ptr;
+ uint32_t n_bytes;
+};
+
/*
* Pipeline.
*/
+struct thread {
+ /* Structures. */
+ uint8_t **structs;
+
+ /* Packet headers. */
+ struct header_runtime *headers; /* Extracted or generated headers. */
+ struct header_out_runtime *headers_out; /* Emitted headers. */
+ uint8_t *header_storage;
+ uint8_t *header_out_storage;
+ uint64_t valid_headers;
+ uint32_t n_headers_out;
+
+ /* Packet meta-data. */
+ uint8_t *metadata;
+};
+
+#ifndef RTE_SWX_PIPELINE_THREADS_MAX
+#define RTE_SWX_PIPELINE_THREADS_MAX 16
+#endif
+
struct rte_swx_pipeline {
+ struct struct_type_tailq struct_types;
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 header_tailq headers;
+ struct struct_type *metadata_st;
+ uint32_t metadata_struct_id;
struct port_in_runtime *in;
struct port_out_runtime *out;
+ struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
+ uint32_t n_structs;
uint32_t n_ports_in;
uint32_t n_ports_out;
+ uint32_t n_headers;
int build_done;
int numa_node;
};
+/*
+ * Struct.
+ */
+static struct struct_type *
+struct_type_find(struct rte_swx_pipeline *p, const char *name)
+{
+ struct struct_type *elem;
+
+ TAILQ_FOREACH(elem, &p->struct_types, node)
+ if (strcmp(elem->name, name) == 0)
+ return elem;
+
+ return NULL;
+}
+
+int
+rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
+ const char *name,
+ struct rte_swx_field_params *fields,
+ uint32_t n_fields)
+{
+ struct struct_type *st;
+ uint32_t i;
+
+ CHECK(p, EINVAL);
+ CHECK_NAME(name, EINVAL);
+ CHECK(fields, EINVAL);
+ CHECK(n_fields, EINVAL);
+
+ for (i = 0; i < n_fields; i++) {
+ struct rte_swx_field_params *f = &fields[i];
+ uint32_t j;
+
+ CHECK_NAME(f->name, EINVAL);
+ CHECK(f->n_bits, EINVAL);
+ CHECK(f->n_bits <= 64, EINVAL);
+ CHECK((f->n_bits & 7) == 0, EINVAL);
+
+ for (j = 0; j < i; j++) {
+ struct rte_swx_field_params *f_prev = &fields[j];
+
+ CHECK(strcmp(f->name, f_prev->name), EINVAL);
+ }
+ }
+
+ CHECK(!struct_type_find(p, name), EEXIST);
+
+ /* Node allocation. */
+ st = calloc(1, sizeof(struct struct_type));
+ CHECK(st, ENOMEM);
+
+ st->fields = calloc(n_fields, sizeof(struct field));
+ if (!st->fields) {
+ free(st);
+ CHECK(0, ENOMEM);
+ }
+
+ /* Node initialization. */
+ strcpy(st->name, name);
+ for (i = 0; i < n_fields; i++) {
+ struct field *dst = &st->fields[i];
+ struct rte_swx_field_params *src = &fields[i];
+
+ strcpy(dst->name, src->name);
+ dst->n_bits = src->n_bits;
+ dst->offset = st->n_bits;
+
+ st->n_bits += src->n_bits;
+ }
+ st->n_fields = n_fields;
+
+ /* Node add to tailq. */
+ TAILQ_INSERT_TAIL(&p->struct_types, st, node);
+
+ return 0;
+}
+
+static int
+struct_build(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ t->structs = calloc(p->n_structs, sizeof(uint8_t *));
+ CHECK(t->structs, ENOMEM);
+ }
+
+ return 0;
+}
+
+static void
+struct_build_free(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ free(t->structs);
+ t->structs = NULL;
+ }
+}
+
+static void
+struct_free(struct rte_swx_pipeline *p)
+{
+ struct_build_free(p);
+
+ /* Struct types. */
+ for ( ; ; ) {
+ struct struct_type *elem;
+
+ elem = TAILQ_FIRST(&p->struct_types);
+ if (!elem)
+ break;
+
+ TAILQ_REMOVE(&p->struct_types, elem, node);
+ free(elem->fields);
+ free(elem);
+ }
+}
+
/*
* Input port.
*/
}
}
+/*
+ * Header.
+ */
+static struct header *
+header_find(struct rte_swx_pipeline *p, const char *name)
+{
+ struct header *elem;
+
+ TAILQ_FOREACH(elem, &p->headers, node)
+ if (strcmp(elem->name, name) == 0)
+ return elem;
+
+ return NULL;
+}
+
+int
+rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
+ const char *name,
+ const char *struct_type_name)
+{
+ struct struct_type *st;
+ struct header *h;
+ size_t n_headers_max;
+
+ CHECK(p, EINVAL);
+ CHECK_NAME(name, EINVAL);
+ CHECK_NAME(struct_type_name, EINVAL);
+
+ CHECK(!header_find(p, name), EEXIST);
+
+ st = struct_type_find(p, struct_type_name);
+ CHECK(st, EINVAL);
+
+ n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
+ CHECK(p->n_headers < n_headers_max, ENOSPC);
+
+ /* Node allocation. */
+ h = calloc(1, sizeof(struct header));
+ CHECK(h, ENOMEM);
+
+ /* Node initialization. */
+ strcpy(h->name, name);
+ h->st = st;
+ h->struct_id = p->n_structs;
+ h->id = p->n_headers;
+
+ /* Node add to tailq. */
+ TAILQ_INSERT_TAIL(&p->headers, h, node);
+ p->n_headers++;
+ p->n_structs++;
+
+ return 0;
+}
+
+static int
+header_build(struct rte_swx_pipeline *p)
+{
+ struct header *h;
+ uint32_t n_bytes = 0, i;
+
+ TAILQ_FOREACH(h, &p->headers, node) {
+ n_bytes += h->st->n_bits / 8;
+ }
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+ uint32_t offset = 0;
+
+ t->headers = calloc(p->n_headers,
+ sizeof(struct header_runtime));
+ CHECK(t->headers, ENOMEM);
+
+ t->headers_out = calloc(p->n_headers,
+ sizeof(struct header_out_runtime));
+ CHECK(t->headers_out, ENOMEM);
+
+ t->header_storage = calloc(1, n_bytes);
+ CHECK(t->header_storage, ENOMEM);
+
+ t->header_out_storage = calloc(1, n_bytes);
+ CHECK(t->header_out_storage, ENOMEM);
+
+ TAILQ_FOREACH(h, &p->headers, node) {
+ uint8_t *header_storage;
+
+ header_storage = &t->header_storage[offset];
+ offset += h->st->n_bits / 8;
+
+ t->headers[h->id].ptr0 = header_storage;
+ t->structs[h->struct_id] = header_storage;
+ }
+ }
+
+ return 0;
+}
+
+static void
+header_build_free(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ free(t->headers_out);
+ t->headers_out = NULL;
+
+ free(t->headers);
+ t->headers = NULL;
+
+ free(t->header_out_storage);
+ t->header_out_storage = NULL;
+
+ free(t->header_storage);
+ t->header_storage = NULL;
+ }
+}
+
+static void
+header_free(struct rte_swx_pipeline *p)
+{
+ header_build_free(p);
+
+ for ( ; ; ) {
+ struct header *elem;
+
+ elem = TAILQ_FIRST(&p->headers);
+ if (!elem)
+ break;
+
+ TAILQ_REMOVE(&p->headers, elem, node);
+ free(elem);
+ }
+}
+
+/*
+ * Meta-data.
+ */
+int
+rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
+ const char *struct_type_name)
+{
+ struct struct_type *st = NULL;
+
+ CHECK(p, EINVAL);
+
+ CHECK_NAME(struct_type_name, EINVAL);
+ st = struct_type_find(p, struct_type_name);
+ CHECK(st, EINVAL);
+ CHECK(!p->metadata_st, EINVAL);
+
+ p->metadata_st = st;
+ p->metadata_struct_id = p->n_structs;
+
+ p->n_structs++;
+
+ return 0;
+}
+
+static int
+metadata_build(struct rte_swx_pipeline *p)
+{
+ uint32_t n_bytes = p->metadata_st->n_bits / 8;
+ uint32_t i;
+
+ /* Thread-level initialization. */
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+ uint8_t *metadata;
+
+ metadata = calloc(1, n_bytes);
+ CHECK(metadata, ENOMEM);
+
+ t->metadata = metadata;
+ t->structs[p->metadata_struct_id] = metadata;
+ }
+
+ return 0;
+}
+
+static void
+metadata_build_free(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ free(t->metadata);
+ t->metadata = NULL;
+ }
+}
+
+static void
+metadata_free(struct rte_swx_pipeline *p)
+{
+ metadata_build_free(p);
+}
+
/*
* Pipeline.
*/
CHECK(pipeline, ENOMEM);
/* Initialization. */
+ TAILQ_INIT(&pipeline->struct_types);
TAILQ_INIT(&pipeline->port_in_types);
TAILQ_INIT(&pipeline->ports_in);
TAILQ_INIT(&pipeline->port_out_types);
TAILQ_INIT(&pipeline->ports_out);
+ TAILQ_INIT(&pipeline->headers);
+ pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
pipeline->numa_node = numa_node;
*p = pipeline;
if (!p)
return;
+ metadata_free(p);
+ header_free(p);
port_out_free(p);
port_in_free(p);
+ struct_free(p);
free(p);
}
if (status)
goto error;
+ status = struct_build(p);
+ if (status)
+ goto error;
+
+ status = header_build(p);
+ if (status)
+ goto error;
+
+ status = metadata_build(p);
+ if (status)
+ goto error;
+
p->build_done = 1;
return 0;
error:
+ metadata_build_free(p);
+ header_build_free(p);
port_out_build_free(p);
port_in_build_free(p);
+ struct_build_free(p);
return status;
}
const char *port_type_name,
void *args);
+/*
+ * Packet headers and meta-data
+ */
+
+/** Structure (struct) field. */
+struct rte_swx_field_params {
+ /** Struct field name. */
+ const char *name;
+
+ /** Struct field size (in bits).
+ * Restriction: All struct fields must be a multiple of 8 bits.
+ * Restriction: All struct fields must be no greater than 64 bits.
+ */
+ uint32_t n_bits;
+};
+
+/**
+ * Pipeline struct type register
+ *
+ * Structs are used extensively in many part of the pipeline to define the size
+ * and layout of a specific memory piece such as: headers, meta-data, action
+ * data stored in a table entry, mailboxes for extern objects and functions.
+ * Similar to C language structs, they are a well defined sequence of fields,
+ * with each field having a unique name and a constant size.
+ *
+ * @param[in] p
+ * Pipeline handle.
+ * @param[in] name
+ * Struct type name.
+ * @param[in] fields
+ * The sequence of struct fields.
+ * @param[in] n_fields
+ * The number of struct fields.
+ * @return
+ * 0 on success or the following error codes otherwise:
+ * -EINVAL: Invalid argument;
+ * -ENOMEM: Not enough space/cannot allocate memory;
+ * -EEXIST: Struct type with this name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
+ const char *name,
+ struct rte_swx_field_params *fields,
+ uint32_t n_fields);
+
+/**
+ * Pipeline packet header register
+ *
+ * @param[in] p
+ * Pipeline handle.
+ * @param[in] name
+ * Header name.
+ * @param[in] struct_type_name
+ * The struct type instantiated by this packet header.
+ * @return
+ * 0 on success or the following error codes otherwise:
+ * -EINVAL: Invalid argument;
+ * -ENOMEM: Not enough space/cannot allocate memory;
+ * -EEXIST: Header with this name already exists;
+ * -ENOSPC: Maximum number of headers reached for the pipeline.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
+ const char *name,
+ const char *struct_type_name);
+
+/**
+ * Pipeline packet meta-data register
+ *
+ * @param[in] p
+ * Pipeline handle.
+ * @param[in] struct_type_name
+ * The struct type instantiated by the packet meta-data.
+ * @return
+ * 0 on success or the following error codes otherwise:
+ * -EINVAL: Invalid argument.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
+ const char *struct_type_name);
+
+
/**
* Pipeline build
*