Add extern objects and functions to plug into the SWX pipeline any functionality that cannot be efficiently implemented with existing instructions, e.g. special checksum/ECC, crypto, meters, stats arrays, heuristics, etc. In/out arguments are passed through mailbox with format defined by struct.
Signed-off-by: Cristian Dumitrescu <cristian.dumitre...@intel.com> --- lib/librte_pipeline/meson.build | 3 +- lib/librte_pipeline/rte_pipeline_version.map | 4 + lib/librte_pipeline/rte_swx_extern.h | 98 ++++ lib/librte_pipeline/rte_swx_pipeline.c | 477 +++++++++++++++++++ lib/librte_pipeline/rte_swx_pipeline.h | 113 +++++ 5 files changed, 694 insertions(+), 1 deletion(-) create mode 100644 lib/librte_pipeline/rte_swx_extern.h diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build index 880c2b274..bea406848 100644 --- a/lib/librte_pipeline/meson.build +++ b/lib/librte_pipeline/meson.build @@ -8,5 +8,6 @@ sources = files('rte_pipeline.c', headers = files('rte_pipeline.h', 'rte_port_in_action.h', 'rte_table_action.h', - 'rte_swx_pipeline.h',) + 'rte_swx_pipeline.h', + 'rte_swx_extern.h',) deps += ['port', 'table', 'meter', 'sched', 'cryptodev'] diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 6a48c3666..4297e185d 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -60,6 +60,10 @@ EXPERIMENTAL { rte_swx_pipeline_port_in_config; rte_swx_pipeline_port_out_type_register; rte_swx_pipeline_port_out_config; + rte_swx_pipeline_extern_type_register; + rte_swx_pipeline_extern_type_member_func_register; + rte_swx_pipeline_extern_object_config; + rte_swx_pipeline_extern_func_register; rte_swx_pipeline_struct_type_register; rte_swx_pipeline_packet_header_register; rte_swx_pipeline_packet_metadata_register; diff --git a/lib/librte_pipeline/rte_swx_extern.h b/lib/librte_pipeline/rte_swx_extern.h new file mode 100644 index 000000000..e10e963d6 --- /dev/null +++ b/lib/librte_pipeline/rte_swx_extern.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ +#ifndef __INCLUDE_RTE_SWX_EXTERN_H__ +#define __INCLUDE_RTE_SWX_EXTERN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * RTE SWX Extern objects and functions + * + * Extern object and extern function interfaces. The extern objects and extern + * functions provide the mechanisms to hook external functionality into the + * packet processing pipeline. + */ + +#include <stdint.h> + +/* + * Extern type + */ + +/** + * Extern object constructor + * + * @param[in] args + * Extern object constructor arguments. It may be NULL. + * @return + * Extern object handle. + */ +typedef void * +(*rte_swx_extern_type_constructor_t)(const char *args); + +/** + * Extern object destructor + * + * @param[in] object + * Extern object handle. + */ +typedef void +(*rte_swx_extern_type_destructor_t)(void *object); + +/** + * Extern object member function + * + * The mailbox is used to pass input arguments to the member function and + * retrieve the output results. The mailbox mechanism allows for multiple + * concurrent executions of the same member function for the same extern object. + * + * Multiple invocations of the same member function may be required in order for + * the associated operation to complete. The completion is flagged by a return + * value of 1, in which case the results are available in the mailbox; in case + * of a return value of 0, the operation is not yet completed, so the member + * function must be invoked again with exactly the same object and mailbox + * arguments. + * + * @param[in] object + * Extern object handle. + * @param[in] mailbox + * Extern object mailbox. + * @return + * 0 when the operation is not yet completed, and 1 when the operation is + * completed. No other return values are allowed. + */ +typedef int +(*rte_swx_extern_type_member_func_t)(void *object, void *mailbox); + +/* + * Extern function + */ + +/** The mailbox is used to pass input arguments to the extern function and + * retrieve the output results. The mailbox mechanism allows for multiple + * concurrent executions of the same extern function. + * + * Multiple invocations of the same extern function may be required in order for + * the associated operation to complete. The completion is flagged by a return + * value of 1, in which case the results are available in the mailbox; in case + * of a return value of 0, the operation is not yet completed, so the extern + * function must be invoked again with exactly the same mailbox argument. + * + * @param[in] mailbox + * Extern object mailbox. + * @return + * 0 when the operation is not yet completed, and 1 when the operation is + * completed. No other return values are allowed. + */ +typedef int +(*rte_swx_extern_func_t)(void *mailbox); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index cb2e32b83..2335831bf 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -90,6 +90,70 @@ struct port_out_runtime { void *obj; }; +/* + * Extern object. + */ +struct extern_type_member_func { + TAILQ_ENTRY(extern_type_member_func) node; + char name[RTE_SWX_NAME_SIZE]; + rte_swx_extern_type_member_func_t func; + uint32_t id; +}; + +TAILQ_HEAD(extern_type_member_func_tailq, extern_type_member_func); + +struct extern_type { + TAILQ_ENTRY(extern_type) node; + char name[RTE_SWX_NAME_SIZE]; + struct struct_type *mailbox_struct_type; + rte_swx_extern_type_constructor_t constructor; + rte_swx_extern_type_destructor_t destructor; + struct extern_type_member_func_tailq funcs; + uint32_t n_funcs; +}; + +TAILQ_HEAD(extern_type_tailq, extern_type); + +struct extern_obj { + TAILQ_ENTRY(extern_obj) node; + char name[RTE_SWX_NAME_SIZE]; + struct extern_type *type; + void *obj; + uint32_t struct_id; + uint32_t id; +}; + +TAILQ_HEAD(extern_obj_tailq, extern_obj); + +#ifndef RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX +#define RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX 8 +#endif + +struct extern_obj_runtime { + void *obj; + uint8_t *mailbox; + rte_swx_extern_type_member_func_t funcs[RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX]; +}; + +/* + * Extern function. + */ +struct extern_func { + TAILQ_ENTRY(extern_func) node; + char name[RTE_SWX_NAME_SIZE]; + struct struct_type *mailbox_struct_type; + rte_swx_extern_func_t func; + uint32_t struct_id; + uint32_t id; +}; + +TAILQ_HEAD(extern_func_tailq, extern_func); + +struct extern_func_runtime { + uint8_t *mailbox; + rte_swx_extern_func_t func; +}; + /* * Header. */ @@ -130,6 +194,10 @@ struct thread { /* Packet meta-data. */ uint8_t *metadata; + + /* Extern objects and functions. */ + struct extern_obj_runtime *extern_objs; + struct extern_func_runtime *extern_funcs; }; #ifndef RTE_SWX_PIPELINE_THREADS_MAX @@ -142,6 +210,9 @@ struct rte_swx_pipeline { struct port_in_tailq ports_in; struct port_out_type_tailq port_out_types; struct port_out_tailq ports_out; + struct extern_type_tailq extern_types; + struct extern_obj_tailq extern_objs; + struct extern_func_tailq extern_funcs; struct header_tailq headers; struct struct_type *metadata_st; uint32_t metadata_struct_id; @@ -153,6 +224,8 @@ struct rte_swx_pipeline { uint32_t n_structs; uint32_t n_ports_in; uint32_t n_ports_out; + uint32_t n_extern_objs; + uint32_t n_extern_funcs; uint32_t n_headers; int build_done; int numa_node; @@ -606,6 +679,395 @@ port_out_free(struct rte_swx_pipeline *p) } } +/* + * Extern object. + */ +static struct extern_type * +extern_type_find(struct rte_swx_pipeline *p, const char *name) +{ + struct extern_type *elem; + + TAILQ_FOREACH(elem, &p->extern_types, node) + if (strcmp(elem->name, name) == 0) + return elem; + + return NULL; +} + +static struct extern_type_member_func * +extern_type_member_func_find(struct extern_type *type, const char *name) +{ + struct extern_type_member_func *elem; + + TAILQ_FOREACH(elem, &type->funcs, node) + if (strcmp(elem->name, name) == 0) + return elem; + + return NULL; +} + +static struct extern_obj * +extern_obj_find(struct rte_swx_pipeline *p, const char *name) +{ + struct extern_obj *elem; + + TAILQ_FOREACH(elem, &p->extern_objs, node) + if (strcmp(elem->name, name) == 0) + return elem; + + return NULL; +} + +int +rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p, + const char *name, + const char *mailbox_struct_type_name, + rte_swx_extern_type_constructor_t constructor, + rte_swx_extern_type_destructor_t destructor) +{ + struct extern_type *elem; + struct struct_type *mailbox_struct_type; + + CHECK(p, EINVAL); + + CHECK_NAME(name, EINVAL); + CHECK(!extern_type_find(p, name), EEXIST); + + CHECK_NAME(mailbox_struct_type_name, EINVAL); + mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name); + CHECK(mailbox_struct_type, EINVAL); + + CHECK(constructor, EINVAL); + CHECK(destructor, EINVAL); + + /* Node allocation. */ + elem = calloc(1, sizeof(struct extern_type)); + CHECK(elem, ENOMEM); + + /* Node initialization. */ + strcpy(elem->name, name); + elem->mailbox_struct_type = mailbox_struct_type; + elem->constructor = constructor; + elem->destructor = destructor; + TAILQ_INIT(&elem->funcs); + + /* Node add to tailq. */ + TAILQ_INSERT_TAIL(&p->extern_types, elem, node); + + return 0; +} + +int +rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p, + const char *extern_type_name, + const char *name, + rte_swx_extern_type_member_func_t member_func) +{ + struct extern_type *type; + struct extern_type_member_func *type_member; + + CHECK(p, EINVAL); + + CHECK(extern_type_name, EINVAL); + type = extern_type_find(p, extern_type_name); + CHECK(type, EINVAL); + CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC); + + CHECK(name, EINVAL); + CHECK(!extern_type_member_func_find(type, name), EEXIST); + + CHECK(member_func, EINVAL); + + /* Node allocation. */ + type_member = calloc(1, sizeof(struct extern_type_member_func)); + CHECK(type_member, ENOMEM); + + /* Node initialization. */ + strcpy(type_member->name, name); + type_member->func = member_func; + type_member->id = type->n_funcs; + + /* Node add to tailq. */ + TAILQ_INSERT_TAIL(&type->funcs, type_member, node); + type->n_funcs++; + + return 0; +} + +int +rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p, + const char *extern_type_name, + const char *name, + const char *args) +{ + struct extern_type *type; + struct extern_obj *obj; + void *obj_handle; + + CHECK(p, EINVAL); + + CHECK_NAME(extern_type_name, EINVAL); + type = extern_type_find(p, extern_type_name); + CHECK(type, EINVAL); + + CHECK_NAME(name, EINVAL); + CHECK(!extern_obj_find(p, name), EEXIST); + + /* Node allocation. */ + obj = calloc(1, sizeof(struct extern_obj)); + CHECK(obj, ENOMEM); + + /* Object construction. */ + obj_handle = type->constructor(args); + if (!obj_handle) { + free(obj); + CHECK(0, ENODEV); + } + + /* Node initialization. */ + strcpy(obj->name, name); + obj->type = type; + obj->obj = obj_handle; + obj->struct_id = p->n_structs; + obj->id = p->n_extern_objs; + + /* Node add to tailq. */ + TAILQ_INSERT_TAIL(&p->extern_objs, obj, node); + p->n_extern_objs++; + p->n_structs++; + + return 0; +} + +static int +extern_obj_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]; + struct extern_obj *obj; + + t->extern_objs = calloc(p->n_extern_objs, + sizeof(struct extern_obj_runtime)); + CHECK(t->extern_objs, ENOMEM); + + TAILQ_FOREACH(obj, &p->extern_objs, node) { + struct extern_obj_runtime *r = + &t->extern_objs[obj->id]; + struct extern_type_member_func *func; + uint32_t mailbox_size = + obj->type->mailbox_struct_type->n_bits / 8; + + r->obj = obj->obj; + + r->mailbox = calloc(1, mailbox_size); + CHECK(r->mailbox, ENOMEM); + + TAILQ_FOREACH(func, &obj->type->funcs, node) + r->funcs[func->id] = func->func; + + t->structs[obj->struct_id] = r->mailbox; + } + } + + return 0; +} + +static void +extern_obj_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]; + uint32_t j; + + if (!t->extern_objs) + continue; + + for (j = 0; j < p->n_extern_objs; j++) { + struct extern_obj_runtime *r = &t->extern_objs[j]; + + free(r->mailbox); + } + + free(t->extern_objs); + t->extern_objs = NULL; + } +} + +static void +extern_obj_free(struct rte_swx_pipeline *p) +{ + extern_obj_build_free(p); + + /* Extern objects. */ + for ( ; ; ) { + struct extern_obj *elem; + + elem = TAILQ_FIRST(&p->extern_objs); + if (!elem) + break; + + TAILQ_REMOVE(&p->extern_objs, elem, node); + if (elem->obj) + elem->type->destructor(elem->obj); + free(elem); + } + + /* Extern types. */ + for ( ; ; ) { + struct extern_type *elem; + + elem = TAILQ_FIRST(&p->extern_types); + if (!elem) + break; + + TAILQ_REMOVE(&p->extern_types, elem, node); + + for ( ; ; ) { + struct extern_type_member_func *func; + + func = TAILQ_FIRST(&elem->funcs); + if (!func) + break; + + TAILQ_REMOVE(&elem->funcs, func, node); + free(func); + } + + free(elem); + } +} + +/* + * Extern function. + */ +static struct extern_func * +extern_func_find(struct rte_swx_pipeline *p, const char *name) +{ + struct extern_func *elem; + + TAILQ_FOREACH(elem, &p->extern_funcs, node) + if (strcmp(elem->name, name) == 0) + return elem; + + return NULL; +} + +int +rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p, + const char *name, + const char *mailbox_struct_type_name, + rte_swx_extern_func_t func) +{ + struct extern_func *f; + struct struct_type *mailbox_struct_type; + + CHECK(p, EINVAL); + + CHECK_NAME(name, EINVAL); + CHECK(!extern_func_find(p, name), EEXIST); + + CHECK_NAME(mailbox_struct_type_name, EINVAL); + mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name); + CHECK(mailbox_struct_type, EINVAL); + + CHECK(func, EINVAL); + + /* Node allocation. */ + f = calloc(1, sizeof(struct extern_func)); + CHECK(func, ENOMEM); + + /* Node initialization. */ + strcpy(f->name, name); + f->mailbox_struct_type = mailbox_struct_type; + f->func = func; + f->struct_id = p->n_structs; + f->id = p->n_extern_funcs; + + /* Node add to tailq. */ + TAILQ_INSERT_TAIL(&p->extern_funcs, f, node); + p->n_extern_funcs++; + p->n_structs++; + + return 0; +} + +static int +extern_func_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]; + struct extern_func *func; + + /* Memory allocation. */ + t->extern_funcs = calloc(p->n_extern_funcs, + sizeof(struct extern_func_runtime)); + CHECK(t->extern_funcs, ENOMEM); + + /* Extern function. */ + TAILQ_FOREACH(func, &p->extern_funcs, node) { + struct extern_func_runtime *r = + &t->extern_funcs[func->id]; + uint32_t mailbox_size = + func->mailbox_struct_type->n_bits / 8; + + r->func = func->func; + + r->mailbox = calloc(1, mailbox_size); + CHECK(r->mailbox, ENOMEM); + + t->structs[func->struct_id] = r->mailbox; + } + } + + return 0; +} + +static void +extern_func_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]; + uint32_t j; + + if (!t->extern_funcs) + continue; + + for (j = 0; j < p->n_extern_funcs; j++) { + struct extern_func_runtime *r = &t->extern_funcs[j]; + + free(r->mailbox); + } + + free(t->extern_funcs); + t->extern_funcs = NULL; + } +} + +static void +extern_func_free(struct rte_swx_pipeline *p) +{ + extern_func_build_free(p); + + for ( ; ; ) { + struct extern_func *elem; + + elem = TAILQ_FIRST(&p->extern_funcs); + if (!elem) + break; + + TAILQ_REMOVE(&p->extern_funcs, elem, node); + free(elem); + } +} + /* * Header. */ @@ -826,6 +1288,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) TAILQ_INIT(&pipeline->ports_in); TAILQ_INIT(&pipeline->port_out_types); TAILQ_INIT(&pipeline->ports_out); + TAILQ_INIT(&pipeline->extern_types); + TAILQ_INIT(&pipeline->extern_objs); + TAILQ_INIT(&pipeline->extern_funcs); TAILQ_INIT(&pipeline->headers); pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */ @@ -843,6 +1308,8 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p) metadata_free(p); header_free(p); + extern_func_free(p); + extern_obj_free(p); port_out_free(p); port_in_free(p); struct_free(p); @@ -870,6 +1337,14 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) if (status) goto error; + status = extern_obj_build(p); + if (status) + goto error; + + status = extern_func_build(p); + if (status) + goto error; + status = header_build(p); if (status) goto error; @@ -884,6 +1359,8 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) error: metadata_build_free(p); header_build_free(p); + extern_func_build_free(p); + extern_obj_build_free(p); port_out_build_free(p); port_in_build_free(p); struct_build_free(p); diff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h index 4a7b679a4..2e8a6cdf8 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.h +++ b/lib/librte_pipeline/rte_swx_pipeline.h @@ -19,6 +19,7 @@ extern "C" { #include <rte_compat.h> #include "rte_swx_port.h" +#include "rte_swx_extern.h" /** Name size. */ #ifndef RTE_SWX_NAME_SIZE @@ -147,6 +148,118 @@ rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p, const char *port_type_name, void *args); +/* + * Extern objects and functions + */ + +/** + * Pipeline extern type register + * + * @param[in] p + * Pipeline handle. + * @param[in] name + * Extern type name. + * @param[in] mailbox_struct_type_name + * Name of existing struct type used to define the mailbox size and layout for + * the extern objects that are instances of this type. Each extern object gets + * its own mailbox, which is used to pass the input arguments to the member + * functions and retrieve the output results. + * @param[in] constructor + * Function used to create the extern objects that are instances of this type. + * @param[in] destructor + * Function used to free the extern objects that are instances of this type. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -EEXIST: Extern type with this name already exists. + */ +__rte_experimental +int +rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p, + const char *name, + const char *mailbox_struct_type_name, + rte_swx_extern_type_constructor_t constructor, + rte_swx_extern_type_destructor_t destructor); + +/** + * Pipeline extern type member function register + * + * @param[in] p + * Pipeline handle. + * @param[in] extern_type_name + * Existing extern type name. + * @param[in] name + * Name for the new member function to be added to the extern type. + * @param[in] member_func + * The new member function. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -EEXIST: Member function with this name already exists for this type; + * -ENOSPC: Maximum number of member functions reached for this type. + */ +__rte_experimental +int +rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p, + const char *extern_type_name, + const char *name, + rte_swx_extern_type_member_func_t member_func); + +/** + * Pipeline extern object configure + * + * Instantiate a given extern type to create new extern object. + * + * @param[in] p + * Pipeline handle. + * @param[in] extern_type_name + * Existing extern type name. + * @param[in] name + * Name for the new object instantiating the extern type. + * @param[in] args + * Extern object constructor arguments. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -EEXIST: Extern object with this name already exists; + * -ENODEV: Extern object constructor error. + */ +__rte_experimental +int +rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p, + const char *extern_type_name, + const char *name, + const char *args); + +/** + * Pipeline extern function register + * + * @param[in] p + * Pipeline handle. + * @param[in] name + * Extern function name. + * @param[in] mailbox_struct_type_name + * Name of existing struct type used to define the mailbox size and layout for + * this extern function. The mailbox is used to pass the input arguments to + * the extern function and retrieve the output results. + * @param[in] func + * The extern function. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough space/cannot allocate memory; + * -EEXIST: Extern function with this name already exists. + */ +__rte_experimental +int +rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p, + const char *name, + const char *mailbox_struct_type_name, + rte_swx_extern_func_t func); + /* * Packet headers and meta-data */ -- 2.17.1