1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
10 #include <rte_common.h>
12 #include "rte_swx_pipeline.h"
14 #define CHECK(condition, err_code) \
20 #define CHECK_NAME(name, err_code) \
21 CHECK((name) && (name)[0], err_code)
27 char name[RTE_SWX_NAME_SIZE];
33 TAILQ_ENTRY(struct_type) node;
34 char name[RTE_SWX_NAME_SIZE];
40 TAILQ_HEAD(struct_type_tailq, struct_type);
46 TAILQ_ENTRY(port_in_type) node;
47 char name[RTE_SWX_NAME_SIZE];
48 struct rte_swx_port_in_ops ops;
51 TAILQ_HEAD(port_in_type_tailq, port_in_type);
54 TAILQ_ENTRY(port_in) node;
55 struct port_in_type *type;
60 TAILQ_HEAD(port_in_tailq, port_in);
62 struct port_in_runtime {
63 rte_swx_port_in_pkt_rx_t pkt_rx;
70 struct port_out_type {
71 TAILQ_ENTRY(port_out_type) node;
72 char name[RTE_SWX_NAME_SIZE];
73 struct rte_swx_port_out_ops ops;
76 TAILQ_HEAD(port_out_type_tailq, port_out_type);
79 TAILQ_ENTRY(port_out) node;
80 struct port_out_type *type;
85 TAILQ_HEAD(port_out_tailq, port_out);
87 struct port_out_runtime {
88 rte_swx_port_out_pkt_tx_t pkt_tx;
89 rte_swx_port_out_flush_t flush;
97 TAILQ_ENTRY(header) node;
98 char name[RTE_SWX_NAME_SIZE];
99 struct struct_type *st;
104 TAILQ_HEAD(header_tailq, header);
106 struct header_runtime {
110 struct header_out_runtime {
123 /* Packet headers. */
124 struct header_runtime *headers; /* Extracted or generated headers. */
125 struct header_out_runtime *headers_out; /* Emitted headers. */
126 uint8_t *header_storage;
127 uint8_t *header_out_storage;
128 uint64_t valid_headers;
129 uint32_t n_headers_out;
131 /* Packet meta-data. */
135 #ifndef RTE_SWX_PIPELINE_THREADS_MAX
136 #define RTE_SWX_PIPELINE_THREADS_MAX 16
139 struct rte_swx_pipeline {
140 struct struct_type_tailq struct_types;
141 struct port_in_type_tailq port_in_types;
142 struct port_in_tailq ports_in;
143 struct port_out_type_tailq port_out_types;
144 struct port_out_tailq ports_out;
145 struct header_tailq headers;
146 struct struct_type *metadata_st;
147 uint32_t metadata_struct_id;
149 struct port_in_runtime *in;
150 struct port_out_runtime *out;
151 struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
155 uint32_t n_ports_out;
164 static struct struct_type *
165 struct_type_find(struct rte_swx_pipeline *p, const char *name)
167 struct struct_type *elem;
169 TAILQ_FOREACH(elem, &p->struct_types, node)
170 if (strcmp(elem->name, name) == 0)
177 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
179 struct rte_swx_field_params *fields,
182 struct struct_type *st;
186 CHECK_NAME(name, EINVAL);
187 CHECK(fields, EINVAL);
188 CHECK(n_fields, EINVAL);
190 for (i = 0; i < n_fields; i++) {
191 struct rte_swx_field_params *f = &fields[i];
194 CHECK_NAME(f->name, EINVAL);
195 CHECK(f->n_bits, EINVAL);
196 CHECK(f->n_bits <= 64, EINVAL);
197 CHECK((f->n_bits & 7) == 0, EINVAL);
199 for (j = 0; j < i; j++) {
200 struct rte_swx_field_params *f_prev = &fields[j];
202 CHECK(strcmp(f->name, f_prev->name), EINVAL);
206 CHECK(!struct_type_find(p, name), EEXIST);
208 /* Node allocation. */
209 st = calloc(1, sizeof(struct struct_type));
212 st->fields = calloc(n_fields, sizeof(struct field));
218 /* Node initialization. */
219 strcpy(st->name, name);
220 for (i = 0; i < n_fields; i++) {
221 struct field *dst = &st->fields[i];
222 struct rte_swx_field_params *src = &fields[i];
224 strcpy(dst->name, src->name);
225 dst->n_bits = src->n_bits;
226 dst->offset = st->n_bits;
228 st->n_bits += src->n_bits;
230 st->n_fields = n_fields;
232 /* Node add to tailq. */
233 TAILQ_INSERT_TAIL(&p->struct_types, st, node);
239 struct_build(struct rte_swx_pipeline *p)
243 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
244 struct thread *t = &p->threads[i];
246 t->structs = calloc(p->n_structs, sizeof(uint8_t *));
247 CHECK(t->structs, ENOMEM);
254 struct_build_free(struct rte_swx_pipeline *p)
258 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
259 struct thread *t = &p->threads[i];
267 struct_free(struct rte_swx_pipeline *p)
269 struct_build_free(p);
273 struct struct_type *elem;
275 elem = TAILQ_FIRST(&p->struct_types);
279 TAILQ_REMOVE(&p->struct_types, elem, node);
288 static struct port_in_type *
289 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
291 struct port_in_type *elem;
296 TAILQ_FOREACH(elem, &p->port_in_types, node)
297 if (strcmp(elem->name, name) == 0)
304 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
306 struct rte_swx_port_in_ops *ops)
308 struct port_in_type *elem;
311 CHECK_NAME(name, EINVAL);
313 CHECK(ops->create, EINVAL);
314 CHECK(ops->free, EINVAL);
315 CHECK(ops->pkt_rx, EINVAL);
316 CHECK(ops->stats_read, EINVAL);
318 CHECK(!port_in_type_find(p, name), EEXIST);
320 /* Node allocation. */
321 elem = calloc(1, sizeof(struct port_in_type));
324 /* Node initialization. */
325 strcpy(elem->name, name);
326 memcpy(&elem->ops, ops, sizeof(*ops));
328 /* Node add to tailq. */
329 TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
334 static struct port_in *
335 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
337 struct port_in *port;
339 TAILQ_FOREACH(port, &p->ports_in, node)
340 if (port->id == port_id)
347 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
349 const char *port_type_name,
352 struct port_in_type *type = NULL;
353 struct port_in *port = NULL;
358 CHECK(!port_in_find(p, port_id), EINVAL);
360 CHECK_NAME(port_type_name, EINVAL);
361 type = port_in_type_find(p, port_type_name);
364 obj = type->ops.create(args);
367 /* Node allocation. */
368 port = calloc(1, sizeof(struct port_in));
371 /* Node initialization. */
376 /* Node add to tailq. */
377 TAILQ_INSERT_TAIL(&p->ports_in, port, node);
378 if (p->n_ports_in < port_id + 1)
379 p->n_ports_in = port_id + 1;
385 port_in_build(struct rte_swx_pipeline *p)
387 struct port_in *port;
390 CHECK(p->n_ports_in, EINVAL);
391 CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
393 for (i = 0; i < p->n_ports_in; i++)
394 CHECK(port_in_find(p, i), EINVAL);
396 p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
397 CHECK(p->in, ENOMEM);
399 TAILQ_FOREACH(port, &p->ports_in, node) {
400 struct port_in_runtime *in = &p->in[port->id];
402 in->pkt_rx = port->type->ops.pkt_rx;
410 port_in_build_free(struct rte_swx_pipeline *p)
417 port_in_free(struct rte_swx_pipeline *p)
419 port_in_build_free(p);
423 struct port_in *port;
425 port = TAILQ_FIRST(&p->ports_in);
429 TAILQ_REMOVE(&p->ports_in, port, node);
430 port->type->ops.free(port->obj);
434 /* Input port types. */
436 struct port_in_type *elem;
438 elem = TAILQ_FIRST(&p->port_in_types);
442 TAILQ_REMOVE(&p->port_in_types, elem, node);
450 static struct port_out_type *
451 port_out_type_find(struct rte_swx_pipeline *p, const char *name)
453 struct port_out_type *elem;
458 TAILQ_FOREACH(elem, &p->port_out_types, node)
459 if (!strcmp(elem->name, name))
466 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
468 struct rte_swx_port_out_ops *ops)
470 struct port_out_type *elem;
473 CHECK_NAME(name, EINVAL);
475 CHECK(ops->create, EINVAL);
476 CHECK(ops->free, EINVAL);
477 CHECK(ops->pkt_tx, EINVAL);
478 CHECK(ops->stats_read, EINVAL);
480 CHECK(!port_out_type_find(p, name), EEXIST);
482 /* Node allocation. */
483 elem = calloc(1, sizeof(struct port_out_type));
486 /* Node initialization. */
487 strcpy(elem->name, name);
488 memcpy(&elem->ops, ops, sizeof(*ops));
490 /* Node add to tailq. */
491 TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
496 static struct port_out *
497 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
499 struct port_out *port;
501 TAILQ_FOREACH(port, &p->ports_out, node)
502 if (port->id == port_id)
509 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
511 const char *port_type_name,
514 struct port_out_type *type = NULL;
515 struct port_out *port = NULL;
520 CHECK(!port_out_find(p, port_id), EINVAL);
522 CHECK_NAME(port_type_name, EINVAL);
523 type = port_out_type_find(p, port_type_name);
526 obj = type->ops.create(args);
529 /* Node allocation. */
530 port = calloc(1, sizeof(struct port_out));
533 /* Node initialization. */
538 /* Node add to tailq. */
539 TAILQ_INSERT_TAIL(&p->ports_out, port, node);
540 if (p->n_ports_out < port_id + 1)
541 p->n_ports_out = port_id + 1;
547 port_out_build(struct rte_swx_pipeline *p)
549 struct port_out *port;
552 CHECK(p->n_ports_out, EINVAL);
554 for (i = 0; i < p->n_ports_out; i++)
555 CHECK(port_out_find(p, i), EINVAL);
557 p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
558 CHECK(p->out, ENOMEM);
560 TAILQ_FOREACH(port, &p->ports_out, node) {
561 struct port_out_runtime *out = &p->out[port->id];
563 out->pkt_tx = port->type->ops.pkt_tx;
564 out->flush = port->type->ops.flush;
565 out->obj = port->obj;
572 port_out_build_free(struct rte_swx_pipeline *p)
579 port_out_free(struct rte_swx_pipeline *p)
581 port_out_build_free(p);
585 struct port_out *port;
587 port = TAILQ_FIRST(&p->ports_out);
591 TAILQ_REMOVE(&p->ports_out, port, node);
592 port->type->ops.free(port->obj);
596 /* Output port types. */
598 struct port_out_type *elem;
600 elem = TAILQ_FIRST(&p->port_out_types);
604 TAILQ_REMOVE(&p->port_out_types, elem, node);
612 static struct header *
613 header_find(struct rte_swx_pipeline *p, const char *name)
617 TAILQ_FOREACH(elem, &p->headers, node)
618 if (strcmp(elem->name, name) == 0)
625 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
627 const char *struct_type_name)
629 struct struct_type *st;
631 size_t n_headers_max;
634 CHECK_NAME(name, EINVAL);
635 CHECK_NAME(struct_type_name, EINVAL);
637 CHECK(!header_find(p, name), EEXIST);
639 st = struct_type_find(p, struct_type_name);
642 n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
643 CHECK(p->n_headers < n_headers_max, ENOSPC);
645 /* Node allocation. */
646 h = calloc(1, sizeof(struct header));
649 /* Node initialization. */
650 strcpy(h->name, name);
652 h->struct_id = p->n_structs;
653 h->id = p->n_headers;
655 /* Node add to tailq. */
656 TAILQ_INSERT_TAIL(&p->headers, h, node);
664 header_build(struct rte_swx_pipeline *p)
667 uint32_t n_bytes = 0, i;
669 TAILQ_FOREACH(h, &p->headers, node) {
670 n_bytes += h->st->n_bits / 8;
673 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
674 struct thread *t = &p->threads[i];
677 t->headers = calloc(p->n_headers,
678 sizeof(struct header_runtime));
679 CHECK(t->headers, ENOMEM);
681 t->headers_out = calloc(p->n_headers,
682 sizeof(struct header_out_runtime));
683 CHECK(t->headers_out, ENOMEM);
685 t->header_storage = calloc(1, n_bytes);
686 CHECK(t->header_storage, ENOMEM);
688 t->header_out_storage = calloc(1, n_bytes);
689 CHECK(t->header_out_storage, ENOMEM);
691 TAILQ_FOREACH(h, &p->headers, node) {
692 uint8_t *header_storage;
694 header_storage = &t->header_storage[offset];
695 offset += h->st->n_bits / 8;
697 t->headers[h->id].ptr0 = header_storage;
698 t->structs[h->struct_id] = header_storage;
706 header_build_free(struct rte_swx_pipeline *p)
710 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
711 struct thread *t = &p->threads[i];
713 free(t->headers_out);
714 t->headers_out = NULL;
719 free(t->header_out_storage);
720 t->header_out_storage = NULL;
722 free(t->header_storage);
723 t->header_storage = NULL;
728 header_free(struct rte_swx_pipeline *p)
730 header_build_free(p);
735 elem = TAILQ_FIRST(&p->headers);
739 TAILQ_REMOVE(&p->headers, elem, node);
748 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
749 const char *struct_type_name)
751 struct struct_type *st = NULL;
755 CHECK_NAME(struct_type_name, EINVAL);
756 st = struct_type_find(p, struct_type_name);
758 CHECK(!p->metadata_st, EINVAL);
761 p->metadata_struct_id = p->n_structs;
769 metadata_build(struct rte_swx_pipeline *p)
771 uint32_t n_bytes = p->metadata_st->n_bits / 8;
774 /* Thread-level initialization. */
775 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
776 struct thread *t = &p->threads[i];
779 metadata = calloc(1, n_bytes);
780 CHECK(metadata, ENOMEM);
782 t->metadata = metadata;
783 t->structs[p->metadata_struct_id] = metadata;
790 metadata_build_free(struct rte_swx_pipeline *p)
794 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
795 struct thread *t = &p->threads[i];
803 metadata_free(struct rte_swx_pipeline *p)
805 metadata_build_free(p);
812 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
814 struct rte_swx_pipeline *pipeline;
816 /* Check input parameters. */
819 /* Memory allocation. */
820 pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
821 CHECK(pipeline, ENOMEM);
823 /* Initialization. */
824 TAILQ_INIT(&pipeline->struct_types);
825 TAILQ_INIT(&pipeline->port_in_types);
826 TAILQ_INIT(&pipeline->ports_in);
827 TAILQ_INIT(&pipeline->port_out_types);
828 TAILQ_INIT(&pipeline->ports_out);
829 TAILQ_INIT(&pipeline->headers);
831 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
832 pipeline->numa_node = numa_node;
839 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
854 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
859 CHECK(p->build_done == 0, EEXIST);
861 status = port_in_build(p);
865 status = port_out_build(p);
869 status = struct_build(p);
873 status = header_build(p);
877 status = metadata_build(p);
885 metadata_build_free(p);
886 header_build_free(p);
887 port_out_build_free(p);
888 port_in_build_free(p);
889 struct_build_free(p);