055056098dd79fc233e530271e4fb2aa16d097d4
[dpdk.git] / lib / pipeline / rte_swx_pipeline.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <errno.h>
7 #include <arpa/inet.h>
8 #include <dlfcn.h>
9
10 #include "rte_swx_pipeline_internal.h"
11
12 #define CHECK(condition, err_code)                                             \
13 do {                                                                           \
14         if (!(condition))                                                      \
15                 return -(err_code);                                            \
16 } while (0)
17
18 #define CHECK_NAME(name, err_code)                                             \
19         CHECK((name) &&                                                        \
20               (name)[0] &&                                                     \
21               (strnlen((name), RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE),        \
22               err_code)
23
24 #define CHECK_INSTRUCTION(instr, err_code)                                     \
25         CHECK((instr) &&                                                       \
26               (instr)[0] &&                                                    \
27               (strnlen((instr), RTE_SWX_INSTRUCTION_SIZE) <                    \
28                RTE_SWX_INSTRUCTION_SIZE),                                      \
29               err_code)
30
31 /*
32  * Environment.
33  */
34 #ifndef RTE_SWX_PIPELINE_HUGE_PAGES_DISABLE
35
36 #include <rte_malloc.h>
37
38 static void *
39 env_malloc(size_t size, size_t alignment, int numa_node)
40 {
41         return rte_zmalloc_socket(NULL, size, alignment, numa_node);
42 }
43
44 static void
45 env_free(void *start, size_t size __rte_unused)
46 {
47         rte_free(start);
48 }
49
50 #else
51
52 #include <numa.h>
53
54 static void *
55 env_malloc(size_t size, size_t alignment __rte_unused, int numa_node)
56 {
57         void *start;
58
59         if (numa_available() == -1)
60                 return NULL;
61
62         start = numa_alloc_onnode(size, numa_node);
63         if (!start)
64                 return NULL;
65
66         memset(start, 0, size);
67         return start;
68 }
69
70 static void
71 env_free(void *start, size_t size)
72 {
73         if (numa_available() == -1)
74                 return;
75
76         numa_free(start, size);
77 }
78
79 #endif
80
81 /*
82  * Struct.
83  */
84 static struct struct_type *
85 struct_type_find(struct rte_swx_pipeline *p, const char *name)
86 {
87         struct struct_type *elem;
88
89         TAILQ_FOREACH(elem, &p->struct_types, node)
90                 if (strcmp(elem->name, name) == 0)
91                         return elem;
92
93         return NULL;
94 }
95
96 static struct field *
97 struct_type_field_find(struct struct_type *st, const char *name)
98 {
99         uint32_t i;
100
101         for (i = 0; i < st->n_fields; i++) {
102                 struct field *f = &st->fields[i];
103
104                 if (strcmp(f->name, name) == 0)
105                         return f;
106         }
107
108         return NULL;
109 }
110
111 int
112 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
113                                       const char *name,
114                                       struct rte_swx_field_params *fields,
115                                       uint32_t n_fields,
116                                       int last_field_has_variable_size)
117 {
118         struct struct_type *st;
119         uint32_t i;
120
121         CHECK(p, EINVAL);
122         CHECK_NAME(name, EINVAL);
123         CHECK(fields, EINVAL);
124         CHECK(n_fields, EINVAL);
125
126         for (i = 0; i < n_fields; i++) {
127                 struct rte_swx_field_params *f = &fields[i];
128                 int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0;
129                 uint32_t j;
130
131                 CHECK_NAME(f->name, EINVAL);
132                 CHECK(f->n_bits, EINVAL);
133                 CHECK((f->n_bits <= 64) || var_size, EINVAL);
134                 CHECK((f->n_bits & 7) == 0, EINVAL);
135
136                 for (j = 0; j < i; j++) {
137                         struct rte_swx_field_params *f_prev = &fields[j];
138
139                         CHECK(strcmp(f->name, f_prev->name), EINVAL);
140                 }
141         }
142
143         CHECK(!struct_type_find(p, name), EEXIST);
144
145         /* Node allocation. */
146         st = calloc(1, sizeof(struct struct_type));
147         CHECK(st, ENOMEM);
148
149         st->fields = calloc(n_fields, sizeof(struct field));
150         if (!st->fields) {
151                 free(st);
152                 CHECK(0, ENOMEM);
153         }
154
155         /* Node initialization. */
156         strcpy(st->name, name);
157         for (i = 0; i < n_fields; i++) {
158                 struct field *dst = &st->fields[i];
159                 struct rte_swx_field_params *src = &fields[i];
160                 int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0;
161
162                 strcpy(dst->name, src->name);
163                 dst->n_bits = src->n_bits;
164                 dst->offset = st->n_bits;
165                 dst->var_size = var_size;
166
167                 st->n_bits += src->n_bits;
168                 st->n_bits_min += var_size ? 0 : src->n_bits;
169         }
170         st->n_fields = n_fields;
171         st->var_size = last_field_has_variable_size;
172
173         /* Node add to tailq. */
174         TAILQ_INSERT_TAIL(&p->struct_types, st, node);
175
176         return 0;
177 }
178
179 static int
180 struct_build(struct rte_swx_pipeline *p)
181 {
182         uint32_t i;
183
184         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
185                 struct thread *t = &p->threads[i];
186
187                 t->structs = calloc(p->n_structs, sizeof(uint8_t *));
188                 CHECK(t->structs, ENOMEM);
189         }
190
191         return 0;
192 }
193
194 static void
195 struct_build_free(struct rte_swx_pipeline *p)
196 {
197         uint32_t i;
198
199         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
200                 struct thread *t = &p->threads[i];
201
202                 free(t->structs);
203                 t->structs = NULL;
204         }
205 }
206
207 static void
208 struct_free(struct rte_swx_pipeline *p)
209 {
210         struct_build_free(p);
211
212         /* Struct types. */
213         for ( ; ; ) {
214                 struct struct_type *elem;
215
216                 elem = TAILQ_FIRST(&p->struct_types);
217                 if (!elem)
218                         break;
219
220                 TAILQ_REMOVE(&p->struct_types, elem, node);
221                 free(elem->fields);
222                 free(elem);
223         }
224 }
225
226 /*
227  * Input port.
228  */
229 static struct port_in_type *
230 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
231 {
232         struct port_in_type *elem;
233
234         if (!name)
235                 return NULL;
236
237         TAILQ_FOREACH(elem, &p->port_in_types, node)
238                 if (strcmp(elem->name, name) == 0)
239                         return elem;
240
241         return NULL;
242 }
243
244 int
245 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
246                                        const char *name,
247                                        struct rte_swx_port_in_ops *ops)
248 {
249         struct port_in_type *elem;
250
251         CHECK(p, EINVAL);
252         CHECK_NAME(name, EINVAL);
253         CHECK(ops, EINVAL);
254         CHECK(ops->create, EINVAL);
255         CHECK(ops->free, EINVAL);
256         CHECK(ops->pkt_rx, EINVAL);
257         CHECK(ops->stats_read, EINVAL);
258
259         CHECK(!port_in_type_find(p, name), EEXIST);
260
261         /* Node allocation. */
262         elem = calloc(1, sizeof(struct port_in_type));
263         CHECK(elem, ENOMEM);
264
265         /* Node initialization. */
266         strcpy(elem->name, name);
267         memcpy(&elem->ops, ops, sizeof(*ops));
268
269         /* Node add to tailq. */
270         TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
271
272         return 0;
273 }
274
275 static struct port_in *
276 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
277 {
278         struct port_in *port;
279
280         TAILQ_FOREACH(port, &p->ports_in, node)
281                 if (port->id == port_id)
282                         return port;
283
284         return NULL;
285 }
286
287 int
288 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
289                                 uint32_t port_id,
290                                 const char *port_type_name,
291                                 void *args)
292 {
293         struct port_in_type *type = NULL;
294         struct port_in *port = NULL;
295         void *obj = NULL;
296
297         CHECK(p, EINVAL);
298
299         CHECK(!port_in_find(p, port_id), EINVAL);
300
301         CHECK_NAME(port_type_name, EINVAL);
302         type = port_in_type_find(p, port_type_name);
303         CHECK(type, EINVAL);
304
305         obj = type->ops.create(args);
306         CHECK(obj, ENODEV);
307
308         /* Node allocation. */
309         port = calloc(1, sizeof(struct port_in));
310         CHECK(port, ENOMEM);
311
312         /* Node initialization. */
313         port->type = type;
314         port->obj = obj;
315         port->id = port_id;
316
317         /* Node add to tailq. */
318         TAILQ_INSERT_TAIL(&p->ports_in, port, node);
319         if (p->n_ports_in < port_id + 1)
320                 p->n_ports_in = port_id + 1;
321
322         return 0;
323 }
324
325 static int
326 port_in_build(struct rte_swx_pipeline *p)
327 {
328         struct port_in *port;
329         uint32_t i;
330
331         CHECK(p->n_ports_in, EINVAL);
332         CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
333
334         for (i = 0; i < p->n_ports_in; i++)
335                 CHECK(port_in_find(p, i), EINVAL);
336
337         p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
338         CHECK(p->in, ENOMEM);
339
340         TAILQ_FOREACH(port, &p->ports_in, node) {
341                 struct port_in_runtime *in = &p->in[port->id];
342
343                 in->pkt_rx = port->type->ops.pkt_rx;
344                 in->obj = port->obj;
345         }
346
347         return 0;
348 }
349
350 static void
351 port_in_build_free(struct rte_swx_pipeline *p)
352 {
353         free(p->in);
354         p->in = NULL;
355 }
356
357 static void
358 port_in_free(struct rte_swx_pipeline *p)
359 {
360         port_in_build_free(p);
361
362         /* Input ports. */
363         for ( ; ; ) {
364                 struct port_in *port;
365
366                 port = TAILQ_FIRST(&p->ports_in);
367                 if (!port)
368                         break;
369
370                 TAILQ_REMOVE(&p->ports_in, port, node);
371                 port->type->ops.free(port->obj);
372                 free(port);
373         }
374
375         /* Input port types. */
376         for ( ; ; ) {
377                 struct port_in_type *elem;
378
379                 elem = TAILQ_FIRST(&p->port_in_types);
380                 if (!elem)
381                         break;
382
383                 TAILQ_REMOVE(&p->port_in_types, elem, node);
384                 free(elem);
385         }
386 }
387
388 /*
389  * Output port.
390  */
391 static struct port_out_type *
392 port_out_type_find(struct rte_swx_pipeline *p, const char *name)
393 {
394         struct port_out_type *elem;
395
396         if (!name)
397                 return NULL;
398
399         TAILQ_FOREACH(elem, &p->port_out_types, node)
400                 if (!strcmp(elem->name, name))
401                         return elem;
402
403         return NULL;
404 }
405
406 int
407 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
408                                         const char *name,
409                                         struct rte_swx_port_out_ops *ops)
410 {
411         struct port_out_type *elem;
412
413         CHECK(p, EINVAL);
414         CHECK_NAME(name, EINVAL);
415         CHECK(ops, EINVAL);
416         CHECK(ops->create, EINVAL);
417         CHECK(ops->free, EINVAL);
418         CHECK(ops->pkt_tx, EINVAL);
419         CHECK(ops->stats_read, EINVAL);
420
421         CHECK(!port_out_type_find(p, name), EEXIST);
422
423         /* Node allocation. */
424         elem = calloc(1, sizeof(struct port_out_type));
425         CHECK(elem, ENOMEM);
426
427         /* Node initialization. */
428         strcpy(elem->name, name);
429         memcpy(&elem->ops, ops, sizeof(*ops));
430
431         /* Node add to tailq. */
432         TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
433
434         return 0;
435 }
436
437 static struct port_out *
438 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
439 {
440         struct port_out *port;
441
442         TAILQ_FOREACH(port, &p->ports_out, node)
443                 if (port->id == port_id)
444                         return port;
445
446         return NULL;
447 }
448
449 int
450 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
451                                  uint32_t port_id,
452                                  const char *port_type_name,
453                                  void *args)
454 {
455         struct port_out_type *type = NULL;
456         struct port_out *port = NULL;
457         void *obj = NULL;
458
459         CHECK(p, EINVAL);
460
461         CHECK(!port_out_find(p, port_id), EINVAL);
462
463         CHECK_NAME(port_type_name, EINVAL);
464         type = port_out_type_find(p, port_type_name);
465         CHECK(type, EINVAL);
466
467         obj = type->ops.create(args);
468         CHECK(obj, ENODEV);
469
470         /* Node allocation. */
471         port = calloc(1, sizeof(struct port_out));
472         CHECK(port, ENOMEM);
473
474         /* Node initialization. */
475         port->type = type;
476         port->obj = obj;
477         port->id = port_id;
478
479         /* Node add to tailq. */
480         TAILQ_INSERT_TAIL(&p->ports_out, port, node);
481         if (p->n_ports_out < port_id + 1)
482                 p->n_ports_out = port_id + 1;
483
484         return 0;
485 }
486
487 static int
488 port_out_build(struct rte_swx_pipeline *p)
489 {
490         struct port_out *port;
491         uint32_t i;
492
493         CHECK(p->n_ports_out, EINVAL);
494
495         for (i = 0; i < p->n_ports_out; i++)
496                 CHECK(port_out_find(p, i), EINVAL);
497
498         p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
499         CHECK(p->out, ENOMEM);
500
501         TAILQ_FOREACH(port, &p->ports_out, node) {
502                 struct port_out_runtime *out = &p->out[port->id];
503
504                 out->pkt_tx = port->type->ops.pkt_tx;
505                 out->flush = port->type->ops.flush;
506                 out->obj = port->obj;
507         }
508
509         return 0;
510 }
511
512 static void
513 port_out_build_free(struct rte_swx_pipeline *p)
514 {
515         free(p->out);
516         p->out = NULL;
517 }
518
519 static void
520 port_out_free(struct rte_swx_pipeline *p)
521 {
522         port_out_build_free(p);
523
524         /* Output ports. */
525         for ( ; ; ) {
526                 struct port_out *port;
527
528                 port = TAILQ_FIRST(&p->ports_out);
529                 if (!port)
530                         break;
531
532                 TAILQ_REMOVE(&p->ports_out, port, node);
533                 port->type->ops.free(port->obj);
534                 free(port);
535         }
536
537         /* Output port types. */
538         for ( ; ; ) {
539                 struct port_out_type *elem;
540
541                 elem = TAILQ_FIRST(&p->port_out_types);
542                 if (!elem)
543                         break;
544
545                 TAILQ_REMOVE(&p->port_out_types, elem, node);
546                 free(elem);
547         }
548 }
549
550 /*
551  * Extern object.
552  */
553 static struct extern_type *
554 extern_type_find(struct rte_swx_pipeline *p, const char *name)
555 {
556         struct extern_type *elem;
557
558         TAILQ_FOREACH(elem, &p->extern_types, node)
559                 if (strcmp(elem->name, name) == 0)
560                         return elem;
561
562         return NULL;
563 }
564
565 static struct extern_type_member_func *
566 extern_type_member_func_find(struct extern_type *type, const char *name)
567 {
568         struct extern_type_member_func *elem;
569
570         TAILQ_FOREACH(elem, &type->funcs, node)
571                 if (strcmp(elem->name, name) == 0)
572                         return elem;
573
574         return NULL;
575 }
576
577 static struct extern_obj *
578 extern_obj_find(struct rte_swx_pipeline *p, const char *name)
579 {
580         struct extern_obj *elem;
581
582         TAILQ_FOREACH(elem, &p->extern_objs, node)
583                 if (strcmp(elem->name, name) == 0)
584                         return elem;
585
586         return NULL;
587 }
588
589 static struct extern_type_member_func *
590 extern_obj_member_func_parse(struct rte_swx_pipeline *p,
591                              const char *name,
592                              struct extern_obj **obj)
593 {
594         struct extern_obj *object;
595         struct extern_type_member_func *func;
596         char *object_name, *func_name;
597
598         if (name[0] != 'e' || name[1] != '.')
599                 return NULL;
600
601         object_name = strdup(&name[2]);
602         if (!object_name)
603                 return NULL;
604
605         func_name = strchr(object_name, '.');
606         if (!func_name) {
607                 free(object_name);
608                 return NULL;
609         }
610
611         *func_name = 0;
612         func_name++;
613
614         object = extern_obj_find(p, object_name);
615         if (!object) {
616                 free(object_name);
617                 return NULL;
618         }
619
620         func = extern_type_member_func_find(object->type, func_name);
621         if (!func) {
622                 free(object_name);
623                 return NULL;
624         }
625
626         if (obj)
627                 *obj = object;
628
629         free(object_name);
630         return func;
631 }
632
633 static struct field *
634 extern_obj_mailbox_field_parse(struct rte_swx_pipeline *p,
635                                const char *name,
636                                struct extern_obj **object)
637 {
638         struct extern_obj *obj;
639         struct field *f;
640         char *obj_name, *field_name;
641
642         if ((name[0] != 'e') || (name[1] != '.'))
643                 return NULL;
644
645         obj_name = strdup(&name[2]);
646         if (!obj_name)
647                 return NULL;
648
649         field_name = strchr(obj_name, '.');
650         if (!field_name) {
651                 free(obj_name);
652                 return NULL;
653         }
654
655         *field_name = 0;
656         field_name++;
657
658         obj = extern_obj_find(p, obj_name);
659         if (!obj) {
660                 free(obj_name);
661                 return NULL;
662         }
663
664         f = struct_type_field_find(obj->type->mailbox_struct_type, field_name);
665         if (!f) {
666                 free(obj_name);
667                 return NULL;
668         }
669
670         if (object)
671                 *object = obj;
672
673         free(obj_name);
674         return f;
675 }
676
677 int
678 rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p,
679         const char *name,
680         const char *mailbox_struct_type_name,
681         rte_swx_extern_type_constructor_t constructor,
682         rte_swx_extern_type_destructor_t destructor)
683 {
684         struct extern_type *elem;
685         struct struct_type *mailbox_struct_type;
686
687         CHECK(p, EINVAL);
688
689         CHECK_NAME(name, EINVAL);
690         CHECK(!extern_type_find(p, name), EEXIST);
691
692         CHECK_NAME(mailbox_struct_type_name, EINVAL);
693         mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
694         CHECK(mailbox_struct_type, EINVAL);
695         CHECK(!mailbox_struct_type->var_size, EINVAL);
696
697         CHECK(constructor, EINVAL);
698         CHECK(destructor, EINVAL);
699
700         /* Node allocation. */
701         elem = calloc(1, sizeof(struct extern_type));
702         CHECK(elem, ENOMEM);
703
704         /* Node initialization. */
705         strcpy(elem->name, name);
706         elem->mailbox_struct_type = mailbox_struct_type;
707         elem->constructor = constructor;
708         elem->destructor = destructor;
709         TAILQ_INIT(&elem->funcs);
710
711         /* Node add to tailq. */
712         TAILQ_INSERT_TAIL(&p->extern_types, elem, node);
713
714         return 0;
715 }
716
717 int
718 rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p,
719         const char *extern_type_name,
720         const char *name,
721         rte_swx_extern_type_member_func_t member_func)
722 {
723         struct extern_type *type;
724         struct extern_type_member_func *type_member;
725
726         CHECK(p, EINVAL);
727
728         CHECK_NAME(extern_type_name, EINVAL);
729         type = extern_type_find(p, extern_type_name);
730         CHECK(type, EINVAL);
731         CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC);
732
733         CHECK_NAME(name, EINVAL);
734         CHECK(!extern_type_member_func_find(type, name), EEXIST);
735
736         CHECK(member_func, EINVAL);
737
738         /* Node allocation. */
739         type_member = calloc(1, sizeof(struct extern_type_member_func));
740         CHECK(type_member, ENOMEM);
741
742         /* Node initialization. */
743         strcpy(type_member->name, name);
744         type_member->func = member_func;
745         type_member->id = type->n_funcs;
746
747         /* Node add to tailq. */
748         TAILQ_INSERT_TAIL(&type->funcs, type_member, node);
749         type->n_funcs++;
750
751         return 0;
752 }
753
754 int
755 rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p,
756                                       const char *extern_type_name,
757                                       const char *name,
758                                       const char *args)
759 {
760         struct extern_type *type;
761         struct extern_obj *obj;
762         void *obj_handle;
763
764         CHECK(p, EINVAL);
765
766         CHECK_NAME(extern_type_name, EINVAL);
767         type = extern_type_find(p, extern_type_name);
768         CHECK(type, EINVAL);
769
770         CHECK_NAME(name, EINVAL);
771         CHECK(!extern_obj_find(p, name), EEXIST);
772
773         /* Node allocation. */
774         obj = calloc(1, sizeof(struct extern_obj));
775         CHECK(obj, ENOMEM);
776
777         /* Object construction. */
778         obj_handle = type->constructor(args);
779         if (!obj_handle) {
780                 free(obj);
781                 CHECK(0, ENODEV);
782         }
783
784         /* Node initialization. */
785         strcpy(obj->name, name);
786         obj->type = type;
787         obj->obj = obj_handle;
788         obj->struct_id = p->n_structs;
789         obj->id = p->n_extern_objs;
790
791         /* Node add to tailq. */
792         TAILQ_INSERT_TAIL(&p->extern_objs, obj, node);
793         p->n_extern_objs++;
794         p->n_structs++;
795
796         return 0;
797 }
798
799 static int
800 extern_obj_build(struct rte_swx_pipeline *p)
801 {
802         uint32_t i;
803
804         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
805                 struct thread *t = &p->threads[i];
806                 struct extern_obj *obj;
807
808                 t->extern_objs = calloc(p->n_extern_objs,
809                                         sizeof(struct extern_obj_runtime));
810                 CHECK(t->extern_objs, ENOMEM);
811
812                 TAILQ_FOREACH(obj, &p->extern_objs, node) {
813                         struct extern_obj_runtime *r =
814                                 &t->extern_objs[obj->id];
815                         struct extern_type_member_func *func;
816                         uint32_t mailbox_size =
817                                 obj->type->mailbox_struct_type->n_bits / 8;
818
819                         r->obj = obj->obj;
820
821                         r->mailbox = calloc(1, mailbox_size);
822                         CHECK(r->mailbox, ENOMEM);
823
824                         TAILQ_FOREACH(func, &obj->type->funcs, node)
825                                 r->funcs[func->id] = func->func;
826
827                         t->structs[obj->struct_id] = r->mailbox;
828                 }
829         }
830
831         return 0;
832 }
833
834 static void
835 extern_obj_build_free(struct rte_swx_pipeline *p)
836 {
837         uint32_t i;
838
839         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
840                 struct thread *t = &p->threads[i];
841                 uint32_t j;
842
843                 if (!t->extern_objs)
844                         continue;
845
846                 for (j = 0; j < p->n_extern_objs; j++) {
847                         struct extern_obj_runtime *r = &t->extern_objs[j];
848
849                         free(r->mailbox);
850                 }
851
852                 free(t->extern_objs);
853                 t->extern_objs = NULL;
854         }
855 }
856
857 static void
858 extern_obj_free(struct rte_swx_pipeline *p)
859 {
860         extern_obj_build_free(p);
861
862         /* Extern objects. */
863         for ( ; ; ) {
864                 struct extern_obj *elem;
865
866                 elem = TAILQ_FIRST(&p->extern_objs);
867                 if (!elem)
868                         break;
869
870                 TAILQ_REMOVE(&p->extern_objs, elem, node);
871                 if (elem->obj)
872                         elem->type->destructor(elem->obj);
873                 free(elem);
874         }
875
876         /* Extern types. */
877         for ( ; ; ) {
878                 struct extern_type *elem;
879
880                 elem = TAILQ_FIRST(&p->extern_types);
881                 if (!elem)
882                         break;
883
884                 TAILQ_REMOVE(&p->extern_types, elem, node);
885
886                 for ( ; ; ) {
887                         struct extern_type_member_func *func;
888
889                         func = TAILQ_FIRST(&elem->funcs);
890                         if (!func)
891                                 break;
892
893                         TAILQ_REMOVE(&elem->funcs, func, node);
894                         free(func);
895                 }
896
897                 free(elem);
898         }
899 }
900
901 /*
902  * Extern function.
903  */
904 static struct extern_func *
905 extern_func_find(struct rte_swx_pipeline *p, const char *name)
906 {
907         struct extern_func *elem;
908
909         TAILQ_FOREACH(elem, &p->extern_funcs, node)
910                 if (strcmp(elem->name, name) == 0)
911                         return elem;
912
913         return NULL;
914 }
915
916 static struct extern_func *
917 extern_func_parse(struct rte_swx_pipeline *p,
918                   const char *name)
919 {
920         if (name[0] != 'f' || name[1] != '.')
921                 return NULL;
922
923         return extern_func_find(p, &name[2]);
924 }
925
926 static struct field *
927 extern_func_mailbox_field_parse(struct rte_swx_pipeline *p,
928                                 const char *name,
929                                 struct extern_func **function)
930 {
931         struct extern_func *func;
932         struct field *f;
933         char *func_name, *field_name;
934
935         if ((name[0] != 'f') || (name[1] != '.'))
936                 return NULL;
937
938         func_name = strdup(&name[2]);
939         if (!func_name)
940                 return NULL;
941
942         field_name = strchr(func_name, '.');
943         if (!field_name) {
944                 free(func_name);
945                 return NULL;
946         }
947
948         *field_name = 0;
949         field_name++;
950
951         func = extern_func_find(p, func_name);
952         if (!func) {
953                 free(func_name);
954                 return NULL;
955         }
956
957         f = struct_type_field_find(func->mailbox_struct_type, field_name);
958         if (!f) {
959                 free(func_name);
960                 return NULL;
961         }
962
963         if (function)
964                 *function = func;
965
966         free(func_name);
967         return f;
968 }
969
970 int
971 rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p,
972                                       const char *name,
973                                       const char *mailbox_struct_type_name,
974                                       rte_swx_extern_func_t func)
975 {
976         struct extern_func *f;
977         struct struct_type *mailbox_struct_type;
978
979         CHECK(p, EINVAL);
980
981         CHECK_NAME(name, EINVAL);
982         CHECK(!extern_func_find(p, name), EEXIST);
983
984         CHECK_NAME(mailbox_struct_type_name, EINVAL);
985         mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
986         CHECK(mailbox_struct_type, EINVAL);
987         CHECK(!mailbox_struct_type->var_size, EINVAL);
988
989         CHECK(func, EINVAL);
990
991         /* Node allocation. */
992         f = calloc(1, sizeof(struct extern_func));
993         CHECK(func, ENOMEM);
994
995         /* Node initialization. */
996         strcpy(f->name, name);
997         f->mailbox_struct_type = mailbox_struct_type;
998         f->func = func;
999         f->struct_id = p->n_structs;
1000         f->id = p->n_extern_funcs;
1001
1002         /* Node add to tailq. */
1003         TAILQ_INSERT_TAIL(&p->extern_funcs, f, node);
1004         p->n_extern_funcs++;
1005         p->n_structs++;
1006
1007         return 0;
1008 }
1009
1010 static int
1011 extern_func_build(struct rte_swx_pipeline *p)
1012 {
1013         uint32_t i;
1014
1015         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1016                 struct thread *t = &p->threads[i];
1017                 struct extern_func *func;
1018
1019                 /* Memory allocation. */
1020                 t->extern_funcs = calloc(p->n_extern_funcs,
1021                                          sizeof(struct extern_func_runtime));
1022                 CHECK(t->extern_funcs, ENOMEM);
1023
1024                 /* Extern function. */
1025                 TAILQ_FOREACH(func, &p->extern_funcs, node) {
1026                         struct extern_func_runtime *r =
1027                                 &t->extern_funcs[func->id];
1028                         uint32_t mailbox_size =
1029                                 func->mailbox_struct_type->n_bits / 8;
1030
1031                         r->func = func->func;
1032
1033                         r->mailbox = calloc(1, mailbox_size);
1034                         CHECK(r->mailbox, ENOMEM);
1035
1036                         t->structs[func->struct_id] = r->mailbox;
1037                 }
1038         }
1039
1040         return 0;
1041 }
1042
1043 static void
1044 extern_func_build_free(struct rte_swx_pipeline *p)
1045 {
1046         uint32_t i;
1047
1048         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1049                 struct thread *t = &p->threads[i];
1050                 uint32_t j;
1051
1052                 if (!t->extern_funcs)
1053                         continue;
1054
1055                 for (j = 0; j < p->n_extern_funcs; j++) {
1056                         struct extern_func_runtime *r = &t->extern_funcs[j];
1057
1058                         free(r->mailbox);
1059                 }
1060
1061                 free(t->extern_funcs);
1062                 t->extern_funcs = NULL;
1063         }
1064 }
1065
1066 static void
1067 extern_func_free(struct rte_swx_pipeline *p)
1068 {
1069         extern_func_build_free(p);
1070
1071         for ( ; ; ) {
1072                 struct extern_func *elem;
1073
1074                 elem = TAILQ_FIRST(&p->extern_funcs);
1075                 if (!elem)
1076                         break;
1077
1078                 TAILQ_REMOVE(&p->extern_funcs, elem, node);
1079                 free(elem);
1080         }
1081 }
1082
1083 /*
1084  * Header.
1085  */
1086 static struct header *
1087 header_find(struct rte_swx_pipeline *p, const char *name)
1088 {
1089         struct header *elem;
1090
1091         TAILQ_FOREACH(elem, &p->headers, node)
1092                 if (strcmp(elem->name, name) == 0)
1093                         return elem;
1094
1095         return NULL;
1096 }
1097
1098 static struct header *
1099 header_find_by_struct_id(struct rte_swx_pipeline *p, uint32_t struct_id)
1100 {
1101         struct header *elem;
1102
1103         TAILQ_FOREACH(elem, &p->headers, node)
1104                 if (elem->struct_id == struct_id)
1105                         return elem;
1106
1107         return NULL;
1108 }
1109
1110 static struct header *
1111 header_parse(struct rte_swx_pipeline *p,
1112              const char *name)
1113 {
1114         if (name[0] != 'h' || name[1] != '.')
1115                 return NULL;
1116
1117         return header_find(p, &name[2]);
1118 }
1119
1120 static struct field *
1121 header_field_parse(struct rte_swx_pipeline *p,
1122                    const char *name,
1123                    struct header **header)
1124 {
1125         struct header *h;
1126         struct field *f;
1127         char *header_name, *field_name;
1128
1129         if ((name[0] != 'h') || (name[1] != '.'))
1130                 return NULL;
1131
1132         header_name = strdup(&name[2]);
1133         if (!header_name)
1134                 return NULL;
1135
1136         field_name = strchr(header_name, '.');
1137         if (!field_name) {
1138                 free(header_name);
1139                 return NULL;
1140         }
1141
1142         *field_name = 0;
1143         field_name++;
1144
1145         h = header_find(p, header_name);
1146         if (!h) {
1147                 free(header_name);
1148                 return NULL;
1149         }
1150
1151         f = struct_type_field_find(h->st, field_name);
1152         if (!f) {
1153                 free(header_name);
1154                 return NULL;
1155         }
1156
1157         if (header)
1158                 *header = h;
1159
1160         free(header_name);
1161         return f;
1162 }
1163
1164 int
1165 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
1166                                         const char *name,
1167                                         const char *struct_type_name)
1168 {
1169         struct struct_type *st;
1170         struct header *h;
1171         size_t n_headers_max;
1172
1173         CHECK(p, EINVAL);
1174         CHECK_NAME(name, EINVAL);
1175         CHECK_NAME(struct_type_name, EINVAL);
1176
1177         CHECK(!header_find(p, name), EEXIST);
1178
1179         st = struct_type_find(p, struct_type_name);
1180         CHECK(st, EINVAL);
1181
1182         n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
1183         CHECK(p->n_headers < n_headers_max, ENOSPC);
1184
1185         /* Node allocation. */
1186         h = calloc(1, sizeof(struct header));
1187         CHECK(h, ENOMEM);
1188
1189         /* Node initialization. */
1190         strcpy(h->name, name);
1191         h->st = st;
1192         h->struct_id = p->n_structs;
1193         h->id = p->n_headers;
1194
1195         /* Node add to tailq. */
1196         TAILQ_INSERT_TAIL(&p->headers, h, node);
1197         p->n_headers++;
1198         p->n_structs++;
1199
1200         return 0;
1201 }
1202
1203 static int
1204 header_build(struct rte_swx_pipeline *p)
1205 {
1206         struct header *h;
1207         uint32_t n_bytes = 0, i;
1208
1209         TAILQ_FOREACH(h, &p->headers, node) {
1210                 n_bytes += h->st->n_bits / 8;
1211         }
1212
1213         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1214                 struct thread *t = &p->threads[i];
1215                 uint32_t offset = 0;
1216
1217                 t->headers = calloc(p->n_headers,
1218                                     sizeof(struct header_runtime));
1219                 CHECK(t->headers, ENOMEM);
1220
1221                 t->headers_out = calloc(p->n_headers,
1222                                         sizeof(struct header_out_runtime));
1223                 CHECK(t->headers_out, ENOMEM);
1224
1225                 t->header_storage = calloc(1, n_bytes);
1226                 CHECK(t->header_storage, ENOMEM);
1227
1228                 t->header_out_storage = calloc(1, n_bytes);
1229                 CHECK(t->header_out_storage, ENOMEM);
1230
1231                 TAILQ_FOREACH(h, &p->headers, node) {
1232                         uint8_t *header_storage;
1233                         uint32_t n_bytes =  h->st->n_bits / 8;
1234
1235                         header_storage = &t->header_storage[offset];
1236                         offset += n_bytes;
1237
1238                         t->headers[h->id].ptr0 = header_storage;
1239                         t->headers[h->id].n_bytes = n_bytes;
1240
1241                         t->structs[h->struct_id] = header_storage;
1242                 }
1243         }
1244
1245         return 0;
1246 }
1247
1248 static void
1249 header_build_free(struct rte_swx_pipeline *p)
1250 {
1251         uint32_t i;
1252
1253         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1254                 struct thread *t = &p->threads[i];
1255
1256                 free(t->headers_out);
1257                 t->headers_out = NULL;
1258
1259                 free(t->headers);
1260                 t->headers = NULL;
1261
1262                 free(t->header_out_storage);
1263                 t->header_out_storage = NULL;
1264
1265                 free(t->header_storage);
1266                 t->header_storage = NULL;
1267         }
1268 }
1269
1270 static void
1271 header_free(struct rte_swx_pipeline *p)
1272 {
1273         header_build_free(p);
1274
1275         for ( ; ; ) {
1276                 struct header *elem;
1277
1278                 elem = TAILQ_FIRST(&p->headers);
1279                 if (!elem)
1280                         break;
1281
1282                 TAILQ_REMOVE(&p->headers, elem, node);
1283                 free(elem);
1284         }
1285 }
1286
1287 /*
1288  * Meta-data.
1289  */
1290 static struct field *
1291 metadata_field_parse(struct rte_swx_pipeline *p, const char *name)
1292 {
1293         if (!p->metadata_st)
1294                 return NULL;
1295
1296         if (name[0] != 'm' || name[1] != '.')
1297                 return NULL;
1298
1299         return struct_type_field_find(p->metadata_st, &name[2]);
1300 }
1301
1302 int
1303 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
1304                                           const char *struct_type_name)
1305 {
1306         struct struct_type *st = NULL;
1307
1308         CHECK(p, EINVAL);
1309
1310         CHECK_NAME(struct_type_name, EINVAL);
1311         st  = struct_type_find(p, struct_type_name);
1312         CHECK(st, EINVAL);
1313         CHECK(!st->var_size, EINVAL);
1314         CHECK(!p->metadata_st, EINVAL);
1315
1316         p->metadata_st = st;
1317         p->metadata_struct_id = p->n_structs;
1318
1319         p->n_structs++;
1320
1321         return 0;
1322 }
1323
1324 static int
1325 metadata_build(struct rte_swx_pipeline *p)
1326 {
1327         uint32_t n_bytes = p->metadata_st->n_bits / 8;
1328         uint32_t i;
1329
1330         /* Thread-level initialization. */
1331         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1332                 struct thread *t = &p->threads[i];
1333                 uint8_t *metadata;
1334
1335                 metadata = calloc(1, n_bytes);
1336                 CHECK(metadata, ENOMEM);
1337
1338                 t->metadata = metadata;
1339                 t->structs[p->metadata_struct_id] = metadata;
1340         }
1341
1342         return 0;
1343 }
1344
1345 static void
1346 metadata_build_free(struct rte_swx_pipeline *p)
1347 {
1348         uint32_t i;
1349
1350         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1351                 struct thread *t = &p->threads[i];
1352
1353                 free(t->metadata);
1354                 t->metadata = NULL;
1355         }
1356 }
1357
1358 static void
1359 metadata_free(struct rte_swx_pipeline *p)
1360 {
1361         metadata_build_free(p);
1362 }
1363
1364 /*
1365  * Instruction.
1366  */
1367 static int
1368 instruction_is_tx(enum instruction_type type)
1369 {
1370         switch (type) {
1371         case INSTR_TX:
1372         case INSTR_TX_I:
1373                 return 1;
1374
1375         default:
1376                 return 0;
1377         }
1378 }
1379
1380 static int
1381 instruction_does_tx(struct instruction *instr)
1382 {
1383         switch (instr->type) {
1384         case INSTR_TX:
1385         case INSTR_TX_I:
1386         case INSTR_HDR_EMIT_TX:
1387         case INSTR_HDR_EMIT2_TX:
1388         case INSTR_HDR_EMIT3_TX:
1389         case INSTR_HDR_EMIT4_TX:
1390         case INSTR_HDR_EMIT5_TX:
1391         case INSTR_HDR_EMIT6_TX:
1392         case INSTR_HDR_EMIT7_TX:
1393         case INSTR_HDR_EMIT8_TX:
1394                 return 1;
1395         default:
1396                 return 0;
1397         }
1398 }
1399
1400 static int
1401 instruction_is_jmp(struct instruction *instr)
1402 {
1403         switch (instr->type) {
1404         case INSTR_JMP:
1405         case INSTR_JMP_VALID:
1406         case INSTR_JMP_INVALID:
1407         case INSTR_JMP_HIT:
1408         case INSTR_JMP_MISS:
1409         case INSTR_JMP_ACTION_HIT:
1410         case INSTR_JMP_ACTION_MISS:
1411         case INSTR_JMP_EQ:
1412         case INSTR_JMP_EQ_MH:
1413         case INSTR_JMP_EQ_HM:
1414         case INSTR_JMP_EQ_HH:
1415         case INSTR_JMP_EQ_I:
1416         case INSTR_JMP_NEQ:
1417         case INSTR_JMP_NEQ_MH:
1418         case INSTR_JMP_NEQ_HM:
1419         case INSTR_JMP_NEQ_HH:
1420         case INSTR_JMP_NEQ_I:
1421         case INSTR_JMP_LT:
1422         case INSTR_JMP_LT_MH:
1423         case INSTR_JMP_LT_HM:
1424         case INSTR_JMP_LT_HH:
1425         case INSTR_JMP_LT_MI:
1426         case INSTR_JMP_LT_HI:
1427         case INSTR_JMP_GT:
1428         case INSTR_JMP_GT_MH:
1429         case INSTR_JMP_GT_HM:
1430         case INSTR_JMP_GT_HH:
1431         case INSTR_JMP_GT_MI:
1432         case INSTR_JMP_GT_HI:
1433                 return 1;
1434
1435         default:
1436                 return 0;
1437         }
1438 }
1439
1440 static int
1441 instruction_does_thread_yield(struct instruction *instr)
1442 {
1443         switch (instr->type) {
1444         case INSTR_RX:
1445         case INSTR_TABLE:
1446         case INSTR_TABLE_AF:
1447         case INSTR_SELECTOR:
1448         case INSTR_LEARNER:
1449         case INSTR_LEARNER_AF:
1450         case INSTR_EXTERN_OBJ:
1451         case INSTR_EXTERN_FUNC:
1452                 return 1;
1453         default:
1454                 return 0;
1455         }
1456 }
1457
1458 static struct field *
1459 action_field_parse(struct action *action, const char *name);
1460
1461 static struct field *
1462 struct_field_parse(struct rte_swx_pipeline *p,
1463                    struct action *action,
1464                    const char *name,
1465                    uint32_t *struct_id)
1466 {
1467         struct field *f;
1468
1469         switch (name[0]) {
1470         case 'h':
1471         {
1472                 struct header *header;
1473
1474                 f = header_field_parse(p, name, &header);
1475                 if (!f)
1476                         return NULL;
1477
1478                 *struct_id = header->struct_id;
1479                 return f;
1480         }
1481
1482         case 'm':
1483         {
1484                 f = metadata_field_parse(p, name);
1485                 if (!f)
1486                         return NULL;
1487
1488                 *struct_id = p->metadata_struct_id;
1489                 return f;
1490         }
1491
1492         case 't':
1493         {
1494                 if (!action)
1495                         return NULL;
1496
1497                 f = action_field_parse(action, name);
1498                 if (!f)
1499                         return NULL;
1500
1501                 *struct_id = 0;
1502                 return f;
1503         }
1504
1505         case 'e':
1506         {
1507                 struct extern_obj *obj;
1508
1509                 f = extern_obj_mailbox_field_parse(p, name, &obj);
1510                 if (!f)
1511                         return NULL;
1512
1513                 *struct_id = obj->struct_id;
1514                 return f;
1515         }
1516
1517         case 'f':
1518         {
1519                 struct extern_func *func;
1520
1521                 f = extern_func_mailbox_field_parse(p, name, &func);
1522                 if (!f)
1523                         return NULL;
1524
1525                 *struct_id = func->struct_id;
1526                 return f;
1527         }
1528
1529         default:
1530                 return NULL;
1531         }
1532 }
1533
1534 /*
1535  * rx.
1536  */
1537 static int
1538 instr_rx_translate(struct rte_swx_pipeline *p,
1539                    struct action *action,
1540                    char **tokens,
1541                    int n_tokens,
1542                    struct instruction *instr,
1543                    struct instruction_data *data __rte_unused)
1544 {
1545         struct field *f;
1546
1547         CHECK(!action, EINVAL);
1548         CHECK(n_tokens == 2, EINVAL);
1549
1550         f = metadata_field_parse(p, tokens[1]);
1551         CHECK(f, EINVAL);
1552
1553         instr->type = INSTR_RX;
1554         instr->io.io.offset = f->offset / 8;
1555         instr->io.io.n_bits = f->n_bits;
1556         return 0;
1557 }
1558
1559 /*
1560  * tx.
1561  */
1562 static int
1563 instr_tx_translate(struct rte_swx_pipeline *p,
1564                    struct action *action __rte_unused,
1565                    char **tokens,
1566                    int n_tokens,
1567                    struct instruction *instr,
1568                    struct instruction_data *data __rte_unused)
1569 {
1570         char *port = tokens[1];
1571         struct field *f;
1572         uint32_t port_val;
1573
1574         CHECK(n_tokens == 2, EINVAL);
1575
1576         f = metadata_field_parse(p, port);
1577         if (f) {
1578                 instr->type = INSTR_TX;
1579                 instr->io.io.offset = f->offset / 8;
1580                 instr->io.io.n_bits = f->n_bits;
1581                 return 0;
1582         }
1583
1584         /* TX_I. */
1585         port_val = strtoul(port, &port, 0);
1586         CHECK(!port[0], EINVAL);
1587
1588         instr->type = INSTR_TX_I;
1589         instr->io.io.val = port_val;
1590         return 0;
1591 }
1592
1593 static int
1594 instr_drop_translate(struct rte_swx_pipeline *p,
1595                      struct action *action __rte_unused,
1596                      char **tokens __rte_unused,
1597                      int n_tokens,
1598                      struct instruction *instr,
1599                      struct instruction_data *data __rte_unused)
1600 {
1601         CHECK(n_tokens == 1, EINVAL);
1602
1603         /* TX_I. */
1604         instr->type = INSTR_TX_I;
1605         instr->io.io.val = p->n_ports_out - 1;
1606         return 0;
1607 }
1608
1609 static inline void
1610 instr_tx_exec(struct rte_swx_pipeline *p)
1611 {
1612         struct thread *t = &p->threads[p->thread_id];
1613         struct instruction *ip = t->ip;
1614
1615         __instr_tx_exec(p, t, ip);
1616
1617         /* Thread. */
1618         thread_ip_reset(p, t);
1619         instr_rx_exec(p);
1620 }
1621
1622 static inline void
1623 instr_tx_i_exec(struct rte_swx_pipeline *p)
1624 {
1625         struct thread *t = &p->threads[p->thread_id];
1626         struct instruction *ip = t->ip;
1627
1628         __instr_tx_i_exec(p, t, ip);
1629
1630         /* Thread. */
1631         thread_ip_reset(p, t);
1632         instr_rx_exec(p);
1633 }
1634
1635 /*
1636  * extract.
1637  */
1638 static int
1639 instr_hdr_extract_translate(struct rte_swx_pipeline *p,
1640                             struct action *action,
1641                             char **tokens,
1642                             int n_tokens,
1643                             struct instruction *instr,
1644                             struct instruction_data *data __rte_unused)
1645 {
1646         struct header *h;
1647
1648         CHECK(!action, EINVAL);
1649         CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL);
1650
1651         h = header_parse(p, tokens[1]);
1652         CHECK(h, EINVAL);
1653
1654         if (n_tokens == 2) {
1655                 CHECK(!h->st->var_size, EINVAL);
1656
1657                 instr->type = INSTR_HDR_EXTRACT;
1658                 instr->io.hdr.header_id[0] = h->id;
1659                 instr->io.hdr.struct_id[0] = h->struct_id;
1660                 instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
1661         } else {
1662                 struct field *mf;
1663
1664                 CHECK(h->st->var_size, EINVAL);
1665
1666                 mf = metadata_field_parse(p, tokens[2]);
1667                 CHECK(mf, EINVAL);
1668                 CHECK(!mf->var_size, EINVAL);
1669
1670                 instr->type = INSTR_HDR_EXTRACT_M;
1671                 instr->io.io.offset = mf->offset / 8;
1672                 instr->io.io.n_bits = mf->n_bits;
1673                 instr->io.hdr.header_id[0] = h->id;
1674                 instr->io.hdr.struct_id[0] = h->struct_id;
1675                 instr->io.hdr.n_bytes[0] = h->st->n_bits_min / 8;
1676         }
1677
1678         return 0;
1679 }
1680
1681 static int
1682 instr_hdr_lookahead_translate(struct rte_swx_pipeline *p,
1683                               struct action *action,
1684                               char **tokens,
1685                               int n_tokens,
1686                               struct instruction *instr,
1687                               struct instruction_data *data __rte_unused)
1688 {
1689         struct header *h;
1690
1691         CHECK(!action, EINVAL);
1692         CHECK(n_tokens == 2, EINVAL);
1693
1694         h = header_parse(p, tokens[1]);
1695         CHECK(h, EINVAL);
1696         CHECK(!h->st->var_size, EINVAL);
1697
1698         instr->type = INSTR_HDR_LOOKAHEAD;
1699         instr->io.hdr.header_id[0] = h->id;
1700         instr->io.hdr.struct_id[0] = h->struct_id;
1701         instr->io.hdr.n_bytes[0] = 0; /* Unused. */
1702
1703         return 0;
1704 }
1705
1706 static inline void
1707 instr_hdr_extract_exec(struct rte_swx_pipeline *p)
1708 {
1709         struct thread *t = &p->threads[p->thread_id];
1710         struct instruction *ip = t->ip;
1711
1712         __instr_hdr_extract_exec(p, t, ip);
1713
1714         /* Thread. */
1715         thread_ip_inc(p);
1716 }
1717
1718 static inline void
1719 instr_hdr_extract2_exec(struct rte_swx_pipeline *p)
1720 {
1721         struct thread *t = &p->threads[p->thread_id];
1722         struct instruction *ip = t->ip;
1723
1724         __instr_hdr_extract2_exec(p, t, ip);
1725
1726         /* Thread. */
1727         thread_ip_inc(p);
1728 }
1729
1730 static inline void
1731 instr_hdr_extract3_exec(struct rte_swx_pipeline *p)
1732 {
1733         struct thread *t = &p->threads[p->thread_id];
1734         struct instruction *ip = t->ip;
1735
1736         __instr_hdr_extract3_exec(p, t, ip);
1737
1738         /* Thread. */
1739         thread_ip_inc(p);
1740 }
1741
1742 static inline void
1743 instr_hdr_extract4_exec(struct rte_swx_pipeline *p)
1744 {
1745         struct thread *t = &p->threads[p->thread_id];
1746         struct instruction *ip = t->ip;
1747
1748         __instr_hdr_extract4_exec(p, t, ip);
1749
1750         /* Thread. */
1751         thread_ip_inc(p);
1752 }
1753
1754 static inline void
1755 instr_hdr_extract5_exec(struct rte_swx_pipeline *p)
1756 {
1757         struct thread *t = &p->threads[p->thread_id];
1758         struct instruction *ip = t->ip;
1759
1760         __instr_hdr_extract5_exec(p, t, ip);
1761
1762         /* Thread. */
1763         thread_ip_inc(p);
1764 }
1765
1766 static inline void
1767 instr_hdr_extract6_exec(struct rte_swx_pipeline *p)
1768 {
1769         struct thread *t = &p->threads[p->thread_id];
1770         struct instruction *ip = t->ip;
1771
1772         __instr_hdr_extract6_exec(p, t, ip);
1773
1774         /* Thread. */
1775         thread_ip_inc(p);
1776 }
1777
1778 static inline void
1779 instr_hdr_extract7_exec(struct rte_swx_pipeline *p)
1780 {
1781         struct thread *t = &p->threads[p->thread_id];
1782         struct instruction *ip = t->ip;
1783
1784         __instr_hdr_extract7_exec(p, t, ip);
1785
1786         /* Thread. */
1787         thread_ip_inc(p);
1788 }
1789
1790 static inline void
1791 instr_hdr_extract8_exec(struct rte_swx_pipeline *p)
1792 {
1793         struct thread *t = &p->threads[p->thread_id];
1794         struct instruction *ip = t->ip;
1795
1796         __instr_hdr_extract8_exec(p, t, ip);
1797
1798         /* Thread. */
1799         thread_ip_inc(p);
1800 }
1801
1802 static inline void
1803 instr_hdr_extract_m_exec(struct rte_swx_pipeline *p)
1804 {
1805         struct thread *t = &p->threads[p->thread_id];
1806         struct instruction *ip = t->ip;
1807
1808         __instr_hdr_extract_m_exec(p, t, ip);
1809
1810         /* Thread. */
1811         thread_ip_inc(p);
1812 }
1813
1814 static inline void
1815 instr_hdr_lookahead_exec(struct rte_swx_pipeline *p)
1816 {
1817         struct thread *t = &p->threads[p->thread_id];
1818         struct instruction *ip = t->ip;
1819
1820         __instr_hdr_lookahead_exec(p, t, ip);
1821
1822         /* Thread. */
1823         thread_ip_inc(p);
1824 }
1825
1826 /*
1827  * emit.
1828  */
1829 static int
1830 instr_hdr_emit_translate(struct rte_swx_pipeline *p,
1831                          struct action *action __rte_unused,
1832                          char **tokens,
1833                          int n_tokens,
1834                          struct instruction *instr,
1835                          struct instruction_data *data __rte_unused)
1836 {
1837         struct header *h;
1838
1839         CHECK(n_tokens == 2, EINVAL);
1840
1841         h = header_parse(p, tokens[1]);
1842         CHECK(h, EINVAL);
1843
1844         instr->type = INSTR_HDR_EMIT;
1845         instr->io.hdr.header_id[0] = h->id;
1846         instr->io.hdr.struct_id[0] = h->struct_id;
1847         instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
1848         return 0;
1849 }
1850
1851 static inline void
1852 instr_hdr_emit_exec(struct rte_swx_pipeline *p)
1853 {
1854         struct thread *t = &p->threads[p->thread_id];
1855         struct instruction *ip = t->ip;
1856
1857         __instr_hdr_emit_exec(p, t, ip);
1858
1859         /* Thread. */
1860         thread_ip_inc(p);
1861 }
1862
1863 static inline void
1864 instr_hdr_emit_tx_exec(struct rte_swx_pipeline *p)
1865 {
1866         struct thread *t = &p->threads[p->thread_id];
1867         struct instruction *ip = t->ip;
1868
1869         __instr_hdr_emit_tx_exec(p, t, ip);
1870
1871         /* Thread. */
1872         thread_ip_reset(p, t);
1873         instr_rx_exec(p);
1874 }
1875
1876 static inline void
1877 instr_hdr_emit2_tx_exec(struct rte_swx_pipeline *p)
1878 {
1879         struct thread *t = &p->threads[p->thread_id];
1880         struct instruction *ip = t->ip;
1881
1882         __instr_hdr_emit2_tx_exec(p, t, ip);
1883
1884         /* Thread. */
1885         thread_ip_reset(p, t);
1886         instr_rx_exec(p);
1887 }
1888
1889 static inline void
1890 instr_hdr_emit3_tx_exec(struct rte_swx_pipeline *p)
1891 {
1892         struct thread *t = &p->threads[p->thread_id];
1893         struct instruction *ip = t->ip;
1894
1895         __instr_hdr_emit3_tx_exec(p, t, ip);
1896
1897         /* Thread. */
1898         thread_ip_reset(p, t);
1899         instr_rx_exec(p);
1900 }
1901
1902 static inline void
1903 instr_hdr_emit4_tx_exec(struct rte_swx_pipeline *p)
1904 {
1905         struct thread *t = &p->threads[p->thread_id];
1906         struct instruction *ip = t->ip;
1907
1908         __instr_hdr_emit4_tx_exec(p, t, ip);
1909
1910         /* Thread. */
1911         thread_ip_reset(p, t);
1912         instr_rx_exec(p);
1913 }
1914
1915 static inline void
1916 instr_hdr_emit5_tx_exec(struct rte_swx_pipeline *p)
1917 {
1918         struct thread *t = &p->threads[p->thread_id];
1919         struct instruction *ip = t->ip;
1920
1921         __instr_hdr_emit5_tx_exec(p, t, ip);
1922
1923         /* Thread. */
1924         thread_ip_reset(p, t);
1925         instr_rx_exec(p);
1926 }
1927
1928 static inline void
1929 instr_hdr_emit6_tx_exec(struct rte_swx_pipeline *p)
1930 {
1931         struct thread *t = &p->threads[p->thread_id];
1932         struct instruction *ip = t->ip;
1933
1934         __instr_hdr_emit6_tx_exec(p, t, ip);
1935
1936         /* Thread. */
1937         thread_ip_reset(p, t);
1938         instr_rx_exec(p);
1939 }
1940
1941 static inline void
1942 instr_hdr_emit7_tx_exec(struct rte_swx_pipeline *p)
1943 {
1944         struct thread *t = &p->threads[p->thread_id];
1945         struct instruction *ip = t->ip;
1946
1947         __instr_hdr_emit7_tx_exec(p, t, ip);
1948
1949         /* Thread. */
1950         thread_ip_reset(p, t);
1951         instr_rx_exec(p);
1952 }
1953
1954 static inline void
1955 instr_hdr_emit8_tx_exec(struct rte_swx_pipeline *p)
1956 {
1957         struct thread *t = &p->threads[p->thread_id];
1958         struct instruction *ip = t->ip;
1959
1960         __instr_hdr_emit8_tx_exec(p, t, ip);
1961
1962         /* Thread. */
1963         thread_ip_reset(p, t);
1964         instr_rx_exec(p);
1965 }
1966
1967 /*
1968  * validate.
1969  */
1970 static int
1971 instr_hdr_validate_translate(struct rte_swx_pipeline *p,
1972                              struct action *action __rte_unused,
1973                              char **tokens,
1974                              int n_tokens,
1975                              struct instruction *instr,
1976                              struct instruction_data *data __rte_unused)
1977 {
1978         struct header *h;
1979
1980         CHECK(n_tokens == 2, EINVAL);
1981
1982         h = header_parse(p, tokens[1]);
1983         CHECK(h, EINVAL);
1984
1985         instr->type = INSTR_HDR_VALIDATE;
1986         instr->valid.header_id = h->id;
1987         return 0;
1988 }
1989
1990 static inline void
1991 instr_hdr_validate_exec(struct rte_swx_pipeline *p)
1992 {
1993         struct thread *t = &p->threads[p->thread_id];
1994         struct instruction *ip = t->ip;
1995
1996         __instr_hdr_validate_exec(p, t, ip);
1997
1998         /* Thread. */
1999         thread_ip_inc(p);
2000 }
2001
2002 /*
2003  * invalidate.
2004  */
2005 static int
2006 instr_hdr_invalidate_translate(struct rte_swx_pipeline *p,
2007                                struct action *action __rte_unused,
2008                                char **tokens,
2009                                int n_tokens,
2010                                struct instruction *instr,
2011                                struct instruction_data *data __rte_unused)
2012 {
2013         struct header *h;
2014
2015         CHECK(n_tokens == 2, EINVAL);
2016
2017         h = header_parse(p, tokens[1]);
2018         CHECK(h, EINVAL);
2019
2020         instr->type = INSTR_HDR_INVALIDATE;
2021         instr->valid.header_id = h->id;
2022         return 0;
2023 }
2024
2025 static inline void
2026 instr_hdr_invalidate_exec(struct rte_swx_pipeline *p)
2027 {
2028         struct thread *t = &p->threads[p->thread_id];
2029         struct instruction *ip = t->ip;
2030
2031         __instr_hdr_invalidate_exec(p, t, ip);
2032
2033         /* Thread. */
2034         thread_ip_inc(p);
2035 }
2036
2037 /*
2038  * table.
2039  */
2040 static struct table *
2041 table_find(struct rte_swx_pipeline *p, const char *name);
2042
2043 static struct selector *
2044 selector_find(struct rte_swx_pipeline *p, const char *name);
2045
2046 static struct learner *
2047 learner_find(struct rte_swx_pipeline *p, const char *name);
2048
2049 static int
2050 instr_table_translate(struct rte_swx_pipeline *p,
2051                       struct action *action,
2052                       char **tokens,
2053                       int n_tokens,
2054                       struct instruction *instr,
2055                       struct instruction_data *data __rte_unused)
2056 {
2057         struct table *t;
2058         struct selector *s;
2059         struct learner *l;
2060
2061         CHECK(!action, EINVAL);
2062         CHECK(n_tokens == 2, EINVAL);
2063
2064         t = table_find(p, tokens[1]);
2065         if (t) {
2066                 instr->type = INSTR_TABLE;
2067                 instr->table.table_id = t->id;
2068                 return 0;
2069         }
2070
2071         s = selector_find(p, tokens[1]);
2072         if (s) {
2073                 instr->type = INSTR_SELECTOR;
2074                 instr->table.table_id = s->id;
2075                 return 0;
2076         }
2077
2078         l = learner_find(p, tokens[1]);
2079         if (l) {
2080                 instr->type = INSTR_LEARNER;
2081                 instr->table.table_id = l->id;
2082                 return 0;
2083         }
2084
2085         CHECK(0, EINVAL);
2086 }
2087
2088 static inline void
2089 instr_table_exec(struct rte_swx_pipeline *p)
2090 {
2091         struct thread *t = &p->threads[p->thread_id];
2092         struct instruction *ip = t->ip;
2093         uint32_t table_id = ip->table.table_id;
2094         struct rte_swx_table_state *ts = &t->table_state[table_id];
2095         struct table_runtime *table = &t->tables[table_id];
2096         struct table_statistics *stats = &p->table_stats[table_id];
2097         uint64_t action_id, n_pkts_hit, n_pkts_action;
2098         uint8_t *action_data;
2099         int done, hit;
2100
2101         /* Table. */
2102         done = table->func(ts->obj,
2103                            table->mailbox,
2104                            table->key,
2105                            &action_id,
2106                            &action_data,
2107                            &hit);
2108         if (!done) {
2109                 /* Thread. */
2110                 TRACE("[Thread %2u] table %u (not finalized)\n",
2111                       p->thread_id,
2112                       table_id);
2113
2114                 thread_yield(p);
2115                 return;
2116         }
2117
2118         action_id = hit ? action_id : ts->default_action_id;
2119         action_data = hit ? action_data : ts->default_action_data;
2120         n_pkts_hit = stats->n_pkts_hit[hit];
2121         n_pkts_action = stats->n_pkts_action[action_id];
2122
2123         TRACE("[Thread %2u] table %u (%s, action %u)\n",
2124               p->thread_id,
2125               table_id,
2126               hit ? "hit" : "miss",
2127               (uint32_t)action_id);
2128
2129         t->action_id = action_id;
2130         t->structs[0] = action_data;
2131         t->hit = hit;
2132         stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2133         stats->n_pkts_action[action_id] = n_pkts_action + 1;
2134
2135         /* Thread. */
2136         thread_ip_action_call(p, t, action_id);
2137 }
2138
2139 static inline void
2140 instr_table_af_exec(struct rte_swx_pipeline *p)
2141 {
2142         struct thread *t = &p->threads[p->thread_id];
2143         struct instruction *ip = t->ip;
2144         uint32_t table_id = ip->table.table_id;
2145         struct rte_swx_table_state *ts = &t->table_state[table_id];
2146         struct table_runtime *table = &t->tables[table_id];
2147         struct table_statistics *stats = &p->table_stats[table_id];
2148         uint64_t action_id, n_pkts_hit, n_pkts_action;
2149         uint8_t *action_data;
2150         action_func_t action_func;
2151         int done, hit;
2152
2153         /* Table. */
2154         done = table->func(ts->obj,
2155                            table->mailbox,
2156                            table->key,
2157                            &action_id,
2158                            &action_data,
2159                            &hit);
2160         if (!done) {
2161                 /* Thread. */
2162                 TRACE("[Thread %2u] table %u (not finalized)\n",
2163                       p->thread_id,
2164                       table_id);
2165
2166                 thread_yield(p);
2167                 return;
2168         }
2169
2170         action_id = hit ? action_id : ts->default_action_id;
2171         action_data = hit ? action_data : ts->default_action_data;
2172         action_func = p->action_funcs[action_id];
2173         n_pkts_hit = stats->n_pkts_hit[hit];
2174         n_pkts_action = stats->n_pkts_action[action_id];
2175
2176         TRACE("[Thread %2u] table %u (%s, action %u)\n",
2177               p->thread_id,
2178               table_id,
2179               hit ? "hit" : "miss",
2180               (uint32_t)action_id);
2181
2182         t->action_id = action_id;
2183         t->structs[0] = action_data;
2184         t->hit = hit;
2185         stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2186         stats->n_pkts_action[action_id] = n_pkts_action + 1;
2187
2188         /* Thread. */
2189         thread_ip_inc(p);
2190
2191         /* Action. */
2192         action_func(p);
2193 }
2194
2195 static inline void
2196 instr_selector_exec(struct rte_swx_pipeline *p)
2197 {
2198         struct thread *t = &p->threads[p->thread_id];
2199         struct instruction *ip = t->ip;
2200         uint32_t selector_id = ip->table.table_id;
2201         struct rte_swx_table_state *ts = &t->table_state[p->n_tables + selector_id];
2202         struct selector_runtime *selector = &t->selectors[selector_id];
2203         struct selector_statistics *stats = &p->selector_stats[selector_id];
2204         uint64_t n_pkts = stats->n_pkts;
2205         int done;
2206
2207         /* Table. */
2208         done = rte_swx_table_selector_select(ts->obj,
2209                            selector->mailbox,
2210                            selector->group_id_buffer,
2211                            selector->selector_buffer,
2212                            selector->member_id_buffer);
2213         if (!done) {
2214                 /* Thread. */
2215                 TRACE("[Thread %2u] selector %u (not finalized)\n",
2216                       p->thread_id,
2217                       selector_id);
2218
2219                 thread_yield(p);
2220                 return;
2221         }
2222
2223
2224         TRACE("[Thread %2u] selector %u\n",
2225               p->thread_id,
2226               selector_id);
2227
2228         stats->n_pkts = n_pkts + 1;
2229
2230         /* Thread. */
2231         thread_ip_inc(p);
2232 }
2233
2234 static inline void
2235 instr_learner_exec(struct rte_swx_pipeline *p)
2236 {
2237         struct thread *t = &p->threads[p->thread_id];
2238         struct instruction *ip = t->ip;
2239         uint32_t learner_id = ip->table.table_id;
2240         struct rte_swx_table_state *ts = &t->table_state[p->n_tables +
2241                 p->n_selectors + learner_id];
2242         struct learner_runtime *l = &t->learners[learner_id];
2243         struct learner_statistics *stats = &p->learner_stats[learner_id];
2244         uint64_t action_id, n_pkts_hit, n_pkts_action, time;
2245         uint8_t *action_data;
2246         int done, hit;
2247
2248         /* Table. */
2249         time = rte_get_tsc_cycles();
2250
2251         done = rte_swx_table_learner_lookup(ts->obj,
2252                                             l->mailbox,
2253                                             time,
2254                                             l->key,
2255                                             &action_id,
2256                                             &action_data,
2257                                             &hit);
2258         if (!done) {
2259                 /* Thread. */
2260                 TRACE("[Thread %2u] learner %u (not finalized)\n",
2261                       p->thread_id,
2262                       learner_id);
2263
2264                 thread_yield(p);
2265                 return;
2266         }
2267
2268         action_id = hit ? action_id : ts->default_action_id;
2269         action_data = hit ? action_data : ts->default_action_data;
2270         n_pkts_hit = stats->n_pkts_hit[hit];
2271         n_pkts_action = stats->n_pkts_action[action_id];
2272
2273         TRACE("[Thread %2u] learner %u (%s, action %u)\n",
2274               p->thread_id,
2275               learner_id,
2276               hit ? "hit" : "miss",
2277               (uint32_t)action_id);
2278
2279         t->action_id = action_id;
2280         t->structs[0] = action_data;
2281         t->hit = hit;
2282         t->learner_id = learner_id;
2283         t->time = time;
2284         stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2285         stats->n_pkts_action[action_id] = n_pkts_action + 1;
2286
2287         /* Thread. */
2288         thread_ip_action_call(p, t, action_id);
2289 }
2290
2291 static inline void
2292 instr_learner_af_exec(struct rte_swx_pipeline *p)
2293 {
2294         struct thread *t = &p->threads[p->thread_id];
2295         struct instruction *ip = t->ip;
2296         uint32_t learner_id = ip->table.table_id;
2297         struct rte_swx_table_state *ts = &t->table_state[p->n_tables +
2298                 p->n_selectors + learner_id];
2299         struct learner_runtime *l = &t->learners[learner_id];
2300         struct learner_statistics *stats = &p->learner_stats[learner_id];
2301         uint64_t action_id, n_pkts_hit, n_pkts_action, time;
2302         uint8_t *action_data;
2303         action_func_t action_func;
2304         int done, hit;
2305
2306         /* Table. */
2307         time = rte_get_tsc_cycles();
2308
2309         done = rte_swx_table_learner_lookup(ts->obj,
2310                                             l->mailbox,
2311                                             time,
2312                                             l->key,
2313                                             &action_id,
2314                                             &action_data,
2315                                             &hit);
2316         if (!done) {
2317                 /* Thread. */
2318                 TRACE("[Thread %2u] learner %u (not finalized)\n",
2319                       p->thread_id,
2320                       learner_id);
2321
2322                 thread_yield(p);
2323                 return;
2324         }
2325
2326         action_id = hit ? action_id : ts->default_action_id;
2327         action_data = hit ? action_data : ts->default_action_data;
2328         action_func = p->action_funcs[action_id];
2329         n_pkts_hit = stats->n_pkts_hit[hit];
2330         n_pkts_action = stats->n_pkts_action[action_id];
2331
2332         TRACE("[Thread %2u] learner %u (%s, action %u)\n",
2333               p->thread_id,
2334               learner_id,
2335               hit ? "hit" : "miss",
2336               (uint32_t)action_id);
2337
2338         t->action_id = action_id;
2339         t->structs[0] = action_data;
2340         t->hit = hit;
2341         t->learner_id = learner_id;
2342         t->time = time;
2343         stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2344         stats->n_pkts_action[action_id] = n_pkts_action + 1;
2345
2346         /* Thread. */
2347         thread_ip_action_call(p, t, action_id);
2348
2349         /* Action */
2350         action_func(p);
2351 }
2352
2353 /*
2354  * learn.
2355  */
2356 static struct action *
2357 action_find(struct rte_swx_pipeline *p, const char *name);
2358
2359 static int
2360 action_has_nbo_args(struct action *a);
2361
2362 static int
2363 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name);
2364
2365 static int
2366 instr_learn_translate(struct rte_swx_pipeline *p,
2367                       struct action *action,
2368                       char **tokens,
2369                       int n_tokens,
2370                       struct instruction *instr,
2371                       struct instruction_data *data __rte_unused)
2372 {
2373         struct action *a;
2374         const char *mf_name;
2375         uint32_t mf_offset = 0;
2376
2377         CHECK(action, EINVAL);
2378         CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL);
2379
2380         a = action_find(p, tokens[1]);
2381         CHECK(a, EINVAL);
2382         CHECK(!action_has_nbo_args(a), EINVAL);
2383
2384         mf_name = (n_tokens > 2) ? tokens[2] : NULL;
2385         CHECK(!learner_action_args_check(p, a, mf_name), EINVAL);
2386
2387         if (mf_name) {
2388                 struct field *mf;
2389
2390                 mf = metadata_field_parse(p, mf_name);
2391                 CHECK(mf, EINVAL);
2392
2393                 mf_offset = mf->offset / 8;
2394         }
2395
2396         instr->type = INSTR_LEARNER_LEARN;
2397         instr->learn.action_id = a->id;
2398         instr->learn.mf_offset = mf_offset;
2399
2400         return 0;
2401 }
2402
2403 static inline void
2404 instr_learn_exec(struct rte_swx_pipeline *p)
2405 {
2406         struct thread *t = &p->threads[p->thread_id];
2407         struct instruction *ip = t->ip;
2408
2409         __instr_learn_exec(p, t, ip);
2410
2411         /* Thread. */
2412         thread_ip_inc(p);
2413 }
2414
2415 /*
2416  * forget.
2417  */
2418 static int
2419 instr_forget_translate(struct rte_swx_pipeline *p __rte_unused,
2420                        struct action *action,
2421                        char **tokens __rte_unused,
2422                        int n_tokens,
2423                        struct instruction *instr,
2424                        struct instruction_data *data __rte_unused)
2425 {
2426         CHECK(action, EINVAL);
2427         CHECK(n_tokens == 1, EINVAL);
2428
2429         instr->type = INSTR_LEARNER_FORGET;
2430
2431         return 0;
2432 }
2433
2434 static inline void
2435 instr_forget_exec(struct rte_swx_pipeline *p)
2436 {
2437         struct thread *t = &p->threads[p->thread_id];
2438         struct instruction *ip = t->ip;
2439
2440         __instr_forget_exec(p, t, ip);
2441
2442         /* Thread. */
2443         thread_ip_inc(p);
2444 }
2445
2446 /*
2447  * extern.
2448  */
2449 static int
2450 instr_extern_translate(struct rte_swx_pipeline *p,
2451                        struct action *action __rte_unused,
2452                        char **tokens,
2453                        int n_tokens,
2454                        struct instruction *instr,
2455                        struct instruction_data *data __rte_unused)
2456 {
2457         char *token = tokens[1];
2458
2459         CHECK(n_tokens == 2, EINVAL);
2460
2461         if (token[0] == 'e') {
2462                 struct extern_obj *obj;
2463                 struct extern_type_member_func *func;
2464
2465                 func = extern_obj_member_func_parse(p, token, &obj);
2466                 CHECK(func, EINVAL);
2467
2468                 instr->type = INSTR_EXTERN_OBJ;
2469                 instr->ext_obj.ext_obj_id = obj->id;
2470                 instr->ext_obj.func_id = func->id;
2471
2472                 return 0;
2473         }
2474
2475         if (token[0] == 'f') {
2476                 struct extern_func *func;
2477
2478                 func = extern_func_parse(p, token);
2479                 CHECK(func, EINVAL);
2480
2481                 instr->type = INSTR_EXTERN_FUNC;
2482                 instr->ext_func.ext_func_id = func->id;
2483
2484                 return 0;
2485         }
2486
2487         CHECK(0, EINVAL);
2488 }
2489
2490 static inline void
2491 instr_extern_obj_exec(struct rte_swx_pipeline *p)
2492 {
2493         struct thread *t = &p->threads[p->thread_id];
2494         struct instruction *ip = t->ip;
2495         uint32_t done;
2496
2497         /* Extern object member function execute. */
2498         done = __instr_extern_obj_exec(p, t, ip);
2499
2500         /* Thread. */
2501         thread_ip_inc_cond(t, done);
2502         thread_yield_cond(p, done ^ 1);
2503 }
2504
2505 static inline void
2506 instr_extern_func_exec(struct rte_swx_pipeline *p)
2507 {
2508         struct thread *t = &p->threads[p->thread_id];
2509         struct instruction *ip = t->ip;
2510         uint32_t done;
2511
2512         /* Extern function execute. */
2513         done = __instr_extern_func_exec(p, t, ip);
2514
2515         /* Thread. */
2516         thread_ip_inc_cond(t, done);
2517         thread_yield_cond(p, done ^ 1);
2518 }
2519
2520 /*
2521  * mov.
2522  */
2523 static int
2524 instr_mov_translate(struct rte_swx_pipeline *p,
2525                     struct action *action,
2526                     char **tokens,
2527                     int n_tokens,
2528                     struct instruction *instr,
2529                     struct instruction_data *data __rte_unused)
2530 {
2531         char *dst = tokens[1], *src = tokens[2];
2532         struct field *fdst, *fsrc;
2533         uint64_t src_val;
2534         uint32_t dst_struct_id = 0, src_struct_id = 0;
2535
2536         CHECK(n_tokens == 3, EINVAL);
2537
2538         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2539         CHECK(fdst, EINVAL);
2540         CHECK(!fdst->var_size, EINVAL);
2541
2542         /* MOV, MOV_MH, MOV_HM or MOV_HH. */
2543         fsrc = struct_field_parse(p, action, src, &src_struct_id);
2544         if (fsrc) {
2545                 CHECK(!fsrc->var_size, EINVAL);
2546
2547                 instr->type = INSTR_MOV;
2548                 if (dst[0] != 'h' && src[0] == 'h')
2549                         instr->type = INSTR_MOV_MH;
2550                 if (dst[0] == 'h' && src[0] != 'h')
2551                         instr->type = INSTR_MOV_HM;
2552                 if (dst[0] == 'h' && src[0] == 'h')
2553                         instr->type = INSTR_MOV_HH;
2554
2555                 instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
2556                 instr->mov.dst.n_bits = fdst->n_bits;
2557                 instr->mov.dst.offset = fdst->offset / 8;
2558                 instr->mov.src.struct_id = (uint8_t)src_struct_id;
2559                 instr->mov.src.n_bits = fsrc->n_bits;
2560                 instr->mov.src.offset = fsrc->offset / 8;
2561                 return 0;
2562         }
2563
2564         /* MOV_I. */
2565         src_val = strtoull(src, &src, 0);
2566         CHECK(!src[0], EINVAL);
2567
2568         if (dst[0] == 'h')
2569                 src_val = hton64(src_val) >> (64 - fdst->n_bits);
2570
2571         instr->type = INSTR_MOV_I;
2572         instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
2573         instr->mov.dst.n_bits = fdst->n_bits;
2574         instr->mov.dst.offset = fdst->offset / 8;
2575         instr->mov.src_val = src_val;
2576         return 0;
2577 }
2578
2579 static inline void
2580 instr_mov_exec(struct rte_swx_pipeline *p)
2581 {
2582         struct thread *t = &p->threads[p->thread_id];
2583         struct instruction *ip = t->ip;
2584
2585         __instr_mov_exec(p, t, ip);
2586
2587         /* Thread. */
2588         thread_ip_inc(p);
2589 }
2590
2591 static inline void
2592 instr_mov_mh_exec(struct rte_swx_pipeline *p)
2593 {
2594         struct thread *t = &p->threads[p->thread_id];
2595         struct instruction *ip = t->ip;
2596
2597         __instr_mov_mh_exec(p, t, ip);
2598
2599         /* Thread. */
2600         thread_ip_inc(p);
2601 }
2602
2603 static inline void
2604 instr_mov_hm_exec(struct rte_swx_pipeline *p)
2605 {
2606         struct thread *t = &p->threads[p->thread_id];
2607         struct instruction *ip = t->ip;
2608
2609         __instr_mov_hm_exec(p, t, ip);
2610
2611         /* Thread. */
2612         thread_ip_inc(p);
2613 }
2614
2615 static inline void
2616 instr_mov_hh_exec(struct rte_swx_pipeline *p)
2617 {
2618         struct thread *t = &p->threads[p->thread_id];
2619         struct instruction *ip = t->ip;
2620
2621         __instr_mov_hh_exec(p, t, ip);
2622
2623         /* Thread. */
2624         thread_ip_inc(p);
2625 }
2626
2627 static inline void
2628 instr_mov_i_exec(struct rte_swx_pipeline *p)
2629 {
2630         struct thread *t = &p->threads[p->thread_id];
2631         struct instruction *ip = t->ip;
2632
2633         __instr_mov_i_exec(p, t, ip);
2634
2635         /* Thread. */
2636         thread_ip_inc(p);
2637 }
2638
2639 /*
2640  * dma.
2641  */
2642 static inline void
2643 instr_dma_ht_exec(struct rte_swx_pipeline *p)
2644 {
2645         struct thread *t = &p->threads[p->thread_id];
2646         struct instruction *ip = t->ip;
2647
2648         __instr_dma_ht_exec(p, t, ip);
2649
2650         /* Thread. */
2651         thread_ip_inc(p);
2652 }
2653
2654 static inline void
2655 instr_dma_ht2_exec(struct rte_swx_pipeline *p)
2656 {
2657         struct thread *t = &p->threads[p->thread_id];
2658         struct instruction *ip = t->ip;
2659
2660         __instr_dma_ht2_exec(p, t, ip);
2661
2662         /* Thread. */
2663         thread_ip_inc(p);
2664 }
2665
2666 static inline void
2667 instr_dma_ht3_exec(struct rte_swx_pipeline *p)
2668 {
2669         struct thread *t = &p->threads[p->thread_id];
2670         struct instruction *ip = t->ip;
2671
2672         __instr_dma_ht3_exec(p, t, ip);
2673
2674         /* Thread. */
2675         thread_ip_inc(p);
2676 }
2677
2678 static inline void
2679 instr_dma_ht4_exec(struct rte_swx_pipeline *p)
2680 {
2681         struct thread *t = &p->threads[p->thread_id];
2682         struct instruction *ip = t->ip;
2683
2684         __instr_dma_ht4_exec(p, t, ip);
2685
2686         /* Thread. */
2687         thread_ip_inc(p);
2688 }
2689
2690 static inline void
2691 instr_dma_ht5_exec(struct rte_swx_pipeline *p)
2692 {
2693         struct thread *t = &p->threads[p->thread_id];
2694         struct instruction *ip = t->ip;
2695
2696         __instr_dma_ht5_exec(p, t, ip);
2697
2698         /* Thread. */
2699         thread_ip_inc(p);
2700 }
2701
2702 static inline void
2703 instr_dma_ht6_exec(struct rte_swx_pipeline *p)
2704 {
2705         struct thread *t = &p->threads[p->thread_id];
2706         struct instruction *ip = t->ip;
2707
2708         __instr_dma_ht6_exec(p, t, ip);
2709
2710         /* Thread. */
2711         thread_ip_inc(p);
2712 }
2713
2714 static inline void
2715 instr_dma_ht7_exec(struct rte_swx_pipeline *p)
2716 {
2717         struct thread *t = &p->threads[p->thread_id];
2718         struct instruction *ip = t->ip;
2719
2720         __instr_dma_ht7_exec(p, t, ip);
2721
2722         /* Thread. */
2723         thread_ip_inc(p);
2724 }
2725
2726 static inline void
2727 instr_dma_ht8_exec(struct rte_swx_pipeline *p)
2728 {
2729         struct thread *t = &p->threads[p->thread_id];
2730         struct instruction *ip = t->ip;
2731
2732         __instr_dma_ht8_exec(p, t, ip);
2733
2734         /* Thread. */
2735         thread_ip_inc(p);
2736 }
2737
2738 /*
2739  * alu.
2740  */
2741 static int
2742 instr_alu_add_translate(struct rte_swx_pipeline *p,
2743                         struct action *action,
2744                         char **tokens,
2745                         int n_tokens,
2746                         struct instruction *instr,
2747                         struct instruction_data *data __rte_unused)
2748 {
2749         char *dst = tokens[1], *src = tokens[2];
2750         struct field *fdst, *fsrc;
2751         uint64_t src_val;
2752         uint32_t dst_struct_id = 0, src_struct_id = 0;
2753
2754         CHECK(n_tokens == 3, EINVAL);
2755
2756         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2757         CHECK(fdst, EINVAL);
2758         CHECK(!fdst->var_size, EINVAL);
2759
2760         /* ADD, ADD_HM, ADD_MH, ADD_HH. */
2761         fsrc = struct_field_parse(p, action, src, &src_struct_id);
2762         if (fsrc) {
2763                 CHECK(!fsrc->var_size, EINVAL);
2764
2765                 instr->type = INSTR_ALU_ADD;
2766                 if (dst[0] == 'h' && src[0] != 'h')
2767                         instr->type = INSTR_ALU_ADD_HM;
2768                 if (dst[0] != 'h' && src[0] == 'h')
2769                         instr->type = INSTR_ALU_ADD_MH;
2770                 if (dst[0] == 'h' && src[0] == 'h')
2771                         instr->type = INSTR_ALU_ADD_HH;
2772
2773                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2774                 instr->alu.dst.n_bits = fdst->n_bits;
2775                 instr->alu.dst.offset = fdst->offset / 8;
2776                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
2777                 instr->alu.src.n_bits = fsrc->n_bits;
2778                 instr->alu.src.offset = fsrc->offset / 8;
2779                 return 0;
2780         }
2781
2782         /* ADD_MI, ADD_HI. */
2783         src_val = strtoull(src, &src, 0);
2784         CHECK(!src[0], EINVAL);
2785
2786         instr->type = INSTR_ALU_ADD_MI;
2787         if (dst[0] == 'h')
2788                 instr->type = INSTR_ALU_ADD_HI;
2789
2790         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2791         instr->alu.dst.n_bits = fdst->n_bits;
2792         instr->alu.dst.offset = fdst->offset / 8;
2793         instr->alu.src_val = src_val;
2794         return 0;
2795 }
2796
2797 static int
2798 instr_alu_sub_translate(struct rte_swx_pipeline *p,
2799                         struct action *action,
2800                         char **tokens,
2801                         int n_tokens,
2802                         struct instruction *instr,
2803                         struct instruction_data *data __rte_unused)
2804 {
2805         char *dst = tokens[1], *src = tokens[2];
2806         struct field *fdst, *fsrc;
2807         uint64_t src_val;
2808         uint32_t dst_struct_id = 0, src_struct_id = 0;
2809
2810         CHECK(n_tokens == 3, EINVAL);
2811
2812         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2813         CHECK(fdst, EINVAL);
2814         CHECK(!fdst->var_size, EINVAL);
2815
2816         /* SUB, SUB_HM, SUB_MH, SUB_HH. */
2817         fsrc = struct_field_parse(p, action, src, &src_struct_id);
2818         if (fsrc) {
2819                 CHECK(!fsrc->var_size, EINVAL);
2820
2821                 instr->type = INSTR_ALU_SUB;
2822                 if (dst[0] == 'h' && src[0] != 'h')
2823                         instr->type = INSTR_ALU_SUB_HM;
2824                 if (dst[0] != 'h' && src[0] == 'h')
2825                         instr->type = INSTR_ALU_SUB_MH;
2826                 if (dst[0] == 'h' && src[0] == 'h')
2827                         instr->type = INSTR_ALU_SUB_HH;
2828
2829                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2830                 instr->alu.dst.n_bits = fdst->n_bits;
2831                 instr->alu.dst.offset = fdst->offset / 8;
2832                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
2833                 instr->alu.src.n_bits = fsrc->n_bits;
2834                 instr->alu.src.offset = fsrc->offset / 8;
2835                 return 0;
2836         }
2837
2838         /* SUB_MI, SUB_HI. */
2839         src_val = strtoull(src, &src, 0);
2840         CHECK(!src[0], EINVAL);
2841
2842         instr->type = INSTR_ALU_SUB_MI;
2843         if (dst[0] == 'h')
2844                 instr->type = INSTR_ALU_SUB_HI;
2845
2846         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2847         instr->alu.dst.n_bits = fdst->n_bits;
2848         instr->alu.dst.offset = fdst->offset / 8;
2849         instr->alu.src_val = src_val;
2850         return 0;
2851 }
2852
2853 static int
2854 instr_alu_ckadd_translate(struct rte_swx_pipeline *p,
2855                           struct action *action __rte_unused,
2856                           char **tokens,
2857                           int n_tokens,
2858                           struct instruction *instr,
2859                           struct instruction_data *data __rte_unused)
2860 {
2861         char *dst = tokens[1], *src = tokens[2];
2862         struct header *hdst, *hsrc;
2863         struct field *fdst, *fsrc;
2864
2865         CHECK(n_tokens == 3, EINVAL);
2866
2867         fdst = header_field_parse(p, dst, &hdst);
2868         CHECK(fdst && (fdst->n_bits == 16), EINVAL);
2869         CHECK(!fdst->var_size, EINVAL);
2870
2871         /* CKADD_FIELD. */
2872         fsrc = header_field_parse(p, src, &hsrc);
2873         if (fsrc) {
2874                 CHECK(!fsrc->var_size, EINVAL);
2875
2876                 instr->type = INSTR_ALU_CKADD_FIELD;
2877                 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2878                 instr->alu.dst.n_bits = fdst->n_bits;
2879                 instr->alu.dst.offset = fdst->offset / 8;
2880                 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2881                 instr->alu.src.n_bits = fsrc->n_bits;
2882                 instr->alu.src.offset = fsrc->offset / 8;
2883                 return 0;
2884         }
2885
2886         /* CKADD_STRUCT, CKADD_STRUCT20. */
2887         hsrc = header_parse(p, src);
2888         CHECK(hsrc, EINVAL);
2889         CHECK(!hsrc->st->var_size, EINVAL);
2890
2891         instr->type = INSTR_ALU_CKADD_STRUCT;
2892         if ((hsrc->st->n_bits / 8) == 20)
2893                 instr->type = INSTR_ALU_CKADD_STRUCT20;
2894
2895         instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2896         instr->alu.dst.n_bits = fdst->n_bits;
2897         instr->alu.dst.offset = fdst->offset / 8;
2898         instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2899         instr->alu.src.n_bits = hsrc->st->n_bits;
2900         instr->alu.src.offset = 0; /* Unused. */
2901         return 0;
2902 }
2903
2904 static int
2905 instr_alu_cksub_translate(struct rte_swx_pipeline *p,
2906                           struct action *action __rte_unused,
2907                           char **tokens,
2908                           int n_tokens,
2909                           struct instruction *instr,
2910                           struct instruction_data *data __rte_unused)
2911 {
2912         char *dst = tokens[1], *src = tokens[2];
2913         struct header *hdst, *hsrc;
2914         struct field *fdst, *fsrc;
2915
2916         CHECK(n_tokens == 3, EINVAL);
2917
2918         fdst = header_field_parse(p, dst, &hdst);
2919         CHECK(fdst && (fdst->n_bits == 16), EINVAL);
2920         CHECK(!fdst->var_size, EINVAL);
2921
2922         fsrc = header_field_parse(p, src, &hsrc);
2923         CHECK(fsrc, EINVAL);
2924         CHECK(!fsrc->var_size, EINVAL);
2925
2926         instr->type = INSTR_ALU_CKSUB_FIELD;
2927         instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2928         instr->alu.dst.n_bits = fdst->n_bits;
2929         instr->alu.dst.offset = fdst->offset / 8;
2930         instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2931         instr->alu.src.n_bits = fsrc->n_bits;
2932         instr->alu.src.offset = fsrc->offset / 8;
2933         return 0;
2934 }
2935
2936 static int
2937 instr_alu_shl_translate(struct rte_swx_pipeline *p,
2938                         struct action *action,
2939                         char **tokens,
2940                         int n_tokens,
2941                         struct instruction *instr,
2942                         struct instruction_data *data __rte_unused)
2943 {
2944         char *dst = tokens[1], *src = tokens[2];
2945         struct field *fdst, *fsrc;
2946         uint64_t src_val;
2947         uint32_t dst_struct_id = 0, src_struct_id = 0;
2948
2949         CHECK(n_tokens == 3, EINVAL);
2950
2951         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2952         CHECK(fdst, EINVAL);
2953         CHECK(!fdst->var_size, EINVAL);
2954
2955         /* SHL, SHL_HM, SHL_MH, SHL_HH. */
2956         fsrc = struct_field_parse(p, action, src, &src_struct_id);
2957         if (fsrc) {
2958                 CHECK(!fsrc->var_size, EINVAL);
2959
2960                 instr->type = INSTR_ALU_SHL;
2961                 if (dst[0] == 'h' && src[0] != 'h')
2962                         instr->type = INSTR_ALU_SHL_HM;
2963                 if (dst[0] != 'h' && src[0] == 'h')
2964                         instr->type = INSTR_ALU_SHL_MH;
2965                 if (dst[0] == 'h' && src[0] == 'h')
2966                         instr->type = INSTR_ALU_SHL_HH;
2967
2968                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2969                 instr->alu.dst.n_bits = fdst->n_bits;
2970                 instr->alu.dst.offset = fdst->offset / 8;
2971                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
2972                 instr->alu.src.n_bits = fsrc->n_bits;
2973                 instr->alu.src.offset = fsrc->offset / 8;
2974                 return 0;
2975         }
2976
2977         /* SHL_MI, SHL_HI. */
2978         src_val = strtoull(src, &src, 0);
2979         CHECK(!src[0], EINVAL);
2980
2981         instr->type = INSTR_ALU_SHL_MI;
2982         if (dst[0] == 'h')
2983                 instr->type = INSTR_ALU_SHL_HI;
2984
2985         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2986         instr->alu.dst.n_bits = fdst->n_bits;
2987         instr->alu.dst.offset = fdst->offset / 8;
2988         instr->alu.src_val = src_val;
2989         return 0;
2990 }
2991
2992 static int
2993 instr_alu_shr_translate(struct rte_swx_pipeline *p,
2994                         struct action *action,
2995                         char **tokens,
2996                         int n_tokens,
2997                         struct instruction *instr,
2998                         struct instruction_data *data __rte_unused)
2999 {
3000         char *dst = tokens[1], *src = tokens[2];
3001         struct field *fdst, *fsrc;
3002         uint64_t src_val;
3003         uint32_t dst_struct_id = 0, src_struct_id = 0;
3004
3005         CHECK(n_tokens == 3, EINVAL);
3006
3007         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3008         CHECK(fdst, EINVAL);
3009         CHECK(!fdst->var_size, EINVAL);
3010
3011         /* SHR, SHR_HM, SHR_MH, SHR_HH. */
3012         fsrc = struct_field_parse(p, action, src, &src_struct_id);
3013         if (fsrc) {
3014                 CHECK(!fsrc->var_size, EINVAL);
3015
3016                 instr->type = INSTR_ALU_SHR;
3017                 if (dst[0] == 'h' && src[0] != 'h')
3018                         instr->type = INSTR_ALU_SHR_HM;
3019                 if (dst[0] != 'h' && src[0] == 'h')
3020                         instr->type = INSTR_ALU_SHR_MH;
3021                 if (dst[0] == 'h' && src[0] == 'h')
3022                         instr->type = INSTR_ALU_SHR_HH;
3023
3024                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3025                 instr->alu.dst.n_bits = fdst->n_bits;
3026                 instr->alu.dst.offset = fdst->offset / 8;
3027                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3028                 instr->alu.src.n_bits = fsrc->n_bits;
3029                 instr->alu.src.offset = fsrc->offset / 8;
3030                 return 0;
3031         }
3032
3033         /* SHR_MI, SHR_HI. */
3034         src_val = strtoull(src, &src, 0);
3035         CHECK(!src[0], EINVAL);
3036
3037         instr->type = INSTR_ALU_SHR_MI;
3038         if (dst[0] == 'h')
3039                 instr->type = INSTR_ALU_SHR_HI;
3040
3041         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3042         instr->alu.dst.n_bits = fdst->n_bits;
3043         instr->alu.dst.offset = fdst->offset / 8;
3044         instr->alu.src_val = src_val;
3045         return 0;
3046 }
3047
3048 static int
3049 instr_alu_and_translate(struct rte_swx_pipeline *p,
3050                         struct action *action,
3051                         char **tokens,
3052                         int n_tokens,
3053                         struct instruction *instr,
3054                         struct instruction_data *data __rte_unused)
3055 {
3056         char *dst = tokens[1], *src = tokens[2];
3057         struct field *fdst, *fsrc;
3058         uint64_t src_val;
3059         uint32_t dst_struct_id = 0, src_struct_id = 0;
3060
3061         CHECK(n_tokens == 3, EINVAL);
3062
3063         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3064         CHECK(fdst, EINVAL);
3065         CHECK(!fdst->var_size, EINVAL);
3066
3067         /* AND, AND_MH, AND_HM, AND_HH. */
3068         fsrc = struct_field_parse(p, action, src, &src_struct_id);
3069         if (fsrc) {
3070                 CHECK(!fsrc->var_size, EINVAL);
3071
3072                 instr->type = INSTR_ALU_AND;
3073                 if (dst[0] != 'h' && src[0] == 'h')
3074                         instr->type = INSTR_ALU_AND_MH;
3075                 if (dst[0] == 'h' && src[0] != 'h')
3076                         instr->type = INSTR_ALU_AND_HM;
3077                 if (dst[0] == 'h' && src[0] == 'h')
3078                         instr->type = INSTR_ALU_AND_HH;
3079
3080                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3081                 instr->alu.dst.n_bits = fdst->n_bits;
3082                 instr->alu.dst.offset = fdst->offset / 8;
3083                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3084                 instr->alu.src.n_bits = fsrc->n_bits;
3085                 instr->alu.src.offset = fsrc->offset / 8;
3086                 return 0;
3087         }
3088
3089         /* AND_I. */
3090         src_val = strtoull(src, &src, 0);
3091         CHECK(!src[0], EINVAL);
3092
3093         if (dst[0] == 'h')
3094                 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3095
3096         instr->type = INSTR_ALU_AND_I;
3097         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3098         instr->alu.dst.n_bits = fdst->n_bits;
3099         instr->alu.dst.offset = fdst->offset / 8;
3100         instr->alu.src_val = src_val;
3101         return 0;
3102 }
3103
3104 static int
3105 instr_alu_or_translate(struct rte_swx_pipeline *p,
3106                        struct action *action,
3107                        char **tokens,
3108                        int n_tokens,
3109                        struct instruction *instr,
3110                        struct instruction_data *data __rte_unused)
3111 {
3112         char *dst = tokens[1], *src = tokens[2];
3113         struct field *fdst, *fsrc;
3114         uint64_t src_val;
3115         uint32_t dst_struct_id = 0, src_struct_id = 0;
3116
3117         CHECK(n_tokens == 3, EINVAL);
3118
3119         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3120         CHECK(fdst, EINVAL);
3121         CHECK(!fdst->var_size, EINVAL);
3122
3123         /* OR, OR_MH, OR_HM, OR_HH. */
3124         fsrc = struct_field_parse(p, action, src, &src_struct_id);
3125         if (fsrc) {
3126                 CHECK(!fsrc->var_size, EINVAL);
3127
3128                 instr->type = INSTR_ALU_OR;
3129                 if (dst[0] != 'h' && src[0] == 'h')
3130                         instr->type = INSTR_ALU_OR_MH;
3131                 if (dst[0] == 'h' && src[0] != 'h')
3132                         instr->type = INSTR_ALU_OR_HM;
3133                 if (dst[0] == 'h' && src[0] == 'h')
3134                         instr->type = INSTR_ALU_OR_HH;
3135
3136                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3137                 instr->alu.dst.n_bits = fdst->n_bits;
3138                 instr->alu.dst.offset = fdst->offset / 8;
3139                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3140                 instr->alu.src.n_bits = fsrc->n_bits;
3141                 instr->alu.src.offset = fsrc->offset / 8;
3142                 return 0;
3143         }
3144
3145         /* OR_I. */
3146         src_val = strtoull(src, &src, 0);
3147         CHECK(!src[0], EINVAL);
3148
3149         if (dst[0] == 'h')
3150                 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3151
3152         instr->type = INSTR_ALU_OR_I;
3153         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3154         instr->alu.dst.n_bits = fdst->n_bits;
3155         instr->alu.dst.offset = fdst->offset / 8;
3156         instr->alu.src_val = src_val;
3157         return 0;
3158 }
3159
3160 static int
3161 instr_alu_xor_translate(struct rte_swx_pipeline *p,
3162                         struct action *action,
3163                         char **tokens,
3164                         int n_tokens,
3165                         struct instruction *instr,
3166                         struct instruction_data *data __rte_unused)
3167 {
3168         char *dst = tokens[1], *src = tokens[2];
3169         struct field *fdst, *fsrc;
3170         uint64_t src_val;
3171         uint32_t dst_struct_id = 0, src_struct_id = 0;
3172
3173         CHECK(n_tokens == 3, EINVAL);
3174
3175         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3176         CHECK(fdst, EINVAL);
3177         CHECK(!fdst->var_size, EINVAL);
3178
3179         /* XOR, XOR_MH, XOR_HM, XOR_HH. */
3180         fsrc = struct_field_parse(p, action, src, &src_struct_id);
3181         if (fsrc) {
3182                 CHECK(!fsrc->var_size, EINVAL);
3183
3184                 instr->type = INSTR_ALU_XOR;
3185                 if (dst[0] != 'h' && src[0] == 'h')
3186                         instr->type = INSTR_ALU_XOR_MH;
3187                 if (dst[0] == 'h' && src[0] != 'h')
3188                         instr->type = INSTR_ALU_XOR_HM;
3189                 if (dst[0] == 'h' && src[0] == 'h')
3190                         instr->type = INSTR_ALU_XOR_HH;
3191
3192                 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3193                 instr->alu.dst.n_bits = fdst->n_bits;
3194                 instr->alu.dst.offset = fdst->offset / 8;
3195                 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3196                 instr->alu.src.n_bits = fsrc->n_bits;
3197                 instr->alu.src.offset = fsrc->offset / 8;
3198                 return 0;
3199         }
3200
3201         /* XOR_I. */
3202         src_val = strtoull(src, &src, 0);
3203         CHECK(!src[0], EINVAL);
3204
3205         if (dst[0] == 'h')
3206                 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3207
3208         instr->type = INSTR_ALU_XOR_I;
3209         instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3210         instr->alu.dst.n_bits = fdst->n_bits;
3211         instr->alu.dst.offset = fdst->offset / 8;
3212         instr->alu.src_val = src_val;
3213         return 0;
3214 }
3215
3216 static inline void
3217 instr_alu_add_exec(struct rte_swx_pipeline *p)
3218 {
3219         struct thread *t = &p->threads[p->thread_id];
3220         struct instruction *ip = t->ip;
3221
3222         /* Structs */
3223         __instr_alu_add_exec(p, t, ip);
3224
3225         /* Thread. */
3226         thread_ip_inc(p);
3227 }
3228
3229 static inline void
3230 instr_alu_add_mh_exec(struct rte_swx_pipeline *p)
3231 {
3232         struct thread *t = &p->threads[p->thread_id];
3233         struct instruction *ip = t->ip;
3234
3235         /* Structs. */
3236         __instr_alu_add_mh_exec(p, t, ip);
3237
3238         /* Thread. */
3239         thread_ip_inc(p);
3240 }
3241
3242 static inline void
3243 instr_alu_add_hm_exec(struct rte_swx_pipeline *p)
3244 {
3245         struct thread *t = &p->threads[p->thread_id];
3246         struct instruction *ip = t->ip;
3247
3248         /* Structs. */
3249         __instr_alu_add_hm_exec(p, t, ip);
3250
3251         /* Thread. */
3252         thread_ip_inc(p);
3253 }
3254
3255 static inline void
3256 instr_alu_add_hh_exec(struct rte_swx_pipeline *p)
3257 {
3258         struct thread *t = &p->threads[p->thread_id];
3259         struct instruction *ip = t->ip;
3260
3261         /* Structs. */
3262         __instr_alu_add_hh_exec(p, t, ip);
3263
3264         /* Thread. */
3265         thread_ip_inc(p);
3266 }
3267
3268 static inline void
3269 instr_alu_add_mi_exec(struct rte_swx_pipeline *p)
3270 {
3271         struct thread *t = &p->threads[p->thread_id];
3272         struct instruction *ip = t->ip;
3273
3274         /* Structs. */
3275         __instr_alu_add_mi_exec(p, t, ip);
3276
3277         /* Thread. */
3278         thread_ip_inc(p);
3279 }
3280
3281 static inline void
3282 instr_alu_add_hi_exec(struct rte_swx_pipeline *p)
3283 {
3284         struct thread *t = &p->threads[p->thread_id];
3285         struct instruction *ip = t->ip;
3286
3287         /* Structs. */
3288         __instr_alu_add_hi_exec(p, t, ip);
3289
3290         /* Thread. */
3291         thread_ip_inc(p);
3292 }
3293
3294 static inline void
3295 instr_alu_sub_exec(struct rte_swx_pipeline *p)
3296 {
3297         struct thread *t = &p->threads[p->thread_id];
3298         struct instruction *ip = t->ip;
3299
3300         /* Structs. */
3301         __instr_alu_sub_exec(p, t, ip);
3302
3303         /* Thread. */
3304         thread_ip_inc(p);
3305 }
3306
3307 static inline void
3308 instr_alu_sub_mh_exec(struct rte_swx_pipeline *p)
3309 {
3310         struct thread *t = &p->threads[p->thread_id];
3311         struct instruction *ip = t->ip;
3312
3313         /* Structs. */
3314         __instr_alu_sub_mh_exec(p, t, ip);
3315
3316         /* Thread. */
3317         thread_ip_inc(p);
3318 }
3319
3320 static inline void
3321 instr_alu_sub_hm_exec(struct rte_swx_pipeline *p)
3322 {
3323         struct thread *t = &p->threads[p->thread_id];
3324         struct instruction *ip = t->ip;
3325
3326         /* Structs. */
3327         __instr_alu_sub_hm_exec(p, t, ip);
3328
3329         /* Thread. */
3330         thread_ip_inc(p);
3331 }
3332
3333 static inline void
3334 instr_alu_sub_hh_exec(struct rte_swx_pipeline *p)
3335 {
3336         struct thread *t = &p->threads[p->thread_id];
3337         struct instruction *ip = t->ip;
3338
3339         /* Structs. */
3340         __instr_alu_sub_hh_exec(p, t, ip);
3341
3342         /* Thread. */
3343         thread_ip_inc(p);
3344 }
3345
3346 static inline void
3347 instr_alu_sub_mi_exec(struct rte_swx_pipeline *p)
3348 {
3349         struct thread *t = &p->threads[p->thread_id];
3350         struct instruction *ip = t->ip;
3351
3352         /* Structs. */
3353         __instr_alu_sub_mi_exec(p, t, ip);
3354
3355         /* Thread. */
3356         thread_ip_inc(p);
3357 }
3358
3359 static inline void
3360 instr_alu_sub_hi_exec(struct rte_swx_pipeline *p)
3361 {
3362         struct thread *t = &p->threads[p->thread_id];
3363         struct instruction *ip = t->ip;
3364
3365         /* Structs. */
3366         __instr_alu_sub_hi_exec(p, t, ip);
3367
3368         /* Thread. */
3369         thread_ip_inc(p);
3370 }
3371
3372 static inline void
3373 instr_alu_shl_exec(struct rte_swx_pipeline *p)
3374 {
3375         struct thread *t = &p->threads[p->thread_id];
3376         struct instruction *ip = t->ip;
3377
3378         /* Structs. */
3379         __instr_alu_shl_exec(p, t, ip);
3380
3381         /* Thread. */
3382         thread_ip_inc(p);
3383 }
3384
3385 static inline void
3386 instr_alu_shl_mh_exec(struct rte_swx_pipeline *p)
3387 {
3388         struct thread *t = &p->threads[p->thread_id];
3389         struct instruction *ip = t->ip;
3390
3391         /* Structs. */
3392         __instr_alu_shl_mh_exec(p, t, ip);
3393
3394         /* Thread. */
3395         thread_ip_inc(p);
3396 }
3397
3398 static inline void
3399 instr_alu_shl_hm_exec(struct rte_swx_pipeline *p)
3400 {
3401         struct thread *t = &p->threads[p->thread_id];
3402         struct instruction *ip = t->ip;
3403
3404         /* Structs. */
3405         __instr_alu_shl_hm_exec(p, t, ip);
3406
3407         /* Thread. */
3408         thread_ip_inc(p);
3409 }
3410
3411 static inline void
3412 instr_alu_shl_hh_exec(struct rte_swx_pipeline *p)
3413 {
3414         struct thread *t = &p->threads[p->thread_id];
3415         struct instruction *ip = t->ip;
3416
3417         /* Structs. */
3418         __instr_alu_shl_hh_exec(p, t, ip);
3419
3420         /* Thread. */
3421         thread_ip_inc(p);
3422 }
3423
3424 static inline void
3425 instr_alu_shl_mi_exec(struct rte_swx_pipeline *p)
3426 {
3427         struct thread *t = &p->threads[p->thread_id];
3428         struct instruction *ip = t->ip;
3429
3430         /* Structs. */
3431         __instr_alu_shl_mi_exec(p, t, ip);
3432
3433         /* Thread. */
3434         thread_ip_inc(p);
3435 }
3436
3437 static inline void
3438 instr_alu_shl_hi_exec(struct rte_swx_pipeline *p)
3439 {
3440         struct thread *t = &p->threads[p->thread_id];
3441         struct instruction *ip = t->ip;
3442
3443         /* Structs. */
3444         __instr_alu_shl_hi_exec(p, t, ip);
3445
3446         /* Thread. */
3447         thread_ip_inc(p);
3448 }
3449
3450 static inline void
3451 instr_alu_shr_exec(struct rte_swx_pipeline *p)
3452 {
3453         struct thread *t = &p->threads[p->thread_id];
3454         struct instruction *ip = t->ip;
3455
3456         /* Structs. */
3457         __instr_alu_shr_exec(p, t, ip);
3458
3459         /* Thread. */
3460         thread_ip_inc(p);
3461 }
3462
3463 static inline void
3464 instr_alu_shr_mh_exec(struct rte_swx_pipeline *p)
3465 {
3466         struct thread *t = &p->threads[p->thread_id];
3467         struct instruction *ip = t->ip;
3468
3469         /* Structs. */
3470         __instr_alu_shr_mh_exec(p, t, ip);
3471
3472         /* Thread. */
3473         thread_ip_inc(p);
3474 }
3475
3476 static inline void
3477 instr_alu_shr_hm_exec(struct rte_swx_pipeline *p)
3478 {
3479         struct thread *t = &p->threads[p->thread_id];
3480         struct instruction *ip = t->ip;
3481
3482         /* Structs. */
3483         __instr_alu_shr_hm_exec(p, t, ip);
3484
3485         /* Thread. */
3486         thread_ip_inc(p);
3487 }
3488
3489 static inline void
3490 instr_alu_shr_hh_exec(struct rte_swx_pipeline *p)
3491 {
3492         struct thread *t = &p->threads[p->thread_id];
3493         struct instruction *ip = t->ip;
3494
3495         /* Structs. */
3496         __instr_alu_shr_hh_exec(p, t, ip);
3497
3498         /* Thread. */
3499         thread_ip_inc(p);
3500 }
3501
3502 static inline void
3503 instr_alu_shr_mi_exec(struct rte_swx_pipeline *p)
3504 {
3505         struct thread *t = &p->threads[p->thread_id];
3506         struct instruction *ip = t->ip;
3507
3508         /* Structs. */
3509         __instr_alu_shr_mi_exec(p, t, ip);
3510
3511         /* Thread. */
3512         thread_ip_inc(p);
3513 }
3514
3515 static inline void
3516 instr_alu_shr_hi_exec(struct rte_swx_pipeline *p)
3517 {
3518         struct thread *t = &p->threads[p->thread_id];
3519         struct instruction *ip = t->ip;
3520
3521         /* Structs. */
3522         __instr_alu_shr_hi_exec(p, t, ip);
3523
3524         /* Thread. */
3525         thread_ip_inc(p);
3526 }
3527
3528 static inline void
3529 instr_alu_and_exec(struct rte_swx_pipeline *p)
3530 {
3531         struct thread *t = &p->threads[p->thread_id];
3532         struct instruction *ip = t->ip;
3533
3534         /* Structs. */
3535         __instr_alu_and_exec(p, t, ip);
3536
3537         /* Thread. */
3538         thread_ip_inc(p);
3539 }
3540
3541 static inline void
3542 instr_alu_and_mh_exec(struct rte_swx_pipeline *p)
3543 {
3544         struct thread *t = &p->threads[p->thread_id];
3545         struct instruction *ip = t->ip;
3546
3547         /* Structs. */
3548         __instr_alu_and_mh_exec(p, t, ip);
3549
3550         /* Thread. */
3551         thread_ip_inc(p);
3552 }
3553
3554 static inline void
3555 instr_alu_and_hm_exec(struct rte_swx_pipeline *p)
3556 {
3557         struct thread *t = &p->threads[p->thread_id];
3558         struct instruction *ip = t->ip;
3559
3560         /* Structs. */
3561         __instr_alu_and_hm_exec(p, t, ip);
3562
3563         /* Thread. */
3564         thread_ip_inc(p);
3565 }
3566
3567 static inline void
3568 instr_alu_and_hh_exec(struct rte_swx_pipeline *p)
3569 {
3570         struct thread *t = &p->threads[p->thread_id];
3571         struct instruction *ip = t->ip;
3572
3573         /* Structs. */
3574         __instr_alu_and_hh_exec(p, t, ip);
3575
3576         /* Thread. */
3577         thread_ip_inc(p);
3578 }
3579
3580 static inline void
3581 instr_alu_and_i_exec(struct rte_swx_pipeline *p)
3582 {
3583         struct thread *t = &p->threads[p->thread_id];
3584         struct instruction *ip = t->ip;
3585
3586         /* Structs. */
3587         __instr_alu_and_i_exec(p, t, ip);
3588
3589         /* Thread. */
3590         thread_ip_inc(p);
3591 }
3592
3593 static inline void
3594 instr_alu_or_exec(struct rte_swx_pipeline *p)
3595 {
3596         struct thread *t = &p->threads[p->thread_id];
3597         struct instruction *ip = t->ip;
3598
3599         /* Structs. */
3600         __instr_alu_or_exec(p, t, ip);
3601
3602         /* Thread. */
3603         thread_ip_inc(p);
3604 }
3605
3606 static inline void
3607 instr_alu_or_mh_exec(struct rte_swx_pipeline *p)
3608 {
3609         struct thread *t = &p->threads[p->thread_id];
3610         struct instruction *ip = t->ip;
3611
3612         /* Structs. */
3613         __instr_alu_or_mh_exec(p, t, ip);
3614
3615         /* Thread. */
3616         thread_ip_inc(p);
3617 }
3618
3619 static inline void
3620 instr_alu_or_hm_exec(struct rte_swx_pipeline *p)
3621 {
3622         struct thread *t = &p->threads[p->thread_id];
3623         struct instruction *ip = t->ip;
3624
3625         /* Structs. */
3626         __instr_alu_or_hm_exec(p, t, ip);
3627
3628         /* Thread. */
3629         thread_ip_inc(p);
3630 }
3631
3632 static inline void
3633 instr_alu_or_hh_exec(struct rte_swx_pipeline *p)
3634 {
3635         struct thread *t = &p->threads[p->thread_id];
3636         struct instruction *ip = t->ip;
3637
3638         /* Structs. */
3639         __instr_alu_or_hh_exec(p, t, ip);
3640
3641         /* Thread. */
3642         thread_ip_inc(p);
3643 }
3644
3645 static inline void
3646 instr_alu_or_i_exec(struct rte_swx_pipeline *p)
3647 {
3648         struct thread *t = &p->threads[p->thread_id];
3649         struct instruction *ip = t->ip;
3650
3651         /* Structs. */
3652         __instr_alu_or_i_exec(p, t, ip);
3653
3654         /* Thread. */
3655         thread_ip_inc(p);
3656 }
3657
3658 static inline void
3659 instr_alu_xor_exec(struct rte_swx_pipeline *p)
3660 {
3661         struct thread *t = &p->threads[p->thread_id];
3662         struct instruction *ip = t->ip;
3663
3664         /* Structs. */
3665         __instr_alu_xor_exec(p, t, ip);
3666
3667         /* Thread. */
3668         thread_ip_inc(p);
3669 }
3670
3671 static inline void
3672 instr_alu_xor_mh_exec(struct rte_swx_pipeline *p)
3673 {
3674         struct thread *t = &p->threads[p->thread_id];
3675         struct instruction *ip = t->ip;
3676
3677         /* Structs. */
3678         __instr_alu_xor_mh_exec(p, t, ip);
3679
3680         /* Thread. */
3681         thread_ip_inc(p);
3682 }
3683
3684 static inline void
3685 instr_alu_xor_hm_exec(struct rte_swx_pipeline *p)
3686 {
3687         struct thread *t = &p->threads[p->thread_id];
3688         struct instruction *ip = t->ip;
3689
3690         /* Structs. */
3691         __instr_alu_xor_hm_exec(p, t, ip);
3692
3693         /* Thread. */
3694         thread_ip_inc(p);
3695 }
3696
3697 static inline void
3698 instr_alu_xor_hh_exec(struct rte_swx_pipeline *p)
3699 {
3700         struct thread *t = &p->threads[p->thread_id];
3701         struct instruction *ip = t->ip;
3702
3703         /* Structs. */
3704         __instr_alu_xor_hh_exec(p, t, ip);
3705
3706         /* Thread. */
3707         thread_ip_inc(p);
3708 }
3709
3710 static inline void
3711 instr_alu_xor_i_exec(struct rte_swx_pipeline *p)
3712 {
3713         struct thread *t = &p->threads[p->thread_id];
3714         struct instruction *ip = t->ip;
3715
3716         /* Structs. */
3717         __instr_alu_xor_i_exec(p, t, ip);
3718
3719         /* Thread. */
3720         thread_ip_inc(p);
3721 }
3722
3723 static inline void
3724 instr_alu_ckadd_field_exec(struct rte_swx_pipeline *p)
3725 {
3726         struct thread *t = &p->threads[p->thread_id];
3727         struct instruction *ip = t->ip;
3728
3729         /* Structs. */
3730         __instr_alu_ckadd_field_exec(p, t, ip);
3731
3732         /* Thread. */
3733         thread_ip_inc(p);
3734 }
3735
3736 static inline void
3737 instr_alu_cksub_field_exec(struct rte_swx_pipeline *p)
3738 {
3739         struct thread *t = &p->threads[p->thread_id];
3740         struct instruction *ip = t->ip;
3741
3742         /* Structs. */
3743         __instr_alu_cksub_field_exec(p, t, ip);
3744
3745         /* Thread. */
3746         thread_ip_inc(p);
3747 }
3748
3749 static inline void
3750 instr_alu_ckadd_struct20_exec(struct rte_swx_pipeline *p)
3751 {
3752         struct thread *t = &p->threads[p->thread_id];
3753         struct instruction *ip = t->ip;
3754
3755         /* Structs. */
3756         __instr_alu_ckadd_struct20_exec(p, t, ip);
3757
3758         /* Thread. */
3759         thread_ip_inc(p);
3760 }
3761
3762 static inline void
3763 instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)
3764 {
3765         struct thread *t = &p->threads[p->thread_id];
3766         struct instruction *ip = t->ip;
3767
3768         /* Structs. */
3769         __instr_alu_ckadd_struct_exec(p, t, ip);
3770
3771         /* Thread. */
3772         thread_ip_inc(p);
3773 }
3774
3775 /*
3776  * Register array.
3777  */
3778 static struct regarray *
3779 regarray_find(struct rte_swx_pipeline *p, const char *name);
3780
3781 static int
3782 instr_regprefetch_translate(struct rte_swx_pipeline *p,
3783                       struct action *action,
3784                       char **tokens,
3785                       int n_tokens,
3786                       struct instruction *instr,
3787                       struct instruction_data *data __rte_unused)
3788 {
3789         char *regarray = tokens[1], *idx = tokens[2];
3790         struct regarray *r;
3791         struct field *fidx;
3792         uint32_t idx_struct_id, idx_val;
3793
3794         CHECK(n_tokens == 3, EINVAL);
3795
3796         r = regarray_find(p, regarray);
3797         CHECK(r, EINVAL);
3798
3799         /* REGPREFETCH_RH, REGPREFETCH_RM. */
3800         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3801         if (fidx) {
3802                 CHECK(!fidx->var_size, EINVAL);
3803
3804                 instr->type = INSTR_REGPREFETCH_RM;
3805                 if (idx[0] == 'h')
3806                         instr->type = INSTR_REGPREFETCH_RH;
3807
3808                 instr->regarray.regarray_id = r->id;
3809                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3810                 instr->regarray.idx.n_bits = fidx->n_bits;
3811                 instr->regarray.idx.offset = fidx->offset / 8;
3812                 instr->regarray.dstsrc_val = 0; /* Unused. */
3813                 return 0;
3814         }
3815
3816         /* REGPREFETCH_RI. */
3817         idx_val = strtoul(idx, &idx, 0);
3818         CHECK(!idx[0], EINVAL);
3819
3820         instr->type = INSTR_REGPREFETCH_RI;
3821         instr->regarray.regarray_id = r->id;
3822         instr->regarray.idx_val = idx_val;
3823         instr->regarray.dstsrc_val = 0; /* Unused. */
3824         return 0;
3825 }
3826
3827 static int
3828 instr_regrd_translate(struct rte_swx_pipeline *p,
3829                       struct action *action,
3830                       char **tokens,
3831                       int n_tokens,
3832                       struct instruction *instr,
3833                       struct instruction_data *data __rte_unused)
3834 {
3835         char *dst = tokens[1], *regarray = tokens[2], *idx = tokens[3];
3836         struct regarray *r;
3837         struct field *fdst, *fidx;
3838         uint32_t dst_struct_id, idx_struct_id, idx_val;
3839
3840         CHECK(n_tokens == 4, EINVAL);
3841
3842         r = regarray_find(p, regarray);
3843         CHECK(r, EINVAL);
3844
3845         fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3846         CHECK(fdst, EINVAL);
3847         CHECK(!fdst->var_size, EINVAL);
3848
3849         /* REGRD_HRH, REGRD_HRM, REGRD_MRH, REGRD_MRM. */
3850         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3851         if (fidx) {
3852                 CHECK(!fidx->var_size, EINVAL);
3853
3854                 instr->type = INSTR_REGRD_MRM;
3855                 if (dst[0] == 'h' && idx[0] != 'h')
3856                         instr->type = INSTR_REGRD_HRM;
3857                 if (dst[0] != 'h' && idx[0] == 'h')
3858                         instr->type = INSTR_REGRD_MRH;
3859                 if (dst[0] == 'h' && idx[0] == 'h')
3860                         instr->type = INSTR_REGRD_HRH;
3861
3862                 instr->regarray.regarray_id = r->id;
3863                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3864                 instr->regarray.idx.n_bits = fidx->n_bits;
3865                 instr->regarray.idx.offset = fidx->offset / 8;
3866                 instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;
3867                 instr->regarray.dstsrc.n_bits = fdst->n_bits;
3868                 instr->regarray.dstsrc.offset = fdst->offset / 8;
3869                 return 0;
3870         }
3871
3872         /* REGRD_MRI, REGRD_HRI. */
3873         idx_val = strtoul(idx, &idx, 0);
3874         CHECK(!idx[0], EINVAL);
3875
3876         instr->type = INSTR_REGRD_MRI;
3877         if (dst[0] == 'h')
3878                 instr->type = INSTR_REGRD_HRI;
3879
3880         instr->regarray.regarray_id = r->id;
3881         instr->regarray.idx_val = idx_val;
3882         instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;
3883         instr->regarray.dstsrc.n_bits = fdst->n_bits;
3884         instr->regarray.dstsrc.offset = fdst->offset / 8;
3885         return 0;
3886 }
3887
3888 static int
3889 instr_regwr_translate(struct rte_swx_pipeline *p,
3890                       struct action *action,
3891                       char **tokens,
3892                       int n_tokens,
3893                       struct instruction *instr,
3894                       struct instruction_data *data __rte_unused)
3895 {
3896         char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];
3897         struct regarray *r;
3898         struct field *fidx, *fsrc;
3899         uint64_t src_val;
3900         uint32_t idx_struct_id, idx_val, src_struct_id;
3901
3902         CHECK(n_tokens == 4, EINVAL);
3903
3904         r = regarray_find(p, regarray);
3905         CHECK(r, EINVAL);
3906
3907         /* REGWR_RHH, REGWR_RHM, REGWR_RMH, REGWR_RMM. */
3908         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3909         fsrc = struct_field_parse(p, action, src, &src_struct_id);
3910         if (fidx && fsrc) {
3911                 CHECK(!fidx->var_size, EINVAL);
3912                 CHECK(!fsrc->var_size, EINVAL);
3913
3914                 instr->type = INSTR_REGWR_RMM;
3915                 if (idx[0] == 'h' && src[0] != 'h')
3916                         instr->type = INSTR_REGWR_RHM;
3917                 if (idx[0] != 'h' && src[0] == 'h')
3918                         instr->type = INSTR_REGWR_RMH;
3919                 if (idx[0] == 'h' && src[0] == 'h')
3920                         instr->type = INSTR_REGWR_RHH;
3921
3922                 instr->regarray.regarray_id = r->id;
3923                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3924                 instr->regarray.idx.n_bits = fidx->n_bits;
3925                 instr->regarray.idx.offset = fidx->offset / 8;
3926                 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
3927                 instr->regarray.dstsrc.n_bits = fsrc->n_bits;
3928                 instr->regarray.dstsrc.offset = fsrc->offset / 8;
3929                 return 0;
3930         }
3931
3932         /* REGWR_RHI, REGWR_RMI. */
3933         if (fidx && !fsrc) {
3934                 CHECK(!fidx->var_size, EINVAL);
3935
3936                 src_val = strtoull(src, &src, 0);
3937                 CHECK(!src[0], EINVAL);
3938
3939                 instr->type = INSTR_REGWR_RMI;
3940                 if (idx[0] == 'h')
3941                         instr->type = INSTR_REGWR_RHI;
3942
3943                 instr->regarray.regarray_id = r->id;
3944                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3945                 instr->regarray.idx.n_bits = fidx->n_bits;
3946                 instr->regarray.idx.offset = fidx->offset / 8;
3947                 instr->regarray.dstsrc_val = src_val;
3948                 return 0;
3949         }
3950
3951         /* REGWR_RIH, REGWR_RIM. */
3952         if (!fidx && fsrc) {
3953                 idx_val = strtoul(idx, &idx, 0);
3954                 CHECK(!idx[0], EINVAL);
3955
3956                 CHECK(!fsrc->var_size, EINVAL);
3957
3958                 instr->type = INSTR_REGWR_RIM;
3959                 if (src[0] == 'h')
3960                         instr->type = INSTR_REGWR_RIH;
3961
3962                 instr->regarray.regarray_id = r->id;
3963                 instr->regarray.idx_val = idx_val;
3964                 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
3965                 instr->regarray.dstsrc.n_bits = fsrc->n_bits;
3966                 instr->regarray.dstsrc.offset = fsrc->offset / 8;
3967                 return 0;
3968         }
3969
3970         /* REGWR_RII. */
3971         src_val = strtoull(src, &src, 0);
3972         CHECK(!src[0], EINVAL);
3973
3974         idx_val = strtoul(idx, &idx, 0);
3975         CHECK(!idx[0], EINVAL);
3976
3977         instr->type = INSTR_REGWR_RII;
3978         instr->regarray.idx_val = idx_val;
3979         instr->regarray.dstsrc_val = src_val;
3980
3981         return 0;
3982 }
3983
3984 static int
3985 instr_regadd_translate(struct rte_swx_pipeline *p,
3986                        struct action *action,
3987                        char **tokens,
3988                        int n_tokens,
3989                        struct instruction *instr,
3990                        struct instruction_data *data __rte_unused)
3991 {
3992         char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];
3993         struct regarray *r;
3994         struct field *fidx, *fsrc;
3995         uint64_t src_val;
3996         uint32_t idx_struct_id, idx_val, src_struct_id;
3997
3998         CHECK(n_tokens == 4, EINVAL);
3999
4000         r = regarray_find(p, regarray);
4001         CHECK(r, EINVAL);
4002
4003         /* REGADD_RHH, REGADD_RHM, REGADD_RMH, REGADD_RMM. */
4004         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4005         fsrc = struct_field_parse(p, action, src, &src_struct_id);
4006         if (fidx && fsrc) {
4007                 CHECK(!fidx->var_size, EINVAL);
4008                 CHECK(!fsrc->var_size, EINVAL);
4009
4010                 instr->type = INSTR_REGADD_RMM;
4011                 if (idx[0] == 'h' && src[0] != 'h')
4012                         instr->type = INSTR_REGADD_RHM;
4013                 if (idx[0] != 'h' && src[0] == 'h')
4014                         instr->type = INSTR_REGADD_RMH;
4015                 if (idx[0] == 'h' && src[0] == 'h')
4016                         instr->type = INSTR_REGADD_RHH;
4017
4018                 instr->regarray.regarray_id = r->id;
4019                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
4020                 instr->regarray.idx.n_bits = fidx->n_bits;
4021                 instr->regarray.idx.offset = fidx->offset / 8;
4022                 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
4023                 instr->regarray.dstsrc.n_bits = fsrc->n_bits;
4024                 instr->regarray.dstsrc.offset = fsrc->offset / 8;
4025                 return 0;
4026         }
4027
4028         /* REGADD_RHI, REGADD_RMI. */
4029         if (fidx && !fsrc) {
4030                 CHECK(!fidx->var_size, EINVAL);
4031
4032                 src_val = strtoull(src, &src, 0);
4033                 CHECK(!src[0], EINVAL);
4034
4035                 instr->type = INSTR_REGADD_RMI;
4036                 if (idx[0] == 'h')
4037                         instr->type = INSTR_REGADD_RHI;
4038
4039                 instr->regarray.regarray_id = r->id;
4040                 instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
4041                 instr->regarray.idx.n_bits = fidx->n_bits;
4042                 instr->regarray.idx.offset = fidx->offset / 8;
4043                 instr->regarray.dstsrc_val = src_val;
4044                 return 0;
4045         }
4046
4047         /* REGADD_RIH, REGADD_RIM. */
4048         if (!fidx && fsrc) {
4049                 idx_val = strtoul(idx, &idx, 0);
4050                 CHECK(!idx[0], EINVAL);
4051
4052                 CHECK(!fsrc->var_size, EINVAL);
4053
4054                 instr->type = INSTR_REGADD_RIM;
4055                 if (src[0] == 'h')
4056                         instr->type = INSTR_REGADD_RIH;
4057
4058                 instr->regarray.regarray_id = r->id;
4059                 instr->regarray.idx_val = idx_val;
4060                 instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
4061                 instr->regarray.dstsrc.n_bits = fsrc->n_bits;
4062                 instr->regarray.dstsrc.offset = fsrc->offset / 8;
4063                 return 0;
4064         }
4065
4066         /* REGADD_RII. */
4067         src_val = strtoull(src, &src, 0);
4068         CHECK(!src[0], EINVAL);
4069
4070         idx_val = strtoul(idx, &idx, 0);
4071         CHECK(!idx[0], EINVAL);
4072
4073         instr->type = INSTR_REGADD_RII;
4074         instr->regarray.idx_val = idx_val;
4075         instr->regarray.dstsrc_val = src_val;
4076         return 0;
4077 }
4078
4079 static inline void
4080 instr_regprefetch_rh_exec(struct rte_swx_pipeline *p)
4081 {
4082         struct thread *t = &p->threads[p->thread_id];
4083         struct instruction *ip = t->ip;
4084
4085         /* Structs. */
4086         __instr_regprefetch_rh_exec(p, t, ip);
4087
4088         /* Thread. */
4089         thread_ip_inc(p);
4090 }
4091
4092 static inline void
4093 instr_regprefetch_rm_exec(struct rte_swx_pipeline *p)
4094 {
4095         struct thread *t = &p->threads[p->thread_id];
4096         struct instruction *ip = t->ip;
4097
4098         /* Structs. */
4099         __instr_regprefetch_rm_exec(p, t, ip);
4100
4101         /* Thread. */
4102         thread_ip_inc(p);
4103 }
4104
4105 static inline void
4106 instr_regprefetch_ri_exec(struct rte_swx_pipeline *p)
4107 {
4108         struct thread *t = &p->threads[p->thread_id];
4109         struct instruction *ip = t->ip;
4110
4111         /* Structs. */
4112         __instr_regprefetch_ri_exec(p, t, ip);
4113
4114         /* Thread. */
4115         thread_ip_inc(p);
4116 }
4117
4118 static inline void
4119 instr_regrd_hrh_exec(struct rte_swx_pipeline *p)
4120 {
4121         struct thread *t = &p->threads[p->thread_id];
4122         struct instruction *ip = t->ip;
4123
4124         /* Structs. */
4125         __instr_regrd_hrh_exec(p, t, ip);
4126
4127         /* Thread. */
4128         thread_ip_inc(p);
4129 }
4130
4131 static inline void
4132 instr_regrd_hrm_exec(struct rte_swx_pipeline *p)
4133 {
4134         struct thread *t = &p->threads[p->thread_id];
4135         struct instruction *ip = t->ip;
4136
4137         /* Structs. */
4138         __instr_regrd_hrm_exec(p, t, ip);
4139
4140         /* Thread. */
4141         thread_ip_inc(p);
4142 }
4143
4144 static inline void
4145 instr_regrd_mrh_exec(struct rte_swx_pipeline *p)
4146 {
4147         struct thread *t = &p->threads[p->thread_id];
4148         struct instruction *ip = t->ip;
4149
4150         /* Structs. */
4151         __instr_regrd_mrh_exec(p, t, ip);
4152
4153         /* Thread. */
4154         thread_ip_inc(p);
4155 }
4156
4157 static inline void
4158 instr_regrd_mrm_exec(struct rte_swx_pipeline *p)
4159 {
4160         struct thread *t = &p->threads[p->thread_id];
4161         struct instruction *ip = t->ip;
4162
4163         /* Structs. */
4164         __instr_regrd_mrm_exec(p, t, ip);
4165
4166         /* Thread. */
4167         thread_ip_inc(p);
4168 }
4169
4170 static inline void
4171 instr_regrd_hri_exec(struct rte_swx_pipeline *p)
4172 {
4173         struct thread *t = &p->threads[p->thread_id];
4174         struct instruction *ip = t->ip;
4175
4176         /* Structs. */
4177         __instr_regrd_hri_exec(p, t, ip);
4178
4179         /* Thread. */
4180         thread_ip_inc(p);
4181 }
4182
4183 static inline void
4184 instr_regrd_mri_exec(struct rte_swx_pipeline *p)
4185 {
4186         struct thread *t = &p->threads[p->thread_id];
4187         struct instruction *ip = t->ip;
4188
4189         /* Structs. */
4190         __instr_regrd_mri_exec(p, t, ip);
4191
4192         /* Thread. */
4193         thread_ip_inc(p);
4194 }
4195
4196 static inline void
4197 instr_regwr_rhh_exec(struct rte_swx_pipeline *p)
4198 {
4199         struct thread *t = &p->threads[p->thread_id];
4200         struct instruction *ip = t->ip;
4201
4202         /* Structs. */
4203         __instr_regwr_rhh_exec(p, t, ip);
4204
4205         /* Thread. */
4206         thread_ip_inc(p);
4207 }
4208
4209 static inline void
4210 instr_regwr_rhm_exec(struct rte_swx_pipeline *p)
4211 {
4212         struct thread *t = &p->threads[p->thread_id];
4213         struct instruction *ip = t->ip;
4214
4215         /* Structs. */
4216         __instr_regwr_rhm_exec(p, t, ip);
4217
4218         /* Thread. */
4219         thread_ip_inc(p);
4220 }
4221
4222 static inline void
4223 instr_regwr_rmh_exec(struct rte_swx_pipeline *p)
4224 {
4225         struct thread *t = &p->threads[p->thread_id];
4226         struct instruction *ip = t->ip;
4227
4228         /* Structs. */
4229         __instr_regwr_rmh_exec(p, t, ip);
4230
4231         /* Thread. */
4232         thread_ip_inc(p);
4233 }
4234
4235 static inline void
4236 instr_regwr_rmm_exec(struct rte_swx_pipeline *p)
4237 {
4238         struct thread *t = &p->threads[p->thread_id];
4239         struct instruction *ip = t->ip;
4240
4241         /* Structs. */
4242         __instr_regwr_rmm_exec(p, t, ip);
4243
4244         /* Thread. */
4245         thread_ip_inc(p);
4246 }
4247
4248 static inline void
4249 instr_regwr_rhi_exec(struct rte_swx_pipeline *p)
4250 {
4251         struct thread *t = &p->threads[p->thread_id];
4252         struct instruction *ip = t->ip;
4253
4254         /* Structs. */
4255         __instr_regwr_rhi_exec(p, t, ip);
4256
4257         /* Thread. */
4258         thread_ip_inc(p);
4259 }
4260
4261 static inline void
4262 instr_regwr_rmi_exec(struct rte_swx_pipeline *p)
4263 {
4264         struct thread *t = &p->threads[p->thread_id];
4265         struct instruction *ip = t->ip;
4266
4267         /* Structs. */
4268         __instr_regwr_rmi_exec(p, t, ip);
4269
4270         /* Thread. */
4271         thread_ip_inc(p);
4272 }
4273
4274 static inline void
4275 instr_regwr_rih_exec(struct rte_swx_pipeline *p)
4276 {
4277         struct thread *t = &p->threads[p->thread_id];
4278         struct instruction *ip = t->ip;
4279
4280         /* Structs. */
4281         __instr_regwr_rih_exec(p, t, ip);
4282
4283         /* Thread. */
4284         thread_ip_inc(p);
4285 }
4286
4287 static inline void
4288 instr_regwr_rim_exec(struct rte_swx_pipeline *p)
4289 {
4290         struct thread *t = &p->threads[p->thread_id];
4291         struct instruction *ip = t->ip;
4292
4293         /* Structs. */
4294         __instr_regwr_rim_exec(p, t, ip);
4295
4296         /* Thread. */
4297         thread_ip_inc(p);
4298 }
4299
4300 static inline void
4301 instr_regwr_rii_exec(struct rte_swx_pipeline *p)
4302 {
4303         struct thread *t = &p->threads[p->thread_id];
4304         struct instruction *ip = t->ip;
4305
4306         /* Structs. */
4307         __instr_regwr_rii_exec(p, t, ip);
4308
4309         /* Thread. */
4310         thread_ip_inc(p);
4311 }
4312
4313 static inline void
4314 instr_regadd_rhh_exec(struct rte_swx_pipeline *p)
4315 {
4316         struct thread *t = &p->threads[p->thread_id];
4317         struct instruction *ip = t->ip;
4318
4319         /* Structs. */
4320         __instr_regadd_rhh_exec(p, t, ip);
4321
4322         /* Thread. */
4323         thread_ip_inc(p);
4324 }
4325
4326 static inline void
4327 instr_regadd_rhm_exec(struct rte_swx_pipeline *p)
4328 {
4329         struct thread *t = &p->threads[p->thread_id];
4330         struct instruction *ip = t->ip;
4331
4332         /* Structs. */
4333         __instr_regadd_rhm_exec(p, t, ip);
4334
4335         /* Thread. */
4336         thread_ip_inc(p);
4337 }
4338
4339 static inline void
4340 instr_regadd_rmh_exec(struct rte_swx_pipeline *p)
4341 {
4342         struct thread *t = &p->threads[p->thread_id];
4343         struct instruction *ip = t->ip;
4344
4345         /* Structs. */
4346         __instr_regadd_rmh_exec(p, t, ip);
4347
4348         /* Thread. */
4349         thread_ip_inc(p);
4350 }
4351
4352 static inline void
4353 instr_regadd_rmm_exec(struct rte_swx_pipeline *p)
4354 {
4355         struct thread *t = &p->threads[p->thread_id];
4356         struct instruction *ip = t->ip;
4357
4358         /* Structs. */
4359         __instr_regadd_rmm_exec(p, t, ip);
4360
4361         /* Thread. */
4362         thread_ip_inc(p);
4363 }
4364
4365 static inline void
4366 instr_regadd_rhi_exec(struct rte_swx_pipeline *p)
4367 {
4368         struct thread *t = &p->threads[p->thread_id];
4369         struct instruction *ip = t->ip;
4370
4371         /* Structs. */
4372         __instr_regadd_rhi_exec(p, t, ip);
4373
4374         /* Thread. */
4375         thread_ip_inc(p);
4376 }
4377
4378 static inline void
4379 instr_regadd_rmi_exec(struct rte_swx_pipeline *p)
4380 {
4381         struct thread *t = &p->threads[p->thread_id];
4382         struct instruction *ip = t->ip;
4383
4384         /* Structs. */
4385         __instr_regadd_rmi_exec(p, t, ip);
4386
4387         /* Thread. */
4388         thread_ip_inc(p);
4389 }
4390
4391 static inline void
4392 instr_regadd_rih_exec(struct rte_swx_pipeline *p)
4393 {
4394         struct thread *t = &p->threads[p->thread_id];
4395         struct instruction *ip = t->ip;
4396
4397         /* Structs. */
4398         __instr_regadd_rih_exec(p, t, ip);
4399
4400         /* Thread. */
4401         thread_ip_inc(p);
4402 }
4403
4404 static inline void
4405 instr_regadd_rim_exec(struct rte_swx_pipeline *p)
4406 {
4407         struct thread *t = &p->threads[p->thread_id];
4408         struct instruction *ip = t->ip;
4409
4410         /* Structs. */
4411         __instr_regadd_rim_exec(p, t, ip);
4412
4413         /* Thread. */
4414         thread_ip_inc(p);
4415 }
4416
4417 static inline void
4418 instr_regadd_rii_exec(struct rte_swx_pipeline *p)
4419 {
4420         struct thread *t = &p->threads[p->thread_id];
4421         struct instruction *ip = t->ip;
4422
4423         /* Structs. */
4424         __instr_regadd_rii_exec(p, t, ip);
4425
4426         /* Thread. */
4427         thread_ip_inc(p);
4428 }
4429
4430 /*
4431  * metarray.
4432  */
4433 static struct metarray *
4434 metarray_find(struct rte_swx_pipeline *p, const char *name);
4435
4436 static int
4437 instr_metprefetch_translate(struct rte_swx_pipeline *p,
4438                             struct action *action,
4439                             char **tokens,
4440                             int n_tokens,
4441                             struct instruction *instr,
4442                             struct instruction_data *data __rte_unused)
4443 {
4444         char *metarray = tokens[1], *idx = tokens[2];
4445         struct metarray *m;
4446         struct field *fidx;
4447         uint32_t idx_struct_id, idx_val;
4448
4449         CHECK(n_tokens == 3, EINVAL);
4450
4451         m = metarray_find(p, metarray);
4452         CHECK(m, EINVAL);
4453
4454         /* METPREFETCH_H, METPREFETCH_M. */
4455         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4456         if (fidx) {
4457                 CHECK(!fidx->var_size, EINVAL);
4458
4459                 instr->type = INSTR_METPREFETCH_M;
4460                 if (idx[0] == 'h')
4461                         instr->type = INSTR_METPREFETCH_H;
4462
4463                 instr->meter.metarray_id = m->id;
4464                 instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4465                 instr->meter.idx.n_bits = fidx->n_bits;
4466                 instr->meter.idx.offset = fidx->offset / 8;
4467                 return 0;
4468         }
4469
4470         /* METPREFETCH_I. */
4471         idx_val = strtoul(idx, &idx, 0);
4472         CHECK(!idx[0], EINVAL);
4473
4474         instr->type = INSTR_METPREFETCH_I;
4475         instr->meter.metarray_id = m->id;
4476         instr->meter.idx_val = idx_val;
4477         return 0;
4478 }
4479
4480 static int
4481 instr_meter_translate(struct rte_swx_pipeline *p,
4482                       struct action *action,
4483                       char **tokens,
4484                       int n_tokens,
4485                       struct instruction *instr,
4486                       struct instruction_data *data __rte_unused)
4487 {
4488         char *metarray = tokens[1], *idx = tokens[2], *length = tokens[3];
4489         char *color_in = tokens[4], *color_out = tokens[5];
4490         struct metarray *m;
4491         struct field *fidx, *flength, *fcin, *fcout;
4492         uint32_t idx_struct_id, length_struct_id;
4493         uint32_t color_in_struct_id, color_out_struct_id;
4494
4495         CHECK(n_tokens == 6, EINVAL);
4496
4497         m = metarray_find(p, metarray);
4498         CHECK(m, EINVAL);
4499
4500         fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4501
4502         flength = struct_field_parse(p, action, length, &length_struct_id);
4503         CHECK(flength, EINVAL);
4504         CHECK(!flength->var_size, EINVAL);
4505
4506         fcin = struct_field_parse(p, action, color_in, &color_in_struct_id);
4507
4508         fcout = struct_field_parse(p, NULL, color_out, &color_out_struct_id);
4509         CHECK(fcout, EINVAL);
4510         CHECK(!fcout->var_size, EINVAL);
4511
4512         /* index = HMEFT, length = HMEFT, color_in = MEFT, color_out = MEF. */
4513         if (fidx && fcin) {
4514                 CHECK(!fidx->var_size, EINVAL);
4515                 CHECK(!fcin->var_size, EINVAL);
4516
4517                 instr->type = INSTR_METER_MMM;
4518                 if (idx[0] == 'h' && length[0] == 'h')
4519                         instr->type = INSTR_METER_HHM;
4520                 if (idx[0] == 'h' && length[0] != 'h')
4521                         instr->type = INSTR_METER_HMM;
4522                 if (idx[0] != 'h' && length[0] == 'h')
4523                         instr->type = INSTR_METER_MHM;
4524
4525                 instr->meter.metarray_id = m->id;
4526
4527                 instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4528                 instr->meter.idx.n_bits = fidx->n_bits;
4529                 instr->meter.idx.offset = fidx->offset / 8;
4530
4531                 instr->meter.length.struct_id = (uint8_t)length_struct_id;
4532                 instr->meter.length.n_bits = flength->n_bits;
4533                 instr->meter.length.offset = flength->offset / 8;
4534
4535                 instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id;
4536                 instr->meter.color_in.n_bits = fcin->n_bits;
4537                 instr->meter.color_in.offset = fcin->offset / 8;
4538
4539                 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4540                 instr->meter.color_out.n_bits = fcout->n_bits;
4541                 instr->meter.color_out.offset = fcout->offset / 8;
4542
4543                 return 0;
4544         }
4545
4546         /* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */
4547         if (fidx && !fcin) {
4548                 uint32_t color_in_val;
4549
4550                 CHECK(!fidx->var_size, EINVAL);
4551
4552                 color_in_val = strtoul(color_in, &color_in, 0);
4553                 CHECK(!color_in[0], EINVAL);
4554
4555                 instr->type = INSTR_METER_MMI;
4556                 if (idx[0] == 'h' && length[0] == 'h')
4557                         instr->type = INSTR_METER_HHI;
4558                 if (idx[0] == 'h' && length[0] != 'h')
4559                         instr->type = INSTR_METER_HMI;
4560                 if (idx[0] != 'h' && length[0] == 'h')
4561                         instr->type = INSTR_METER_MHI;
4562
4563                 instr->meter.metarray_id = m->id;
4564
4565                 instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4566                 instr->meter.idx.n_bits = fidx->n_bits;
4567                 instr->meter.idx.offset = fidx->offset / 8;
4568
4569                 instr->meter.length.struct_id = (uint8_t)length_struct_id;
4570                 instr->meter.length.n_bits = flength->n_bits;
4571                 instr->meter.length.offset = flength->offset / 8;
4572
4573                 instr->meter.color_in_val = color_in_val;
4574
4575                 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4576                 instr->meter.color_out.n_bits = fcout->n_bits;
4577                 instr->meter.color_out.offset = fcout->offset / 8;
4578
4579                 return 0;
4580         }
4581
4582         /* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */
4583         if (!fidx && fcin) {
4584                 uint32_t idx_val;
4585
4586                 idx_val = strtoul(idx, &idx, 0);
4587                 CHECK(!idx[0], EINVAL);
4588
4589                 CHECK(!fcin->var_size, EINVAL);
4590
4591                 instr->type = INSTR_METER_IMM;
4592                 if (length[0] == 'h')
4593                         instr->type = INSTR_METER_IHM;
4594
4595                 instr->meter.metarray_id = m->id;
4596
4597                 instr->meter.idx_val = idx_val;
4598
4599                 instr->meter.length.struct_id = (uint8_t)length_struct_id;
4600                 instr->meter.length.n_bits = flength->n_bits;
4601                 instr->meter.length.offset = flength->offset / 8;
4602
4603                 instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id;
4604                 instr->meter.color_in.n_bits = fcin->n_bits;
4605                 instr->meter.color_in.offset = fcin->offset / 8;
4606
4607                 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4608                 instr->meter.color_out.n_bits = fcout->n_bits;
4609                 instr->meter.color_out.offset = fcout->offset / 8;
4610
4611                 return 0;
4612         }
4613
4614         /* index = I, length = HMEFT, color_in = I, color_out = MEF. */
4615         if (!fidx && !fcin) {
4616                 uint32_t idx_val, color_in_val;
4617
4618                 idx_val = strtoul(idx, &idx, 0);
4619                 CHECK(!idx[0], EINVAL);
4620
4621                 color_in_val = strtoul(color_in, &color_in, 0);
4622                 CHECK(!color_in[0], EINVAL);
4623
4624                 instr->type = INSTR_METER_IMI;
4625                 if (length[0] == 'h')
4626                         instr->type = INSTR_METER_IHI;
4627
4628                 instr->meter.metarray_id = m->id;
4629
4630                 instr->meter.idx_val = idx_val;
4631
4632                 instr->meter.length.struct_id = (uint8_t)length_struct_id;
4633                 instr->meter.length.n_bits = flength->n_bits;
4634                 instr->meter.length.offset = flength->offset / 8;
4635
4636                 instr->meter.color_in_val = color_in_val;
4637
4638                 instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4639                 instr->meter.color_out.n_bits = fcout->n_bits;
4640                 instr->meter.color_out.offset = fcout->offset / 8;
4641
4642                 return 0;
4643         }
4644
4645         CHECK(0, EINVAL);
4646 }
4647
4648 static inline void
4649 instr_metprefetch_h_exec(struct rte_swx_pipeline *p)
4650 {
4651         struct thread *t = &p->threads[p->thread_id];
4652         struct instruction *ip = t->ip;
4653
4654         /* Structs. */
4655         __instr_metprefetch_h_exec(p, t, ip);
4656
4657         /* Thread. */
4658         thread_ip_inc(p);
4659 }
4660
4661 static inline void
4662 instr_metprefetch_m_exec(struct rte_swx_pipeline *p)
4663 {
4664         struct thread *t = &p->threads[p->thread_id];
4665         struct instruction *ip = t->ip;
4666
4667         /* Structs. */
4668         __instr_metprefetch_m_exec(p, t, ip);
4669
4670         /* Thread. */
4671         thread_ip_inc(p);
4672 }
4673
4674 static inline void
4675 instr_metprefetch_i_exec(struct rte_swx_pipeline *p)
4676 {
4677         struct thread *t = &p->threads[p->thread_id];
4678         struct instruction *ip = t->ip;
4679
4680         /* Structs. */
4681         __instr_metprefetch_i_exec(p, t, ip);
4682
4683         /* Thread. */
4684         thread_ip_inc(p);
4685 }
4686
4687 static inline void
4688 instr_meter_hhm_exec(struct rte_swx_pipeline *p)
4689 {
4690         struct thread *t = &p->threads[p->thread_id];
4691         struct instruction *ip = t->ip;
4692
4693         /* Structs. */
4694         __instr_meter_hhm_exec(p, t, ip);
4695
4696         /* Thread. */
4697         thread_ip_inc(p);
4698 }
4699
4700 static inline void
4701 instr_meter_hhi_exec(struct rte_swx_pipeline *p)
4702 {
4703         struct thread *t = &p->threads[p->thread_id];
4704         struct instruction *ip = t->ip;
4705
4706         /* Structs. */
4707         __instr_meter_hhi_exec(p, t, ip);
4708
4709         /* Thread. */
4710         thread_ip_inc(p);
4711 }
4712
4713 static inline void
4714 instr_meter_hmm_exec(struct rte_swx_pipeline *p)
4715 {
4716         struct thread *t = &p->threads[p->thread_id];
4717         struct instruction *ip = t->ip;
4718
4719         /* Structs. */
4720         __instr_meter_hmm_exec(p, t, ip);
4721
4722         /* Thread. */
4723         thread_ip_inc(p);
4724 }
4725
4726 static inline void
4727 instr_meter_hmi_exec(struct rte_swx_pipeline *p)
4728 {
4729         struct thread *t = &p->threads[p->thread_id];
4730         struct instruction *ip = t->ip;
4731
4732         /* Structs. */
4733         __instr_meter_hmi_exec(p, t, ip);
4734
4735         /* Thread. */
4736         thread_ip_inc(p);
4737 }
4738
4739 static inline void
4740 instr_meter_mhm_exec(struct rte_swx_pipeline *p)
4741 {
4742         struct thread *t = &p->threads[p->thread_id];
4743         struct instruction *ip = t->ip;
4744
4745         /* Structs. */
4746         __instr_meter_mhm_exec(p, t, ip);
4747
4748         /* Thread. */
4749         thread_ip_inc(p);
4750 }
4751
4752 static inline void
4753 instr_meter_mhi_exec(struct rte_swx_pipeline *p)
4754 {
4755         struct thread *t = &p->threads[p->thread_id];
4756         struct instruction *ip = t->ip;
4757
4758         /* Structs. */
4759         __instr_meter_mhi_exec(p, t, ip);
4760
4761         /* Thread. */
4762         thread_ip_inc(p);
4763 }
4764
4765 static inline void
4766 instr_meter_mmm_exec(struct rte_swx_pipeline *p)
4767 {
4768         struct thread *t = &p->threads[p->thread_id];
4769         struct instruction *ip = t->ip;
4770
4771         /* Structs. */
4772         __instr_meter_mmm_exec(p, t, ip);
4773
4774         /* Thread. */
4775         thread_ip_inc(p);
4776 }
4777
4778 static inline void
4779 instr_meter_mmi_exec(struct rte_swx_pipeline *p)
4780 {
4781         struct thread *t = &p->threads[p->thread_id];
4782         struct instruction *ip = t->ip;
4783
4784         /* Structs. */
4785         __instr_meter_mmi_exec(p, t, ip);
4786
4787         /* Thread. */
4788         thread_ip_inc(p);
4789 }
4790
4791 static inline void
4792 instr_meter_ihm_exec(struct rte_swx_pipeline *p)
4793 {
4794         struct thread *t = &p->threads[p->thread_id];
4795         struct instruction *ip = t->ip;
4796
4797         /* Structs. */
4798         __instr_meter_ihm_exec(p, t, ip);
4799
4800         /* Thread. */
4801         thread_ip_inc(p);
4802 }
4803
4804 static inline void
4805 instr_meter_ihi_exec(struct rte_swx_pipeline *p)
4806 {
4807         struct thread *t = &p->threads[p->thread_id];
4808         struct instruction *ip = t->ip;
4809
4810         /* Structs. */
4811         __instr_meter_ihi_exec(p, t, ip);
4812
4813         /* Thread. */
4814         thread_ip_inc(p);
4815 }
4816
4817 static inline void
4818 instr_meter_imm_exec(struct rte_swx_pipeline *p)
4819 {
4820         struct thread *t = &p->threads[p->thread_id];
4821         struct instruction *ip = t->ip;
4822
4823         /* Structs. */
4824         __instr_meter_imm_exec(p, t, ip);
4825
4826         /* Thread. */
4827         thread_ip_inc(p);
4828 }
4829
4830 static inline void
4831 instr_meter_imi_exec(struct rte_swx_pipeline *p)
4832 {
4833         struct thread *t = &p->threads[p->thread_id];
4834         struct instruction *ip = t->ip;
4835
4836         /* Structs. */
4837         __instr_meter_imi_exec(p, t, ip);
4838
4839         /* Thread. */
4840         thread_ip_inc(p);
4841 }
4842
4843 /*
4844  * jmp.
4845  */
4846 static int
4847 instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,
4848                     struct action *action __rte_unused,
4849                     char **tokens,
4850                     int n_tokens,
4851                     struct instruction *instr,
4852                     struct instruction_data *data)
4853 {
4854         CHECK(n_tokens == 2, EINVAL);
4855
4856         strcpy(data->jmp_label, tokens[1]);
4857
4858         instr->type = INSTR_JMP;
4859         instr->jmp.ip = NULL; /* Resolved later. */
4860         return 0;
4861 }
4862
4863 static int
4864 instr_jmp_valid_translate(struct rte_swx_pipeline *p,
4865                           struct action *action __rte_unused,
4866                           char **tokens,
4867                           int n_tokens,
4868                           struct instruction *instr,
4869                           struct instruction_data *data)
4870 {
4871         struct header *h;
4872
4873         CHECK(n_tokens == 3, EINVAL);
4874
4875         strcpy(data->jmp_label, tokens[1]);
4876
4877         h = header_parse(p, tokens[2]);
4878         CHECK(h, EINVAL);
4879
4880         instr->type = INSTR_JMP_VALID;
4881         instr->jmp.ip = NULL; /* Resolved later. */
4882         instr->jmp.header_id = h->id;
4883         return 0;
4884 }
4885
4886 static int
4887 instr_jmp_invalid_translate(struct rte_swx_pipeline *p,
4888                             struct action *action __rte_unused,
4889                             char **tokens,
4890                             int n_tokens,
4891                             struct instruction *instr,
4892                             struct instruction_data *data)
4893 {
4894         struct header *h;
4895
4896         CHECK(n_tokens == 3, EINVAL);
4897
4898         strcpy(data->jmp_label, tokens[1]);
4899
4900         h = header_parse(p, tokens[2]);
4901         CHECK(h, EINVAL);
4902
4903         instr->type = INSTR_JMP_INVALID;
4904         instr->jmp.ip = NULL; /* Resolved later. */
4905         instr->jmp.header_id = h->id;
4906         return 0;
4907 }
4908
4909 static int
4910 instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,
4911                         struct action *action,
4912                         char **tokens,
4913                         int n_tokens,
4914                         struct instruction *instr,
4915                         struct instruction_data *data)
4916 {
4917         CHECK(!action, EINVAL);
4918         CHECK(n_tokens == 2, EINVAL);
4919
4920         strcpy(data->jmp_label, tokens[1]);
4921
4922         instr->type = INSTR_JMP_HIT;
4923         instr->jmp.ip = NULL; /* Resolved later. */
4924         return 0;
4925 }
4926
4927 static int
4928 instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,
4929                          struct action *action,
4930                          char **tokens,
4931                          int n_tokens,
4932                          struct instruction *instr,
4933                          struct instruction_data *data)
4934 {
4935         CHECK(!action, EINVAL);
4936         CHECK(n_tokens == 2, EINVAL);
4937
4938         strcpy(data->jmp_label, tokens[1]);
4939
4940         instr->type = INSTR_JMP_MISS;
4941         instr->jmp.ip = NULL; /* Resolved later. */
4942         return 0;
4943 }
4944
4945 static int
4946 instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,
4947                                struct action *action,
4948                                char **tokens,
4949                                int n_tokens,
4950                                struct instruction *instr,
4951                                struct instruction_data *data)
4952 {
4953         struct action *a;
4954
4955         CHECK(!action, EINVAL);
4956         CHECK(n_tokens == 3, EINVAL);
4957
4958         strcpy(data->jmp_label, tokens[1]);
4959
4960         a = action_find(p, tokens[2]);
4961         CHECK(a, EINVAL);
4962
4963         instr->type = INSTR_JMP_ACTION_HIT;
4964         instr->jmp.ip = NULL; /* Resolved later. */
4965         instr->jmp.action_id = a->id;
4966         return 0;
4967 }
4968
4969 static int
4970 instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,
4971                                 struct action *action,
4972                                 char **tokens,
4973                                 int n_tokens,
4974                                 struct instruction *instr,
4975                                 struct instruction_data *data)
4976 {
4977         struct action *a;
4978
4979         CHECK(!action, EINVAL);
4980         CHECK(n_tokens == 3, EINVAL);
4981
4982         strcpy(data->jmp_label, tokens[1]);
4983
4984         a = action_find(p, tokens[2]);
4985         CHECK(a, EINVAL);
4986
4987         instr->type = INSTR_JMP_ACTION_MISS;
4988         instr->jmp.ip = NULL; /* Resolved later. */
4989         instr->jmp.action_id = a->id;
4990         return 0;
4991 }
4992
4993 static int
4994 instr_jmp_eq_translate(struct rte_swx_pipeline *p,
4995                        struct action *action,
4996                        char **tokens,
4997                        int n_tokens,
4998                        struct instruction *instr,
4999                        struct instruction_data *data)
5000 {
5001         char *a = tokens[2], *b = tokens[3];
5002         struct field *fa, *fb;
5003         uint64_t b_val;
5004         uint32_t a_struct_id, b_struct_id;
5005
5006         CHECK(n_tokens == 4, EINVAL);
5007
5008         strcpy(data->jmp_label, tokens[1]);
5009
5010         fa = struct_field_parse(p, action, a, &a_struct_id);
5011         CHECK(fa, EINVAL);
5012         CHECK(!fa->var_size, EINVAL);
5013
5014         /* JMP_EQ, JMP_EQ_MH, JMP_EQ_HM, JMP_EQ_HH. */
5015         fb = struct_field_parse(p, action, b, &b_struct_id);
5016         if (fb) {
5017                 CHECK(!fb->var_size, EINVAL);
5018
5019                 instr->type = INSTR_JMP_EQ;
5020                 if (a[0] != 'h' && b[0] == 'h')
5021                         instr->type = INSTR_JMP_EQ_MH;
5022                 if (a[0] == 'h' && b[0] != 'h')
5023                         instr->type = INSTR_JMP_EQ_HM;
5024                 if (a[0] == 'h' && b[0] == 'h')
5025                         instr->type = INSTR_JMP_EQ_HH;
5026                 instr->jmp.ip = NULL; /* Resolved later. */
5027
5028                 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5029                 instr->jmp.a.n_bits = fa->n_bits;
5030                 instr->jmp.a.offset = fa->offset / 8;
5031                 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5032                 instr->jmp.b.n_bits = fb->n_bits;
5033                 instr->jmp.b.offset = fb->offset / 8;
5034                 return 0;
5035         }
5036
5037         /* JMP_EQ_I. */
5038         b_val = strtoull(b, &b, 0);
5039         CHECK(!b[0], EINVAL);
5040
5041         if (a[0] == 'h')
5042                 b_val = hton64(b_val) >> (64 - fa->n_bits);
5043
5044         instr->type = INSTR_JMP_EQ_I;
5045         instr->jmp.ip = NULL; /* Resolved later. */
5046         instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5047         instr->jmp.a.n_bits = fa->n_bits;
5048         instr->jmp.a.offset = fa->offset / 8;
5049         instr->jmp.b_val = b_val;
5050         return 0;
5051 }
5052
5053 static int
5054 instr_jmp_neq_translate(struct rte_swx_pipeline *p,
5055                         struct action *action,
5056                         char **tokens,
5057                         int n_tokens,
5058                         struct instruction *instr,
5059                         struct instruction_data *data)
5060 {
5061         char *a = tokens[2], *b = tokens[3];
5062         struct field *fa, *fb;
5063         uint64_t b_val;
5064         uint32_t a_struct_id, b_struct_id;
5065
5066         CHECK(n_tokens == 4, EINVAL);
5067
5068         strcpy(data->jmp_label, tokens[1]);
5069
5070         fa = struct_field_parse(p, action, a, &a_struct_id);
5071         CHECK(fa, EINVAL);
5072         CHECK(!fa->var_size, EINVAL);
5073
5074         /* JMP_NEQ, JMP_NEQ_MH, JMP_NEQ_HM, JMP_NEQ_HH. */
5075         fb = struct_field_parse(p, action, b, &b_struct_id);
5076         if (fb) {
5077                 CHECK(!fb->var_size, EINVAL);
5078
5079                 instr->type = INSTR_JMP_NEQ;
5080                 if (a[0] != 'h' && b[0] == 'h')
5081                         instr->type = INSTR_JMP_NEQ_MH;
5082                 if (a[0] == 'h' && b[0] != 'h')
5083                         instr->type = INSTR_JMP_NEQ_HM;
5084                 if (a[0] == 'h' && b[0] == 'h')
5085                         instr->type = INSTR_JMP_NEQ_HH;
5086                 instr->jmp.ip = NULL; /* Resolved later. */
5087
5088                 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5089                 instr->jmp.a.n_bits = fa->n_bits;
5090                 instr->jmp.a.offset = fa->offset / 8;
5091                 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5092                 instr->jmp.b.n_bits = fb->n_bits;
5093                 instr->jmp.b.offset = fb->offset / 8;
5094                 return 0;
5095         }
5096
5097         /* JMP_NEQ_I. */
5098         b_val = strtoull(b, &b, 0);
5099         CHECK(!b[0], EINVAL);
5100
5101         if (a[0] == 'h')
5102                 b_val = hton64(b_val) >> (64 - fa->n_bits);
5103
5104         instr->type = INSTR_JMP_NEQ_I;
5105         instr->jmp.ip = NULL; /* Resolved later. */
5106         instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5107         instr->jmp.a.n_bits = fa->n_bits;
5108         instr->jmp.a.offset = fa->offset / 8;
5109         instr->jmp.b_val = b_val;
5110         return 0;
5111 }
5112
5113 static int
5114 instr_jmp_lt_translate(struct rte_swx_pipeline *p,
5115                        struct action *action,
5116                        char **tokens,
5117                        int n_tokens,
5118                        struct instruction *instr,
5119                        struct instruction_data *data)
5120 {
5121         char *a = tokens[2], *b = tokens[3];
5122         struct field *fa, *fb;
5123         uint64_t b_val;
5124         uint32_t a_struct_id, b_struct_id;
5125
5126         CHECK(n_tokens == 4, EINVAL);
5127
5128         strcpy(data->jmp_label, tokens[1]);
5129
5130         fa = struct_field_parse(p, action, a, &a_struct_id);
5131         CHECK(fa, EINVAL);
5132         CHECK(!fa->var_size, EINVAL);
5133
5134         /* JMP_LT, JMP_LT_MH, JMP_LT_HM, JMP_LT_HH. */
5135         fb = struct_field_parse(p, action, b, &b_struct_id);
5136         if (fb) {
5137                 CHECK(!fb->var_size, EINVAL);
5138
5139                 instr->type = INSTR_JMP_LT;
5140                 if (a[0] == 'h' && b[0] != 'h')
5141                         instr->type = INSTR_JMP_LT_HM;
5142                 if (a[0] != 'h' && b[0] == 'h')
5143                         instr->type = INSTR_JMP_LT_MH;
5144                 if (a[0] == 'h' && b[0] == 'h')
5145                         instr->type = INSTR_JMP_LT_HH;
5146                 instr->jmp.ip = NULL; /* Resolved later. */
5147
5148                 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5149                 instr->jmp.a.n_bits = fa->n_bits;
5150                 instr->jmp.a.offset = fa->offset / 8;
5151                 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5152                 instr->jmp.b.n_bits = fb->n_bits;
5153                 instr->jmp.b.offset = fb->offset / 8;
5154                 return 0;
5155         }
5156
5157         /* JMP_LT_MI, JMP_LT_HI. */
5158         b_val = strtoull(b, &b, 0);
5159         CHECK(!b[0], EINVAL);
5160
5161         instr->type = INSTR_JMP_LT_MI;
5162         if (a[0] == 'h')
5163                 instr->type = INSTR_JMP_LT_HI;
5164         instr->jmp.ip = NULL; /* Resolved later. */
5165
5166         instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5167         instr->jmp.a.n_bits = fa->n_bits;
5168         instr->jmp.a.offset = fa->offset / 8;
5169         instr->jmp.b_val = b_val;
5170         return 0;
5171 }
5172
5173 static int
5174 instr_jmp_gt_translate(struct rte_swx_pipeline *p,
5175                        struct action *action,
5176                        char **tokens,
5177                        int n_tokens,
5178                        struct instruction *instr,
5179                        struct instruction_data *data)
5180 {
5181         char *a = tokens[2], *b = tokens[3];
5182         struct field *fa, *fb;
5183         uint64_t b_val;
5184         uint32_t a_struct_id, b_struct_id;
5185
5186         CHECK(n_tokens == 4, EINVAL);
5187
5188         strcpy(data->jmp_label, tokens[1]);
5189
5190         fa = struct_field_parse(p, action, a, &a_struct_id);
5191         CHECK(fa, EINVAL);
5192         CHECK(!fa->var_size, EINVAL);
5193
5194         /* JMP_GT, JMP_GT_MH, JMP_GT_HM, JMP_GT_HH. */
5195         fb = struct_field_parse(p, action, b, &b_struct_id);
5196         if (fb) {
5197                 CHECK(!fb->var_size, EINVAL);
5198
5199                 instr->type = INSTR_JMP_GT;
5200                 if (a[0] == 'h' && b[0] != 'h')
5201                         instr->type = INSTR_JMP_GT_HM;
5202                 if (a[0] != 'h' && b[0] == 'h')
5203                         instr->type = INSTR_JMP_GT_MH;
5204                 if (a[0] == 'h' && b[0] == 'h')
5205                         instr->type = INSTR_JMP_GT_HH;
5206                 instr->jmp.ip = NULL; /* Resolved later. */
5207
5208                 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5209                 instr->jmp.a.n_bits = fa->n_bits;
5210                 instr->jmp.a.offset = fa->offset / 8;
5211                 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5212                 instr->jmp.b.n_bits = fb->n_bits;
5213                 instr->jmp.b.offset = fb->offset / 8;
5214                 return 0;
5215         }
5216
5217         /* JMP_GT_MI, JMP_GT_HI. */
5218         b_val = strtoull(b, &b, 0);
5219         CHECK(!b[0], EINVAL);
5220
5221         instr->type = INSTR_JMP_GT_MI;
5222         if (a[0] == 'h')
5223                 instr->type = INSTR_JMP_GT_HI;
5224         instr->jmp.ip = NULL; /* Resolved later. */
5225
5226         instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5227         instr->jmp.a.n_bits = fa->n_bits;
5228         instr->jmp.a.offset = fa->offset / 8;
5229         instr->jmp.b_val = b_val;
5230         return 0;
5231 }
5232
5233 static inline void
5234 instr_jmp_exec(struct rte_swx_pipeline *p)
5235 {
5236         struct thread *t = &p->threads[p->thread_id];
5237         struct instruction *ip = t->ip;
5238
5239         TRACE("[Thread %2u] jmp\n", p->thread_id);
5240
5241         thread_ip_set(t, ip->jmp.ip);
5242 }
5243
5244 static inline void
5245 instr_jmp_valid_exec(struct rte_swx_pipeline *p)
5246 {
5247         struct thread *t = &p->threads[p->thread_id];
5248         struct instruction *ip = t->ip;
5249         uint32_t header_id = ip->jmp.header_id;
5250
5251         TRACE("[Thread %2u] jmpv\n", p->thread_id);
5252
5253         t->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1);
5254 }
5255
5256 static inline void
5257 instr_jmp_invalid_exec(struct rte_swx_pipeline *p)
5258 {
5259         struct thread *t = &p->threads[p->thread_id];
5260         struct instruction *ip = t->ip;
5261         uint32_t header_id = ip->jmp.header_id;
5262
5263         TRACE("[Thread %2u] jmpnv\n", p->thread_id);
5264
5265         t->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip;
5266 }
5267
5268 static inline void
5269 instr_jmp_hit_exec(struct rte_swx_pipeline *p)
5270 {
5271         struct thread *t = &p->threads[p->thread_id];
5272         struct instruction *ip = t->ip;
5273         struct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip};
5274
5275         TRACE("[Thread %2u] jmph\n", p->thread_id);
5276
5277         t->ip = ip_next[t->hit];
5278 }
5279
5280 static inline void
5281 instr_jmp_miss_exec(struct rte_swx_pipeline *p)
5282 {
5283         struct thread *t = &p->threads[p->thread_id];
5284         struct instruction *ip = t->ip;
5285         struct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1};
5286
5287         TRACE("[Thread %2u] jmpnh\n", p->thread_id);
5288
5289         t->ip = ip_next[t->hit];
5290 }
5291
5292 static inline void
5293 instr_jmp_action_hit_exec(struct rte_swx_pipeline *p)
5294 {
5295         struct thread *t = &p->threads[p->thread_id];
5296         struct instruction *ip = t->ip;
5297
5298         TRACE("[Thread %2u] jmpa\n", p->thread_id);
5299
5300         t->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1);
5301 }
5302
5303 static inline void
5304 instr_jmp_action_miss_exec(struct rte_swx_pipeline *p)
5305 {
5306         struct thread *t = &p->threads[p->thread_id];
5307         struct instruction *ip = t->ip;
5308
5309         TRACE("[Thread %2u] jmpna\n", p->thread_id);
5310
5311         t->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip;
5312 }
5313
5314 static inline void
5315 instr_jmp_eq_exec(struct rte_swx_pipeline *p)
5316 {
5317         struct thread *t = &p->threads[p->thread_id];
5318         struct instruction *ip = t->ip;
5319
5320         TRACE("[Thread %2u] jmpeq\n", p->thread_id);
5321
5322         JMP_CMP(t, ip, ==);
5323 }
5324
5325 static inline void
5326 instr_jmp_eq_mh_exec(struct rte_swx_pipeline *p)
5327 {
5328         struct thread *t = &p->threads[p->thread_id];
5329         struct instruction *ip = t->ip;
5330
5331         TRACE("[Thread %2u] jmpeq (mh)\n", p->thread_id);
5332
5333         JMP_CMP_MH(t, ip, ==);
5334 }
5335
5336 static inline void
5337 instr_jmp_eq_hm_exec(struct rte_swx_pipeline *p)
5338 {
5339         struct thread *t = &p->threads[p->thread_id];
5340         struct instruction *ip = t->ip;
5341
5342         TRACE("[Thread %2u] jmpeq (hm)\n", p->thread_id);
5343
5344         JMP_CMP_HM(t, ip, ==);
5345 }
5346
5347 static inline void
5348 instr_jmp_eq_hh_exec(struct rte_swx_pipeline *p)
5349 {
5350         struct thread *t = &p->threads[p->thread_id];
5351         struct instruction *ip = t->ip;
5352
5353         TRACE("[Thread %2u] jmpeq (hh)\n", p->thread_id);
5354
5355         JMP_CMP_HH_FAST(t, ip, ==);
5356 }
5357
5358 static inline void
5359 instr_jmp_eq_i_exec(struct rte_swx_pipeline *p)
5360 {
5361         struct thread *t = &p->threads[p->thread_id];
5362         struct instruction *ip = t->ip;
5363
5364         TRACE("[Thread %2u] jmpeq (i)\n", p->thread_id);
5365
5366         JMP_CMP_I(t, ip, ==);
5367 }
5368
5369 static inline void
5370 instr_jmp_neq_exec(struct rte_swx_pipeline *p)
5371 {
5372         struct thread *t = &p->threads[p->thread_id];
5373         struct instruction *ip = t->ip;
5374
5375         TRACE("[Thread %2u] jmpneq\n", p->thread_id);
5376
5377         JMP_CMP(t, ip, !=);
5378 }
5379
5380 static inline void
5381 instr_jmp_neq_mh_exec(struct rte_swx_pipeline *p)
5382 {
5383         struct thread *t = &p->threads[p->thread_id];
5384         struct instruction *ip = t->ip;
5385
5386         TRACE("[Thread %2u] jmpneq (mh)\n", p->thread_id);
5387
5388         JMP_CMP_MH(t, ip, !=);
5389 }
5390
5391 static inline void
5392 instr_jmp_neq_hm_exec(struct rte_swx_pipeline *p)
5393 {
5394         struct thread *t = &p->threads[p->thread_id];
5395         struct instruction *ip = t->ip;
5396
5397         TRACE("[Thread %2u] jmpneq (hm)\n", p->thread_id);
5398
5399         JMP_CMP_HM(t, ip, !=);
5400 }
5401
5402 static inline void
5403 instr_jmp_neq_hh_exec(struct rte_swx_pipeline *p)
5404 {
5405         struct thread *t = &p->threads[p->thread_id];
5406         struct instruction *ip = t->ip;
5407
5408         TRACE("[Thread %2u] jmpneq (hh)\n", p->thread_id);
5409
5410         JMP_CMP_HH_FAST(t, ip, !=);
5411 }
5412
5413 static inline void
5414 instr_jmp_neq_i_exec(struct rte_swx_pipeline *p)
5415 {
5416         struct thread *t = &p->threads[p->thread_id];
5417         struct instruction *ip = t->ip;
5418
5419         TRACE("[Thread %2u] jmpneq (i)\n", p->thread_id);
5420
5421         JMP_CMP_I(t, ip, !=);
5422 }
5423
5424 static inline void
5425 instr_jmp_lt_exec(struct rte_swx_pipeline *p)
5426 {
5427         struct thread *t = &p->threads[p->thread_id];
5428         struct instruction *ip = t->ip;
5429
5430         TRACE("[Thread %2u] jmplt\n", p->thread_id);
5431
5432         JMP_CMP(t, ip, <);
5433 }
5434
5435 static inline void
5436 instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p)
5437 {
5438         struct thread *t = &p->threads[p->thread_id];
5439         struct instruction *ip = t->ip;
5440
5441         TRACE("[Thread %2u] jmplt (mh)\n", p->thread_id);
5442
5443         JMP_CMP_MH(t, ip, <);
5444 }
5445
5446 static inline void
5447 instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p)
5448 {
5449         struct thread *t = &p->threads[p->thread_id];
5450         struct instruction *ip = t->ip;
5451
5452         TRACE("[Thread %2u] jmplt (hm)\n", p->thread_id);
5453
5454         JMP_CMP_HM(t, ip, <);
5455 }
5456
5457 static inline void
5458 instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p)
5459 {
5460         struct thread *t = &p->threads[p->thread_id];
5461         struct instruction *ip = t->ip;
5462
5463         TRACE("[Thread %2u] jmplt (hh)\n", p->thread_id);
5464
5465         JMP_CMP_HH(t, ip, <);
5466 }
5467
5468 static inline void
5469 instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p)
5470 {
5471         struct thread *t = &p->threads[p->thread_id];
5472         struct instruction *ip = t->ip;
5473
5474         TRACE("[Thread %2u] jmplt (mi)\n", p->thread_id);
5475
5476         JMP_CMP_MI(t, ip, <);
5477 }
5478
5479 static inline void
5480 instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p)
5481 {
5482         struct thread *t = &p->threads[p->thread_id];
5483         struct instruction *ip = t->ip;
5484
5485         TRACE("[Thread %2u] jmplt (hi)\n", p->thread_id);
5486
5487         JMP_CMP_HI(t, ip, <);
5488 }
5489
5490 static inline void
5491 instr_jmp_gt_exec(struct rte_swx_pipeline *p)
5492 {
5493         struct thread *t = &p->threads[p->thread_id];
5494         struct instruction *ip = t->ip;
5495
5496         TRACE("[Thread %2u] jmpgt\n", p->thread_id);
5497
5498         JMP_CMP(t, ip, >);
5499 }
5500
5501 static inline void
5502 instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p)
5503 {
5504         struct thread *t = &p->threads[p->thread_id];
5505         struct instruction *ip = t->ip;
5506
5507         TRACE("[Thread %2u] jmpgt (mh)\n", p->thread_id);
5508
5509         JMP_CMP_MH(t, ip, >);
5510 }
5511
5512 static inline void
5513 instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p)
5514 {
5515         struct thread *t = &p->threads[p->thread_id];
5516         struct instruction *ip = t->ip;
5517
5518         TRACE("[Thread %2u] jmpgt (hm)\n", p->thread_id);
5519
5520         JMP_CMP_HM(t, ip, >);
5521 }
5522
5523 static inline void
5524 instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p)
5525 {
5526         struct thread *t = &p->threads[p->thread_id];
5527         struct instruction *ip = t->ip;
5528
5529         TRACE("[Thread %2u] jmpgt (hh)\n", p->thread_id);
5530
5531         JMP_CMP_HH(t, ip, >);
5532 }
5533
5534 static inline void
5535 instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p)
5536 {
5537         struct thread *t = &p->threads[p->thread_id];
5538         struct instruction *ip = t->ip;
5539
5540         TRACE("[Thread %2u] jmpgt (mi)\n", p->thread_id);
5541
5542         JMP_CMP_MI(t, ip, >);
5543 }
5544
5545 static inline void
5546 instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p)
5547 {
5548         struct thread *t = &p->threads[p->thread_id];
5549         struct instruction *ip = t->ip;
5550
5551         TRACE("[Thread %2u] jmpgt (hi)\n", p->thread_id);
5552
5553         JMP_CMP_HI(t, ip, >);
5554 }
5555
5556 /*
5557  * return.
5558  */
5559 static int
5560 instr_return_translate(struct rte_swx_pipeline *p __rte_unused,
5561                        struct action *action,
5562                        char **tokens __rte_unused,
5563                        int n_tokens,
5564                        struct instruction *instr,
5565                        struct instruction_data *data __rte_unused)
5566 {
5567         CHECK(action, EINVAL);
5568         CHECK(n_tokens == 1, EINVAL);
5569
5570         instr->type = INSTR_RETURN;
5571         return 0;
5572 }
5573
5574 static inline void
5575 instr_return_exec(struct rte_swx_pipeline *p)
5576 {
5577         struct thread *t = &p->threads[p->thread_id];
5578
5579         TRACE("[Thread %2u] return\n", p->thread_id);
5580
5581         t->ip = t->ret;
5582 }
5583
5584 static int
5585 instr_translate(struct rte_swx_pipeline *p,
5586                 struct action *action,
5587                 char *string,
5588                 struct instruction *instr,
5589                 struct instruction_data *data)
5590 {
5591         char *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX];
5592         int n_tokens = 0, tpos = 0;
5593
5594         /* Parse the instruction string into tokens. */
5595         for ( ; ; ) {
5596                 char *token;
5597
5598                 token = strtok_r(string, " \t\v", &string);
5599                 if (!token)
5600                         break;
5601
5602                 CHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL);
5603                 CHECK_NAME(token, EINVAL);
5604
5605                 tokens[n_tokens] = token;
5606                 n_tokens++;
5607         }
5608
5609         CHECK(n_tokens, EINVAL);
5610
5611         /* Handle the optional instruction label. */
5612         if ((n_tokens >= 2) && !strcmp(tokens[1], ":")) {
5613                 strcpy(data->label, tokens[0]);
5614
5615                 tpos += 2;
5616                 CHECK(n_tokens - tpos, EINVAL);
5617         }
5618
5619         /* Identify the instruction type. */
5620         if (!strcmp(tokens[tpos], "rx"))
5621                 return instr_rx_translate(p,
5622                                           action,
5623                                           &tokens[tpos],
5624                                           n_tokens - tpos,
5625                                           instr,
5626                                           data);
5627
5628         if (!strcmp(tokens[tpos], "tx"))
5629                 return instr_tx_translate(p,
5630                                           action,
5631                                           &tokens[tpos],
5632                                           n_tokens - tpos,
5633                                           instr,
5634                                           data);
5635
5636         if (!strcmp(tokens[tpos], "drop"))
5637                 return instr_drop_translate(p,
5638                                             action,
5639                                             &tokens[tpos],
5640                                             n_tokens - tpos,
5641                                             instr,
5642                                             data);
5643
5644         if (!strcmp(tokens[tpos], "extract"))
5645                 return instr_hdr_extract_translate(p,
5646                                                    action,
5647                                                    &tokens[tpos],
5648                                                    n_tokens - tpos,
5649                                                    instr,
5650                                                    data);
5651
5652         if (!strcmp(tokens[tpos], "lookahead"))
5653                 return instr_hdr_lookahead_translate(p,
5654                                                      action,
5655                                                      &tokens[tpos],
5656                                                      n_tokens - tpos,
5657                                                      instr,
5658                                                      data);
5659
5660         if (!strcmp(tokens[tpos], "emit"))
5661                 return instr_hdr_emit_translate(p,
5662                                                 action,
5663                                                 &tokens[tpos],
5664                                                 n_tokens - tpos,
5665                                                 instr,
5666                                                 data);
5667
5668         if (!strcmp(tokens[tpos], "validate"))
5669                 return instr_hdr_validate_translate(p,
5670                                                     action,
5671                                                     &tokens[tpos],
5672                                                     n_tokens - tpos,
5673                                                     instr,
5674                                                     data);
5675
5676         if (!strcmp(tokens[tpos], "invalidate"))
5677                 return instr_hdr_invalidate_translate(p,
5678                                                       action,
5679                                                       &tokens[tpos],
5680                                                       n_tokens - tpos,
5681                                                       instr,
5682                                                       data);
5683
5684         if (!strcmp(tokens[tpos], "mov"))
5685                 return instr_mov_translate(p,
5686                                            action,
5687                                            &tokens[tpos],
5688                                            n_tokens - tpos,
5689                                            instr,
5690                                            data);
5691
5692         if (!strcmp(tokens[tpos], "add"))
5693                 return instr_alu_add_translate(p,
5694                                                action,
5695                                                &tokens[tpos],
5696                                                n_tokens - tpos,
5697                                                instr,
5698                                                data);
5699
5700         if (!strcmp(tokens[tpos], "sub"))
5701                 return instr_alu_sub_translate(p,
5702                                                action,
5703                                                &tokens[tpos],
5704                                                n_tokens - tpos,
5705                                                instr,
5706                                                data);
5707
5708         if (!strcmp(tokens[tpos], "ckadd"))
5709                 return instr_alu_ckadd_translate(p,
5710                                                  action,
5711                                                  &tokens[tpos],
5712                                                  n_tokens - tpos,
5713                                                  instr,
5714                                                  data);
5715
5716         if (!strcmp(tokens[tpos], "cksub"))
5717                 return instr_alu_cksub_translate(p,
5718                                                  action,
5719                                                  &tokens[tpos],
5720                                                  n_tokens - tpos,
5721                                                  instr,
5722                                                  data);
5723
5724         if (!strcmp(tokens[tpos], "and"))
5725                 return instr_alu_and_translate(p,
5726                                                action,
5727                                                &tokens[tpos],
5728                                                n_tokens - tpos,
5729                                                instr,
5730                                                data);
5731
5732         if (!strcmp(tokens[tpos], "or"))
5733                 return instr_alu_or_translate(p,
5734                                               action,
5735                                               &tokens[tpos],
5736                                               n_tokens - tpos,
5737                                               instr,
5738                                               data);
5739
5740         if (!strcmp(tokens[tpos], "xor"))
5741                 return instr_alu_xor_translate(p,
5742                                                action,
5743                                                &tokens[tpos],
5744                                                n_tokens - tpos,
5745                                                instr,
5746                                                data);
5747
5748         if (!strcmp(tokens[tpos], "shl"))
5749                 return instr_alu_shl_translate(p,
5750                                                action,
5751                                                &tokens[tpos],
5752                                                n_tokens - tpos,
5753                                                instr,
5754                                                data);
5755
5756         if (!strcmp(tokens[tpos], "shr"))
5757                 return instr_alu_shr_translate(p,
5758                                                action,
5759                                                &tokens[tpos],
5760                                                n_tokens - tpos,
5761                                                instr,
5762                                                data);
5763
5764         if (!strcmp(tokens[tpos], "regprefetch"))
5765                 return instr_regprefetch_translate(p,
5766                                                    action,
5767                                                    &tokens[tpos],
5768                                                    n_tokens - tpos,
5769                                                    instr,
5770                                                    data);
5771
5772         if (!strcmp(tokens[tpos], "regrd"))
5773                 return instr_regrd_translate(p,
5774                                              action,
5775                                              &tokens[tpos],
5776                                              n_tokens - tpos,
5777                                              instr,
5778                                              data);
5779
5780         if (!strcmp(tokens[tpos], "regwr"))
5781                 return instr_regwr_translate(p,
5782                                              action,
5783                                              &tokens[tpos],
5784                                              n_tokens - tpos,
5785                                              instr,
5786                                              data);
5787
5788         if (!strcmp(tokens[tpos], "regadd"))
5789                 return instr_regadd_translate(p,
5790                                               action,
5791                                               &tokens[tpos],
5792                                               n_tokens - tpos,
5793                                               instr,
5794                                               data);
5795
5796         if (!strcmp(tokens[tpos], "metprefetch"))
5797                 return instr_metprefetch_translate(p,
5798                                                    action,
5799                                                    &tokens[tpos],
5800                                                    n_tokens - tpos,
5801                                                    instr,
5802                                                    data);
5803
5804         if (!strcmp(tokens[tpos], "meter"))
5805                 return instr_meter_translate(p,
5806                                              action,
5807                                              &tokens[tpos],
5808                                              n_tokens - tpos,
5809                                              instr,
5810                                              data);
5811
5812         if (!strcmp(tokens[tpos], "table"))
5813                 return instr_table_translate(p,
5814                                              action,
5815                                              &tokens[tpos],
5816                                              n_tokens - tpos,
5817                                              instr,
5818                                              data);
5819
5820         if (!strcmp(tokens[tpos], "learn"))
5821                 return instr_learn_translate(p,
5822                                              action,
5823                                              &tokens[tpos],
5824                                              n_tokens - tpos,
5825                                              instr,
5826                                              data);
5827
5828         if (!strcmp(tokens[tpos], "forget"))
5829                 return instr_forget_translate(p,
5830                                               action,
5831                                               &tokens[tpos],
5832                                               n_tokens - tpos,
5833                                               instr,
5834                                               data);
5835
5836         if (!strcmp(tokens[tpos], "extern"))
5837                 return instr_extern_translate(p,
5838                                               action,
5839                                               &tokens[tpos],
5840                                               n_tokens - tpos,
5841                                               instr,
5842                                               data);
5843
5844         if (!strcmp(tokens[tpos], "jmp"))
5845                 return instr_jmp_translate(p,
5846                                            action,
5847                                            &tokens[tpos],
5848                                            n_tokens - tpos,
5849                                            instr,
5850                                            data);
5851
5852         if (!strcmp(tokens[tpos], "jmpv"))
5853                 return instr_jmp_valid_translate(p,
5854                                                  action,
5855                                                  &tokens[tpos],
5856                                                  n_tokens - tpos,
5857                                                  instr,
5858                                                  data);
5859
5860         if (!strcmp(tokens[tpos], "jmpnv"))
5861                 return instr_jmp_invalid_translate(p,
5862                                                    action,
5863                                                    &tokens[tpos],
5864                                                    n_tokens - tpos,
5865                                                    instr,
5866                                                    data);
5867
5868         if (!strcmp(tokens[tpos], "jmph"))
5869                 return instr_jmp_hit_translate(p,
5870                                                action,
5871                                                &tokens[tpos],
5872                                                n_tokens - tpos,
5873                                                instr,
5874                                                data);
5875
5876         if (!strcmp(tokens[tpos], "jmpnh"))
5877                 return instr_jmp_miss_translate(p,
5878                                                 action,
5879                                                 &tokens[tpos],
5880                                                 n_tokens - tpos,
5881                                                 instr,
5882                                                 data);
5883
5884         if (!strcmp(tokens[tpos], "jmpa"))
5885                 return instr_jmp_action_hit_translate(p,
5886                                                       action,
5887                                                       &tokens[tpos],
5888                                                       n_tokens - tpos,
5889                                                       instr,
5890                                                       data);
5891
5892         if (!strcmp(tokens[tpos], "jmpna"))
5893                 return instr_jmp_action_miss_translate(p,
5894                                                        action,
5895                                                        &tokens[tpos],
5896                                                        n_tokens - tpos,
5897                                                        instr,
5898                                                        data);
5899
5900         if (!strcmp(tokens[tpos], "jmpeq"))
5901                 return instr_jmp_eq_translate(p,
5902                                               action,
5903                                               &tokens[tpos],
5904                                               n_tokens - tpos,
5905                                               instr,
5906                                               data);
5907
5908         if (!strcmp(tokens[tpos], "jmpneq"))
5909                 return instr_jmp_neq_translate(p,
5910                                                action,
5911                                                &tokens[tpos],
5912                                                n_tokens - tpos,
5913                                                instr,
5914                                                data);
5915
5916         if (!strcmp(tokens[tpos], "jmplt"))
5917                 return instr_jmp_lt_translate(p,
5918                                               action,
5919                                               &tokens[tpos],
5920                                               n_tokens - tpos,
5921                                               instr,
5922                                               data);
5923
5924         if (!strcmp(tokens[tpos], "jmpgt"))
5925                 return instr_jmp_gt_translate(p,
5926                                               action,
5927                                               &tokens[tpos],
5928                                               n_tokens - tpos,
5929                                               instr,
5930                                               data);
5931
5932         if (!strcmp(tokens[tpos], "return"))
5933                 return instr_return_translate(p,
5934                                               action,
5935                                               &tokens[tpos],
5936                                               n_tokens - tpos,
5937                                               instr,
5938                                               data);
5939
5940         CHECK(0, EINVAL);
5941 }
5942
5943 static struct instruction_data *
5944 label_find(struct instruction_data *data, uint32_t n, const char *label)
5945 {
5946         uint32_t i;
5947
5948         for (i = 0; i < n; i++)
5949                 if (!strcmp(label, data[i].label))
5950                         return &data[i];
5951
5952         return NULL;
5953 }
5954
5955 static uint32_t
5956 label_is_used(struct instruction_data *data, uint32_t n, const char *label)
5957 {
5958         uint32_t count = 0, i;
5959
5960         if (!label[0])
5961                 return 0;
5962
5963         for (i = 0; i < n; i++)
5964                 if (!strcmp(label, data[i].jmp_label))
5965                         count++;
5966
5967         return count;
5968 }
5969
5970 static int
5971 instr_label_check(struct instruction_data *instruction_data,
5972                   uint32_t n_instructions)
5973 {
5974         uint32_t i;
5975
5976         /* Check that all instruction labels are unique. */
5977         for (i = 0; i < n_instructions; i++) {
5978                 struct instruction_data *data = &instruction_data[i];
5979                 char *label = data->label;
5980                 uint32_t j;
5981
5982                 if (!label[0])
5983                         continue;
5984
5985                 for (j = i + 1; j < n_instructions; j++)
5986                         CHECK(strcmp(label, instruction_data[j].label), EINVAL);
5987         }
5988
5989         /* Get users for each instruction label. */
5990         for (i = 0; i < n_instructions; i++) {
5991                 struct instruction_data *data = &instruction_data[i];
5992                 char *label = data->label;
5993
5994                 data->n_users = label_is_used(instruction_data,
5995                                               n_instructions,
5996                                               label);
5997         }
5998
5999         return 0;
6000 }
6001
6002 static int
6003 instr_jmp_resolve(struct instruction *instructions,
6004                   struct instruction_data *instruction_data,
6005                   uint32_t n_instructions)
6006 {
6007         uint32_t i;
6008
6009         for (i = 0; i < n_instructions; i++) {
6010                 struct instruction *instr = &instructions[i];
6011                 struct instruction_data *data = &instruction_data[i];
6012                 struct instruction_data *found;
6013
6014                 if (!instruction_is_jmp(instr))
6015                         continue;
6016
6017                 found = label_find(instruction_data,
6018                                    n_instructions,
6019                                    data->jmp_label);
6020                 CHECK(found, EINVAL);
6021
6022                 instr->jmp.ip = &instructions[found - instruction_data];
6023         }
6024
6025         return 0;
6026 }
6027
6028 static int
6029 instr_verify(struct rte_swx_pipeline *p __rte_unused,
6030              struct action *a,
6031              struct instruction *instr,
6032              struct instruction_data *data __rte_unused,
6033              uint32_t n_instructions)
6034 {
6035         if (!a) {
6036                 enum instruction_type type;
6037                 uint32_t i;
6038
6039                 /* Check that the first instruction is rx. */
6040                 CHECK(instr[0].type == INSTR_RX, EINVAL);
6041
6042                 /* Check that there is at least one tx instruction. */
6043                 for (i = 0; i < n_instructions; i++) {
6044                         type = instr[i].type;
6045
6046                         if (instruction_is_tx(type))
6047                                 break;
6048                 }
6049                 CHECK(i < n_instructions, EINVAL);
6050
6051                 /* Check that the last instruction is either tx or unconditional
6052                  * jump.
6053                  */
6054                 type = instr[n_instructions - 1].type;
6055                 CHECK(instruction_is_tx(type) || (type == INSTR_JMP), EINVAL);
6056         }
6057
6058         if (a) {
6059                 enum instruction_type type;
6060                 uint32_t i;
6061
6062                 /* Check that there is at least one return or tx instruction. */
6063                 for (i = 0; i < n_instructions; i++) {
6064                         type = instr[i].type;
6065
6066                         if ((type == INSTR_RETURN) || instruction_is_tx(type))
6067                                 break;
6068                 }
6069                 CHECK(i < n_instructions, EINVAL);
6070         }
6071
6072         return 0;
6073 }
6074
6075 static uint32_t
6076 instr_compact(struct instruction *instructions,
6077               struct instruction_data *instruction_data,
6078               uint32_t n_instructions)
6079 {
6080         uint32_t i, pos = 0;
6081
6082         /* Eliminate the invalid instructions that have been optimized out. */
6083         for (i = 0; i < n_instructions; i++) {
6084                 struct instruction *instr = &instructions[i];
6085                 struct instruction_data *data = &instruction_data[i];
6086
6087                 if (data->invalid)
6088                         continue;
6089
6090                 if (i != pos) {
6091                         memcpy(&instructions[pos], instr, sizeof(*instr));
6092                         memcpy(&instruction_data[pos], data, sizeof(*data));
6093                 }
6094
6095                 pos++;
6096         }
6097
6098         return pos;
6099 }
6100
6101 static int
6102 instr_pattern_extract_many_search(struct instruction *instr,
6103                                   struct instruction_data *data,
6104                                   uint32_t n_instr,
6105                                   uint32_t *n_pattern_instr)
6106 {
6107         uint32_t i;
6108
6109         for (i = 0; i < n_instr; i++) {
6110                 if (data[i].invalid)
6111                         break;
6112
6113                 if (instr[i].type != INSTR_HDR_EXTRACT)
6114                         break;
6115
6116                 if (i == RTE_DIM(instr->io.hdr.header_id))
6117                         break;
6118
6119                 if (i && data[i].n_users)
6120                         break;
6121         }
6122
6123         if (i < 2)
6124                 return 0;
6125
6126         *n_pattern_instr = i;
6127         return 1;
6128 }
6129
6130 static void
6131 instr_pattern_extract_many_replace(struct instruction *instr,
6132                                    struct instruction_data *data,
6133                                    uint32_t n_instr)
6134 {
6135         uint32_t i;
6136
6137         for (i = 1; i < n_instr; i++) {
6138                 instr[0].type++;
6139                 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
6140                 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
6141                 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
6142
6143                 data[i].invalid = 1;
6144         }
6145 }
6146
6147 static uint32_t
6148 instr_pattern_extract_many_optimize(struct instruction *instructions,
6149                                     struct instruction_data *instruction_data,
6150                                     uint32_t n_instructions)
6151 {
6152         uint32_t i;
6153
6154         for (i = 0; i < n_instructions; ) {
6155                 struct instruction *instr = &instructions[i];
6156                 struct instruction_data *data = &instruction_data[i];
6157                 uint32_t n_instr = 0;
6158                 int detected;
6159
6160                 /* Extract many. */
6161                 detected = instr_pattern_extract_many_search(instr,
6162                                                              data,
6163                                                              n_instructions - i,
6164                                                              &n_instr);
6165                 if (detected) {
6166                         instr_pattern_extract_many_replace(instr,
6167                                                            data,
6168                                                            n_instr);
6169                         i += n_instr;
6170                         continue;
6171                 }
6172
6173                 /* No pattern starting at the current instruction. */
6174                 i++;
6175         }
6176
6177         /* Eliminate the invalid instructions that have been optimized out. */
6178         n_instructions = instr_compact(instructions,
6179                                        instruction_data,
6180                                        n_instructions);
6181
6182         return n_instructions;
6183 }
6184
6185 static int
6186 instr_pattern_emit_many_tx_search(struct instruction *instr,
6187                                   struct instruction_data *data,
6188                                   uint32_t n_instr,
6189                                   uint32_t *n_pattern_instr)
6190 {
6191         uint32_t i;
6192
6193         for (i = 0; i < n_instr; i++) {
6194                 if (data[i].invalid)
6195                         break;
6196
6197                 if (instr[i].type != INSTR_HDR_EMIT)
6198                         break;
6199
6200                 if (i == RTE_DIM(instr->io.hdr.header_id))
6201                         break;
6202
6203                 if (i && data[i].n_users)
6204                         break;
6205         }
6206
6207         if (!i)
6208                 return 0;
6209
6210         if (!instruction_is_tx(instr[i].type))
6211                 return 0;
6212
6213         if (data[i].n_users)
6214                 return 0;
6215
6216         i++;
6217
6218         *n_pattern_instr = i;
6219         return 1;
6220 }
6221
6222 static void
6223 instr_pattern_emit_many_tx_replace(struct instruction *instr,
6224                                    struct instruction_data *data,
6225                                    uint32_t n_instr)
6226 {
6227         uint32_t i;
6228
6229         /* Any emit instruction in addition to the first one. */
6230         for (i = 1; i < n_instr - 1; i++) {
6231                 instr[0].type++;
6232                 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
6233                 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
6234                 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
6235
6236                 data[i].invalid = 1;
6237         }
6238
6239         /* The TX instruction is the last one in the pattern. */
6240         instr[0].type++;
6241         instr[0].io.io.offset = instr[i].io.io.offset;
6242         instr[0].io.io.n_bits = instr[i].io.io.n_bits;
6243         data[i].invalid = 1;
6244 }
6245
6246 static uint32_t
6247 instr_pattern_emit_many_tx_optimize(struct instruction *instructions,
6248                                     struct instruction_data *instruction_data,
6249                                     uint32_t n_instructions)
6250 {
6251         uint32_t i;
6252
6253         for (i = 0; i < n_instructions; ) {
6254                 struct instruction *instr = &instructions[i];
6255                 struct instruction_data *data = &instruction_data[i];
6256                 uint32_t n_instr = 0;
6257                 int detected;
6258
6259                 /* Emit many + TX. */
6260                 detected = instr_pattern_emit_many_tx_search(instr,
6261                                                              data,
6262                                                              n_instructions - i,
6263                                                              &n_instr);
6264                 if (detected) {
6265                         instr_pattern_emit_many_tx_replace(instr,
6266                                                            data,
6267                                                            n_instr);
6268                         i += n_instr;
6269                         continue;
6270                 }
6271
6272                 /* No pattern starting at the current instruction. */
6273                 i++;
6274         }
6275
6276         /* Eliminate the invalid instructions that have been optimized out. */
6277         n_instructions = instr_compact(instructions,
6278                                        instruction_data,
6279                                        n_instructions);
6280
6281         return n_instructions;
6282 }
6283
6284 static uint32_t
6285 action_arg_src_mov_count(struct action *a,
6286                          uint32_t arg_id,
6287                          struct instruction *instructions,
6288                          struct instruction_data *instruction_data,
6289                          uint32_t n_instructions);
6290
6291 static int
6292 instr_pattern_mov_all_validate_search(struct rte_swx_pipeline *p,
6293                                       struct action *a,
6294                                       struct instruction *instr,
6295                                       struct instruction_data *data,
6296                                       uint32_t n_instr,
6297                                       struct instruction *instructions,
6298                                       struct instruction_data *instruction_data,
6299                                       uint32_t n_instructions,
6300                                       uint32_t *n_pattern_instr)
6301 {
6302         struct header *h;
6303         uint32_t src_field_id, i, j;
6304
6305         /* Prerequisites. */
6306         if (!a || !a->st)
6307                 return 0;
6308
6309         /* First instruction: MOV_HM. */
6310         if (data[0].invalid || (instr[0].type != INSTR_MOV_HM))
6311                 return 0;
6312
6313         h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
6314         if (!h || h->st->var_size)
6315                 return 0;
6316
6317         for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
6318                 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
6319                         break;
6320
6321         if (src_field_id == a->st->n_fields)
6322                 return 0;
6323
6324         if (instr[0].mov.dst.offset ||
6325             (instr[0].mov.dst.n_bits != h->st->fields[0].n_bits) ||
6326             instr[0].mov.src.struct_id ||
6327             (instr[0].mov.src.n_bits != a->st->fields[src_field_id].n_bits) ||
6328             (instr[0].mov.dst.n_bits != instr[0].mov.src.n_bits))
6329                 return 0;
6330
6331         if ((n_instr < h->st->n_fields + 1) ||
6332              (a->st->n_fields < src_field_id + h->st->n_fields + 1))
6333                 return 0;
6334
6335         /* Subsequent instructions: MOV_HM. */
6336         for (i = 1; i < h->st->n_fields; i++)
6337                 if (data[i].invalid ||
6338                     data[i].n_users ||
6339                     (instr[i].type != INSTR_MOV_HM) ||
6340                     (instr[i].mov.dst.struct_id != h->struct_id) ||
6341                     (instr[i].mov.dst.offset != h->st->fields[i].offset / 8) ||
6342                     (instr[i].mov.dst.n_bits != h->st->fields[i].n_bits) ||
6343                     instr[i].mov.src.struct_id ||
6344                     (instr[i].mov.src.offset != a->st->fields[src_field_id + i].offset / 8) ||
6345                     (instr[i].mov.src.n_bits != a->st->fields[src_field_id + i].n_bits) ||
6346                     (instr[i].mov.dst.n_bits != instr[i].mov.src.n_bits))
6347                         return 0;
6348
6349         /* Last instruction: HDR_VALIDATE. */
6350         if ((instr[i].type != INSTR_HDR_VALIDATE) ||
6351             (instr[i].valid.header_id != h->id))
6352                 return 0;
6353
6354         /* Check that none of the action args that are used as source for this
6355          * DMA transfer are not used as source in any other mov instruction.
6356          */
6357         for (j = src_field_id; j < src_field_id + h->st->n_fields; j++) {
6358                 uint32_t n_users;
6359
6360                 n_users = action_arg_src_mov_count(a,
6361                                                    j,
6362                                                    instructions,
6363                                                    instruction_data,
6364                                                    n_instructions);
6365                 if (n_users > 1)
6366                         return 0;
6367         }
6368
6369         *n_pattern_instr = 1 + i;
6370         return 1;
6371 }
6372
6373 static void
6374 instr_pattern_mov_all_validate_replace(struct rte_swx_pipeline *p,
6375                                        struct action *a,
6376                                        struct instruction *instr,
6377                                        struct instruction_data *data,
6378                                        uint32_t n_instr)
6379 {
6380         struct header *h;
6381         uint32_t src_field_id, src_offset, i;
6382
6383         /* Read from the instructions before they are modified. */
6384         h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
6385         if (!h)
6386                 return;
6387
6388         for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
6389                 if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
6390                         break;
6391
6392         if (src_field_id == a->st->n_fields)
6393                 return;
6394
6395         src_offset = instr[0].mov.src.offset;
6396
6397         /* Modify the instructions. */
6398         instr[0].type = INSTR_DMA_HT;
6399         instr[0].dma.dst.header_id[0] = h->id;
6400         instr[0].dma.dst.struct_id[0] = h->struct_id;
6401         instr[0].dma.src.offset[0] = (uint8_t)src_offset;
6402         instr[0].dma.n_bytes[0] = h->st->n_bits / 8;
6403
6404         for (i = 1; i < n_instr; i++)
6405                 data[i].invalid = 1;
6406
6407         /* Update the endianness of the action arguments to header endianness. */
6408         for (i = 0; i < h->st->n_fields; i++)
6409                 a->args_endianness[src_field_id + i] = 1;
6410 }
6411
6412 static uint32_t
6413 instr_pattern_mov_all_validate_optimize(struct rte_swx_pipeline *p,
6414                                         struct action *a,
6415                                         struct instruction *instructions,
6416                                         struct instruction_data *instruction_data,
6417                                         uint32_t n_instructions)
6418 {
6419         uint32_t i;
6420
6421         if (!a || !a->st)
6422                 return n_instructions;
6423
6424         for (i = 0; i < n_instructions; ) {
6425                 struct instruction *instr = &instructions[i];
6426                 struct instruction_data *data = &instruction_data[i];
6427                 uint32_t n_instr = 0;
6428                 int detected;
6429
6430                 /* Mov all + validate. */
6431                 detected = instr_pattern_mov_all_validate_search(p,
6432                                                                  a,
6433                                                                  instr,
6434                                                                  data,
6435                                                                  n_instructions - i,
6436                                                                  instructions,
6437                                                                  instruction_data,
6438                                                                  n_instructions,
6439                                                                  &n_instr);
6440                 if (detected) {
6441                         instr_pattern_mov_all_validate_replace(p, a, instr, data, n_instr);
6442                         i += n_instr;
6443                         continue;
6444                 }
6445
6446                 /* No pattern starting at the current instruction. */
6447                 i++;
6448         }
6449
6450         /* Eliminate the invalid instructions that have been optimized out. */
6451         n_instructions = instr_compact(instructions,
6452                                        instruction_data,
6453                                        n_instructions);
6454
6455         return n_instructions;
6456 }
6457
6458 static int
6459 instr_pattern_dma_many_search(struct instruction *instr,
6460                               struct instruction_data *data,
6461                               uint32_t n_instr,
6462                               uint32_t *n_pattern_instr)
6463 {
6464         uint32_t i;
6465
6466         for (i = 0; i < n_instr; i++) {
6467                 if (data[i].invalid)
6468                         break;
6469
6470                 if (instr[i].type != INSTR_DMA_HT)
6471                         break;
6472
6473                 if (i == RTE_DIM(instr->dma.dst.header_id))
6474                         break;
6475
6476                 if (i && data[i].n_users)
6477                         break;
6478         }
6479
6480         if (i < 2)
6481                 return 0;
6482
6483         *n_pattern_instr = i;
6484         return 1;
6485 }
6486
6487 static void
6488 instr_pattern_dma_many_replace(struct instruction *instr,
6489                                struct instruction_data *data,
6490                                uint32_t n_instr)
6491 {
6492         uint32_t i;
6493
6494         for (i = 1; i < n_instr; i++) {
6495                 instr[0].type++;
6496                 instr[0].dma.dst.header_id[i] = instr[i].dma.dst.header_id[0];
6497                 instr[0].dma.dst.struct_id[i] = instr[i].dma.dst.struct_id[0];
6498                 instr[0].dma.src.offset[i] = instr[i].dma.src.offset[0];
6499                 instr[0].dma.n_bytes[i] = instr[i].dma.n_bytes[0];
6500
6501                 data[i].invalid = 1;
6502         }
6503 }
6504
6505 static uint32_t
6506 instr_pattern_dma_many_optimize(struct instruction *instructions,
6507                struct instruction_data *instruction_data,
6508                uint32_t n_instructions)
6509 {
6510         uint32_t i;
6511
6512         for (i = 0; i < n_instructions; ) {
6513                 struct instruction *instr = &instructions[i];
6514                 struct instruction_data *data = &instruction_data[i];
6515                 uint32_t n_instr = 0;
6516                 int detected;
6517
6518                 /* DMA many. */
6519                 detected = instr_pattern_dma_many_search(instr,
6520                                                          data,
6521                                                          n_instructions - i,
6522                                                          &n_instr);
6523                 if (detected) {
6524                         instr_pattern_dma_many_replace(instr, data, n_instr);
6525                         i += n_instr;
6526                         continue;
6527                 }
6528
6529                 /* No pattern starting at the current instruction. */
6530                 i++;
6531         }
6532
6533         /* Eliminate the invalid instructions that have been optimized out. */
6534         n_instructions = instr_compact(instructions,
6535                                        instruction_data,
6536                                        n_instructions);
6537
6538         return n_instructions;
6539 }
6540
6541 static uint32_t
6542 instr_optimize(struct rte_swx_pipeline *p,
6543                struct action *a,
6544                struct instruction *instructions,
6545                struct instruction_data *instruction_data,
6546                uint32_t n_instructions)
6547 {
6548         /* Extract many. */
6549         n_instructions = instr_pattern_extract_many_optimize(instructions,
6550                                                              instruction_data,
6551                                                              n_instructions);
6552
6553         /* Emit many + TX. */
6554         n_instructions = instr_pattern_emit_many_tx_optimize(instructions,
6555                                                              instruction_data,
6556                                                              n_instructions);
6557
6558         /* Mov all + validate. */
6559         n_instructions = instr_pattern_mov_all_validate_optimize(p,
6560                                                                  a,
6561                                                                  instructions,
6562                                                                  instruction_data,
6563                                                                  n_instructions);
6564
6565         /* DMA many. */
6566         n_instructions = instr_pattern_dma_many_optimize(instructions,
6567                                                          instruction_data,
6568                                                          n_instructions);
6569
6570         return n_instructions;
6571 }
6572
6573 static int
6574 instruction_config(struct rte_swx_pipeline *p,
6575                    struct action *a,
6576                    const char **instructions,
6577                    uint32_t n_instructions)
6578 {
6579         struct instruction *instr = NULL;
6580         struct instruction_data *data = NULL;
6581         int err = 0;
6582         uint32_t i;
6583
6584         CHECK(n_instructions, EINVAL);
6585         CHECK(instructions, EINVAL);
6586         for (i = 0; i < n_instructions; i++)
6587                 CHECK_INSTRUCTION(instructions[i], EINVAL);
6588
6589         /* Memory allocation. */
6590         instr = calloc(n_instructions, sizeof(struct instruction));
6591         if (!instr) {
6592                 err = -ENOMEM;
6593                 goto error;
6594         }
6595
6596         data = calloc(n_instructions, sizeof(struct instruction_data));
6597         if (!data) {
6598                 err = -ENOMEM;
6599                 goto error;
6600         }
6601
6602         for (i = 0; i < n_instructions; i++) {
6603                 char *string = strdup(instructions[i]);
6604                 if (!string) {
6605                         err = -ENOMEM;
6606                         goto error;
6607                 }
6608
6609                 err = instr_translate(p, a, string, &instr[i], &data[i]);
6610                 if (err) {
6611                         free(string);
6612                         goto error;
6613                 }
6614
6615                 free(string);
6616         }
6617
6618         err = instr_label_check(data, n_instructions);
6619         if (err)
6620                 goto error;
6621
6622         err = instr_verify(p, a, instr, data, n_instructions);
6623         if (err)
6624                 goto error;
6625
6626         n_instructions = instr_optimize(p, a, instr, data, n_instructions);
6627
6628         err = instr_jmp_resolve(instr, data, n_instructions);
6629         if (err)
6630                 goto error;
6631
6632         if (a) {
6633                 a->instructions = instr;
6634                 a->instruction_data = data;
6635                 a->n_instructions = n_instructions;
6636         } else {
6637                 p->instructions = instr;
6638                 p->instruction_data = data;
6639                 p->n_instructions = n_instructions;
6640         }
6641
6642         return 0;
6643
6644 error:
6645         free(data);
6646         free(instr);
6647         return err;
6648 }
6649
6650 static instr_exec_t instruction_table[] = {
6651         [INSTR_RX] = instr_rx_exec,
6652         [INSTR_TX] = instr_tx_exec,
6653         [INSTR_TX_I] = instr_tx_i_exec,
6654
6655         [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
6656         [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
6657         [INSTR_HDR_EXTRACT3] = instr_hdr_extract3_exec,
6658         [INSTR_HDR_EXTRACT4] = instr_hdr_extract4_exec,
6659         [INSTR_HDR_EXTRACT5] = instr_hdr_extract5_exec,
6660         [INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec,
6661         [INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec,
6662         [INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec,
6663         [INSTR_HDR_EXTRACT_M] = instr_hdr_extract_m_exec,
6664         [INSTR_HDR_LOOKAHEAD] = instr_hdr_lookahead_exec,
6665
6666         [INSTR_HDR_EMIT] = instr_hdr_emit_exec,
6667         [INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec,
6668         [INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec,
6669         [INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec,
6670         [INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec,
6671         [INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec,
6672         [INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec,
6673         [INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec,
6674         [INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec,
6675
6676         [INSTR_HDR_VALIDATE] = instr_hdr_validate_exec,
6677         [INSTR_HDR_INVALIDATE] = instr_hdr_invalidate_exec,
6678
6679         [INSTR_MOV] = instr_mov_exec,
6680         [INSTR_MOV_MH] = instr_mov_mh_exec,
6681         [INSTR_MOV_HM] = instr_mov_hm_exec,
6682         [INSTR_MOV_HH] = instr_mov_hh_exec,
6683         [INSTR_MOV_I] = instr_mov_i_exec,
6684
6685         [INSTR_DMA_HT] = instr_dma_ht_exec,
6686         [INSTR_DMA_HT2] = instr_dma_ht2_exec,
6687         [INSTR_DMA_HT3] = instr_dma_ht3_exec,
6688         [INSTR_DMA_HT4] = instr_dma_ht4_exec,
6689         [INSTR_DMA_HT5] = instr_dma_ht5_exec,
6690         [INSTR_DMA_HT6] = instr_dma_ht6_exec,
6691         [INSTR_DMA_HT7] = instr_dma_ht7_exec,
6692         [INSTR_DMA_HT8] = instr_dma_ht8_exec,
6693
6694         [INSTR_ALU_ADD] = instr_alu_add_exec,
6695         [INSTR_ALU_ADD_MH] = instr_alu_add_mh_exec,
6696         [INSTR_ALU_ADD_HM] = instr_alu_add_hm_exec,
6697         [INSTR_ALU_ADD_HH] = instr_alu_add_hh_exec,
6698         [INSTR_ALU_ADD_MI] = instr_alu_add_mi_exec,
6699         [INSTR_ALU_ADD_HI] = instr_alu_add_hi_exec,
6700
6701         [INSTR_ALU_SUB] = instr_alu_sub_exec,
6702         [INSTR_ALU_SUB_MH] = instr_alu_sub_mh_exec,
6703         [INSTR_ALU_SUB_HM] = instr_alu_sub_hm_exec,
6704         [INSTR_ALU_SUB_HH] = instr_alu_sub_hh_exec,
6705         [INSTR_ALU_SUB_MI] = instr_alu_sub_mi_exec,
6706         [INSTR_ALU_SUB_HI] = instr_alu_sub_hi_exec,
6707
6708         [INSTR_ALU_CKADD_FIELD] = instr_alu_ckadd_field_exec,
6709         [INSTR_ALU_CKADD_STRUCT] = instr_alu_ckadd_struct_exec,
6710         [INSTR_ALU_CKADD_STRUCT20] = instr_alu_ckadd_struct20_exec,
6711         [INSTR_ALU_CKSUB_FIELD] = instr_alu_cksub_field_exec,
6712
6713         [INSTR_ALU_AND] = instr_alu_and_exec,
6714         [INSTR_ALU_AND_MH] = instr_alu_and_mh_exec,
6715         [INSTR_ALU_AND_HM] = instr_alu_and_hm_exec,
6716         [INSTR_ALU_AND_HH] = instr_alu_and_hh_exec,
6717         [INSTR_ALU_AND_I] = instr_alu_and_i_exec,
6718
6719         [INSTR_ALU_OR] = instr_alu_or_exec,
6720         [INSTR_ALU_OR_MH] = instr_alu_or_mh_exec,
6721         [INSTR_ALU_OR_HM] = instr_alu_or_hm_exec,
6722         [INSTR_ALU_OR_HH] = instr_alu_or_hh_exec,
6723         [INSTR_ALU_OR_I] = instr_alu_or_i_exec,
6724
6725         [INSTR_ALU_XOR] = instr_alu_xor_exec,
6726         [INSTR_ALU_XOR_MH] = instr_alu_xor_mh_exec,
6727         [INSTR_ALU_XOR_HM] = instr_alu_xor_hm_exec,
6728         [INSTR_ALU_XOR_HH] = instr_alu_xor_hh_exec,
6729         [INSTR_ALU_XOR_I] = instr_alu_xor_i_exec,
6730
6731         [INSTR_ALU_SHL] = instr_alu_shl_exec,
6732         [INSTR_ALU_SHL_MH] = instr_alu_shl_mh_exec,
6733         [INSTR_ALU_SHL_HM] = instr_alu_shl_hm_exec,
6734         [INSTR_ALU_SHL_HH] = instr_alu_shl_hh_exec,
6735         [INSTR_ALU_SHL_MI] = instr_alu_shl_mi_exec,
6736         [INSTR_ALU_SHL_HI] = instr_alu_shl_hi_exec,
6737
6738         [INSTR_ALU_SHR] = instr_alu_shr_exec,
6739         [INSTR_ALU_SHR_MH] = instr_alu_shr_mh_exec,
6740         [INSTR_ALU_SHR_HM] = instr_alu_shr_hm_exec,
6741         [INSTR_ALU_SHR_HH] = instr_alu_shr_hh_exec,
6742         [INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec,
6743         [INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec,
6744
6745         [INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec,
6746         [INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec,
6747         [INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec,
6748
6749         [INSTR_REGRD_HRH] = instr_regrd_hrh_exec,
6750         [INSTR_REGRD_HRM] = instr_regrd_hrm_exec,
6751         [INSTR_REGRD_MRH] = instr_regrd_mrh_exec,
6752         [INSTR_REGRD_MRM] = instr_regrd_mrm_exec,
6753         [INSTR_REGRD_HRI] = instr_regrd_hri_exec,
6754         [INSTR_REGRD_MRI] = instr_regrd_mri_exec,
6755
6756         [INSTR_REGWR_RHH] = instr_regwr_rhh_exec,
6757         [INSTR_REGWR_RHM] = instr_regwr_rhm_exec,
6758         [INSTR_REGWR_RMH] = instr_regwr_rmh_exec,
6759         [INSTR_REGWR_RMM] = instr_regwr_rmm_exec,
6760         [INSTR_REGWR_RHI] = instr_regwr_rhi_exec,
6761         [INSTR_REGWR_RMI] = instr_regwr_rmi_exec,
6762         [INSTR_REGWR_RIH] = instr_regwr_rih_exec,
6763         [INSTR_REGWR_RIM] = instr_regwr_rim_exec,
6764         [INSTR_REGWR_RII] = instr_regwr_rii_exec,
6765
6766         [INSTR_REGADD_RHH] = instr_regadd_rhh_exec,
6767         [INSTR_REGADD_RHM] = instr_regadd_rhm_exec,
6768         [INSTR_REGADD_RMH] = instr_regadd_rmh_exec,
6769         [INSTR_REGADD_RMM] = instr_regadd_rmm_exec,
6770         [INSTR_REGADD_RHI] = instr_regadd_rhi_exec,
6771         [INSTR_REGADD_RMI] = instr_regadd_rmi_exec,
6772         [INSTR_REGADD_RIH] = instr_regadd_rih_exec,
6773         [INSTR_REGADD_RIM] = instr_regadd_rim_exec,
6774         [INSTR_REGADD_RII] = instr_regadd_rii_exec,
6775
6776         [INSTR_METPREFETCH_H] = instr_metprefetch_h_exec,
6777         [INSTR_METPREFETCH_M] = instr_metprefetch_m_exec,
6778         [INSTR_METPREFETCH_I] = instr_metprefetch_i_exec,
6779
6780         [INSTR_METER_HHM] = instr_meter_hhm_exec,
6781         [INSTR_METER_HHI] = instr_meter_hhi_exec,
6782         [INSTR_METER_HMM] = instr_meter_hmm_exec,
6783         [INSTR_METER_HMI] = instr_meter_hmi_exec,
6784         [INSTR_METER_MHM] = instr_meter_mhm_exec,
6785         [INSTR_METER_MHI] = instr_meter_mhi_exec,
6786         [INSTR_METER_MMM] = instr_meter_mmm_exec,
6787         [INSTR_METER_MMI] = instr_meter_mmi_exec,
6788         [INSTR_METER_IHM] = instr_meter_ihm_exec,
6789         [INSTR_METER_IHI] = instr_meter_ihi_exec,
6790         [INSTR_METER_IMM] = instr_meter_imm_exec,
6791         [INSTR_METER_IMI] = instr_meter_imi_exec,
6792
6793         [INSTR_TABLE] = instr_table_exec,
6794         [INSTR_TABLE_AF] = instr_table_af_exec,
6795         [INSTR_SELECTOR] = instr_selector_exec,
6796         [INSTR_LEARNER] = instr_learner_exec,
6797         [INSTR_LEARNER_AF] = instr_learner_af_exec,
6798         [INSTR_LEARNER_LEARN] = instr_learn_exec,
6799         [INSTR_LEARNER_FORGET] = instr_forget_exec,
6800         [INSTR_EXTERN_OBJ] = instr_extern_obj_exec,
6801         [INSTR_EXTERN_FUNC] = instr_extern_func_exec,
6802
6803         [INSTR_JMP] = instr_jmp_exec,
6804         [INSTR_JMP_VALID] = instr_jmp_valid_exec,
6805         [INSTR_JMP_INVALID] = instr_jmp_invalid_exec,
6806         [INSTR_JMP_HIT] = instr_jmp_hit_exec,
6807         [INSTR_JMP_MISS] = instr_jmp_miss_exec,
6808         [INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec,
6809         [INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec,
6810
6811         [INSTR_JMP_EQ] = instr_jmp_eq_exec,
6812         [INSTR_JMP_EQ_MH] = instr_jmp_eq_mh_exec,
6813         [INSTR_JMP_EQ_HM] = instr_jmp_eq_hm_exec,
6814         [INSTR_JMP_EQ_HH] = instr_jmp_eq_hh_exec,
6815         [INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec,
6816
6817         [INSTR_JMP_NEQ] = instr_jmp_neq_exec,
6818         [INSTR_JMP_NEQ_MH] = instr_jmp_neq_mh_exec,
6819         [INSTR_JMP_NEQ_HM] = instr_jmp_neq_hm_exec,
6820         [INSTR_JMP_NEQ_HH] = instr_jmp_neq_hh_exec,
6821         [INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec,
6822
6823         [INSTR_JMP_LT] = instr_jmp_lt_exec,
6824         [INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec,
6825         [INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec,
6826         [INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec,
6827         [INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec,
6828         [INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec,
6829
6830         [INSTR_JMP_GT] = instr_jmp_gt_exec,
6831         [INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec,
6832         [INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec,
6833         [INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec,
6834         [INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec,
6835         [INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec,
6836
6837         [INSTR_RETURN] = instr_return_exec,
6838 };
6839
6840 static int
6841 instruction_table_build(struct rte_swx_pipeline *p)
6842 {
6843         p->instruction_table = calloc(RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX,
6844                                       sizeof(struct instr_exec_t *));
6845         if (!p->instruction_table)
6846                 return -EINVAL;
6847
6848         memcpy(p->instruction_table, instruction_table, sizeof(instruction_table));
6849
6850         return 0;
6851 }
6852
6853 static void
6854 instruction_table_build_free(struct rte_swx_pipeline *p)
6855 {
6856         if (!p->instruction_table)
6857                 return;
6858
6859         free(p->instruction_table);
6860         p->instruction_table = NULL;
6861 }
6862
6863 static void
6864 instruction_table_free(struct rte_swx_pipeline *p)
6865 {
6866         instruction_table_build_free(p);
6867 }
6868
6869 static inline void
6870 instr_exec(struct rte_swx_pipeline *p)
6871 {
6872         struct thread *t = &p->threads[p->thread_id];
6873         struct instruction *ip = t->ip;
6874         instr_exec_t instr = p->instruction_table[ip->type];
6875
6876         instr(p);
6877 }
6878
6879 /*
6880  * Action.
6881  */
6882 static struct action *
6883 action_find(struct rte_swx_pipeline *p, const char *name)
6884 {
6885         struct action *elem;
6886
6887         if (!name)
6888                 return NULL;
6889
6890         TAILQ_FOREACH(elem, &p->actions, node)
6891                 if (strcmp(elem->name, name) == 0)
6892                         return elem;
6893
6894         return NULL;
6895 }
6896
6897 static struct action *
6898 action_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
6899 {
6900         struct action *action = NULL;
6901
6902         TAILQ_FOREACH(action, &p->actions, node)
6903                 if (action->id == id)
6904                         return action;
6905
6906         return NULL;
6907 }
6908
6909 static struct field *
6910 action_field_find(struct action *a, const char *name)
6911 {
6912         return a->st ? struct_type_field_find(a->st, name) : NULL;
6913 }
6914
6915 static struct field *
6916 action_field_parse(struct action *action, const char *name)
6917 {
6918         if (name[0] != 't' || name[1] != '.')
6919                 return NULL;
6920
6921         return action_field_find(action, &name[2]);
6922 }
6923
6924 static int
6925 action_has_nbo_args(struct action *a)
6926 {
6927         uint32_t i;
6928
6929         /* Return if the action does not have any args. */
6930         if (!a->st)
6931                 return 0; /* FALSE */
6932
6933         for (i = 0; i < a->st->n_fields; i++)
6934                 if (a->args_endianness[i])
6935                         return 1; /* TRUE */
6936
6937         return 0; /* FALSE */
6938 }
6939
6940 static int
6941 action_does_learning(struct action *a)
6942 {
6943         uint32_t i;
6944
6945         for (i = 0; i < a->n_instructions; i++)
6946                 switch (a->instructions[i].type) {
6947                 case INSTR_LEARNER_LEARN:
6948                         return 1; /* TRUE */
6949
6950                 case INSTR_LEARNER_FORGET:
6951                         return 1; /* TRUE */
6952
6953                 default:
6954                         continue;
6955                 }
6956
6957         return 0; /* FALSE */
6958 }
6959
6960 int
6961 rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
6962                                const char *name,
6963                                const char *args_struct_type_name,
6964                                const char **instructions,
6965                                uint32_t n_instructions)
6966 {
6967         struct struct_type *args_struct_type = NULL;
6968         struct action *a;
6969         int err;
6970
6971         CHECK(p, EINVAL);
6972
6973         CHECK_NAME(name, EINVAL);
6974         CHECK(!action_find(p, name), EEXIST);
6975
6976         if (args_struct_type_name) {
6977                 CHECK_NAME(args_struct_type_name, EINVAL);
6978                 args_struct_type = struct_type_find(p, args_struct_type_name);
6979                 CHECK(args_struct_type, EINVAL);
6980                 CHECK(!args_struct_type->var_size, EINVAL);
6981         }
6982
6983         /* Node allocation. */
6984         a = calloc(1, sizeof(struct action));
6985         CHECK(a, ENOMEM);
6986         if (args_struct_type) {
6987                 a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int));
6988                 if (!a->args_endianness) {
6989                         free(a);
6990                         CHECK(0, ENOMEM);
6991                 }
6992         }
6993
6994         /* Node initialization. */
6995         strcpy(a->name, name);
6996         a->st = args_struct_type;
6997         a->id = p->n_actions;
6998
6999         /* Instruction translation. */
7000         err = instruction_config(p, a, instructions, n_instructions);
7001         if (err) {
7002                 free(a->args_endianness);
7003                 free(a);
7004                 return err;
7005         }
7006
7007         /* Node add to tailq. */
7008         TAILQ_INSERT_TAIL(&p->actions, a, node);
7009         p->n_actions++;
7010
7011         return 0;
7012 }
7013
7014 static int
7015 action_build(struct rte_swx_pipeline *p)
7016 {
7017         struct action *action;
7018
7019         /* p->action_instructions. */
7020         p->action_instructions = calloc(p->n_actions, sizeof(struct instruction *));
7021         CHECK(p->action_instructions, ENOMEM);
7022
7023         TAILQ_FOREACH(action, &p->actions, node)
7024                 p->action_instructions[action->id] = action->instructions;
7025
7026         /* p->action_funcs. */
7027         p->action_funcs = calloc(p->n_actions, sizeof(action_func_t));
7028         CHECK(p->action_funcs, ENOMEM);
7029
7030         return 0;
7031 }
7032
7033 static void
7034 action_build_free(struct rte_swx_pipeline *p)
7035 {
7036         free(p->action_funcs);
7037         p->action_funcs = NULL;
7038
7039         free(p->action_instructions);
7040         p->action_instructions = NULL;
7041 }
7042
7043 static void
7044 action_free(struct rte_swx_pipeline *p)
7045 {
7046         action_build_free(p);
7047
7048         for ( ; ; ) {
7049                 struct action *action;
7050
7051                 action = TAILQ_FIRST(&p->actions);
7052                 if (!action)
7053                         break;
7054
7055                 TAILQ_REMOVE(&p->actions, action, node);
7056                 free(action->instruction_data);
7057                 free(action->instructions);
7058                 free(action);
7059         }
7060 }
7061
7062 static uint32_t
7063 action_arg_src_mov_count(struct action *a,
7064                          uint32_t arg_id,
7065                          struct instruction *instructions,
7066                          struct instruction_data *instruction_data,
7067                          uint32_t n_instructions)
7068 {
7069         uint32_t offset, n_users = 0, i;
7070
7071         if (!a->st ||
7072             (arg_id >= a->st->n_fields) ||
7073             !instructions ||
7074             !instruction_data ||
7075             !n_instructions)
7076                 return 0;
7077
7078         offset = a->st->fields[arg_id].offset / 8;
7079
7080         for (i = 0; i < n_instructions; i++) {
7081                 struct instruction *instr = &instructions[i];
7082                 struct instruction_data *data = &instruction_data[i];
7083
7084                 if (data->invalid ||
7085                     ((instr->type != INSTR_MOV) && (instr->type != INSTR_MOV_HM)) ||
7086                     instr->mov.src.struct_id ||
7087                     (instr->mov.src.offset != offset))
7088                         continue;
7089
7090                 n_users++;
7091         }
7092
7093         return n_users;
7094 }
7095
7096 /*
7097  * Table.
7098  */
7099 static struct table_type *
7100 table_type_find(struct rte_swx_pipeline *p, const char *name)
7101 {
7102         struct table_type *elem;
7103
7104         TAILQ_FOREACH(elem, &p->table_types, node)
7105                 if (strcmp(elem->name, name) == 0)
7106                         return elem;
7107
7108         return NULL;
7109 }
7110
7111 static struct table_type *
7112 table_type_resolve(struct rte_swx_pipeline *p,
7113                    const char *recommended_type_name,
7114                    enum rte_swx_table_match_type match_type)
7115 {
7116         struct table_type *elem;
7117
7118         /* Only consider the recommended type if the match type is correct. */
7119         if (recommended_type_name)
7120                 TAILQ_FOREACH(elem, &p->table_types, node)
7121                         if (!strcmp(elem->name, recommended_type_name) &&
7122                             (elem->match_type == match_type))
7123                                 return elem;
7124
7125         /* Ignore the recommended type and get the first element with this match
7126          * type.
7127          */
7128         TAILQ_FOREACH(elem, &p->table_types, node)
7129                 if (elem->match_type == match_type)
7130                         return elem;
7131
7132         return NULL;
7133 }
7134
7135 static struct table *
7136 table_find(struct rte_swx_pipeline *p, const char *name)
7137 {
7138         struct table *elem;
7139
7140         TAILQ_FOREACH(elem, &p->tables, node)
7141                 if (strcmp(elem->name, name) == 0)
7142                         return elem;
7143
7144         return NULL;
7145 }
7146
7147 static struct table *
7148 table_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
7149 {
7150         struct table *table = NULL;
7151
7152         TAILQ_FOREACH(table, &p->tables, node)
7153                 if (table->id == id)
7154                         return table;
7155
7156         return NULL;
7157 }
7158
7159 int
7160 rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p,
7161                                      const char *name,
7162                                      enum rte_swx_table_match_type match_type,
7163                                      struct rte_swx_table_ops *ops)
7164 {
7165         struct table_type *elem;
7166
7167         CHECK(p, EINVAL);
7168
7169         CHECK_NAME(name, EINVAL);
7170         CHECK(!table_type_find(p, name), EEXIST);
7171
7172         CHECK(ops, EINVAL);
7173         CHECK(ops->create, EINVAL);
7174         CHECK(ops->lkp, EINVAL);
7175         CHECK(ops->free, EINVAL);
7176
7177         /* Node allocation. */
7178         elem = calloc(1, sizeof(struct table_type));
7179         CHECK(elem, ENOMEM);
7180
7181         /* Node initialization. */
7182         strcpy(elem->name, name);
7183         elem->match_type = match_type;
7184         memcpy(&elem->ops, ops, sizeof(*ops));
7185
7186         /* Node add to tailq. */
7187         TAILQ_INSERT_TAIL(&p->table_types, elem, node);
7188
7189         return 0;
7190 }
7191
7192 static int
7193 table_match_type_resolve(struct rte_swx_match_field_params *fields,
7194                          uint32_t n_fields,
7195                          enum rte_swx_table_match_type *match_type)
7196 {
7197         uint32_t n_fields_em = 0, n_fields_lpm = 0, i;
7198
7199         for (i = 0; i < n_fields; i++) {
7200                 struct rte_swx_match_field_params  *f = &fields[i];
7201
7202                 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
7203                         n_fields_em++;
7204
7205                 if (f->match_type == RTE_SWX_TABLE_MATCH_LPM)
7206                         n_fields_lpm++;
7207         }
7208
7209         if ((n_fields_lpm > 1) ||
7210             (n_fields_lpm && (n_fields_em != n_fields - 1)))
7211                 return -EINVAL;
7212
7213         *match_type = (n_fields_em == n_fields) ?
7214                        RTE_SWX_TABLE_MATCH_EXACT :
7215                        RTE_SWX_TABLE_MATCH_WILDCARD;
7216
7217         return 0;
7218 }
7219
7220 static int
7221 table_match_fields_check(struct rte_swx_pipeline *p,
7222                          struct rte_swx_pipeline_table_params *params,
7223                          struct header **header)
7224 {
7225         struct header *h0 = NULL;
7226         struct field *hf, *mf;
7227         uint32_t *offset = NULL, i;
7228         int status = 0;
7229
7230         /* Return if no match fields. */
7231         if (!params->n_fields) {
7232                 if (params->fields) {
7233                         status = -EINVAL;
7234                         goto end;
7235                 }
7236
7237                 if (header)
7238                         *header = NULL;
7239
7240                 return 0;
7241         }
7242
7243         /* Memory allocation. */
7244         offset = calloc(params->n_fields, sizeof(uint32_t));
7245         if (!offset) {
7246                 status = -ENOMEM;
7247                 goto end;
7248         }
7249
7250         /* Check that all the match fields belong to either the same header or
7251          * to the meta-data.
7252          */
7253         hf = header_field_parse(p, params->fields[0].name, &h0);
7254         mf = metadata_field_parse(p, params->fields[0].name);
7255         if ((!hf && !mf) || (hf && hf->var_size)) {
7256                 status = -EINVAL;
7257                 goto end;
7258         }
7259
7260         offset[0] = h0 ? hf->offset : mf->offset;
7261
7262         for (i = 1; i < params->n_fields; i++)
7263                 if (h0) {
7264                         struct header *h;
7265
7266                         hf = header_field_parse(p, params->fields[i].name, &h);
7267                         if (!hf || (h->id != h0->id) || hf->var_size) {
7268                                 status = -EINVAL;
7269                                 goto end;
7270                         }
7271
7272                         offset[i] = hf->offset;
7273                 } else {
7274                         mf = metadata_field_parse(p, params->fields[i].name);
7275                         if (!mf) {
7276                                 status = -EINVAL;
7277                                 goto end;
7278                         }
7279
7280                         offset[i] = mf->offset;
7281                 }
7282
7283         /* Check that there are no duplicated match fields. */
7284         for (i = 0; i < params->n_fields; i++) {
7285                 uint32_t j;
7286
7287                 for (j = 0; j < i; j++)
7288                         if (offset[j] == offset[i]) {
7289                                 status = -EINVAL;
7290                                 goto end;
7291                         }
7292         }
7293
7294         /* Return. */
7295         if (header)
7296                 *header = h0;
7297
7298 end:
7299         free(offset);
7300         return status;
7301 }
7302
7303 int
7304 rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
7305                               const char *name,
7306                               struct rte_swx_pipeline_table_params *params,
7307                               const char *recommended_table_type_name,
7308                               const char *args,
7309                               uint32_t size)
7310 {
7311         struct table_type *type;
7312         struct table *t;
7313         struct action *default_action;
7314         struct header *header = NULL;
7315         uint32_t action_data_size_max = 0, i;
7316         int status = 0;
7317
7318         CHECK(p, EINVAL);
7319
7320         CHECK_NAME(name, EINVAL);
7321         CHECK(!table_find(p, name), EEXIST);
7322         CHECK(!selector_find(p, name), EEXIST);
7323         CHECK(!learner_find(p, name), EEXIST);
7324
7325         CHECK(params, EINVAL);
7326
7327         /* Match checks. */
7328         status = table_match_fields_check(p, params, &header);
7329         if (status)
7330                 return status;
7331
7332         /* Action checks. */
7333         CHECK(params->n_actions, EINVAL);
7334         CHECK(params->action_names, EINVAL);
7335         for (i = 0; i < params->n_actions; i++) {
7336                 const char *action_name = params->action_names[i];
7337                 struct action *a;
7338                 uint32_t action_data_size;
7339
7340                 CHECK_NAME(action_name, EINVAL);
7341
7342                 a = action_find(p, action_name);
7343                 CHECK(a, EINVAL);
7344                 CHECK(!action_does_learning(a), EINVAL);
7345
7346                 action_data_size = a->st ? a->st->n_bits / 8 : 0;
7347                 if (action_data_size > action_data_size_max)
7348                         action_data_size_max = action_data_size;
7349         }
7350
7351         CHECK_NAME(params->default_action_name, EINVAL);
7352         for (i = 0; i < p->n_actions; i++)
7353                 if (!strcmp(params->action_names[i],
7354                             params->default_action_name))
7355                         break;
7356         CHECK(i < params->n_actions, EINVAL);
7357         default_action = action_find(p, params->default_action_name);
7358         CHECK((default_action->st && params->default_action_data) ||
7359               !params->default_action_data, EINVAL);
7360
7361         /* Table type checks. */
7362         if (recommended_table_type_name)
7363                 CHECK_NAME(recommended_table_type_name, EINVAL);
7364
7365         if (params->n_fields) {
7366                 enum rte_swx_table_match_type match_type;
7367
7368                 status = table_match_type_resolve(params->fields, params->n_fields, &match_type);
7369                 if (status)
7370                         return status;
7371
7372                 type = table_type_resolve(p, recommended_table_type_name, match_type);
7373                 CHECK(type, EINVAL);
7374         } else {
7375                 type = NULL;
7376         }
7377
7378         /* Memory allocation. */
7379         t = calloc(1, sizeof(struct table));
7380         CHECK(t, ENOMEM);
7381
7382         t->fields = calloc(params->n_fields, sizeof(struct match_field));
7383         if (!t->fields) {
7384                 free(t);
7385                 CHECK(0, ENOMEM);
7386         }
7387
7388         t->actions = calloc(params->n_actions, sizeof(struct action *));
7389         if (!t->actions) {
7390                 free(t->fields);
7391                 free(t);
7392                 CHECK(0, ENOMEM);
7393         }
7394
7395         if (action_data_size_max) {
7396                 t->default_action_data = calloc(1, action_data_size_max);
7397                 if (!t->default_action_data) {
7398                         free(t->actions);
7399                         free(t->fields);
7400                         free(t);
7401                         CHECK(0, ENOMEM);
7402                 }
7403         }
7404
7405         /* Node initialization. */
7406         strcpy(t->name, name);
7407         if (args && args[0])
7408                 strcpy(t->args, args);
7409         t->type = type;
7410
7411         for (i = 0; i < params->n_fields; i++) {
7412                 struct rte_swx_match_field_params *field = &params->fields[i];
7413                 struct match_field *f = &t->fields[i];
7414
7415                 f->match_type = field->match_type;
7416                 f->field = header ?
7417                         header_field_parse(p, field->name, NULL) :
7418                         metadata_field_parse(p, field->name);
7419         }
7420         t->n_fields = params->n_fields;
7421         t->header = header;
7422
7423         for (i = 0; i < params->n_actions; i++)
7424                 t->actions[i] = action_find(p, params->action_names[i]);
7425         t->default_action = default_action;
7426         if (default_action->st)
7427                 memcpy(t->default_action_data,
7428                        params->default_action_data,
7429                        default_action->st->n_bits / 8);
7430         t->n_actions = params->n_actions;
7431         t->default_action_is_const = params->default_action_is_const;
7432         t->action_data_size_max = action_data_size_max;
7433
7434         t->size = size;
7435         t->id = p->n_tables;
7436
7437         /* Node add to tailq. */
7438         TAILQ_INSERT_TAIL(&p->tables, t, node);
7439         p->n_tables++;
7440
7441         return 0;
7442 }
7443
7444 static struct rte_swx_table_params *
7445 table_params_get(struct table *table)
7446 {
7447         struct rte_swx_table_params *params;
7448         struct field *first, *last;
7449         uint8_t *key_mask;
7450         uint32_t key_size, key_offset, action_data_size, i;
7451
7452         /* Memory allocation. */
7453         params = calloc(1, sizeof(struct rte_swx_table_params));
7454         if (!params)
7455                 return NULL;
7456
7457         /* Find first (smallest offset) and last (biggest offset) match fields. */
7458         first = table->fields[0].field;
7459         last = table->fields[0].field;
7460
7461         for (i = 0; i < table->n_fields; i++) {
7462                 struct field *f = table->fields[i].field;
7463
7464                 if (f->offset < first->offset)
7465                         first = f;
7466
7467                 if (f->offset > last->offset)
7468                         last = f;
7469         }
7470
7471         /* Key offset and size. */
7472         key_offset = first->offset / 8;
7473         key_size = (last->offset + last->n_bits - first->offset) / 8;
7474
7475         /* Memory allocation. */
7476         key_mask = calloc(1, key_size);
7477         if (!key_mask) {
7478                 free(params);
7479                 return NULL;
7480         }
7481
7482         /* Key mask. */
7483         for (i = 0; i < table->n_fields; i++) {
7484                 struct field *f = table->fields[i].field;
7485                 uint32_t start = (f->offset - first->offset) / 8;
7486                 size_t size = f->n_bits / 8;
7487
7488                 memset(&key_mask[start], 0xFF, size);
7489         }
7490
7491         /* Action data size. */
7492         action_data_size = 0;
7493         for (i = 0; i < table->n_actions; i++) {
7494                 struct action *action = table->actions[i];
7495                 uint32_t ads = action->st ? action->st->n_bits / 8 : 0;
7496
7497                 if (ads > action_data_size)
7498                         action_data_size = ads;
7499         }
7500
7501         /* Fill in. */
7502         params->match_type = table->type->match_type;
7503         params->key_size = key_size;
7504         params->key_offset = key_offset;
7505         params->key_mask0 = key_mask;
7506         params->action_data_size = action_data_size;
7507         params->n_keys_max = table->size;
7508
7509         return params;
7510 }
7511
7512 static void
7513 table_params_free(struct rte_swx_table_params *params)
7514 {
7515         if (!params)
7516                 return;
7517
7518         free(params->key_mask0);
7519         free(params);
7520 }
7521
7522 static int
7523 table_stub_lkp(void *table __rte_unused,
7524                void *mailbox __rte_unused,
7525                uint8_t **key __rte_unused,
7526                uint64_t *action_id __rte_unused,
7527                uint8_t **action_data __rte_unused,
7528                int *hit)
7529 {
7530         *hit = 0;
7531         return 1; /* DONE. */
7532 }
7533
7534 static int
7535 table_build(struct rte_swx_pipeline *p)
7536 {
7537         uint32_t i;
7538
7539         /* Per pipeline: table statistics. */
7540         p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics));
7541         CHECK(p->table_stats, ENOMEM);
7542
7543         for (i = 0; i < p->n_tables; i++) {
7544                 p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t));
7545                 CHECK(p->table_stats[i].n_pkts_action, ENOMEM);
7546         }
7547
7548         /* Per thread: table runt-time. */
7549         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7550                 struct thread *t = &p->threads[i];
7551                 struct table *table;
7552
7553                 t->tables = calloc(p->n_tables, sizeof(struct table_runtime));
7554                 CHECK(t->tables, ENOMEM);
7555
7556                 TAILQ_FOREACH(table, &p->tables, node) {
7557                         struct table_runtime *r = &t->tables[table->id];
7558
7559                         if (table->type) {
7560                                 uint64_t size;
7561
7562                                 size = table->type->ops.mailbox_size_get();
7563
7564                                 /* r->func. */
7565                                 r->func = table->type->ops.lkp;
7566
7567                                 /* r->mailbox. */
7568                                 if (size) {
7569                                         r->mailbox = calloc(1, size);
7570                                         CHECK(r->mailbox, ENOMEM);
7571                                 }
7572
7573                                 /* r->key. */
7574                                 r->key = table->header ?
7575                                         &t->structs[table->header->struct_id] :
7576                                         &t->structs[p->metadata_struct_id];
7577                         } else {
7578                                 r->func = table_stub_lkp;
7579                         }
7580                 }
7581         }
7582
7583         return 0;
7584 }
7585
7586 static void
7587 table_build_free(struct rte_swx_pipeline *p)
7588 {
7589         uint32_t i;
7590
7591         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7592                 struct thread *t = &p->threads[i];
7593                 uint32_t j;
7594
7595                 if (!t->tables)
7596                         continue;
7597
7598                 for (j = 0; j < p->n_tables; j++) {
7599                         struct table_runtime *r = &t->tables[j];
7600
7601                         free(r->mailbox);
7602                 }
7603
7604                 free(t->tables);
7605                 t->tables = NULL;
7606         }
7607
7608         if (p->table_stats) {
7609                 for (i = 0; i < p->n_tables; i++)
7610                         free(p->table_stats[i].n_pkts_action);
7611
7612                 free(p->table_stats);
7613         }
7614 }
7615
7616 static void
7617 table_free(struct rte_swx_pipeline *p)
7618 {
7619         table_build_free(p);
7620
7621         /* Tables. */
7622         for ( ; ; ) {
7623                 struct table *elem;
7624
7625                 elem = TAILQ_FIRST(&p->tables);
7626                 if (!elem)
7627                         break;
7628
7629                 TAILQ_REMOVE(&p->tables, elem, node);
7630                 free(elem->fields);
7631                 free(elem->actions);
7632                 free(elem->default_action_data);
7633                 free(elem);
7634         }
7635
7636         /* Table types. */
7637         for ( ; ; ) {
7638                 struct table_type *elem;
7639
7640                 elem = TAILQ_FIRST(&p->table_types);
7641                 if (!elem)
7642                         break;
7643
7644                 TAILQ_REMOVE(&p->table_types, elem, node);
7645                 free(elem);
7646         }
7647 }
7648
7649 /*
7650  * Selector.
7651  */
7652 static struct selector *
7653 selector_find(struct rte_swx_pipeline *p, const char *name)
7654 {
7655         struct selector *s;
7656
7657         TAILQ_FOREACH(s, &p->selectors, node)
7658                 if (strcmp(s->name, name) == 0)
7659                         return s;
7660
7661         return NULL;
7662 }
7663
7664 static struct selector *
7665 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
7666 {
7667         struct selector *s = NULL;
7668
7669         TAILQ_FOREACH(s, &p->selectors, node)
7670                 if (s->id == id)
7671                         return s;
7672
7673         return NULL;
7674 }
7675
7676 static int
7677 selector_fields_check(struct rte_swx_pipeline *p,
7678                       struct rte_swx_pipeline_selector_params *params,
7679                       struct header **header)
7680 {
7681         struct header *h0 = NULL;
7682         struct field *hf, *mf;
7683         uint32_t i;
7684
7685         /* Return if no selector fields. */
7686         if (!params->n_selector_fields || !params->selector_field_names)
7687                 return -EINVAL;
7688
7689         /* Check that all the selector fields either belong to the same header
7690          * or are all meta-data fields.
7691          */
7692         hf = header_field_parse(p, params->selector_field_names[0], &h0);
7693         mf = metadata_field_parse(p, params->selector_field_names[0]);
7694         if (!hf && !mf)
7695                 return -EINVAL;
7696
7697         for (i = 1; i < params->n_selector_fields; i++)
7698                 if (h0) {
7699                         struct header *h;
7700
7701                         hf = header_field_parse(p, params->selector_field_names[i], &h);
7702                         if (!hf || (h->id != h0->id))
7703                                 return -EINVAL;
7704                 } else {
7705                         mf = metadata_field_parse(p, params->selector_field_names[i]);
7706                         if (!mf)
7707                                 return -EINVAL;
7708                 }
7709
7710         /* Check that there are no duplicated match fields. */
7711         for (i = 0; i < params->n_selector_fields; i++) {
7712                 const char *field_name = params->selector_field_names[i];
7713                 uint32_t j;
7714
7715                 for (j = i + 1; j < params->n_selector_fields; j++)
7716                         if (!strcmp(params->selector_field_names[j], field_name))
7717                                 return -EINVAL;
7718         }
7719
7720         /* Return. */
7721         if (header)
7722                 *header = h0;
7723
7724         return 0;
7725 }
7726
7727 int
7728 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p,
7729                                  const char *name,
7730                                  struct rte_swx_pipeline_selector_params *params)
7731 {
7732         struct selector *s;
7733         struct header *selector_header = NULL;
7734         struct field *group_id_field, *member_id_field;
7735         uint32_t i;
7736         int status = 0;
7737
7738         CHECK(p, EINVAL);
7739
7740         CHECK_NAME(name, EINVAL);
7741         CHECK(!table_find(p, name), EEXIST);
7742         CHECK(!selector_find(p, name), EEXIST);
7743         CHECK(!learner_find(p, name), EEXIST);
7744
7745         CHECK(params, EINVAL);
7746
7747         CHECK_NAME(params->group_id_field_name, EINVAL);
7748         group_id_field = metadata_field_parse(p, params->group_id_field_name);
7749         CHECK(group_id_field, EINVAL);
7750
7751         for (i = 0; i < params->n_selector_fields; i++) {
7752                 const char *field_name = params->selector_field_names[i];
7753
7754                 CHECK_NAME(field_name, EINVAL);
7755         }
7756         status = selector_fields_check(p, params, &selector_header);
7757         if (status)
7758                 return status;
7759
7760         CHECK_NAME(params->member_id_field_name, EINVAL);
7761         member_id_field = metadata_field_parse(p, params->member_id_field_name);
7762         CHECK(member_id_field, EINVAL);
7763
7764         CHECK(params->n_groups_max, EINVAL);
7765
7766         CHECK(params->n_members_per_group_max, EINVAL);
7767
7768         /* Memory allocation. */
7769         s = calloc(1, sizeof(struct selector));
7770         if (!s) {
7771                 status = -ENOMEM;
7772                 goto error;
7773         }
7774
7775         s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *));
7776         if (!s->selector_fields) {
7777                 status = -ENOMEM;
7778                 goto error;
7779         }
7780
7781         /* Node initialization. */
7782         strcpy(s->name, name);
7783
7784         s->group_id_field = group_id_field;
7785
7786         for (i = 0; i < params->n_selector_fields; i++) {
7787                 const char *field_name = params->selector_field_names[i];
7788
7789                 s->selector_fields[i] = selector_header ?
7790                         header_field_parse(p, field_name, NULL) :
7791                         metadata_field_parse(p, field_name);
7792         }
7793
7794         s->n_selector_fields = params->n_selector_fields;
7795
7796         s->selector_header = selector_header;
7797
7798         s->member_id_field = member_id_field;
7799
7800         s->n_groups_max = params->n_groups_max;
7801
7802         s->n_members_per_group_max = params->n_members_per_group_max;
7803
7804         s->id = p->n_selectors;
7805
7806         /* Node add to tailq. */
7807         TAILQ_INSERT_TAIL(&p->selectors, s, node);
7808         p->n_selectors++;
7809
7810         return 0;
7811
7812 error:
7813         if (!s)
7814                 return status;
7815
7816         free(s->selector_fields);
7817
7818         free(s);
7819
7820         return status;
7821 }
7822
7823 static void
7824 selector_params_free(struct rte_swx_table_selector_params *params)
7825 {
7826         if (!params)
7827                 return;
7828
7829         free(params->selector_mask);
7830
7831         free(params);
7832 }
7833
7834 static struct rte_swx_table_selector_params *
7835 selector_table_params_get(struct selector *s)
7836 {
7837         struct rte_swx_table_selector_params *params = NULL;
7838         struct field *first, *last;
7839         uint32_t i;
7840
7841         /* Memory allocation. */
7842         params = calloc(1, sizeof(struct rte_swx_table_selector_params));
7843         if (!params)
7844                 goto error;
7845
7846         /* Group ID. */
7847         params->group_id_offset = s->group_id_field->offset / 8;
7848
7849         /* Find first (smallest offset) and last (biggest offset) selector fields. */
7850         first = s->selector_fields[0];
7851         last = s->selector_fields[0];
7852
7853         for (i = 0; i < s->n_selector_fields; i++) {
7854                 struct field *f = s->selector_fields[i];
7855
7856                 if (f->offset < first->offset)
7857                         first = f;
7858
7859                 if (f->offset > last->offset)
7860                         last = f;
7861         }
7862
7863         /* Selector offset and size. */
7864         params->selector_offset = first->offset / 8;
7865         params->selector_size = (last->offset + last->n_bits - first->offset) / 8;
7866
7867         /* Memory allocation. */
7868         params->selector_mask = calloc(1, params->selector_size);
7869         if (!params->selector_mask)
7870                 goto error;
7871
7872         /* Selector mask. */
7873         for (i = 0; i < s->n_selector_fields; i++) {
7874                 struct field *f = s->selector_fields[i];
7875                 uint32_t start = (f->offset - first->offset) / 8;
7876                 size_t size = f->n_bits / 8;
7877
7878                 memset(&params->selector_mask[start], 0xFF, size);
7879         }
7880
7881         /* Member ID. */
7882         params->member_id_offset = s->member_id_field->offset / 8;
7883
7884         /* Maximum number of groups. */
7885         params->n_groups_max = s->n_groups_max;
7886
7887         /* Maximum number of members per group. */
7888         params->n_members_per_group_max = s->n_members_per_group_max;
7889
7890         return params;
7891
7892 error:
7893         selector_params_free(params);
7894         return NULL;
7895 }
7896
7897 static void
7898 selector_build_free(struct rte_swx_pipeline *p)
7899 {
7900         uint32_t i;
7901
7902         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7903                 struct thread *t = &p->threads[i];
7904                 uint32_t j;
7905
7906                 if (!t->selectors)
7907                         continue;
7908
7909                 for (j = 0; j < p->n_selectors; j++) {
7910                         struct selector_runtime *r = &t->selectors[j];
7911
7912                         free(r->mailbox);
7913                 }
7914
7915                 free(t->selectors);
7916                 t->selectors = NULL;
7917         }
7918
7919         free(p->selector_stats);
7920         p->selector_stats = NULL;
7921 }
7922
7923 static int
7924 selector_build(struct rte_swx_pipeline *p)
7925 {
7926         uint32_t i;
7927         int status = 0;
7928
7929         /* Per pipeline: selector statistics. */
7930         p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics));
7931         if (!p->selector_stats) {
7932                 status = -ENOMEM;
7933                 goto error;
7934         }
7935
7936         /* Per thread: selector run-time. */
7937         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7938                 struct thread *t = &p->threads[i];
7939                 struct selector *s;
7940
7941                 t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime));
7942                 if (!t->selectors) {
7943                         status = -ENOMEM;
7944                         goto error;
7945                 }
7946
7947                 TAILQ_FOREACH(s, &p->selectors, node) {
7948                         struct selector_runtime *r = &t->selectors[s->id];
7949                         uint64_t size;
7950
7951                         /* r->mailbox. */
7952                         size = rte_swx_table_selector_mailbox_size_get();
7953                         if (size) {
7954                                 r->mailbox = calloc(1, size);
7955                                 if (!r->mailbox) {
7956                                         status = -ENOMEM;
7957                                         goto error;
7958                                 }
7959                         }
7960
7961                         /* r->group_id_buffer. */
7962                         r->group_id_buffer = &t->structs[p->metadata_struct_id];
7963
7964                         /* r->selector_buffer. */
7965                         r->selector_buffer = s->selector_header ?
7966                                 &t->structs[s->selector_header->struct_id] :
7967                                 &t->structs[p->metadata_struct_id];
7968
7969                         /* r->member_id_buffer. */
7970                         r->member_id_buffer = &t->structs[p->metadata_struct_id];
7971                 }
7972         }
7973
7974         return 0;
7975
7976 error:
7977         selector_build_free(p);
7978         return status;
7979 }
7980
7981 static void
7982 selector_free(struct rte_swx_pipeline *p)
7983 {
7984         selector_build_free(p);
7985
7986         /* Selector tables. */
7987         for ( ; ; ) {
7988                 struct selector *elem;
7989
7990                 elem = TAILQ_FIRST(&p->selectors);
7991                 if (!elem)
7992                         break;
7993
7994                 TAILQ_REMOVE(&p->selectors, elem, node);
7995                 free(elem->selector_fields);
7996                 free(elem);
7997         }
7998 }
7999
8000 /*
8001  * Learner table.
8002  */
8003 static struct learner *
8004 learner_find(struct rte_swx_pipeline *p, const char *name)
8005 {
8006         struct learner *l;
8007
8008         TAILQ_FOREACH(l, &p->learners, node)
8009                 if (!strcmp(l->name, name))
8010                         return l;
8011
8012         return NULL;
8013 }
8014
8015 static struct learner *
8016 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8017 {
8018         struct learner *l = NULL;
8019
8020         TAILQ_FOREACH(l, &p->learners, node)
8021                 if (l->id == id)
8022                         return l;
8023
8024         return NULL;
8025 }
8026
8027 static int
8028 learner_match_fields_check(struct rte_swx_pipeline *p,
8029                            struct rte_swx_pipeline_learner_params *params,
8030                            struct header **header)
8031 {
8032         struct header *h0 = NULL;
8033         struct field *hf, *mf;
8034         uint32_t i;
8035
8036         /* Return if no match fields. */
8037         if (!params->n_fields || !params->field_names)
8038                 return -EINVAL;
8039
8040         /* Check that all the match fields either belong to the same header
8041          * or are all meta-data fields.
8042          */
8043         hf = header_field_parse(p, params->field_names[0], &h0);
8044         mf = metadata_field_parse(p, params->field_names[0]);
8045         if (!hf && !mf)
8046                 return -EINVAL;
8047
8048         for (i = 1; i < params->n_fields; i++)
8049                 if (h0) {
8050                         struct header *h;
8051
8052                         hf = header_field_parse(p, params->field_names[i], &h);
8053                         if (!hf || (h->id != h0->id))
8054                                 return -EINVAL;
8055                 } else {
8056                         mf = metadata_field_parse(p, params->field_names[i]);
8057                         if (!mf)
8058                                 return -EINVAL;
8059                 }
8060
8061         /* Check that there are no duplicated match fields. */
8062         for (i = 0; i < params->n_fields; i++) {
8063                 const char *field_name = params->field_names[i];
8064                 uint32_t j;
8065
8066                 for (j = i + 1; j < params->n_fields; j++)
8067                         if (!strcmp(params->field_names[j], field_name))
8068                                 return -EINVAL;
8069         }
8070
8071         /* Return. */
8072         if (header)
8073                 *header = h0;
8074
8075         return 0;
8076 }
8077
8078 static int
8079 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name)
8080 {
8081         struct struct_type *mst = p->metadata_st, *ast = a->st;
8082         struct field *mf, *af;
8083         uint32_t mf_pos, i;
8084
8085         if (!ast) {
8086                 if (mf_name)
8087                         return -EINVAL;
8088
8089                 return 0;
8090         }
8091
8092         /* Check that mf_name is the name of a valid meta-data field. */
8093         CHECK_NAME(mf_name, EINVAL);
8094         mf = metadata_field_parse(p, mf_name);
8095         CHECK(mf, EINVAL);
8096
8097         /* Check that there are enough meta-data fields, starting with the mf_name field, to cover
8098          * all the action arguments.
8099          */
8100         mf_pos = mf - mst->fields;
8101         CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL);
8102
8103         /* Check that the size of each of the identified meta-data fields matches exactly the size
8104          * of the corresponding action argument.
8105          */
8106         for (i = 0; i < ast->n_fields; i++) {
8107                 mf = &mst->fields[mf_pos + i];
8108                 af = &ast->fields[i];
8109
8110                 CHECK(mf->n_bits == af->n_bits, EINVAL);
8111         }
8112
8113         return 0;
8114 }
8115
8116 static int
8117 learner_action_learning_check(struct rte_swx_pipeline *p,
8118                               struct action *action,
8119                               const char **action_names,
8120                               uint32_t n_actions)
8121 {
8122         uint32_t i;
8123
8124         /* For each "learn" instruction of the current action, check that the learned action (i.e.
8125          * the action passed as argument to the "learn" instruction) is also enabled for the
8126          * current learner table.
8127          */
8128         for (i = 0; i < action->n_instructions; i++) {
8129                 struct instruction *instr = &action->instructions[i];
8130                 uint32_t found = 0, j;
8131
8132                 if (instr->type != INSTR_LEARNER_LEARN)
8133                         continue;
8134
8135                 for (j = 0; j < n_actions; j++) {
8136                         struct action *a;
8137
8138                         a = action_find(p, action_names[j]);
8139                         if (!a)
8140                                 return -EINVAL;
8141
8142                         if (a->id == instr->learn.action_id)
8143                                 found = 1;
8144                 }
8145
8146                 if (!found)
8147                         return -EINVAL;
8148         }
8149
8150         return 0;
8151 }
8152
8153 int
8154 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p,
8155                               const char *name,
8156                               struct rte_swx_pipeline_learner_params *params,
8157                               uint32_t size,
8158                               uint32_t timeout)
8159 {
8160         struct learner *l = NULL;
8161         struct action *default_action;
8162         struct header *header = NULL;
8163         uint32_t action_data_size_max = 0, i;
8164         int status = 0;
8165
8166         CHECK(p, EINVAL);
8167
8168         CHECK_NAME(name, EINVAL);
8169         CHECK(!table_find(p, name), EEXIST);
8170         CHECK(!selector_find(p, name), EEXIST);
8171         CHECK(!learner_find(p, name), EEXIST);
8172
8173         CHECK(params, EINVAL);
8174
8175         /* Match checks. */
8176         status = learner_match_fields_check(p, params, &header);
8177         if (status)
8178                 return status;
8179
8180         /* Action checks. */
8181         CHECK(params->n_actions, EINVAL);
8182
8183         CHECK(params->action_names, EINVAL);
8184         for (i = 0; i < params->n_actions; i++) {
8185                 const char *action_name = params->action_names[i];
8186                 struct action *a;
8187                 uint32_t action_data_size;
8188
8189                 CHECK_NAME(action_name, EINVAL);
8190
8191                 a = action_find(p, action_name);
8192                 CHECK(a, EINVAL);
8193
8194                 status = learner_action_learning_check(p,
8195                                                        a,
8196                                                        params->action_names,
8197                                                        params->n_actions);
8198                 if (status)
8199                         return status;
8200
8201                 action_data_size = a->st ? a->st->n_bits / 8 : 0;
8202                 if (action_data_size > action_data_size_max)
8203                         action_data_size_max = action_data_size;
8204         }
8205
8206         CHECK_NAME(params->default_action_name, EINVAL);
8207         for (i = 0; i < p->n_actions; i++)
8208                 if (!strcmp(params->action_names[i],
8209                             params->default_action_name))
8210                         break;
8211         CHECK(i < params->n_actions, EINVAL);
8212
8213         default_action = action_find(p, params->default_action_name);
8214         CHECK((default_action->st && params->default_action_data) ||
8215               !params->default_action_data, EINVAL);
8216
8217         /* Any other checks. */
8218         CHECK(size, EINVAL);
8219         CHECK(timeout, EINVAL);
8220
8221         /* Memory allocation. */
8222         l = calloc(1, sizeof(struct learner));
8223         if (!l)
8224                 goto nomem;
8225
8226         l->fields = calloc(params->n_fields, sizeof(struct field *));
8227         if (!l->fields)
8228                 goto nomem;
8229
8230         l->actions = calloc(params->n_actions, sizeof(struct action *));
8231         if (!l->actions)
8232                 goto nomem;
8233
8234         if (action_data_size_max) {
8235                 l->default_action_data = calloc(1, action_data_size_max);
8236                 if (!l->default_action_data)
8237                         goto nomem;
8238         }
8239
8240         /* Node initialization. */
8241         strcpy(l->name, name);
8242
8243         for (i = 0; i < params->n_fields; i++) {
8244                 const char *field_name = params->field_names[i];
8245
8246                 l->fields[i] = header ?
8247                         header_field_parse(p, field_name, NULL) :
8248                         metadata_field_parse(p, field_name);
8249         }
8250
8251         l->n_fields = params->n_fields;
8252
8253         l->header = header;
8254
8255         for (i = 0; i < params->n_actions; i++)
8256                 l->actions[i] = action_find(p, params->action_names[i]);
8257
8258         l->default_action = default_action;
8259
8260         if (default_action->st)
8261                 memcpy(l->default_action_data,
8262                        params->default_action_data,
8263                        default_action->st->n_bits / 8);
8264
8265         l->n_actions = params->n_actions;
8266
8267         l->default_action_is_const = params->default_action_is_const;
8268
8269         l->action_data_size_max = action_data_size_max;
8270
8271         l->size = size;
8272
8273         l->timeout = timeout;
8274
8275         l->id = p->n_learners;
8276
8277         /* Node add to tailq. */
8278         TAILQ_INSERT_TAIL(&p->learners, l, node);
8279         p->n_learners++;
8280
8281         return 0;
8282
8283 nomem:
8284         if (!l)
8285                 return -ENOMEM;
8286
8287         free(l->actions);
8288         free(l->fields);
8289         free(l);
8290
8291         return -ENOMEM;
8292 }
8293
8294 static void
8295 learner_params_free(struct rte_swx_table_learner_params *params)
8296 {
8297         if (!params)
8298                 return;
8299
8300         free(params->key_mask0);
8301
8302         free(params);
8303 }
8304
8305 static struct rte_swx_table_learner_params *
8306 learner_params_get(struct learner *l)
8307 {
8308         struct rte_swx_table_learner_params *params = NULL;
8309         struct field *first, *last;
8310         uint32_t i;
8311
8312         /* Memory allocation. */
8313         params = calloc(1, sizeof(struct rte_swx_table_learner_params));
8314         if (!params)
8315                 goto error;
8316
8317         /* Find first (smallest offset) and last (biggest offset) match fields. */
8318         first = l->fields[0];
8319         last = l->fields[0];
8320
8321         for (i = 0; i < l->n_fields; i++) {
8322                 struct field *f = l->fields[i];
8323
8324                 if (f->offset < first->offset)
8325                         first = f;
8326
8327                 if (f->offset > last->offset)
8328                         last = f;
8329         }
8330
8331         /* Key offset and size. */
8332         params->key_offset = first->offset / 8;
8333         params->key_size = (last->offset + last->n_bits - first->offset) / 8;
8334
8335         /* Memory allocation. */
8336         params->key_mask0 = calloc(1, params->key_size);
8337         if (!params->key_mask0)
8338                 goto error;
8339
8340         /* Key mask. */
8341         for (i = 0; i < l->n_fields; i++) {
8342                 struct field *f = l->fields[i];
8343                 uint32_t start = (f->offset - first->offset) / 8;
8344                 size_t size = f->n_bits / 8;
8345
8346                 memset(&params->key_mask0[start], 0xFF, size);
8347         }
8348
8349         /* Action data size. */
8350         params->action_data_size = l->action_data_size_max;
8351
8352         /* Maximum number of keys. */
8353         params->n_keys_max = l->size;
8354
8355         /* Timeout. */
8356         params->key_timeout = l->timeout;
8357
8358         return params;
8359
8360 error:
8361         learner_params_free(params);
8362         return NULL;
8363 }
8364
8365 static void
8366 learner_build_free(struct rte_swx_pipeline *p)
8367 {
8368         uint32_t i;
8369
8370         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
8371                 struct thread *t = &p->threads[i];
8372                 uint32_t j;
8373
8374                 if (!t->learners)
8375                         continue;
8376
8377                 for (j = 0; j < p->n_learners; j++) {
8378                         struct learner_runtime *r = &t->learners[j];
8379
8380                         free(r->mailbox);
8381                 }
8382
8383                 free(t->learners);
8384                 t->learners = NULL;
8385         }
8386
8387         if (p->learner_stats) {
8388                 for (i = 0; i < p->n_learners; i++)
8389                         free(p->learner_stats[i].n_pkts_action);
8390
8391                 free(p->learner_stats);
8392         }
8393 }
8394
8395 static int
8396 learner_build(struct rte_swx_pipeline *p)
8397 {
8398         uint32_t i;
8399         int status = 0;
8400
8401         /* Per pipeline: learner statistics. */
8402         p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics));
8403         CHECK(p->learner_stats, ENOMEM);
8404
8405         for (i = 0; i < p->n_learners; i++) {
8406                 p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t));
8407                 CHECK(p->learner_stats[i].n_pkts_action, ENOMEM);
8408         }
8409
8410         /* Per thread: learner run-time. */
8411         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
8412                 struct thread *t = &p->threads[i];
8413                 struct learner *l;
8414
8415                 t->learners = calloc(p->n_learners, sizeof(struct learner_runtime));
8416                 if (!t->learners) {
8417                         status = -ENOMEM;
8418                         goto error;
8419                 }
8420
8421                 TAILQ_FOREACH(l, &p->learners, node) {
8422                         struct learner_runtime *r = &t->learners[l->id];
8423                         uint64_t size;
8424
8425                         /* r->mailbox. */
8426                         size = rte_swx_table_learner_mailbox_size_get();
8427                         if (size) {
8428                                 r->mailbox = calloc(1, size);
8429                                 if (!r->mailbox) {
8430                                         status = -ENOMEM;
8431                                         goto error;
8432                                 }
8433                         }
8434
8435                         /* r->key. */
8436                         r->key = l->header ?
8437                                 &t->structs[l->header->struct_id] :
8438                                 &t->structs[p->metadata_struct_id];
8439                 }
8440         }
8441
8442         return 0;
8443
8444 error:
8445         learner_build_free(p);
8446         return status;
8447 }
8448
8449 static void
8450 learner_free(struct rte_swx_pipeline *p)
8451 {
8452         learner_build_free(p);
8453
8454         /* Learner tables. */
8455         for ( ; ; ) {
8456                 struct learner *l;
8457
8458                 l = TAILQ_FIRST(&p->learners);
8459                 if (!l)
8460                         break;
8461
8462                 TAILQ_REMOVE(&p->learners, l, node);
8463                 free(l->fields);
8464                 free(l->actions);
8465                 free(l->default_action_data);
8466                 free(l);
8467         }
8468 }
8469
8470 /*
8471  * Table state.
8472  */
8473 static int
8474 table_state_build(struct rte_swx_pipeline *p)
8475 {
8476         struct table *table;
8477         struct selector *s;
8478         struct learner *l;
8479
8480         p->table_state = calloc(p->n_tables + p->n_selectors,
8481                                 sizeof(struct rte_swx_table_state));
8482         CHECK(p->table_state, ENOMEM);
8483
8484         TAILQ_FOREACH(table, &p->tables, node) {
8485                 struct rte_swx_table_state *ts = &p->table_state[table->id];
8486
8487                 if (table->type) {
8488                         struct rte_swx_table_params *params;
8489
8490                         /* ts->obj. */
8491                         params = table_params_get(table);
8492                         CHECK(params, ENOMEM);
8493
8494                         ts->obj = table->type->ops.create(params,
8495                                 NULL,
8496                                 table->args,
8497                                 p->numa_node);
8498
8499                         table_params_free(params);
8500                         CHECK(ts->obj, ENODEV);
8501                 }
8502
8503                 /* ts->default_action_data. */
8504                 if (table->action_data_size_max) {
8505                         ts->default_action_data =
8506                                 malloc(table->action_data_size_max);
8507                         CHECK(ts->default_action_data, ENOMEM);
8508
8509                         memcpy(ts->default_action_data,
8510                                table->default_action_data,
8511                                table->action_data_size_max);
8512                 }
8513
8514                 /* ts->default_action_id. */
8515                 ts->default_action_id = table->default_action->id;
8516         }
8517
8518         TAILQ_FOREACH(s, &p->selectors, node) {
8519                 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id];
8520                 struct rte_swx_table_selector_params *params;
8521
8522                 /* ts->obj. */
8523                 params = selector_table_params_get(s);
8524                 CHECK(params, ENOMEM);
8525
8526                 ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node);
8527
8528                 selector_params_free(params);
8529                 CHECK(ts->obj, ENODEV);
8530         }
8531
8532         TAILQ_FOREACH(l, &p->learners, node) {
8533                 struct rte_swx_table_state *ts = &p->table_state[p->n_tables +
8534                         p->n_selectors + l->id];
8535                 struct rte_swx_table_learner_params *params;
8536
8537                 /* ts->obj. */
8538                 params = learner_params_get(l);
8539                 CHECK(params, ENOMEM);
8540
8541                 ts->obj = rte_swx_table_learner_create(params, p->numa_node);
8542                 learner_params_free(params);
8543                 CHECK(ts->obj, ENODEV);
8544
8545                 /* ts->default_action_data. */
8546                 if (l->action_data_size_max) {
8547                         ts->default_action_data = malloc(l->action_data_size_max);
8548                         CHECK(ts->default_action_data, ENOMEM);
8549
8550                         memcpy(ts->default_action_data,
8551                                l->default_action_data,
8552                                l->action_data_size_max);
8553                 }
8554
8555                 /* ts->default_action_id. */
8556                 ts->default_action_id = l->default_action->id;
8557         }
8558
8559         return 0;
8560 }
8561
8562 static void
8563 table_state_build_free(struct rte_swx_pipeline *p)
8564 {
8565         uint32_t i;
8566
8567         if (!p->table_state)
8568                 return;
8569
8570         for (i = 0; i < p->n_tables; i++) {
8571                 struct rte_swx_table_state *ts = &p->table_state[i];
8572                 struct table *table = table_find_by_id(p, i);
8573
8574                 /* ts->obj. */
8575                 if (table->type && ts->obj)
8576                         table->type->ops.free(ts->obj);
8577
8578                 /* ts->default_action_data. */
8579                 free(ts->default_action_data);
8580         }
8581
8582         for (i = 0; i < p->n_selectors; i++) {
8583                 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i];
8584
8585                 /* ts->obj. */
8586                 if (ts->obj)
8587                         rte_swx_table_selector_free(ts->obj);
8588         }
8589
8590         for (i = 0; i < p->n_learners; i++) {
8591                 struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i];
8592
8593                 /* ts->obj. */
8594                 if (ts->obj)
8595                         rte_swx_table_learner_free(ts->obj);
8596
8597                 /* ts->default_action_data. */
8598                 free(ts->default_action_data);
8599         }
8600
8601         free(p->table_state);
8602         p->table_state = NULL;
8603 }
8604
8605 static void
8606 table_state_free(struct rte_swx_pipeline *p)
8607 {
8608         table_state_build_free(p);
8609 }
8610
8611 /*
8612  * Register array.
8613  */
8614 static struct regarray *
8615 regarray_find(struct rte_swx_pipeline *p, const char *name)
8616 {
8617         struct regarray *elem;
8618
8619         TAILQ_FOREACH(elem, &p->regarrays, node)
8620                 if (!strcmp(elem->name, name))
8621                         return elem;
8622
8623         return NULL;
8624 }
8625
8626 static struct regarray *
8627 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8628 {
8629         struct regarray *elem = NULL;
8630
8631         TAILQ_FOREACH(elem, &p->regarrays, node)
8632                 if (elem->id == id)
8633                         return elem;
8634
8635         return NULL;
8636 }
8637
8638 int
8639 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,
8640                               const char *name,
8641                               uint32_t size,
8642                               uint64_t init_val)
8643 {
8644         struct regarray *r;
8645
8646         CHECK(p, EINVAL);
8647
8648         CHECK_NAME(name, EINVAL);
8649         CHECK(!regarray_find(p, name), EEXIST);
8650
8651         CHECK(size, EINVAL);
8652         size = rte_align32pow2(size);
8653
8654         /* Memory allocation. */
8655         r = calloc(1, sizeof(struct regarray));
8656         CHECK(r, ENOMEM);
8657
8658         /* Node initialization. */
8659         strcpy(r->name, name);
8660         r->init_val = init_val;
8661         r->size = size;
8662         r->id = p->n_regarrays;
8663
8664         /* Node add to tailq. */
8665         TAILQ_INSERT_TAIL(&p->regarrays, r, node);
8666         p->n_regarrays++;
8667
8668         return 0;
8669 }
8670
8671 static int
8672 regarray_build(struct rte_swx_pipeline *p)
8673 {
8674         struct regarray *regarray;
8675
8676         if (!p->n_regarrays)
8677                 return 0;
8678
8679         p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime));
8680         CHECK(p->regarray_runtime, ENOMEM);
8681
8682         TAILQ_FOREACH(regarray, &p->regarrays, node) {
8683                 struct regarray_runtime *r = &p->regarray_runtime[regarray->id];
8684                 uint32_t i;
8685
8686                 r->regarray = env_malloc(regarray->size * sizeof(uint64_t),
8687                                          RTE_CACHE_LINE_SIZE,
8688                                          p->numa_node);
8689                 CHECK(r->regarray, ENOMEM);
8690
8691                 if (regarray->init_val)
8692                         for (i = 0; i < regarray->size; i++)
8693                                 r->regarray[i] = regarray->init_val;
8694
8695                 r->size_mask = regarray->size - 1;
8696         }
8697
8698         return 0;
8699 }
8700
8701 static void
8702 regarray_build_free(struct rte_swx_pipeline *p)
8703 {
8704         uint32_t i;
8705
8706         if (!p->regarray_runtime)
8707                 return;
8708
8709         for (i = 0; i < p->n_regarrays; i++) {
8710                 struct regarray *regarray = regarray_find_by_id(p, i);
8711                 struct regarray_runtime *r = &p->regarray_runtime[i];
8712
8713                 env_free(r->regarray, regarray->size * sizeof(uint64_t));
8714         }
8715
8716         free(p->regarray_runtime);
8717         p->regarray_runtime = NULL;
8718 }
8719
8720 static void
8721 regarray_free(struct rte_swx_pipeline *p)
8722 {
8723         regarray_build_free(p);
8724
8725         for ( ; ; ) {
8726                 struct regarray *elem;
8727
8728                 elem = TAILQ_FIRST(&p->regarrays);
8729                 if (!elem)
8730                         break;
8731
8732                 TAILQ_REMOVE(&p->regarrays, elem, node);
8733                 free(elem);
8734         }
8735 }
8736
8737 /*
8738  * Meter array.
8739  */
8740 static struct meter_profile *
8741 meter_profile_find(struct rte_swx_pipeline *p, const char *name)
8742 {
8743         struct meter_profile *elem;
8744
8745         TAILQ_FOREACH(elem, &p->meter_profiles, node)
8746                 if (!strcmp(elem->name, name))
8747                         return elem;
8748
8749         return NULL;
8750 }
8751
8752 static struct metarray *
8753 metarray_find(struct rte_swx_pipeline *p, const char *name)
8754 {
8755         struct metarray *elem;
8756
8757         TAILQ_FOREACH(elem, &p->metarrays, node)
8758                 if (!strcmp(elem->name, name))
8759                         return elem;
8760
8761         return NULL;
8762 }
8763
8764 static struct metarray *
8765 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8766 {
8767         struct metarray *elem = NULL;
8768
8769         TAILQ_FOREACH(elem, &p->metarrays, node)
8770                 if (elem->id == id)
8771                         return elem;
8772
8773         return NULL;
8774 }
8775
8776 int
8777 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p,
8778                                  const char *name,
8779                                  uint32_t size)
8780 {
8781         struct metarray *m;
8782
8783         CHECK(p, EINVAL);
8784
8785         CHECK_NAME(name, EINVAL);
8786         CHECK(!metarray_find(p, name), EEXIST);
8787
8788         CHECK(size, EINVAL);
8789         size = rte_align32pow2(size);
8790
8791         /* Memory allocation. */
8792         m = calloc(1, sizeof(struct metarray));
8793         CHECK(m, ENOMEM);
8794
8795         /* Node initialization. */
8796         strcpy(m->name, name);
8797         m->size = size;
8798         m->id = p->n_metarrays;
8799
8800         /* Node add to tailq. */
8801         TAILQ_INSERT_TAIL(&p->metarrays, m, node);
8802         p->n_metarrays++;
8803
8804         return 0;
8805 }
8806
8807 struct meter_profile meter_profile_default = {
8808         .node = {0},
8809         .name = "",
8810         .params = {0},
8811
8812         .profile = {
8813                 .cbs = 10000,
8814                 .pbs = 10000,
8815                 .cir_period = 1,
8816                 .cir_bytes_per_period = 1,
8817                 .pir_period = 1,
8818                 .pir_bytes_per_period = 1,
8819         },
8820
8821         .n_users = 0,
8822 };
8823
8824 static void
8825 meter_init(struct meter *m)
8826 {
8827         memset(m, 0, sizeof(struct meter));
8828         rte_meter_trtcm_config(&m->m, &meter_profile_default.profile);
8829         m->profile = &meter_profile_default;
8830         m->color_mask = RTE_COLOR_GREEN;
8831
8832         meter_profile_default.n_users++;
8833 }
8834
8835 static int
8836 metarray_build(struct rte_swx_pipeline *p)
8837 {
8838         struct metarray *m;
8839
8840         if (!p->n_metarrays)
8841                 return 0;
8842
8843         p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime));
8844         CHECK(p->metarray_runtime, ENOMEM);
8845
8846         TAILQ_FOREACH(m, &p->metarrays, node) {
8847                 struct metarray_runtime *r = &p->metarray_runtime[m->id];
8848                 uint32_t i;
8849
8850                 r->metarray = env_malloc(m->size * sizeof(struct meter),
8851                                          RTE_CACHE_LINE_SIZE,
8852                                          p->numa_node);
8853                 CHECK(r->metarray, ENOMEM);
8854
8855                 for (i = 0; i < m->size; i++)
8856                         meter_init(&r->metarray[i]);
8857
8858                 r->size_mask = m->size - 1;
8859         }
8860
8861         return 0;
8862 }
8863
8864 static void
8865 metarray_build_free(struct rte_swx_pipeline *p)
8866 {
8867         uint32_t i;
8868
8869         if (!p->metarray_runtime)
8870                 return;
8871
8872         for (i = 0; i < p->n_metarrays; i++) {
8873                 struct metarray *m = metarray_find_by_id(p, i);
8874                 struct metarray_runtime *r = &p->metarray_runtime[i];
8875
8876                 env_free(r->metarray, m->size * sizeof(struct meter));
8877         }
8878
8879         free(p->metarray_runtime);
8880         p->metarray_runtime = NULL;
8881 }
8882
8883 static void
8884 metarray_free(struct rte_swx_pipeline *p)
8885 {
8886         metarray_build_free(p);
8887
8888         /* Meter arrays. */
8889         for ( ; ; ) {
8890                 struct metarray *elem;
8891
8892                 elem = TAILQ_FIRST(&p->metarrays);
8893                 if (!elem)
8894                         break;
8895
8896                 TAILQ_REMOVE(&p->metarrays, elem, node);
8897                 free(elem);
8898         }
8899
8900         /* Meter profiles. */
8901         for ( ; ; ) {
8902                 struct meter_profile *elem;
8903
8904                 elem = TAILQ_FIRST(&p->meter_profiles);
8905                 if (!elem)
8906                         break;
8907
8908                 TAILQ_REMOVE(&p->meter_profiles, elem, node);
8909                 free(elem);
8910         }
8911 }
8912
8913 /*
8914  * Pipeline.
8915  */
8916 int
8917 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
8918 {
8919         struct rte_swx_pipeline *pipeline;
8920
8921         /* Check input parameters. */
8922         CHECK(p, EINVAL);
8923
8924         /* Memory allocation. */
8925         pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
8926         CHECK(pipeline, ENOMEM);
8927
8928         /* Initialization. */
8929         TAILQ_INIT(&pipeline->struct_types);
8930         TAILQ_INIT(&pipeline->port_in_types);
8931         TAILQ_INIT(&pipeline->ports_in);
8932         TAILQ_INIT(&pipeline->port_out_types);
8933         TAILQ_INIT(&pipeline->ports_out);
8934         TAILQ_INIT(&pipeline->extern_types);
8935         TAILQ_INIT(&pipeline->extern_objs);
8936         TAILQ_INIT(&pipeline->extern_funcs);
8937         TAILQ_INIT(&pipeline->headers);
8938         TAILQ_INIT(&pipeline->actions);
8939         TAILQ_INIT(&pipeline->table_types);
8940         TAILQ_INIT(&pipeline->tables);
8941         TAILQ_INIT(&pipeline->selectors);
8942         TAILQ_INIT(&pipeline->learners);
8943         TAILQ_INIT(&pipeline->regarrays);
8944         TAILQ_INIT(&pipeline->meter_profiles);
8945         TAILQ_INIT(&pipeline->metarrays);
8946
8947         pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
8948         pipeline->numa_node = numa_node;
8949
8950         *p = pipeline;
8951         return 0;
8952 }
8953
8954 void
8955 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
8956 {
8957         void *lib;
8958
8959         if (!p)
8960                 return;
8961
8962         lib = p->lib;
8963
8964         free(p->instruction_data);
8965         free(p->instructions);
8966
8967         metarray_free(p);
8968         regarray_free(p);
8969         table_state_free(p);
8970         learner_free(p);
8971         selector_free(p);
8972         table_free(p);
8973         action_free(p);
8974         instruction_table_free(p);
8975         metadata_free(p);
8976         header_free(p);
8977         extern_func_free(p);
8978         extern_obj_free(p);
8979         port_out_free(p);
8980         port_in_free(p);
8981         struct_free(p);
8982
8983         free(p);
8984
8985         if (lib)
8986                 dlclose(lib);
8987 }
8988
8989 int
8990 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
8991                                      const char **instructions,
8992                                      uint32_t n_instructions)
8993 {
8994         int err;
8995         uint32_t i;
8996
8997         err = instruction_config(p, NULL, instructions, n_instructions);
8998         if (err)
8999                 return err;
9000
9001         /* Thread instruction pointer reset. */
9002         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
9003                 struct thread *t = &p->threads[i];
9004
9005                 thread_ip_reset(p, t);
9006         }
9007
9008         return 0;
9009 }
9010
9011 static int
9012 pipeline_compile(struct rte_swx_pipeline *p);
9013
9014 int
9015 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
9016 {
9017         int status;
9018
9019         CHECK(p, EINVAL);
9020         CHECK(p->build_done == 0, EEXIST);
9021
9022         status = port_in_build(p);
9023         if (status)
9024                 goto error;
9025
9026         status = port_out_build(p);
9027         if (status)
9028                 goto error;
9029
9030         status = struct_build(p);
9031         if (status)
9032                 goto error;
9033
9034         status = extern_obj_build(p);
9035         if (status)
9036                 goto error;
9037
9038         status = extern_func_build(p);
9039         if (status)
9040                 goto error;
9041
9042         status = header_build(p);
9043         if (status)
9044                 goto error;
9045
9046         status = metadata_build(p);
9047         if (status)
9048                 goto error;
9049
9050         status = instruction_table_build(p);
9051         if (status)
9052                 goto error;
9053
9054         status = action_build(p);
9055         if (status)
9056                 goto error;
9057
9058         status = table_build(p);
9059         if (status)
9060                 goto error;
9061
9062         status = selector_build(p);
9063         if (status)
9064                 goto error;
9065
9066         status = learner_build(p);
9067         if (status)
9068                 goto error;
9069
9070         status = table_state_build(p);
9071         if (status)
9072                 goto error;
9073
9074         status = regarray_build(p);
9075         if (status)
9076                 goto error;
9077
9078         status = metarray_build(p);
9079         if (status)
9080                 goto error;
9081
9082         p->build_done = 1;
9083
9084         pipeline_compile(p);
9085
9086         return 0;
9087
9088 error:
9089         metarray_build_free(p);
9090         regarray_build_free(p);
9091         table_state_build_free(p);
9092         learner_build_free(p);
9093         selector_build_free(p);
9094         table_build_free(p);
9095         action_build_free(p);
9096         instruction_table_build_free(p);
9097         metadata_build_free(p);
9098         header_build_free(p);
9099         extern_func_build_free(p);
9100         extern_obj_build_free(p);
9101         port_out_build_free(p);
9102         port_in_build_free(p);
9103         struct_build_free(p);
9104
9105         return status;
9106 }
9107
9108 void
9109 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions)
9110 {
9111         uint32_t i;
9112
9113         for (i = 0; i < n_instructions; i++)
9114                 instr_exec(p);
9115 }
9116
9117 void
9118 rte_swx_pipeline_flush(struct rte_swx_pipeline *p)
9119 {
9120         uint32_t i;
9121
9122         for (i = 0; i < p->n_ports_out; i++) {
9123                 struct port_out_runtime *port = &p->out[i];
9124
9125                 if (port->flush)
9126                         port->flush(port->obj);
9127         }
9128 }
9129
9130 /*
9131  * Control.
9132  */
9133 int
9134 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
9135                               struct rte_swx_ctl_pipeline_info *pipeline)
9136 {
9137         struct action *action;
9138         struct table *table;
9139         uint32_t n_actions = 0, n_tables = 0;
9140
9141         if (!p || !pipeline)
9142                 return -EINVAL;
9143
9144         TAILQ_FOREACH(action, &p->actions, node)
9145                 n_actions++;
9146
9147         TAILQ_FOREACH(table, &p->tables, node)
9148                 n_tables++;
9149
9150         pipeline->n_ports_in = p->n_ports_in;
9151         pipeline->n_ports_out = p->n_ports_out;
9152         pipeline->n_actions = n_actions;
9153         pipeline->n_tables = n_tables;
9154         pipeline->n_selectors = p->n_selectors;
9155         pipeline->n_learners = p->n_learners;
9156         pipeline->n_regarrays = p->n_regarrays;
9157         pipeline->n_metarrays = p->n_metarrays;
9158
9159         return 0;
9160 }
9161
9162 int
9163 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node)
9164 {
9165         if (!p || !numa_node)
9166                 return -EINVAL;
9167
9168         *numa_node = p->numa_node;
9169         return 0;
9170 }
9171
9172 int
9173 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p,
9174                             uint32_t action_id,
9175                             struct rte_swx_ctl_action_info *action)
9176 {
9177         struct action *a = NULL;
9178
9179         if (!p || (action_id >= p->n_actions) || !action)
9180                 return -EINVAL;
9181
9182         a = action_find_by_id(p, action_id);
9183         if (!a)
9184                 return -EINVAL;
9185
9186         strcpy(action->name, a->name);
9187         action->n_args = a->st ? a->st->n_fields : 0;
9188         return 0;
9189 }
9190
9191 int
9192 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p,
9193                                 uint32_t action_id,
9194                                 uint32_t action_arg_id,
9195                                 struct rte_swx_ctl_action_arg_info *action_arg)
9196 {
9197         struct action *a = NULL;
9198         struct field *arg = NULL;
9199
9200         if (!p || (action_id >= p->n_actions) || !action_arg)
9201                 return -EINVAL;
9202
9203         a = action_find_by_id(p, action_id);
9204         if (!a || !a->st || (action_arg_id >= a->st->n_fields))
9205                 return -EINVAL;
9206
9207         arg = &a->st->fields[action_arg_id];
9208         strcpy(action_arg->name, arg->name);
9209         action_arg->n_bits = arg->n_bits;
9210         action_arg->is_network_byte_order = a->args_endianness[action_arg_id];
9211
9212         return 0;
9213 }
9214
9215 int
9216 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p,
9217                            uint32_t table_id,
9218                            struct rte_swx_ctl_table_info *table)
9219 {
9220         struct table *t = NULL;
9221
9222         if (!p || !table)
9223                 return -EINVAL;
9224
9225         t = table_find_by_id(p, table_id);
9226         if (!t)
9227                 return -EINVAL;
9228
9229         strcpy(table->name, t->name);
9230         strcpy(table->args, t->args);
9231         table->n_match_fields = t->n_fields;
9232         table->n_actions = t->n_actions;
9233         table->default_action_is_const = t->default_action_is_const;
9234         table->size = t->size;
9235         return 0;
9236 }
9237
9238 int
9239 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p,
9240         uint32_t table_id,
9241         uint32_t match_field_id,
9242         struct rte_swx_ctl_table_match_field_info *match_field)
9243 {
9244         struct table *t;
9245         struct match_field *f;
9246
9247         if (!p || (table_id >= p->n_tables) || !match_field)
9248                 return -EINVAL;
9249
9250         t = table_find_by_id(p, table_id);
9251         if (!t || (match_field_id >= t->n_fields))
9252                 return -EINVAL;
9253
9254         f = &t->fields[match_field_id];
9255         match_field->match_type = f->match_type;
9256         match_field->is_header = t->header ? 1 : 0;
9257         match_field->n_bits = f->field->n_bits;
9258         match_field->offset = f->field->offset;
9259
9260         return 0;
9261 }
9262
9263 int
9264 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p,
9265         uint32_t table_id,
9266         uint32_t table_action_id,
9267         struct rte_swx_ctl_table_action_info *table_action)
9268 {
9269         struct table *t;
9270
9271         if (!p || (table_id >= p->n_tables) || !table_action)
9272                 return -EINVAL;
9273
9274         t = table_find_by_id(p, table_id);
9275         if (!t || (table_action_id >= t->n_actions))
9276                 return -EINVAL;
9277
9278         table_action->action_id = t->actions[table_action_id]->id;
9279
9280         return 0;
9281 }
9282
9283 int
9284 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p,
9285                           uint32_t table_id,
9286                           struct rte_swx_table_ops *table_ops,
9287                           int *is_stub)
9288 {
9289         struct table *t;
9290
9291         if (!p || (table_id >= p->n_tables))
9292                 return -EINVAL;
9293
9294         t = table_find_by_id(p, table_id);
9295         if (!t)
9296                 return -EINVAL;
9297
9298         if (t->type) {
9299                 if (table_ops)
9300                         memcpy(table_ops, &t->type->ops, sizeof(*table_ops));
9301                 *is_stub = 0;
9302         } else {
9303                 *is_stub = 1;
9304         }
9305
9306         return 0;
9307 }
9308
9309 int
9310 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p,
9311                               uint32_t selector_id,
9312                               struct rte_swx_ctl_selector_info *selector)
9313 {
9314         struct selector *s = NULL;
9315
9316         if (!p || !selector)
9317                 return -EINVAL;
9318
9319         s = selector_find_by_id(p, selector_id);
9320         if (!s)
9321                 return -EINVAL;
9322
9323         strcpy(selector->name, s->name);
9324
9325         selector->n_selector_fields = s->n_selector_fields;
9326         selector->n_groups_max = s->n_groups_max;
9327         selector->n_members_per_group_max = s->n_members_per_group_max;
9328
9329         return 0;
9330 }
9331
9332 int
9333 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p,
9334          uint32_t selector_id,
9335          struct rte_swx_ctl_table_match_field_info *field)
9336 {
9337         struct selector *s;
9338
9339         if (!p || (selector_id >= p->n_selectors) || !field)
9340                 return -EINVAL;
9341
9342         s = selector_find_by_id(p, selector_id);
9343         if (!s)
9344                 return -EINVAL;
9345
9346         field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9347         field->is_header = 0;
9348         field->n_bits = s->group_id_field->n_bits;
9349         field->offset = s->group_id_field->offset;
9350
9351         return 0;
9352 }
9353
9354 int
9355 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p,
9356          uint32_t selector_id,
9357          uint32_t selector_field_id,
9358          struct rte_swx_ctl_table_match_field_info *field)
9359 {
9360         struct selector *s;
9361         struct field *f;
9362
9363         if (!p || (selector_id >= p->n_selectors) || !field)
9364                 return -EINVAL;
9365
9366         s = selector_find_by_id(p, selector_id);
9367         if (!s || (selector_field_id >= s->n_selector_fields))
9368                 return -EINVAL;
9369
9370         f = s->selector_fields[selector_field_id];
9371         field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9372         field->is_header = s->selector_header ? 1 : 0;
9373         field->n_bits = f->n_bits;
9374         field->offset = f->offset;
9375
9376         return 0;
9377 }
9378
9379 int
9380 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p,
9381          uint32_t selector_id,
9382          struct rte_swx_ctl_table_match_field_info *field)
9383 {
9384         struct selector *s;
9385
9386         if (!p || (selector_id >= p->n_selectors) || !field)
9387                 return -EINVAL;
9388
9389         s = selector_find_by_id(p, selector_id);
9390         if (!s)
9391                 return -EINVAL;
9392
9393         field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9394         field->is_header = 0;
9395         field->n_bits = s->member_id_field->n_bits;
9396         field->offset = s->member_id_field->offset;
9397
9398         return 0;
9399 }
9400
9401 int
9402 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p,
9403                              uint32_t learner_id,
9404                              struct rte_swx_ctl_learner_info *learner)
9405 {
9406         struct learner *l = NULL;
9407
9408         if (!p || !learner)
9409                 return -EINVAL;
9410
9411         l = learner_find_by_id(p, learner_id);
9412         if (!l)
9413                 return -EINVAL;
9414
9415         strcpy(learner->name, l->name);
9416
9417         learner->n_match_fields = l->n_fields;
9418         learner->n_actions = l->n_actions;
9419         learner->default_action_is_const = l->default_action_is_const;
9420         learner->size = l->size;
9421
9422         return 0;
9423 }
9424
9425 int
9426 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p,
9427                                          uint32_t learner_id,
9428                                          uint32_t match_field_id,
9429                                          struct rte_swx_ctl_table_match_field_info *match_field)
9430 {
9431         struct learner *l;
9432         struct field *f;
9433
9434         if (!p || (learner_id >= p->n_learners) || !match_field)
9435                 return -EINVAL;
9436
9437         l = learner_find_by_id(p, learner_id);
9438         if (!l || (match_field_id >= l->n_fields))
9439                 return -EINVAL;
9440
9441         f = l->fields[match_field_id];
9442         match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9443         match_field->is_header = l->header ? 1 : 0;
9444         match_field->n_bits = f->n_bits;
9445         match_field->offset = f->offset;
9446
9447         return 0;
9448 }
9449
9450 int
9451 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p,
9452                                     uint32_t learner_id,
9453                                     uint32_t learner_action_id,
9454                                     struct rte_swx_ctl_table_action_info *learner_action)
9455 {
9456         struct learner *l;
9457
9458         if (!p || (learner_id >= p->n_learners) || !learner_action)
9459                 return -EINVAL;
9460
9461         l = learner_find_by_id(p, learner_id);
9462         if (!l || (learner_action_id >= l->n_actions))
9463                 return -EINVAL;
9464
9465         learner_action->action_id = l->actions[learner_action_id]->id;
9466
9467         return 0;
9468 }
9469
9470 int
9471 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
9472                                  struct rte_swx_table_state **table_state)
9473 {
9474         if (!p || !table_state || !p->build_done)
9475                 return -EINVAL;
9476
9477         *table_state = p->table_state;
9478         return 0;
9479 }
9480
9481 int
9482 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
9483                                  struct rte_swx_table_state *table_state)
9484 {
9485         if (!p || !table_state || !p->build_done)
9486                 return -EINVAL;
9487
9488         p->table_state = table_state;
9489         return 0;
9490 }
9491
9492 int
9493 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p,
9494                                         uint32_t port_id,
9495                                         struct rte_swx_port_in_stats *stats)
9496 {
9497         struct port_in *port;
9498
9499         if (!p || !stats)
9500                 return -EINVAL;
9501
9502         port = port_in_find(p, port_id);
9503         if (!port)
9504                 return -EINVAL;
9505
9506         port->type->ops.stats_read(port->obj, stats);
9507         return 0;
9508 }
9509
9510 int
9511 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p,
9512                                          uint32_t port_id,
9513                                          struct rte_swx_port_out_stats *stats)
9514 {
9515         struct port_out *port;
9516
9517         if (!p || !stats)
9518                 return -EINVAL;
9519
9520         port = port_out_find(p, port_id);
9521         if (!port)
9522                 return -EINVAL;
9523
9524         port->type->ops.stats_read(port->obj, stats);
9525         return 0;
9526 }
9527
9528 int
9529 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p,
9530                                       const char *table_name,
9531                                       struct rte_swx_table_stats *stats)
9532 {
9533         struct table *table;
9534         struct table_statistics *table_stats;
9535
9536         if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action)
9537                 return -EINVAL;
9538
9539         table = table_find(p, table_name);
9540         if (!table)
9541                 return -EINVAL;
9542
9543         table_stats = &p->table_stats[table->id];
9544
9545         memcpy(stats->n_pkts_action,
9546                table_stats->n_pkts_action,
9547                p->n_actions * sizeof(uint64_t));
9548
9549         stats->n_pkts_hit = table_stats->n_pkts_hit[1];
9550         stats->n_pkts_miss = table_stats->n_pkts_hit[0];
9551
9552         return 0;
9553 }
9554
9555 int
9556 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p,
9557         const char *selector_name,
9558         struct rte_swx_pipeline_selector_stats *stats)
9559 {
9560         struct selector *s;
9561
9562         if (!p || !selector_name || !selector_name[0] || !stats)
9563                 return -EINVAL;
9564
9565         s = selector_find(p, selector_name);
9566         if (!s)
9567                 return -EINVAL;
9568
9569         stats->n_pkts = p->selector_stats[s->id].n_pkts;
9570
9571         return 0;
9572 }
9573
9574 int
9575 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p,
9576                                         const char *learner_name,
9577                                         struct rte_swx_learner_stats *stats)
9578 {
9579         struct learner *l;
9580         struct learner_statistics *learner_stats;
9581
9582         if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action)
9583                 return -EINVAL;
9584
9585         l = learner_find(p, learner_name);
9586         if (!l)
9587                 return -EINVAL;
9588
9589         learner_stats = &p->learner_stats[l->id];
9590
9591         memcpy(stats->n_pkts_action,
9592                learner_stats->n_pkts_action,
9593                p->n_actions * sizeof(uint64_t));
9594
9595         stats->n_pkts_hit = learner_stats->n_pkts_hit[1];
9596         stats->n_pkts_miss = learner_stats->n_pkts_hit[0];
9597
9598         stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0];
9599         stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1];
9600
9601         stats->n_pkts_forget = learner_stats->n_pkts_forget;
9602
9603         return 0;
9604 }
9605
9606 int
9607 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,
9608                               uint32_t regarray_id,
9609                               struct rte_swx_ctl_regarray_info *regarray)
9610 {
9611         struct regarray *r;
9612
9613         if (!p || !regarray)
9614                 return -EINVAL;
9615
9616         r = regarray_find_by_id(p, regarray_id);
9617         if (!r)
9618                 return -EINVAL;
9619
9620         strcpy(regarray->name, r->name);
9621         regarray->size = r->size;
9622         return 0;
9623 }
9624
9625 int
9626 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,
9627                                    const char *regarray_name,
9628                                    uint32_t regarray_index,
9629                                    uint64_t *value)
9630 {
9631         struct regarray *regarray;
9632         struct regarray_runtime *r;
9633
9634         if (!p || !regarray_name || !value)
9635                 return -EINVAL;
9636
9637         regarray = regarray_find(p, regarray_name);
9638         if (!regarray || (regarray_index >= regarray->size))
9639                 return -EINVAL;
9640
9641         r = &p->regarray_runtime[regarray->id];
9642         *value = r->regarray[regarray_index];
9643         return 0;
9644 }
9645
9646 int
9647 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,
9648                                    const char *regarray_name,
9649                                    uint32_t regarray_index,
9650                                    uint64_t value)
9651 {
9652         struct regarray *regarray;
9653         struct regarray_runtime *r;
9654
9655         if (!p || !regarray_name)
9656                 return -EINVAL;
9657
9658         regarray = regarray_find(p, regarray_name);
9659         if (!regarray || (regarray_index >= regarray->size))
9660                 return -EINVAL;
9661
9662         r = &p->regarray_runtime[regarray->id];
9663         r->regarray[regarray_index] = value;
9664         return 0;
9665 }
9666
9667 int
9668 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p,
9669                               uint32_t metarray_id,
9670                               struct rte_swx_ctl_metarray_info *metarray)
9671 {
9672         struct metarray *m;
9673
9674         if (!p || !metarray)
9675                 return -EINVAL;
9676
9677         m = metarray_find_by_id(p, metarray_id);
9678         if (!m)
9679                 return -EINVAL;
9680
9681         strcpy(metarray->name, m->name);
9682         metarray->size = m->size;
9683         return 0;
9684 }
9685
9686 int
9687 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p,
9688                               const char *name,
9689                               struct rte_meter_trtcm_params *params)
9690 {
9691         struct meter_profile *mp;
9692         int status;
9693
9694         CHECK(p, EINVAL);
9695         CHECK_NAME(name, EINVAL);
9696         CHECK(params, EINVAL);
9697         CHECK(!meter_profile_find(p, name), EEXIST);
9698
9699         /* Node allocation. */
9700         mp = calloc(1, sizeof(struct meter_profile));
9701         CHECK(mp, ENOMEM);
9702
9703         /* Node initialization. */
9704         strcpy(mp->name, name);
9705         memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params));
9706         status = rte_meter_trtcm_profile_config(&mp->profile, params);
9707         if (status) {
9708                 free(mp);
9709                 CHECK(0, EINVAL);
9710         }
9711
9712         /* Node add to tailq. */
9713         TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node);
9714
9715         return 0;
9716 }
9717
9718 int
9719 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p,
9720                                  const char *name)
9721 {
9722         struct meter_profile *mp;
9723
9724         CHECK(p, EINVAL);
9725         CHECK_NAME(name, EINVAL);
9726
9727         mp = meter_profile_find(p, name);
9728         CHECK(mp, EINVAL);
9729         CHECK(!mp->n_users, EBUSY);
9730
9731         /* Remove node from tailq. */
9732         TAILQ_REMOVE(&p->meter_profiles, mp, node);
9733         free(mp);
9734
9735         return 0;
9736 }
9737
9738 int
9739 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p,
9740                         const char *metarray_name,
9741                         uint32_t metarray_index)
9742 {
9743         struct meter_profile *mp_old;
9744         struct metarray *metarray;
9745         struct metarray_runtime *metarray_runtime;
9746         struct meter *m;
9747
9748         CHECK(p, EINVAL);
9749         CHECK_NAME(metarray_name, EINVAL);
9750
9751         metarray = metarray_find(p, metarray_name);
9752         CHECK(metarray, EINVAL);
9753         CHECK(metarray_index < metarray->size, EINVAL);
9754
9755         metarray_runtime = &p->metarray_runtime[metarray->id];
9756         m = &metarray_runtime->metarray[metarray_index];
9757         mp_old = m->profile;
9758
9759         meter_init(m);
9760
9761         mp_old->n_users--;
9762
9763         return 0;
9764 }
9765
9766 int
9767 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p,
9768                       const char *metarray_name,
9769                       uint32_t metarray_index,
9770                       const char *profile_name)
9771 {
9772         struct meter_profile *mp, *mp_old;
9773         struct metarray *metarray;
9774         struct metarray_runtime *metarray_runtime;
9775         struct meter *m;
9776
9777         CHECK(p, EINVAL);
9778         CHECK_NAME(metarray_name, EINVAL);
9779
9780         metarray = metarray_find(p, metarray_name);
9781         CHECK(metarray, EINVAL);
9782         CHECK(metarray_index < metarray->size, EINVAL);
9783
9784         mp = meter_profile_find(p, profile_name);
9785         CHECK(mp, EINVAL);
9786
9787         metarray_runtime = &p->metarray_runtime[metarray->id];
9788         m = &metarray_runtime->metarray[metarray_index];
9789         mp_old = m->profile;
9790
9791         memset(m, 0, sizeof(struct meter));
9792         rte_meter_trtcm_config(&m->m, &mp->profile);
9793         m->profile = mp;
9794         m->color_mask = RTE_COLORS;
9795
9796         mp->n_users++;
9797         mp_old->n_users--;
9798
9799         return 0;
9800 }
9801
9802 int
9803 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p,
9804                              const char *metarray_name,
9805                              uint32_t metarray_index,
9806                              struct rte_swx_ctl_meter_stats *stats)
9807 {
9808         struct metarray *metarray;
9809         struct metarray_runtime *metarray_runtime;
9810         struct meter *m;
9811
9812         CHECK(p, EINVAL);
9813         CHECK_NAME(metarray_name, EINVAL);
9814
9815         metarray = metarray_find(p, metarray_name);
9816         CHECK(metarray, EINVAL);
9817         CHECK(metarray_index < metarray->size, EINVAL);
9818
9819         CHECK(stats, EINVAL);
9820
9821         metarray_runtime = &p->metarray_runtime[metarray->id];
9822         m = &metarray_runtime->metarray[metarray_index];
9823
9824         memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts));
9825         memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes));
9826
9827         return 0;
9828 }
9829
9830 /*
9831  * Pipeline compilation.
9832  */
9833 static const char *
9834 instr_type_to_name(struct instruction *instr)
9835 {
9836         switch (instr->type) {
9837         case INSTR_RX: return "INSTR_RX";
9838
9839         case INSTR_TX: return "INSTR_TX";
9840         case INSTR_TX_I: return "INSTR_TX_I";
9841
9842         case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT";
9843         case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2";
9844         case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3";
9845         case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4";
9846         case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5";
9847         case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6";
9848         case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7";
9849         case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8";
9850
9851         case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M";
9852
9853         case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD";
9854
9855         case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT";
9856         case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX";
9857         case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX";
9858         case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX";
9859         case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX";
9860         case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX";
9861         case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX";
9862         case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX";
9863         case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX";
9864
9865         case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE";
9866         case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE";
9867
9868         case INSTR_MOV: return "INSTR_MOV";
9869         case INSTR_MOV_MH: return "INSTR_MOV_MH";
9870         case INSTR_MOV_HM: return "INSTR_MOV_HM";
9871         case INSTR_MOV_HH: return "INSTR_MOV_HH";
9872         case INSTR_MOV_I: return "INSTR_MOV_I";
9873
9874         case INSTR_DMA_HT: return "INSTR_DMA_HT";
9875         case INSTR_DMA_HT2: return "INSTR_DMA_HT2";
9876         case INSTR_DMA_HT3: return "INSTR_DMA_HT3";
9877         case INSTR_DMA_HT4: return "INSTR_DMA_HT4";
9878         case INSTR_DMA_HT5: return "INSTR_DMA_HT5";
9879         case INSTR_DMA_HT6: return "INSTR_DMA_HT6";
9880         case INSTR_DMA_HT7: return "INSTR_DMA_HT7";
9881         case INSTR_DMA_HT8: return "INSTR_DMA_HT8";
9882
9883         case INSTR_ALU_ADD: return "INSTR_ALU_ADD";
9884         case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH";
9885         case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM";
9886         case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH";
9887         case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI";
9888         case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI";
9889
9890         case INSTR_ALU_SUB: return "INSTR_ALU_SUB";
9891         case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH";
9892         case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM";
9893         case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH";
9894         case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI";
9895         case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI";
9896
9897         case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD";
9898         case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20";
9899         case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT";
9900         case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD";
9901
9902         case INSTR_ALU_AND: return "INSTR_ALU_AND";
9903         case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH";
9904         case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM";
9905         case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH";
9906         case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I";
9907
9908         case INSTR_ALU_OR: return "INSTR_ALU_OR";
9909         case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH";
9910         case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM";
9911         case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH";
9912         case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I";
9913
9914         case INSTR_ALU_XOR: return "INSTR_ALU_XOR";
9915         case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH";
9916         case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM";
9917         case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH";
9918         case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I";
9919
9920         case INSTR_ALU_SHL: return "INSTR_ALU_SHL";
9921         case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH";
9922         case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM";
9923         case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH";
9924         case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI";
9925         case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI";
9926
9927         case INSTR_ALU_SHR: return "INSTR_ALU_SHR";
9928         case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH";
9929         case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM";
9930         case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH";
9931         case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI";
9932         case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI";
9933
9934         case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH";
9935         case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM";
9936         case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI";
9937
9938         case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH";
9939         case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM";
9940         case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI";
9941         case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH";
9942         case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM";
9943         case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI";
9944
9945         case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH";
9946         case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM";
9947         case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI";
9948         case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH";
9949         case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM";
9950         case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI";
9951         case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH";
9952         case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM";
9953         case INSTR_REGWR_RII: return "INSTR_REGWR_RII";
9954
9955         case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH";
9956         case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM";
9957         case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI";
9958         case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH";
9959         case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM";
9960         case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI";
9961         case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH";
9962         case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM";
9963         case INSTR_REGADD_RII: return "INSTR_REGADD_RII";
9964
9965         case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H";
9966         case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M";
9967         case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I";
9968
9969         case INSTR_METER_HHM: return "INSTR_METER_HHM";
9970         case INSTR_METER_HHI: return "INSTR_METER_HHI";
9971         case INSTR_METER_HMM: return "INSTR_METER_HMM";
9972         case INSTR_METER_HMI: return "INSTR_METER_HMI";
9973         case INSTR_METER_MHM: return "INSTR_METER_MHM";
9974         case INSTR_METER_MHI: return "INSTR_METER_MHI";
9975         case INSTR_METER_MMM: return "INSTR_METER_MMM";
9976         case INSTR_METER_MMI: return "INSTR_METER_MMI";
9977         case INSTR_METER_IHM: return "INSTR_METER_IHM";
9978         case INSTR_METER_IHI: return "INSTR_METER_IHI";
9979         case INSTR_METER_IMM: return "INSTR_METER_IMM";
9980         case INSTR_METER_IMI: return "INSTR_METER_IMI";
9981
9982         case INSTR_TABLE: return "INSTR_TABLE";
9983         case INSTR_TABLE_AF: return "INSTR_TABLE_AF";
9984         case INSTR_SELECTOR: return "INSTR_SELECTOR";
9985         case INSTR_LEARNER: return "INSTR_LEARNER";
9986         case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF";
9987
9988         case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN";
9989         case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET";
9990
9991         case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ";
9992         case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC";
9993
9994         case INSTR_JMP: return "INSTR_JMP";
9995         case INSTR_JMP_VALID: return "INSTR_JMP_VALID";
9996         case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID";
9997         case INSTR_JMP_HIT: return "INSTR_JMP_HIT";
9998         case INSTR_JMP_MISS: return "INSTR_JMP_MISS";
9999         case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT";
10000         case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS";
10001         case INSTR_JMP_EQ: return "INSTR_JMP_EQ";
10002         case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH";
10003         case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM";
10004         case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH";
10005         case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I";
10006         case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ";
10007         case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH";
10008         case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM";
10009         case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH";
10010         case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I";
10011         case INSTR_JMP_LT: return "INSTR_JMP_LT";
10012         case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH";
10013         case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM";
10014         case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH";
10015         case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI";
10016         case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI";
10017         case INSTR_JMP_GT: return "INSTR_JMP_GT";
10018         case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH";
10019         case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM";
10020         case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH";
10021         case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI";
10022         case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI";
10023
10024         case INSTR_RETURN: return "INSTR_RETURN";
10025
10026         default: return "INSTR_UNKNOWN";
10027         }
10028 }
10029
10030 typedef void
10031 (*instruction_export_t)(struct instruction *, FILE *);
10032
10033 static void
10034 instr_io_export(struct instruction *instr, FILE *f)
10035 {
10036         uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i;
10037
10038         /* n_io, n_io_imm, n_hdrs. */
10039         if (instr->type == INSTR_RX ||
10040             instr->type == INSTR_TX ||
10041             instr->type == INSTR_HDR_EXTRACT_M ||
10042             (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX))
10043                 n_io = 1;
10044
10045         if (instr->type == INSTR_TX_I)
10046                 n_io_imm = 1;
10047
10048         if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8)
10049                 n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT);
10050
10051         if (instr->type == INSTR_HDR_EXTRACT_M ||
10052             instr->type == INSTR_HDR_LOOKAHEAD ||
10053             instr->type == INSTR_HDR_EMIT)
10054                 n_hdrs = 1;
10055
10056         if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)
10057                 n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX);
10058
10059         /* instr. */
10060         fprintf(f,
10061                 "\t{\n"
10062                 "\t\t.type = %s,\n",
10063                 instr_type_to_name(instr));
10064
10065         /* instr.io. */
10066         fprintf(f,
10067                 "\t\t.io = {\n");
10068
10069         /* instr.io.io. */
10070         if (n_io)
10071                 fprintf(f,
10072                         "\t\t\t.io = {\n"
10073                         "\t\t\t\t.offset = %u,\n"
10074                         "\t\t\t\t.n_bits = %u,\n"
10075                         "\t\t\t},\n",
10076                         instr->io.io.offset,
10077                         instr->io.io.n_bits);
10078
10079         if (n_io_imm)
10080                 fprintf(f,
10081                         "\t\t\t.io = {\n"
10082                         "\t\t\t\t.val = %u,\n"
10083                         "\t\t\t},\n",
10084                         instr->io.io.val);
10085
10086         /* instr.io.hdr. */
10087         if (n_hdrs) {
10088                 fprintf(f,
10089                         "\t\t.hdr = {\n");
10090
10091                 /* instr.io.hdr.header_id. */
10092                 fprintf(f,
10093                         "\t\t\t.header_id = {");
10094
10095                 for (i = 0; i < n_hdrs; i++)
10096                         fprintf(f,
10097                                 "%u, ",
10098                                 instr->io.hdr.header_id[i]);
10099
10100                 fprintf(f,
10101                         "},\n");
10102
10103                 /* instr.io.hdr.struct_id. */
10104                 fprintf(f,
10105                         "\t\t\t.struct_id = {");
10106
10107                 for (i = 0; i < n_hdrs; i++)
10108                         fprintf(f,
10109                                 "%u, ",
10110                                 instr->io.hdr.struct_id[i]);
10111
10112                 fprintf(f,
10113                         "},\n");
10114
10115                 /* instr.io.hdr.n_bytes. */
10116                 fprintf(f,
10117                         "\t\t\t.n_bytes = {");
10118
10119                 for (i = 0; i < n_hdrs; i++)
10120                         fprintf(f,
10121                                 "%u, ",
10122                                 instr->io.hdr.n_bytes[i]);
10123
10124                 fprintf(f,
10125                         "},\n");
10126
10127                 /* instr.io.hdr - closing curly brace. */
10128                 fprintf(f,
10129                         "\t\t\t}\n,");
10130         }
10131
10132         /* instr.io - closing curly brace. */
10133         fprintf(f,
10134                 "\t\t},\n");
10135
10136         /* instr - closing curly brace. */
10137         fprintf(f,
10138                 "\t},\n");
10139 }
10140
10141 static void
10142 instr_hdr_validate_export(struct instruction *instr, FILE *f)
10143 {
10144         fprintf(f,
10145                 "\t{\n"
10146                 "\t\t.type = %s,\n"
10147                 "\t\t.valid = {\n"
10148                 "\t\t\t.header_id = %u,\n"
10149                 "\t\t},\n"
10150                 "\t},\n",
10151                 instr_type_to_name(instr),
10152                 instr->valid.header_id);
10153 }
10154
10155 static void
10156 instr_mov_export(struct instruction *instr, FILE *f)
10157 {
10158         if (instr->type != INSTR_MOV_I)
10159                 fprintf(f,
10160                         "\t{\n"
10161                         "\t\t.type = %s,\n"
10162                         "\t\t.mov = {\n"
10163                         "\t\t\t.dst = {\n"
10164                         "\t\t\t\t.struct_id = %u,\n"
10165                         "\t\t\t\t.n_bits = %u,\n"
10166                         "\t\t\t\t.offset = %u,\n"
10167                         "\t\t\t},\n"
10168                         "\t\t\t.src = {\n"
10169                         "\t\t\t\t.struct_id = %u,\n"
10170                         "\t\t\t\t.n_bits = %u,\n"
10171                         "\t\t\t\t.offset = %u,\n"
10172                         "\t\t\t},\n"
10173                         "\t\t},\n"
10174                         "\t},\n",
10175                         instr_type_to_name(instr),
10176                         instr->mov.dst.struct_id,
10177                         instr->mov.dst.n_bits,
10178                         instr->mov.dst.offset,
10179                         instr->mov.src.struct_id,
10180                         instr->mov.src.n_bits,
10181                         instr->mov.src.offset);
10182         else
10183                 fprintf(f,
10184                         "\t{\n"
10185                         "\t\t.type = %s,\n"
10186                         "\t\t.mov = {\n"
10187                         "\t\t\t.dst = {\n"
10188                         "\t\t\t\t.struct_id = %u,\n"
10189                         "\t\t\t\t.n_bits = %u,\n"
10190                         "\t\t\t\t.offset = %u,\n"
10191                         "\t\t\t}\n,"
10192                         "\t\t\t.src_val = %" PRIu64 ",\n"
10193                         "\t\t},\n"
10194                         "\t},\n",
10195                         instr_type_to_name(instr),
10196                         instr->mov.dst.struct_id,
10197                         instr->mov.dst.n_bits,
10198                         instr->mov.dst.offset,
10199                         instr->mov.src_val);
10200 }
10201
10202 static void
10203 instr_dma_ht_export(struct instruction *instr, FILE *f)
10204 {
10205         uint32_t n_dma = 0, i;
10206
10207         /* n_dma. */
10208         n_dma = 1 + (instr->type - INSTR_DMA_HT);
10209
10210         /* instr. */
10211         fprintf(f,
10212                 "\t{\n"
10213                 "\t\t.type = %s,\n",
10214                 instr_type_to_name(instr));
10215
10216         /* instr.dma. */
10217         fprintf(f,
10218                 "\t\t.dma = {\n");
10219
10220         /* instr.dma.dst. */
10221         fprintf(f,
10222                 "\t\t\t.dst = {\n");
10223
10224         /* instr.dma.dst.header_id. */
10225         fprintf(f,
10226                 "\t\t\t\t.header_id = {");
10227
10228         for (i = 0; i < n_dma; i++)
10229                 fprintf(f,
10230                         "%u, ",
10231                         instr->dma.dst.header_id[i]);
10232
10233         fprintf(f,
10234                 "},\n");
10235
10236         /* instr.dma.dst.struct_id. */
10237         fprintf(f,
10238                 "\t\t\t\t.struct_id = {");
10239
10240         for (i = 0; i < n_dma; i++)
10241                 fprintf(f,
10242                         "%u, ",
10243                         instr->dma.dst.struct_id[i]);
10244
10245         fprintf(f,
10246                 "},\n");
10247
10248         /* instr.dma.dst - closing curly brace. */
10249         fprintf(f,
10250                 "\t\t\t},\n");
10251
10252         /* instr.dma.src. */
10253         fprintf(f,
10254                 "\t\t\t.src = {\n");
10255
10256         /* instr.dma.src.offset. */
10257         fprintf(f,
10258                 "\t\t\t\t.offset = {");
10259
10260         for (i = 0; i < n_dma; i++)
10261                 fprintf(f,
10262                         "%u, ",
10263                         instr->dma.src.offset[i]);
10264
10265         fprintf(f,
10266                 "},\n");
10267
10268         /* instr.dma.src - closing curly brace. */
10269         fprintf(f,
10270                 "\t\t\t},\n");
10271
10272         /* instr.dma.n_bytes. */
10273         fprintf(f,
10274                 "\t\t\t.n_bytes = {");
10275
10276         for (i = 0; i < n_dma; i++)
10277                 fprintf(f,
10278                         "%u, ",
10279                         instr->dma.n_bytes[i]);
10280
10281         fprintf(f,
10282                 "},\n");
10283
10284         /* instr.dma - closing curly brace. */
10285         fprintf(f,
10286                 "\t\t},\n");
10287
10288         /* instr - closing curly brace. */
10289         fprintf(f,
10290                 "\t},\n");
10291 }
10292
10293 static void
10294 instr_alu_export(struct instruction *instr, FILE *f)
10295 {
10296         int imm = 0;
10297
10298         if (instr->type == INSTR_ALU_ADD_MI ||
10299             instr->type == INSTR_ALU_ADD_HI ||
10300             instr->type == INSTR_ALU_SUB_MI ||
10301             instr->type == INSTR_ALU_SUB_HI ||
10302             instr->type == INSTR_ALU_SHL_MI ||
10303             instr->type == INSTR_ALU_SHL_HI ||
10304             instr->type == INSTR_ALU_SHR_MI ||
10305             instr->type == INSTR_ALU_SHR_HI ||
10306             instr->type == INSTR_ALU_AND_I ||
10307             instr->type == INSTR_ALU_OR_I ||
10308             instr->type == INSTR_ALU_XOR_I)
10309                 imm = 1;
10310
10311         if (!imm)
10312                 fprintf(f,
10313                         "\t{\n"
10314                         "\t\t.type = %s,\n"
10315                         "\t\t.alu = {\n"
10316                         "\t\t\t.dst = {\n"
10317                         "\t\t\t\t.struct_id = %u,\n"
10318                         "\t\t\t\t.n_bits = %u,\n"
10319                         "\t\t\t\t.offset = %u,\n"
10320                         "\t\t\t},\n"
10321                         "\t\t\t.src = {\n"
10322                         "\t\t\t\t.struct_id = %u,\n"
10323                         "\t\t\t\t.n_bits = %u,\n"
10324                         "\t\t\t\t.offset = %u,\n"
10325                         "\t\t\t},\n"
10326                         "\t\t},\n"
10327                         "\t},\n",
10328                         instr_type_to_name(instr),
10329                         instr->alu.dst.struct_id,
10330                         instr->alu.dst.n_bits,
10331                         instr->alu.dst.offset,
10332                         instr->alu.src.struct_id,
10333                         instr->alu.src.n_bits,
10334                         instr->alu.src.offset);
10335         else
10336                 fprintf(f,
10337                         "\t{\n"
10338                         "\t\t.type = %s,\n"
10339                         "\t\t.alu = {\n"
10340                         "\t\t\t.dst = {\n"
10341                         "\t\t\t\t.struct_id = %u,\n"
10342                         "\t\t\t\t.n_bits = %u,\n"
10343                         "\t\t\t\t.offset = %u,\n"
10344                         "\t\t\t}\n,"
10345                         "\t\t\t.src_val = %" PRIu64 ",\n"
10346                         "\t\t},\n"
10347                         "\t},\n",
10348                         instr_type_to_name(instr),
10349                         instr->alu.dst.struct_id,
10350                         instr->alu.dst.n_bits,
10351                         instr->alu.dst.offset,
10352                         instr->alu.src_val);
10353 }
10354
10355 static void
10356 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused)
10357 {
10358         int prefetch  = 0, idx_imm = 0, src_imm = 0;
10359
10360         if (instr->type == INSTR_REGPREFETCH_RH ||
10361             instr->type == INSTR_REGPREFETCH_RM ||
10362             instr->type == INSTR_REGPREFETCH_RI)
10363                 prefetch = 1;
10364
10365         /* index is the 3rd operand for the regrd instruction and the 2nd
10366          * operand for the regwr and regadd instructions.
10367          */
10368         if (instr->type == INSTR_REGPREFETCH_RI ||
10369             instr->type == INSTR_REGRD_HRI ||
10370             instr->type == INSTR_REGRD_MRI ||
10371             instr->type == INSTR_REGWR_RIH ||
10372             instr->type == INSTR_REGWR_RIM ||
10373             instr->type == INSTR_REGWR_RII ||
10374             instr->type == INSTR_REGADD_RIH ||
10375             instr->type == INSTR_REGADD_RIM ||
10376             instr->type == INSTR_REGADD_RII)
10377                 idx_imm = 1;
10378
10379         /* src is the 3rd operand for the regwr and regadd instructions. */
10380         if (instr->type == INSTR_REGWR_RHI ||
10381             instr->type == INSTR_REGWR_RMI ||
10382             instr->type == INSTR_REGWR_RII ||
10383             instr->type == INSTR_REGADD_RHI ||
10384             instr->type == INSTR_REGADD_RMI ||
10385             instr->type == INSTR_REGADD_RII)
10386                 src_imm = 1;
10387
10388         /* instr.regarray.regarray_id. */
10389         fprintf(f,
10390                 "\t{\n"
10391                 "\t\t.type = %s,\n"
10392                 "\t\t.regarray = {\n"
10393                 "\t\t\t.regarray_id = %u,\n",
10394                 instr_type_to_name(instr),
10395                 instr->regarray.regarray_id);
10396
10397         /* instr.regarray.idx / instr.regarray.idx_val. */
10398         if (!idx_imm)
10399                 fprintf(f,
10400                         "\t\t\t\t.idx = {\n"
10401                         "\t\t\t\t\t.struct_id = %u,\n"
10402                         "\t\t\t\t\t.n_bits = %u,\n"
10403                         "\t\t\t\t\t.offset = %u,\n"
10404                         "\t\t\t\t},\n",
10405                         instr->regarray.idx.struct_id,
10406                         instr->regarray.idx.n_bits,
10407                         instr->regarray.idx.offset);
10408         else
10409                 fprintf(f,
10410                         "\t\t\t\t.idx_val = %u,\n",
10411                         instr->regarray.idx_val);
10412
10413         /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */
10414         if (!prefetch) {
10415                 if (!src_imm)
10416                         fprintf(f,
10417                                 "\t\t\t\t.dstsrc = {\n"
10418                                 "\t\t\t\t\t.struct_id = %u,\n"
10419                                 "\t\t\t\t\t.n_bits = %u,\n"
10420                                 "\t\t\t\t\t.offset = %u,\n"
10421                                 "\t\t\t\t},\n",
10422                                 instr->regarray.dstsrc.struct_id,
10423                                 instr->regarray.dstsrc.n_bits,
10424                                 instr->regarray.dstsrc.offset);
10425                 else
10426                         fprintf(f,
10427                                 "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n",
10428                                 instr->regarray.dstsrc_val);
10429         }
10430
10431         /* instr.regarray and instr - closing curly braces. */
10432         fprintf(f,
10433                 "\t\t},\n"
10434                 "\t},\n");
10435 }
10436
10437 static void
10438 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused)
10439 {
10440         int prefetch  = 0, idx_imm = 0, color_in_imm = 0;
10441
10442         if (instr->type == INSTR_METPREFETCH_H ||
10443             instr->type == INSTR_METPREFETCH_M ||
10444             instr->type == INSTR_METPREFETCH_I)
10445                 prefetch = 1;
10446
10447         /* idx_imm. */
10448         if (instr->type == INSTR_METPREFETCH_I ||
10449             instr->type == INSTR_METER_IHM ||
10450             instr->type == INSTR_METER_IHI ||
10451             instr->type == INSTR_METER_IMM ||
10452             instr->type == INSTR_METER_IMI)
10453                 idx_imm = 1;
10454
10455         /* color_in_imm. */
10456         if (instr->type == INSTR_METER_HHI ||
10457             instr->type == INSTR_METER_HMI ||
10458             instr->type == INSTR_METER_MHI ||
10459             instr->type == INSTR_METER_MMI ||
10460             instr->type == INSTR_METER_IHI ||
10461             instr->type == INSTR_METER_IMI)
10462                 color_in_imm = 1;
10463
10464         /* instr.meter.metarray_id. */
10465         fprintf(f,
10466                 "\t{\n"
10467                 "\t\t.type = %s,\n"
10468                 "\t\t.meter = {\n"
10469                 "\t\t\t.metarray_id = %u,\n",
10470                 instr_type_to_name(instr),
10471                 instr->meter.metarray_id);
10472
10473         /* instr.meter.idx / instr.meter.idx_val. */
10474         if (!idx_imm)
10475                 fprintf(f,
10476                         "\t\t\t.idx = {\n"
10477                         "\t\t\t\t.struct_id = %u,\n"
10478                         "\t\t\t\t.n_bits = %u,\n"
10479                         "\t\t\t\t.offset = %u,\n"
10480                         "\t\t\t},\n",
10481                         instr->meter.idx.struct_id,
10482                         instr->meter.idx.n_bits,
10483                         instr->meter.idx.offset);
10484         else
10485                 fprintf(f,
10486                         "\t\t\t.idx_val = %u,\n",
10487                         instr->meter.idx_val);
10488
10489         if (!prefetch) {
10490                 /* instr.meter.length. */
10491                 fprintf(f,
10492                         "\t\t\t.length = {\n"
10493                         "\t\t\t\t.struct_id = %u,\n"
10494                         "\t\t\t\t.n_bits = %u,\n"
10495                         "\t\t\t\t.offset = %u,\n"
10496                         "\t\t\t},\n",
10497                         instr->meter.length.struct_id,
10498                         instr->meter.length.n_bits,
10499                         instr->meter.length.offset);
10500
10501                 /* instr.meter.color_in / instr.meter.color_in_val. */
10502                 if (!color_in_imm)
10503                         fprintf(f,
10504                                 "\t\t\t.color_in = {\n"
10505                                 "\t\t\t\t.struct_id = %u,\n"
10506                                 "\t\t\t\t.n_bits = %u,\n"
10507                                 "\t\t\t\t.offset = %u,\n"
10508                                 "\t\t\t},\n",
10509                                 instr->meter.color_in.struct_id,
10510                                 instr->meter.color_in.n_bits,
10511                                 instr->meter.color_in.offset);
10512                 else
10513                         fprintf(f,
10514                                 "\t\t\t.color_in_val = %u,\n",
10515                                 (uint32_t)instr->meter.color_in_val);
10516
10517                 /* instr.meter.color_out. */
10518                 fprintf(f,
10519                         "\t\t\t.color_out = {\n"
10520                         "\t\t\t\t.struct_id = %u,\n"
10521                         "\t\t\t\t.n_bits = %u,\n"
10522                         "\t\t\t\t.offset = %u,\n"
10523                         "\t\t\t},\n",
10524                         instr->meter.color_out.struct_id,
10525                         instr->meter.color_out.n_bits,
10526                         instr->meter.color_out.offset);
10527         }
10528
10529         /* instr.meter and instr - closing curly braces. */
10530         fprintf(f,
10531                 "\t\t},\n"
10532                 "\t},\n");
10533 }
10534
10535 static void
10536 instr_table_export(struct instruction *instr,
10537                 FILE *f)
10538 {
10539         fprintf(f,
10540                 "\t{\n"
10541                 "\t\t.type = %s,\n"
10542                 "\t\t.table = {\n"
10543                 "\t\t\t.table_id = %u,\n"
10544                 "\t\t},\n"
10545                 "\t},\n",
10546                 instr_type_to_name(instr),
10547                 instr->table.table_id);
10548 }
10549
10550 static void
10551 instr_learn_export(struct instruction *instr, FILE *f)
10552 {
10553         fprintf(f,
10554                 "\t{\n"
10555                 "\t\t.type = %s,\n"
10556                 "\t\t.learn = {\n"
10557                 "\t\t\t\t.action_id = %u,\n"
10558                 "\t\t},\n"
10559                 "\t},\n",
10560                 instr_type_to_name(instr),
10561                 instr->learn.action_id);
10562 }
10563
10564 static void
10565 instr_forget_export(struct instruction *instr, FILE *f)
10566 {
10567         fprintf(f,
10568                 "\t{\n"
10569                 "\t\t.type = %s,\n"
10570                 "\t},\n",
10571                 instr_type_to_name(instr));
10572 }
10573
10574 static void
10575 instr_extern_export(struct instruction *instr, FILE *f)
10576 {
10577         if (instr->type == INSTR_EXTERN_OBJ)
10578                 fprintf(f,
10579                         "\t{\n"
10580                         "\t\t.type = %s,\n"
10581                         "\t\t.ext_obj = {\n"
10582                         "\t\t\t.ext_obj_id = %u,\n"
10583                         "\t\t\t.func_id = %u,\n"
10584                         "\t\t},\n"
10585                         "\t},\n",
10586                         instr_type_to_name(instr),
10587                         instr->ext_obj.ext_obj_id,
10588                         instr->ext_obj.func_id);
10589         else
10590                 fprintf(f,
10591                         "\t{\n"
10592                         "\t\t.type = %s,\n"
10593                         "\t\t.ext_func = {\n"
10594                         "\t\t\t.ext_func_id = %u,\n"
10595                         "\t\t},\n"
10596                         "\t},\n",
10597                         instr_type_to_name(instr),
10598                         instr->ext_func.ext_func_id);
10599 }
10600
10601 static void
10602 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused)
10603 {
10604         fprintf(f,
10605                 "\t{\n"
10606                 "\t\t.type = %s,\n"
10607                 "\t\t.jmp = {\n"
10608                 "\t\t\t.ip = NULL,\n",
10609                 instr_type_to_name(instr));
10610
10611         switch (instr->type) {
10612         case INSTR_JMP_VALID:
10613         case INSTR_JMP_INVALID:
10614                 fprintf(f,
10615                         "\t\t\t.header_id = %u,\n",
10616                         instr->jmp.header_id);
10617                 break;
10618
10619         case INSTR_JMP_ACTION_HIT:
10620         case INSTR_JMP_ACTION_MISS:
10621                 fprintf(f,
10622                         "\t\t\t.action_id = %u,\n",
10623                         instr->jmp.action_id);
10624                 break;
10625
10626         case INSTR_JMP_EQ:
10627         case INSTR_JMP_EQ_MH:
10628         case INSTR_JMP_EQ_HM:
10629         case INSTR_JMP_EQ_HH:
10630         case INSTR_JMP_NEQ:
10631         case INSTR_JMP_NEQ_MH:
10632         case INSTR_JMP_NEQ_HM:
10633         case INSTR_JMP_NEQ_HH:
10634         case INSTR_JMP_LT:
10635         case INSTR_JMP_LT_MH:
10636         case INSTR_JMP_LT_HM:
10637         case INSTR_JMP_LT_HH:
10638         case INSTR_JMP_GT:
10639         case INSTR_JMP_GT_MH:
10640         case INSTR_JMP_GT_HM:
10641         case INSTR_JMP_GT_HH:
10642                 fprintf(f,
10643                         "\t\t\t.a = {\n"
10644                         "\t\t\t\t.struct_id = %u,\n"
10645                         "\t\t\t\t.n_bits = %u,\n"
10646                         "\t\t\t\t.offset = %u,\n"
10647                         "\t\t\t},\n"
10648                         "\t\t\t.b = {\n"
10649                         "\t\t\t\t.struct_id = %u,\n"
10650                         "\t\t\t\t.n_bits = %u,\n"
10651                         "\t\t\t\t.offset = %u,\n"
10652                         "\t\t\t},\n",
10653                         instr->jmp.a.struct_id,
10654                         instr->jmp.a.n_bits,
10655                         instr->jmp.a.offset,
10656                         instr->jmp.b.struct_id,
10657                         instr->jmp.b.n_bits,
10658                         instr->jmp.b.offset);
10659                 break;
10660
10661         case INSTR_JMP_EQ_I:
10662         case INSTR_JMP_NEQ_I:
10663         case INSTR_JMP_LT_MI:
10664         case INSTR_JMP_LT_HI:
10665         case INSTR_JMP_GT_MI:
10666         case INSTR_JMP_GT_HI:
10667                 fprintf(f,
10668                         "\t\t\t.a = {\n"
10669                         "\t\t\t\t.struct_id = %u,\n"
10670                         "\t\t\t\t.n_bits = %u,\n"
10671                         "\t\t\t\t.offset = %u,\n"
10672                         "\t\t\t}\n,"
10673                         "\t\t\t.b_val = %" PRIu64 ",\n",
10674                         instr->jmp.a.struct_id,
10675                         instr->jmp.a.n_bits,
10676                         instr->jmp.a.offset,
10677                         instr->jmp.b_val);
10678                 break;
10679
10680         default:
10681                 break;
10682         }
10683
10684         fprintf(f,
10685                 "\t\t},\n"
10686                 "\t},\n");
10687 }
10688
10689 static void
10690 instr_return_export(struct instruction *instr,
10691                 FILE *f)
10692 {
10693         fprintf(f,
10694                 "\t{\n"
10695                 "\t\t.type = %s,\n",
10696                 instr_type_to_name(instr));
10697
10698         fprintf(f,
10699                 "\t},\n");
10700 }
10701
10702 static instruction_export_t export_table[] = {
10703         [INSTR_RX] = instr_io_export,
10704
10705         [INSTR_TX] = instr_io_export,
10706         [INSTR_TX_I] = instr_io_export,
10707
10708         [INSTR_HDR_EXTRACT] = instr_io_export,
10709         [INSTR_HDR_EXTRACT2] = instr_io_export,
10710         [INSTR_HDR_EXTRACT3] = instr_io_export,
10711         [INSTR_HDR_EXTRACT4] = instr_io_export,
10712         [INSTR_HDR_EXTRACT5] = instr_io_export,
10713         [INSTR_HDR_EXTRACT6] = instr_io_export,
10714         [INSTR_HDR_EXTRACT7] = instr_io_export,
10715         [INSTR_HDR_EXTRACT8] = instr_io_export,
10716
10717         [INSTR_HDR_EXTRACT_M] = instr_io_export,
10718
10719         [INSTR_HDR_LOOKAHEAD] = instr_io_export,
10720
10721         [INSTR_HDR_EMIT] = instr_io_export,
10722         [INSTR_HDR_EMIT_TX] = instr_io_export,
10723         [INSTR_HDR_EMIT2_TX] = instr_io_export,
10724         [INSTR_HDR_EMIT3_TX] = instr_io_export,
10725         [INSTR_HDR_EMIT4_TX] = instr_io_export,
10726         [INSTR_HDR_EMIT5_TX] = instr_io_export,
10727         [INSTR_HDR_EMIT6_TX] = instr_io_export,
10728         [INSTR_HDR_EMIT7_TX] = instr_io_export,
10729         [INSTR_HDR_EMIT8_TX] = instr_io_export,
10730
10731         [INSTR_HDR_VALIDATE] = instr_hdr_validate_export,
10732         [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export,
10733
10734         [INSTR_MOV] = instr_mov_export,
10735         [INSTR_MOV_MH] = instr_mov_export,
10736         [INSTR_MOV_HM] = instr_mov_export,
10737         [INSTR_MOV_HH] = instr_mov_export,
10738         [INSTR_MOV_I] = instr_mov_export,
10739
10740         [INSTR_DMA_HT]  = instr_dma_ht_export,
10741         [INSTR_DMA_HT2] = instr_dma_ht_export,
10742         [INSTR_DMA_HT3] = instr_dma_ht_export,
10743         [INSTR_DMA_HT4] = instr_dma_ht_export,
10744         [INSTR_DMA_HT5] = instr_dma_ht_export,
10745         [INSTR_DMA_HT6] = instr_dma_ht_export,
10746         [INSTR_DMA_HT7] = instr_dma_ht_export,
10747         [INSTR_DMA_HT8] = instr_dma_ht_export,
10748
10749         [INSTR_ALU_ADD] = instr_alu_export,
10750         [INSTR_ALU_ADD_MH] = instr_alu_export,
10751         [INSTR_ALU_ADD_HM] = instr_alu_export,
10752         [INSTR_ALU_ADD_HH] = instr_alu_export,
10753         [INSTR_ALU_ADD_MI] = instr_alu_export,
10754         [INSTR_ALU_ADD_HI] = instr_alu_export,
10755
10756         [INSTR_ALU_SUB] = instr_alu_export,
10757         [INSTR_ALU_SUB_MH] = instr_alu_export,
10758         [INSTR_ALU_SUB_HM] = instr_alu_export,
10759         [INSTR_ALU_SUB_HH] = instr_alu_export,
10760         [INSTR_ALU_SUB_MI] = instr_alu_export,
10761         [INSTR_ALU_SUB_HI] = instr_alu_export,
10762
10763         [INSTR_ALU_CKADD_FIELD] = instr_alu_export,
10764         [INSTR_ALU_CKADD_STRUCT] = instr_alu_export,
10765         [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export,
10766         [INSTR_ALU_CKSUB_FIELD] = instr_alu_export,
10767
10768         [INSTR_ALU_AND] = instr_alu_export,
10769         [INSTR_ALU_AND_MH] = instr_alu_export,
10770         [INSTR_ALU_AND_HM] = instr_alu_export,
10771         [INSTR_ALU_AND_HH] = instr_alu_export,
10772         [INSTR_ALU_AND_I] = instr_alu_export,
10773
10774         [INSTR_ALU_OR] = instr_alu_export,
10775         [INSTR_ALU_OR_MH] = instr_alu_export,
10776         [INSTR_ALU_OR_HM] = instr_alu_export,
10777         [INSTR_ALU_OR_HH] = instr_alu_export,
10778         [INSTR_ALU_OR_I] = instr_alu_export,
10779
10780         [INSTR_ALU_XOR] = instr_alu_export,
10781         [INSTR_ALU_XOR_MH] = instr_alu_export,
10782         [INSTR_ALU_XOR_HM] = instr_alu_export,
10783         [INSTR_ALU_XOR_HH] = instr_alu_export,
10784         [INSTR_ALU_XOR_I] = instr_alu_export,
10785
10786         [INSTR_ALU_SHL] = instr_alu_export,
10787         [INSTR_ALU_SHL_MH] = instr_alu_export,
10788         [INSTR_ALU_SHL_HM] = instr_alu_export,
10789         [INSTR_ALU_SHL_HH] = instr_alu_export,
10790         [INSTR_ALU_SHL_MI] = instr_alu_export,
10791         [INSTR_ALU_SHL_HI] = instr_alu_export,
10792
10793         [INSTR_ALU_SHR] = instr_alu_export,
10794         [INSTR_ALU_SHR_MH] = instr_alu_export,
10795         [INSTR_ALU_SHR_HM] = instr_alu_export,
10796         [INSTR_ALU_SHR_HH] = instr_alu_export,
10797         [INSTR_ALU_SHR_MI] = instr_alu_export,
10798         [INSTR_ALU_SHR_HI] = instr_alu_export,
10799
10800         [INSTR_REGPREFETCH_RH] = instr_reg_export,
10801         [INSTR_REGPREFETCH_RM] = instr_reg_export,
10802         [INSTR_REGPREFETCH_RI] = instr_reg_export,
10803
10804         [INSTR_REGRD_HRH] = instr_reg_export,
10805         [INSTR_REGRD_HRM] = instr_reg_export,
10806         [INSTR_REGRD_MRH] = instr_reg_export,
10807         [INSTR_REGRD_MRM] = instr_reg_export,
10808         [INSTR_REGRD_HRI] = instr_reg_export,
10809         [INSTR_REGRD_MRI] = instr_reg_export,
10810
10811         [INSTR_REGWR_RHH] = instr_reg_export,
10812         [INSTR_REGWR_RHM] = instr_reg_export,
10813         [INSTR_REGWR_RMH] = instr_reg_export,
10814         [INSTR_REGWR_RMM] = instr_reg_export,
10815         [INSTR_REGWR_RHI] = instr_reg_export,
10816         [INSTR_REGWR_RMI] = instr_reg_export,
10817         [INSTR_REGWR_RIH] = instr_reg_export,
10818         [INSTR_REGWR_RIM] = instr_reg_export,
10819         [INSTR_REGWR_RII] = instr_reg_export,
10820
10821         [INSTR_REGADD_RHH] = instr_reg_export,
10822         [INSTR_REGADD_RHM] = instr_reg_export,
10823         [INSTR_REGADD_RMH] = instr_reg_export,
10824         [INSTR_REGADD_RMM] = instr_reg_export,
10825         [INSTR_REGADD_RHI] = instr_reg_export,
10826         [INSTR_REGADD_RMI] = instr_reg_export,
10827         [INSTR_REGADD_RIH] = instr_reg_export,
10828         [INSTR_REGADD_RIM] = instr_reg_export,
10829         [INSTR_REGADD_RII] = instr_reg_export,
10830
10831         [INSTR_METPREFETCH_H] = instr_meter_export,
10832         [INSTR_METPREFETCH_M] = instr_meter_export,
10833         [INSTR_METPREFETCH_I] = instr_meter_export,
10834
10835         [INSTR_METER_HHM] = instr_meter_export,
10836         [INSTR_METER_HHI] = instr_meter_export,
10837         [INSTR_METER_HMM] = instr_meter_export,
10838         [INSTR_METER_HMI] = instr_meter_export,
10839         [INSTR_METER_MHM] = instr_meter_export,
10840         [INSTR_METER_MHI] = instr_meter_export,
10841         [INSTR_METER_MMM] = instr_meter_export,
10842         [INSTR_METER_MMI] = instr_meter_export,
10843         [INSTR_METER_IHM] = instr_meter_export,
10844         [INSTR_METER_IHI] = instr_meter_export,
10845         [INSTR_METER_IMM] = instr_meter_export,
10846         [INSTR_METER_IMI] = instr_meter_export,
10847
10848         [INSTR_TABLE] = instr_table_export,
10849         [INSTR_TABLE_AF] = instr_table_export,
10850         [INSTR_SELECTOR] = instr_table_export,
10851         [INSTR_LEARNER] = instr_table_export,
10852         [INSTR_LEARNER_AF] = instr_table_export,
10853
10854         [INSTR_LEARNER_LEARN] = instr_learn_export,
10855         [INSTR_LEARNER_FORGET] = instr_forget_export,
10856
10857         [INSTR_EXTERN_OBJ] = instr_extern_export,
10858         [INSTR_EXTERN_FUNC] = instr_extern_export,
10859
10860         [INSTR_JMP] = instr_jmp_export,
10861         [INSTR_JMP_VALID] = instr_jmp_export,
10862         [INSTR_JMP_INVALID] = instr_jmp_export,
10863         [INSTR_JMP_HIT] = instr_jmp_export,
10864         [INSTR_JMP_MISS] = instr_jmp_export,
10865         [INSTR_JMP_ACTION_HIT] = instr_jmp_export,
10866         [INSTR_JMP_ACTION_MISS] = instr_jmp_export,
10867
10868         [INSTR_JMP_EQ] = instr_jmp_export,
10869         [INSTR_JMP_EQ_MH] = instr_jmp_export,
10870         [INSTR_JMP_EQ_HM] = instr_jmp_export,
10871         [INSTR_JMP_EQ_HH] = instr_jmp_export,
10872         [INSTR_JMP_EQ_I] = instr_jmp_export,
10873
10874         [INSTR_JMP_NEQ] = instr_jmp_export,
10875         [INSTR_JMP_NEQ_MH] = instr_jmp_export,
10876         [INSTR_JMP_NEQ_HM] = instr_jmp_export,
10877         [INSTR_JMP_NEQ_HH] = instr_jmp_export,
10878         [INSTR_JMP_NEQ_I] = instr_jmp_export,
10879
10880         [INSTR_JMP_LT] = instr_jmp_export,
10881         [INSTR_JMP_LT_MH] = instr_jmp_export,
10882         [INSTR_JMP_LT_HM] = instr_jmp_export,
10883         [INSTR_JMP_LT_HH] = instr_jmp_export,
10884         [INSTR_JMP_LT_MI] = instr_jmp_export,
10885         [INSTR_JMP_LT_HI] = instr_jmp_export,
10886
10887         [INSTR_JMP_GT] = instr_jmp_export,
10888         [INSTR_JMP_GT_MH] = instr_jmp_export,
10889         [INSTR_JMP_GT_HM] = instr_jmp_export,
10890         [INSTR_JMP_GT_HH] = instr_jmp_export,
10891         [INSTR_JMP_GT_MI] = instr_jmp_export,
10892         [INSTR_JMP_GT_HI] = instr_jmp_export,
10893
10894         [INSTR_RETURN] = instr_return_export,
10895 };
10896
10897 static void
10898 action_data_codegen(struct action *a, FILE *f)
10899 {
10900         uint32_t i;
10901
10902         fprintf(f,
10903                 "static const struct instruction action_%s_instructions[] = {\n",
10904                 a->name);
10905
10906         for (i = 0; i < a->n_instructions; i++) {
10907                 struct instruction *instr = &a->instructions[i];
10908                 instruction_export_t func = export_table[instr->type];
10909
10910                 func(instr, f);
10911         }
10912
10913         fprintf(f, "};\n");
10914 }
10915
10916 static const char *
10917 instr_type_to_func(struct instruction *instr)
10918 {
10919         switch (instr->type) {
10920         case INSTR_RX: return NULL;
10921
10922         case INSTR_TX: return "__instr_tx_exec";
10923         case INSTR_TX_I: return "__instr_tx_i_exec";
10924
10925         case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec";
10926         case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec";
10927         case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec";
10928         case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec";
10929         case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec";
10930         case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec";
10931         case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec";
10932         case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec";
10933
10934         case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec";
10935
10936         case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec";
10937
10938         case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec";
10939         case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec";
10940         case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec";
10941         case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec";
10942         case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec";
10943         case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec";
10944         case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec";
10945         case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec";
10946         case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec";
10947
10948         case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec";
10949         case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec";
10950
10951         case INSTR_MOV: return "__instr_mov_exec";
10952         case INSTR_MOV_MH: return "__instr_mov_mh_exec";
10953         case INSTR_MOV_HM: return "__instr_mov_hm_exec";
10954         case INSTR_MOV_HH: return "__instr_mov_hh_exec";
10955         case INSTR_MOV_I: return "__instr_mov_i_exec";
10956
10957         case INSTR_DMA_HT: return "__instr_dma_ht_exec";
10958         case INSTR_DMA_HT2: return "__instr_dma_ht2_exec";
10959         case INSTR_DMA_HT3: return "__instr_dma_ht3_exec";
10960         case INSTR_DMA_HT4: return "__instr_dma_ht4_exec";
10961         case INSTR_DMA_HT5: return "__instr_dma_ht5_exec";
10962         case INSTR_DMA_HT6: return "__instr_dma_ht6_exec";
10963         case INSTR_DMA_HT7: return "__instr_dma_ht7_exec";
10964         case INSTR_DMA_HT8: return "__instr_dma_ht8_exec";
10965
10966         case INSTR_ALU_ADD: return "__instr_alu_add_exec";
10967         case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec";
10968         case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec";
10969         case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec";
10970         case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec";
10971         case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec";
10972
10973         case INSTR_ALU_SUB: return "__instr_alu_sub_exec";
10974         case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec";
10975         case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec";
10976         case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec";
10977         case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec";
10978         case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec";
10979
10980         case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec";
10981         case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec";
10982         case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec";
10983         case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec";
10984
10985         case INSTR_ALU_AND: return "__instr_alu_and_exec";
10986         case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec";
10987         case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec";
10988         case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec";
10989         case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec";
10990
10991         case INSTR_ALU_OR: return "__instr_alu_or_exec";
10992         case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec";
10993         case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec";
10994         case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec";
10995         case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec";
10996
10997         case INSTR_ALU_XOR: return "__instr_alu_xor_exec";
10998         case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec";
10999         case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec";
11000         case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec";
11001         case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec";
11002
11003         case INSTR_ALU_SHL: return "__instr_alu_shl_exec";
11004         case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec";
11005         case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec";
11006         case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec";
11007         case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec";
11008         case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec";
11009
11010         case INSTR_ALU_SHR: return "__instr_alu_shr_exec";
11011         case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec";
11012         case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec";
11013         case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec";
11014         case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec";
11015         case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec";
11016
11017         case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec";
11018         case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec";
11019         case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec";
11020
11021         case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec";
11022         case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec";
11023         case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec";
11024         case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec";
11025         case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec";
11026         case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec";
11027
11028         case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec";
11029         case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec";
11030         case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec";
11031         case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec";
11032         case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec";
11033         case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec";
11034         case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec";
11035         case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec";
11036         case INSTR_REGWR_RII: return "__instr_regwr_rii_exec";
11037
11038         case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec";
11039         case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec";
11040         case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec";
11041         case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec";
11042         case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec";
11043         case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec";
11044         case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec";
11045         case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec";
11046         case INSTR_REGADD_RII: return "__instr_regadd_rii_exec";
11047
11048         case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec";
11049         case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec";
11050         case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec";
11051
11052         case INSTR_METER_HHM: return "__instr_meter_hhm_exec";
11053         case INSTR_METER_HHI: return "__instr_meter_hhi_exec";
11054         case INSTR_METER_HMM: return "__instr_meter_hmm_exec";
11055         case INSTR_METER_HMI: return "__instr_meter_hmi_exec";
11056         case INSTR_METER_MHM: return "__instr_meter_mhm_exec";
11057         case INSTR_METER_MHI: return "__instr_meter_mhi_exec";
11058         case INSTR_METER_MMM: return "__instr_meter_mmm_exec";
11059         case INSTR_METER_MMI: return "__instr_meter_mmi_exec";
11060         case INSTR_METER_IHM: return "__instr_meter_ihm_exec";
11061         case INSTR_METER_IHI: return "__instr_meter_ihi_exec";
11062         case INSTR_METER_IMM: return "__instr_meter_imm_exec";
11063         case INSTR_METER_IMI: return "__instr_meter_imi_exec";
11064
11065         case INSTR_TABLE: return NULL;
11066         case INSTR_TABLE_AF: return NULL;
11067         case INSTR_SELECTOR: return NULL;
11068         case INSTR_LEARNER: return NULL;
11069         case INSTR_LEARNER_AF: return NULL;
11070
11071         case INSTR_LEARNER_LEARN: return "__instr_learn_exec";
11072         case INSTR_LEARNER_FORGET: return "__instr_forget_exec";
11073
11074         case INSTR_EXTERN_OBJ: return NULL;
11075         case INSTR_EXTERN_FUNC: return NULL;
11076
11077         case INSTR_JMP: return NULL;
11078         case INSTR_JMP_VALID: return NULL;
11079         case INSTR_JMP_INVALID: return NULL;
11080         case INSTR_JMP_HIT: return NULL;
11081         case INSTR_JMP_MISS: return NULL;
11082         case INSTR_JMP_ACTION_HIT: return NULL;
11083         case INSTR_JMP_ACTION_MISS: return NULL;
11084         case INSTR_JMP_EQ: return NULL;
11085         case INSTR_JMP_EQ_MH: return NULL;
11086         case INSTR_JMP_EQ_HM: return NULL;
11087         case INSTR_JMP_EQ_HH: return NULL;
11088         case INSTR_JMP_EQ_I: return NULL;
11089         case INSTR_JMP_NEQ: return NULL;
11090         case INSTR_JMP_NEQ_MH: return NULL;
11091         case INSTR_JMP_NEQ_HM: return NULL;
11092         case INSTR_JMP_NEQ_HH: return NULL;
11093         case INSTR_JMP_NEQ_I: return NULL;
11094         case INSTR_JMP_LT: return NULL;
11095         case INSTR_JMP_LT_MH: return NULL;
11096         case INSTR_JMP_LT_HM: return NULL;
11097         case INSTR_JMP_LT_HH: return NULL;
11098         case INSTR_JMP_LT_MI: return NULL;
11099         case INSTR_JMP_LT_HI: return NULL;
11100         case INSTR_JMP_GT: return NULL;
11101         case INSTR_JMP_GT_MH: return NULL;
11102         case INSTR_JMP_GT_HM: return NULL;
11103         case INSTR_JMP_GT_HH: return NULL;
11104         case INSTR_JMP_GT_MI: return NULL;
11105         case INSTR_JMP_GT_HI: return NULL;
11106
11107         case INSTR_RETURN: return NULL;
11108
11109         default: return NULL;
11110         }
11111 }
11112
11113 static void
11114 action_instr_does_tx_codegen(struct action *a,
11115                         uint32_t instr_pos,
11116                         struct instruction *instr,
11117                         FILE *f)
11118 {
11119         fprintf(f,
11120                 "%s(p, t, &action_%s_instructions[%u]);\n"
11121                 "\tthread_ip_reset(p, t);\n"
11122                 "\tinstr_rx_exec(p);\n"
11123                 "\treturn;\n",
11124                 instr_type_to_func(instr),
11125                 a->name,
11126                 instr_pos);
11127 }
11128
11129 static void
11130 action_instr_extern_obj_codegen(struct action *a,
11131                                 uint32_t instr_pos,
11132                                 FILE *f)
11133 {
11134         fprintf(f,
11135                 "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n",
11136                 a->name,
11137                 instr_pos);
11138 }
11139
11140 static void
11141 action_instr_extern_func_codegen(struct action *a,
11142                                  uint32_t instr_pos,
11143                                  FILE *f)
11144 {
11145         fprintf(f,
11146                 "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n",
11147                 a->name,
11148                 instr_pos);
11149 }
11150
11151 static void
11152 action_instr_jmp_codegen(struct action *a,
11153                          uint32_t instr_pos,
11154                          struct instruction *instr,
11155                          struct instruction_data *data,
11156                          FILE *f)
11157 {
11158         switch (instr->type) {
11159         case INSTR_JMP:
11160                 fprintf(f,
11161                         "goto %s;\n",
11162                         data->jmp_label);
11163                 return;
11164
11165         case INSTR_JMP_VALID:
11166                 fprintf(f,
11167                         "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n"
11168                         "\t\tgoto %s;\n",
11169                         a->name,
11170                         instr_pos,
11171                         data->jmp_label);
11172                 return;
11173
11174         case INSTR_JMP_INVALID:
11175                 fprintf(f,
11176                         "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n"
11177                         "\t\tgoto %s;\n",
11178                         a->name,
11179                         instr_pos,
11180                         data->jmp_label);
11181                 return;
11182
11183         case INSTR_JMP_HIT:
11184                 fprintf(f,
11185                         "if (t->hit)\n"
11186                         "\t\tgoto %s;\n",
11187                         data->jmp_label);
11188                 return;
11189
11190         case INSTR_JMP_MISS:
11191                 fprintf(f,
11192                         "if (!t->hit)\n"
11193                         "\t\tgoto %s;\n",
11194                         data->jmp_label);
11195                 return;
11196
11197         case INSTR_JMP_ACTION_HIT:
11198                 fprintf(f,
11199                         "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n"
11200                         "\t\tgoto %s;\n",
11201                         a->name,
11202                         instr_pos,
11203                         data->jmp_label);
11204                 return;
11205
11206         case INSTR_JMP_ACTION_MISS:
11207                 fprintf(f,
11208                         "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n"
11209                         "\t\tgoto %s;\n",
11210                         a->name,
11211                         instr_pos,
11212                         data->jmp_label);
11213                 return;
11214
11215         case INSTR_JMP_EQ:
11216                 fprintf(f,
11217                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11218                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11219                         "\t\tgoto %s;\n",
11220                         a->name,
11221                         instr_pos,
11222                         a->name,
11223                         instr_pos,
11224                         data->jmp_label);
11225                 return;
11226
11227         case INSTR_JMP_EQ_MH:
11228                 fprintf(f,
11229                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11230                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11231                         "\t\tgoto %s;\n",
11232                         a->name,
11233                         instr_pos,
11234                         a->name,
11235                         instr_pos,
11236                         data->jmp_label);
11237                 return;
11238
11239         case INSTR_JMP_EQ_HM:
11240                 fprintf(f,
11241                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == "
11242                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11243                         "\t\tgoto %s;\n",
11244                         a->name,
11245                         instr_pos,
11246                         a->name,
11247                         instr_pos,
11248                         data->jmp_label);
11249                 return;
11250
11251         case INSTR_JMP_EQ_HH:
11252                 fprintf(f,
11253                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == "
11254                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11255                         "\t\tgoto %s;\n",
11256                         a->name,
11257                         instr_pos,
11258                         a->name,
11259                         instr_pos,
11260                         data->jmp_label);
11261                 return;
11262
11263         case INSTR_JMP_EQ_I:
11264                 fprintf(f,
11265                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11266                         "action_%s_instructions[%u].jmp.b_val)\n"
11267                         "\t\tgoto %s;\n",
11268                         a->name,
11269                         instr_pos,
11270                         a->name,
11271                         instr_pos,
11272                         data->jmp_label);
11273                 return;
11274
11275         case INSTR_JMP_NEQ:
11276                 fprintf(f,
11277                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11278                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11279                         "\t\tgoto %s;\n",
11280                         a->name,
11281                         instr_pos,
11282                         a->name,
11283                         instr_pos,
11284                         data->jmp_label);
11285                 return;
11286
11287         case INSTR_JMP_NEQ_MH:
11288                 fprintf(f,
11289                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11290                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11291                         "\t\tgoto %s;\n",
11292                         a->name,
11293                         instr_pos,
11294                         a->name,
11295                         instr_pos,
11296                         data->jmp_label);
11297                 return;
11298
11299         case INSTR_JMP_NEQ_HM:
11300                 fprintf(f,
11301                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != "
11302                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11303                         "\t\tgoto %s;\n",
11304                         a->name,
11305                         instr_pos,
11306                         a->name,
11307                         instr_pos,
11308                         data->jmp_label);
11309                 return;
11310
11311         case INSTR_JMP_NEQ_HH:
11312                 fprintf(f,
11313                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != "
11314                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11315                         "\t\tgoto %s;\n",
11316                         a->name,
11317                         instr_pos,
11318                         a->name,
11319                         instr_pos,
11320                         data->jmp_label);
11321                 return;
11322
11323         case INSTR_JMP_NEQ_I:
11324                 fprintf(f,
11325                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11326                         "action_%s_instructions[%u].jmp.b_val)\n"
11327                         "\t\tgoto %s;\n",
11328                         a->name,
11329                         instr_pos,
11330                         a->name,
11331                         instr_pos,
11332                         data->jmp_label);
11333                 return;
11334
11335         case INSTR_JMP_LT:
11336                 fprintf(f,
11337                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11338                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11339                         "\t\tgoto %s;\n",
11340                         a->name,
11341                         instr_pos,
11342                         a->name,
11343                         instr_pos,
11344                         data->jmp_label);
11345                 return;
11346
11347         case INSTR_JMP_LT_MH:
11348                 fprintf(f,
11349                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11350                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11351                         "\t\tgoto %s;\n",
11352                         a->name,
11353                         instr_pos,
11354                         a->name,
11355                         instr_pos,
11356                         data->jmp_label);
11357                 return;
11358
11359         case INSTR_JMP_LT_HM:
11360                 fprintf(f,
11361                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11362                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11363                         "\t\tgoto %s;\n",
11364                         a->name,
11365                         instr_pos,
11366                         a->name,
11367                         instr_pos,
11368                         data->jmp_label);
11369                 return;
11370
11371         case INSTR_JMP_LT_HH:
11372                 fprintf(f,
11373                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11374                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11375                         "\t\tgoto %s;\n",
11376                         a->name,
11377                         instr_pos,
11378                         a->name,
11379                         instr_pos,
11380                         data->jmp_label);
11381                 return;
11382
11383         case INSTR_JMP_LT_MI:
11384                 fprintf(f,
11385                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11386                         "action_%s_instructions[%u].jmp.b_val)\n"
11387                         "\t\tgoto %s;\n",
11388                         a->name,
11389                         instr_pos,
11390                         a->name,
11391                         instr_pos,
11392                         data->jmp_label);
11393                 return;
11394
11395         case INSTR_JMP_LT_HI:
11396                 fprintf(f,
11397                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11398                         "action_%s_instructions[%u].jmp.b_val)\n"
11399                         "\t\tgoto %s;\n",
11400                         a->name,
11401                         instr_pos,
11402                         a->name,
11403                         instr_pos,
11404                         data->jmp_label);
11405                 return;
11406
11407         case INSTR_JMP_GT:
11408                 fprintf(f,
11409                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11410                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11411                         "\t\tgoto %s;\n",
11412                         a->name,
11413                         instr_pos,
11414                         a->name,
11415                         instr_pos,
11416                         data->jmp_label);
11417                 return;
11418
11419         case INSTR_JMP_GT_MH:
11420                 fprintf(f,
11421                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11422                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11423                         "\t\tgoto %s;\n",
11424                         a->name,
11425                         instr_pos,
11426                         a->name,
11427                         instr_pos,
11428                         data->jmp_label);
11429                 return;
11430
11431         case INSTR_JMP_GT_HM:
11432                 fprintf(f,
11433                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11434                         "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11435                         "\t\tgoto %s;\n",
11436                         a->name,
11437                         instr_pos,
11438                         a->name,
11439                         instr_pos,
11440                         data->jmp_label);
11441                 return;
11442
11443         case INSTR_JMP_GT_HH:
11444                 fprintf(f,
11445                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11446                         "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11447                         "\t\tgoto %s;\n",
11448                         a->name,
11449                         instr_pos,
11450                         a->name,
11451                         instr_pos,
11452                         data->jmp_label);
11453                 return;
11454
11455         case INSTR_JMP_GT_MI:
11456                 fprintf(f,
11457                         "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11458                         "action_%s_instructions[%u].jmp.b_val)\n"
11459                         "\t\tgoto %s;\n",
11460                         a->name,
11461                         instr_pos,
11462                         a->name,
11463                         instr_pos,
11464                         data->jmp_label);
11465                 return;
11466
11467         case INSTR_JMP_GT_HI:
11468                 fprintf(f,
11469                         "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11470                         "action_%s_instructions[%u].jmp.b_val)\n"
11471                         "\t\tgoto %s;\n",
11472                         a->name,
11473                         instr_pos,
11474                         a->name,
11475                         instr_pos,
11476                         data->jmp_label);
11477                 return;
11478
11479         default:
11480                 return;
11481         }
11482 }
11483
11484 static void
11485 action_instr_return_codegen(FILE *f)
11486 {
11487         fprintf(f,
11488                 "return;\n");
11489 }
11490
11491 static void
11492 action_instr_codegen(struct action *a, FILE *f)
11493 {
11494         uint32_t i;
11495
11496         fprintf(f,
11497                 "void\n"
11498                 "action_%s_run(struct rte_swx_pipeline *p)\n"
11499                 "{\n"
11500                 "\tstruct thread *t = &p->threads[p->thread_id];\n"
11501                 "\n",
11502                 a->name);
11503
11504         for (i = 0; i < a->n_instructions; i++) {
11505                 struct instruction *instr = &a->instructions[i];
11506                 struct instruction_data *data = &a->instruction_data[i];
11507
11508                 /* Label, if present. */
11509                 if (data->label[0])
11510                         fprintf(f, "\n%s : ", data->label);
11511                 else
11512                         fprintf(f, "\n\t");
11513
11514                 /* TX instruction type. */
11515                 if (instruction_does_tx(instr)) {
11516                         action_instr_does_tx_codegen(a, i, instr, f);
11517                         continue;
11518                 }
11519
11520                 /* Extern object/function instruction type. */
11521                 if (instr->type == INSTR_EXTERN_OBJ) {
11522                         action_instr_extern_obj_codegen(a, i, f);
11523                         continue;
11524                 }
11525
11526                 if (instr->type == INSTR_EXTERN_FUNC) {
11527                         action_instr_extern_func_codegen(a, i, f);
11528                         continue;
11529                 }
11530
11531                 /* Jump instruction type. */
11532                 if (instruction_is_jmp(instr)) {
11533                         action_instr_jmp_codegen(a, i, instr, data, f);
11534                         continue;
11535                 }
11536
11537                 /* Return instruction type. */
11538                 if (instr->type == INSTR_RETURN) {
11539                         action_instr_return_codegen(f);
11540                         continue;
11541                 }
11542
11543                 /* Any other instruction type. */
11544                 fprintf(f,
11545                         "%s(p, t, &action_%s_instructions[%u]);\n",
11546                         instr_type_to_func(instr),
11547                         a->name,
11548                         i);
11549         }
11550
11551         fprintf(f, "}\n\n");
11552 }
11553
11554 struct instruction_group {
11555         TAILQ_ENTRY(instruction_group) node;
11556
11557         uint32_t group_id;
11558
11559         uint32_t first_instr_id;
11560
11561         uint32_t last_instr_id;
11562
11563         instr_exec_t func;
11564 };
11565
11566 TAILQ_HEAD(instruction_group_list, instruction_group);
11567
11568 static struct instruction_group *
11569 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id)
11570 {
11571         struct instruction_group *g;
11572
11573         TAILQ_FOREACH(g, igl, node)
11574                 if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id))
11575                         return g;
11576
11577         return NULL;
11578 }
11579
11580 static void
11581 instruction_group_list_free(struct instruction_group_list *igl)
11582 {
11583         if (!igl)
11584                 return;
11585
11586         for ( ; ; ) {
11587                 struct instruction_group *g;
11588
11589                 g = TAILQ_FIRST(igl);
11590                 if (!g)
11591                         break;
11592
11593                 TAILQ_REMOVE(igl, g, node);
11594                 free(g);
11595         }
11596
11597         free(igl);
11598 }
11599
11600 static struct instruction_group_list *
11601 instruction_group_list_create(struct rte_swx_pipeline *p)
11602 {
11603         struct instruction_group_list *igl = NULL;
11604         struct instruction_group *g = NULL;
11605         uint32_t n_groups = 0, i;
11606
11607         if (!p || !p->instructions || !p->instruction_data || !p->n_instructions)
11608                 goto error;
11609
11610         /* List init. */
11611         igl = calloc(1, sizeof(struct instruction_group_list));
11612         if (!igl)
11613                 goto error;
11614
11615         TAILQ_INIT(igl);
11616
11617         /* Allocate the first group. */
11618         g = calloc(1, sizeof(struct instruction_group));
11619         if (!g)
11620                 goto error;
11621
11622         /* Iteration 1: Separate the instructions into groups based on the thread yield
11623          * instructions. Do not worry about the jump instructions at this point.
11624          */
11625         for (i = 0; i < p->n_instructions; i++) {
11626                 struct instruction *instr = &p->instructions[i];
11627
11628                 /* Check for thread yield instructions. */
11629                 if (!instruction_does_thread_yield(instr))
11630                         continue;
11631
11632                 /* If the current group contains at least one instruction, then finalize it (with
11633                  * the previous instruction), add it to the list and allocate a new group (that
11634                  * starts with the current instruction).
11635                  */
11636                 if (i - g->first_instr_id) {
11637                         /* Finalize the group. */
11638                         g->last_instr_id = i - 1;
11639
11640                         /* Add the group to the list. Advance the number of groups. */
11641                         TAILQ_INSERT_TAIL(igl, g, node);
11642                         n_groups++;
11643
11644                         /* Allocate a new group. */
11645                         g = calloc(1, sizeof(struct instruction_group));
11646                         if (!g)
11647                                 goto error;
11648
11649                         /* Initialize the new group. */
11650                         g->group_id = n_groups;
11651                         g->first_instr_id = i;
11652                 }
11653
11654                 /* Finalize the current group (with the current instruction, therefore this group
11655                  * contains just the current thread yield instruction), add it to the list and
11656                  * allocate a new group (that starts with the next instruction).
11657                  */
11658
11659                 /* Finalize the group. */
11660                 g->last_instr_id = i;
11661
11662                 /* Add the group to the list. Advance the number of groups. */
11663                 TAILQ_INSERT_TAIL(igl, g, node);
11664                 n_groups++;
11665
11666                 /* Allocate a new group. */
11667                 g = calloc(1, sizeof(struct instruction_group));
11668                 if (!g)
11669                         goto error;
11670
11671                 /* Initialize the new group. */
11672                 g->group_id = n_groups;
11673                 g->first_instr_id = i + 1;
11674         }
11675
11676         /* Handle the last group. */
11677         if (i - g->first_instr_id) {
11678                 /* Finalize the group. */
11679                 g->last_instr_id = i - 1;
11680
11681                 /* Add the group to the list. Advance the number of groups. */
11682                 TAILQ_INSERT_TAIL(igl, g, node);
11683                 n_groups++;
11684         } else
11685                 free(g);
11686
11687         g = NULL;
11688
11689         /* Iteration 2: Handle jumps. If the current group contains an instruction which represents
11690          * the destination of a jump instruction located in a different group ("far jump"), then the
11691          * current group has to be split, so that the instruction representing the far jump
11692          * destination is at the start of its group.
11693          */
11694         for ( ; ; ) {
11695                 int is_modified = 0;
11696
11697                 for (i = 0; i < p->n_instructions; i++) {
11698                         struct instruction_data *data = &p->instruction_data[i];
11699                         struct instruction_group *g;
11700                         uint32_t j;
11701
11702                         /* Continue when the current instruction is not a jump destination. */
11703                         if (!data->n_users)
11704                                 continue;
11705
11706                         g = instruction_group_list_group_find(igl, i);
11707                         if (!g)
11708                                 goto error;
11709
11710                         /* Find out all the jump instructions with this destination. */
11711                         for (j = 0; j < p->n_instructions; j++) {
11712                                 struct instruction *jmp_instr = &p->instructions[j];
11713                                 struct instruction_data *jmp_data = &p->instruction_data[j];
11714                                 struct instruction_group *jmp_g, *new_g;
11715
11716                                 /* Continue when not a jump instruction. Even when jump instruction,
11717                                  * continue when the jump destination is not this instruction.
11718                                  */
11719                                 if (!instruction_is_jmp(jmp_instr) ||
11720                                     strcmp(jmp_data->jmp_label, data->label))
11721                                         continue;
11722
11723                                 jmp_g = instruction_group_list_group_find(igl, j);
11724                                 if (!jmp_g)
11725                                         goto error;
11726
11727                                 /* Continue when both the jump instruction and the jump destination
11728                                  * instruction are in the same group. Even when in different groups,
11729                                  * still continue if the jump destination instruction is already the
11730                                  * first instruction of its group.
11731                                  */
11732                                 if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i))
11733                                         continue;
11734
11735                                 /* Split the group of the current jump destination instruction to
11736                                  * make this instruction the first instruction of a new group.
11737                                  */
11738                                 new_g = calloc(1, sizeof(struct instruction_group));
11739                                 if (!new_g)
11740                                         goto error;
11741
11742                                 new_g->group_id = n_groups;
11743                                 new_g->first_instr_id = i;
11744                                 new_g->last_instr_id = g->last_instr_id;
11745
11746                                 g->last_instr_id = i - 1;
11747
11748                                 TAILQ_INSERT_AFTER(igl, g, new_g, node);
11749                                 n_groups++;
11750                                 is_modified = 1;
11751
11752                                 /* The decision to split this group (to make the current instruction
11753                                  * the first instruction of a new group) is already taken and fully
11754                                  * implemented, so no need to search for more reasons to do it.
11755                                  */
11756                                 break;
11757                         }
11758                 }
11759
11760                 /* Re-evaluate everything, as at least one group got split, so some jumps that were
11761                  * previously considered local (i.e. the jump destination is in the same group as
11762                  * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a
11763                  * different group than the jump instruction). Wost case scenario: each instruction
11764                  * that is a jump destination ends up as the first instruction of its group.
11765                  */
11766                 if (!is_modified)
11767                         break;
11768         }
11769
11770         /* Re-assign the group IDs to be in incremental order. */
11771         i = 0;
11772         TAILQ_FOREACH(g, igl, node) {
11773                 g->group_id = i;
11774
11775                 i++;
11776         }
11777
11778         return igl;
11779
11780 error:
11781         instruction_group_list_free(igl);
11782
11783         free(g);
11784
11785         return NULL;
11786 }
11787
11788 static void
11789 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused,
11790                                uint32_t instr_pos,
11791                                struct instruction *instr,
11792                                FILE *f)
11793 {
11794         fprintf(f,
11795                 "%s(p, t, &pipeline_instructions[%u]);\n"
11796                 "\tthread_ip_reset(p, t);\n"
11797                 "\tinstr_rx_exec(p);\n"
11798                 "\treturn;\n",
11799                 instr_type_to_func(instr),
11800                 instr_pos);
11801 }
11802
11803 static int
11804 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p,
11805                            struct instruction_group_list *igl,
11806                            uint32_t jmp_instr_id,
11807                            struct instruction *jmp_instr,
11808                            struct instruction_data *jmp_data,
11809                            FILE *f)
11810 {
11811         struct instruction_group *jmp_g, *g;
11812         struct instruction_data *data;
11813         uint32_t instr_id;
11814
11815         switch (jmp_instr->type) {
11816         case INSTR_JMP:
11817                 break;
11818
11819         case INSTR_JMP_VALID:
11820                 fprintf(f,
11821                         "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))",
11822                         jmp_instr_id);
11823                 break;
11824
11825         case INSTR_JMP_INVALID:
11826                 fprintf(f,
11827                         "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))",
11828                         jmp_instr_id);
11829                 break;
11830
11831         case INSTR_JMP_HIT:
11832                 fprintf(f,
11833                         "if (t->hit)\n");
11834                 break;
11835
11836         case INSTR_JMP_MISS:
11837                 fprintf(f,
11838                         "if (!t->hit)\n");
11839                 break;
11840
11841         case INSTR_JMP_ACTION_HIT:
11842                 fprintf(f,
11843                         "if (t->action_id == pipeline_instructions[%u].jmp.action_id)",
11844                         jmp_instr_id);
11845                 break;
11846
11847         case INSTR_JMP_ACTION_MISS:
11848                 fprintf(f,
11849                         "if (t->action_id != pipeline_instructions[%u].jmp.action_id)",
11850                         jmp_instr_id);
11851                 break;
11852
11853         case INSTR_JMP_EQ:
11854                 fprintf(f,
11855                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
11856                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11857                         jmp_instr_id,
11858                         jmp_instr_id);
11859                 break;
11860
11861         case INSTR_JMP_EQ_MH:
11862                 fprintf(f,
11863                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
11864                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11865                         jmp_instr_id,
11866                         jmp_instr_id);
11867                 break;
11868
11869         case INSTR_JMP_EQ_HM:
11870                 fprintf(f,
11871                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == "
11872                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11873                         jmp_instr_id,
11874                         jmp_instr_id);
11875                 break;
11876
11877         case INSTR_JMP_EQ_HH:
11878                 fprintf(f,
11879                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == "
11880                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11881                         jmp_instr_id,
11882                         jmp_instr_id);
11883                 break;
11884
11885         case INSTR_JMP_EQ_I:
11886                 fprintf(f,
11887                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
11888                         "pipeline_instructions[%u].jmp.b_val)",
11889                         jmp_instr_id,
11890                         jmp_instr_id);
11891                 break;
11892
11893         case INSTR_JMP_NEQ:
11894                 fprintf(f,
11895                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
11896                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11897                         jmp_instr_id,
11898                         jmp_instr_id);
11899                 break;
11900
11901         case INSTR_JMP_NEQ_MH:
11902                 fprintf(f,
11903                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
11904                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11905                         jmp_instr_id,
11906                         jmp_instr_id);
11907                 break;
11908
11909         case INSTR_JMP_NEQ_HM:
11910                 fprintf(f,
11911                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != "
11912                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11913                         jmp_instr_id,
11914                         jmp_instr_id);
11915                 break;
11916
11917         case INSTR_JMP_NEQ_HH:
11918                 fprintf(f,
11919                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != "
11920                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11921                         jmp_instr_id,
11922                         jmp_instr_id);
11923                 break;
11924
11925         case INSTR_JMP_NEQ_I:
11926                 fprintf(f,
11927                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
11928                         "pipeline_instructions[%u].jmp.b_val)",
11929                         jmp_instr_id,
11930                         jmp_instr_id);
11931                 break;
11932
11933         case INSTR_JMP_LT:
11934                 fprintf(f,
11935                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
11936                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11937                         jmp_instr_id,
11938                         jmp_instr_id);
11939                 break;
11940
11941         case INSTR_JMP_LT_MH:
11942                 fprintf(f,
11943                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
11944                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11945                         jmp_instr_id,
11946                         jmp_instr_id);
11947                 break;
11948
11949         case INSTR_JMP_LT_HM:
11950                 fprintf(f,
11951                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
11952                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11953                         jmp_instr_id,
11954                         jmp_instr_id);
11955                 break;
11956
11957         case INSTR_JMP_LT_HH:
11958                 fprintf(f,
11959                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
11960                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11961                         jmp_instr_id,
11962                         jmp_instr_id);
11963                 break;
11964
11965         case INSTR_JMP_LT_MI:
11966                 fprintf(f,
11967                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
11968                         "pipeline_instructions[%u].jmp.b_val)",
11969                         jmp_instr_id,
11970                         jmp_instr_id);
11971                 break;
11972
11973         case INSTR_JMP_LT_HI:
11974                 fprintf(f,
11975                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
11976                         "pipeline_instructions[%u].jmp.b_val)",
11977                         jmp_instr_id,
11978                         jmp_instr_id);
11979                 break;
11980
11981         case INSTR_JMP_GT:
11982                 fprintf(f,
11983                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
11984                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
11985                         jmp_instr_id,
11986                         jmp_instr_id);
11987                 break;
11988
11989         case INSTR_JMP_GT_MH:
11990                 fprintf(f,
11991                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
11992                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
11993                         jmp_instr_id,
11994                         jmp_instr_id);
11995                 break;
11996
11997         case INSTR_JMP_GT_HM:
11998                 fprintf(f,
11999                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12000                         "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12001                         jmp_instr_id,
12002                         jmp_instr_id);
12003                 break;
12004
12005         case INSTR_JMP_GT_HH:
12006                 fprintf(f,
12007                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12008                         "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12009                         jmp_instr_id,
12010                         jmp_instr_id);
12011                 break;
12012
12013         case INSTR_JMP_GT_MI:
12014                 fprintf(f,
12015                         "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
12016                         "pipeline_instructions[%u].jmp.b_val)",
12017                         jmp_instr_id,
12018                         jmp_instr_id);
12019                 break;
12020
12021         case INSTR_JMP_GT_HI:
12022                 fprintf(f,
12023                         "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12024                         "pipeline_instructions[%u].jmp.b_val)",
12025                         jmp_instr_id,
12026                         jmp_instr_id);
12027                 break;
12028
12029         default:
12030                 break;
12031         }
12032
12033         /* Find the instruction group of the jump instruction. */
12034         jmp_g = instruction_group_list_group_find(igl, jmp_instr_id);
12035         if (!jmp_g)
12036                 return -EINVAL;
12037
12038         /* Find the instruction group of the jump destination instruction. */
12039         data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label);
12040         if (!data)
12041                 return -EINVAL;
12042
12043         instr_id = data - p->instruction_data;
12044
12045         g = instruction_group_list_group_find(igl, instr_id);
12046         if (!g)
12047                 return -EINVAL;
12048
12049         /* Code generation for "near" jump (same instruction group) or "far" jump (different
12050          * instruction group).
12051          */
12052         if (g->group_id == jmp_g->group_id)
12053                 fprintf(f,
12054                         "\n\t\tgoto %s;\n",
12055                         jmp_data->jmp_label);
12056         else
12057                 fprintf(f,
12058                         " {\n"
12059                         "\t\tthread_ip_set(t, &p->instructions[%u]);\n"
12060                         "\t\treturn;\n"
12061                         "\t}\n\n",
12062                         g->group_id);
12063
12064         return 0;
12065 }
12066
12067 static void
12068 instruction_group_list_codegen(struct instruction_group_list *igl,
12069                                struct rte_swx_pipeline *p,
12070                                FILE *f)
12071 {
12072         struct instruction_group *g;
12073         uint32_t i;
12074         int is_required = 0;
12075
12076         /* Check if code generation is required. */
12077         TAILQ_FOREACH(g, igl, node)
12078                 if (g->first_instr_id < g->last_instr_id)
12079                         is_required = 1;
12080
12081         if (!is_required)
12082                 return;
12083
12084         /* Generate the code for the pipeline instruction array. */
12085         fprintf(f,
12086                 "static const struct instruction pipeline_instructions[] = {\n");
12087
12088         for (i = 0; i < p->n_instructions; i++) {
12089                 struct instruction *instr = &p->instructions[i];
12090                 instruction_export_t func = export_table[instr->type];
12091
12092                 func(instr, f);
12093         }
12094
12095         fprintf(f, "};\n\n");
12096
12097         /* Generate the code for the pipeline functions: one function for each instruction group
12098          * that contains more than one instruction.
12099          */
12100         TAILQ_FOREACH(g, igl, node) {
12101                 struct instruction *last_instr;
12102                 uint32_t j;
12103
12104                 /* Skip if group contains a single instruction. */
12105                 if (g->last_instr_id == g->first_instr_id)
12106                         continue;
12107
12108                 /* Generate new pipeline function. */
12109                 fprintf(f,
12110                         "void\n"
12111                         "pipeline_func_%u(struct rte_swx_pipeline *p)\n"
12112                         "{\n"
12113                         "\tstruct thread *t = &p->threads[p->thread_id];\n"
12114                         "\n",
12115                         g->group_id);
12116
12117                 /* Generate the code for each pipeline instruction. */
12118                 for (j = g->first_instr_id; j <= g->last_instr_id; j++) {
12119                         struct instruction *instr = &p->instructions[j];
12120                         struct instruction_data *data = &p->instruction_data[j];
12121
12122                         /* Label, if present. */
12123                         if (data->label[0])
12124                                 fprintf(f, "\n%s : ", data->label);
12125                         else
12126                                 fprintf(f, "\n\t");
12127
12128                         /* TX instruction type. */
12129                         if (instruction_does_tx(instr)) {
12130                                 pipeline_instr_does_tx_codegen(p, j, instr, f);
12131                                 continue;
12132                         }
12133
12134                         /* Jump instruction type. */
12135                         if (instruction_is_jmp(instr)) {
12136                                 pipeline_instr_jmp_codegen(p, igl, j, instr, data, f);
12137                                 continue;
12138                         }
12139
12140                         /* Any other instruction type. */
12141                         fprintf(f,
12142                                 "%s(p, t, &pipeline_instructions[%u]);\n",
12143                                 instr_type_to_func(instr),
12144                                 j);
12145                 }
12146
12147                 /* Finalize the generated pipeline function. For some instructions such as TX,
12148                  * emit-many-and-TX and unconditional jump, the next instruction has been already
12149                  * decided unconditionally and the instruction pointer of the current thread set
12150                  * accordingly; for all the other instructions, the instruction pointer must be
12151                  * incremented now.
12152                  */
12153                 last_instr = &p->instructions[g->last_instr_id];
12154
12155                 if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP))
12156                         fprintf(f,
12157                                 "thread_ip_inc(p);\n");
12158
12159                 fprintf(f,
12160                         "}\n"
12161                         "\n");
12162         }
12163 }
12164
12165 static uint32_t
12166 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl)
12167 {
12168         struct instruction_group *g;
12169         uint32_t n_custom_instr = 0;
12170
12171         /* Groups with a single instruction: no function is generated for this group, the group
12172          * keeps its current instruction. Groups with more than two instructions: one function and
12173          * the associated custom instruction get generated for each such group.
12174          */
12175         TAILQ_FOREACH(g, igl, node) {
12176                 if (g->first_instr_id == g->last_instr_id)
12177                         continue;
12178
12179                 n_custom_instr++;
12180         }
12181
12182         return n_custom_instr;
12183 }
12184
12185 static int
12186 pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12187 {
12188         struct action *a;
12189         FILE *f = NULL;
12190
12191         /* Create the .c file. */
12192         f = fopen("/tmp/pipeline.c", "w");
12193         if (!f)
12194                 return -EIO;
12195
12196         /* Include the .h file. */
12197         fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
12198
12199         /* Add the code for each action. */
12200         TAILQ_FOREACH(a, &p->actions, node) {
12201                 fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
12202
12203                 action_data_codegen(a, f);
12204
12205                 fprintf(f, "\n");
12206
12207                 action_instr_codegen(a, f);
12208
12209                 fprintf(f, "\n");
12210         }
12211
12212         /* Add the pipeline code. */
12213         instruction_group_list_codegen(igl, p, f);
12214
12215         /* Close the .c file. */
12216         fclose(f);
12217
12218         return 0;
12219 }
12220
12221 #ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
12222 #define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
12223 #endif
12224
12225 static int
12226 pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12227 {
12228         struct action *a;
12229         struct instruction_group *g;
12230         char *dir_in, *buffer = NULL;
12231         const char *dir_out;
12232         int status = 0;
12233
12234         /* Get the environment variables. */
12235         dir_in = getenv("RTE_INSTALL_DIR");
12236         if (!dir_in) {
12237                 status = -EINVAL;
12238                 goto free;
12239         }
12240
12241         dir_out = "/tmp";
12242
12243         /* Memory allocation for the command buffer. */
12244         buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
12245         if (!buffer) {
12246                 status = -ENOMEM;
12247                 goto free;
12248         }
12249
12250         snprintf(buffer,
12251                  RTE_SWX_PIPELINE_CMD_MAX_SIZE,
12252                  "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
12253                  "-I %s/lib/pipeline "
12254                  "-I %s/lib/eal/include "
12255                  "-I %s/lib/eal/x86/include "
12256                  "-I %s/lib/eal/include/generic "
12257                  "-I %s/lib/meter "
12258                  "-I %s/lib/port "
12259                  "-I %s/lib/table "
12260                  "-I %s/lib/pipeline "
12261                  "-I %s/config "
12262                  "-I %s/build "
12263                  "-I %s/lib/eal/linux/include "
12264                  ">%s/pipeline.log 2>&1 "
12265                  "&& "
12266                  "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
12267                  ">>%s/pipeline.log 2>&1",
12268                  dir_out,
12269                  dir_out,
12270                  dir_in,
12271                  dir_in,
12272                  dir_in,
12273                  dir_in,
12274                  dir_in,
12275                  dir_in,
12276                  dir_in,
12277                  dir_in,
12278                  dir_in,
12279                  dir_in,
12280                  dir_in,
12281                  dir_out,
12282                  dir_out,
12283                  dir_out,
12284                  dir_out);
12285
12286         /* Build the shared object library. */
12287         status = system(buffer);
12288         if (status)
12289                 goto free;
12290
12291         /* Open library. */
12292         snprintf(buffer,
12293                  RTE_SWX_PIPELINE_CMD_MAX_SIZE,
12294                  "%s/libpipeline.so",
12295                  dir_out);
12296
12297         p->lib = dlopen(buffer, RTLD_LAZY);
12298         if (!p->lib) {
12299                 status = -EIO;
12300                 goto free;
12301         }
12302
12303         /* Get the action function symbols. */
12304         TAILQ_FOREACH(a, &p->actions, node) {
12305                 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
12306
12307                 p->action_funcs[a->id] = dlsym(p->lib, buffer);
12308                 if (!p->action_funcs[a->id]) {
12309                         status = -EINVAL;
12310                         goto free;
12311                 }
12312         }
12313
12314         /* Get the pipeline function symbols. */
12315         TAILQ_FOREACH(g, igl, node) {
12316                 if (g->first_instr_id == g->last_instr_id)
12317                         continue;
12318
12319                 snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
12320
12321                 g->func = dlsym(p->lib, buffer);
12322                 if (!g->func) {
12323                         status = -EINVAL;
12324                         goto free;
12325                 }
12326         }
12327
12328 free:
12329         if (status && p->lib) {
12330                 dlclose(p->lib);
12331                 p->lib = NULL;
12332         }
12333
12334         free(buffer);
12335
12336         return status;
12337 }
12338
12339 static int
12340 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
12341                       struct instruction_group_list *igl)
12342 {
12343         uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl);
12344
12345         /* Check that enough space is available within the pipeline instruction table to store all
12346          * the custom instructions.
12347          */
12348         if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX)
12349                 return -ENOSPC;
12350
12351         return 0;
12352 }
12353
12354 static void
12355 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12356 {
12357         struct instruction_group *g;
12358         uint32_t i;
12359
12360         /* Pipeline table instructions. */
12361         for (i = 0; i < p->n_instructions; i++) {
12362                 struct instruction *instr = &p->instructions[i];
12363
12364                 if (instr->type == INSTR_TABLE)
12365                         instr->type = INSTR_TABLE_AF;
12366
12367                 if (instr->type == INSTR_LEARNER)
12368                         instr->type = INSTR_LEARNER_AF;
12369         }
12370
12371         /* Pipeline custom instructions. */
12372         i = 0;
12373         TAILQ_FOREACH(g, igl, node) {
12374                 struct instruction *instr = &p->instructions[g->first_instr_id];
12375                 uint32_t j;
12376
12377                 if (g->first_instr_id == g->last_instr_id)
12378                         continue;
12379
12380                 /* Install a new custom instruction. */
12381                 p->instruction_table[INSTR_CUSTOM_0 + i] = g->func;
12382
12383                 /* First instruction of the group: change its type to the new custom instruction. */
12384                 instr->type = INSTR_CUSTOM_0 + i;
12385
12386                 /* All the subsequent instructions of the group: invalidate. */
12387                 for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) {
12388                         struct instruction_data *data = &p->instruction_data[j];
12389
12390                         data->invalid = 1;
12391                 }
12392
12393                 i++;
12394         }
12395
12396         /* Remove the invalidated instructions. */
12397         p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions);
12398
12399         /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump
12400          * instructions that are the only instruction within their group, so they were left
12401          * unmodified).
12402          */
12403         instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
12404 }
12405
12406 static int
12407 pipeline_compile(struct rte_swx_pipeline *p)
12408 {
12409         struct instruction_group_list *igl = NULL;
12410         int status = 0;
12411
12412         igl = instruction_group_list_create(p);
12413         if (!igl) {
12414                 status = -ENOMEM;
12415                 goto free;
12416         }
12417
12418         /* Code generation. */
12419         status = pipeline_codegen(p, igl);
12420         if (status)
12421                 goto free;
12422
12423         /* Build and load the shared object library. */
12424         status = pipeline_libload(p, igl);
12425         if (status)
12426                 goto free;
12427
12428         /* Adjust instructions. */
12429         status = pipeline_adjust_check(p, igl);
12430         if (status)
12431                 goto free;
12432
12433         pipeline_adjust(p, igl);
12434
12435 free:
12436         instruction_group_list_free(igl);
12437
12438         return status;
12439 }