1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
10 #include <rte_common.h>
12 #include "rte_swx_pipeline.h"
13 #include "rte_swx_ctl.h"
15 #define CHECK(condition, err_code) \
21 #define CHECK_NAME(name, err_code) \
22 CHECK((name) && (name)[0], err_code)
28 char name[RTE_SWX_NAME_SIZE];
34 TAILQ_ENTRY(struct_type) node;
35 char name[RTE_SWX_NAME_SIZE];
41 TAILQ_HEAD(struct_type_tailq, struct_type);
47 TAILQ_ENTRY(port_in_type) node;
48 char name[RTE_SWX_NAME_SIZE];
49 struct rte_swx_port_in_ops ops;
52 TAILQ_HEAD(port_in_type_tailq, port_in_type);
55 TAILQ_ENTRY(port_in) node;
56 struct port_in_type *type;
61 TAILQ_HEAD(port_in_tailq, port_in);
63 struct port_in_runtime {
64 rte_swx_port_in_pkt_rx_t pkt_rx;
71 struct port_out_type {
72 TAILQ_ENTRY(port_out_type) node;
73 char name[RTE_SWX_NAME_SIZE];
74 struct rte_swx_port_out_ops ops;
77 TAILQ_HEAD(port_out_type_tailq, port_out_type);
80 TAILQ_ENTRY(port_out) node;
81 struct port_out_type *type;
86 TAILQ_HEAD(port_out_tailq, port_out);
88 struct port_out_runtime {
89 rte_swx_port_out_pkt_tx_t pkt_tx;
90 rte_swx_port_out_flush_t flush;
97 struct extern_type_member_func {
98 TAILQ_ENTRY(extern_type_member_func) node;
99 char name[RTE_SWX_NAME_SIZE];
100 rte_swx_extern_type_member_func_t func;
104 TAILQ_HEAD(extern_type_member_func_tailq, extern_type_member_func);
107 TAILQ_ENTRY(extern_type) node;
108 char name[RTE_SWX_NAME_SIZE];
109 struct struct_type *mailbox_struct_type;
110 rte_swx_extern_type_constructor_t constructor;
111 rte_swx_extern_type_destructor_t destructor;
112 struct extern_type_member_func_tailq funcs;
116 TAILQ_HEAD(extern_type_tailq, extern_type);
119 TAILQ_ENTRY(extern_obj) node;
120 char name[RTE_SWX_NAME_SIZE];
121 struct extern_type *type;
127 TAILQ_HEAD(extern_obj_tailq, extern_obj);
129 #ifndef RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX
130 #define RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX 8
133 struct extern_obj_runtime {
136 rte_swx_extern_type_member_func_t funcs[RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX];
143 TAILQ_ENTRY(extern_func) node;
144 char name[RTE_SWX_NAME_SIZE];
145 struct struct_type *mailbox_struct_type;
146 rte_swx_extern_func_t func;
151 TAILQ_HEAD(extern_func_tailq, extern_func);
153 struct extern_func_runtime {
155 rte_swx_extern_func_t func;
162 TAILQ_ENTRY(header) node;
163 char name[RTE_SWX_NAME_SIZE];
164 struct struct_type *st;
169 TAILQ_HEAD(header_tailq, header);
171 struct header_runtime {
175 struct header_out_runtime {
191 TAILQ_ENTRY(action) node;
192 char name[RTE_SWX_NAME_SIZE];
193 struct struct_type *st;
194 struct instruction *instructions;
195 uint32_t n_instructions;
199 TAILQ_HEAD(action_tailq, action);
205 TAILQ_ENTRY(table_type) node;
206 char name[RTE_SWX_NAME_SIZE];
207 enum rte_swx_table_match_type match_type;
208 struct rte_swx_table_ops ops;
211 TAILQ_HEAD(table_type_tailq, table_type);
214 enum rte_swx_table_match_type match_type;
219 TAILQ_ENTRY(table) node;
220 char name[RTE_SWX_NAME_SIZE];
221 char args[RTE_SWX_NAME_SIZE];
222 struct table_type *type; /* NULL when n_fields == 0. */
225 struct match_field *fields;
227 int is_header; /* Only valid when n_fields > 0. */
228 struct header *header; /* Only valid when n_fields > 0. */
231 struct action **actions;
232 struct action *default_action;
233 uint8_t *default_action_data;
235 int default_action_is_const;
236 uint32_t action_data_size_max;
242 TAILQ_HEAD(table_tailq, table);
244 struct table_runtime {
245 rte_swx_table_lookup_t func;
257 /* Packet headers. */
258 struct header_runtime *headers; /* Extracted or generated headers. */
259 struct header_out_runtime *headers_out; /* Emitted headers. */
260 uint8_t *header_storage;
261 uint8_t *header_out_storage;
262 uint64_t valid_headers;
263 uint32_t n_headers_out;
265 /* Packet meta-data. */
269 struct table_runtime *tables;
270 struct rte_swx_table_state *table_state;
272 int hit; /* 0 = Miss, 1 = Hit. */
274 /* Extern objects and functions. */
275 struct extern_obj_runtime *extern_objs;
276 struct extern_func_runtime *extern_funcs;
279 #ifndef RTE_SWX_PIPELINE_THREADS_MAX
280 #define RTE_SWX_PIPELINE_THREADS_MAX 16
283 struct rte_swx_pipeline {
284 struct struct_type_tailq struct_types;
285 struct port_in_type_tailq port_in_types;
286 struct port_in_tailq ports_in;
287 struct port_out_type_tailq port_out_types;
288 struct port_out_tailq ports_out;
289 struct extern_type_tailq extern_types;
290 struct extern_obj_tailq extern_objs;
291 struct extern_func_tailq extern_funcs;
292 struct header_tailq headers;
293 struct struct_type *metadata_st;
294 uint32_t metadata_struct_id;
295 struct action_tailq actions;
296 struct table_type_tailq table_types;
297 struct table_tailq tables;
299 struct port_in_runtime *in;
300 struct port_out_runtime *out;
301 struct instruction **action_instructions;
302 struct rte_swx_table_state *table_state;
303 struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
307 uint32_t n_ports_out;
308 uint32_t n_extern_objs;
309 uint32_t n_extern_funcs;
320 static struct struct_type *
321 struct_type_find(struct rte_swx_pipeline *p, const char *name)
323 struct struct_type *elem;
325 TAILQ_FOREACH(elem, &p->struct_types, node)
326 if (strcmp(elem->name, name) == 0)
332 static struct field *
333 struct_type_field_find(struct struct_type *st, const char *name)
337 for (i = 0; i < st->n_fields; i++) {
338 struct field *f = &st->fields[i];
340 if (strcmp(f->name, name) == 0)
348 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
350 struct rte_swx_field_params *fields,
353 struct struct_type *st;
357 CHECK_NAME(name, EINVAL);
358 CHECK(fields, EINVAL);
359 CHECK(n_fields, EINVAL);
361 for (i = 0; i < n_fields; i++) {
362 struct rte_swx_field_params *f = &fields[i];
365 CHECK_NAME(f->name, EINVAL);
366 CHECK(f->n_bits, EINVAL);
367 CHECK(f->n_bits <= 64, EINVAL);
368 CHECK((f->n_bits & 7) == 0, EINVAL);
370 for (j = 0; j < i; j++) {
371 struct rte_swx_field_params *f_prev = &fields[j];
373 CHECK(strcmp(f->name, f_prev->name), EINVAL);
377 CHECK(!struct_type_find(p, name), EEXIST);
379 /* Node allocation. */
380 st = calloc(1, sizeof(struct struct_type));
383 st->fields = calloc(n_fields, sizeof(struct field));
389 /* Node initialization. */
390 strcpy(st->name, name);
391 for (i = 0; i < n_fields; i++) {
392 struct field *dst = &st->fields[i];
393 struct rte_swx_field_params *src = &fields[i];
395 strcpy(dst->name, src->name);
396 dst->n_bits = src->n_bits;
397 dst->offset = st->n_bits;
399 st->n_bits += src->n_bits;
401 st->n_fields = n_fields;
403 /* Node add to tailq. */
404 TAILQ_INSERT_TAIL(&p->struct_types, st, node);
410 struct_build(struct rte_swx_pipeline *p)
414 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
415 struct thread *t = &p->threads[i];
417 t->structs = calloc(p->n_structs, sizeof(uint8_t *));
418 CHECK(t->structs, ENOMEM);
425 struct_build_free(struct rte_swx_pipeline *p)
429 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
430 struct thread *t = &p->threads[i];
438 struct_free(struct rte_swx_pipeline *p)
440 struct_build_free(p);
444 struct struct_type *elem;
446 elem = TAILQ_FIRST(&p->struct_types);
450 TAILQ_REMOVE(&p->struct_types, elem, node);
459 static struct port_in_type *
460 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
462 struct port_in_type *elem;
467 TAILQ_FOREACH(elem, &p->port_in_types, node)
468 if (strcmp(elem->name, name) == 0)
475 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
477 struct rte_swx_port_in_ops *ops)
479 struct port_in_type *elem;
482 CHECK_NAME(name, EINVAL);
484 CHECK(ops->create, EINVAL);
485 CHECK(ops->free, EINVAL);
486 CHECK(ops->pkt_rx, EINVAL);
487 CHECK(ops->stats_read, EINVAL);
489 CHECK(!port_in_type_find(p, name), EEXIST);
491 /* Node allocation. */
492 elem = calloc(1, sizeof(struct port_in_type));
495 /* Node initialization. */
496 strcpy(elem->name, name);
497 memcpy(&elem->ops, ops, sizeof(*ops));
499 /* Node add to tailq. */
500 TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
505 static struct port_in *
506 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
508 struct port_in *port;
510 TAILQ_FOREACH(port, &p->ports_in, node)
511 if (port->id == port_id)
518 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
520 const char *port_type_name,
523 struct port_in_type *type = NULL;
524 struct port_in *port = NULL;
529 CHECK(!port_in_find(p, port_id), EINVAL);
531 CHECK_NAME(port_type_name, EINVAL);
532 type = port_in_type_find(p, port_type_name);
535 obj = type->ops.create(args);
538 /* Node allocation. */
539 port = calloc(1, sizeof(struct port_in));
542 /* Node initialization. */
547 /* Node add to tailq. */
548 TAILQ_INSERT_TAIL(&p->ports_in, port, node);
549 if (p->n_ports_in < port_id + 1)
550 p->n_ports_in = port_id + 1;
556 port_in_build(struct rte_swx_pipeline *p)
558 struct port_in *port;
561 CHECK(p->n_ports_in, EINVAL);
562 CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
564 for (i = 0; i < p->n_ports_in; i++)
565 CHECK(port_in_find(p, i), EINVAL);
567 p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
568 CHECK(p->in, ENOMEM);
570 TAILQ_FOREACH(port, &p->ports_in, node) {
571 struct port_in_runtime *in = &p->in[port->id];
573 in->pkt_rx = port->type->ops.pkt_rx;
581 port_in_build_free(struct rte_swx_pipeline *p)
588 port_in_free(struct rte_swx_pipeline *p)
590 port_in_build_free(p);
594 struct port_in *port;
596 port = TAILQ_FIRST(&p->ports_in);
600 TAILQ_REMOVE(&p->ports_in, port, node);
601 port->type->ops.free(port->obj);
605 /* Input port types. */
607 struct port_in_type *elem;
609 elem = TAILQ_FIRST(&p->port_in_types);
613 TAILQ_REMOVE(&p->port_in_types, elem, node);
621 static struct port_out_type *
622 port_out_type_find(struct rte_swx_pipeline *p, const char *name)
624 struct port_out_type *elem;
629 TAILQ_FOREACH(elem, &p->port_out_types, node)
630 if (!strcmp(elem->name, name))
637 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
639 struct rte_swx_port_out_ops *ops)
641 struct port_out_type *elem;
644 CHECK_NAME(name, EINVAL);
646 CHECK(ops->create, EINVAL);
647 CHECK(ops->free, EINVAL);
648 CHECK(ops->pkt_tx, EINVAL);
649 CHECK(ops->stats_read, EINVAL);
651 CHECK(!port_out_type_find(p, name), EEXIST);
653 /* Node allocation. */
654 elem = calloc(1, sizeof(struct port_out_type));
657 /* Node initialization. */
658 strcpy(elem->name, name);
659 memcpy(&elem->ops, ops, sizeof(*ops));
661 /* Node add to tailq. */
662 TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
667 static struct port_out *
668 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
670 struct port_out *port;
672 TAILQ_FOREACH(port, &p->ports_out, node)
673 if (port->id == port_id)
680 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
682 const char *port_type_name,
685 struct port_out_type *type = NULL;
686 struct port_out *port = NULL;
691 CHECK(!port_out_find(p, port_id), EINVAL);
693 CHECK_NAME(port_type_name, EINVAL);
694 type = port_out_type_find(p, port_type_name);
697 obj = type->ops.create(args);
700 /* Node allocation. */
701 port = calloc(1, sizeof(struct port_out));
704 /* Node initialization. */
709 /* Node add to tailq. */
710 TAILQ_INSERT_TAIL(&p->ports_out, port, node);
711 if (p->n_ports_out < port_id + 1)
712 p->n_ports_out = port_id + 1;
718 port_out_build(struct rte_swx_pipeline *p)
720 struct port_out *port;
723 CHECK(p->n_ports_out, EINVAL);
725 for (i = 0; i < p->n_ports_out; i++)
726 CHECK(port_out_find(p, i), EINVAL);
728 p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
729 CHECK(p->out, ENOMEM);
731 TAILQ_FOREACH(port, &p->ports_out, node) {
732 struct port_out_runtime *out = &p->out[port->id];
734 out->pkt_tx = port->type->ops.pkt_tx;
735 out->flush = port->type->ops.flush;
736 out->obj = port->obj;
743 port_out_build_free(struct rte_swx_pipeline *p)
750 port_out_free(struct rte_swx_pipeline *p)
752 port_out_build_free(p);
756 struct port_out *port;
758 port = TAILQ_FIRST(&p->ports_out);
762 TAILQ_REMOVE(&p->ports_out, port, node);
763 port->type->ops.free(port->obj);
767 /* Output port types. */
769 struct port_out_type *elem;
771 elem = TAILQ_FIRST(&p->port_out_types);
775 TAILQ_REMOVE(&p->port_out_types, elem, node);
783 static struct extern_type *
784 extern_type_find(struct rte_swx_pipeline *p, const char *name)
786 struct extern_type *elem;
788 TAILQ_FOREACH(elem, &p->extern_types, node)
789 if (strcmp(elem->name, name) == 0)
795 static struct extern_type_member_func *
796 extern_type_member_func_find(struct extern_type *type, const char *name)
798 struct extern_type_member_func *elem;
800 TAILQ_FOREACH(elem, &type->funcs, node)
801 if (strcmp(elem->name, name) == 0)
807 static struct extern_obj *
808 extern_obj_find(struct rte_swx_pipeline *p, const char *name)
810 struct extern_obj *elem;
812 TAILQ_FOREACH(elem, &p->extern_objs, node)
813 if (strcmp(elem->name, name) == 0)
820 rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p,
822 const char *mailbox_struct_type_name,
823 rte_swx_extern_type_constructor_t constructor,
824 rte_swx_extern_type_destructor_t destructor)
826 struct extern_type *elem;
827 struct struct_type *mailbox_struct_type;
831 CHECK_NAME(name, EINVAL);
832 CHECK(!extern_type_find(p, name), EEXIST);
834 CHECK_NAME(mailbox_struct_type_name, EINVAL);
835 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
836 CHECK(mailbox_struct_type, EINVAL);
838 CHECK(constructor, EINVAL);
839 CHECK(destructor, EINVAL);
841 /* Node allocation. */
842 elem = calloc(1, sizeof(struct extern_type));
845 /* Node initialization. */
846 strcpy(elem->name, name);
847 elem->mailbox_struct_type = mailbox_struct_type;
848 elem->constructor = constructor;
849 elem->destructor = destructor;
850 TAILQ_INIT(&elem->funcs);
852 /* Node add to tailq. */
853 TAILQ_INSERT_TAIL(&p->extern_types, elem, node);
859 rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p,
860 const char *extern_type_name,
862 rte_swx_extern_type_member_func_t member_func)
864 struct extern_type *type;
865 struct extern_type_member_func *type_member;
869 CHECK(extern_type_name, EINVAL);
870 type = extern_type_find(p, extern_type_name);
872 CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC);
875 CHECK(!extern_type_member_func_find(type, name), EEXIST);
877 CHECK(member_func, EINVAL);
879 /* Node allocation. */
880 type_member = calloc(1, sizeof(struct extern_type_member_func));
881 CHECK(type_member, ENOMEM);
883 /* Node initialization. */
884 strcpy(type_member->name, name);
885 type_member->func = member_func;
886 type_member->id = type->n_funcs;
888 /* Node add to tailq. */
889 TAILQ_INSERT_TAIL(&type->funcs, type_member, node);
896 rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p,
897 const char *extern_type_name,
901 struct extern_type *type;
902 struct extern_obj *obj;
907 CHECK_NAME(extern_type_name, EINVAL);
908 type = extern_type_find(p, extern_type_name);
911 CHECK_NAME(name, EINVAL);
912 CHECK(!extern_obj_find(p, name), EEXIST);
914 /* Node allocation. */
915 obj = calloc(1, sizeof(struct extern_obj));
918 /* Object construction. */
919 obj_handle = type->constructor(args);
925 /* Node initialization. */
926 strcpy(obj->name, name);
928 obj->obj = obj_handle;
929 obj->struct_id = p->n_structs;
930 obj->id = p->n_extern_objs;
932 /* Node add to tailq. */
933 TAILQ_INSERT_TAIL(&p->extern_objs, obj, node);
941 extern_obj_build(struct rte_swx_pipeline *p)
945 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
946 struct thread *t = &p->threads[i];
947 struct extern_obj *obj;
949 t->extern_objs = calloc(p->n_extern_objs,
950 sizeof(struct extern_obj_runtime));
951 CHECK(t->extern_objs, ENOMEM);
953 TAILQ_FOREACH(obj, &p->extern_objs, node) {
954 struct extern_obj_runtime *r =
955 &t->extern_objs[obj->id];
956 struct extern_type_member_func *func;
957 uint32_t mailbox_size =
958 obj->type->mailbox_struct_type->n_bits / 8;
962 r->mailbox = calloc(1, mailbox_size);
963 CHECK(r->mailbox, ENOMEM);
965 TAILQ_FOREACH(func, &obj->type->funcs, node)
966 r->funcs[func->id] = func->func;
968 t->structs[obj->struct_id] = r->mailbox;
976 extern_obj_build_free(struct rte_swx_pipeline *p)
980 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
981 struct thread *t = &p->threads[i];
987 for (j = 0; j < p->n_extern_objs; j++) {
988 struct extern_obj_runtime *r = &t->extern_objs[j];
993 free(t->extern_objs);
994 t->extern_objs = NULL;
999 extern_obj_free(struct rte_swx_pipeline *p)
1001 extern_obj_build_free(p);
1003 /* Extern objects. */
1005 struct extern_obj *elem;
1007 elem = TAILQ_FIRST(&p->extern_objs);
1011 TAILQ_REMOVE(&p->extern_objs, elem, node);
1013 elem->type->destructor(elem->obj);
1019 struct extern_type *elem;
1021 elem = TAILQ_FIRST(&p->extern_types);
1025 TAILQ_REMOVE(&p->extern_types, elem, node);
1028 struct extern_type_member_func *func;
1030 func = TAILQ_FIRST(&elem->funcs);
1034 TAILQ_REMOVE(&elem->funcs, func, node);
1045 static struct extern_func *
1046 extern_func_find(struct rte_swx_pipeline *p, const char *name)
1048 struct extern_func *elem;
1050 TAILQ_FOREACH(elem, &p->extern_funcs, node)
1051 if (strcmp(elem->name, name) == 0)
1058 rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p,
1060 const char *mailbox_struct_type_name,
1061 rte_swx_extern_func_t func)
1063 struct extern_func *f;
1064 struct struct_type *mailbox_struct_type;
1068 CHECK_NAME(name, EINVAL);
1069 CHECK(!extern_func_find(p, name), EEXIST);
1071 CHECK_NAME(mailbox_struct_type_name, EINVAL);
1072 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
1073 CHECK(mailbox_struct_type, EINVAL);
1075 CHECK(func, EINVAL);
1077 /* Node allocation. */
1078 f = calloc(1, sizeof(struct extern_func));
1079 CHECK(func, ENOMEM);
1081 /* Node initialization. */
1082 strcpy(f->name, name);
1083 f->mailbox_struct_type = mailbox_struct_type;
1085 f->struct_id = p->n_structs;
1086 f->id = p->n_extern_funcs;
1088 /* Node add to tailq. */
1089 TAILQ_INSERT_TAIL(&p->extern_funcs, f, node);
1090 p->n_extern_funcs++;
1097 extern_func_build(struct rte_swx_pipeline *p)
1101 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1102 struct thread *t = &p->threads[i];
1103 struct extern_func *func;
1105 /* Memory allocation. */
1106 t->extern_funcs = calloc(p->n_extern_funcs,
1107 sizeof(struct extern_func_runtime));
1108 CHECK(t->extern_funcs, ENOMEM);
1110 /* Extern function. */
1111 TAILQ_FOREACH(func, &p->extern_funcs, node) {
1112 struct extern_func_runtime *r =
1113 &t->extern_funcs[func->id];
1114 uint32_t mailbox_size =
1115 func->mailbox_struct_type->n_bits / 8;
1117 r->func = func->func;
1119 r->mailbox = calloc(1, mailbox_size);
1120 CHECK(r->mailbox, ENOMEM);
1122 t->structs[func->struct_id] = r->mailbox;
1130 extern_func_build_free(struct rte_swx_pipeline *p)
1134 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1135 struct thread *t = &p->threads[i];
1138 if (!t->extern_funcs)
1141 for (j = 0; j < p->n_extern_funcs; j++) {
1142 struct extern_func_runtime *r = &t->extern_funcs[j];
1147 free(t->extern_funcs);
1148 t->extern_funcs = NULL;
1153 extern_func_free(struct rte_swx_pipeline *p)
1155 extern_func_build_free(p);
1158 struct extern_func *elem;
1160 elem = TAILQ_FIRST(&p->extern_funcs);
1164 TAILQ_REMOVE(&p->extern_funcs, elem, node);
1172 static struct header *
1173 header_find(struct rte_swx_pipeline *p, const char *name)
1175 struct header *elem;
1177 TAILQ_FOREACH(elem, &p->headers, node)
1178 if (strcmp(elem->name, name) == 0)
1184 static struct field *
1185 header_field_parse(struct rte_swx_pipeline *p,
1187 struct header **header)
1191 char *header_name, *field_name;
1193 if ((name[0] != 'h') || (name[1] != '.'))
1196 header_name = strdup(&name[2]);
1200 field_name = strchr(header_name, '.');
1209 h = header_find(p, header_name);
1215 f = struct_type_field_find(h->st, field_name);
1229 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
1231 const char *struct_type_name)
1233 struct struct_type *st;
1235 size_t n_headers_max;
1238 CHECK_NAME(name, EINVAL);
1239 CHECK_NAME(struct_type_name, EINVAL);
1241 CHECK(!header_find(p, name), EEXIST);
1243 st = struct_type_find(p, struct_type_name);
1246 n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
1247 CHECK(p->n_headers < n_headers_max, ENOSPC);
1249 /* Node allocation. */
1250 h = calloc(1, sizeof(struct header));
1253 /* Node initialization. */
1254 strcpy(h->name, name);
1256 h->struct_id = p->n_structs;
1257 h->id = p->n_headers;
1259 /* Node add to tailq. */
1260 TAILQ_INSERT_TAIL(&p->headers, h, node);
1268 header_build(struct rte_swx_pipeline *p)
1271 uint32_t n_bytes = 0, i;
1273 TAILQ_FOREACH(h, &p->headers, node) {
1274 n_bytes += h->st->n_bits / 8;
1277 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1278 struct thread *t = &p->threads[i];
1279 uint32_t offset = 0;
1281 t->headers = calloc(p->n_headers,
1282 sizeof(struct header_runtime));
1283 CHECK(t->headers, ENOMEM);
1285 t->headers_out = calloc(p->n_headers,
1286 sizeof(struct header_out_runtime));
1287 CHECK(t->headers_out, ENOMEM);
1289 t->header_storage = calloc(1, n_bytes);
1290 CHECK(t->header_storage, ENOMEM);
1292 t->header_out_storage = calloc(1, n_bytes);
1293 CHECK(t->header_out_storage, ENOMEM);
1295 TAILQ_FOREACH(h, &p->headers, node) {
1296 uint8_t *header_storage;
1298 header_storage = &t->header_storage[offset];
1299 offset += h->st->n_bits / 8;
1301 t->headers[h->id].ptr0 = header_storage;
1302 t->structs[h->struct_id] = header_storage;
1310 header_build_free(struct rte_swx_pipeline *p)
1314 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1315 struct thread *t = &p->threads[i];
1317 free(t->headers_out);
1318 t->headers_out = NULL;
1323 free(t->header_out_storage);
1324 t->header_out_storage = NULL;
1326 free(t->header_storage);
1327 t->header_storage = NULL;
1332 header_free(struct rte_swx_pipeline *p)
1334 header_build_free(p);
1337 struct header *elem;
1339 elem = TAILQ_FIRST(&p->headers);
1343 TAILQ_REMOVE(&p->headers, elem, node);
1351 static struct field *
1352 metadata_field_parse(struct rte_swx_pipeline *p, const char *name)
1354 if (!p->metadata_st)
1357 if (name[0] != 'm' || name[1] != '.')
1360 return struct_type_field_find(p->metadata_st, &name[2]);
1364 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
1365 const char *struct_type_name)
1367 struct struct_type *st = NULL;
1371 CHECK_NAME(struct_type_name, EINVAL);
1372 st = struct_type_find(p, struct_type_name);
1374 CHECK(!p->metadata_st, EINVAL);
1376 p->metadata_st = st;
1377 p->metadata_struct_id = p->n_structs;
1385 metadata_build(struct rte_swx_pipeline *p)
1387 uint32_t n_bytes = p->metadata_st->n_bits / 8;
1390 /* Thread-level initialization. */
1391 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1392 struct thread *t = &p->threads[i];
1395 metadata = calloc(1, n_bytes);
1396 CHECK(metadata, ENOMEM);
1398 t->metadata = metadata;
1399 t->structs[p->metadata_struct_id] = metadata;
1406 metadata_build_free(struct rte_swx_pipeline *p)
1410 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1411 struct thread *t = &p->threads[i];
1419 metadata_free(struct rte_swx_pipeline *p)
1421 metadata_build_free(p);
1428 instruction_config(struct rte_swx_pipeline *p __rte_unused,
1429 struct action *a __rte_unused,
1430 const char **instructions __rte_unused,
1431 uint32_t n_instructions __rte_unused)
1439 static struct action *
1440 action_find(struct rte_swx_pipeline *p, const char *name)
1442 struct action *elem;
1447 TAILQ_FOREACH(elem, &p->actions, node)
1448 if (strcmp(elem->name, name) == 0)
1455 rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
1457 const char *args_struct_type_name,
1458 const char **instructions,
1459 uint32_t n_instructions)
1461 struct struct_type *args_struct_type;
1467 CHECK_NAME(name, EINVAL);
1468 CHECK(!action_find(p, name), EEXIST);
1470 if (args_struct_type_name) {
1471 CHECK_NAME(args_struct_type_name, EINVAL);
1472 args_struct_type = struct_type_find(p, args_struct_type_name);
1473 CHECK(args_struct_type, EINVAL);
1475 args_struct_type = NULL;
1478 /* Node allocation. */
1479 a = calloc(1, sizeof(struct action));
1482 /* Node initialization. */
1483 strcpy(a->name, name);
1484 a->st = args_struct_type;
1485 a->id = p->n_actions;
1487 /* Instruction translation. */
1488 err = instruction_config(p, a, instructions, n_instructions);
1494 /* Node add to tailq. */
1495 TAILQ_INSERT_TAIL(&p->actions, a, node);
1502 action_build(struct rte_swx_pipeline *p)
1504 struct action *action;
1506 p->action_instructions = calloc(p->n_actions,
1507 sizeof(struct instruction *));
1508 CHECK(p->action_instructions, ENOMEM);
1510 TAILQ_FOREACH(action, &p->actions, node)
1511 p->action_instructions[action->id] = action->instructions;
1517 action_build_free(struct rte_swx_pipeline *p)
1519 free(p->action_instructions);
1520 p->action_instructions = NULL;
1524 action_free(struct rte_swx_pipeline *p)
1526 action_build_free(p);
1529 struct action *action;
1531 action = TAILQ_FIRST(&p->actions);
1535 TAILQ_REMOVE(&p->actions, action, node);
1536 free(action->instructions);
1544 static struct table_type *
1545 table_type_find(struct rte_swx_pipeline *p, const char *name)
1547 struct table_type *elem;
1549 TAILQ_FOREACH(elem, &p->table_types, node)
1550 if (strcmp(elem->name, name) == 0)
1556 static struct table_type *
1557 table_type_resolve(struct rte_swx_pipeline *p,
1558 const char *recommended_type_name,
1559 enum rte_swx_table_match_type match_type)
1561 struct table_type *elem;
1563 /* Only consider the recommended type if the match type is correct. */
1564 if (recommended_type_name)
1565 TAILQ_FOREACH(elem, &p->table_types, node)
1566 if (!strcmp(elem->name, recommended_type_name) &&
1567 (elem->match_type == match_type))
1570 /* Ignore the recommended type and get the first element with this match
1573 TAILQ_FOREACH(elem, &p->table_types, node)
1574 if (elem->match_type == match_type)
1580 static struct table *
1581 table_find(struct rte_swx_pipeline *p, const char *name)
1585 TAILQ_FOREACH(elem, &p->tables, node)
1586 if (strcmp(elem->name, name) == 0)
1592 static struct table *
1593 table_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
1595 struct table *table = NULL;
1597 TAILQ_FOREACH(table, &p->tables, node)
1598 if (table->id == id)
1605 rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p,
1607 enum rte_swx_table_match_type match_type,
1608 struct rte_swx_table_ops *ops)
1610 struct table_type *elem;
1614 CHECK_NAME(name, EINVAL);
1615 CHECK(!table_type_find(p, name), EEXIST);
1618 CHECK(ops->create, EINVAL);
1619 CHECK(ops->lkp, EINVAL);
1620 CHECK(ops->free, EINVAL);
1622 /* Node allocation. */
1623 elem = calloc(1, sizeof(struct table_type));
1624 CHECK(elem, ENOMEM);
1626 /* Node initialization. */
1627 strcpy(elem->name, name);
1628 elem->match_type = match_type;
1629 memcpy(&elem->ops, ops, sizeof(*ops));
1631 /* Node add to tailq. */
1632 TAILQ_INSERT_TAIL(&p->table_types, elem, node);
1637 static enum rte_swx_table_match_type
1638 table_match_type_resolve(struct rte_swx_match_field_params *fields,
1643 for (i = 0; i < n_fields; i++)
1644 if (fields[i].match_type != RTE_SWX_TABLE_MATCH_EXACT)
1648 return RTE_SWX_TABLE_MATCH_EXACT;
1650 if ((i == n_fields - 1) &&
1651 (fields[i].match_type == RTE_SWX_TABLE_MATCH_LPM))
1652 return RTE_SWX_TABLE_MATCH_LPM;
1654 return RTE_SWX_TABLE_MATCH_WILDCARD;
1658 rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
1660 struct rte_swx_pipeline_table_params *params,
1661 const char *recommended_table_type_name,
1665 struct table_type *type;
1667 struct action *default_action;
1668 struct header *header = NULL;
1670 uint32_t offset_prev = 0, action_data_size_max = 0, i;
1674 CHECK_NAME(name, EINVAL);
1675 CHECK(!table_find(p, name), EEXIST);
1677 CHECK(params, EINVAL);
1680 CHECK(!params->n_fields || params->fields, EINVAL);
1681 for (i = 0; i < params->n_fields; i++) {
1682 struct rte_swx_match_field_params *field = ¶ms->fields[i];
1684 struct field *hf, *mf;
1687 CHECK_NAME(field->name, EINVAL);
1689 hf = header_field_parse(p, field->name, &h);
1690 mf = metadata_field_parse(p, field->name);
1691 CHECK(hf || mf, EINVAL);
1693 offset = hf ? hf->offset : mf->offset;
1696 is_header = hf ? 1 : 0;
1697 header = hf ? h : NULL;
1698 offset_prev = offset;
1703 CHECK((is_header && hf && (h->id == header->id)) ||
1704 (!is_header && mf), EINVAL);
1706 CHECK(offset > offset_prev, EINVAL);
1707 offset_prev = offset;
1710 /* Action checks. */
1711 CHECK(params->n_actions, EINVAL);
1712 CHECK(params->action_names, EINVAL);
1713 for (i = 0; i < params->n_actions; i++) {
1714 const char *action_name = params->action_names[i];
1716 uint32_t action_data_size;
1718 CHECK(action_name, EINVAL);
1720 a = action_find(p, action_name);
1723 action_data_size = a->st ? a->st->n_bits / 8 : 0;
1724 if (action_data_size > action_data_size_max)
1725 action_data_size_max = action_data_size;
1728 CHECK(params->default_action_name, EINVAL);
1729 for (i = 0; i < p->n_actions; i++)
1730 if (!strcmp(params->action_names[i],
1731 params->default_action_name))
1733 CHECK(i < params->n_actions, EINVAL);
1734 default_action = action_find(p, params->default_action_name);
1735 CHECK((default_action->st && params->default_action_data) ||
1736 !params->default_action_data, EINVAL);
1738 /* Table type checks. */
1739 if (params->n_fields) {
1740 enum rte_swx_table_match_type match_type;
1742 match_type = table_match_type_resolve(params->fields,
1744 type = table_type_resolve(p,
1745 recommended_table_type_name,
1747 CHECK(type, EINVAL);
1752 /* Memory allocation. */
1753 t = calloc(1, sizeof(struct table));
1756 t->fields = calloc(params->n_fields, sizeof(struct match_field));
1762 t->actions = calloc(params->n_actions, sizeof(struct action *));
1769 if (action_data_size_max) {
1770 t->default_action_data = calloc(1, action_data_size_max);
1771 if (!t->default_action_data) {
1779 /* Node initialization. */
1780 strcpy(t->name, name);
1781 if (args && args[0])
1782 strcpy(t->args, args);
1785 for (i = 0; i < params->n_fields; i++) {
1786 struct rte_swx_match_field_params *field = ¶ms->fields[i];
1787 struct match_field *f = &t->fields[i];
1789 f->match_type = field->match_type;
1790 f->field = is_header ?
1791 header_field_parse(p, field->name, NULL) :
1792 metadata_field_parse(p, field->name);
1794 t->n_fields = params->n_fields;
1795 t->is_header = is_header;
1798 for (i = 0; i < params->n_actions; i++)
1799 t->actions[i] = action_find(p, params->action_names[i]);
1800 t->default_action = default_action;
1801 if (default_action->st)
1802 memcpy(t->default_action_data,
1803 params->default_action_data,
1804 default_action->st->n_bits / 8);
1805 t->n_actions = params->n_actions;
1806 t->default_action_is_const = params->default_action_is_const;
1807 t->action_data_size_max = action_data_size_max;
1810 t->id = p->n_tables;
1812 /* Node add to tailq. */
1813 TAILQ_INSERT_TAIL(&p->tables, t, node);
1819 static struct rte_swx_table_params *
1820 table_params_get(struct table *table)
1822 struct rte_swx_table_params *params;
1823 struct field *first, *last;
1825 uint32_t key_size, key_offset, action_data_size, i;
1827 /* Memory allocation. */
1828 params = calloc(1, sizeof(struct rte_swx_table_params));
1832 /* Key offset and size. */
1833 first = table->fields[0].field;
1834 last = table->fields[table->n_fields - 1].field;
1835 key_offset = first->offset / 8;
1836 key_size = (last->offset + last->n_bits - first->offset) / 8;
1838 /* Memory allocation. */
1839 key_mask = calloc(1, key_size);
1846 for (i = 0; i < table->n_fields; i++) {
1847 struct field *f = table->fields[i].field;
1848 uint32_t start = (f->offset - first->offset) / 8;
1849 size_t size = f->n_bits / 8;
1851 memset(&key_mask[start], 0xFF, size);
1854 /* Action data size. */
1855 action_data_size = 0;
1856 for (i = 0; i < table->n_actions; i++) {
1857 struct action *action = table->actions[i];
1858 uint32_t ads = action->st ? action->st->n_bits / 8 : 0;
1860 if (ads > action_data_size)
1861 action_data_size = ads;
1865 params->match_type = table->type->match_type;
1866 params->key_size = key_size;
1867 params->key_offset = key_offset;
1868 params->key_mask0 = key_mask;
1869 params->action_data_size = action_data_size;
1870 params->n_keys_max = table->size;
1876 table_params_free(struct rte_swx_table_params *params)
1881 free(params->key_mask0);
1886 table_state_build(struct rte_swx_pipeline *p)
1888 struct table *table;
1890 p->table_state = calloc(p->n_tables,
1891 sizeof(struct rte_swx_table_state));
1892 CHECK(p->table_state, ENOMEM);
1894 TAILQ_FOREACH(table, &p->tables, node) {
1895 struct rte_swx_table_state *ts = &p->table_state[table->id];
1898 struct rte_swx_table_params *params;
1901 params = table_params_get(table);
1902 CHECK(params, ENOMEM);
1904 ts->obj = table->type->ops.create(params,
1909 table_params_free(params);
1910 CHECK(ts->obj, ENODEV);
1913 /* ts->default_action_data. */
1914 if (table->action_data_size_max) {
1915 ts->default_action_data =
1916 malloc(table->action_data_size_max);
1917 CHECK(ts->default_action_data, ENOMEM);
1919 memcpy(ts->default_action_data,
1920 table->default_action_data,
1921 table->action_data_size_max);
1924 /* ts->default_action_id. */
1925 ts->default_action_id = table->default_action->id;
1932 table_state_build_free(struct rte_swx_pipeline *p)
1936 if (!p->table_state)
1939 for (i = 0; i < p->n_tables; i++) {
1940 struct rte_swx_table_state *ts = &p->table_state[i];
1941 struct table *table = table_find_by_id(p, i);
1944 if (table->type && ts->obj)
1945 table->type->ops.free(ts->obj);
1947 /* ts->default_action_data. */
1948 free(ts->default_action_data);
1951 free(p->table_state);
1952 p->table_state = NULL;
1956 table_state_free(struct rte_swx_pipeline *p)
1958 table_state_build_free(p);
1962 table_stub_lkp(void *table __rte_unused,
1963 void *mailbox __rte_unused,
1964 uint8_t **key __rte_unused,
1965 uint64_t *action_id __rte_unused,
1966 uint8_t **action_data __rte_unused,
1970 return 1; /* DONE. */
1974 table_build(struct rte_swx_pipeline *p)
1978 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1979 struct thread *t = &p->threads[i];
1980 struct table *table;
1982 t->tables = calloc(p->n_tables, sizeof(struct table_runtime));
1983 CHECK(t->tables, ENOMEM);
1985 TAILQ_FOREACH(table, &p->tables, node) {
1986 struct table_runtime *r = &t->tables[table->id];
1991 size = table->type->ops.mailbox_size_get();
1994 r->func = table->type->ops.lkp;
1998 r->mailbox = calloc(1, size);
1999 CHECK(r->mailbox, ENOMEM);
2003 r->key = table->is_header ?
2004 &t->structs[table->header->struct_id] :
2005 &t->structs[p->metadata_struct_id];
2007 r->func = table_stub_lkp;
2016 table_build_free(struct rte_swx_pipeline *p)
2020 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
2021 struct thread *t = &p->threads[i];
2027 for (j = 0; j < p->n_tables; j++) {
2028 struct table_runtime *r = &t->tables[j];
2039 table_free(struct rte_swx_pipeline *p)
2041 table_build_free(p);
2047 elem = TAILQ_FIRST(&p->tables);
2051 TAILQ_REMOVE(&p->tables, elem, node);
2053 free(elem->actions);
2054 free(elem->default_action_data);
2060 struct table_type *elem;
2062 elem = TAILQ_FIRST(&p->table_types);
2066 TAILQ_REMOVE(&p->table_types, elem, node);
2075 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
2077 struct rte_swx_pipeline *pipeline;
2079 /* Check input parameters. */
2082 /* Memory allocation. */
2083 pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
2084 CHECK(pipeline, ENOMEM);
2086 /* Initialization. */
2087 TAILQ_INIT(&pipeline->struct_types);
2088 TAILQ_INIT(&pipeline->port_in_types);
2089 TAILQ_INIT(&pipeline->ports_in);
2090 TAILQ_INIT(&pipeline->port_out_types);
2091 TAILQ_INIT(&pipeline->ports_out);
2092 TAILQ_INIT(&pipeline->extern_types);
2093 TAILQ_INIT(&pipeline->extern_objs);
2094 TAILQ_INIT(&pipeline->extern_funcs);
2095 TAILQ_INIT(&pipeline->headers);
2096 TAILQ_INIT(&pipeline->actions);
2097 TAILQ_INIT(&pipeline->table_types);
2098 TAILQ_INIT(&pipeline->tables);
2100 pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
2101 pipeline->numa_node = numa_node;
2108 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
2113 table_state_free(p);
2118 extern_func_free(p);
2128 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
2133 CHECK(p->build_done == 0, EEXIST);
2135 status = port_in_build(p);
2139 status = port_out_build(p);
2143 status = struct_build(p);
2147 status = extern_obj_build(p);
2151 status = extern_func_build(p);
2155 status = header_build(p);
2159 status = metadata_build(p);
2163 status = action_build(p);
2167 status = table_build(p);
2171 status = table_state_build(p);
2179 table_state_build_free(p);
2180 table_build_free(p);
2181 action_build_free(p);
2182 metadata_build_free(p);
2183 header_build_free(p);
2184 extern_func_build_free(p);
2185 extern_obj_build_free(p);
2186 port_out_build_free(p);
2187 port_in_build_free(p);
2188 struct_build_free(p);
2197 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
2198 struct rte_swx_table_state **table_state)
2200 if (!p || !table_state || !p->build_done)
2203 *table_state = p->table_state;
2208 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
2209 struct rte_swx_table_state *table_state)
2211 if (!p || !table_state || !p->build_done)
2214 p->table_state = table_state;