1
2
3
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <sys/queue.h>
10#include <arpa/inet.h>
11
12#include <rte_common.h>
13#include <rte_prefetch.h>
14#include <rte_byteorder.h>
15
16#include "rte_swx_pipeline.h"
17#include "rte_swx_ctl.h"
18
19#define CHECK(condition, err_code) \
20do { \
21 if (!(condition)) \
22 return -(err_code); \
23} while (0)
24
25#define CHECK_NAME(name, err_code) \
26 CHECK((name) && \
27 (name)[0] && \
28 (strnlen((name), RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), \
29 err_code)
30
31#define CHECK_INSTRUCTION(instr, err_code) \
32 CHECK((instr) && \
33 (instr)[0] && \
34 (strnlen((instr), RTE_SWX_INSTRUCTION_SIZE) < \
35 RTE_SWX_INSTRUCTION_SIZE), \
36 err_code)
37
38#ifndef TRACE_LEVEL
39#define TRACE_LEVEL 0
40#endif
41
42#if TRACE_LEVEL
43#define TRACE(...) printf(__VA_ARGS__)
44#else
45#define TRACE(...)
46#endif
47
48#define ntoh64(x) rte_be_to_cpu_64(x)
49#define hton64(x) rte_cpu_to_be_64(x)
50
51
52
53
54struct field {
55 char name[RTE_SWX_NAME_SIZE];
56 uint32_t n_bits;
57 uint32_t offset;
58};
59
60struct struct_type {
61 TAILQ_ENTRY(struct_type) node;
62 char name[RTE_SWX_NAME_SIZE];
63 struct field *fields;
64 uint32_t n_fields;
65 uint32_t n_bits;
66};
67
68TAILQ_HEAD(struct_type_tailq, struct_type);
69
70
71
72
73struct port_in_type {
74 TAILQ_ENTRY(port_in_type) node;
75 char name[RTE_SWX_NAME_SIZE];
76 struct rte_swx_port_in_ops ops;
77};
78
79TAILQ_HEAD(port_in_type_tailq, port_in_type);
80
81struct port_in {
82 TAILQ_ENTRY(port_in) node;
83 struct port_in_type *type;
84 void *obj;
85 uint32_t id;
86};
87
88TAILQ_HEAD(port_in_tailq, port_in);
89
90struct port_in_runtime {
91 rte_swx_port_in_pkt_rx_t pkt_rx;
92 void *obj;
93};
94
95
96
97
98struct port_out_type {
99 TAILQ_ENTRY(port_out_type) node;
100 char name[RTE_SWX_NAME_SIZE];
101 struct rte_swx_port_out_ops ops;
102};
103
104TAILQ_HEAD(port_out_type_tailq, port_out_type);
105
106struct port_out {
107 TAILQ_ENTRY(port_out) node;
108 struct port_out_type *type;
109 void *obj;
110 uint32_t id;
111};
112
113TAILQ_HEAD(port_out_tailq, port_out);
114
115struct port_out_runtime {
116 rte_swx_port_out_pkt_tx_t pkt_tx;
117 rte_swx_port_out_flush_t flush;
118 void *obj;
119};
120
121
122
123
124struct extern_type_member_func {
125 TAILQ_ENTRY(extern_type_member_func) node;
126 char name[RTE_SWX_NAME_SIZE];
127 rte_swx_extern_type_member_func_t func;
128 uint32_t id;
129};
130
131TAILQ_HEAD(extern_type_member_func_tailq, extern_type_member_func);
132
133struct extern_type {
134 TAILQ_ENTRY(extern_type) node;
135 char name[RTE_SWX_NAME_SIZE];
136 struct struct_type *mailbox_struct_type;
137 rte_swx_extern_type_constructor_t constructor;
138 rte_swx_extern_type_destructor_t destructor;
139 struct extern_type_member_func_tailq funcs;
140 uint32_t n_funcs;
141};
142
143TAILQ_HEAD(extern_type_tailq, extern_type);
144
145struct extern_obj {
146 TAILQ_ENTRY(extern_obj) node;
147 char name[RTE_SWX_NAME_SIZE];
148 struct extern_type *type;
149 void *obj;
150 uint32_t struct_id;
151 uint32_t id;
152};
153
154TAILQ_HEAD(extern_obj_tailq, extern_obj);
155
156#ifndef RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX
157#define RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX 8
158#endif
159
160struct extern_obj_runtime {
161 void *obj;
162 uint8_t *mailbox;
163 rte_swx_extern_type_member_func_t funcs[RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX];
164};
165
166
167
168
169struct extern_func {
170 TAILQ_ENTRY(extern_func) node;
171 char name[RTE_SWX_NAME_SIZE];
172 struct struct_type *mailbox_struct_type;
173 rte_swx_extern_func_t func;
174 uint32_t struct_id;
175 uint32_t id;
176};
177
178TAILQ_HEAD(extern_func_tailq, extern_func);
179
180struct extern_func_runtime {
181 uint8_t *mailbox;
182 rte_swx_extern_func_t func;
183};
184
185
186
187
188struct header {
189 TAILQ_ENTRY(header) node;
190 char name[RTE_SWX_NAME_SIZE];
191 struct struct_type *st;
192 uint32_t struct_id;
193 uint32_t id;
194};
195
196TAILQ_HEAD(header_tailq, header);
197
198struct header_runtime {
199 uint8_t *ptr0;
200};
201
202struct header_out_runtime {
203 uint8_t *ptr0;
204 uint8_t *ptr;
205 uint32_t n_bytes;
206};
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228enum instruction_type {
229
230 INSTR_RX,
231
232
233 INSTR_TX,
234
235
236 INSTR_HDR_EXTRACT,
237 INSTR_HDR_EXTRACT2,
238 INSTR_HDR_EXTRACT3,
239 INSTR_HDR_EXTRACT4,
240 INSTR_HDR_EXTRACT5,
241 INSTR_HDR_EXTRACT6,
242 INSTR_HDR_EXTRACT7,
243 INSTR_HDR_EXTRACT8,
244
245
246 INSTR_HDR_EMIT,
247 INSTR_HDR_EMIT_TX,
248 INSTR_HDR_EMIT2_TX,
249 INSTR_HDR_EMIT3_TX,
250 INSTR_HDR_EMIT4_TX,
251 INSTR_HDR_EMIT5_TX,
252 INSTR_HDR_EMIT6_TX,
253 INSTR_HDR_EMIT7_TX,
254 INSTR_HDR_EMIT8_TX,
255
256
257 INSTR_HDR_VALIDATE,
258
259
260 INSTR_HDR_INVALIDATE,
261
262
263
264
265
266 INSTR_MOV,
267 INSTR_MOV_S,
268 INSTR_MOV_I,
269
270
271
272
273 INSTR_DMA_HT,
274 INSTR_DMA_HT2,
275 INSTR_DMA_HT3,
276 INSTR_DMA_HT4,
277 INSTR_DMA_HT5,
278 INSTR_DMA_HT6,
279 INSTR_DMA_HT7,
280 INSTR_DMA_HT8,
281
282
283
284
285
286 INSTR_ALU_ADD,
287 INSTR_ALU_ADD_MH,
288 INSTR_ALU_ADD_HM,
289 INSTR_ALU_ADD_HH,
290 INSTR_ALU_ADD_MI,
291 INSTR_ALU_ADD_HI,
292
293
294
295
296
297 INSTR_ALU_SUB,
298 INSTR_ALU_SUB_MH,
299 INSTR_ALU_SUB_HM,
300 INSTR_ALU_SUB_HH,
301 INSTR_ALU_SUB_MI,
302 INSTR_ALU_SUB_HI,
303
304
305
306
307
308 INSTR_ALU_CKADD_FIELD,
309 INSTR_ALU_CKADD_STRUCT20,
310 INSTR_ALU_CKADD_STRUCT,
311
312
313
314
315
316 INSTR_ALU_CKSUB_FIELD,
317
318
319
320
321
322 INSTR_ALU_AND,
323 INSTR_ALU_AND_S,
324 INSTR_ALU_AND_I,
325
326
327
328
329
330 INSTR_ALU_OR,
331 INSTR_ALU_OR_S,
332 INSTR_ALU_OR_I,
333
334
335
336
337
338 INSTR_ALU_XOR,
339 INSTR_ALU_XOR_S,
340 INSTR_ALU_XOR_I,
341
342
343
344
345
346 INSTR_ALU_SHL,
347 INSTR_ALU_SHL_MH,
348 INSTR_ALU_SHL_HM,
349 INSTR_ALU_SHL_HH,
350 INSTR_ALU_SHL_MI,
351 INSTR_ALU_SHL_HI,
352
353
354
355
356
357 INSTR_ALU_SHR,
358 INSTR_ALU_SHR_MH,
359 INSTR_ALU_SHR_HM,
360 INSTR_ALU_SHR_HH,
361 INSTR_ALU_SHR_MI,
362 INSTR_ALU_SHR_HI,
363
364
365 INSTR_TABLE,
366
367
368 INSTR_EXTERN_OBJ,
369
370
371 INSTR_EXTERN_FUNC,
372
373
374
375
376 INSTR_JMP,
377
378
379
380
381 INSTR_JMP_VALID,
382
383
384
385
386 INSTR_JMP_INVALID,
387
388
389
390
391 INSTR_JMP_HIT,
392
393
394
395
396 INSTR_JMP_MISS,
397
398
399
400
401 INSTR_JMP_ACTION_HIT,
402
403
404
405
406 INSTR_JMP_ACTION_MISS,
407
408
409
410
411
412 INSTR_JMP_EQ,
413 INSTR_JMP_EQ_S,
414 INSTR_JMP_EQ_I,
415
416
417
418
419
420 INSTR_JMP_NEQ,
421 INSTR_JMP_NEQ_S,
422 INSTR_JMP_NEQ_I,
423
424
425
426
427
428 INSTR_JMP_LT,
429 INSTR_JMP_LT_MH,
430 INSTR_JMP_LT_HM,
431 INSTR_JMP_LT_HH,
432 INSTR_JMP_LT_MI,
433 INSTR_JMP_LT_HI,
434
435
436
437
438
439 INSTR_JMP_GT,
440 INSTR_JMP_GT_MH,
441 INSTR_JMP_GT_HM,
442 INSTR_JMP_GT_HH,
443 INSTR_JMP_GT_MI,
444 INSTR_JMP_GT_HI,
445
446
447
448
449 INSTR_RETURN,
450};
451
452struct instr_operand {
453 uint8_t struct_id;
454 uint8_t n_bits;
455 uint8_t offset;
456 uint8_t pad;
457};
458
459struct instr_io {
460 struct {
461 uint8_t offset;
462 uint8_t n_bits;
463 uint8_t pad[2];
464 } io;
465
466 struct {
467 uint8_t header_id[8];
468 uint8_t struct_id[8];
469 uint8_t n_bytes[8];
470 } hdr;
471};
472
473struct instr_hdr_validity {
474 uint8_t header_id;
475};
476
477struct instr_table {
478 uint8_t table_id;
479};
480
481struct instr_extern_obj {
482 uint8_t ext_obj_id;
483 uint8_t func_id;
484};
485
486struct instr_extern_func {
487 uint8_t ext_func_id;
488};
489
490struct instr_dst_src {
491 struct instr_operand dst;
492 union {
493 struct instr_operand src;
494 uint64_t src_val;
495 };
496};
497
498struct instr_dma {
499 struct {
500 uint8_t header_id[8];
501 uint8_t struct_id[8];
502 } dst;
503
504 struct {
505 uint8_t offset[8];
506 } src;
507
508 uint16_t n_bytes[8];
509};
510
511struct instr_jmp {
512 struct instruction *ip;
513
514 union {
515 struct instr_operand a;
516 uint8_t header_id;
517 uint8_t action_id;
518 };
519
520 union {
521 struct instr_operand b;
522 uint64_t b_val;
523 };
524};
525
526struct instruction {
527 enum instruction_type type;
528 union {
529 struct instr_io io;
530 struct instr_hdr_validity valid;
531 struct instr_dst_src mov;
532 struct instr_dma dma;
533 struct instr_dst_src alu;
534 struct instr_table table;
535 struct instr_extern_obj ext_obj;
536 struct instr_extern_func ext_func;
537 struct instr_jmp jmp;
538 };
539};
540
541struct instruction_data {
542 char label[RTE_SWX_NAME_SIZE];
543 char jmp_label[RTE_SWX_NAME_SIZE];
544 uint32_t n_users;
545 int invalid;
546};
547
548
549
550
551struct action {
552 TAILQ_ENTRY(action) node;
553 char name[RTE_SWX_NAME_SIZE];
554 struct struct_type *st;
555 struct instruction *instructions;
556 uint32_t n_instructions;
557 uint32_t id;
558};
559
560TAILQ_HEAD(action_tailq, action);
561
562
563
564
565struct table_type {
566 TAILQ_ENTRY(table_type) node;
567 char name[RTE_SWX_NAME_SIZE];
568 enum rte_swx_table_match_type match_type;
569 struct rte_swx_table_ops ops;
570};
571
572TAILQ_HEAD(table_type_tailq, table_type);
573
574struct match_field {
575 enum rte_swx_table_match_type match_type;
576 struct field *field;
577};
578
579struct table {
580 TAILQ_ENTRY(table) node;
581 char name[RTE_SWX_NAME_SIZE];
582 char args[RTE_SWX_NAME_SIZE];
583 struct table_type *type;
584
585
586 struct match_field *fields;
587 uint32_t n_fields;
588 int is_header;
589 struct header *header;
590
591
592 struct action **actions;
593 struct action *default_action;
594 uint8_t *default_action_data;
595 uint32_t n_actions;
596 int default_action_is_const;
597 uint32_t action_data_size_max;
598
599 uint32_t size;
600 uint32_t id;
601};
602
603TAILQ_HEAD(table_tailq, table);
604
605struct table_runtime {
606 rte_swx_table_lookup_t func;
607 void *mailbox;
608 uint8_t **key;
609};
610
611
612
613
614struct thread {
615
616 struct rte_swx_pkt pkt;
617 uint8_t *ptr;
618
619
620 uint8_t **structs;
621
622
623 struct header_runtime *headers;
624 struct header_out_runtime *headers_out;
625 uint8_t *header_storage;
626 uint8_t *header_out_storage;
627 uint64_t valid_headers;
628 uint32_t n_headers_out;
629
630
631 uint8_t *metadata;
632
633
634 struct table_runtime *tables;
635 struct rte_swx_table_state *table_state;
636 uint64_t action_id;
637 int hit;
638
639
640 struct extern_obj_runtime *extern_objs;
641 struct extern_func_runtime *extern_funcs;
642
643
644 struct instruction *ip;
645 struct instruction *ret;
646};
647
648#define MASK64_BIT_GET(mask, pos) ((mask) & (1LLU << (pos)))
649#define MASK64_BIT_SET(mask, pos) ((mask) | (1LLU << (pos)))
650#define MASK64_BIT_CLR(mask, pos) ((mask) & ~(1LLU << (pos)))
651
652#define HEADER_VALID(thread, header_id) \
653 MASK64_BIT_GET((thread)->valid_headers, header_id)
654
655#define ALU(thread, ip, operator) \
656{ \
657 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
658 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
659 uint64_t dst64 = *dst64_ptr; \
660 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
661 uint64_t dst = dst64 & dst64_mask; \
662 \
663 uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id]; \
664 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset]; \
665 uint64_t src64 = *src64_ptr; \
666 uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits); \
667 uint64_t src = src64 & src64_mask; \
668 \
669 uint64_t result = dst operator src; \
670 \
671 *dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask); \
672}
673
674#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
675
676#define ALU_S(thread, ip, operator) \
677{ \
678 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
679 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
680 uint64_t dst64 = *dst64_ptr; \
681 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
682 uint64_t dst = dst64 & dst64_mask; \
683 \
684 uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id]; \
685 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset]; \
686 uint64_t src64 = *src64_ptr; \
687 uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits); \
688 \
689 uint64_t result = dst operator src; \
690 \
691 *dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask); \
692}
693
694#define ALU_MH ALU_S
695
696#define ALU_HM(thread, ip, operator) \
697{ \
698 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
699 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
700 uint64_t dst64 = *dst64_ptr; \
701 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
702 uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits); \
703 \
704 uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id]; \
705 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset]; \
706 uint64_t src64 = *src64_ptr; \
707 uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits); \
708 uint64_t src = src64 & src64_mask; \
709 \
710 uint64_t result = dst operator src; \
711 result = hton64(result << (64 - (ip)->alu.dst.n_bits)); \
712 \
713 *dst64_ptr = (dst64 & ~dst64_mask) | result; \
714}
715
716#define ALU_HH(thread, ip, operator) \
717{ \
718 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
719 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
720 uint64_t dst64 = *dst64_ptr; \
721 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
722 uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits); \
723 \
724 uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id]; \
725 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset]; \
726 uint64_t src64 = *src64_ptr; \
727 uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits); \
728 \
729 uint64_t result = dst operator src; \
730 result = hton64(result << (64 - (ip)->alu.dst.n_bits)); \
731 \
732 *dst64_ptr = (dst64 & ~dst64_mask) | result; \
733}
734
735#else
736
737#define ALU_S ALU
738#define ALU_MH ALU
739#define ALU_HM ALU
740#define ALU_HH ALU
741
742#endif
743
744#define ALU_I(thread, ip, operator) \
745{ \
746 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
747 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
748 uint64_t dst64 = *dst64_ptr; \
749 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
750 uint64_t dst = dst64 & dst64_mask; \
751 \
752 uint64_t src = (ip)->alu.src_val; \
753 \
754 uint64_t result = dst operator src; \
755 \
756 *dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask); \
757}
758
759#define ALU_MI ALU_I
760
761#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
762
763#define ALU_HI(thread, ip, operator) \
764{ \
765 uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id]; \
766 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset]; \
767 uint64_t dst64 = *dst64_ptr; \
768 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits); \
769 uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits); \
770 \
771 uint64_t src = (ip)->alu.src_val; \
772 \
773 uint64_t result = dst operator src; \
774 result = hton64(result << (64 - (ip)->alu.dst.n_bits)); \
775 \
776 *dst64_ptr = (dst64 & ~dst64_mask) | result; \
777}
778
779#else
780
781#define ALU_HI ALU_I
782
783#endif
784
785#define MOV(thread, ip) \
786{ \
787 uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id]; \
788 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset]; \
789 uint64_t dst64 = *dst64_ptr; \
790 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits); \
791 \
792 uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id]; \
793 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset]; \
794 uint64_t src64 = *src64_ptr; \
795 uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->mov.src.n_bits); \
796 uint64_t src = src64 & src64_mask; \
797 \
798 *dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask); \
799}
800
801#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
802
803#define MOV_S(thread, ip) \
804{ \
805 uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id]; \
806 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset]; \
807 uint64_t dst64 = *dst64_ptr; \
808 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits); \
809 \
810 uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id]; \
811 uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset]; \
812 uint64_t src64 = *src64_ptr; \
813 uint64_t src = ntoh64(src64) >> (64 - (ip)->mov.src.n_bits); \
814 \
815 *dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask); \
816}
817
818#else
819
820#define MOV_S MOV
821
822#endif
823
824#define MOV_I(thread, ip) \
825{ \
826 uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id]; \
827 uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset]; \
828 uint64_t dst64 = *dst64_ptr; \
829 uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits); \
830 \
831 uint64_t src = (ip)->mov.src_val; \
832 \
833 *dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask); \
834}
835
836#define JMP_CMP(thread, ip, operator) \
837{ \
838 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
839 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
840 uint64_t a64 = *a64_ptr; \
841 uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits); \
842 uint64_t a = a64 & a64_mask; \
843 \
844 uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id]; \
845 uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset]; \
846 uint64_t b64 = *b64_ptr; \
847 uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits); \
848 uint64_t b = b64 & b64_mask; \
849 \
850 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
851}
852
853#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
854
855#define JMP_CMP_S(thread, ip, operator) \
856{ \
857 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
858 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
859 uint64_t a64 = *a64_ptr; \
860 uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits); \
861 uint64_t a = a64 & a64_mask; \
862 \
863 uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id]; \
864 uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset]; \
865 uint64_t b64 = *b64_ptr; \
866 uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits); \
867 \
868 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
869}
870
871#define JMP_CMP_MH JMP_CMP_S
872
873#define JMP_CMP_HM(thread, ip, operator) \
874{ \
875 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
876 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
877 uint64_t a64 = *a64_ptr; \
878 uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits); \
879 \
880 uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id]; \
881 uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset]; \
882 uint64_t b64 = *b64_ptr; \
883 uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits); \
884 uint64_t b = b64 & b64_mask; \
885 \
886 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
887}
888
889#define JMP_CMP_HH(thread, ip, operator) \
890{ \
891 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
892 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
893 uint64_t a64 = *a64_ptr; \
894 uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits); \
895 \
896 uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id]; \
897 uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset]; \
898 uint64_t b64 = *b64_ptr; \
899 uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits); \
900 \
901 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
902}
903
904#else
905
906#define JMP_CMP_S JMP_CMP
907#define JMP_CMP_MH JMP_CMP
908#define JMP_CMP_HM JMP_CMP
909#define JMP_CMP_HH JMP_CMP
910
911#endif
912
913#define JMP_CMP_I(thread, ip, operator) \
914{ \
915 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
916 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
917 uint64_t a64 = *a64_ptr; \
918 uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits); \
919 uint64_t a = a64 & a64_mask; \
920 \
921 uint64_t b = (ip)->jmp.b_val; \
922 \
923 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
924}
925
926#define JMP_CMP_MI JMP_CMP_I
927
928#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
929
930#define JMP_CMP_HI(thread, ip, operator) \
931{ \
932 uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id]; \
933 uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset]; \
934 uint64_t a64 = *a64_ptr; \
935 uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits); \
936 \
937 uint64_t b = (ip)->jmp.b_val; \
938 \
939 (thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1); \
940}
941
942#else
943
944#define JMP_CMP_HI JMP_CMP_I
945
946#endif
947
948#define METADATA_READ(thread, offset, n_bits) \
949({ \
950 uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset]; \
951 uint64_t m64 = *m64_ptr; \
952 uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits)); \
953 (m64 & m64_mask); \
954})
955
956#define METADATA_WRITE(thread, offset, n_bits, value) \
957{ \
958 uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset]; \
959 uint64_t m64 = *m64_ptr; \
960 uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits)); \
961 \
962 uint64_t m_new = value; \
963 \
964 *m64_ptr = (m64 & ~m64_mask) | (m_new & m64_mask); \
965}
966
967#ifndef RTE_SWX_PIPELINE_THREADS_MAX
968#define RTE_SWX_PIPELINE_THREADS_MAX 16
969#endif
970
971struct rte_swx_pipeline {
972 struct struct_type_tailq struct_types;
973 struct port_in_type_tailq port_in_types;
974 struct port_in_tailq ports_in;
975 struct port_out_type_tailq port_out_types;
976 struct port_out_tailq ports_out;
977 struct extern_type_tailq extern_types;
978 struct extern_obj_tailq extern_objs;
979 struct extern_func_tailq extern_funcs;
980 struct header_tailq headers;
981 struct struct_type *metadata_st;
982 uint32_t metadata_struct_id;
983 struct action_tailq actions;
984 struct table_type_tailq table_types;
985 struct table_tailq tables;
986
987 struct port_in_runtime *in;
988 struct port_out_runtime *out;
989 struct instruction **action_instructions;
990 struct rte_swx_table_state *table_state;
991 struct instruction *instructions;
992 struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
993
994 uint32_t n_structs;
995 uint32_t n_ports_in;
996 uint32_t n_ports_out;
997 uint32_t n_extern_objs;
998 uint32_t n_extern_funcs;
999 uint32_t n_actions;
1000 uint32_t n_tables;
1001 uint32_t n_headers;
1002 uint32_t thread_id;
1003 uint32_t port_id;
1004 uint32_t n_instructions;
1005 int build_done;
1006 int numa_node;
1007};
1008
1009
1010
1011
1012static struct struct_type *
1013struct_type_find(struct rte_swx_pipeline *p, const char *name)
1014{
1015 struct struct_type *elem;
1016
1017 TAILQ_FOREACH(elem, &p->struct_types, node)
1018 if (strcmp(elem->name, name) == 0)
1019 return elem;
1020
1021 return NULL;
1022}
1023
1024static struct field *
1025struct_type_field_find(struct struct_type *st, const char *name)
1026{
1027 uint32_t i;
1028
1029 for (i = 0; i < st->n_fields; i++) {
1030 struct field *f = &st->fields[i];
1031
1032 if (strcmp(f->name, name) == 0)
1033 return f;
1034 }
1035
1036 return NULL;
1037}
1038
1039int
1040rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
1041 const char *name,
1042 struct rte_swx_field_params *fields,
1043 uint32_t n_fields)
1044{
1045 struct struct_type *st;
1046 uint32_t i;
1047
1048 CHECK(p, EINVAL);
1049 CHECK_NAME(name, EINVAL);
1050 CHECK(fields, EINVAL);
1051 CHECK(n_fields, EINVAL);
1052
1053 for (i = 0; i < n_fields; i++) {
1054 struct rte_swx_field_params *f = &fields[i];
1055 uint32_t j;
1056
1057 CHECK_NAME(f->name, EINVAL);
1058 CHECK(f->n_bits, EINVAL);
1059 CHECK(f->n_bits <= 64, EINVAL);
1060 CHECK((f->n_bits & 7) == 0, EINVAL);
1061
1062 for (j = 0; j < i; j++) {
1063 struct rte_swx_field_params *f_prev = &fields[j];
1064
1065 CHECK(strcmp(f->name, f_prev->name), EINVAL);
1066 }
1067 }
1068
1069 CHECK(!struct_type_find(p, name), EEXIST);
1070
1071
1072 st = calloc(1, sizeof(struct struct_type));
1073 CHECK(st, ENOMEM);
1074
1075 st->fields = calloc(n_fields, sizeof(struct field));
1076 if (!st->fields) {
1077 free(st);
1078 CHECK(0, ENOMEM);
1079 }
1080
1081
1082 strcpy(st->name, name);
1083 for (i = 0; i < n_fields; i++) {
1084 struct field *dst = &st->fields[i];
1085 struct rte_swx_field_params *src = &fields[i];
1086
1087 strcpy(dst->name, src->name);
1088 dst->n_bits = src->n_bits;
1089 dst->offset = st->n_bits;
1090
1091 st->n_bits += src->n_bits;
1092 }
1093 st->n_fields = n_fields;
1094
1095
1096 TAILQ_INSERT_TAIL(&p->struct_types, st, node);
1097
1098 return 0;
1099}
1100
1101static int
1102struct_build(struct rte_swx_pipeline *p)
1103{
1104 uint32_t i;
1105
1106 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1107 struct thread *t = &p->threads[i];
1108
1109 t->structs = calloc(p->n_structs, sizeof(uint8_t *));
1110 CHECK(t->structs, ENOMEM);
1111 }
1112
1113 return 0;
1114}
1115
1116static void
1117struct_build_free(struct rte_swx_pipeline *p)
1118{
1119 uint32_t i;
1120
1121 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1122 struct thread *t = &p->threads[i];
1123
1124 free(t->structs);
1125 t->structs = NULL;
1126 }
1127}
1128
1129static void
1130struct_free(struct rte_swx_pipeline *p)
1131{
1132 struct_build_free(p);
1133
1134
1135 for ( ; ; ) {
1136 struct struct_type *elem;
1137
1138 elem = TAILQ_FIRST(&p->struct_types);
1139 if (!elem)
1140 break;
1141
1142 TAILQ_REMOVE(&p->struct_types, elem, node);
1143 free(elem->fields);
1144 free(elem);
1145 }
1146}
1147
1148
1149
1150
1151static struct port_in_type *
1152port_in_type_find(struct rte_swx_pipeline *p, const char *name)
1153{
1154 struct port_in_type *elem;
1155
1156 if (!name)
1157 return NULL;
1158
1159 TAILQ_FOREACH(elem, &p->port_in_types, node)
1160 if (strcmp(elem->name, name) == 0)
1161 return elem;
1162
1163 return NULL;
1164}
1165
1166int
1167rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
1168 const char *name,
1169 struct rte_swx_port_in_ops *ops)
1170{
1171 struct port_in_type *elem;
1172
1173 CHECK(p, EINVAL);
1174 CHECK_NAME(name, EINVAL);
1175 CHECK(ops, EINVAL);
1176 CHECK(ops->create, EINVAL);
1177 CHECK(ops->free, EINVAL);
1178 CHECK(ops->pkt_rx, EINVAL);
1179 CHECK(ops->stats_read, EINVAL);
1180
1181 CHECK(!port_in_type_find(p, name), EEXIST);
1182
1183
1184 elem = calloc(1, sizeof(struct port_in_type));
1185 CHECK(elem, ENOMEM);
1186
1187
1188 strcpy(elem->name, name);
1189 memcpy(&elem->ops, ops, sizeof(*ops));
1190
1191
1192 TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
1193
1194 return 0;
1195}
1196
1197static struct port_in *
1198port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
1199{
1200 struct port_in *port;
1201
1202 TAILQ_FOREACH(port, &p->ports_in, node)
1203 if (port->id == port_id)
1204 return port;
1205
1206 return NULL;
1207}
1208
1209int
1210rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
1211 uint32_t port_id,
1212 const char *port_type_name,
1213 void *args)
1214{
1215 struct port_in_type *type = NULL;
1216 struct port_in *port = NULL;
1217 void *obj = NULL;
1218
1219 CHECK(p, EINVAL);
1220
1221 CHECK(!port_in_find(p, port_id), EINVAL);
1222
1223 CHECK_NAME(port_type_name, EINVAL);
1224 type = port_in_type_find(p, port_type_name);
1225 CHECK(type, EINVAL);
1226
1227 obj = type->ops.create(args);
1228 CHECK(obj, ENODEV);
1229
1230
1231 port = calloc(1, sizeof(struct port_in));
1232 CHECK(port, ENOMEM);
1233
1234
1235 port->type = type;
1236 port->obj = obj;
1237 port->id = port_id;
1238
1239
1240 TAILQ_INSERT_TAIL(&p->ports_in, port, node);
1241 if (p->n_ports_in < port_id + 1)
1242 p->n_ports_in = port_id + 1;
1243
1244 return 0;
1245}
1246
1247static int
1248port_in_build(struct rte_swx_pipeline *p)
1249{
1250 struct port_in *port;
1251 uint32_t i;
1252
1253 CHECK(p->n_ports_in, EINVAL);
1254 CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
1255
1256 for (i = 0; i < p->n_ports_in; i++)
1257 CHECK(port_in_find(p, i), EINVAL);
1258
1259 p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
1260 CHECK(p->in, ENOMEM);
1261
1262 TAILQ_FOREACH(port, &p->ports_in, node) {
1263 struct port_in_runtime *in = &p->in[port->id];
1264
1265 in->pkt_rx = port->type->ops.pkt_rx;
1266 in->obj = port->obj;
1267 }
1268
1269 return 0;
1270}
1271
1272static void
1273port_in_build_free(struct rte_swx_pipeline *p)
1274{
1275 free(p->in);
1276 p->in = NULL;
1277}
1278
1279static void
1280port_in_free(struct rte_swx_pipeline *p)
1281{
1282 port_in_build_free(p);
1283
1284
1285 for ( ; ; ) {
1286 struct port_in *port;
1287
1288 port = TAILQ_FIRST(&p->ports_in);
1289 if (!port)
1290 break;
1291
1292 TAILQ_REMOVE(&p->ports_in, port, node);
1293 port->type->ops.free(port->obj);
1294 free(port);
1295 }
1296
1297
1298 for ( ; ; ) {
1299 struct port_in_type *elem;
1300
1301 elem = TAILQ_FIRST(&p->port_in_types);
1302 if (!elem)
1303 break;
1304
1305 TAILQ_REMOVE(&p->port_in_types, elem, node);
1306 free(elem);
1307 }
1308}
1309
1310
1311
1312
1313static struct port_out_type *
1314port_out_type_find(struct rte_swx_pipeline *p, const char *name)
1315{
1316 struct port_out_type *elem;
1317
1318 if (!name)
1319 return NULL;
1320
1321 TAILQ_FOREACH(elem, &p->port_out_types, node)
1322 if (!strcmp(elem->name, name))
1323 return elem;
1324
1325 return NULL;
1326}
1327
1328int
1329rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
1330 const char *name,
1331 struct rte_swx_port_out_ops *ops)
1332{
1333 struct port_out_type *elem;
1334
1335 CHECK(p, EINVAL);
1336 CHECK_NAME(name, EINVAL);
1337 CHECK(ops, EINVAL);
1338 CHECK(ops->create, EINVAL);
1339 CHECK(ops->free, EINVAL);
1340 CHECK(ops->pkt_tx, EINVAL);
1341 CHECK(ops->stats_read, EINVAL);
1342
1343 CHECK(!port_out_type_find(p, name), EEXIST);
1344
1345
1346 elem = calloc(1, sizeof(struct port_out_type));
1347 CHECK(elem, ENOMEM);
1348
1349
1350 strcpy(elem->name, name);
1351 memcpy(&elem->ops, ops, sizeof(*ops));
1352
1353
1354 TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
1355
1356 return 0;
1357}
1358
1359static struct port_out *
1360port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
1361{
1362 struct port_out *port;
1363
1364 TAILQ_FOREACH(port, &p->ports_out, node)
1365 if (port->id == port_id)
1366 return port;
1367
1368 return NULL;
1369}
1370
1371int
1372rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
1373 uint32_t port_id,
1374 const char *port_type_name,
1375 void *args)
1376{
1377 struct port_out_type *type = NULL;
1378 struct port_out *port = NULL;
1379 void *obj = NULL;
1380
1381 CHECK(p, EINVAL);
1382
1383 CHECK(!port_out_find(p, port_id), EINVAL);
1384
1385 CHECK_NAME(port_type_name, EINVAL);
1386 type = port_out_type_find(p, port_type_name);
1387 CHECK(type, EINVAL);
1388
1389 obj = type->ops.create(args);
1390 CHECK(obj, ENODEV);
1391
1392
1393 port = calloc(1, sizeof(struct port_out));
1394 CHECK(port, ENOMEM);
1395
1396
1397 port->type = type;
1398 port->obj = obj;
1399 port->id = port_id;
1400
1401
1402 TAILQ_INSERT_TAIL(&p->ports_out, port, node);
1403 if (p->n_ports_out < port_id + 1)
1404 p->n_ports_out = port_id + 1;
1405
1406 return 0;
1407}
1408
1409static int
1410port_out_build(struct rte_swx_pipeline *p)
1411{
1412 struct port_out *port;
1413 uint32_t i;
1414
1415 CHECK(p->n_ports_out, EINVAL);
1416
1417 for (i = 0; i < p->n_ports_out; i++)
1418 CHECK(port_out_find(p, i), EINVAL);
1419
1420 p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
1421 CHECK(p->out, ENOMEM);
1422
1423 TAILQ_FOREACH(port, &p->ports_out, node) {
1424 struct port_out_runtime *out = &p->out[port->id];
1425
1426 out->pkt_tx = port->type->ops.pkt_tx;
1427 out->flush = port->type->ops.flush;
1428 out->obj = port->obj;
1429 }
1430
1431 return 0;
1432}
1433
1434static void
1435port_out_build_free(struct rte_swx_pipeline *p)
1436{
1437 free(p->out);
1438 p->out = NULL;
1439}
1440
1441static void
1442port_out_free(struct rte_swx_pipeline *p)
1443{
1444 port_out_build_free(p);
1445
1446
1447 for ( ; ; ) {
1448 struct port_out *port;
1449
1450 port = TAILQ_FIRST(&p->ports_out);
1451 if (!port)
1452 break;
1453
1454 TAILQ_REMOVE(&p->ports_out, port, node);
1455 port->type->ops.free(port->obj);
1456 free(port);
1457 }
1458
1459
1460 for ( ; ; ) {
1461 struct port_out_type *elem;
1462
1463 elem = TAILQ_FIRST(&p->port_out_types);
1464 if (!elem)
1465 break;
1466
1467 TAILQ_REMOVE(&p->port_out_types, elem, node);
1468 free(elem);
1469 }
1470}
1471
1472
1473
1474
1475static struct extern_type *
1476extern_type_find(struct rte_swx_pipeline *p, const char *name)
1477{
1478 struct extern_type *elem;
1479
1480 TAILQ_FOREACH(elem, &p->extern_types, node)
1481 if (strcmp(elem->name, name) == 0)
1482 return elem;
1483
1484 return NULL;
1485}
1486
1487static struct extern_type_member_func *
1488extern_type_member_func_find(struct extern_type *type, const char *name)
1489{
1490 struct extern_type_member_func *elem;
1491
1492 TAILQ_FOREACH(elem, &type->funcs, node)
1493 if (strcmp(elem->name, name) == 0)
1494 return elem;
1495
1496 return NULL;
1497}
1498
1499static struct extern_obj *
1500extern_obj_find(struct rte_swx_pipeline *p, const char *name)
1501{
1502 struct extern_obj *elem;
1503
1504 TAILQ_FOREACH(elem, &p->extern_objs, node)
1505 if (strcmp(elem->name, name) == 0)
1506 return elem;
1507
1508 return NULL;
1509}
1510
1511static struct extern_type_member_func *
1512extern_obj_member_func_parse(struct rte_swx_pipeline *p,
1513 const char *name,
1514 struct extern_obj **obj)
1515{
1516 struct extern_obj *object;
1517 struct extern_type_member_func *func;
1518 char *object_name, *func_name;
1519
1520 if (name[0] != 'e' || name[1] != '.')
1521 return NULL;
1522
1523 object_name = strdup(&name[2]);
1524 if (!object_name)
1525 return NULL;
1526
1527 func_name = strchr(object_name, '.');
1528 if (!func_name) {
1529 free(object_name);
1530 return NULL;
1531 }
1532
1533 *func_name = 0;
1534 func_name++;
1535
1536 object = extern_obj_find(p, object_name);
1537 if (!object) {
1538 free(object_name);
1539 return NULL;
1540 }
1541
1542 func = extern_type_member_func_find(object->type, func_name);
1543 if (!func) {
1544 free(object_name);
1545 return NULL;
1546 }
1547
1548 if (obj)
1549 *obj = object;
1550
1551 free(object_name);
1552 return func;
1553}
1554
1555static struct field *
1556extern_obj_mailbox_field_parse(struct rte_swx_pipeline *p,
1557 const char *name,
1558 struct extern_obj **object)
1559{
1560 struct extern_obj *obj;
1561 struct field *f;
1562 char *obj_name, *field_name;
1563
1564 if ((name[0] != 'e') || (name[1] != '.'))
1565 return NULL;
1566
1567 obj_name = strdup(&name[2]);
1568 if (!obj_name)
1569 return NULL;
1570
1571 field_name = strchr(obj_name, '.');
1572 if (!field_name) {
1573 free(obj_name);
1574 return NULL;
1575 }
1576
1577 *field_name = 0;
1578 field_name++;
1579
1580 obj = extern_obj_find(p, obj_name);
1581 if (!obj) {
1582 free(obj_name);
1583 return NULL;
1584 }
1585
1586 f = struct_type_field_find(obj->type->mailbox_struct_type, field_name);
1587 if (!f) {
1588 free(obj_name);
1589 return NULL;
1590 }
1591
1592 if (object)
1593 *object = obj;
1594
1595 free(obj_name);
1596 return f;
1597}
1598
1599int
1600rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p,
1601 const char *name,
1602 const char *mailbox_struct_type_name,
1603 rte_swx_extern_type_constructor_t constructor,
1604 rte_swx_extern_type_destructor_t destructor)
1605{
1606 struct extern_type *elem;
1607 struct struct_type *mailbox_struct_type;
1608
1609 CHECK(p, EINVAL);
1610
1611 CHECK_NAME(name, EINVAL);
1612 CHECK(!extern_type_find(p, name), EEXIST);
1613
1614 CHECK_NAME(mailbox_struct_type_name, EINVAL);
1615 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
1616 CHECK(mailbox_struct_type, EINVAL);
1617
1618 CHECK(constructor, EINVAL);
1619 CHECK(destructor, EINVAL);
1620
1621
1622 elem = calloc(1, sizeof(struct extern_type));
1623 CHECK(elem, ENOMEM);
1624
1625
1626 strcpy(elem->name, name);
1627 elem->mailbox_struct_type = mailbox_struct_type;
1628 elem->constructor = constructor;
1629 elem->destructor = destructor;
1630 TAILQ_INIT(&elem->funcs);
1631
1632
1633 TAILQ_INSERT_TAIL(&p->extern_types, elem, node);
1634
1635 return 0;
1636}
1637
1638int
1639rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p,
1640 const char *extern_type_name,
1641 const char *name,
1642 rte_swx_extern_type_member_func_t member_func)
1643{
1644 struct extern_type *type;
1645 struct extern_type_member_func *type_member;
1646
1647 CHECK(p, EINVAL);
1648
1649 CHECK_NAME(extern_type_name, EINVAL);
1650 type = extern_type_find(p, extern_type_name);
1651 CHECK(type, EINVAL);
1652 CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC);
1653
1654 CHECK_NAME(name, EINVAL);
1655 CHECK(!extern_type_member_func_find(type, name), EEXIST);
1656
1657 CHECK(member_func, EINVAL);
1658
1659
1660 type_member = calloc(1, sizeof(struct extern_type_member_func));
1661 CHECK(type_member, ENOMEM);
1662
1663
1664 strcpy(type_member->name, name);
1665 type_member->func = member_func;
1666 type_member->id = type->n_funcs;
1667
1668
1669 TAILQ_INSERT_TAIL(&type->funcs, type_member, node);
1670 type->n_funcs++;
1671
1672 return 0;
1673}
1674
1675int
1676rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p,
1677 const char *extern_type_name,
1678 const char *name,
1679 const char *args)
1680{
1681 struct extern_type *type;
1682 struct extern_obj *obj;
1683 void *obj_handle;
1684
1685 CHECK(p, EINVAL);
1686
1687 CHECK_NAME(extern_type_name, EINVAL);
1688 type = extern_type_find(p, extern_type_name);
1689 CHECK(type, EINVAL);
1690
1691 CHECK_NAME(name, EINVAL);
1692 CHECK(!extern_obj_find(p, name), EEXIST);
1693
1694
1695 obj = calloc(1, sizeof(struct extern_obj));
1696 CHECK(obj, ENOMEM);
1697
1698
1699 obj_handle = type->constructor(args);
1700 if (!obj_handle) {
1701 free(obj);
1702 CHECK(0, ENODEV);
1703 }
1704
1705
1706 strcpy(obj->name, name);
1707 obj->type = type;
1708 obj->obj = obj_handle;
1709 obj->struct_id = p->n_structs;
1710 obj->id = p->n_extern_objs;
1711
1712
1713 TAILQ_INSERT_TAIL(&p->extern_objs, obj, node);
1714 p->n_extern_objs++;
1715 p->n_structs++;
1716
1717 return 0;
1718}
1719
1720static int
1721extern_obj_build(struct rte_swx_pipeline *p)
1722{
1723 uint32_t i;
1724
1725 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1726 struct thread *t = &p->threads[i];
1727 struct extern_obj *obj;
1728
1729 t->extern_objs = calloc(p->n_extern_objs,
1730 sizeof(struct extern_obj_runtime));
1731 CHECK(t->extern_objs, ENOMEM);
1732
1733 TAILQ_FOREACH(obj, &p->extern_objs, node) {
1734 struct extern_obj_runtime *r =
1735 &t->extern_objs[obj->id];
1736 struct extern_type_member_func *func;
1737 uint32_t mailbox_size =
1738 obj->type->mailbox_struct_type->n_bits / 8;
1739
1740 r->obj = obj->obj;
1741
1742 r->mailbox = calloc(1, mailbox_size);
1743 CHECK(r->mailbox, ENOMEM);
1744
1745 TAILQ_FOREACH(func, &obj->type->funcs, node)
1746 r->funcs[func->id] = func->func;
1747
1748 t->structs[obj->struct_id] = r->mailbox;
1749 }
1750 }
1751
1752 return 0;
1753}
1754
1755static void
1756extern_obj_build_free(struct rte_swx_pipeline *p)
1757{
1758 uint32_t i;
1759
1760 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1761 struct thread *t = &p->threads[i];
1762 uint32_t j;
1763
1764 if (!t->extern_objs)
1765 continue;
1766
1767 for (j = 0; j < p->n_extern_objs; j++) {
1768 struct extern_obj_runtime *r = &t->extern_objs[j];
1769
1770 free(r->mailbox);
1771 }
1772
1773 free(t->extern_objs);
1774 t->extern_objs = NULL;
1775 }
1776}
1777
1778static void
1779extern_obj_free(struct rte_swx_pipeline *p)
1780{
1781 extern_obj_build_free(p);
1782
1783
1784 for ( ; ; ) {
1785 struct extern_obj *elem;
1786
1787 elem = TAILQ_FIRST(&p->extern_objs);
1788 if (!elem)
1789 break;
1790
1791 TAILQ_REMOVE(&p->extern_objs, elem, node);
1792 if (elem->obj)
1793 elem->type->destructor(elem->obj);
1794 free(elem);
1795 }
1796
1797
1798 for ( ; ; ) {
1799 struct extern_type *elem;
1800
1801 elem = TAILQ_FIRST(&p->extern_types);
1802 if (!elem)
1803 break;
1804
1805 TAILQ_REMOVE(&p->extern_types, elem, node);
1806
1807 for ( ; ; ) {
1808 struct extern_type_member_func *func;
1809
1810 func = TAILQ_FIRST(&elem->funcs);
1811 if (!func)
1812 break;
1813
1814 TAILQ_REMOVE(&elem->funcs, func, node);
1815 free(func);
1816 }
1817
1818 free(elem);
1819 }
1820}
1821
1822
1823
1824
1825static struct extern_func *
1826extern_func_find(struct rte_swx_pipeline *p, const char *name)
1827{
1828 struct extern_func *elem;
1829
1830 TAILQ_FOREACH(elem, &p->extern_funcs, node)
1831 if (strcmp(elem->name, name) == 0)
1832 return elem;
1833
1834 return NULL;
1835}
1836
1837static struct extern_func *
1838extern_func_parse(struct rte_swx_pipeline *p,
1839 const char *name)
1840{
1841 if (name[0] != 'f' || name[1] != '.')
1842 return NULL;
1843
1844 return extern_func_find(p, &name[2]);
1845}
1846
1847static struct field *
1848extern_func_mailbox_field_parse(struct rte_swx_pipeline *p,
1849 const char *name,
1850 struct extern_func **function)
1851{
1852 struct extern_func *func;
1853 struct field *f;
1854 char *func_name, *field_name;
1855
1856 if ((name[0] != 'f') || (name[1] != '.'))
1857 return NULL;
1858
1859 func_name = strdup(&name[2]);
1860 if (!func_name)
1861 return NULL;
1862
1863 field_name = strchr(func_name, '.');
1864 if (!field_name) {
1865 free(func_name);
1866 return NULL;
1867 }
1868
1869 *field_name = 0;
1870 field_name++;
1871
1872 func = extern_func_find(p, func_name);
1873 if (!func) {
1874 free(func_name);
1875 return NULL;
1876 }
1877
1878 f = struct_type_field_find(func->mailbox_struct_type, field_name);
1879 if (!f) {
1880 free(func_name);
1881 return NULL;
1882 }
1883
1884 if (function)
1885 *function = func;
1886
1887 free(func_name);
1888 return f;
1889}
1890
1891int
1892rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p,
1893 const char *name,
1894 const char *mailbox_struct_type_name,
1895 rte_swx_extern_func_t func)
1896{
1897 struct extern_func *f;
1898 struct struct_type *mailbox_struct_type;
1899
1900 CHECK(p, EINVAL);
1901
1902 CHECK_NAME(name, EINVAL);
1903 CHECK(!extern_func_find(p, name), EEXIST);
1904
1905 CHECK_NAME(mailbox_struct_type_name, EINVAL);
1906 mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
1907 CHECK(mailbox_struct_type, EINVAL);
1908
1909 CHECK(func, EINVAL);
1910
1911
1912 f = calloc(1, sizeof(struct extern_func));
1913 CHECK(func, ENOMEM);
1914
1915
1916 strcpy(f->name, name);
1917 f->mailbox_struct_type = mailbox_struct_type;
1918 f->func = func;
1919 f->struct_id = p->n_structs;
1920 f->id = p->n_extern_funcs;
1921
1922
1923 TAILQ_INSERT_TAIL(&p->extern_funcs, f, node);
1924 p->n_extern_funcs++;
1925 p->n_structs++;
1926
1927 return 0;
1928}
1929
1930static int
1931extern_func_build(struct rte_swx_pipeline *p)
1932{
1933 uint32_t i;
1934
1935 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1936 struct thread *t = &p->threads[i];
1937 struct extern_func *func;
1938
1939
1940 t->extern_funcs = calloc(p->n_extern_funcs,
1941 sizeof(struct extern_func_runtime));
1942 CHECK(t->extern_funcs, ENOMEM);
1943
1944
1945 TAILQ_FOREACH(func, &p->extern_funcs, node) {
1946 struct extern_func_runtime *r =
1947 &t->extern_funcs[func->id];
1948 uint32_t mailbox_size =
1949 func->mailbox_struct_type->n_bits / 8;
1950
1951 r->func = func->func;
1952
1953 r->mailbox = calloc(1, mailbox_size);
1954 CHECK(r->mailbox, ENOMEM);
1955
1956 t->structs[func->struct_id] = r->mailbox;
1957 }
1958 }
1959
1960 return 0;
1961}
1962
1963static void
1964extern_func_build_free(struct rte_swx_pipeline *p)
1965{
1966 uint32_t i;
1967
1968 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1969 struct thread *t = &p->threads[i];
1970 uint32_t j;
1971
1972 if (!t->extern_funcs)
1973 continue;
1974
1975 for (j = 0; j < p->n_extern_funcs; j++) {
1976 struct extern_func_runtime *r = &t->extern_funcs[j];
1977
1978 free(r->mailbox);
1979 }
1980
1981 free(t->extern_funcs);
1982 t->extern_funcs = NULL;
1983 }
1984}
1985
1986static void
1987extern_func_free(struct rte_swx_pipeline *p)
1988{
1989 extern_func_build_free(p);
1990
1991 for ( ; ; ) {
1992 struct extern_func *elem;
1993
1994 elem = TAILQ_FIRST(&p->extern_funcs);
1995 if (!elem)
1996 break;
1997
1998 TAILQ_REMOVE(&p->extern_funcs, elem, node);
1999 free(elem);
2000 }
2001}
2002
2003
2004
2005
2006static struct header *
2007header_find(struct rte_swx_pipeline *p, const char *name)
2008{
2009 struct header *elem;
2010
2011 TAILQ_FOREACH(elem, &p->headers, node)
2012 if (strcmp(elem->name, name) == 0)
2013 return elem;
2014
2015 return NULL;
2016}
2017
2018static struct header *
2019header_parse(struct rte_swx_pipeline *p,
2020 const char *name)
2021{
2022 if (name[0] != 'h' || name[1] != '.')
2023 return NULL;
2024
2025 return header_find(p, &name[2]);
2026}
2027
2028static struct field *
2029header_field_parse(struct rte_swx_pipeline *p,
2030 const char *name,
2031 struct header **header)
2032{
2033 struct header *h;
2034 struct field *f;
2035 char *header_name, *field_name;
2036
2037 if ((name[0] != 'h') || (name[1] != '.'))
2038 return NULL;
2039
2040 header_name = strdup(&name[2]);
2041 if (!header_name)
2042 return NULL;
2043
2044 field_name = strchr(header_name, '.');
2045 if (!field_name) {
2046 free(header_name);
2047 return NULL;
2048 }
2049
2050 *field_name = 0;
2051 field_name++;
2052
2053 h = header_find(p, header_name);
2054 if (!h) {
2055 free(header_name);
2056 return NULL;
2057 }
2058
2059 f = struct_type_field_find(h->st, field_name);
2060 if (!f) {
2061 free(header_name);
2062 return NULL;
2063 }
2064
2065 if (header)
2066 *header = h;
2067
2068 free(header_name);
2069 return f;
2070}
2071
2072int
2073rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
2074 const char *name,
2075 const char *struct_type_name)
2076{
2077 struct struct_type *st;
2078 struct header *h;
2079 size_t n_headers_max;
2080
2081 CHECK(p, EINVAL);
2082 CHECK_NAME(name, EINVAL);
2083 CHECK_NAME(struct_type_name, EINVAL);
2084
2085 CHECK(!header_find(p, name), EEXIST);
2086
2087 st = struct_type_find(p, struct_type_name);
2088 CHECK(st, EINVAL);
2089
2090 n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
2091 CHECK(p->n_headers < n_headers_max, ENOSPC);
2092
2093
2094 h = calloc(1, sizeof(struct header));
2095 CHECK(h, ENOMEM);
2096
2097
2098 strcpy(h->name, name);
2099 h->st = st;
2100 h->struct_id = p->n_structs;
2101 h->id = p->n_headers;
2102
2103
2104 TAILQ_INSERT_TAIL(&p->headers, h, node);
2105 p->n_headers++;
2106 p->n_structs++;
2107
2108 return 0;
2109}
2110
2111static int
2112header_build(struct rte_swx_pipeline *p)
2113{
2114 struct header *h;
2115 uint32_t n_bytes = 0, i;
2116
2117 TAILQ_FOREACH(h, &p->headers, node) {
2118 n_bytes += h->st->n_bits / 8;
2119 }
2120
2121 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
2122 struct thread *t = &p->threads[i];
2123 uint32_t offset = 0;
2124
2125 t->headers = calloc(p->n_headers,
2126 sizeof(struct header_runtime));
2127 CHECK(t->headers, ENOMEM);
2128
2129 t->headers_out = calloc(p->n_headers,
2130 sizeof(struct header_out_runtime));
2131 CHECK(t->headers_out, ENOMEM);
2132
2133 t->header_storage = calloc(1, n_bytes);
2134 CHECK(t->header_storage, ENOMEM);
2135
2136 t->header_out_storage = calloc(1, n_bytes);
2137 CHECK(t->header_out_storage, ENOMEM);
2138
2139 TAILQ_FOREACH(h, &p->headers, node) {
2140 uint8_t *header_storage;
2141
2142 header_storage = &t->header_storage[offset];
2143 offset += h->st->n_bits / 8;
2144
2145 t->headers[h->id].ptr0 = header_storage;
2146 t->structs[h->struct_id] = header_storage;
2147 }
2148 }
2149
2150 return 0;
2151}
2152
2153static void
2154header_build_free(struct rte_swx_pipeline *p)
2155{
2156 uint32_t i;
2157
2158 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
2159 struct thread *t = &p->threads[i];
2160
2161 free(t->headers_out);
2162 t->headers_out = NULL;
2163
2164 free(t->headers);
2165 t->headers = NULL;
2166
2167 free(t->header_out_storage);
2168 t->header_out_storage = NULL;
2169
2170 free(t->header_storage);
2171 t->header_storage = NULL;
2172 }
2173}
2174
2175static void
2176header_free(struct rte_swx_pipeline *p)
2177{
2178 header_build_free(p);
2179
2180 for ( ; ; ) {
2181 struct header *elem;
2182
2183 elem = TAILQ_FIRST(&p->headers);
2184 if (!elem)
2185 break;
2186
2187 TAILQ_REMOVE(&p->headers, elem, node);
2188 free(elem);
2189 }
2190}
2191
2192
2193
2194
2195static struct field *
2196metadata_field_parse(struct rte_swx_pipeline *p, const char *name)
2197{
2198 if (!p->metadata_st)
2199 return NULL;
2200
2201 if (name[0] != 'm' || name[1] != '.')
2202 return NULL;
2203
2204 return struct_type_field_find(p->metadata_st, &name[2]);
2205}
2206
2207int
2208rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
2209 const char *struct_type_name)
2210{
2211 struct struct_type *st = NULL;
2212
2213 CHECK(p, EINVAL);
2214
2215 CHECK_NAME(struct_type_name, EINVAL);
2216 st = struct_type_find(p, struct_type_name);
2217 CHECK(st, EINVAL);
2218 CHECK(!p->metadata_st, EINVAL);
2219
2220 p->metadata_st = st;
2221 p->metadata_struct_id = p->n_structs;
2222
2223 p->n_structs++;
2224
2225 return 0;
2226}
2227
2228static int
2229metadata_build(struct rte_swx_pipeline *p)
2230{
2231 uint32_t n_bytes = p->metadata_st->n_bits / 8;
2232 uint32_t i;
2233
2234
2235 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
2236 struct thread *t = &p->threads[i];
2237 uint8_t *metadata;
2238
2239 metadata = calloc(1, n_bytes);
2240 CHECK(metadata, ENOMEM);
2241
2242 t->metadata = metadata;
2243 t->structs[p->metadata_struct_id] = metadata;
2244 }
2245
2246 return 0;
2247}
2248
2249static void
2250metadata_build_free(struct rte_swx_pipeline *p)
2251{
2252 uint32_t i;
2253
2254 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
2255 struct thread *t = &p->threads[i];
2256
2257 free(t->metadata);
2258 t->metadata = NULL;
2259 }
2260}
2261
2262static void
2263metadata_free(struct rte_swx_pipeline *p)
2264{
2265 metadata_build_free(p);
2266}
2267
2268
2269
2270
2271static int
2272instruction_is_jmp(struct instruction *instr)
2273{
2274 switch (instr->type) {
2275 case INSTR_JMP:
2276 case INSTR_JMP_VALID:
2277 case INSTR_JMP_INVALID:
2278 case INSTR_JMP_HIT:
2279 case INSTR_JMP_MISS:
2280 case INSTR_JMP_ACTION_HIT:
2281 case INSTR_JMP_ACTION_MISS:
2282 case INSTR_JMP_EQ:
2283 case INSTR_JMP_EQ_S:
2284 case INSTR_JMP_EQ_I:
2285 case INSTR_JMP_NEQ:
2286 case INSTR_JMP_NEQ_S:
2287 case INSTR_JMP_NEQ_I:
2288 case INSTR_JMP_LT:
2289 case INSTR_JMP_LT_MH:
2290 case INSTR_JMP_LT_HM:
2291 case INSTR_JMP_LT_HH:
2292 case INSTR_JMP_LT_MI:
2293 case INSTR_JMP_LT_HI:
2294 case INSTR_JMP_GT:
2295 case INSTR_JMP_GT_MH:
2296 case INSTR_JMP_GT_HM:
2297 case INSTR_JMP_GT_HH:
2298 case INSTR_JMP_GT_MI:
2299 case INSTR_JMP_GT_HI:
2300 return 1;
2301
2302 default:
2303 return 0;
2304 }
2305}
2306
2307static struct field *
2308action_field_parse(struct action *action, const char *name);
2309
2310static struct field *
2311struct_field_parse(struct rte_swx_pipeline *p,
2312 struct action *action,
2313 const char *name,
2314 uint32_t *struct_id)
2315{
2316 struct field *f;
2317
2318 switch (name[0]) {
2319 case 'h':
2320 {
2321 struct header *header;
2322
2323 f = header_field_parse(p, name, &header);
2324 if (!f)
2325 return NULL;
2326
2327 *struct_id = header->struct_id;
2328 return f;
2329 }
2330
2331 case 'm':
2332 {
2333 f = metadata_field_parse(p, name);
2334 if (!f)
2335 return NULL;
2336
2337 *struct_id = p->metadata_struct_id;
2338 return f;
2339 }
2340
2341 case 't':
2342 {
2343 if (!action)
2344 return NULL;
2345
2346 f = action_field_parse(action, name);
2347 if (!f)
2348 return NULL;
2349
2350 *struct_id = 0;
2351 return f;
2352 }
2353
2354 case 'e':
2355 {
2356 struct extern_obj *obj;
2357
2358 f = extern_obj_mailbox_field_parse(p, name, &obj);
2359 if (!f)
2360 return NULL;
2361
2362 *struct_id = obj->struct_id;
2363 return f;
2364 }
2365
2366 case 'f':
2367 {
2368 struct extern_func *func;
2369
2370 f = extern_func_mailbox_field_parse(p, name, &func);
2371 if (!f)
2372 return NULL;
2373
2374 *struct_id = func->struct_id;
2375 return f;
2376 }
2377
2378 default:
2379 return NULL;
2380 }
2381}
2382
2383static inline void
2384pipeline_port_inc(struct rte_swx_pipeline *p)
2385{
2386 p->port_id = (p->port_id + 1) & (p->n_ports_in - 1);
2387}
2388
2389static inline void
2390thread_ip_reset(struct rte_swx_pipeline *p, struct thread *t)
2391{
2392 t->ip = p->instructions;
2393}
2394
2395static inline void
2396thread_ip_set(struct thread *t, struct instruction *ip)
2397{
2398 t->ip = ip;
2399}
2400
2401static inline void
2402thread_ip_action_call(struct rte_swx_pipeline *p,
2403 struct thread *t,
2404 uint32_t action_id)
2405{
2406 t->ret = t->ip + 1;
2407 t->ip = p->action_instructions[action_id];
2408}
2409
2410static inline void
2411thread_ip_inc(struct rte_swx_pipeline *p);
2412
2413static inline void
2414thread_ip_inc(struct rte_swx_pipeline *p)
2415{
2416 struct thread *t = &p->threads[p->thread_id];
2417
2418 t->ip++;
2419}
2420
2421static inline void
2422thread_ip_inc_cond(struct thread *t, int cond)
2423{
2424 t->ip += cond;
2425}
2426
2427static inline void
2428thread_yield(struct rte_swx_pipeline *p)
2429{
2430 p->thread_id = (p->thread_id + 1) & (RTE_SWX_PIPELINE_THREADS_MAX - 1);
2431}
2432
2433static inline void
2434thread_yield_cond(struct rte_swx_pipeline *p, int cond)
2435{
2436 p->thread_id = (p->thread_id + cond) & (RTE_SWX_PIPELINE_THREADS_MAX - 1);
2437}
2438
2439
2440
2441
2442static int
2443instr_rx_translate(struct rte_swx_pipeline *p,
2444 struct action *action,
2445 char **tokens,
2446 int n_tokens,
2447 struct instruction *instr,
2448 struct instruction_data *data __rte_unused)
2449{
2450 struct field *f;
2451
2452 CHECK(!action, EINVAL);
2453 CHECK(n_tokens == 2, EINVAL);
2454
2455 f = metadata_field_parse(p, tokens[1]);
2456 CHECK(f, EINVAL);
2457
2458 instr->type = INSTR_RX;
2459 instr->io.io.offset = f->offset / 8;
2460 instr->io.io.n_bits = f->n_bits;
2461 return 0;
2462}
2463
2464static inline void
2465instr_rx_exec(struct rte_swx_pipeline *p);
2466
2467static inline void
2468instr_rx_exec(struct rte_swx_pipeline *p)
2469{
2470 struct thread *t = &p->threads[p->thread_id];
2471 struct instruction *ip = t->ip;
2472 struct port_in_runtime *port = &p->in[p->port_id];
2473 struct rte_swx_pkt *pkt = &t->pkt;
2474 int pkt_received;
2475
2476
2477 pkt_received = port->pkt_rx(port->obj, pkt);
2478 t->ptr = &pkt->pkt[pkt->offset];
2479 rte_prefetch0(t->ptr);
2480
2481 TRACE("[Thread %2u] rx %s from port %u\n",
2482 p->thread_id,
2483 pkt_received ? "1 pkt" : "0 pkts",
2484 p->port_id);
2485
2486
2487 t->valid_headers = 0;
2488 t->n_headers_out = 0;
2489
2490
2491 METADATA_WRITE(t, ip->io.io.offset, ip->io.io.n_bits, p->port_id);
2492
2493
2494 t->table_state = p->table_state;
2495
2496
2497 pipeline_port_inc(p);
2498 thread_ip_inc_cond(t, pkt_received);
2499 thread_yield(p);
2500}
2501
2502
2503
2504
2505static int
2506instr_tx_translate(struct rte_swx_pipeline *p,
2507 struct action *action __rte_unused,
2508 char **tokens,
2509 int n_tokens,
2510 struct instruction *instr,
2511 struct instruction_data *data __rte_unused)
2512{
2513 struct field *f;
2514
2515 CHECK(n_tokens == 2, EINVAL);
2516
2517 f = metadata_field_parse(p, tokens[1]);
2518 CHECK(f, EINVAL);
2519
2520 instr->type = INSTR_TX;
2521 instr->io.io.offset = f->offset / 8;
2522 instr->io.io.n_bits = f->n_bits;
2523 return 0;
2524}
2525
2526static inline void
2527emit_handler(struct thread *t)
2528{
2529 struct header_out_runtime *h0 = &t->headers_out[0];
2530 struct header_out_runtime *h1 = &t->headers_out[1];
2531 uint32_t offset = 0, i;
2532
2533
2534 if ((t->n_headers_out == 1) &&
2535 (h0->ptr + h0->n_bytes == t->ptr)) {
2536 TRACE("Emit handler: no header change or header decap.\n");
2537
2538 t->pkt.offset -= h0->n_bytes;
2539 t->pkt.length += h0->n_bytes;
2540
2541 return;
2542 }
2543
2544
2545 if ((t->n_headers_out == 2) &&
2546 (h1->ptr + h1->n_bytes == t->ptr) &&
2547 (h0->ptr == h0->ptr0)) {
2548 uint32_t offset;
2549
2550 TRACE("Emit handler: header encapsulation.\n");
2551
2552 offset = h0->n_bytes + h1->n_bytes;
2553 memcpy(t->ptr - offset, h0->ptr, h0->n_bytes);
2554 t->pkt.offset -= offset;
2555 t->pkt.length += offset;
2556
2557 return;
2558 }
2559
2560
2561
2562
2563
2564
2565
2566
2567 TRACE("Emit handler: complex case.\n");
2568
2569 for (i = 0; i < t->n_headers_out; i++) {
2570 struct header_out_runtime *h = &t->headers_out[i];
2571
2572 memcpy(&t->header_out_storage[offset], h->ptr, h->n_bytes);
2573 offset += h->n_bytes;
2574 }
2575
2576 if (offset) {
2577 memcpy(t->ptr - offset, t->header_out_storage, offset);
2578 t->pkt.offset -= offset;
2579 t->pkt.length += offset;
2580 }
2581}
2582
2583static inline void
2584instr_tx_exec(struct rte_swx_pipeline *p);
2585
2586static inline void
2587instr_tx_exec(struct rte_swx_pipeline *p)
2588{
2589 struct thread *t = &p->threads[p->thread_id];
2590 struct instruction *ip = t->ip;
2591 uint64_t port_id = METADATA_READ(t, ip->io.io.offset, ip->io.io.n_bits);
2592 struct port_out_runtime *port = &p->out[port_id];
2593 struct rte_swx_pkt *pkt = &t->pkt;
2594
2595 TRACE("[Thread %2u]: tx 1 pkt to port %u\n",
2596 p->thread_id,
2597 (uint32_t)port_id);
2598
2599
2600 emit_handler(t);
2601
2602
2603 port->pkt_tx(port->obj, pkt);
2604
2605
2606 thread_ip_reset(p, t);
2607 instr_rx_exec(p);
2608}
2609
2610
2611
2612
2613static int
2614instr_hdr_extract_translate(struct rte_swx_pipeline *p,
2615 struct action *action,
2616 char **tokens,
2617 int n_tokens,
2618 struct instruction *instr,
2619 struct instruction_data *data __rte_unused)
2620{
2621 struct header *h;
2622
2623 CHECK(!action, EINVAL);
2624 CHECK(n_tokens == 2, EINVAL);
2625
2626 h = header_parse(p, tokens[1]);
2627 CHECK(h, EINVAL);
2628
2629 instr->type = INSTR_HDR_EXTRACT;
2630 instr->io.hdr.header_id[0] = h->id;
2631 instr->io.hdr.struct_id[0] = h->struct_id;
2632 instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
2633 return 0;
2634}
2635
2636static inline void
2637__instr_hdr_extract_exec(struct rte_swx_pipeline *p, uint32_t n_extract);
2638
2639static inline void
2640__instr_hdr_extract_exec(struct rte_swx_pipeline *p, uint32_t n_extract)
2641{
2642 struct thread *t = &p->threads[p->thread_id];
2643 struct instruction *ip = t->ip;
2644 uint64_t valid_headers = t->valid_headers;
2645 uint8_t *ptr = t->ptr;
2646 uint32_t offset = t->pkt.offset;
2647 uint32_t length = t->pkt.length;
2648 uint32_t i;
2649
2650 for (i = 0; i < n_extract; i++) {
2651 uint32_t header_id = ip->io.hdr.header_id[i];
2652 uint32_t struct_id = ip->io.hdr.struct_id[i];
2653 uint32_t n_bytes = ip->io.hdr.n_bytes[i];
2654
2655 TRACE("[Thread %2u]: extract header %u (%u bytes)\n",
2656 p->thread_id,
2657 header_id,
2658 n_bytes);
2659
2660
2661 t->structs[struct_id] = ptr;
2662 valid_headers = MASK64_BIT_SET(valid_headers, header_id);
2663
2664
2665 offset += n_bytes;
2666 length -= n_bytes;
2667 ptr += n_bytes;
2668 }
2669
2670
2671 t->valid_headers = valid_headers;
2672
2673
2674 t->pkt.offset = offset;
2675 t->pkt.length = length;
2676 t->ptr = ptr;
2677}
2678
2679static inline void
2680instr_hdr_extract_exec(struct rte_swx_pipeline *p)
2681{
2682 __instr_hdr_extract_exec(p, 1);
2683
2684
2685 thread_ip_inc(p);
2686}
2687
2688static inline void
2689instr_hdr_extract2_exec(struct rte_swx_pipeline *p)
2690{
2691 TRACE("[Thread %2u] *** The next 2 instructions are fused. ***\n",
2692 p->thread_id);
2693
2694 __instr_hdr_extract_exec(p, 2);
2695
2696
2697 thread_ip_inc(p);
2698}
2699
2700static inline void
2701instr_hdr_extract3_exec(struct rte_swx_pipeline *p)
2702{
2703 TRACE("[Thread %2u] *** The next 3 instructions are fused. ***\n",
2704 p->thread_id);
2705
2706 __instr_hdr_extract_exec(p, 3);
2707
2708
2709 thread_ip_inc(p);
2710}
2711
2712static inline void
2713instr_hdr_extract4_exec(struct rte_swx_pipeline *p)
2714{
2715 TRACE("[Thread %2u] *** The next 4 instructions are fused. ***\n",
2716 p->thread_id);
2717
2718 __instr_hdr_extract_exec(p, 4);
2719
2720
2721 thread_ip_inc(p);
2722}
2723
2724static inline void
2725instr_hdr_extract5_exec(struct rte_swx_pipeline *p)
2726{
2727 TRACE("[Thread %2u] *** The next 5 instructions are fused. ***\n",
2728 p->thread_id);
2729
2730 __instr_hdr_extract_exec(p, 5);
2731
2732
2733 thread_ip_inc(p);
2734}
2735
2736static inline void
2737instr_hdr_extract6_exec(struct rte_swx_pipeline *p)
2738{
2739 TRACE("[Thread %2u] *** The next 6 instructions are fused. ***\n",
2740 p->thread_id);
2741
2742 __instr_hdr_extract_exec(p, 6);
2743
2744
2745 thread_ip_inc(p);
2746}
2747
2748static inline void
2749instr_hdr_extract7_exec(struct rte_swx_pipeline *p)
2750{
2751 TRACE("[Thread %2u] *** The next 7 instructions are fused. ***\n",
2752 p->thread_id);
2753
2754 __instr_hdr_extract_exec(p, 7);
2755
2756
2757 thread_ip_inc(p);
2758}
2759
2760static inline void
2761instr_hdr_extract8_exec(struct rte_swx_pipeline *p)
2762{
2763 TRACE("[Thread %2u] *** The next 8 instructions are fused. ***\n",
2764 p->thread_id);
2765
2766 __instr_hdr_extract_exec(p, 8);
2767
2768
2769 thread_ip_inc(p);
2770}
2771
2772
2773
2774
2775static int
2776instr_hdr_emit_translate(struct rte_swx_pipeline *p,
2777 struct action *action __rte_unused,
2778 char **tokens,
2779 int n_tokens,
2780 struct instruction *instr,
2781 struct instruction_data *data __rte_unused)
2782{
2783 struct header *h;
2784
2785 CHECK(n_tokens == 2, EINVAL);
2786
2787 h = header_parse(p, tokens[1]);
2788 CHECK(h, EINVAL);
2789
2790 instr->type = INSTR_HDR_EMIT;
2791 instr->io.hdr.header_id[0] = h->id;
2792 instr->io.hdr.struct_id[0] = h->struct_id;
2793 instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
2794 return 0;
2795}
2796
2797static inline void
2798__instr_hdr_emit_exec(struct rte_swx_pipeline *p, uint32_t n_emit);
2799
2800static inline void
2801__instr_hdr_emit_exec(struct rte_swx_pipeline *p, uint32_t n_emit)
2802{
2803 struct thread *t = &p->threads[p->thread_id];
2804 struct instruction *ip = t->ip;
2805 uint32_t n_headers_out = t->n_headers_out;
2806 struct header_out_runtime *ho = &t->headers_out[n_headers_out - 1];
2807 uint8_t *ho_ptr = NULL;
2808 uint32_t ho_nbytes = 0, i;
2809
2810 for (i = 0; i < n_emit; i++) {
2811 uint32_t header_id = ip->io.hdr.header_id[i];
2812 uint32_t struct_id = ip->io.hdr.struct_id[i];
2813 uint32_t n_bytes = ip->io.hdr.n_bytes[i];
2814
2815 struct header_runtime *hi = &t->headers[header_id];
2816 uint8_t *hi_ptr = t->structs[struct_id];
2817
2818 TRACE("[Thread %2u]: emit header %u\n",
2819 p->thread_id,
2820 header_id);
2821
2822
2823 if (!i) {
2824 if (!t->n_headers_out) {
2825 ho = &t->headers_out[0];
2826
2827 ho->ptr0 = hi->ptr0;
2828 ho->ptr = hi_ptr;
2829
2830 ho_ptr = hi_ptr;
2831 ho_nbytes = n_bytes;
2832
2833 n_headers_out = 1;
2834
2835 continue;
2836 } else {
2837 ho_ptr = ho->ptr;
2838 ho_nbytes = ho->n_bytes;
2839 }
2840 }
2841
2842 if (ho_ptr + ho_nbytes == hi_ptr) {
2843 ho_nbytes += n_bytes;
2844 } else {
2845 ho->n_bytes = ho_nbytes;
2846
2847 ho++;
2848 ho->ptr0 = hi->ptr0;
2849 ho->ptr = hi_ptr;
2850
2851 ho_ptr = hi_ptr;
2852 ho_nbytes = n_bytes;
2853
2854 n_headers_out++;
2855 }
2856 }
2857
2858 ho->n_bytes = ho_nbytes;
2859 t->n_headers_out = n_headers_out;
2860}
2861
2862static inline void
2863instr_hdr_emit_exec(struct rte_swx_pipeline *p)
2864{
2865 __instr_hdr_emit_exec(p, 1);
2866
2867
2868 thread_ip_inc(p);
2869}
2870
2871static inline void
2872instr_hdr_emit_tx_exec(struct rte_swx_pipeline *p)
2873{
2874 TRACE("[Thread %2u] *** The next 2 instructions are fused. ***\n",
2875 p->thread_id);
2876
2877 __instr_hdr_emit_exec(p, 1);
2878 instr_tx_exec(p);
2879}
2880
2881static inline void
2882instr_hdr_emit2_tx_exec(struct rte_swx_pipeline *p)
2883{
2884 TRACE("[Thread %2u] *** The next 3 instructions are fused. ***\n",
2885 p->thread_id);
2886
2887 __instr_hdr_emit_exec(p, 2);
2888 instr_tx_exec(p);
2889}
2890
2891static inline void
2892instr_hdr_emit3_tx_exec(struct rte_swx_pipeline *p)
2893{
2894 TRACE("[Thread %2u] *** The next 4 instructions are fused. ***\n",
2895 p->thread_id);
2896
2897 __instr_hdr_emit_exec(p, 3);
2898 instr_tx_exec(p);
2899}
2900
2901static inline void
2902instr_hdr_emit4_tx_exec(struct rte_swx_pipeline *p)
2903{
2904 TRACE("[Thread %2u] *** The next 5 instructions are fused. ***\n",
2905 p->thread_id);
2906
2907 __instr_hdr_emit_exec(p, 4);
2908 instr_tx_exec(p);
2909}
2910
2911static inline void
2912instr_hdr_emit5_tx_exec(struct rte_swx_pipeline *p)
2913{
2914 TRACE("[Thread %2u] *** The next 6 instructions are fused. ***\n",
2915 p->thread_id);
2916
2917 __instr_hdr_emit_exec(p, 5);
2918 instr_tx_exec(p);
2919}
2920
2921static inline void
2922instr_hdr_emit6_tx_exec(struct rte_swx_pipeline *p)
2923{
2924 TRACE("[Thread %2u] *** The next 7 instructions are fused. ***\n",
2925 p->thread_id);
2926
2927 __instr_hdr_emit_exec(p, 6);
2928 instr_tx_exec(p);
2929}
2930
2931static inline void
2932instr_hdr_emit7_tx_exec(struct rte_swx_pipeline *p)
2933{
2934 TRACE("[Thread %2u] *** The next 8 instructions are fused. ***\n",
2935 p->thread_id);
2936
2937 __instr_hdr_emit_exec(p, 7);
2938 instr_tx_exec(p);
2939}
2940
2941static inline void
2942instr_hdr_emit8_tx_exec(struct rte_swx_pipeline *p)
2943{
2944 TRACE("[Thread %2u] *** The next 9 instructions are fused. ***\n",
2945 p->thread_id);
2946
2947 __instr_hdr_emit_exec(p, 8);
2948 instr_tx_exec(p);
2949}
2950
2951
2952
2953
2954static int
2955instr_hdr_validate_translate(struct rte_swx_pipeline *p,
2956 struct action *action __rte_unused,
2957 char **tokens,
2958 int n_tokens,
2959 struct instruction *instr,
2960 struct instruction_data *data __rte_unused)
2961{
2962 struct header *h;
2963
2964 CHECK(n_tokens == 2, EINVAL);
2965
2966 h = header_parse(p, tokens[1]);
2967 CHECK(h, EINVAL);
2968
2969 instr->type = INSTR_HDR_VALIDATE;
2970 instr->valid.header_id = h->id;
2971 return 0;
2972}
2973
2974static inline void
2975instr_hdr_validate_exec(struct rte_swx_pipeline *p)
2976{
2977 struct thread *t = &p->threads[p->thread_id];
2978 struct instruction *ip = t->ip;
2979 uint32_t header_id = ip->valid.header_id;
2980
2981 TRACE("[Thread %2u] validate header %u\n", p->thread_id, header_id);
2982
2983
2984 t->valid_headers = MASK64_BIT_SET(t->valid_headers, header_id);
2985
2986
2987 thread_ip_inc(p);
2988}
2989
2990
2991
2992
2993static int
2994instr_hdr_invalidate_translate(struct rte_swx_pipeline *p,
2995 struct action *action __rte_unused,
2996 char **tokens,
2997 int n_tokens,
2998 struct instruction *instr,
2999 struct instruction_data *data __rte_unused)
3000{
3001 struct header *h;
3002
3003 CHECK(n_tokens == 2, EINVAL);
3004
3005 h = header_parse(p, tokens[1]);
3006 CHECK(h, EINVAL);
3007
3008 instr->type = INSTR_HDR_INVALIDATE;
3009 instr->valid.header_id = h->id;
3010 return 0;
3011}
3012
3013static inline void
3014instr_hdr_invalidate_exec(struct rte_swx_pipeline *p)
3015{
3016 struct thread *t = &p->threads[p->thread_id];
3017 struct instruction *ip = t->ip;
3018 uint32_t header_id = ip->valid.header_id;
3019
3020 TRACE("[Thread %2u] invalidate header %u\n", p->thread_id, header_id);
3021
3022
3023 t->valid_headers = MASK64_BIT_CLR(t->valid_headers, header_id);
3024
3025
3026 thread_ip_inc(p);
3027}
3028
3029
3030
3031
3032static struct table *
3033table_find(struct rte_swx_pipeline *p, const char *name);
3034
3035static int
3036instr_table_translate(struct rte_swx_pipeline *p,
3037 struct action *action,
3038 char **tokens,
3039 int n_tokens,
3040 struct instruction *instr,
3041 struct instruction_data *data __rte_unused)
3042{
3043 struct table *t;
3044
3045 CHECK(!action, EINVAL);
3046 CHECK(n_tokens == 2, EINVAL);
3047
3048 t = table_find(p, tokens[1]);
3049 CHECK(t, EINVAL);
3050
3051 instr->type = INSTR_TABLE;
3052 instr->table.table_id = t->id;
3053 return 0;
3054}
3055
3056static inline void
3057instr_table_exec(struct rte_swx_pipeline *p)
3058{
3059 struct thread *t = &p->threads[p->thread_id];
3060 struct instruction *ip = t->ip;
3061 uint32_t table_id = ip->table.table_id;
3062 struct rte_swx_table_state *ts = &t->table_state[table_id];
3063 struct table_runtime *table = &t->tables[table_id];
3064 uint64_t action_id;
3065 uint8_t *action_data;
3066 int done, hit;
3067
3068
3069 done = table->func(ts->obj,
3070 table->mailbox,
3071 table->key,
3072 &action_id,
3073 &action_data,
3074 &hit);
3075 if (!done) {
3076
3077 TRACE("[Thread %2u] table %u (not finalized)\n",
3078 p->thread_id,
3079 table_id);
3080
3081 thread_yield(p);
3082 return;
3083 }
3084
3085 action_id = hit ? action_id : ts->default_action_id;
3086 action_data = hit ? action_data : ts->default_action_data;
3087
3088 TRACE("[Thread %2u] table %u (%s, action %u)\n",
3089 p->thread_id,
3090 table_id,
3091 hit ? "hit" : "miss",
3092 (uint32_t)action_id);
3093
3094 t->action_id = action_id;
3095 t->structs[0] = action_data;
3096 t->hit = hit;
3097
3098
3099 thread_ip_action_call(p, t, action_id);
3100}
3101
3102
3103
3104
3105static int
3106instr_extern_translate(struct rte_swx_pipeline *p,
3107 struct action *action __rte_unused,
3108 char **tokens,
3109 int n_tokens,
3110 struct instruction *instr,
3111 struct instruction_data *data __rte_unused)
3112{
3113 char *token = tokens[1];
3114
3115 CHECK(n_tokens == 2, EINVAL);
3116
3117 if (token[0] == 'e') {
3118 struct extern_obj *obj;
3119 struct extern_type_member_func *func;
3120
3121 func = extern_obj_member_func_parse(p, token, &obj);
3122 CHECK(func, EINVAL);
3123
3124 instr->type = INSTR_EXTERN_OBJ;
3125 instr->ext_obj.ext_obj_id = obj->id;
3126 instr->ext_obj.func_id = func->id;
3127
3128 return 0;
3129 }
3130
3131 if (token[0] == 'f') {
3132 struct extern_func *func;
3133
3134 func = extern_func_parse(p, token);
3135 CHECK(func, EINVAL);
3136
3137 instr->type = INSTR_EXTERN_FUNC;
3138 instr->ext_func.ext_func_id = func->id;
3139
3140 return 0;
3141 }
3142
3143 CHECK(0, EINVAL);
3144}
3145
3146static inline void
3147instr_extern_obj_exec(struct rte_swx_pipeline *p)
3148{
3149 struct thread *t = &p->threads[p->thread_id];
3150 struct instruction *ip = t->ip;
3151 uint32_t obj_id = ip->ext_obj.ext_obj_id;
3152 uint32_t func_id = ip->ext_obj.func_id;
3153 struct extern_obj_runtime *obj = &t->extern_objs[obj_id];
3154 rte_swx_extern_type_member_func_t func = obj->funcs[func_id];
3155
3156 TRACE("[Thread %2u] extern obj %u member func %u\n",
3157 p->thread_id,
3158 obj_id,
3159 func_id);
3160
3161
3162 uint32_t done = func(obj->obj, obj->mailbox);
3163
3164
3165 thread_ip_inc_cond(t, done);
3166 thread_yield_cond(p, done ^ 1);
3167}
3168
3169static inline void
3170instr_extern_func_exec(struct rte_swx_pipeline *p)
3171{
3172 struct thread *t = &p->threads[p->thread_id];
3173 struct instruction *ip = t->ip;
3174 uint32_t ext_func_id = ip->ext_func.ext_func_id;
3175 struct extern_func_runtime *ext_func = &t->extern_funcs[ext_func_id];
3176 rte_swx_extern_func_t func = ext_func->func;
3177
3178 TRACE("[Thread %2u] extern func %u\n",
3179 p->thread_id,
3180 ext_func_id);
3181
3182
3183 uint32_t done = func(ext_func->mailbox);
3184
3185
3186 thread_ip_inc_cond(t, done);
3187 thread_yield_cond(p, done ^ 1);
3188}
3189
3190
3191
3192
3193static int
3194instr_mov_translate(struct rte_swx_pipeline *p,
3195 struct action *action,
3196 char **tokens,
3197 int n_tokens,
3198 struct instruction *instr,
3199 struct instruction_data *data __rte_unused)
3200{
3201 char *dst = tokens[1], *src = tokens[2];
3202 struct field *fdst, *fsrc;
3203 uint64_t src_val;
3204 uint32_t dst_struct_id, src_struct_id;
3205
3206 CHECK(n_tokens == 3, EINVAL);
3207
3208 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3209 CHECK(fdst, EINVAL);
3210
3211
3212 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3213 if (fsrc) {
3214 instr->type = INSTR_MOV;
3215 if ((dst[0] == 'h' && src[0] != 'h') ||
3216 (dst[0] != 'h' && src[0] == 'h'))
3217 instr->type = INSTR_MOV_S;
3218
3219 instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
3220 instr->mov.dst.n_bits = fdst->n_bits;
3221 instr->mov.dst.offset = fdst->offset / 8;
3222 instr->mov.src.struct_id = (uint8_t)src_struct_id;
3223 instr->mov.src.n_bits = fsrc->n_bits;
3224 instr->mov.src.offset = fsrc->offset / 8;
3225 return 0;
3226 }
3227
3228
3229 src_val = strtoull(src, &src, 0);
3230 CHECK(!src[0], EINVAL);
3231
3232 if (dst[0] == 'h')
3233 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3234
3235 instr->type = INSTR_MOV_I;
3236 instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
3237 instr->mov.dst.n_bits = fdst->n_bits;
3238 instr->mov.dst.offset = fdst->offset / 8;
3239 instr->mov.src_val = src_val;
3240 return 0;
3241}
3242
3243static inline void
3244instr_mov_exec(struct rte_swx_pipeline *p)
3245{
3246 struct thread *t = &p->threads[p->thread_id];
3247 struct instruction *ip = t->ip;
3248
3249 TRACE("[Thread %2u] mov\n",
3250 p->thread_id);
3251
3252 MOV(t, ip);
3253
3254
3255 thread_ip_inc(p);
3256}
3257
3258static inline void
3259instr_mov_s_exec(struct rte_swx_pipeline *p)
3260{
3261 struct thread *t = &p->threads[p->thread_id];
3262 struct instruction *ip = t->ip;
3263
3264 TRACE("[Thread %2u] mov (s)\n",
3265 p->thread_id);
3266
3267 MOV_S(t, ip);
3268
3269
3270 thread_ip_inc(p);
3271}
3272
3273static inline void
3274instr_mov_i_exec(struct rte_swx_pipeline *p)
3275{
3276 struct thread *t = &p->threads[p->thread_id];
3277 struct instruction *ip = t->ip;
3278
3279 TRACE("[Thread %2u] mov m.f %" PRIx64 "\n",
3280 p->thread_id,
3281 ip->mov.src_val);
3282
3283 MOV_I(t, ip);
3284
3285
3286 thread_ip_inc(p);
3287}
3288
3289
3290
3291
3292static int
3293instr_dma_translate(struct rte_swx_pipeline *p,
3294 struct action *action,
3295 char **tokens,
3296 int n_tokens,
3297 struct instruction *instr,
3298 struct instruction_data *data __rte_unused)
3299{
3300 char *dst = tokens[1];
3301 char *src = tokens[2];
3302 struct header *h;
3303 struct field *tf;
3304
3305 CHECK(action, EINVAL);
3306 CHECK(n_tokens == 3, EINVAL);
3307
3308 h = header_parse(p, dst);
3309 CHECK(h, EINVAL);
3310
3311 tf = action_field_parse(action, src);
3312 CHECK(tf, EINVAL);
3313
3314 instr->type = INSTR_DMA_HT;
3315 instr->dma.dst.header_id[0] = h->id;
3316 instr->dma.dst.struct_id[0] = h->struct_id;
3317 instr->dma.n_bytes[0] = h->st->n_bits / 8;
3318 instr->dma.src.offset[0] = tf->offset / 8;
3319
3320 return 0;
3321}
3322
3323static inline void
3324__instr_dma_ht_exec(struct rte_swx_pipeline *p, uint32_t n_dma);
3325
3326static inline void
3327__instr_dma_ht_exec(struct rte_swx_pipeline *p, uint32_t n_dma)
3328{
3329 struct thread *t = &p->threads[p->thread_id];
3330 struct instruction *ip = t->ip;
3331 uint8_t *action_data = t->structs[0];
3332 uint64_t valid_headers = t->valid_headers;
3333 uint32_t i;
3334
3335 for (i = 0; i < n_dma; i++) {
3336 uint32_t header_id = ip->dma.dst.header_id[i];
3337 uint32_t struct_id = ip->dma.dst.struct_id[i];
3338 uint32_t offset = ip->dma.src.offset[i];
3339 uint32_t n_bytes = ip->dma.n_bytes[i];
3340
3341 struct header_runtime *h = &t->headers[header_id];
3342 uint8_t *h_ptr0 = h->ptr0;
3343 uint8_t *h_ptr = t->structs[struct_id];
3344
3345 void *dst = MASK64_BIT_GET(valid_headers, header_id) ?
3346 h_ptr : h_ptr0;
3347 void *src = &action_data[offset];
3348
3349 TRACE("[Thread %2u] dma h.s t.f\n", p->thread_id);
3350
3351
3352 memcpy(dst, src, n_bytes);
3353 t->structs[struct_id] = dst;
3354 valid_headers = MASK64_BIT_SET(valid_headers, header_id);
3355 }
3356
3357 t->valid_headers = valid_headers;
3358}
3359
3360static inline void
3361instr_dma_ht_exec(struct rte_swx_pipeline *p)
3362{
3363 __instr_dma_ht_exec(p, 1);
3364
3365
3366 thread_ip_inc(p);
3367}
3368
3369static inline void
3370instr_dma_ht2_exec(struct rte_swx_pipeline *p)
3371{
3372 TRACE("[Thread %2u] *** The next 2 instructions are fused. ***\n",
3373 p->thread_id);
3374
3375 __instr_dma_ht_exec(p, 2);
3376
3377
3378 thread_ip_inc(p);
3379}
3380
3381static inline void
3382instr_dma_ht3_exec(struct rte_swx_pipeline *p)
3383{
3384 TRACE("[Thread %2u] *** The next 3 instructions are fused. ***\n",
3385 p->thread_id);
3386
3387 __instr_dma_ht_exec(p, 3);
3388
3389
3390 thread_ip_inc(p);
3391}
3392
3393static inline void
3394instr_dma_ht4_exec(struct rte_swx_pipeline *p)
3395{
3396 TRACE("[Thread %2u] *** The next 4 instructions are fused. ***\n",
3397 p->thread_id);
3398
3399 __instr_dma_ht_exec(p, 4);
3400
3401
3402 thread_ip_inc(p);
3403}
3404
3405static inline void
3406instr_dma_ht5_exec(struct rte_swx_pipeline *p)
3407{
3408 TRACE("[Thread %2u] *** The next 5 instructions are fused. ***\n",
3409 p->thread_id);
3410
3411 __instr_dma_ht_exec(p, 5);
3412
3413
3414 thread_ip_inc(p);
3415}
3416
3417static inline void
3418instr_dma_ht6_exec(struct rte_swx_pipeline *p)
3419{
3420 TRACE("[Thread %2u] *** The next 6 instructions are fused. ***\n",
3421 p->thread_id);
3422
3423 __instr_dma_ht_exec(p, 6);
3424
3425
3426 thread_ip_inc(p);
3427}
3428
3429static inline void
3430instr_dma_ht7_exec(struct rte_swx_pipeline *p)
3431{
3432 TRACE("[Thread %2u] *** The next 7 instructions are fused. ***\n",
3433 p->thread_id);
3434
3435 __instr_dma_ht_exec(p, 7);
3436
3437
3438 thread_ip_inc(p);
3439}
3440
3441static inline void
3442instr_dma_ht8_exec(struct rte_swx_pipeline *p)
3443{
3444 TRACE("[Thread %2u] *** The next 8 instructions are fused. ***\n",
3445 p->thread_id);
3446
3447 __instr_dma_ht_exec(p, 8);
3448
3449
3450 thread_ip_inc(p);
3451}
3452
3453
3454
3455
3456static int
3457instr_alu_add_translate(struct rte_swx_pipeline *p,
3458 struct action *action,
3459 char **tokens,
3460 int n_tokens,
3461 struct instruction *instr,
3462 struct instruction_data *data __rte_unused)
3463{
3464 char *dst = tokens[1], *src = tokens[2];
3465 struct field *fdst, *fsrc;
3466 uint64_t src_val;
3467 uint32_t dst_struct_id, src_struct_id;
3468
3469 CHECK(n_tokens == 3, EINVAL);
3470
3471 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3472 CHECK(fdst, EINVAL);
3473
3474
3475 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3476 if (fsrc) {
3477 instr->type = INSTR_ALU_ADD;
3478 if (dst[0] == 'h' && src[0] == 'm')
3479 instr->type = INSTR_ALU_ADD_HM;
3480 if (dst[0] == 'm' && src[0] == 'h')
3481 instr->type = INSTR_ALU_ADD_MH;
3482 if (dst[0] == 'h' && src[0] == 'h')
3483 instr->type = INSTR_ALU_ADD_HH;
3484
3485 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3486 instr->alu.dst.n_bits = fdst->n_bits;
3487 instr->alu.dst.offset = fdst->offset / 8;
3488 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3489 instr->alu.src.n_bits = fsrc->n_bits;
3490 instr->alu.src.offset = fsrc->offset / 8;
3491 return 0;
3492 }
3493
3494
3495 src_val = strtoull(src, &src, 0);
3496 CHECK(!src[0], EINVAL);
3497
3498 instr->type = INSTR_ALU_ADD_MI;
3499 if (dst[0] == 'h')
3500 instr->type = INSTR_ALU_ADD_HI;
3501
3502 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3503 instr->alu.dst.n_bits = fdst->n_bits;
3504 instr->alu.dst.offset = fdst->offset / 8;
3505 instr->alu.src_val = src_val;
3506 return 0;
3507}
3508
3509static int
3510instr_alu_sub_translate(struct rte_swx_pipeline *p,
3511 struct action *action,
3512 char **tokens,
3513 int n_tokens,
3514 struct instruction *instr,
3515 struct instruction_data *data __rte_unused)
3516{
3517 char *dst = tokens[1], *src = tokens[2];
3518 struct field *fdst, *fsrc;
3519 uint64_t src_val;
3520 uint32_t dst_struct_id, src_struct_id;
3521
3522 CHECK(n_tokens == 3, EINVAL);
3523
3524 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3525 CHECK(fdst, EINVAL);
3526
3527
3528 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3529 if (fsrc) {
3530 instr->type = INSTR_ALU_SUB;
3531 if (dst[0] == 'h' && src[0] == 'm')
3532 instr->type = INSTR_ALU_SUB_HM;
3533 if (dst[0] == 'm' && src[0] == 'h')
3534 instr->type = INSTR_ALU_SUB_MH;
3535 if (dst[0] == 'h' && src[0] == 'h')
3536 instr->type = INSTR_ALU_SUB_HH;
3537
3538 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3539 instr->alu.dst.n_bits = fdst->n_bits;
3540 instr->alu.dst.offset = fdst->offset / 8;
3541 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3542 instr->alu.src.n_bits = fsrc->n_bits;
3543 instr->alu.src.offset = fsrc->offset / 8;
3544 return 0;
3545 }
3546
3547
3548 src_val = strtoull(src, &src, 0);
3549 CHECK(!src[0], EINVAL);
3550
3551 instr->type = INSTR_ALU_SUB_MI;
3552 if (dst[0] == 'h')
3553 instr->type = INSTR_ALU_SUB_HI;
3554
3555 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3556 instr->alu.dst.n_bits = fdst->n_bits;
3557 instr->alu.dst.offset = fdst->offset / 8;
3558 instr->alu.src_val = src_val;
3559 return 0;
3560}
3561
3562static int
3563instr_alu_ckadd_translate(struct rte_swx_pipeline *p,
3564 struct action *action __rte_unused,
3565 char **tokens,
3566 int n_tokens,
3567 struct instruction *instr,
3568 struct instruction_data *data __rte_unused)
3569{
3570 char *dst = tokens[1], *src = tokens[2];
3571 struct header *hdst, *hsrc;
3572 struct field *fdst, *fsrc;
3573
3574 CHECK(n_tokens == 3, EINVAL);
3575
3576 fdst = header_field_parse(p, dst, &hdst);
3577 CHECK(fdst && (fdst->n_bits == 16), EINVAL);
3578
3579
3580 fsrc = header_field_parse(p, src, &hsrc);
3581 if (fsrc) {
3582 instr->type = INSTR_ALU_CKADD_FIELD;
3583 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
3584 instr->alu.dst.n_bits = fdst->n_bits;
3585 instr->alu.dst.offset = fdst->offset / 8;
3586 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
3587 instr->alu.src.n_bits = fsrc->n_bits;
3588 instr->alu.src.offset = fsrc->offset / 8;
3589 return 0;
3590 }
3591
3592
3593 hsrc = header_parse(p, src);
3594 CHECK(hsrc, EINVAL);
3595
3596 instr->type = INSTR_ALU_CKADD_STRUCT;
3597 if ((hsrc->st->n_bits / 8) == 20)
3598 instr->type = INSTR_ALU_CKADD_STRUCT20;
3599
3600 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
3601 instr->alu.dst.n_bits = fdst->n_bits;
3602 instr->alu.dst.offset = fdst->offset / 8;
3603 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
3604 instr->alu.src.n_bits = hsrc->st->n_bits;
3605 instr->alu.src.offset = 0;
3606 return 0;
3607}
3608
3609static int
3610instr_alu_cksub_translate(struct rte_swx_pipeline *p,
3611 struct action *action __rte_unused,
3612 char **tokens,
3613 int n_tokens,
3614 struct instruction *instr,
3615 struct instruction_data *data __rte_unused)
3616{
3617 char *dst = tokens[1], *src = tokens[2];
3618 struct header *hdst, *hsrc;
3619 struct field *fdst, *fsrc;
3620
3621 CHECK(n_tokens == 3, EINVAL);
3622
3623 fdst = header_field_parse(p, dst, &hdst);
3624 CHECK(fdst && (fdst->n_bits == 16), EINVAL);
3625
3626 fsrc = header_field_parse(p, src, &hsrc);
3627 CHECK(fsrc, EINVAL);
3628
3629 instr->type = INSTR_ALU_CKSUB_FIELD;
3630 instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
3631 instr->alu.dst.n_bits = fdst->n_bits;
3632 instr->alu.dst.offset = fdst->offset / 8;
3633 instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
3634 instr->alu.src.n_bits = fsrc->n_bits;
3635 instr->alu.src.offset = fsrc->offset / 8;
3636 return 0;
3637}
3638
3639static int
3640instr_alu_shl_translate(struct rte_swx_pipeline *p,
3641 struct action *action,
3642 char **tokens,
3643 int n_tokens,
3644 struct instruction *instr,
3645 struct instruction_data *data __rte_unused)
3646{
3647 char *dst = tokens[1], *src = tokens[2];
3648 struct field *fdst, *fsrc;
3649 uint64_t src_val;
3650 uint32_t dst_struct_id, src_struct_id;
3651
3652 CHECK(n_tokens == 3, EINVAL);
3653
3654 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3655 CHECK(fdst, EINVAL);
3656
3657
3658 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3659 if (fsrc) {
3660 instr->type = INSTR_ALU_SHL;
3661 if (dst[0] == 'h' && src[0] == 'm')
3662 instr->type = INSTR_ALU_SHL_HM;
3663 if (dst[0] == 'm' && src[0] == 'h')
3664 instr->type = INSTR_ALU_SHL_MH;
3665 if (dst[0] == 'h' && src[0] == 'h')
3666 instr->type = INSTR_ALU_SHL_HH;
3667
3668 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3669 instr->alu.dst.n_bits = fdst->n_bits;
3670 instr->alu.dst.offset = fdst->offset / 8;
3671 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3672 instr->alu.src.n_bits = fsrc->n_bits;
3673 instr->alu.src.offset = fsrc->offset / 8;
3674 return 0;
3675 }
3676
3677
3678 src_val = strtoull(src, &src, 0);
3679 CHECK(!src[0], EINVAL);
3680
3681 instr->type = INSTR_ALU_SHL_MI;
3682 if (dst[0] == 'h')
3683 instr->type = INSTR_ALU_SHL_HI;
3684
3685 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3686 instr->alu.dst.n_bits = fdst->n_bits;
3687 instr->alu.dst.offset = fdst->offset / 8;
3688 instr->alu.src_val = src_val;
3689 return 0;
3690}
3691
3692static int
3693instr_alu_shr_translate(struct rte_swx_pipeline *p,
3694 struct action *action,
3695 char **tokens,
3696 int n_tokens,
3697 struct instruction *instr,
3698 struct instruction_data *data __rte_unused)
3699{
3700 char *dst = tokens[1], *src = tokens[2];
3701 struct field *fdst, *fsrc;
3702 uint64_t src_val;
3703 uint32_t dst_struct_id, src_struct_id;
3704
3705 CHECK(n_tokens == 3, EINVAL);
3706
3707 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3708 CHECK(fdst, EINVAL);
3709
3710
3711 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3712 if (fsrc) {
3713 instr->type = INSTR_ALU_SHR;
3714 if (dst[0] == 'h' && src[0] == 'm')
3715 instr->type = INSTR_ALU_SHR_HM;
3716 if (dst[0] == 'm' && src[0] == 'h')
3717 instr->type = INSTR_ALU_SHR_MH;
3718 if (dst[0] == 'h' && src[0] == 'h')
3719 instr->type = INSTR_ALU_SHR_HH;
3720
3721 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3722 instr->alu.dst.n_bits = fdst->n_bits;
3723 instr->alu.dst.offset = fdst->offset / 8;
3724 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3725 instr->alu.src.n_bits = fsrc->n_bits;
3726 instr->alu.src.offset = fsrc->offset / 8;
3727 return 0;
3728 }
3729
3730
3731 src_val = strtoull(src, &src, 0);
3732 CHECK(!src[0], EINVAL);
3733
3734 instr->type = INSTR_ALU_SHR_MI;
3735 if (dst[0] == 'h')
3736 instr->type = INSTR_ALU_SHR_HI;
3737
3738 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3739 instr->alu.dst.n_bits = fdst->n_bits;
3740 instr->alu.dst.offset = fdst->offset / 8;
3741 instr->alu.src_val = src_val;
3742 return 0;
3743}
3744
3745static int
3746instr_alu_and_translate(struct rte_swx_pipeline *p,
3747 struct action *action,
3748 char **tokens,
3749 int n_tokens,
3750 struct instruction *instr,
3751 struct instruction_data *data __rte_unused)
3752{
3753 char *dst = tokens[1], *src = tokens[2];
3754 struct field *fdst, *fsrc;
3755 uint64_t src_val;
3756 uint32_t dst_struct_id, src_struct_id;
3757
3758 CHECK(n_tokens == 3, EINVAL);
3759
3760 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3761 CHECK(fdst, EINVAL);
3762
3763
3764 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3765 if (fsrc) {
3766 instr->type = INSTR_ALU_AND;
3767 if ((dst[0] == 'h' && src[0] != 'h') ||
3768 (dst[0] != 'h' && src[0] == 'h'))
3769 instr->type = INSTR_ALU_AND_S;
3770
3771 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3772 instr->alu.dst.n_bits = fdst->n_bits;
3773 instr->alu.dst.offset = fdst->offset / 8;
3774 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3775 instr->alu.src.n_bits = fsrc->n_bits;
3776 instr->alu.src.offset = fsrc->offset / 8;
3777 return 0;
3778 }
3779
3780
3781 src_val = strtoull(src, &src, 0);
3782 CHECK(!src[0], EINVAL);
3783
3784 if (dst[0] == 'h')
3785 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3786
3787 instr->type = INSTR_ALU_AND_I;
3788 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3789 instr->alu.dst.n_bits = fdst->n_bits;
3790 instr->alu.dst.offset = fdst->offset / 8;
3791 instr->alu.src_val = src_val;
3792 return 0;
3793}
3794
3795static int
3796instr_alu_or_translate(struct rte_swx_pipeline *p,
3797 struct action *action,
3798 char **tokens,
3799 int n_tokens,
3800 struct instruction *instr,
3801 struct instruction_data *data __rte_unused)
3802{
3803 char *dst = tokens[1], *src = tokens[2];
3804 struct field *fdst, *fsrc;
3805 uint64_t src_val;
3806 uint32_t dst_struct_id, src_struct_id;
3807
3808 CHECK(n_tokens == 3, EINVAL);
3809
3810 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3811 CHECK(fdst, EINVAL);
3812
3813
3814 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3815 if (fsrc) {
3816 instr->type = INSTR_ALU_OR;
3817 if ((dst[0] == 'h' && src[0] != 'h') ||
3818 (dst[0] != 'h' && src[0] == 'h'))
3819 instr->type = INSTR_ALU_OR_S;
3820
3821 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3822 instr->alu.dst.n_bits = fdst->n_bits;
3823 instr->alu.dst.offset = fdst->offset / 8;
3824 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3825 instr->alu.src.n_bits = fsrc->n_bits;
3826 instr->alu.src.offset = fsrc->offset / 8;
3827 return 0;
3828 }
3829
3830
3831 src_val = strtoull(src, &src, 0);
3832 CHECK(!src[0], EINVAL);
3833
3834 if (dst[0] == 'h')
3835 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3836
3837 instr->type = INSTR_ALU_OR_I;
3838 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3839 instr->alu.dst.n_bits = fdst->n_bits;
3840 instr->alu.dst.offset = fdst->offset / 8;
3841 instr->alu.src_val = src_val;
3842 return 0;
3843}
3844
3845static int
3846instr_alu_xor_translate(struct rte_swx_pipeline *p,
3847 struct action *action,
3848 char **tokens,
3849 int n_tokens,
3850 struct instruction *instr,
3851 struct instruction_data *data __rte_unused)
3852{
3853 char *dst = tokens[1], *src = tokens[2];
3854 struct field *fdst, *fsrc;
3855 uint64_t src_val;
3856 uint32_t dst_struct_id, src_struct_id;
3857
3858 CHECK(n_tokens == 3, EINVAL);
3859
3860 fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3861 CHECK(fdst, EINVAL);
3862
3863
3864 fsrc = struct_field_parse(p, action, src, &src_struct_id);
3865 if (fsrc) {
3866 instr->type = INSTR_ALU_XOR;
3867 if ((dst[0] == 'h' && src[0] != 'h') ||
3868 (dst[0] != 'h' && src[0] == 'h'))
3869 instr->type = INSTR_ALU_XOR_S;
3870
3871 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3872 instr->alu.dst.n_bits = fdst->n_bits;
3873 instr->alu.dst.offset = fdst->offset / 8;
3874 instr->alu.src.struct_id = (uint8_t)src_struct_id;
3875 instr->alu.src.n_bits = fsrc->n_bits;
3876 instr->alu.src.offset = fsrc->offset / 8;
3877 return 0;
3878 }
3879
3880
3881 src_val = strtoull(src, &src, 0);
3882 CHECK(!src[0], EINVAL);
3883
3884 if (dst[0] == 'h')
3885 src_val = hton64(src_val) >> (64 - fdst->n_bits);
3886
3887 instr->type = INSTR_ALU_XOR_I;
3888 instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3889 instr->alu.dst.n_bits = fdst->n_bits;
3890 instr->alu.dst.offset = fdst->offset / 8;
3891 instr->alu.src_val = src_val;
3892 return 0;
3893}
3894
3895static inline void
3896instr_alu_add_exec(struct rte_swx_pipeline *p)
3897{
3898 struct thread *t = &p->threads[p->thread_id];
3899 struct instruction *ip = t->ip;
3900
3901 TRACE("[Thread %2u] add\n", p->thread_id);
3902
3903
3904 ALU(t, ip, +);
3905
3906
3907 thread_ip_inc(p);
3908}
3909
3910static inline void
3911instr_alu_add_mh_exec(struct rte_swx_pipeline *p)
3912{
3913 struct thread *t = &p->threads[p->thread_id];
3914 struct instruction *ip = t->ip;
3915
3916 TRACE("[Thread %2u] add (mh)\n", p->thread_id);
3917
3918
3919 ALU_MH(t, ip, +);
3920
3921
3922 thread_ip_inc(p);
3923}
3924
3925static inline void
3926instr_alu_add_hm_exec(struct rte_swx_pipeline *p)
3927{
3928 struct thread *t = &p->threads[p->thread_id];
3929 struct instruction *ip = t->ip;
3930
3931 TRACE("[Thread %2u] add (hm)\n", p->thread_id);
3932
3933
3934 ALU_HM(t, ip, +);
3935
3936
3937 thread_ip_inc(p);
3938}
3939
3940static inline void
3941instr_alu_add_hh_exec(struct rte_swx_pipeline *p)
3942{
3943 struct thread *t = &p->threads[p->thread_id];
3944 struct instruction *ip = t->ip;
3945
3946 TRACE("[Thread %2u] add (hh)\n", p->thread_id);
3947
3948
3949 ALU_HH(t, ip, +);
3950
3951
3952 thread_ip_inc(p);
3953}
3954
3955static inline void
3956instr_alu_add_mi_exec(struct rte_swx_pipeline *p)
3957{
3958 struct thread *t = &p->threads[p->thread_id];
3959 struct instruction *ip = t->ip;
3960
3961 TRACE("[Thread %2u] add (mi)\n", p->thread_id);
3962
3963
3964 ALU_MI(t, ip, +);
3965
3966
3967 thread_ip_inc(p);
3968}
3969
3970static inline void
3971instr_alu_add_hi_exec(struct rte_swx_pipeline *p)
3972{
3973 struct thread *t = &p->threads[p->thread_id];
3974 struct instruction *ip = t->ip;
3975
3976 TRACE("[Thread %2u] add (hi)\n", p->thread_id);
3977
3978
3979 ALU_HI(t, ip, +);
3980
3981
3982 thread_ip_inc(p);
3983}
3984
3985static inline void
3986instr_alu_sub_exec(struct rte_swx_pipeline *p)
3987{
3988 struct thread *t = &p->threads[p->thread_id];
3989 struct instruction *ip = t->ip;
3990
3991 TRACE("[Thread %2u] sub\n", p->thread_id);
3992
3993
3994 ALU(t, ip, -);
3995
3996
3997 thread_ip_inc(p);
3998}
3999
4000static inline void
4001instr_alu_sub_mh_exec(struct rte_swx_pipeline *p)
4002{
4003 struct thread *t = &p->threads[p->thread_id];
4004 struct instruction *ip = t->ip;
4005
4006 TRACE("[Thread %2u] sub (mh)\n", p->thread_id);
4007
4008
4009 ALU_MH(t, ip, -);
4010
4011
4012 thread_ip_inc(p);
4013}
4014
4015static inline void
4016instr_alu_sub_hm_exec(struct rte_swx_pipeline *p)
4017{
4018 struct thread *t = &p->threads[p->thread_id];
4019 struct instruction *ip = t->ip;
4020
4021 TRACE("[Thread %2u] sub (hm)\n", p->thread_id);
4022
4023
4024 ALU_HM(t, ip, -);
4025
4026
4027 thread_ip_inc(p);
4028}
4029
4030static inline void
4031instr_alu_sub_hh_exec(struct rte_swx_pipeline *p)
4032{
4033 struct thread *t = &p->threads[p->thread_id];
4034 struct instruction *ip = t->ip;
4035
4036 TRACE("[Thread %2u] sub (hh)\n", p->thread_id);
4037
4038
4039 ALU_HH(t, ip, -);
4040
4041
4042 thread_ip_inc(p);
4043}
4044
4045static inline void
4046instr_alu_sub_mi_exec(struct rte_swx_pipeline *p)
4047{
4048 struct thread *t = &p->threads[p->thread_id];
4049 struct instruction *ip = t->ip;
4050
4051 TRACE("[Thread %2u] sub (mi)\n", p->thread_id);
4052
4053
4054 ALU_MI(t, ip, -);
4055
4056
4057 thread_ip_inc(p);
4058}
4059
4060static inline void
4061instr_alu_sub_hi_exec(struct rte_swx_pipeline *p)
4062{
4063 struct thread *t = &p->threads[p->thread_id];
4064 struct instruction *ip = t->ip;
4065
4066 TRACE("[Thread %2u] sub (hi)\n", p->thread_id);
4067
4068
4069 ALU_HI(t, ip, -);
4070
4071
4072 thread_ip_inc(p);
4073}
4074
4075static inline void
4076instr_alu_shl_exec(struct rte_swx_pipeline *p)
4077{
4078 struct thread *t = &p->threads[p->thread_id];
4079 struct instruction *ip = t->ip;
4080
4081 TRACE("[Thread %2u] shl\n", p->thread_id);
4082
4083
4084 ALU(t, ip, <<);
4085
4086
4087 thread_ip_inc(p);
4088}
4089
4090static inline void
4091instr_alu_shl_mh_exec(struct rte_swx_pipeline *p)
4092{
4093 struct thread *t = &p->threads[p->thread_id];
4094 struct instruction *ip = t->ip;
4095
4096 TRACE("[Thread %2u] shl (mh)\n", p->thread_id);
4097
4098
4099 ALU_MH(t, ip, <<);
4100
4101
4102 thread_ip_inc(p);
4103}
4104
4105static inline void
4106instr_alu_shl_hm_exec(struct rte_swx_pipeline *p)
4107{
4108 struct thread *t = &p->threads[p->thread_id];
4109 struct instruction *ip = t->ip;
4110
4111 TRACE("[Thread %2u] shl (hm)\n", p->thread_id);
4112
4113
4114 ALU_HM(t, ip, <<);
4115
4116
4117 thread_ip_inc(p);
4118}
4119
4120static inline void
4121instr_alu_shl_hh_exec(struct rte_swx_pipeline *p)
4122{
4123 struct thread *t = &p->threads[p->thread_id];
4124 struct instruction *ip = t->ip;
4125
4126 TRACE("[Thread %2u] shl (hh)\n", p->thread_id);
4127
4128
4129 ALU_HH(t, ip, <<);
4130
4131
4132 thread_ip_inc(p);
4133}
4134
4135static inline void
4136instr_alu_shl_mi_exec(struct rte_swx_pipeline *p)
4137{
4138 struct thread *t = &p->threads[p->thread_id];
4139 struct instruction *ip = t->ip;
4140
4141 TRACE("[Thread %2u] shl (mi)\n", p->thread_id);
4142
4143
4144 ALU_MI(t, ip, <<);
4145
4146
4147 thread_ip_inc(p);
4148}
4149
4150static inline void
4151instr_alu_shl_hi_exec(struct rte_swx_pipeline *p)
4152{
4153 struct thread *t = &p->threads[p->thread_id];
4154 struct instruction *ip = t->ip;
4155
4156 TRACE("[Thread %2u] shl (hi)\n", p->thread_id);
4157
4158
4159 ALU_HI(t, ip, <<);
4160
4161
4162 thread_ip_inc(p);
4163}
4164
4165static inline void
4166instr_alu_shr_exec(struct rte_swx_pipeline *p)
4167{
4168 struct thread *t = &p->threads[p->thread_id];
4169 struct instruction *ip = t->ip;
4170
4171 TRACE("[Thread %2u] shr\n", p->thread_id);
4172
4173
4174 ALU(t, ip, >>);
4175
4176
4177 thread_ip_inc(p);
4178}
4179
4180static inline void
4181instr_alu_shr_mh_exec(struct rte_swx_pipeline *p)
4182{
4183 struct thread *t = &p->threads[p->thread_id];
4184 struct instruction *ip = t->ip;
4185
4186 TRACE("[Thread %2u] shr (mh)\n", p->thread_id);
4187
4188
4189 ALU_MH(t, ip, >>);
4190
4191
4192 thread_ip_inc(p);
4193}
4194
4195static inline void
4196instr_alu_shr_hm_exec(struct rte_swx_pipeline *p)
4197{
4198 struct thread *t = &p->threads[p->thread_id];
4199 struct instruction *ip = t->ip;
4200
4201 TRACE("[Thread %2u] shr (hm)\n", p->thread_id);
4202
4203
4204 ALU_HM(t, ip, >>);
4205
4206
4207 thread_ip_inc(p);
4208}
4209
4210static inline void
4211instr_alu_shr_hh_exec(struct rte_swx_pipeline *p)
4212{
4213 struct thread *t = &p->threads[p->thread_id];
4214 struct instruction *ip = t->ip;
4215
4216 TRACE("[Thread %2u] shr (hh)\n", p->thread_id);
4217
4218
4219 ALU_HH(t, ip, >>);
4220
4221
4222 thread_ip_inc(p);
4223}
4224
4225static inline void
4226instr_alu_shr_mi_exec(struct rte_swx_pipeline *p)
4227{
4228 struct thread *t = &p->threads[p->thread_id];
4229 struct instruction *ip = t->ip;
4230
4231 TRACE("[Thread %2u] shr (mi)\n", p->thread_id);
4232
4233
4234 ALU_MI(t, ip, >>);
4235
4236
4237 thread_ip_inc(p);
4238}
4239
4240static inline void
4241instr_alu_shr_hi_exec(struct rte_swx_pipeline *p)
4242{
4243 struct thread *t = &p->threads[p->thread_id];
4244 struct instruction *ip = t->ip;
4245
4246 TRACE("[Thread %2u] shr (hi)\n", p->thread_id);
4247
4248
4249 ALU_HI(t, ip, >>);
4250
4251
4252 thread_ip_inc(p);
4253}
4254
4255static inline void
4256instr_alu_and_exec(struct rte_swx_pipeline *p)
4257{
4258 struct thread *t = &p->threads[p->thread_id];
4259 struct instruction *ip = t->ip;
4260
4261 TRACE("[Thread %2u] and\n", p->thread_id);
4262
4263
4264 ALU(t, ip, &);
4265
4266
4267 thread_ip_inc(p);
4268}
4269
4270static inline void
4271instr_alu_and_s_exec(struct rte_swx_pipeline *p)
4272{
4273 struct thread *t = &p->threads[p->thread_id];
4274 struct instruction *ip = t->ip;
4275
4276 TRACE("[Thread %2u] and (s)\n", p->thread_id);
4277
4278
4279 ALU_S(t, ip, &);
4280
4281
4282 thread_ip_inc(p);
4283}
4284
4285static inline void
4286instr_alu_and_i_exec(struct rte_swx_pipeline *p)
4287{
4288 struct thread *t = &p->threads[p->thread_id];
4289 struct instruction *ip = t->ip;
4290
4291 TRACE("[Thread %2u] and (i)\n", p->thread_id);
4292
4293
4294 ALU_I(t, ip, &);
4295
4296
4297 thread_ip_inc(p);
4298}
4299
4300static inline void
4301instr_alu_or_exec(struct rte_swx_pipeline *p)
4302{
4303 struct thread *t = &p->threads[p->thread_id];
4304 struct instruction *ip = t->ip;
4305
4306 TRACE("[Thread %2u] or\n", p->thread_id);
4307
4308
4309 ALU(t, ip, |);
4310
4311
4312 thread_ip_inc(p);
4313}
4314
4315static inline void
4316instr_alu_or_s_exec(struct rte_swx_pipeline *p)
4317{
4318 struct thread *t = &p->threads[p->thread_id];
4319 struct instruction *ip = t->ip;
4320
4321 TRACE("[Thread %2u] or (s)\n", p->thread_id);
4322
4323
4324 ALU_S(t, ip, |);
4325
4326
4327 thread_ip_inc(p);
4328}
4329
4330static inline void
4331instr_alu_or_i_exec(struct rte_swx_pipeline *p)
4332{
4333 struct thread *t = &p->threads[p->thread_id];
4334 struct instruction *ip = t->ip;
4335
4336 TRACE("[Thread %2u] or (i)\n", p->thread_id);
4337
4338
4339 ALU_I(t, ip, |);
4340
4341
4342 thread_ip_inc(p);
4343}
4344
4345static inline void
4346instr_alu_xor_exec(struct rte_swx_pipeline *p)
4347{
4348 struct thread *t = &p->threads[p->thread_id];
4349 struct instruction *ip = t->ip;
4350
4351 TRACE("[Thread %2u] xor\n", p->thread_id);
4352
4353
4354 ALU(t, ip, ^);
4355
4356
4357 thread_ip_inc(p);
4358}
4359
4360static inline void
4361instr_alu_xor_s_exec(struct rte_swx_pipeline *p)
4362{
4363 struct thread *t = &p->threads[p->thread_id];
4364 struct instruction *ip = t->ip;
4365
4366 TRACE("[Thread %2u] xor (s)\n", p->thread_id);
4367
4368
4369 ALU_S(t, ip, ^);
4370
4371
4372 thread_ip_inc(p);
4373}
4374
4375static inline void
4376instr_alu_xor_i_exec(struct rte_swx_pipeline *p)
4377{
4378 struct thread *t = &p->threads[p->thread_id];
4379 struct instruction *ip = t->ip;
4380
4381 TRACE("[Thread %2u] xor (i)\n", p->thread_id);
4382
4383
4384 ALU_I(t, ip, ^);
4385
4386
4387 thread_ip_inc(p);
4388}
4389
4390static inline void
4391instr_alu_ckadd_field_exec(struct rte_swx_pipeline *p)
4392{
4393 struct thread *t = &p->threads[p->thread_id];
4394 struct instruction *ip = t->ip;
4395 uint8_t *dst_struct, *src_struct;
4396 uint16_t *dst16_ptr, dst;
4397 uint64_t *src64_ptr, src64, src64_mask, src;
4398 uint64_t r;
4399
4400 TRACE("[Thread %2u] ckadd (field)\n", p->thread_id);
4401
4402
4403 dst_struct = t->structs[ip->alu.dst.struct_id];
4404 dst16_ptr = (uint16_t *)&dst_struct[ip->alu.dst.offset];
4405 dst = *dst16_ptr;
4406
4407 src_struct = t->structs[ip->alu.src.struct_id];
4408 src64_ptr = (uint64_t *)&src_struct[ip->alu.src.offset];
4409 src64 = *src64_ptr;
4410 src64_mask = UINT64_MAX >> (64 - ip->alu.src.n_bits);
4411 src = src64 & src64_mask;
4412
4413 r = dst;
4414 r = ~r & 0xFFFF;
4415
4416
4417
4418
4419
4420 r += (src >> 32) + (src & 0xFFFFFFFF);
4421
4422
4423
4424
4425
4426 r = (r & 0xFFFF) + (r >> 16);
4427
4428
4429
4430
4431 r = (r & 0xFFFF) + (r >> 16);
4432
4433
4434
4435
4436
4437
4438 r = (r & 0xFFFF) + (r >> 16);
4439
4440 r = ~r & 0xFFFF;
4441 r = r ? r : 0xFFFF;
4442
4443 *dst16_ptr = (uint16_t)r;
4444
4445
4446 thread_ip_inc(p);
4447}
4448
4449static inline void
4450instr_alu_cksub_field_exec(struct rte_swx_pipeline *p)
4451{
4452 struct thread *t = &p->threads[p->thread_id];
4453 struct instruction *ip = t->ip;
4454 uint8_t *dst_struct, *src_struct;
4455 uint16_t *dst16_ptr, dst;
4456 uint64_t *src64_ptr, src64, src64_mask, src;
4457 uint64_t r;
4458
4459 TRACE("[Thread %2u] cksub (field)\n", p->thread_id);
4460
4461
4462 dst_struct = t->structs[ip->alu.dst.struct_id];
4463 dst16_ptr = (uint16_t *)&dst_struct[ip->alu.dst.offset];
4464 dst = *dst16_ptr;
4465
4466 src_struct = t->structs[ip->alu.src.struct_id];
4467 src64_ptr = (uint64_t *)&src_struct[ip->alu.src.offset];
4468 src64 = *src64_ptr;
4469 src64_mask = UINT64_MAX >> (64 - ip->alu.src.n_bits);
4470 src = src64 & src64_mask;
4471
4472 r = dst;
4473 r = ~r & 0xFFFF;
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487 r += 0xFFFF00000ULL;
4488
4489
4490
4491
4492 r -= (src >> 32) + (src & 0xFFFFFFFF);
4493
4494
4495
4496
4497 r = (r & 0xFFFF) + (r >> 16);
4498
4499
4500
4501
4502 r = (r & 0xFFFF) + (r >> 16);
4503
4504
4505
4506
4507
4508
4509 r = (r & 0xFFFF) + (r >> 16);
4510
4511 r = ~r & 0xFFFF;
4512 r = r ? r : 0xFFFF;
4513
4514 *dst16_ptr = (uint16_t)r;
4515
4516
4517 thread_ip_inc(p);
4518}
4519
4520static inline void
4521instr_alu_ckadd_struct20_exec(struct rte_swx_pipeline *p)
4522{
4523 struct thread *t = &p->threads[p->thread_id];
4524 struct instruction *ip = t->ip;
4525 uint8_t *dst_struct, *src_struct;
4526 uint16_t *dst16_ptr;
4527 uint32_t *src32_ptr;
4528 uint64_t r0, r1;
4529
4530 TRACE("[Thread %2u] ckadd (struct of 20 bytes)\n", p->thread_id);
4531
4532
4533 dst_struct = t->structs[ip->alu.dst.struct_id];
4534 dst16_ptr = (uint16_t *)&dst_struct[ip->alu.dst.offset];
4535
4536 src_struct = t->structs[ip->alu.src.struct_id];
4537 src32_ptr = (uint32_t *)&src_struct[0];
4538
4539 r0 = src32_ptr[0];
4540 r1 = src32_ptr[1];
4541 r0 += src32_ptr[2];
4542 r1 += src32_ptr[3];
4543 r0 += r1 + src32_ptr[4];
4544
4545
4546
4547
4548 r0 = (r0 & 0xFFFF) + (r0 >> 16);
4549
4550
4551
4552
4553 r0 = (r0 & 0xFFFF) + (r0 >> 16);
4554
4555
4556
4557
4558
4559
4560 r0 = (r0 & 0xFFFF) + (r0 >> 16);
4561
4562 r0 = ~r0 & 0xFFFF;
4563 r0 = r0 ? r0 : 0xFFFF;
4564
4565 *dst16_ptr = (uint16_t)r0;
4566
4567
4568 thread_ip_inc(p);
4569}
4570
4571static inline void
4572instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)
4573{
4574 struct thread *t = &p->threads[p->thread_id];
4575 struct instruction *ip = t->ip;
4576 uint8_t *dst_struct, *src_struct;
4577 uint16_t *dst16_ptr;
4578 uint32_t *src32_ptr;
4579 uint64_t r = 0;
4580 uint32_t i;
4581
4582 TRACE("[Thread %2u] ckadd (struct)\n", p->thread_id);
4583
4584
4585 dst_struct = t->structs[ip->alu.dst.struct_id];
4586 dst16_ptr = (uint16_t *)&dst_struct[ip->alu.dst.offset];
4587
4588 src_struct = t->structs[ip->alu.src.struct_id];
4589 src32_ptr = (uint32_t *)&src_struct[0];
4590
4591
4592
4593
4594
4595 for (i = 0; i < ip->alu.src.n_bits / 32; i++, src32_ptr++)
4596 r += *src32_ptr;
4597
4598
4599
4600
4601 r = (r & 0xFFFF) + (r >> 16);
4602
4603
4604
4605
4606 r = (r & 0xFFFF) + (r >> 16);
4607
4608
4609
4610
4611
4612
4613 r = (r & 0xFFFF) + (r >> 16);
4614
4615 r = ~r & 0xFFFF;
4616 r = r ? r : 0xFFFF;
4617
4618 *dst16_ptr = (uint16_t)r;
4619
4620
4621 thread_ip_inc(p);
4622}
4623
4624
4625
4626
4627static struct action *
4628action_find(struct rte_swx_pipeline *p, const char *name);
4629
4630static int
4631instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,
4632 struct action *action __rte_unused,
4633 char **tokens,
4634 int n_tokens,
4635 struct instruction *instr,
4636 struct instruction_data *data)
4637{
4638 CHECK(n_tokens == 2, EINVAL);
4639
4640 strcpy(data->jmp_label, tokens[1]);
4641
4642 instr->type = INSTR_JMP;
4643 instr->jmp.ip = NULL;
4644 return 0;
4645}
4646
4647static int
4648instr_jmp_valid_translate(struct rte_swx_pipeline *p,
4649 struct action *action __rte_unused,
4650 char **tokens,
4651 int n_tokens,
4652 struct instruction *instr,
4653 struct instruction_data *data)
4654{
4655 struct header *h;
4656
4657 CHECK(n_tokens == 3, EINVAL);
4658
4659 strcpy(data->jmp_label, tokens[1]);
4660
4661 h = header_parse(p, tokens[2]);
4662 CHECK(h, EINVAL);
4663
4664 instr->type = INSTR_JMP_VALID;
4665 instr->jmp.ip = NULL;
4666 instr->jmp.header_id = h->id;
4667 return 0;
4668}
4669
4670static int
4671instr_jmp_invalid_translate(struct rte_swx_pipeline *p,
4672 struct action *action __rte_unused,
4673 char **tokens,
4674 int n_tokens,
4675 struct instruction *instr,
4676 struct instruction_data *data)
4677{
4678 struct header *h;
4679
4680 CHECK(n_tokens == 3, EINVAL);
4681
4682 strcpy(data->jmp_label, tokens[1]);
4683
4684 h = header_parse(p, tokens[2]);
4685 CHECK(h, EINVAL);
4686
4687 instr->type = INSTR_JMP_INVALID;
4688 instr->jmp.ip = NULL;
4689 instr->jmp.header_id = h->id;
4690 return 0;
4691}
4692
4693static int
4694instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,
4695 struct action *action,
4696 char **tokens,
4697 int n_tokens,
4698 struct instruction *instr,
4699 struct instruction_data *data)
4700{
4701 CHECK(!action, EINVAL);
4702 CHECK(n_tokens == 2, EINVAL);
4703
4704 strcpy(data->jmp_label, tokens[1]);
4705
4706 instr->type = INSTR_JMP_HIT;
4707 instr->jmp.ip = NULL;
4708 return 0;
4709}
4710
4711static int
4712instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,
4713 struct action *action,
4714 char **tokens,
4715 int n_tokens,
4716 struct instruction *instr,
4717 struct instruction_data *data)
4718{
4719 CHECK(!action, EINVAL);
4720 CHECK(n_tokens == 2, EINVAL);
4721
4722 strcpy(data->jmp_label, tokens[1]);
4723
4724 instr->type = INSTR_JMP_MISS;
4725 instr->jmp.ip = NULL;
4726 return 0;
4727}
4728
4729static int
4730instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,
4731 struct action *action,
4732 char **tokens,
4733 int n_tokens,
4734 struct instruction *instr,
4735 struct instruction_data *data)
4736{
4737 struct action *a;
4738
4739 CHECK(!action, EINVAL);
4740 CHECK(n_tokens == 3, EINVAL);
4741
4742 strcpy(data->jmp_label, tokens[1]);
4743
4744 a = action_find(p, tokens[2]);
4745 CHECK(a, EINVAL);
4746
4747 instr->type = INSTR_JMP_ACTION_HIT;
4748 instr->jmp.ip = NULL;
4749 instr->jmp.action_id = a->id;
4750 return 0;
4751}
4752
4753static int
4754instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,
4755 struct action *action,
4756 char **tokens,
4757 int n_tokens,
4758 struct instruction *instr,
4759 struct instruction_data *data)
4760{
4761 struct action *a;
4762
4763 CHECK(!action, EINVAL);
4764 CHECK(n_tokens == 3, EINVAL);
4765
4766 strcpy(data->jmp_label, tokens[1]);
4767
4768 a = action_find(p, tokens[2]);
4769 CHECK(a, EINVAL);
4770
4771 instr->type = INSTR_JMP_ACTION_MISS;
4772 instr->jmp.ip = NULL;
4773 instr->jmp.action_id = a->id;
4774 return 0;
4775}
4776
4777static int
4778instr_jmp_eq_translate(struct rte_swx_pipeline *p,
4779 struct action *action,
4780 char **tokens,
4781 int n_tokens,
4782 struct instruction *instr,
4783 struct instruction_data *data)
4784{
4785 char *a = tokens[2], *b = tokens[3];
4786 struct field *fa, *fb;
4787 uint64_t b_val;
4788 uint32_t a_struct_id, b_struct_id;
4789
4790 CHECK(n_tokens == 4, EINVAL);
4791
4792 strcpy(data->jmp_label, tokens[1]);
4793
4794 fa = struct_field_parse(p, action, a, &a_struct_id);
4795 CHECK(fa, EINVAL);
4796
4797
4798 fb = struct_field_parse(p, action, b, &b_struct_id);
4799 if (fb) {
4800 instr->type = INSTR_JMP_EQ;
4801 if ((a[0] == 'h' && b[0] != 'h') ||
4802 (a[0] != 'h' && b[0] == 'h'))
4803 instr->type = INSTR_JMP_EQ_S;
4804 instr->jmp.ip = NULL;
4805
4806 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4807 instr->jmp.a.n_bits = fa->n_bits;
4808 instr->jmp.a.offset = fa->offset / 8;
4809 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
4810 instr->jmp.b.n_bits = fb->n_bits;
4811 instr->jmp.b.offset = fb->offset / 8;
4812 return 0;
4813 }
4814
4815
4816 b_val = strtoull(b, &b, 0);
4817 CHECK(!b[0], EINVAL);
4818
4819 if (a[0] == 'h')
4820 b_val = hton64(b_val) >> (64 - fa->n_bits);
4821
4822 instr->type = INSTR_JMP_EQ_I;
4823 instr->jmp.ip = NULL;
4824 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4825 instr->jmp.a.n_bits = fa->n_bits;
4826 instr->jmp.a.offset = fa->offset / 8;
4827 instr->jmp.b_val = b_val;
4828 return 0;
4829}
4830
4831static int
4832instr_jmp_neq_translate(struct rte_swx_pipeline *p,
4833 struct action *action,
4834 char **tokens,
4835 int n_tokens,
4836 struct instruction *instr,
4837 struct instruction_data *data)
4838{
4839 char *a = tokens[2], *b = tokens[3];
4840 struct field *fa, *fb;
4841 uint64_t b_val;
4842 uint32_t a_struct_id, b_struct_id;
4843
4844 CHECK(n_tokens == 4, EINVAL);
4845
4846 strcpy(data->jmp_label, tokens[1]);
4847
4848 fa = struct_field_parse(p, action, a, &a_struct_id);
4849 CHECK(fa, EINVAL);
4850
4851
4852 fb = struct_field_parse(p, action, b, &b_struct_id);
4853 if (fb) {
4854 instr->type = INSTR_JMP_NEQ;
4855 if ((a[0] == 'h' && b[0] != 'h') ||
4856 (a[0] != 'h' && b[0] == 'h'))
4857 instr->type = INSTR_JMP_NEQ_S;
4858 instr->jmp.ip = NULL;
4859
4860 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4861 instr->jmp.a.n_bits = fa->n_bits;
4862 instr->jmp.a.offset = fa->offset / 8;
4863 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
4864 instr->jmp.b.n_bits = fb->n_bits;
4865 instr->jmp.b.offset = fb->offset / 8;
4866 return 0;
4867 }
4868
4869
4870 b_val = strtoull(b, &b, 0);
4871 CHECK(!b[0], EINVAL);
4872
4873 if (a[0] == 'h')
4874 b_val = hton64(b_val) >> (64 - fa->n_bits);
4875
4876 instr->type = INSTR_JMP_NEQ_I;
4877 instr->jmp.ip = NULL;
4878 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4879 instr->jmp.a.n_bits = fa->n_bits;
4880 instr->jmp.a.offset = fa->offset / 8;
4881 instr->jmp.b_val = b_val;
4882 return 0;
4883}
4884
4885static int
4886instr_jmp_lt_translate(struct rte_swx_pipeline *p,
4887 struct action *action,
4888 char **tokens,
4889 int n_tokens,
4890 struct instruction *instr,
4891 struct instruction_data *data)
4892{
4893 char *a = tokens[2], *b = tokens[3];
4894 struct field *fa, *fb;
4895 uint64_t b_val;
4896 uint32_t a_struct_id, b_struct_id;
4897
4898 CHECK(n_tokens == 4, EINVAL);
4899
4900 strcpy(data->jmp_label, tokens[1]);
4901
4902 fa = struct_field_parse(p, action, a, &a_struct_id);
4903 CHECK(fa, EINVAL);
4904
4905
4906 fb = struct_field_parse(p, action, b, &b_struct_id);
4907 if (fb) {
4908 instr->type = INSTR_JMP_LT;
4909 if (a[0] == 'h' && b[0] == 'm')
4910 instr->type = INSTR_JMP_LT_HM;
4911 if (a[0] == 'm' && b[0] == 'h')
4912 instr->type = INSTR_JMP_LT_MH;
4913 if (a[0] == 'h' && b[0] == 'h')
4914 instr->type = INSTR_JMP_LT_HH;
4915 instr->jmp.ip = NULL;
4916
4917 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4918 instr->jmp.a.n_bits = fa->n_bits;
4919 instr->jmp.a.offset = fa->offset / 8;
4920 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
4921 instr->jmp.b.n_bits = fb->n_bits;
4922 instr->jmp.b.offset = fb->offset / 8;
4923 return 0;
4924 }
4925
4926
4927 b_val = strtoull(b, &b, 0);
4928 CHECK(!b[0], EINVAL);
4929
4930 instr->type = INSTR_JMP_LT_MI;
4931 if (a[0] == 'h')
4932 instr->type = INSTR_JMP_LT_HI;
4933 instr->jmp.ip = NULL;
4934
4935 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4936 instr->jmp.a.n_bits = fa->n_bits;
4937 instr->jmp.a.offset = fa->offset / 8;
4938 instr->jmp.b_val = b_val;
4939 return 0;
4940}
4941
4942static int
4943instr_jmp_gt_translate(struct rte_swx_pipeline *p,
4944 struct action *action,
4945 char **tokens,
4946 int n_tokens,
4947 struct instruction *instr,
4948 struct instruction_data *data)
4949{
4950 char *a = tokens[2], *b = tokens[3];
4951 struct field *fa, *fb;
4952 uint64_t b_val;
4953 uint32_t a_struct_id, b_struct_id;
4954
4955 CHECK(n_tokens == 4, EINVAL);
4956
4957 strcpy(data->jmp_label, tokens[1]);
4958
4959 fa = struct_field_parse(p, action, a, &a_struct_id);
4960 CHECK(fa, EINVAL);
4961
4962
4963 fb = struct_field_parse(p, action, b, &b_struct_id);
4964 if (fb) {
4965 instr->type = INSTR_JMP_GT;
4966 if (a[0] == 'h' && b[0] == 'm')
4967 instr->type = INSTR_JMP_GT_HM;
4968 if (a[0] == 'm' && b[0] == 'h')
4969 instr->type = INSTR_JMP_GT_MH;
4970 if (a[0] == 'h' && b[0] == 'h')
4971 instr->type = INSTR_JMP_GT_HH;
4972 instr->jmp.ip = NULL;
4973
4974 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4975 instr->jmp.a.n_bits = fa->n_bits;
4976 instr->jmp.a.offset = fa->offset / 8;
4977 instr->jmp.b.struct_id = (uint8_t)b_struct_id;
4978 instr->jmp.b.n_bits = fb->n_bits;
4979 instr->jmp.b.offset = fb->offset / 8;
4980 return 0;
4981 }
4982
4983
4984 b_val = strtoull(b, &b, 0);
4985 CHECK(!b[0], EINVAL);
4986
4987 instr->type = INSTR_JMP_GT_MI;
4988 if (a[0] == 'h')
4989 instr->type = INSTR_JMP_GT_HI;
4990 instr->jmp.ip = NULL;
4991
4992 instr->jmp.a.struct_id = (uint8_t)a_struct_id;
4993 instr->jmp.a.n_bits = fa->n_bits;
4994 instr->jmp.a.offset = fa->offset / 8;
4995 instr->jmp.b_val = b_val;
4996 return 0;
4997}
4998
4999static inline void
5000instr_jmp_exec(struct rte_swx_pipeline *p)
5001{
5002 struct thread *t = &p->threads[p->thread_id];
5003 struct instruction *ip = t->ip;
5004
5005 TRACE("[Thread %2u] jmp\n", p->thread_id);
5006
5007 thread_ip_set(t, ip->jmp.ip);
5008}
5009
5010static inline void
5011instr_jmp_valid_exec(struct rte_swx_pipeline *p)
5012{
5013 struct thread *t = &p->threads[p->thread_id];
5014 struct instruction *ip = t->ip;
5015 uint32_t header_id = ip->jmp.header_id;
5016
5017 TRACE("[Thread %2u] jmpv\n", p->thread_id);
5018
5019 t->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1);
5020}
5021
5022static inline void
5023instr_jmp_invalid_exec(struct rte_swx_pipeline *p)
5024{
5025 struct thread *t = &p->threads[p->thread_id];
5026 struct instruction *ip = t->ip;
5027 uint32_t header_id = ip->jmp.header_id;
5028
5029 TRACE("[Thread %2u] jmpnv\n", p->thread_id);
5030
5031 t->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip;
5032}
5033
5034static inline void
5035instr_jmp_hit_exec(struct rte_swx_pipeline *p)
5036{
5037 struct thread *t = &p->threads[p->thread_id];
5038 struct instruction *ip = t->ip;
5039 struct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip};
5040
5041 TRACE("[Thread %2u] jmph\n", p->thread_id);
5042
5043 t->ip = ip_next[t->hit];
5044}
5045
5046static inline void
5047instr_jmp_miss_exec(struct rte_swx_pipeline *p)
5048{
5049 struct thread *t = &p->threads[p->thread_id];
5050 struct instruction *ip = t->ip;
5051 struct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1};
5052
5053 TRACE("[Thread %2u] jmpnh\n", p->thread_id);
5054
5055 t->ip = ip_next[t->hit];
5056}
5057
5058static inline void
5059instr_jmp_action_hit_exec(struct rte_swx_pipeline *p)
5060{
5061 struct thread *t = &p->threads[p->thread_id];
5062 struct instruction *ip = t->ip;
5063
5064 TRACE("[Thread %2u] jmpa\n", p->thread_id);
5065
5066 t->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1);
5067}
5068
5069static inline void
5070instr_jmp_action_miss_exec(struct rte_swx_pipeline *p)
5071{
5072 struct thread *t = &p->threads[p->thread_id];
5073 struct instruction *ip = t->ip;
5074
5075 TRACE("[Thread %2u] jmpna\n", p->thread_id);
5076
5077 t->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip;
5078}
5079
5080static inline void
5081instr_jmp_eq_exec(struct rte_swx_pipeline *p)
5082{
5083 struct thread *t = &p->threads[p->thread_id];
5084 struct instruction *ip = t->ip;
5085
5086 TRACE("[Thread %2u] jmpeq\n", p->thread_id);
5087
5088 JMP_CMP(t, ip, ==);
5089}
5090
5091static inline void
5092instr_jmp_eq_s_exec(struct rte_swx_pipeline *p)
5093{
5094 struct thread *t = &p->threads[p->thread_id];
5095 struct instruction *ip = t->ip;
5096
5097 TRACE("[Thread %2u] jmpeq (s)\n", p->thread_id);
5098
5099 JMP_CMP_S(t, ip, ==);
5100}
5101
5102static inline void
5103instr_jmp_eq_i_exec(struct rte_swx_pipeline *p)
5104{
5105 struct thread *t = &p->threads[p->thread_id];
5106 struct instruction *ip = t->ip;
5107
5108 TRACE("[Thread %2u] jmpeq (i)\n", p->thread_id);
5109
5110 JMP_CMP_I(t, ip, ==);
5111}
5112
5113static inline void
5114instr_jmp_neq_exec(struct rte_swx_pipeline *p)
5115{
5116 struct thread *t = &p->threads[p->thread_id];
5117 struct instruction *ip = t->ip;
5118
5119 TRACE("[Thread %2u] jmpneq\n", p->thread_id);
5120
5121 JMP_CMP(t, ip, !=);
5122}
5123
5124static inline void
5125instr_jmp_neq_s_exec(struct rte_swx_pipeline *p)
5126{
5127 struct thread *t = &p->threads[p->thread_id];
5128 struct instruction *ip = t->ip;
5129
5130 TRACE("[Thread %2u] jmpneq (s)\n", p->thread_id);
5131
5132 JMP_CMP_S(t, ip, !=);
5133}
5134
5135static inline void
5136instr_jmp_neq_i_exec(struct rte_swx_pipeline *p)
5137{
5138 struct thread *t = &p->threads[p->thread_id];
5139 struct instruction *ip = t->ip;
5140
5141 TRACE("[Thread %2u] jmpneq (i)\n", p->thread_id);
5142
5143 JMP_CMP_I(t, ip, !=);
5144}
5145
5146static inline void
5147instr_jmp_lt_exec(struct rte_swx_pipeline *p)
5148{
5149 struct thread *t = &p->threads[p->thread_id];
5150 struct instruction *ip = t->ip;
5151
5152 TRACE("[Thread %2u] jmplt\n", p->thread_id);
5153
5154 JMP_CMP(t, ip, <);
5155}
5156
5157static inline void
5158instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p)
5159{
5160 struct thread *t = &p->threads[p->thread_id];
5161 struct instruction *ip = t->ip;
5162
5163 TRACE("[Thread %2u] jmplt (mh)\n", p->thread_id);
5164
5165 JMP_CMP_MH(t, ip, <);
5166}
5167
5168static inline void
5169instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p)
5170{
5171 struct thread *t = &p->threads[p->thread_id];
5172 struct instruction *ip = t->ip;
5173
5174 TRACE("[Thread %2u] jmplt (hm)\n", p->thread_id);
5175
5176 JMP_CMP_HM(t, ip, <);
5177}
5178
5179static inline void
5180instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p)
5181{
5182 struct thread *t = &p->threads[p->thread_id];
5183 struct instruction *ip = t->ip;
5184
5185 TRACE("[Thread %2u] jmplt (hh)\n", p->thread_id);
5186
5187 JMP_CMP_HH(t, ip, <);
5188}
5189
5190static inline void
5191instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p)
5192{
5193 struct thread *t = &p->threads[p->thread_id];
5194 struct instruction *ip = t->ip;
5195
5196 TRACE("[Thread %2u] jmplt (mi)\n", p->thread_id);
5197
5198 JMP_CMP_MI(t, ip, <);
5199}
5200
5201static inline void
5202instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p)
5203{
5204 struct thread *t = &p->threads[p->thread_id];
5205 struct instruction *ip = t->ip;
5206
5207 TRACE("[Thread %2u] jmplt (hi)\n", p->thread_id);
5208
5209 JMP_CMP_HI(t, ip, <);
5210}
5211
5212static inline void
5213instr_jmp_gt_exec(struct rte_swx_pipeline *p)
5214{
5215 struct thread *t = &p->threads[p->thread_id];
5216 struct instruction *ip = t->ip;
5217
5218 TRACE("[Thread %2u] jmpgt\n", p->thread_id);
5219
5220 JMP_CMP(t, ip, >);
5221}
5222
5223static inline void
5224instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p)
5225{
5226 struct thread *t = &p->threads[p->thread_id];
5227 struct instruction *ip = t->ip;
5228
5229 TRACE("[Thread %2u] jmpgt (mh)\n", p->thread_id);
5230
5231 JMP_CMP_MH(t, ip, >);
5232}
5233
5234static inline void
5235instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p)
5236{
5237 struct thread *t = &p->threads[p->thread_id];
5238 struct instruction *ip = t->ip;
5239
5240 TRACE("[Thread %2u] jmpgt (hm)\n", p->thread_id);
5241
5242 JMP_CMP_HM(t, ip, >);
5243}
5244
5245static inline void
5246instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p)
5247{
5248 struct thread *t = &p->threads[p->thread_id];
5249 struct instruction *ip = t->ip;
5250
5251 TRACE("[Thread %2u] jmpgt (hh)\n", p->thread_id);
5252
5253 JMP_CMP_HH(t, ip, >);
5254}
5255
5256static inline void
5257instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p)
5258{
5259 struct thread *t = &p->threads[p->thread_id];
5260 struct instruction *ip = t->ip;
5261
5262 TRACE("[Thread %2u] jmpgt (mi)\n", p->thread_id);
5263
5264 JMP_CMP_MI(t, ip, >);
5265}
5266
5267static inline void
5268instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p)
5269{
5270 struct thread *t = &p->threads[p->thread_id];
5271 struct instruction *ip = t->ip;
5272
5273 TRACE("[Thread %2u] jmpgt (hi)\n", p->thread_id);
5274
5275 JMP_CMP_HI(t, ip, >);
5276}
5277
5278
5279
5280
5281static int
5282instr_return_translate(struct rte_swx_pipeline *p __rte_unused,
5283 struct action *action,
5284 char **tokens __rte_unused,
5285 int n_tokens,
5286 struct instruction *instr,
5287 struct instruction_data *data __rte_unused)
5288{
5289 CHECK(action, EINVAL);
5290 CHECK(n_tokens == 1, EINVAL);
5291
5292 instr->type = INSTR_RETURN;
5293 return 0;
5294}
5295
5296static inline void
5297instr_return_exec(struct rte_swx_pipeline *p)
5298{
5299 struct thread *t = &p->threads[p->thread_id];
5300
5301 TRACE("[Thread %2u] return\n", p->thread_id);
5302
5303 t->ip = t->ret;
5304}
5305
5306static int
5307instr_translate(struct rte_swx_pipeline *p,
5308 struct action *action,
5309 char *string,
5310 struct instruction *instr,
5311 struct instruction_data *data)
5312{
5313 char *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX];
5314 int n_tokens = 0, tpos = 0;
5315
5316
5317 for ( ; ; ) {
5318 char *token;
5319
5320 token = strtok_r(string, " \t\v", &string);
5321 if (!token)
5322 break;
5323
5324 CHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL);
5325 CHECK_NAME(token, EINVAL);
5326
5327 tokens[n_tokens] = token;
5328 n_tokens++;
5329 }
5330
5331 CHECK(n_tokens, EINVAL);
5332
5333
5334 if ((n_tokens >= 2) && !strcmp(tokens[1], ":")) {
5335 strcpy(data->label, tokens[0]);
5336
5337 tpos += 2;
5338 CHECK(n_tokens - tpos, EINVAL);
5339 }
5340
5341
5342 if (!strcmp(tokens[tpos], "rx"))
5343 return instr_rx_translate(p,
5344 action,
5345 &tokens[tpos],
5346 n_tokens - tpos,
5347 instr,
5348 data);
5349
5350 if (!strcmp(tokens[tpos], "tx"))
5351 return instr_tx_translate(p,
5352 action,
5353 &tokens[tpos],
5354 n_tokens - tpos,
5355 instr,
5356 data);
5357
5358 if (!strcmp(tokens[tpos], "extract"))
5359 return instr_hdr_extract_translate(p,
5360 action,
5361 &tokens[tpos],
5362 n_tokens - tpos,
5363 instr,
5364 data);
5365
5366 if (!strcmp(tokens[tpos], "emit"))
5367 return instr_hdr_emit_translate(p,
5368 action,
5369 &tokens[tpos],
5370 n_tokens - tpos,
5371 instr,
5372 data);
5373
5374 if (!strcmp(tokens[tpos], "validate"))
5375 return instr_hdr_validate_translate(p,
5376 action,
5377 &tokens[tpos],
5378 n_tokens - tpos,
5379 instr,
5380 data);
5381
5382 if (!strcmp(tokens[tpos], "invalidate"))
5383 return instr_hdr_invalidate_translate(p,
5384 action,
5385 &tokens[tpos],
5386 n_tokens - tpos,
5387 instr,
5388 data);
5389
5390 if (!strcmp(tokens[tpos], "mov"))
5391 return instr_mov_translate(p,
5392 action,
5393 &tokens[tpos],
5394 n_tokens - tpos,
5395 instr,
5396 data);
5397
5398 if (!strcmp(tokens[tpos], "dma"))
5399 return instr_dma_translate(p,
5400 action,
5401 &tokens[tpos],
5402 n_tokens - tpos,
5403 instr,
5404 data);
5405
5406 if (!strcmp(tokens[tpos], "add"))
5407 return instr_alu_add_translate(p,
5408 action,
5409 &tokens[tpos],
5410 n_tokens - tpos,
5411 instr,
5412 data);
5413
5414 if (!strcmp(tokens[tpos], "sub"))
5415 return instr_alu_sub_translate(p,
5416 action,
5417 &tokens[tpos],
5418 n_tokens - tpos,
5419 instr,
5420 data);
5421
5422 if (!strcmp(tokens[tpos], "ckadd"))
5423 return instr_alu_ckadd_translate(p,
5424 action,
5425 &tokens[tpos],
5426 n_tokens - tpos,
5427 instr,
5428 data);
5429
5430 if (!strcmp(tokens[tpos], "cksub"))
5431 return instr_alu_cksub_translate(p,
5432 action,
5433 &tokens[tpos],
5434 n_tokens - tpos,
5435 instr,
5436 data);
5437
5438 if (!strcmp(tokens[tpos], "and"))
5439 return instr_alu_and_translate(p,
5440 action,
5441 &tokens[tpos],
5442 n_tokens - tpos,
5443 instr,
5444 data);
5445
5446 if (!strcmp(tokens[tpos], "or"))
5447 return instr_alu_or_translate(p,
5448 action,
5449 &tokens[tpos],
5450 n_tokens - tpos,
5451 instr,
5452 data);
5453
5454 if (!strcmp(tokens[tpos], "xor"))
5455 return instr_alu_xor_translate(p,
5456 action,
5457 &tokens[tpos],
5458 n_tokens - tpos,
5459 instr,
5460 data);
5461
5462 if (!strcmp(tokens[tpos], "shl"))
5463 return instr_alu_shl_translate(p,
5464 action,
5465 &tokens[tpos],
5466 n_tokens - tpos,
5467 instr,
5468 data);
5469
5470 if (!strcmp(tokens[tpos], "shr"))
5471 return instr_alu_shr_translate(p,
5472 action,
5473 &tokens[tpos],
5474 n_tokens - tpos,
5475 instr,
5476 data);
5477
5478 if (!strcmp(tokens[tpos], "table"))
5479 return instr_table_translate(p,
5480 action,
5481 &tokens[tpos],
5482 n_tokens - tpos,
5483 instr,
5484 data);
5485
5486 if (!strcmp(tokens[tpos], "extern"))
5487 return instr_extern_translate(p,
5488 action,
5489 &tokens[tpos],
5490 n_tokens - tpos,
5491 instr,
5492 data);
5493
5494 if (!strcmp(tokens[tpos], "jmp"))
5495 return instr_jmp_translate(p,
5496 action,
5497 &tokens[tpos],
5498 n_tokens - tpos,
5499 instr,
5500 data);
5501
5502 if (!strcmp(tokens[tpos], "jmpv"))
5503 return instr_jmp_valid_translate(p,
5504 action,
5505 &tokens[tpos],
5506 n_tokens - tpos,
5507 instr,
5508 data);
5509
5510 if (!strcmp(tokens[tpos], "jmpnv"))
5511 return instr_jmp_invalid_translate(p,
5512 action,
5513 &tokens[tpos],
5514 n_tokens - tpos,
5515 instr,
5516 data);
5517
5518 if (!strcmp(tokens[tpos], "jmph"))
5519 return instr_jmp_hit_translate(p,
5520 action,
5521 &tokens[tpos],
5522 n_tokens - tpos,
5523 instr,
5524 data);
5525
5526 if (!strcmp(tokens[tpos], "jmpnh"))
5527 return instr_jmp_miss_translate(p,
5528 action,
5529 &tokens[tpos],
5530 n_tokens - tpos,
5531 instr,
5532 data);
5533
5534 if (!strcmp(tokens[tpos], "jmpa"))
5535 return instr_jmp_action_hit_translate(p,
5536 action,
5537 &tokens[tpos],
5538 n_tokens - tpos,
5539 instr,
5540 data);
5541
5542 if (!strcmp(tokens[tpos], "jmpna"))
5543 return instr_jmp_action_miss_translate(p,
5544 action,
5545 &tokens[tpos],
5546 n_tokens - tpos,
5547 instr,
5548 data);
5549
5550 if (!strcmp(tokens[tpos], "jmpeq"))
5551 return instr_jmp_eq_translate(p,
5552 action,
5553 &tokens[tpos],
5554 n_tokens - tpos,
5555 instr,
5556 data);
5557
5558 if (!strcmp(tokens[tpos], "jmpneq"))
5559 return instr_jmp_neq_translate(p,
5560 action,
5561 &tokens[tpos],
5562 n_tokens - tpos,
5563 instr,
5564 data);
5565
5566 if (!strcmp(tokens[tpos], "jmplt"))
5567 return instr_jmp_lt_translate(p,
5568 action,
5569 &tokens[tpos],
5570 n_tokens - tpos,
5571 instr,
5572 data);
5573
5574 if (!strcmp(tokens[tpos], "jmpgt"))
5575 return instr_jmp_gt_translate(p,
5576 action,
5577 &tokens[tpos],
5578 n_tokens - tpos,
5579 instr,
5580 data);
5581
5582 if (!strcmp(tokens[tpos], "return"))
5583 return instr_return_translate(p,
5584 action,
5585 &tokens[tpos],
5586 n_tokens - tpos,
5587 instr,
5588 data);
5589
5590 CHECK(0, EINVAL);
5591}
5592
5593static struct instruction_data *
5594label_find(struct instruction_data *data, uint32_t n, const char *label)
5595{
5596 uint32_t i;
5597
5598 for (i = 0; i < n; i++)
5599 if (!strcmp(label, data[i].label))
5600 return &data[i];
5601
5602 return NULL;
5603}
5604
5605static uint32_t
5606label_is_used(struct instruction_data *data, uint32_t n, const char *label)
5607{
5608 uint32_t count = 0, i;
5609
5610 if (!label[0])
5611 return 0;
5612
5613 for (i = 0; i < n; i++)
5614 if (!strcmp(label, data[i].jmp_label))
5615 count++;
5616
5617 return count;
5618}
5619
5620static int
5621instr_label_check(struct instruction_data *instruction_data,
5622 uint32_t n_instructions)
5623{
5624 uint32_t i;
5625
5626
5627 for (i = 0; i < n_instructions; i++) {
5628 struct instruction_data *data = &instruction_data[i];
5629 char *label = data->label;
5630 uint32_t j;
5631
5632 if (!label[0])
5633 continue;
5634
5635 for (j = i + 1; j < n_instructions; j++)
5636 CHECK(strcmp(label, data[j].label), EINVAL);
5637 }
5638
5639
5640 for (i = 0; i < n_instructions; i++) {
5641 struct instruction_data *data = &instruction_data[i];
5642 char *label = data->label;
5643
5644 data->n_users = label_is_used(instruction_data,
5645 n_instructions,
5646 label);
5647 }
5648
5649 return 0;
5650}
5651
5652static int
5653instr_jmp_resolve(struct instruction *instructions,
5654 struct instruction_data *instruction_data,
5655 uint32_t n_instructions)
5656{
5657 uint32_t i;
5658
5659 for (i = 0; i < n_instructions; i++) {
5660 struct instruction *instr = &instructions[i];
5661 struct instruction_data *data = &instruction_data[i];
5662 struct instruction_data *found;
5663
5664 if (!instruction_is_jmp(instr))
5665 continue;
5666
5667 found = label_find(instruction_data,
5668 n_instructions,
5669 data->jmp_label);
5670 CHECK(found, EINVAL);
5671
5672 instr->jmp.ip = &instructions[found - instruction_data];
5673 }
5674
5675 return 0;
5676}
5677
5678static int
5679instr_verify(struct rte_swx_pipeline *p __rte_unused,
5680 struct action *a,
5681 struct instruction *instr,
5682 struct instruction_data *data __rte_unused,
5683 uint32_t n_instructions)
5684{
5685 if (!a) {
5686 enum instruction_type type;
5687 uint32_t i;
5688
5689
5690 CHECK(instr[0].type == INSTR_RX, EINVAL);
5691
5692
5693 for (i = 0; i < n_instructions; i++) {
5694 type = instr[i].type;
5695
5696 if (type == INSTR_TX)
5697 break;
5698 }
5699 CHECK(i < n_instructions, EINVAL);
5700
5701
5702
5703
5704 type = instr[n_instructions - 1].type;
5705 CHECK((type == INSTR_TX) || (type == INSTR_JMP), EINVAL);
5706 }
5707
5708 if (a) {
5709 enum instruction_type type;
5710 uint32_t i;
5711
5712
5713 for (i = 0; i < n_instructions; i++) {
5714 type = instr[i].type;
5715
5716 if ((type == INSTR_RETURN) || (type == INSTR_TX))
5717 break;
5718 }
5719 CHECK(i < n_instructions, EINVAL);
5720 }
5721
5722 return 0;
5723}
5724
5725static int
5726instr_pattern_extract_many_detect(struct instruction *instr,
5727 struct instruction_data *data,
5728 uint32_t n_instr,
5729 uint32_t *n_pattern_instr)
5730{
5731 uint32_t i;
5732
5733 for (i = 0; i < n_instr; i++) {
5734 if (data[i].invalid)
5735 break;
5736
5737 if (instr[i].type != INSTR_HDR_EXTRACT)
5738 break;
5739
5740 if (i == RTE_DIM(instr->io.hdr.header_id))
5741 break;
5742
5743 if (i && data[i].n_users)
5744 break;
5745 }
5746
5747 if (i < 2)
5748 return 0;
5749
5750 *n_pattern_instr = i;
5751 return 1;
5752}
5753
5754static void
5755instr_pattern_extract_many_optimize(struct instruction *instr,
5756 struct instruction_data *data,
5757 uint32_t n_instr)
5758{
5759 uint32_t i;
5760
5761 for (i = 1; i < n_instr; i++) {
5762 instr[0].type++;
5763 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
5764 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
5765 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
5766
5767 data[i].invalid = 1;
5768 }
5769}
5770
5771static int
5772instr_pattern_emit_many_tx_detect(struct instruction *instr,
5773 struct instruction_data *data,
5774 uint32_t n_instr,
5775 uint32_t *n_pattern_instr)
5776{
5777 uint32_t i;
5778
5779 for (i = 0; i < n_instr; i++) {
5780 if (data[i].invalid)
5781 break;
5782
5783 if (instr[i].type != INSTR_HDR_EMIT)
5784 break;
5785
5786 if (i == RTE_DIM(instr->io.hdr.header_id))
5787 break;
5788
5789 if (i && data[i].n_users)
5790 break;
5791 }
5792
5793 if (!i)
5794 return 0;
5795
5796 if (instr[i].type != INSTR_TX)
5797 return 0;
5798
5799 if (data[i].n_users)
5800 return 0;
5801
5802 i++;
5803
5804 *n_pattern_instr = i;
5805 return 1;
5806}
5807
5808static void
5809instr_pattern_emit_many_tx_optimize(struct instruction *instr,
5810 struct instruction_data *data,
5811 uint32_t n_instr)
5812{
5813 uint32_t i;
5814
5815
5816 for (i = 1; i < n_instr - 1; i++) {
5817 instr[0].type++;
5818 instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
5819 instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
5820 instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
5821
5822 data[i].invalid = 1;
5823 }
5824
5825
5826 instr[0].type++;
5827 instr[0].io.io.offset = instr[i].io.io.offset;
5828 instr[0].io.io.n_bits = instr[i].io.io.n_bits;
5829 data[i].invalid = 1;
5830}
5831
5832static int
5833instr_pattern_dma_many_detect(struct instruction *instr,
5834 struct instruction_data *data,
5835 uint32_t n_instr,
5836 uint32_t *n_pattern_instr)
5837{
5838 uint32_t i;
5839
5840 for (i = 0; i < n_instr; i++) {
5841 if (data[i].invalid)
5842 break;
5843
5844 if (instr[i].type != INSTR_DMA_HT)
5845 break;
5846
5847 if (i == RTE_DIM(instr->dma.dst.header_id))
5848 break;
5849
5850 if (i && data[i].n_users)
5851 break;
5852 }
5853
5854 if (i < 2)
5855 return 0;
5856
5857 *n_pattern_instr = i;
5858 return 1;
5859}
5860
5861static void
5862instr_pattern_dma_many_optimize(struct instruction *instr,
5863 struct instruction_data *data,
5864 uint32_t n_instr)
5865{
5866 uint32_t i;
5867
5868 for (i = 1; i < n_instr; i++) {
5869 instr[0].type++;
5870 instr[0].dma.dst.header_id[i] = instr[i].dma.dst.header_id[0];
5871 instr[0].dma.dst.struct_id[i] = instr[i].dma.dst.struct_id[0];
5872 instr[0].dma.src.offset[i] = instr[i].dma.src.offset[0];
5873 instr[0].dma.n_bytes[i] = instr[i].dma.n_bytes[0];
5874
5875 data[i].invalid = 1;
5876 }
5877}
5878
5879static uint32_t
5880instr_optimize(struct instruction *instructions,
5881 struct instruction_data *instruction_data,
5882 uint32_t n_instructions)
5883{
5884 uint32_t i, pos = 0;
5885
5886 for (i = 0; i < n_instructions; ) {
5887 struct instruction *instr = &instructions[i];
5888 struct instruction_data *data = &instruction_data[i];
5889 uint32_t n_instr = 0;
5890 int detected;
5891
5892
5893 detected = instr_pattern_extract_many_detect(instr,
5894 data,
5895 n_instructions - i,
5896 &n_instr);
5897 if (detected) {
5898 instr_pattern_extract_many_optimize(instr,
5899 data,
5900 n_instr);
5901 i += n_instr;
5902 continue;
5903 }
5904
5905
5906 detected = instr_pattern_emit_many_tx_detect(instr,
5907 data,
5908 n_instructions - i,
5909 &n_instr);
5910 if (detected) {
5911 instr_pattern_emit_many_tx_optimize(instr,
5912 data,
5913 n_instr);
5914 i += n_instr;
5915 continue;
5916 }
5917
5918
5919 detected = instr_pattern_dma_many_detect(instr,
5920 data,
5921 n_instructions - i,
5922 &n_instr);
5923 if (detected) {
5924 instr_pattern_dma_many_optimize(instr, data, n_instr);
5925 i += n_instr;
5926 continue;
5927 }
5928
5929
5930 i++;
5931 }
5932
5933
5934 for (i = 0; i < n_instructions; i++) {
5935 struct instruction *instr = &instructions[i];
5936 struct instruction_data *data = &instruction_data[i];
5937
5938 if (data->invalid)
5939 continue;
5940
5941 if (i != pos) {
5942 memcpy(&instructions[pos], instr, sizeof(*instr));
5943 memcpy(&instruction_data[pos], data, sizeof(*data));
5944 }
5945
5946 pos++;
5947 }
5948
5949 return pos;
5950}
5951
5952static int
5953instruction_config(struct rte_swx_pipeline *p,
5954 struct action *a,
5955 const char **instructions,
5956 uint32_t n_instructions)
5957{
5958 struct instruction *instr = NULL;
5959 struct instruction_data *data = NULL;
5960 int err = 0;
5961 uint32_t i;
5962
5963 CHECK(n_instructions, EINVAL);
5964 CHECK(instructions, EINVAL);
5965 for (i = 0; i < n_instructions; i++)
5966 CHECK_INSTRUCTION(instructions[i], EINVAL);
5967
5968
5969 instr = calloc(n_instructions, sizeof(struct instruction));
5970 if (!instr) {
5971 err = ENOMEM;
5972 goto error;
5973 }
5974
5975 data = calloc(n_instructions, sizeof(struct instruction_data));
5976 if (!data) {
5977 err = ENOMEM;
5978 goto error;
5979 }
5980
5981 for (i = 0; i < n_instructions; i++) {
5982 char *string = strdup(instructions[i]);
5983 if (!string) {
5984 err = ENOMEM;
5985 goto error;
5986 }
5987
5988 err = instr_translate(p, a, string, &instr[i], &data[i]);
5989 if (err) {
5990 free(string);
5991 goto error;
5992 }
5993
5994 free(string);
5995 }
5996
5997 err = instr_label_check(data, n_instructions);
5998 if (err)
5999 goto error;
6000
6001 err = instr_verify(p, a, instr, data, n_instructions);
6002 if (err)
6003 goto error;
6004
6005 n_instructions = instr_optimize(instr, data, n_instructions);
6006
6007 err = instr_jmp_resolve(instr, data, n_instructions);
6008 if (err)
6009 goto error;
6010
6011 if (a) {
6012 a->instructions = instr;
6013 a->n_instructions = n_instructions;
6014 } else {
6015 p->instructions = instr;
6016 p->n_instructions = n_instructions;
6017 }
6018
6019 free(data);
6020 return 0;
6021
6022error:
6023 free(data);
6024 free(instr);
6025 return err;
6026}
6027
6028typedef void (*instr_exec_t)(struct rte_swx_pipeline *);
6029
6030static instr_exec_t instruction_table[] = {
6031 [INSTR_RX] = instr_rx_exec,
6032 [INSTR_TX] = instr_tx_exec,
6033
6034 [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
6035 [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
6036 [INSTR_HDR_EXTRACT3] = instr_hdr_extract3_exec,
6037 [INSTR_HDR_EXTRACT4] = instr_hdr_extract4_exec,
6038 [INSTR_HDR_EXTRACT5] = instr_hdr_extract5_exec,
6039 [INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec,
6040 [INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec,
6041 [INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec,
6042
6043 [INSTR_HDR_EMIT] = instr_hdr_emit_exec,
6044 [INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec,
6045 [INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec,
6046 [INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec,
6047 [INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec,
6048 [INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec,
6049 [INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec,
6050 [INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec,
6051 [INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec,
6052
6053 [INSTR_HDR_VALIDATE] = instr_hdr_validate_exec,
6054 [INSTR_HDR_INVALIDATE] = instr_hdr_invalidate_exec,
6055
6056 [INSTR_MOV] = instr_mov_exec,
6057 [INSTR_MOV_S] = instr_mov_s_exec,
6058 [INSTR_MOV_I] = instr_mov_i_exec,
6059
6060 [INSTR_DMA_HT] = instr_dma_ht_exec,
6061 [INSTR_DMA_HT2] = instr_dma_ht2_exec,
6062 [INSTR_DMA_HT3] = instr_dma_ht3_exec,
6063 [INSTR_DMA_HT4] = instr_dma_ht4_exec,
6064 [INSTR_DMA_HT5] = instr_dma_ht5_exec,
6065 [INSTR_DMA_HT6] = instr_dma_ht6_exec,
6066 [INSTR_DMA_HT7] = instr_dma_ht7_exec,
6067 [INSTR_DMA_HT8] = instr_dma_ht8_exec,
6068
6069 [INSTR_ALU_ADD] = instr_alu_add_exec,
6070 [INSTR_ALU_ADD_MH] = instr_alu_add_mh_exec,
6071 [INSTR_ALU_ADD_HM] = instr_alu_add_hm_exec,
6072 [INSTR_ALU_ADD_HH] = instr_alu_add_hh_exec,
6073 [INSTR_ALU_ADD_MI] = instr_alu_add_mi_exec,
6074 [INSTR_ALU_ADD_HI] = instr_alu_add_hi_exec,
6075
6076 [INSTR_ALU_SUB] = instr_alu_sub_exec,
6077 [INSTR_ALU_SUB_MH] = instr_alu_sub_mh_exec,
6078 [INSTR_ALU_SUB_HM] = instr_alu_sub_hm_exec,
6079 [INSTR_ALU_SUB_HH] = instr_alu_sub_hh_exec,
6080 [INSTR_ALU_SUB_MI] = instr_alu_sub_mi_exec,
6081 [INSTR_ALU_SUB_HI] = instr_alu_sub_hi_exec,
6082
6083 [INSTR_ALU_CKADD_FIELD] = instr_alu_ckadd_field_exec,
6084 [INSTR_ALU_CKADD_STRUCT] = instr_alu_ckadd_struct_exec,
6085 [INSTR_ALU_CKADD_STRUCT20] = instr_alu_ckadd_struct20_exec,
6086 [INSTR_ALU_CKSUB_FIELD] = instr_alu_cksub_field_exec,
6087
6088 [INSTR_ALU_AND] = instr_alu_and_exec,
6089 [INSTR_ALU_AND_S] = instr_alu_and_s_exec,
6090 [INSTR_ALU_AND_I] = instr_alu_and_i_exec,
6091
6092 [INSTR_ALU_OR] = instr_alu_or_exec,
6093 [INSTR_ALU_OR_S] = instr_alu_or_s_exec,
6094 [INSTR_ALU_OR_I] = instr_alu_or_i_exec,
6095
6096 [INSTR_ALU_XOR] = instr_alu_xor_exec,
6097 [INSTR_ALU_XOR_S] = instr_alu_xor_s_exec,
6098 [INSTR_ALU_XOR_I] = instr_alu_xor_i_exec,
6099
6100 [INSTR_ALU_SHL] = instr_alu_shl_exec,
6101 [INSTR_ALU_SHL_MH] = instr_alu_shl_mh_exec,
6102 [INSTR_ALU_SHL_HM] = instr_alu_shl_hm_exec,
6103 [INSTR_ALU_SHL_HH] = instr_alu_shl_hh_exec,
6104 [INSTR_ALU_SHL_MI] = instr_alu_shl_mi_exec,
6105 [INSTR_ALU_SHL_HI] = instr_alu_shl_hi_exec,
6106
6107 [INSTR_ALU_SHR] = instr_alu_shr_exec,
6108 [INSTR_ALU_SHR_MH] = instr_alu_shr_mh_exec,
6109 [INSTR_ALU_SHR_HM] = instr_alu_shr_hm_exec,
6110 [INSTR_ALU_SHR_HH] = instr_alu_shr_hh_exec,
6111 [INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec,
6112 [INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec,
6113
6114 [INSTR_TABLE] = instr_table_exec,
6115 [INSTR_EXTERN_OBJ] = instr_extern_obj_exec,
6116 [INSTR_EXTERN_FUNC] = instr_extern_func_exec,
6117
6118 [INSTR_JMP] = instr_jmp_exec,
6119 [INSTR_JMP_VALID] = instr_jmp_valid_exec,
6120 [INSTR_JMP_INVALID] = instr_jmp_invalid_exec,
6121 [INSTR_JMP_HIT] = instr_jmp_hit_exec,
6122 [INSTR_JMP_MISS] = instr_jmp_miss_exec,
6123 [INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec,
6124 [INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec,
6125
6126 [INSTR_JMP_EQ] = instr_jmp_eq_exec,
6127 [INSTR_JMP_EQ_S] = instr_jmp_eq_s_exec,
6128 [INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec,
6129
6130 [INSTR_JMP_NEQ] = instr_jmp_neq_exec,
6131 [INSTR_JMP_NEQ_S] = instr_jmp_neq_s_exec,
6132 [INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec,
6133
6134 [INSTR_JMP_LT] = instr_jmp_lt_exec,
6135 [INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec,
6136 [INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec,
6137 [INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec,
6138 [INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec,
6139 [INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec,
6140
6141 [INSTR_JMP_GT] = instr_jmp_gt_exec,
6142 [INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec,
6143 [INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec,
6144 [INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec,
6145 [INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec,
6146 [INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec,
6147
6148 [INSTR_RETURN] = instr_return_exec,
6149};
6150
6151static inline void
6152instr_exec(struct rte_swx_pipeline *p)
6153{
6154 struct thread *t = &p->threads[p->thread_id];
6155 struct instruction *ip = t->ip;
6156 instr_exec_t instr = instruction_table[ip->type];
6157
6158 instr(p);
6159}
6160
6161
6162
6163
6164static struct action *
6165action_find(struct rte_swx_pipeline *p, const char *name)
6166{
6167 struct action *elem;
6168
6169 if (!name)
6170 return NULL;
6171
6172 TAILQ_FOREACH(elem, &p->actions, node)
6173 if (strcmp(elem->name, name) == 0)
6174 return elem;
6175
6176 return NULL;
6177}
6178
6179static struct action *
6180action_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
6181{
6182 struct action *action = NULL;
6183
6184 TAILQ_FOREACH(action, &p->actions, node)
6185 if (action->id == id)
6186 return action;
6187
6188 return NULL;
6189}
6190
6191static struct field *
6192action_field_find(struct action *a, const char *name)
6193{
6194 return a->st ? struct_type_field_find(a->st, name) : NULL;
6195}
6196
6197static struct field *
6198action_field_parse(struct action *action, const char *name)
6199{
6200 if (name[0] != 't' || name[1] != '.')
6201 return NULL;
6202
6203 return action_field_find(action, &name[2]);
6204}
6205
6206int
6207rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
6208 const char *name,
6209 const char *args_struct_type_name,
6210 const char **instructions,
6211 uint32_t n_instructions)
6212{
6213 struct struct_type *args_struct_type;
6214 struct action *a;
6215 int err;
6216
6217 CHECK(p, EINVAL);
6218
6219 CHECK_NAME(name, EINVAL);
6220 CHECK(!action_find(p, name), EEXIST);
6221
6222 if (args_struct_type_name) {
6223 CHECK_NAME(args_struct_type_name, EINVAL);
6224 args_struct_type = struct_type_find(p, args_struct_type_name);
6225 CHECK(args_struct_type, EINVAL);
6226 } else {
6227 args_struct_type = NULL;
6228 }
6229
6230
6231 a = calloc(1, sizeof(struct action));
6232 CHECK(a, ENOMEM);
6233
6234
6235 strcpy(a->name, name);
6236 a->st = args_struct_type;
6237 a->id = p->n_actions;
6238
6239
6240 err = instruction_config(p, a, instructions, n_instructions);
6241 if (err) {
6242 free(a);
6243 return err;
6244 }
6245
6246
6247 TAILQ_INSERT_TAIL(&p->actions, a, node);
6248 p->n_actions++;
6249
6250 return 0;
6251}
6252
6253static int
6254action_build(struct rte_swx_pipeline *p)
6255{
6256 struct action *action;
6257
6258 p->action_instructions = calloc(p->n_actions,
6259 sizeof(struct instruction *));
6260 CHECK(p->action_instructions, ENOMEM);
6261
6262 TAILQ_FOREACH(action, &p->actions, node)
6263 p->action_instructions[action->id] = action->instructions;
6264
6265 return 0;
6266}
6267
6268static void
6269action_build_free(struct rte_swx_pipeline *p)
6270{
6271 free(p->action_instructions);
6272 p->action_instructions = NULL;
6273}
6274
6275static void
6276action_free(struct rte_swx_pipeline *p)
6277{
6278 action_build_free(p);
6279
6280 for ( ; ; ) {
6281 struct action *action;
6282
6283 action = TAILQ_FIRST(&p->actions);
6284 if (!action)
6285 break;
6286
6287 TAILQ_REMOVE(&p->actions, action, node);
6288 free(action->instructions);
6289 free(action);
6290 }
6291}
6292
6293
6294
6295
6296static struct table_type *
6297table_type_find(struct rte_swx_pipeline *p, const char *name)
6298{
6299 struct table_type *elem;
6300
6301 TAILQ_FOREACH(elem, &p->table_types, node)
6302 if (strcmp(elem->name, name) == 0)
6303 return elem;
6304
6305 return NULL;
6306}
6307
6308static struct table_type *
6309table_type_resolve(struct rte_swx_pipeline *p,
6310 const char *recommended_type_name,
6311 enum rte_swx_table_match_type match_type)
6312{
6313 struct table_type *elem;
6314
6315
6316 if (recommended_type_name)
6317 TAILQ_FOREACH(elem, &p->table_types, node)
6318 if (!strcmp(elem->name, recommended_type_name) &&
6319 (elem->match_type == match_type))
6320 return elem;
6321
6322
6323
6324
6325 TAILQ_FOREACH(elem, &p->table_types, node)
6326 if (elem->match_type == match_type)
6327 return elem;
6328
6329 return NULL;
6330}
6331
6332static struct table *
6333table_find(struct rte_swx_pipeline *p, const char *name)
6334{
6335 struct table *elem;
6336
6337 TAILQ_FOREACH(elem, &p->tables, node)
6338 if (strcmp(elem->name, name) == 0)
6339 return elem;
6340
6341 return NULL;
6342}
6343
6344static struct table *
6345table_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
6346{
6347 struct table *table = NULL;
6348
6349 TAILQ_FOREACH(table, &p->tables, node)
6350 if (table->id == id)
6351 return table;
6352
6353 return NULL;
6354}
6355
6356int
6357rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p,
6358 const char *name,
6359 enum rte_swx_table_match_type match_type,
6360 struct rte_swx_table_ops *ops)
6361{
6362 struct table_type *elem;
6363
6364 CHECK(p, EINVAL);
6365
6366 CHECK_NAME(name, EINVAL);
6367 CHECK(!table_type_find(p, name), EEXIST);
6368
6369 CHECK(ops, EINVAL);
6370 CHECK(ops->create, EINVAL);
6371 CHECK(ops->lkp, EINVAL);
6372 CHECK(ops->free, EINVAL);
6373
6374
6375 elem = calloc(1, sizeof(struct table_type));
6376 CHECK(elem, ENOMEM);
6377
6378
6379 strcpy(elem->name, name);
6380 elem->match_type = match_type;
6381 memcpy(&elem->ops, ops, sizeof(*ops));
6382
6383
6384 TAILQ_INSERT_TAIL(&p->table_types, elem, node);
6385
6386 return 0;
6387}
6388
6389static enum rte_swx_table_match_type
6390table_match_type_resolve(struct rte_swx_match_field_params *fields,
6391 uint32_t n_fields)
6392{
6393 uint32_t i;
6394
6395 for (i = 0; i < n_fields; i++)
6396 if (fields[i].match_type != RTE_SWX_TABLE_MATCH_EXACT)
6397 break;
6398
6399 if (i == n_fields)
6400 return RTE_SWX_TABLE_MATCH_EXACT;
6401
6402 if ((i == n_fields - 1) &&
6403 (fields[i].match_type == RTE_SWX_TABLE_MATCH_LPM))
6404 return RTE_SWX_TABLE_MATCH_LPM;
6405
6406 return RTE_SWX_TABLE_MATCH_WILDCARD;
6407}
6408
6409int
6410rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
6411 const char *name,
6412 struct rte_swx_pipeline_table_params *params,
6413 const char *recommended_table_type_name,
6414 const char *args,
6415 uint32_t size)
6416{
6417 struct table_type *type;
6418 struct table *t;
6419 struct action *default_action;
6420 struct header *header = NULL;
6421 int is_header = 0;
6422 uint32_t offset_prev = 0, action_data_size_max = 0, i;
6423
6424 CHECK(p, EINVAL);
6425
6426 CHECK_NAME(name, EINVAL);
6427 CHECK(!table_find(p, name), EEXIST);
6428
6429 CHECK(params, EINVAL);
6430
6431
6432 CHECK(!params->n_fields || params->fields, EINVAL);
6433 for (i = 0; i < params->n_fields; i++) {
6434 struct rte_swx_match_field_params *field = ¶ms->fields[i];
6435 struct header *h;
6436 struct field *hf, *mf;
6437 uint32_t offset;
6438
6439 CHECK_NAME(field->name, EINVAL);
6440
6441 hf = header_field_parse(p, field->name, &h);
6442 mf = metadata_field_parse(p, field->name);
6443 CHECK(hf || mf, EINVAL);
6444
6445 offset = hf ? hf->offset : mf->offset;
6446
6447 if (i == 0) {
6448 is_header = hf ? 1 : 0;
6449 header = hf ? h : NULL;
6450 offset_prev = offset;
6451
6452 continue;
6453 }
6454
6455 CHECK((is_header && hf && (h->id == header->id)) ||
6456 (!is_header && mf), EINVAL);
6457
6458 CHECK(offset > offset_prev, EINVAL);
6459 offset_prev = offset;
6460 }
6461
6462
6463 CHECK(params->n_actions, EINVAL);
6464 CHECK(params->action_names, EINVAL);
6465 for (i = 0; i < params->n_actions; i++) {
6466 const char *action_name = params->action_names[i];
6467 struct action *a;
6468 uint32_t action_data_size;
6469
6470 CHECK_NAME(action_name, EINVAL);
6471
6472 a = action_find(p, action_name);
6473 CHECK(a, EINVAL);
6474
6475 action_data_size = a->st ? a->st->n_bits / 8 : 0;
6476 if (action_data_size > action_data_size_max)
6477 action_data_size_max = action_data_size;
6478 }
6479
6480 CHECK_NAME(params->default_action_name, EINVAL);
6481 for (i = 0; i < p->n_actions; i++)
6482 if (!strcmp(params->action_names[i],
6483 params->default_action_name))
6484 break;
6485 CHECK(i < params->n_actions, EINVAL);
6486 default_action = action_find(p, params->default_action_name);
6487 CHECK((default_action->st && params->default_action_data) ||
6488 !params->default_action_data, EINVAL);
6489
6490
6491 if (recommended_table_type_name)
6492 CHECK_NAME(recommended_table_type_name, EINVAL);
6493
6494 if (params->n_fields) {
6495 enum rte_swx_table_match_type match_type;
6496
6497 match_type = table_match_type_resolve(params->fields,
6498 params->n_fields);
6499 type = table_type_resolve(p,
6500 recommended_table_type_name,
6501 match_type);
6502 CHECK(type, EINVAL);
6503 } else {
6504 type = NULL;
6505 }
6506
6507
6508 t = calloc(1, sizeof(struct table));
6509 CHECK(t, ENOMEM);
6510
6511 t->fields = calloc(params->n_fields, sizeof(struct match_field));
6512 if (!t->fields) {
6513 free(t);
6514 CHECK(0, ENOMEM);
6515 }
6516
6517 t->actions = calloc(params->n_actions, sizeof(struct action *));
6518 if (!t->actions) {
6519 free(t->fields);
6520 free(t);
6521 CHECK(0, ENOMEM);
6522 }
6523
6524 if (action_data_size_max) {
6525 t->default_action_data = calloc(1, action_data_size_max);
6526 if (!t->default_action_data) {
6527 free(t->actions);
6528 free(t->fields);
6529 free(t);
6530 CHECK(0, ENOMEM);
6531 }
6532 }
6533
6534
6535 strcpy(t->name, name);
6536 if (args && args[0])
6537 strcpy(t->args, args);
6538 t->type = type;
6539
6540 for (i = 0; i < params->n_fields; i++) {
6541 struct rte_swx_match_field_params *field = ¶ms->fields[i];
6542 struct match_field *f = &t->fields[i];
6543
6544 f->match_type = field->match_type;
6545 f->field = is_header ?
6546 header_field_parse(p, field->name, NULL) :
6547 metadata_field_parse(p, field->name);
6548 }
6549 t->n_fields = params->n_fields;
6550 t->is_header = is_header;
6551 t->header = header;
6552
6553 for (i = 0; i < params->n_actions; i++)
6554 t->actions[i] = action_find(p, params->action_names[i]);
6555 t->default_action = default_action;
6556 if (default_action->st)
6557 memcpy(t->default_action_data,
6558 params->default_action_data,
6559 default_action->st->n_bits / 8);
6560 t->n_actions = params->n_actions;
6561 t->default_action_is_const = params->default_action_is_const;
6562 t->action_data_size_max = action_data_size_max;
6563
6564 t->size = size;
6565 t->id = p->n_tables;
6566
6567
6568 TAILQ_INSERT_TAIL(&p->tables, t, node);
6569 p->n_tables++;
6570
6571 return 0;
6572}
6573
6574static struct rte_swx_table_params *
6575table_params_get(struct table *table)
6576{
6577 struct rte_swx_table_params *params;
6578 struct field *first, *last;
6579 uint8_t *key_mask;
6580 uint32_t key_size, key_offset, action_data_size, i;
6581
6582
6583 params = calloc(1, sizeof(struct rte_swx_table_params));
6584 if (!params)
6585 return NULL;
6586
6587
6588 first = table->fields[0].field;
6589 last = table->fields[table->n_fields - 1].field;
6590 key_offset = first->offset / 8;
6591 key_size = (last->offset + last->n_bits - first->offset) / 8;
6592
6593
6594 key_mask = calloc(1, key_size);
6595 if (!key_mask) {
6596 free(params);
6597 return NULL;
6598 }
6599
6600
6601 for (i = 0; i < table->n_fields; i++) {
6602 struct field *f = table->fields[i].field;
6603 uint32_t start = (f->offset - first->offset) / 8;
6604 size_t size = f->n_bits / 8;
6605
6606 memset(&key_mask[start], 0xFF, size);
6607 }
6608
6609
6610 action_data_size = 0;
6611 for (i = 0; i < table->n_actions; i++) {
6612 struct action *action = table->actions[i];
6613 uint32_t ads = action->st ? action->st->n_bits / 8 : 0;
6614
6615 if (ads > action_data_size)
6616 action_data_size = ads;
6617 }
6618
6619
6620 params->match_type = table->type->match_type;
6621 params->key_size = key_size;
6622 params->key_offset = key_offset;
6623 params->key_mask0 = key_mask;
6624 params->action_data_size = action_data_size;
6625 params->n_keys_max = table->size;
6626
6627 return params;
6628}
6629
6630static void
6631table_params_free(struct rte_swx_table_params *params)
6632{
6633 if (!params)
6634 return;
6635
6636 free(params->key_mask0);
6637 free(params);
6638}
6639
6640static int
6641table_state_build(struct rte_swx_pipeline *p)
6642{
6643 struct table *table;
6644
6645 p->table_state = calloc(p->n_tables,
6646 sizeof(struct rte_swx_table_state));
6647 CHECK(p->table_state, ENOMEM);
6648
6649 TAILQ_FOREACH(table, &p->tables, node) {
6650 struct rte_swx_table_state *ts = &p->table_state[table->id];
6651
6652 if (table->type) {
6653 struct rte_swx_table_params *params;
6654
6655
6656 params = table_params_get(table);
6657 CHECK(params, ENOMEM);
6658
6659 ts->obj = table->type->ops.create(params,
6660 NULL,
6661 table->args,
6662 p->numa_node);
6663
6664 table_params_free(params);
6665 CHECK(ts->obj, ENODEV);
6666 }
6667
6668
6669 if (table->action_data_size_max) {
6670 ts->default_action_data =
6671 malloc(table->action_data_size_max);
6672 CHECK(ts->default_action_data, ENOMEM);
6673
6674 memcpy(ts->default_action_data,
6675 table->default_action_data,
6676 table->action_data_size_max);
6677 }
6678
6679
6680 ts->default_action_id = table->default_action->id;
6681 }
6682
6683 return 0;
6684}
6685
6686static void
6687table_state_build_free(struct rte_swx_pipeline *p)
6688{
6689 uint32_t i;
6690
6691 if (!p->table_state)
6692 return;
6693
6694 for (i = 0; i < p->n_tables; i++) {
6695 struct rte_swx_table_state *ts = &p->table_state[i];
6696 struct table *table = table_find_by_id(p, i);
6697
6698
6699 if (table->type && ts->obj)
6700 table->type->ops.free(ts->obj);
6701
6702
6703 free(ts->default_action_data);
6704 }
6705
6706 free(p->table_state);
6707 p->table_state = NULL;
6708}
6709
6710static void
6711table_state_free(struct rte_swx_pipeline *p)
6712{
6713 table_state_build_free(p);
6714}
6715
6716static int
6717table_stub_lkp(void *table __rte_unused,
6718 void *mailbox __rte_unused,
6719 uint8_t **key __rte_unused,
6720 uint64_t *action_id __rte_unused,
6721 uint8_t **action_data __rte_unused,
6722 int *hit)
6723{
6724 *hit = 0;
6725 return 1;
6726}
6727
6728static int
6729table_build(struct rte_swx_pipeline *p)
6730{
6731 uint32_t i;
6732
6733 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
6734 struct thread *t = &p->threads[i];
6735 struct table *table;
6736
6737 t->tables = calloc(p->n_tables, sizeof(struct table_runtime));
6738 CHECK(t->tables, ENOMEM);
6739
6740 TAILQ_FOREACH(table, &p->tables, node) {
6741 struct table_runtime *r = &t->tables[table->id];
6742
6743 if (table->type) {
6744 uint64_t size;
6745
6746 size = table->type->ops.mailbox_size_get();
6747
6748
6749 r->func = table->type->ops.lkp;
6750
6751
6752 if (size) {
6753 r->mailbox = calloc(1, size);
6754 CHECK(r->mailbox, ENOMEM);
6755 }
6756
6757
6758 r->key = table->is_header ?
6759 &t->structs[table->header->struct_id] :
6760 &t->structs[p->metadata_struct_id];
6761 } else {
6762 r->func = table_stub_lkp;
6763 }
6764 }
6765 }
6766
6767 return 0;
6768}
6769
6770static void
6771table_build_free(struct rte_swx_pipeline *p)
6772{
6773 uint32_t i;
6774
6775 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
6776 struct thread *t = &p->threads[i];
6777 uint32_t j;
6778
6779 if (!t->tables)
6780 continue;
6781
6782 for (j = 0; j < p->n_tables; j++) {
6783 struct table_runtime *r = &t->tables[j];
6784
6785 free(r->mailbox);
6786 }
6787
6788 free(t->tables);
6789 t->tables = NULL;
6790 }
6791}
6792
6793static void
6794table_free(struct rte_swx_pipeline *p)
6795{
6796 table_build_free(p);
6797
6798
6799 for ( ; ; ) {
6800 struct table *elem;
6801
6802 elem = TAILQ_FIRST(&p->tables);
6803 if (!elem)
6804 break;
6805
6806 TAILQ_REMOVE(&p->tables, elem, node);
6807 free(elem->fields);
6808 free(elem->actions);
6809 free(elem->default_action_data);
6810 free(elem);
6811 }
6812
6813
6814 for ( ; ; ) {
6815 struct table_type *elem;
6816
6817 elem = TAILQ_FIRST(&p->table_types);
6818 if (!elem)
6819 break;
6820
6821 TAILQ_REMOVE(&p->table_types, elem, node);
6822 free(elem);
6823 }
6824}
6825
6826
6827
6828
6829int
6830rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
6831{
6832 struct rte_swx_pipeline *pipeline;
6833
6834
6835 CHECK(p, EINVAL);
6836
6837
6838 pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
6839 CHECK(pipeline, ENOMEM);
6840
6841
6842 TAILQ_INIT(&pipeline->struct_types);
6843 TAILQ_INIT(&pipeline->port_in_types);
6844 TAILQ_INIT(&pipeline->ports_in);
6845 TAILQ_INIT(&pipeline->port_out_types);
6846 TAILQ_INIT(&pipeline->ports_out);
6847 TAILQ_INIT(&pipeline->extern_types);
6848 TAILQ_INIT(&pipeline->extern_objs);
6849 TAILQ_INIT(&pipeline->extern_funcs);
6850 TAILQ_INIT(&pipeline->headers);
6851 TAILQ_INIT(&pipeline->actions);
6852 TAILQ_INIT(&pipeline->table_types);
6853 TAILQ_INIT(&pipeline->tables);
6854
6855 pipeline->n_structs = 1;
6856 pipeline->numa_node = numa_node;
6857
6858 *p = pipeline;
6859 return 0;
6860}
6861
6862void
6863rte_swx_pipeline_free(struct rte_swx_pipeline *p)
6864{
6865 if (!p)
6866 return;
6867
6868 free(p->instructions);
6869
6870 table_state_free(p);
6871 table_free(p);
6872 action_free(p);
6873 metadata_free(p);
6874 header_free(p);
6875 extern_func_free(p);
6876 extern_obj_free(p);
6877 port_out_free(p);
6878 port_in_free(p);
6879 struct_free(p);
6880
6881 free(p);
6882}
6883
6884int
6885rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
6886 const char **instructions,
6887 uint32_t n_instructions)
6888{
6889 int err;
6890 uint32_t i;
6891
6892 err = instruction_config(p, NULL, instructions, n_instructions);
6893 if (err)
6894 return err;
6895
6896
6897 for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
6898 struct thread *t = &p->threads[i];
6899
6900 thread_ip_reset(p, t);
6901 }
6902
6903 return 0;
6904}
6905
6906int
6907rte_swx_pipeline_build(struct rte_swx_pipeline *p)
6908{
6909 int status;
6910
6911 CHECK(p, EINVAL);
6912 CHECK(p->build_done == 0, EEXIST);
6913
6914 status = port_in_build(p);
6915 if (status)
6916 goto error;
6917
6918 status = port_out_build(p);
6919 if (status)
6920 goto error;
6921
6922 status = struct_build(p);
6923 if (status)
6924 goto error;
6925
6926 status = extern_obj_build(p);
6927 if (status)
6928 goto error;
6929
6930 status = extern_func_build(p);
6931 if (status)
6932 goto error;
6933
6934 status = header_build(p);
6935 if (status)
6936 goto error;
6937
6938 status = metadata_build(p);
6939 if (status)
6940 goto error;
6941
6942 status = action_build(p);
6943 if (status)
6944 goto error;
6945
6946 status = table_build(p);
6947 if (status)
6948 goto error;
6949
6950 status = table_state_build(p);
6951 if (status)
6952 goto error;
6953
6954 p->build_done = 1;
6955 return 0;
6956
6957error:
6958 table_state_build_free(p);
6959 table_build_free(p);
6960 action_build_free(p);
6961 metadata_build_free(p);
6962 header_build_free(p);
6963 extern_func_build_free(p);
6964 extern_obj_build_free(p);
6965 port_out_build_free(p);
6966 port_in_build_free(p);
6967 struct_build_free(p);
6968
6969 return status;
6970}
6971
6972void
6973rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions)
6974{
6975 uint32_t i;
6976
6977 for (i = 0; i < n_instructions; i++)
6978 instr_exec(p);
6979}
6980
6981void
6982rte_swx_pipeline_flush(struct rte_swx_pipeline *p)
6983{
6984 uint32_t i;
6985
6986 for (i = 0; i < p->n_ports_out; i++) {
6987 struct port_out_runtime *port = &p->out[i];
6988
6989 if (port->flush)
6990 port->flush(port->obj);
6991 }
6992}
6993
6994
6995
6996
6997int
6998rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
6999 struct rte_swx_ctl_pipeline_info *pipeline)
7000{
7001 struct action *action;
7002 struct table *table;
7003 uint32_t n_actions = 0, n_tables = 0;
7004
7005 if (!p || !pipeline)
7006 return -EINVAL;
7007
7008 TAILQ_FOREACH(action, &p->actions, node)
7009 n_actions++;
7010
7011 TAILQ_FOREACH(table, &p->tables, node)
7012 n_tables++;
7013
7014 pipeline->n_ports_in = p->n_ports_in;
7015 pipeline->n_ports_out = p->n_ports_out;
7016 pipeline->n_actions = n_actions;
7017 pipeline->n_tables = n_tables;
7018
7019 return 0;
7020}
7021
7022int
7023rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node)
7024{
7025 if (!p || !numa_node)
7026 return -EINVAL;
7027
7028 *numa_node = p->numa_node;
7029 return 0;
7030}
7031
7032int
7033rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p,
7034 uint32_t action_id,
7035 struct rte_swx_ctl_action_info *action)
7036{
7037 struct action *a = NULL;
7038
7039 if (!p || (action_id >= p->n_actions) || !action)
7040 return -EINVAL;
7041
7042 a = action_find_by_id(p, action_id);
7043 if (!a)
7044 return -EINVAL;
7045
7046 strcpy(action->name, a->name);
7047 action->n_args = a->st ? a->st->n_fields : 0;
7048 return 0;
7049}
7050
7051int
7052rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p,
7053 uint32_t action_id,
7054 uint32_t action_arg_id,
7055 struct rte_swx_ctl_action_arg_info *action_arg)
7056{
7057 struct action *a = NULL;
7058 struct field *arg = NULL;
7059
7060 if (!p || (action_id >= p->n_actions) || !action_arg)
7061 return -EINVAL;
7062
7063 a = action_find_by_id(p, action_id);
7064 if (!a || !a->st || (action_arg_id >= a->st->n_fields))
7065 return -EINVAL;
7066
7067 arg = &a->st->fields[action_arg_id];
7068 strcpy(action_arg->name, arg->name);
7069 action_arg->n_bits = arg->n_bits;
7070
7071 return 0;
7072}
7073
7074int
7075rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p,
7076 uint32_t table_id,
7077 struct rte_swx_ctl_table_info *table)
7078{
7079 struct table *t = NULL;
7080
7081 if (!p || !table)
7082 return -EINVAL;
7083
7084 t = table_find_by_id(p, table_id);
7085 if (!t)
7086 return -EINVAL;
7087
7088 strcpy(table->name, t->name);
7089 strcpy(table->args, t->args);
7090 table->n_match_fields = t->n_fields;
7091 table->n_actions = t->n_actions;
7092 table->default_action_is_const = t->default_action_is_const;
7093 table->size = t->size;
7094 return 0;
7095}
7096
7097int
7098rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p,
7099 uint32_t table_id,
7100 uint32_t match_field_id,
7101 struct rte_swx_ctl_table_match_field_info *match_field)
7102{
7103 struct table *t;
7104 struct match_field *f;
7105
7106 if (!p || (table_id >= p->n_tables) || !match_field)
7107 return -EINVAL;
7108
7109 t = table_find_by_id(p, table_id);
7110 if (!t || (match_field_id >= t->n_fields))
7111 return -EINVAL;
7112
7113 f = &t->fields[match_field_id];
7114 match_field->match_type = f->match_type;
7115 match_field->is_header = t->is_header;
7116 match_field->n_bits = f->field->n_bits;
7117 match_field->offset = f->field->offset;
7118
7119 return 0;
7120}
7121
7122int
7123rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p,
7124 uint32_t table_id,
7125 uint32_t table_action_id,
7126 struct rte_swx_ctl_table_action_info *table_action)
7127{
7128 struct table *t;
7129
7130 if (!p || (table_id >= p->n_tables) || !table_action)
7131 return -EINVAL;
7132
7133 t = table_find_by_id(p, table_id);
7134 if (!t || (table_action_id >= t->n_actions))
7135 return -EINVAL;
7136
7137 table_action->action_id = t->actions[table_action_id]->id;
7138
7139 return 0;
7140}
7141
7142int
7143rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p,
7144 uint32_t table_id,
7145 struct rte_swx_table_ops *table_ops,
7146 int *is_stub)
7147{
7148 struct table *t;
7149
7150 if (!p || (table_id >= p->n_tables))
7151 return -EINVAL;
7152
7153 t = table_find_by_id(p, table_id);
7154 if (!t)
7155 return -EINVAL;
7156
7157 if (t->type) {
7158 if (table_ops)
7159 memcpy(table_ops, &t->type->ops, sizeof(*table_ops));
7160 *is_stub = 0;
7161 } else {
7162 *is_stub = 1;
7163 }
7164
7165 return 0;
7166}
7167
7168int
7169rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
7170 struct rte_swx_table_state **table_state)
7171{
7172 if (!p || !table_state || !p->build_done)
7173 return -EINVAL;
7174
7175 *table_state = p->table_state;
7176 return 0;
7177}
7178
7179int
7180rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
7181 struct rte_swx_table_state *table_state)
7182{
7183 if (!p || !table_state || !p->build_done)
7184 return -EINVAL;
7185
7186 p->table_state = table_state;
7187 return 0;
7188}
7189
7190int
7191rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p,
7192 uint32_t port_id,
7193 struct rte_swx_port_in_stats *stats)
7194{
7195 struct port_in *port;
7196
7197 if (!p || !stats)
7198 return -EINVAL;
7199
7200 port = port_in_find(p, port_id);
7201 if (!port)
7202 return -EINVAL;
7203
7204 port->type->ops.stats_read(port->obj, stats);
7205 return 0;
7206}
7207
7208int
7209rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p,
7210 uint32_t port_id,
7211 struct rte_swx_port_out_stats *stats)
7212{
7213 struct port_out *port;
7214
7215 if (!p || !stats)
7216 return -EINVAL;
7217
7218 port = port_out_find(p, port_id);
7219 if (!port)
7220 return -EINVAL;
7221
7222 port->type->ops.stats_read(port->obj, stats);
7223 return 0;
7224}
7225