pipeline: add SWX headers and meta-data
Add support for dynamically-defined packet headers and meta-data to the SWX pipeline. The header and meta-data format are defined by the struct type they instantiate. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
parent
99a0ba8f4c
commit
e719fe9e95
@ -63,8 +63,11 @@ EXPERIMENTAL {
|
||||
rte_swx_pipeline_build;
|
||||
rte_swx_pipeline_config;
|
||||
rte_swx_pipeline_free;
|
||||
rte_swx_pipeline_packet_header_register;
|
||||
rte_swx_pipeline_packet_metadata_register;
|
||||
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;
|
||||
rte_swx_pipeline_struct_type_register;
|
||||
};
|
||||
|
@ -20,6 +20,25 @@ do { \
|
||||
#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.
|
||||
*/
|
||||
@ -71,24 +90,198 @@ struct port_out_runtime {
|
||||
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.
|
||||
*/
|
||||
@ -413,6 +606,205 @@ port_out_free(struct rte_swx_pipeline *p)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -429,11 +821,14 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
|
||||
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;
|
||||
@ -446,8 +841,11 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
metadata_free(p);
|
||||
header_free(p);
|
||||
port_out_free(p);
|
||||
port_in_free(p);
|
||||
struct_free(p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
@ -468,12 +866,27 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *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;
|
||||
}
|
||||
|
@ -147,6 +147,91 @@ rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
|
||||
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
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user