From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D0490A04B1; Tue, 8 Sep 2020 22:19:29 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 9818B1C114; Tue, 8 Sep 2020 22:19:01 +0200 (CEST) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 9F4221BF8A for ; Tue, 8 Sep 2020 22:18:54 +0200 (CEST) IronPort-SDR: qEnCt4bSaMg1WupQOBQNbnDv2fugum27rFpsWQ7FhydlqOen7FBM6AfybLB1OISQIn2F0tL8QF uKfr1Sy6i8vg== X-IronPort-AV: E=McAfee;i="6000,8403,9738"; a="145939368" X-IronPort-AV: E=Sophos;i="5.76,407,1592895600"; d="scan'208";a="145939368" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Sep 2020 13:18:36 -0700 IronPort-SDR: sQChWTin4npWgud5Uu+q8nabO2svH2o46DL/3xPmw7QnG3lXPCnrB12DCf63J0zu+sEoeHQ1Ko 6v6o5A0r1e6A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,406,1592895600"; d="scan'208";a="504493368" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by fmsmga006.fm.intel.com with ESMTP; 08 Sep 2020 13:18:35 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Date: Tue, 8 Sep 2020 21:17:53 +0100 Message-Id: <20200908201830.74206-5-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200908201830.74206-1-cristian.dumitrescu@intel.com> References: <20200907214032.95052-2-cristian.dumitrescu@intel.com> <20200908201830.74206-1-cristian.dumitrescu@intel.com> Subject: [dpdk-dev] [PATCH v3 04/41] pipeline: add SWX headers and meta-data X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- lib/librte_pipeline/rte_pipeline_version.map | 3 + lib/librte_pipeline/rte_swx_pipeline.c | 413 +++++++++++++++++++ lib/librte_pipeline/rte_swx_pipeline.h | 85 ++++ 3 files changed, 501 insertions(+) diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 88fd38ca8..6a48c3666 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -60,6 +60,9 @@ EXPERIMENTAL { rte_swx_pipeline_port_in_config; rte_swx_pipeline_port_out_type_register; rte_swx_pipeline_port_out_config; + rte_swx_pipeline_struct_type_register; + rte_swx_pipeline_packet_header_register; + rte_swx_pipeline_packet_metadata_register; rte_swx_pipeline_build; rte_swx_pipeline_free; }; diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index 7aeac8cc8..cb2e32b83 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -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; } diff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h index 2be83bd35..4a7b679a4 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.h +++ b/lib/librte_pipeline/rte_swx_pipeline.h @@ -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 * -- 2.17.1