1
2
3
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7#include <sys/queue.h>
8#include <unistd.h>
9
10#include <rte_common.h>
11#include <rte_byteorder.h>
12
13#include <rte_swx_table_selector.h>
14
15#include "rte_swx_ctl.h"
16
17#define CHECK(condition, err_code) \
18do { \
19 if (!(condition)) \
20 return -(err_code); \
21} while (0)
22
23#define ntoh64(x) rte_be_to_cpu_64(x)
24#define hton64(x) rte_cpu_to_be_64(x)
25
26#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
27#define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
28#define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
29#else
30#define field_ntoh(val, n_bits) (val)
31#define field_hton(val, n_bits) (val)
32#endif
33
34struct action {
35 struct rte_swx_ctl_action_info info;
36 struct rte_swx_ctl_action_arg_info *args;
37 uint32_t data_size;
38};
39
40struct table {
41 struct rte_swx_ctl_table_info info;
42 struct rte_swx_ctl_table_match_field_info *mf;
43
44
45 struct rte_swx_ctl_table_match_field_info *mf_first;
46
47
48 struct rte_swx_ctl_table_match_field_info *mf_last;
49
50 struct rte_swx_ctl_table_action_info *actions;
51 struct rte_swx_table_ops ops;
52 struct rte_swx_table_params params;
53
54
55
56
57
58 struct rte_swx_table_entry_list entries;
59
60
61
62
63
64 struct rte_swx_table_entry_list pending_add;
65
66
67
68
69
70
71
72
73 struct rte_swx_table_entry_list pending_modify0;
74 struct rte_swx_table_entry_list pending_modify1;
75
76
77
78
79
80 struct rte_swx_table_entry_list pending_delete;
81
82
83
84
85
86 struct rte_swx_table_entry *pending_default;
87
88 int is_stub;
89 uint32_t n_add;
90 uint32_t n_modify;
91 uint32_t n_delete;
92};
93
94struct selector {
95
96 struct rte_swx_ctl_selector_info info;
97
98
99 struct rte_swx_ctl_table_match_field_info group_id_field;
100
101
102 struct rte_swx_ctl_table_match_field_info *selector_fields;
103
104
105 struct rte_swx_ctl_table_match_field_info member_id_field;
106
107
108 struct rte_swx_table_selector_group **groups;
109
110
111
112 struct rte_swx_table_selector_group **pending_groups;
113
114
115 int *groups_added;
116
117
118
119
120 int *groups_pending_delete;
121
122
123 struct rte_swx_table_selector_params params;
124};
125
126struct learner {
127 struct rte_swx_ctl_learner_info info;
128 struct rte_swx_ctl_table_match_field_info *mf;
129 struct rte_swx_ctl_table_action_info *actions;
130 uint32_t action_data_size;
131
132
133
134
135
136 struct rte_swx_table_entry *pending_default;
137};
138
139struct rte_swx_ctl_pipeline {
140 struct rte_swx_ctl_pipeline_info info;
141 struct rte_swx_pipeline *p;
142 struct action *actions;
143 struct table *tables;
144 struct selector *selectors;
145 struct learner *learners;
146 struct rte_swx_table_state *ts;
147 struct rte_swx_table_state *ts_next;
148 int numa_node;
149};
150
151static struct action *
152action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
153{
154 uint32_t i;
155
156 for (i = 0; i < ctl->info.n_actions; i++) {
157 struct action *a = &ctl->actions[i];
158
159 if (!strcmp(action_name, a->info.name))
160 return a;
161 }
162
163 return NULL;
164}
165
166static void
167action_free(struct rte_swx_ctl_pipeline *ctl)
168{
169 uint32_t i;
170
171 if (!ctl->actions)
172 return;
173
174 for (i = 0; i < ctl->info.n_actions; i++) {
175 struct action *action = &ctl->actions[i];
176
177 free(action->args);
178 }
179
180 free(ctl->actions);
181 ctl->actions = NULL;
182}
183
184static struct table *
185table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
186{
187 uint32_t i;
188
189 for (i = 0; i < ctl->info.n_tables; i++) {
190 struct table *table = &ctl->tables[i];
191
192 if (!strcmp(table_name, table->info.name))
193 return table;
194 }
195
196 return NULL;
197}
198
199static int
200table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
201{
202 struct table *table = &ctl->tables[table_id];
203 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
204 uint8_t *key_mask = NULL;
205 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
206 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
207
208 if (table->info.n_match_fields) {
209 uint32_t n_match_fields_em = 0, i;
210
211
212 first = &table->mf[0];
213 last = &table->mf[0];
214
215 for (i = 1; i < table->info.n_match_fields; i++) {
216 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
217
218 if (f->offset < first->offset)
219 first = f;
220
221 if (f->offset > last->offset)
222 last = f;
223 }
224
225
226 for (i = 0; i < table->info.n_match_fields; i++) {
227 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
228
229 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
230 n_match_fields_em++;
231 }
232
233 if (n_match_fields_em == table->info.n_match_fields)
234 match_type = RTE_SWX_TABLE_MATCH_EXACT;
235
236
237 key_offset = first->offset / 8;
238
239
240 key_size = (last->offset + last->n_bits - first->offset) / 8;
241
242
243 key_mask = calloc(1, key_size);
244 CHECK(key_mask, ENOMEM);
245
246 for (i = 0; i < table->info.n_match_fields; i++) {
247 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
248 uint32_t start;
249 size_t size;
250
251 start = (f->offset - first->offset) / 8;
252 size = f->n_bits / 8;
253
254 memset(&key_mask[start], 0xFF, size);
255 }
256 }
257
258
259 for (i = 0; i < table->info.n_actions; i++) {
260 uint32_t action_id = table->actions[i].action_id;
261 struct action *a = &ctl->actions[action_id];
262
263 if (a->data_size > action_data_size)
264 action_data_size = a->data_size;
265 }
266
267
268 table->params.match_type = match_type;
269 table->params.key_size = key_size;
270 table->params.key_offset = key_offset;
271 table->params.key_mask0 = key_mask;
272 table->params.action_data_size = action_data_size;
273 table->params.n_keys_max = table->info.size;
274
275 table->mf_first = first;
276 table->mf_last = last;
277
278 return 0;
279}
280
281static void
282table_entry_free(struct rte_swx_table_entry *entry)
283{
284 if (!entry)
285 return;
286
287 free(entry->key);
288 free(entry->key_mask);
289 free(entry->action_data);
290 free(entry);
291}
292
293static struct rte_swx_table_entry *
294table_entry_alloc(struct table *table)
295{
296 struct rte_swx_table_entry *entry;
297
298 entry = calloc(1, sizeof(struct rte_swx_table_entry));
299 if (!entry)
300 goto error;
301
302
303 if (!table->is_stub) {
304 entry->key = calloc(1, table->params.key_size);
305 if (!entry->key)
306 goto error;
307
308 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
309 entry->key_mask = calloc(1, table->params.key_size);
310 if (!entry->key_mask)
311 goto error;
312 }
313 }
314
315
316 if (table->params.action_data_size) {
317 entry->action_data = calloc(1, table->params.action_data_size);
318 if (!entry->action_data)
319 goto error;
320 }
321
322 return entry;
323
324error:
325 table_entry_free(entry);
326 return NULL;
327}
328
329static int
330table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
331{
332 uint8_t *key_mask0 = table->params.key_mask0;
333 uint32_t key_size = table->params.key_size, i;
334
335 if (!entry->key_mask)
336 return 0;
337
338 for (i = 0; i < key_size; i++) {
339 uint8_t km0 = key_mask0[i];
340 uint8_t km = entry->key_mask[i];
341
342 if ((km & km0) != km0)
343 return -EINVAL;
344 }
345
346 return 0;
347}
348
349static int
350table_entry_check(struct rte_swx_ctl_pipeline *ctl,
351 uint32_t table_id,
352 struct rte_swx_table_entry *entry,
353 int key_check,
354 int data_check)
355{
356 struct table *table = &ctl->tables[table_id];
357 int status;
358
359 CHECK(entry, EINVAL);
360
361 if (key_check && !table->is_stub) {
362
363 CHECK(entry->key, EINVAL);
364
365
366 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
367 status = table_entry_key_check_em(table, entry);
368 if (status)
369 return status;
370 }
371 }
372
373 if (data_check) {
374 struct action *a;
375 struct rte_swx_ctl_table_action_info *tai;
376 uint32_t i;
377
378
379 for (i = 0; i < table->info.n_actions; i++) {
380 tai = &table->actions[i];
381
382 if (entry->action_id == tai->action_id)
383 break;
384 }
385
386 CHECK(i < table->info.n_actions, EINVAL);
387
388
389 a = &ctl->actions[entry->action_id];
390 CHECK(!(a->data_size && !entry->action_data), EINVAL);
391
392
393
394
395 if (key_check && !tai->action_is_for_table_entries)
396 return -EINVAL;
397
398
399
400
401 if (!key_check && !tai->action_is_for_default_entry)
402 return -EINVAL;
403 }
404
405 return 0;
406}
407
408static struct rte_swx_table_entry *
409table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
410 uint32_t table_id,
411 struct rte_swx_table_entry *entry,
412 int key_duplicate,
413 int data_duplicate)
414{
415 struct table *table = &ctl->tables[table_id];
416 struct rte_swx_table_entry *new_entry = NULL;
417
418 if (!entry)
419 goto error;
420
421 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
422 if (!new_entry)
423 goto error;
424
425 if (key_duplicate && !table->is_stub) {
426
427 if (!entry->key)
428 goto error;
429
430 new_entry->key = malloc(table->params.key_size);
431 if (!new_entry->key)
432 goto error;
433
434 memcpy(new_entry->key, entry->key, table->params.key_size);
435
436
437 new_entry->key_signature = entry->key_signature;
438
439
440 if (entry->key_mask) {
441 new_entry->key_mask = malloc(table->params.key_size);
442 if (!new_entry->key_mask)
443 goto error;
444
445 memcpy(new_entry->key_mask,
446 entry->key_mask,
447 table->params.key_size);
448 }
449
450
451 new_entry->key_priority = entry->key_priority;
452 }
453
454 if (data_duplicate) {
455 struct action *a;
456 uint32_t i;
457
458
459 for (i = 0; i < table->info.n_actions; i++)
460 if (entry->action_id == table->actions[i].action_id)
461 break;
462
463 if (i >= table->info.n_actions)
464 goto error;
465
466 new_entry->action_id = entry->action_id;
467
468
469 a = &ctl->actions[entry->action_id];
470 if (a->data_size && !entry->action_data)
471 goto error;
472
473
474
475
476
477
478
479
480 new_entry->action_data = calloc(1, table->params.action_data_size);
481 if (!new_entry->action_data)
482 goto error;
483
484 if (a->data_size)
485 memcpy(new_entry->action_data,
486 entry->action_data,
487 a->data_size);
488 }
489
490 return new_entry;
491
492error:
493 table_entry_free(new_entry);
494 return NULL;
495}
496
497static int
498table_entry_keycmp(struct table *table,
499 struct rte_swx_table_entry *e0,
500 struct rte_swx_table_entry *e1)
501{
502 uint32_t key_size = table->params.key_size;
503 uint32_t i;
504
505 for (i = 0; i < key_size; i++) {
506 uint8_t *key_mask0 = table->params.key_mask0;
507 uint8_t km0, km[2], k[2];
508
509 km0 = key_mask0 ? key_mask0[i] : 0xFF;
510
511 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
512 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
513
514 k[0] = e0->key[i];
515 k[1] = e1->key[i];
516
517
518 if ((km[0] & km0) != (km[1] & km0))
519 return 1;
520
521
522 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
523 return 1;
524 }
525
526 return 0;
527}
528
529static struct rte_swx_table_entry *
530table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
531{
532 struct rte_swx_table_entry *e;
533
534 TAILQ_FOREACH(e, &table->entries, node)
535 if (!table_entry_keycmp(table, entry, e))
536 return e;
537
538 return NULL;
539}
540
541static void
542table_entries_free(struct table *table)
543{
544 for ( ; ; ) {
545 struct rte_swx_table_entry *entry;
546
547 entry = TAILQ_FIRST(&table->entries);
548 if (!entry)
549 break;
550
551 TAILQ_REMOVE(&table->entries, entry, node);
552 table_entry_free(entry);
553 }
554}
555
556static struct rte_swx_table_entry *
557table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
558{
559 struct rte_swx_table_entry *e;
560
561 TAILQ_FOREACH(e, &table->pending_add, node)
562 if (!table_entry_keycmp(table, entry, e))
563 return e;
564
565 return NULL;
566}
567
568static void
569table_pending_add_admit(struct table *table)
570{
571 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
572}
573
574static void
575table_pending_add_free(struct table *table)
576{
577 for ( ; ; ) {
578 struct rte_swx_table_entry *entry;
579
580 entry = TAILQ_FIRST(&table->pending_add);
581 if (!entry)
582 break;
583
584 TAILQ_REMOVE(&table->pending_add, entry, node);
585 table_entry_free(entry);
586 }
587}
588
589static struct rte_swx_table_entry *
590table_pending_modify0_find(struct table *table,
591 struct rte_swx_table_entry *entry)
592{
593 struct rte_swx_table_entry *e;
594
595 TAILQ_FOREACH(e, &table->pending_modify0, node)
596 if (!table_entry_keycmp(table, entry, e))
597 return e;
598
599 return NULL;
600}
601
602static void
603table_pending_modify0_admit(struct table *table)
604{
605 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
606}
607
608static void
609table_pending_modify0_free(struct table *table)
610{
611 for ( ; ; ) {
612 struct rte_swx_table_entry *entry;
613
614 entry = TAILQ_FIRST(&table->pending_modify0);
615 if (!entry)
616 break;
617
618 TAILQ_REMOVE(&table->pending_modify0, entry, node);
619 table_entry_free(entry);
620 }
621}
622
623static struct rte_swx_table_entry *
624table_pending_modify1_find(struct table *table,
625 struct rte_swx_table_entry *entry)
626{
627 struct rte_swx_table_entry *e;
628
629 TAILQ_FOREACH(e, &table->pending_modify1, node)
630 if (!table_entry_keycmp(table, entry, e))
631 return e;
632
633 return NULL;
634}
635
636static void
637table_pending_modify1_admit(struct table *table)
638{
639 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
640}
641
642static void
643table_pending_modify1_free(struct table *table)
644{
645 for ( ; ; ) {
646 struct rte_swx_table_entry *entry;
647
648 entry = TAILQ_FIRST(&table->pending_modify1);
649 if (!entry)
650 break;
651
652 TAILQ_REMOVE(&table->pending_modify1, entry, node);
653 table_entry_free(entry);
654 }
655}
656
657static struct rte_swx_table_entry *
658table_pending_delete_find(struct table *table,
659 struct rte_swx_table_entry *entry)
660{
661 struct rte_swx_table_entry *e;
662
663 TAILQ_FOREACH(e, &table->pending_delete, node)
664 if (!table_entry_keycmp(table, entry, e))
665 return e;
666
667 return NULL;
668}
669
670static void
671table_pending_delete_admit(struct table *table)
672{
673 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
674}
675
676static void
677table_pending_delete_free(struct table *table)
678{
679 for ( ; ; ) {
680 struct rte_swx_table_entry *entry;
681
682 entry = TAILQ_FIRST(&table->pending_delete);
683 if (!entry)
684 break;
685
686 TAILQ_REMOVE(&table->pending_delete, entry, node);
687 table_entry_free(entry);
688 }
689}
690
691static void
692table_pending_default_free(struct table *table)
693{
694 if (!table->pending_default)
695 return;
696
697 free(table->pending_default->action_data);
698 free(table->pending_default);
699 table->pending_default = NULL;
700}
701
702static int
703table_is_update_pending(struct table *table, int consider_pending_default)
704{
705 struct rte_swx_table_entry *e;
706 uint32_t n = 0;
707
708
709 TAILQ_FOREACH(e, &table->pending_add, node)
710 n++;
711
712
713 TAILQ_FOREACH(e, &table->pending_modify1, node)
714 n++;
715
716
717 TAILQ_FOREACH(e, &table->pending_delete, node)
718 n++;
719
720
721 if (consider_pending_default && table->pending_default)
722 n++;
723
724 return n;
725}
726
727static void
728table_free(struct rte_swx_ctl_pipeline *ctl)
729{
730 uint32_t i;
731
732 if (!ctl->tables)
733 return;
734
735 for (i = 0; i < ctl->info.n_tables; i++) {
736 struct table *table = &ctl->tables[i];
737
738 free(table->mf);
739 free(table->actions);
740 free(table->params.key_mask0);
741
742 table_entries_free(table);
743 table_pending_add_free(table);
744 table_pending_modify0_free(table);
745 table_pending_modify1_free(table);
746 table_pending_delete_free(table);
747 table_pending_default_free(table);
748 }
749
750 free(ctl->tables);
751 ctl->tables = NULL;
752}
753
754static void
755selector_group_members_free(struct selector *s, uint32_t group_id)
756{
757 struct rte_swx_table_selector_group *group = s->groups[group_id];
758
759 if (!group)
760 return;
761
762 for ( ; ; ) {
763 struct rte_swx_table_selector_member *m;
764
765 m = TAILQ_FIRST(&group->members);
766 if (!m)
767 break;
768
769 TAILQ_REMOVE(&group->members, m, node);
770 free(m);
771 }
772
773 free(group);
774 s->groups[group_id] = NULL;
775}
776
777static void
778selector_pending_group_members_free(struct selector *s, uint32_t group_id)
779{
780 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
781
782 if (!group)
783 return;
784
785 for ( ; ; ) {
786 struct rte_swx_table_selector_member *m;
787
788 m = TAILQ_FIRST(&group->members);
789 if (!m)
790 break;
791
792 TAILQ_REMOVE(&group->members, m, node);
793 free(m);
794 }
795
796 free(group);
797 s->pending_groups[group_id] = NULL;
798}
799
800static int
801selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
802{
803 struct rte_swx_table_selector_group *g, *gp;
804 struct rte_swx_table_selector_member *m;
805
806 selector_pending_group_members_free(s, group_id);
807
808 g = s->groups[group_id];
809 gp = s->pending_groups[group_id];
810
811 if (!gp) {
812 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
813 if (!gp)
814 goto error;
815
816 TAILQ_INIT(&gp->members);
817
818 s->pending_groups[group_id] = gp;
819 }
820
821 if (!g)
822 return 0;
823
824 TAILQ_FOREACH(m, &g->members, node) {
825 struct rte_swx_table_selector_member *mp;
826
827 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
828 if (!mp)
829 goto error;
830
831 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
832
833 TAILQ_INSERT_TAIL(&gp->members, mp, node);
834 }
835
836 return 0;
837
838error:
839 selector_pending_group_members_free(s, group_id);
840 return -ENOMEM;
841}
842
843static void
844selector_free(struct rte_swx_ctl_pipeline *ctl)
845{
846 uint32_t i;
847
848 if (!ctl->selectors)
849 return;
850
851 for (i = 0; i < ctl->info.n_selectors; i++) {
852 struct selector *s = &ctl->selectors[i];
853 uint32_t i;
854
855
856 free(s->selector_fields);
857
858
859 if (s->groups)
860 for (i = 0; i < s->info.n_groups_max; i++)
861 selector_group_members_free(s, i);
862
863 free(s->groups);
864
865
866 if (s->pending_groups)
867 for (i = 0; i < s->info.n_groups_max; i++)
868 selector_pending_group_members_free(s, i);
869
870 free(s->pending_groups);
871
872
873 free(s->groups_added);
874
875
876 free(s->groups_pending_delete);
877
878
879 free(s->params.selector_mask);
880 }
881
882 free(ctl->selectors);
883 ctl->selectors = NULL;
884}
885
886static struct selector *
887selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
888{
889 uint32_t i;
890
891 for (i = 0; i < ctl->info.n_selectors; i++) {
892 struct selector *s = &ctl->selectors[i];
893
894 if (!strcmp(selector_name, s->info.name))
895 return s;
896 }
897
898 return NULL;
899}
900
901static int
902selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
903{
904 struct selector *s = &ctl->selectors[selector_id];
905 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
906 uint8_t *selector_mask = NULL;
907 uint32_t selector_size = 0, selector_offset = 0, i;
908
909
910 first = &s->selector_fields[0];
911 last = &s->selector_fields[0];
912
913 for (i = 1; i < s->info.n_selector_fields; i++) {
914 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
915
916 if (f->offset < first->offset)
917 first = f;
918
919 if (f->offset > last->offset)
920 last = f;
921 }
922
923
924 selector_offset = first->offset / 8;
925
926
927 selector_size = (last->offset + last->n_bits - first->offset) / 8;
928
929
930 selector_mask = calloc(1, selector_size);
931 if (!selector_mask)
932 return -ENOMEM;
933
934 for (i = 0; i < s->info.n_selector_fields; i++) {
935 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
936 uint32_t start;
937 size_t size;
938
939 start = (f->offset - first->offset) / 8;
940 size = f->n_bits / 8;
941
942 memset(&selector_mask[start], 0xFF, size);
943 }
944
945
946 s->params.group_id_offset = s->group_id_field.offset / 8;
947 s->params.selector_size = selector_size;
948 s->params.selector_offset = selector_offset;
949 s->params.selector_mask = selector_mask;
950 s->params.member_id_offset = s->member_id_field.offset / 8;
951 s->params.n_groups_max = s->info.n_groups_max;
952 s->params.n_members_per_group_max = s->info.n_members_per_group_max;
953
954 return 0;
955}
956
957static void
958learner_pending_default_free(struct learner *l)
959{
960 if (!l->pending_default)
961 return;
962
963 free(l->pending_default->action_data);
964 free(l->pending_default);
965 l->pending_default = NULL;
966}
967
968
969static void
970learner_free(struct rte_swx_ctl_pipeline *ctl)
971{
972 uint32_t i;
973
974 if (!ctl->learners)
975 return;
976
977 for (i = 0; i < ctl->info.n_learners; i++) {
978 struct learner *l = &ctl->learners[i];
979
980 free(l->mf);
981 free(l->actions);
982
983 learner_pending_default_free(l);
984 }
985
986 free(ctl->learners);
987 ctl->learners = NULL;
988}
989
990static struct learner *
991learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
992{
993 uint32_t i;
994
995 for (i = 0; i < ctl->info.n_learners; i++) {
996 struct learner *l = &ctl->learners[i];
997
998 if (!strcmp(learner_name, l->info.name))
999 return l;
1000 }
1001
1002 return NULL;
1003}
1004
1005static uint32_t
1006learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1007{
1008 uint32_t action_data_size = 0, i;
1009
1010 for (i = 0; i < l->info.n_actions; i++) {
1011 uint32_t action_id = l->actions[i].action_id;
1012 struct action *a = &ctl->actions[action_id];
1013
1014 if (a->data_size > action_data_size)
1015 action_data_size = a->data_size;
1016 }
1017
1018 return action_data_size;
1019}
1020
1021static void
1022table_state_free(struct rte_swx_ctl_pipeline *ctl)
1023{
1024 uint32_t table_base_index, selector_base_index, learner_base_index, i;
1025
1026 if (!ctl->ts_next)
1027 return;
1028
1029
1030 table_base_index = 0;
1031 for (i = 0; i < ctl->info.n_tables; i++) {
1032 struct table *table = &ctl->tables[i];
1033 struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
1034
1035
1036 free(ts->default_action_data);
1037
1038
1039 if (!table->is_stub && table->ops.free && ts->obj)
1040 table->ops.free(ts->obj);
1041 }
1042
1043
1044 selector_base_index = ctl->info.n_tables;
1045 for (i = 0; i < ctl->info.n_selectors; i++) {
1046 struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1047
1048
1049 rte_swx_table_selector_free(ts->obj);
1050 }
1051
1052
1053 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1054 for (i = 0; i < ctl->info.n_learners; i++) {
1055 struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1056
1057
1058 free(ts->default_action_data);
1059 }
1060
1061 free(ctl->ts_next);
1062 ctl->ts_next = NULL;
1063}
1064
1065static int
1066table_state_create(struct rte_swx_ctl_pipeline *ctl)
1067{
1068 uint32_t table_base_index, selector_base_index, learner_base_index, i;
1069 int status = 0;
1070
1071 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1072 sizeof(struct rte_swx_table_state));
1073 if (!ctl->ts_next) {
1074 status = -ENOMEM;
1075 goto error;
1076 }
1077
1078
1079 table_base_index = 0;
1080 for (i = 0; i < ctl->info.n_tables; i++) {
1081 struct table *table = &ctl->tables[i];
1082 struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1083 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1084
1085
1086 if (!table->is_stub && table->ops.add) {
1087 ts_next->obj = table->ops.create(&table->params,
1088 &table->entries,
1089 table->info.args,
1090 ctl->numa_node);
1091 if (!ts_next->obj) {
1092 status = -ENODEV;
1093 goto error;
1094 }
1095 }
1096
1097 if (!table->is_stub && !table->ops.add)
1098 ts_next->obj = ts->obj;
1099
1100
1101 ts_next->default_action_data =
1102 malloc(table->params.action_data_size);
1103 if (!ts_next->default_action_data) {
1104 status = -ENOMEM;
1105 goto error;
1106 }
1107
1108 memcpy(ts_next->default_action_data,
1109 ts->default_action_data,
1110 table->params.action_data_size);
1111
1112 ts_next->default_action_id = ts->default_action_id;
1113 }
1114
1115
1116 selector_base_index = ctl->info.n_tables;
1117 for (i = 0; i < ctl->info.n_selectors; i++) {
1118 struct selector *s = &ctl->selectors[i];
1119 struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1120
1121
1122 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1123 if (!ts_next->obj) {
1124 status = -ENODEV;
1125 goto error;
1126 }
1127 }
1128
1129
1130 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1131 for (i = 0; i < ctl->info.n_learners; i++) {
1132 struct learner *l = &ctl->learners[i];
1133 struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1134 struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1135
1136
1137 ts_next->obj = ts->obj;
1138
1139
1140 ts_next->default_action_data = malloc(l->action_data_size);
1141 if (!ts_next->default_action_data) {
1142 status = -ENOMEM;
1143 goto error;
1144 }
1145
1146 memcpy(ts_next->default_action_data,
1147 ts->default_action_data,
1148 l->action_data_size);
1149
1150 ts_next->default_action_id = ts->default_action_id;
1151 }
1152
1153 return 0;
1154
1155error:
1156 table_state_free(ctl);
1157 return status;
1158}
1159
1160void
1161rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1162{
1163 if (!ctl)
1164 return;
1165
1166 action_free(ctl);
1167
1168 table_state_free(ctl);
1169
1170 learner_free(ctl);
1171
1172 selector_free(ctl);
1173
1174 table_free(ctl);
1175
1176 free(ctl);
1177}
1178
1179struct rte_swx_ctl_pipeline *
1180rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1181{
1182 struct rte_swx_ctl_pipeline *ctl = NULL;
1183 uint32_t i;
1184 int status;
1185
1186 if (!p)
1187 goto error;
1188
1189 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1190 if (!ctl)
1191 goto error;
1192
1193
1194 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1195 if (status)
1196 goto error;
1197
1198
1199 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1200 if (status)
1201 goto error;
1202
1203
1204 ctl->p = p;
1205
1206
1207 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1208 if (!ctl->actions)
1209 goto error;
1210
1211 for (i = 0; i < ctl->info.n_actions; i++) {
1212 struct action *a = &ctl->actions[i];
1213 uint32_t j;
1214
1215
1216 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1217 if (status)
1218 goto error;
1219
1220
1221 a->args = calloc(a->info.n_args,
1222 sizeof(struct rte_swx_ctl_action_arg_info));
1223 if (!a->args)
1224 goto error;
1225
1226 for (j = 0; j < a->info.n_args; j++) {
1227 status = rte_swx_ctl_action_arg_info_get(p,
1228 i,
1229 j,
1230 &a->args[j]);
1231 if (status)
1232 goto error;
1233 }
1234
1235
1236 for (j = 0; j < a->info.n_args; j++) {
1237 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1238
1239 a->data_size += info->n_bits;
1240 }
1241
1242 a->data_size = (a->data_size + 7) / 8;
1243 }
1244
1245
1246 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1247 if (!ctl->tables)
1248 goto error;
1249
1250 for (i = 0; i < ctl->info.n_tables; i++) {
1251 struct table *t = &ctl->tables[i];
1252
1253 TAILQ_INIT(&t->entries);
1254 TAILQ_INIT(&t->pending_add);
1255 TAILQ_INIT(&t->pending_modify0);
1256 TAILQ_INIT(&t->pending_modify1);
1257 TAILQ_INIT(&t->pending_delete);
1258 }
1259
1260 for (i = 0; i < ctl->info.n_tables; i++) {
1261 struct table *t = &ctl->tables[i];
1262 uint32_t j;
1263
1264
1265 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1266 if (status)
1267 goto error;
1268
1269
1270 t->mf = calloc(t->info.n_match_fields,
1271 sizeof(struct rte_swx_ctl_table_match_field_info));
1272 if (!t->mf)
1273 goto error;
1274
1275 for (j = 0; j < t->info.n_match_fields; j++) {
1276 status = rte_swx_ctl_table_match_field_info_get(p,
1277 i,
1278 j,
1279 &t->mf[j]);
1280 if (status)
1281 goto error;
1282 }
1283
1284
1285 t->actions = calloc(t->info.n_actions,
1286 sizeof(struct rte_swx_ctl_table_action_info));
1287 if (!t->actions)
1288 goto error;
1289
1290 for (j = 0; j < t->info.n_actions; j++) {
1291 status = rte_swx_ctl_table_action_info_get(p,
1292 i,
1293 j,
1294 &t->actions[j]);
1295 if (status ||
1296 t->actions[j].action_id >= ctl->info.n_actions)
1297 goto error;
1298 }
1299
1300
1301 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1302 if (status)
1303 goto error;
1304
1305 if ((t->is_stub && t->info.n_match_fields) ||
1306 (!t->is_stub && !t->info.n_match_fields))
1307 goto error;
1308
1309
1310 status = table_params_get(ctl, i);
1311 if (status)
1312 goto error;
1313 }
1314
1315
1316 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1317 if (!ctl->selectors)
1318 goto error;
1319
1320 for (i = 0; i < ctl->info.n_selectors; i++) {
1321 struct selector *s = &ctl->selectors[i];
1322 uint32_t j;
1323
1324
1325 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1326 if (status)
1327 goto error;
1328
1329
1330 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1331 i,
1332 &s->group_id_field);
1333 if (status)
1334 goto error;
1335
1336
1337 s->selector_fields = calloc(s->info.n_selector_fields,
1338 sizeof(struct rte_swx_ctl_table_match_field_info));
1339 if (!s->selector_fields)
1340 goto error;
1341
1342 for (j = 0; j < s->info.n_selector_fields; j++) {
1343 status = rte_swx_ctl_selector_field_info_get(p,
1344 i,
1345 j,
1346 &s->selector_fields[j]);
1347 if (status)
1348 goto error;
1349 }
1350
1351
1352 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1353 i,
1354 &s->member_id_field);
1355 if (status)
1356 goto error;
1357
1358
1359 s->groups = calloc(s->info.n_groups_max,
1360 sizeof(struct rte_swx_table_selector_group *));
1361 if (!s->groups)
1362 goto error;
1363
1364
1365 s->pending_groups = calloc(s->info.n_groups_max,
1366 sizeof(struct rte_swx_table_selector_group *));
1367 if (!s->pending_groups)
1368 goto error;
1369
1370
1371 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1372 if (!s->groups_added)
1373 goto error;
1374
1375
1376 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1377 if (!s->groups_pending_delete)
1378 goto error;
1379
1380
1381 status = selector_params_get(ctl, i);
1382 if (status)
1383 goto error;
1384 }
1385
1386
1387 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1388 if (!ctl->learners)
1389 goto error;
1390
1391 for (i = 0; i < ctl->info.n_learners; i++) {
1392 struct learner *l = &ctl->learners[i];
1393 uint32_t j;
1394
1395
1396 status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1397 if (status)
1398 goto error;
1399
1400
1401 l->mf = calloc(l->info.n_match_fields,
1402 sizeof(struct rte_swx_ctl_table_match_field_info));
1403 if (!l->mf)
1404 goto error;
1405
1406 for (j = 0; j < l->info.n_match_fields; j++) {
1407 status = rte_swx_ctl_learner_match_field_info_get(p,
1408 i,
1409 j,
1410 &l->mf[j]);
1411 if (status)
1412 goto error;
1413 }
1414
1415
1416 l->actions = calloc(l->info.n_actions,
1417 sizeof(struct rte_swx_ctl_table_action_info));
1418 if (!l->actions)
1419 goto error;
1420
1421 for (j = 0; j < l->info.n_actions; j++) {
1422 status = rte_swx_ctl_learner_action_info_get(p,
1423 i,
1424 j,
1425 &l->actions[j]);
1426 if (status || l->actions[j].action_id >= ctl->info.n_actions)
1427 goto error;
1428 }
1429
1430
1431 l->action_data_size = learner_action_data_size_get(ctl, l);
1432 }
1433
1434
1435 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1436 if (status)
1437 goto error;
1438
1439
1440 status = table_state_create(ctl);
1441 if (status)
1442 goto error;
1443
1444 return ctl;
1445
1446error:
1447 rte_swx_ctl_pipeline_free(ctl);
1448 return NULL;
1449}
1450
1451int
1452rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1453 const char *table_name,
1454 struct rte_swx_table_entry *entry)
1455{
1456 struct table *table;
1457 struct rte_swx_table_entry *new_entry, *existing_entry;
1458 uint32_t table_id;
1459
1460 CHECK(ctl, EINVAL);
1461 CHECK(table_name && table_name[0], EINVAL);
1462
1463 table = table_find(ctl, table_name);
1464 CHECK(table, EINVAL);
1465 table_id = table - ctl->tables;
1466
1467 CHECK(entry, EINVAL);
1468 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1469
1470 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1471 CHECK(new_entry, ENOMEM);
1472
1473
1474
1475
1476
1477
1478 existing_entry = table_entries_find(table, entry);
1479 if (existing_entry) {
1480 TAILQ_INSERT_TAIL(&table->pending_modify1,
1481 new_entry,
1482 node);
1483
1484 TAILQ_REMOVE(&table->entries,
1485 existing_entry,
1486 node);
1487
1488 TAILQ_INSERT_TAIL(&table->pending_modify0,
1489 existing_entry,
1490 node);
1491
1492 return 0;
1493 }
1494
1495
1496
1497
1498
1499 existing_entry = table_pending_add_find(table, entry);
1500 if (existing_entry) {
1501 TAILQ_INSERT_AFTER(&table->pending_add,
1502 existing_entry,
1503 new_entry,
1504 node);
1505
1506 TAILQ_REMOVE(&table->pending_add,
1507 existing_entry,
1508 node);
1509
1510 table_entry_free(existing_entry);
1511
1512 return 0;
1513 }
1514
1515
1516
1517
1518
1519 existing_entry = table_pending_modify1_find(table, entry);
1520 if (existing_entry) {
1521 TAILQ_INSERT_AFTER(&table->pending_modify1,
1522 existing_entry,
1523 new_entry,
1524 node);
1525
1526 TAILQ_REMOVE(&table->pending_modify1,
1527 existing_entry,
1528 node);
1529
1530 table_entry_free(existing_entry);
1531
1532 return 0;
1533 }
1534
1535
1536
1537
1538
1539
1540 existing_entry = table_pending_delete_find(table, entry);
1541 if (existing_entry) {
1542 TAILQ_INSERT_TAIL(&table->pending_modify1,
1543 new_entry,
1544 node);
1545
1546 TAILQ_REMOVE(&table->pending_delete,
1547 existing_entry,
1548 node);
1549
1550 TAILQ_INSERT_TAIL(&table->pending_modify0,
1551 existing_entry,
1552 node);
1553
1554 return 0;
1555 }
1556
1557
1558
1559
1560 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1561
1562 return 0;
1563}
1564
1565int
1566rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1567 const char *table_name,
1568 struct rte_swx_table_entry *entry)
1569{
1570 struct table *table;
1571 struct rte_swx_table_entry *existing_entry;
1572 uint32_t table_id;
1573
1574 CHECK(ctl, EINVAL);
1575
1576 CHECK(table_name && table_name[0], EINVAL);
1577 table = table_find(ctl, table_name);
1578 CHECK(table, EINVAL);
1579 table_id = table - ctl->tables;
1580
1581 CHECK(entry, EINVAL);
1582 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1583
1584
1585
1586
1587
1588 existing_entry = table_entries_find(table, entry);
1589 if (existing_entry) {
1590 TAILQ_REMOVE(&table->entries,
1591 existing_entry,
1592 node);
1593
1594 TAILQ_INSERT_TAIL(&table->pending_delete,
1595 existing_entry,
1596 node);
1597
1598 return 0;
1599 }
1600
1601
1602
1603
1604 existing_entry = table_pending_add_find(table, entry);
1605 if (existing_entry) {
1606 TAILQ_REMOVE(&table->pending_add,
1607 existing_entry,
1608 node);
1609
1610 table_entry_free(existing_entry);
1611 }
1612
1613
1614
1615
1616
1617
1618 existing_entry = table_pending_modify1_find(table, entry);
1619 if (existing_entry) {
1620 struct rte_swx_table_entry *real_existing_entry;
1621
1622 TAILQ_REMOVE(&table->pending_modify1,
1623 existing_entry,
1624 node);
1625
1626 table_entry_free(existing_entry);
1627
1628 real_existing_entry = table_pending_modify0_find(table, entry);
1629 CHECK(real_existing_entry, EINVAL);
1630
1631 TAILQ_REMOVE(&table->pending_modify0,
1632 real_existing_entry,
1633 node);
1634
1635 TAILQ_INSERT_TAIL(&table->pending_delete,
1636 real_existing_entry,
1637 node);
1638
1639 return 0;
1640 }
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652 return 0;
1653}
1654
1655int
1656rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1657 const char *table_name,
1658 struct rte_swx_table_entry *entry)
1659{
1660 struct table *table;
1661 struct rte_swx_table_entry *new_entry;
1662 uint32_t table_id;
1663
1664 CHECK(ctl, EINVAL);
1665
1666 CHECK(table_name && table_name[0], EINVAL);
1667 table = table_find(ctl, table_name);
1668 CHECK(table, EINVAL);
1669 table_id = table - ctl->tables;
1670 CHECK(!table->info.default_action_is_const, EINVAL);
1671
1672 CHECK(entry, EINVAL);
1673 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1674
1675 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1676 CHECK(new_entry, ENOMEM);
1677
1678 table_pending_default_free(table);
1679
1680 table->pending_default = new_entry;
1681 return 0;
1682}
1683
1684
1685static void
1686table_entry_list_free(struct rte_swx_table_entry_list *list)
1687{
1688 for ( ; ; ) {
1689 struct rte_swx_table_entry *entry;
1690
1691 entry = TAILQ_FIRST(list);
1692 if (!entry)
1693 break;
1694
1695 TAILQ_REMOVE(list, entry, node);
1696 table_entry_free(entry);
1697 }
1698}
1699
1700static int
1701table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1702 uint32_t table_id,
1703 struct rte_swx_table_entry_list *dst,
1704 struct rte_swx_table_entry_list *src)
1705{
1706 struct rte_swx_table_entry *src_entry;
1707
1708 TAILQ_FOREACH(src_entry, src, node) {
1709 struct rte_swx_table_entry *dst_entry;
1710
1711 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1712 if (!dst_entry)
1713 goto error;
1714
1715 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1716 }
1717
1718 return 0;
1719
1720error:
1721 table_entry_list_free(dst);
1722 return -ENOMEM;
1723}
1724
1725
1726
1727
1728static int
1729table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1730 uint32_t table_id,
1731 uint32_t after_swap)
1732{
1733 struct table *table = &ctl->tables[table_id];
1734 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1735 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1736
1737 if (table->is_stub || !table_is_update_pending(table, 0))
1738 return 0;
1739
1740
1741
1742
1743 if (table->ops.add) {
1744
1745 table->n_add = 0;
1746 table->n_modify = 0;
1747 table->n_delete = 0;
1748
1749
1750 struct rte_swx_table_entry *entry;
1751
1752 TAILQ_FOREACH(entry, &table->pending_add, node) {
1753 int status;
1754
1755 status = table->ops.add(ts_next->obj, entry);
1756 if (status)
1757 return status;
1758
1759 table->n_add++;
1760 }
1761
1762
1763 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1764 int status;
1765
1766 status = table->ops.add(ts_next->obj, entry);
1767 if (status)
1768 return status;
1769
1770 table->n_modify++;
1771 }
1772
1773
1774 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1775 int status;
1776
1777 status = table->ops.del(ts_next->obj, entry);
1778 if (status)
1779 return status;
1780
1781 table->n_delete++;
1782 }
1783
1784 return 0;
1785 }
1786
1787
1788
1789
1790 if (!after_swap) {
1791 struct rte_swx_table_entry_list list;
1792 int status;
1793
1794
1795 TAILQ_INIT(&list);
1796
1797 status = table_entry_list_duplicate(ctl,
1798 table_id,
1799 &list,
1800 &table->entries);
1801 if (status)
1802 goto error;
1803
1804 status = table_entry_list_duplicate(ctl,
1805 table_id,
1806 &list,
1807 &table->pending_add);
1808 if (status)
1809 goto error;
1810
1811 status = table_entry_list_duplicate(ctl,
1812 table_id,
1813 &list,
1814 &table->pending_modify1);
1815 if (status)
1816 goto error;
1817
1818
1819 ts_next->obj = table->ops.create(&table->params,
1820 &list,
1821 table->info.args,
1822 ctl->numa_node);
1823 if (!ts_next->obj) {
1824 status = -ENODEV;
1825 goto error;
1826 }
1827
1828 table_entry_list_free(&list);
1829
1830 return 0;
1831
1832error:
1833 table_entry_list_free(&list);
1834 return status;
1835 }
1836
1837
1838 if (ts_next->obj && table->ops.free)
1839 table->ops.free(ts_next->obj);
1840
1841
1842 ts_next->obj = ts->obj;
1843
1844 return 0;
1845}
1846
1847
1848
1849
1850
1851static void
1852table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1853{
1854 struct table *table = &ctl->tables[table_id];
1855 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1856 struct action *a;
1857 uint8_t *action_data;
1858 uint64_t action_id;
1859
1860
1861 if (!table->pending_default)
1862 return;
1863
1864 action_id = table->pending_default->action_id;
1865 action_data = table->pending_default->action_data;
1866 a = &ctl->actions[action_id];
1867
1868 if (a->data_size)
1869 memcpy(ts_next->default_action_data, action_data, a->data_size);
1870
1871 ts_next->default_action_id = action_id;
1872}
1873
1874
1875
1876
1877
1878static void
1879table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1880{
1881 struct table *table = &ctl->tables[table_id];
1882
1883
1884
1885
1886 table_pending_add_admit(table);
1887
1888
1889
1890
1891
1892 table_pending_modify1_admit(table);
1893 table_pending_modify0_free(table);
1894
1895
1896
1897
1898 table_pending_delete_free(table);
1899
1900
1901 table_pending_default_free(table);
1902}
1903
1904
1905
1906
1907
1908
1909static void
1910table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1911{
1912 struct table *table = &ctl->tables[table_id];
1913 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1914
1915 if (table->is_stub || !table_is_update_pending(table, 0))
1916 return;
1917
1918 if (table->ops.add) {
1919 struct rte_swx_table_entry *entry;
1920
1921
1922 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1923 if (!table->n_delete)
1924 break;
1925
1926 table->ops.add(ts_next->obj, entry);
1927 table->n_delete--;
1928 }
1929
1930
1931
1932
1933 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1934 if (!table->n_modify)
1935 break;
1936
1937 table->ops.add(ts_next->obj, entry);
1938 table->n_modify--;
1939 }
1940
1941
1942 TAILQ_FOREACH(entry, &table->pending_add, node) {
1943 if (!table->n_add)
1944 break;
1945
1946 table->ops.del(ts_next->obj, entry);
1947 table->n_add--;
1948 }
1949 } else {
1950 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1951
1952
1953 if (ts_next->obj && table->ops.free)
1954 table->ops.free(ts_next->obj);
1955
1956
1957 ts_next->obj = ts->obj;
1958 }
1959}
1960
1961
1962
1963
1964static void
1965table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1966{
1967 struct table *table = &ctl->tables[table_id];
1968
1969
1970
1971
1972 table_pending_add_free(table);
1973
1974
1975
1976
1977
1978 table_pending_modify1_free(table);
1979 table_pending_modify0_admit(table);
1980
1981
1982
1983
1984 table_pending_delete_admit(table);
1985
1986
1987
1988
1989 table_pending_default_free(table);
1990}
1991
1992int
1993rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1994 const char *selector_name,
1995 uint32_t *group_id)
1996{
1997 struct selector *s;
1998 uint32_t i;
1999
2000
2001 if (!ctl || !selector_name || !selector_name[0] || !group_id)
2002 return -EINVAL;
2003
2004 s = selector_find(ctl, selector_name);
2005 if (!s)
2006 return -EINVAL;
2007
2008
2009 for (i = 0; i < s->info.n_groups_max; i++)
2010 if (!s->groups_added[i]) {
2011 *group_id = i;
2012 s->groups_added[i] = 1;
2013 return 0;
2014 }
2015
2016 return -ENOSPC;
2017}
2018
2019int
2020rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2021 const char *selector_name,
2022 uint32_t group_id)
2023{
2024 struct selector *s;
2025 struct rte_swx_table_selector_group *group;
2026
2027
2028 if (!ctl || !selector_name || !selector_name[0])
2029 return -EINVAL;
2030
2031 s = selector_find(ctl, selector_name);
2032 if (!s ||
2033 (group_id >= s->info.n_groups_max) ||
2034 !s->groups_added[group_id])
2035 return -EINVAL;
2036
2037
2038 if (s->groups_pending_delete[group_id])
2039 return 0;
2040
2041
2042 if (!s->pending_groups[group_id]) {
2043 int status;
2044
2045 status = selector_group_duplicate_to_pending(s, group_id);
2046 if (status)
2047 return status;
2048 }
2049
2050 group = s->pending_groups[group_id];
2051
2052
2053 for ( ; ; ) {
2054 struct rte_swx_table_selector_member *m;
2055
2056 m = TAILQ_FIRST(&group->members);
2057 if (!m)
2058 break;
2059
2060 TAILQ_REMOVE(&group->members, m, node);
2061 free(m);
2062 }
2063
2064
2065 s->groups_pending_delete[group_id] = 1;
2066
2067 return 0;
2068}
2069
2070int
2071rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2072 const char *selector_name,
2073 uint32_t group_id,
2074 uint32_t member_id,
2075 uint32_t member_weight)
2076{
2077 struct selector *s;
2078 struct rte_swx_table_selector_group *group;
2079 struct rte_swx_table_selector_member *m;
2080
2081 if (!member_weight)
2082 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2083 selector_name,
2084 group_id,
2085 member_id);
2086
2087
2088 if (!ctl || !selector_name || !selector_name[0])
2089 return -EINVAL;
2090
2091 s = selector_find(ctl, selector_name);
2092 if (!s ||
2093 (group_id >= s->info.n_groups_max) ||
2094 !s->groups_added[group_id] ||
2095 s->groups_pending_delete[group_id])
2096 return -EINVAL;
2097
2098
2099 if (!s->pending_groups[group_id]) {
2100 int status;
2101
2102 status = selector_group_duplicate_to_pending(s, group_id);
2103 if (status)
2104 return status;
2105 }
2106
2107 group = s->pending_groups[group_id];
2108
2109
2110 TAILQ_FOREACH(m, &group->members, node)
2111 if (m->member_id == member_id) {
2112 m->member_weight = member_weight;
2113 return 0;
2114 }
2115
2116
2117 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2118 if (!m)
2119 return -ENOMEM;
2120
2121 m->member_id = member_id;
2122 m->member_weight = member_weight;
2123
2124 TAILQ_INSERT_TAIL(&group->members, m, node);
2125
2126 return 0;
2127}
2128
2129int
2130rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2131 const char *selector_name,
2132 uint32_t group_id __rte_unused,
2133 uint32_t member_id __rte_unused)
2134{
2135 struct selector *s;
2136 struct rte_swx_table_selector_group *group;
2137 struct rte_swx_table_selector_member *m;
2138
2139
2140 if (!ctl || !selector_name || !selector_name[0])
2141 return -EINVAL;
2142
2143 s = selector_find(ctl, selector_name);
2144 if (!s ||
2145 (group_id >= s->info.n_groups_max) ||
2146 !s->groups_added[group_id] ||
2147 s->groups_pending_delete[group_id])
2148 return -EINVAL;
2149
2150
2151 if (!s->pending_groups[group_id]) {
2152 int status;
2153
2154 status = selector_group_duplicate_to_pending(s, group_id);
2155 if (status)
2156 return status;
2157 }
2158
2159 group = s->pending_groups[group_id];
2160
2161
2162 TAILQ_FOREACH(m, &group->members, node)
2163 if (m->member_id == member_id) {
2164 TAILQ_REMOVE(&group->members, m, node);
2165 free(m);
2166 return 0;
2167 }
2168
2169 return 0;
2170}
2171
2172static int
2173selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2174{
2175 struct selector *s = &ctl->selectors[selector_id];
2176 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2177 uint32_t group_id;
2178
2179
2180
2181
2182 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2183 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2184 int status;
2185
2186
2187 if (!group)
2188 continue;
2189
2190
2191 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2192 if (status)
2193 return status;
2194 }
2195
2196 return 0;
2197}
2198
2199static void
2200selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2201{
2202 struct selector *s = &ctl->selectors[selector_id];
2203 uint32_t group_id;
2204
2205
2206
2207
2208 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2209 struct rte_swx_table_selector_group *g = s->groups[group_id];
2210 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2211
2212
2213 if (!gp)
2214 continue;
2215
2216
2217 s->groups[group_id] = gp;
2218 s->pending_groups[group_id] = NULL;
2219
2220
2221 if (!g)
2222 continue;
2223
2224 for ( ; ; ) {
2225 struct rte_swx_table_selector_member *m;
2226
2227 m = TAILQ_FIRST(&g->members);
2228 if (!m)
2229 break;
2230
2231 TAILQ_REMOVE(&g->members, m, node);
2232 free(m);
2233 }
2234
2235 free(g);
2236 }
2237
2238
2239
2240
2241 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2242 if (s->groups_pending_delete[group_id]) {
2243 s->groups_added[group_id] = 0;
2244 s->groups_pending_delete[group_id] = 0;
2245 }
2246}
2247
2248static void
2249selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2250{
2251 struct selector *s = &ctl->selectors[selector_id];
2252 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2253 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2254 uint32_t group_id;
2255
2256
2257 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2258 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2259
2260 if (gp) {
2261 ts_next->obj = ts->obj;
2262 break;
2263 }
2264 }
2265}
2266
2267static void
2268selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2269{
2270 struct selector *s = &ctl->selectors[selector_id];
2271 uint32_t group_id;
2272
2273
2274 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2275 selector_pending_group_members_free(s, group_id);
2276
2277
2278 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2279}
2280
2281static struct rte_swx_table_entry *
2282learner_default_entry_alloc(struct learner *l)
2283{
2284 struct rte_swx_table_entry *entry;
2285
2286 entry = calloc(1, sizeof(struct rte_swx_table_entry));
2287 if (!entry)
2288 goto error;
2289
2290
2291 if (l->action_data_size) {
2292 entry->action_data = calloc(1, l->action_data_size);
2293 if (!entry->action_data)
2294 goto error;
2295 }
2296
2297 return entry;
2298
2299error:
2300 table_entry_free(entry);
2301 return NULL;
2302}
2303
2304static int
2305learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2306 uint32_t learner_id,
2307 struct rte_swx_table_entry *entry)
2308{
2309 struct learner *l = &ctl->learners[learner_id];
2310 struct action *a;
2311 uint32_t i;
2312
2313 CHECK(entry, EINVAL);
2314
2315
2316 for (i = 0; i < l->info.n_actions; i++)
2317 if (entry->action_id == l->actions[i].action_id)
2318 break;
2319
2320 CHECK(i < l->info.n_actions, EINVAL);
2321
2322
2323 a = &ctl->actions[entry->action_id];
2324 CHECK(!(a->data_size && !entry->action_data), EINVAL);
2325
2326 return 0;
2327}
2328
2329static struct rte_swx_table_entry *
2330learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2331 uint32_t learner_id,
2332 struct rte_swx_table_entry *entry)
2333{
2334 struct learner *l = &ctl->learners[learner_id];
2335 struct rte_swx_table_entry *new_entry = NULL;
2336 struct action *a;
2337 uint32_t i;
2338
2339 if (!entry)
2340 goto error;
2341
2342 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2343 if (!new_entry)
2344 goto error;
2345
2346
2347 for (i = 0; i < l->info.n_actions; i++)
2348 if (entry->action_id == l->actions[i].action_id)
2349 break;
2350
2351 if (i >= l->info.n_actions)
2352 goto error;
2353
2354 new_entry->action_id = entry->action_id;
2355
2356
2357 a = &ctl->actions[entry->action_id];
2358 if (a->data_size && !entry->action_data)
2359 goto error;
2360
2361
2362
2363
2364
2365
2366
2367
2368 new_entry->action_data = calloc(1, l->action_data_size);
2369 if (!new_entry->action_data)
2370 goto error;
2371
2372 if (a->data_size)
2373 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2374
2375 return new_entry;
2376
2377error:
2378 table_entry_free(new_entry);
2379 return NULL;
2380}
2381
2382int
2383rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2384 const char *learner_name,
2385 struct rte_swx_table_entry *entry)
2386{
2387 struct learner *l;
2388 struct rte_swx_table_entry *new_entry;
2389 uint32_t learner_id;
2390
2391 CHECK(ctl, EINVAL);
2392
2393 CHECK(learner_name && learner_name[0], EINVAL);
2394 l = learner_find(ctl, learner_name);
2395 CHECK(l, EINVAL);
2396 learner_id = l - ctl->learners;
2397 CHECK(!l->info.default_action_is_const, EINVAL);
2398
2399 CHECK(entry, EINVAL);
2400 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2401
2402 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2403
2404 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2405 CHECK(new_entry, ENOMEM);
2406
2407 learner_pending_default_free(l);
2408
2409 l->pending_default = new_entry;
2410 return 0;
2411}
2412
2413static void
2414learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2415{
2416 struct learner *l = &ctl->learners[learner_id];
2417 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2418 ctl->info.n_selectors + learner_id];
2419 struct action *a;
2420 uint8_t *action_data;
2421 uint64_t action_id;
2422
2423
2424 if (!l->pending_default)
2425 return;
2426
2427 action_id = l->pending_default->action_id;
2428 action_data = l->pending_default->action_data;
2429 a = &ctl->actions[action_id];
2430
2431 if (a->data_size)
2432 memcpy(ts_next->default_action_data, action_data, a->data_size);
2433
2434 ts_next->default_action_id = action_id;
2435}
2436
2437static void
2438learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2439{
2440 struct learner *l = &ctl->learners[learner_id];
2441
2442
2443 learner_pending_default_free(l);
2444}
2445
2446static void
2447learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2448{
2449 struct learner *l = &ctl->learners[learner_id];
2450
2451
2452 learner_pending_default_free(l);
2453}
2454
2455int
2456rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2457{
2458 struct rte_swx_table_state *ts;
2459 int status = 0;
2460 uint32_t i;
2461
2462 CHECK(ctl, EINVAL);
2463
2464
2465
2466
2467
2468 for (i = 0; i < ctl->info.n_tables; i++) {
2469 status = table_rollfwd0(ctl, i, 0);
2470 if (status)
2471 goto rollback;
2472 }
2473
2474 for (i = 0; i < ctl->info.n_selectors; i++) {
2475 status = selector_rollfwd(ctl, i);
2476 if (status)
2477 goto rollback;
2478 }
2479
2480
2481
2482
2483 for (i = 0; i < ctl->info.n_tables; i++)
2484 table_rollfwd1(ctl, i);
2485
2486 for (i = 0; i < ctl->info.n_learners; i++)
2487 learner_rollfwd(ctl, i);
2488
2489
2490
2491
2492 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2493 usleep(100);
2494 ts = ctl->ts;
2495 ctl->ts = ctl->ts_next;
2496 ctl->ts_next = ts;
2497
2498
2499
2500
2501
2502
2503 for (i = 0; i < ctl->info.n_tables; i++) {
2504 table_rollfwd0(ctl, i, 1);
2505 table_rollfwd1(ctl, i);
2506 table_rollfwd2(ctl, i);
2507 }
2508
2509 for (i = 0; i < ctl->info.n_selectors; i++) {
2510 selector_rollfwd(ctl, i);
2511 selector_rollfwd_finalize(ctl, i);
2512 }
2513
2514 for (i = 0; i < ctl->info.n_learners; i++) {
2515 learner_rollfwd(ctl, i);
2516 learner_rollfwd_finalize(ctl, i);
2517 }
2518
2519 return 0;
2520
2521rollback:
2522 for (i = 0; i < ctl->info.n_tables; i++) {
2523 table_rollback(ctl, i);
2524 if (abort_on_fail)
2525 table_abort(ctl, i);
2526 }
2527
2528 for (i = 0; i < ctl->info.n_selectors; i++) {
2529 selector_rollback(ctl, i);
2530 if (abort_on_fail)
2531 selector_abort(ctl, i);
2532 }
2533
2534 if (abort_on_fail)
2535 for (i = 0; i < ctl->info.n_learners; i++)
2536 learner_abort(ctl, i);
2537
2538 return status;
2539}
2540
2541void
2542rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2543{
2544 uint32_t i;
2545
2546 if (!ctl)
2547 return;
2548
2549 for (i = 0; i < ctl->info.n_tables; i++)
2550 table_abort(ctl, i);
2551
2552 for (i = 0; i < ctl->info.n_selectors; i++)
2553 selector_abort(ctl, i);
2554
2555 for (i = 0; i < ctl->info.n_learners; i++)
2556 learner_abort(ctl, i);
2557}
2558
2559static int
2560mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2561{
2562 uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2563
2564 if (!mask) {
2565 *prefix_length = 0;
2566 return 0;
2567 }
2568
2569
2570 for (i = 0; i < 64; i++) {
2571 if (mask & (1LLU << i))
2572 break;
2573
2574 n_trailing_zeros++;
2575 }
2576
2577
2578 for ( ; i < 64; i++) {
2579 if (!(mask & (1LLU << i)))
2580 break;
2581
2582 n_ones++;
2583 }
2584
2585
2586 for ( ; i < 64; i++)
2587 if (mask & (1LLU << i))
2588 return -EINVAL;
2589
2590
2591 if (n_ones + n_trailing_zeros != mask_length)
2592 return -EINVAL;
2593
2594 *prefix_length = n_ones;
2595 return 0;
2596}
2597
2598static int
2599token_is_comment(const char *token)
2600{
2601 if ((token[0] == '#') ||
2602 (token[0] == ';') ||
2603 ((token[0] == '/') && (token[1] == '/')))
2604 return 1;
2605
2606 return 0;
2607}
2608
2609#define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2610
2611struct rte_swx_table_entry *
2612rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2613 const char *table_name,
2614 const char *string,
2615 int *is_blank_or_comment)
2616{
2617 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2618 struct table *table;
2619 struct action *action;
2620 struct rte_swx_table_entry *entry = NULL;
2621 char *s0 = NULL, *s;
2622 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2623 int lpm = 0, blank_or_comment = 0;
2624
2625
2626 if (!ctl)
2627 goto error;
2628
2629 if (!table_name || !table_name[0])
2630 goto error;
2631
2632 table = table_find(ctl, table_name);
2633 if (!table)
2634 goto error;
2635
2636 if (!string || !string[0])
2637 goto error;
2638
2639
2640 s0 = strdup(string);
2641 if (!s0)
2642 goto error;
2643
2644 entry = table_entry_alloc(table);
2645 if (!entry)
2646 goto error;
2647
2648
2649 for (s = s0; ; ) {
2650 char *token;
2651
2652 token = strtok_r(s, " \f\n\r\t\v", &s);
2653 if (!token || token_is_comment(token))
2654 break;
2655
2656 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2657 goto error;
2658
2659 token_array[n_tokens] = token;
2660 n_tokens++;
2661 }
2662
2663 if (!n_tokens) {
2664 blank_or_comment = 1;
2665 goto error;
2666 }
2667
2668 tokens = token_array;
2669
2670
2671
2672
2673 if (!(n_tokens && !strcmp(tokens[0], "match")))
2674 goto action;
2675
2676 if (n_tokens < 1 + table->info.n_match_fields)
2677 goto error;
2678
2679 for (i = 0; i < table->info.n_match_fields; i++) {
2680 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2681 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2682 uint64_t val, mask = UINT64_MAX;
2683 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2684
2685
2686
2687
2688 mf_mask = strchr(mf_val, '/');
2689 if (mf_mask) {
2690 *mf_mask = 0;
2691 mf_mask++;
2692
2693
2694 mask = strtoull(mf_mask, &mf_mask, 0);
2695 if (mf_mask[0])
2696 goto error;
2697
2698
2699 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2700 int status;
2701
2702 lpm = 1;
2703
2704 lpm_prefix_length_max = mf->n_bits;
2705
2706 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2707 if (status)
2708 goto error;
2709 }
2710
2711
2712 if (mf->is_header)
2713 mask = field_hton(mask, mf->n_bits);
2714 }
2715
2716
2717 if (entry->key_mask)
2718 memcpy(&entry->key_mask[offset],
2719 (uint8_t *)&mask,
2720 mf->n_bits / 8);
2721
2722
2723
2724
2725
2726 val = strtoull(mf_val, &mf_val, 0);
2727 if (mf_val[0])
2728 goto error;
2729
2730
2731 if (mf->is_header)
2732 val = field_hton(val, mf->n_bits);
2733
2734
2735 memcpy(&entry->key[offset],
2736 (uint8_t *)&val,
2737 mf->n_bits / 8);
2738 }
2739
2740 tokens += 1 + table->info.n_match_fields;
2741 n_tokens -= 1 + table->info.n_match_fields;
2742
2743
2744
2745
2746 if (n_tokens && !strcmp(tokens[0], "priority")) {
2747 char *priority = tokens[1];
2748 uint32_t val;
2749
2750 if (n_tokens < 2)
2751 goto error;
2752
2753
2754 val = strtoul(priority, &priority, 0);
2755 if (priority[0])
2756 goto error;
2757
2758
2759 entry->key_priority = val;
2760
2761 tokens += 2;
2762 n_tokens -= 2;
2763 }
2764
2765
2766 if (lpm)
2767 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2768
2769
2770
2771
2772action:
2773 if (!(n_tokens && !strcmp(tokens[0], "action")))
2774 goto other;
2775
2776 if (n_tokens < 2)
2777 goto error;
2778
2779 action = action_find(ctl, tokens[1]);
2780 if (!action)
2781 goto error;
2782
2783 if (n_tokens < 2 + action->info.n_args * 2)
2784 goto error;
2785
2786
2787 entry->action_id = action - ctl->actions;
2788
2789
2790 for (i = 0; i < action->info.n_args; i++) {
2791 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2792 char *arg_name, *arg_val;
2793 uint64_t val;
2794
2795 arg_name = tokens[2 + i * 2];
2796 arg_val = tokens[2 + i * 2 + 1];
2797
2798 if (strcmp(arg_name, arg->name))
2799 goto error;
2800
2801 val = strtoull(arg_val, &arg_val, 0);
2802 if (arg_val[0])
2803 goto error;
2804
2805
2806 if (arg->is_network_byte_order)
2807 val = field_hton(val, arg->n_bits);
2808
2809
2810 memcpy(&entry->action_data[arg_offset],
2811 (uint8_t *)&val,
2812 arg->n_bits / 8);
2813
2814 arg_offset += arg->n_bits / 8;
2815 }
2816
2817 tokens += 2 + action->info.n_args * 2;
2818 n_tokens -= 2 + action->info.n_args * 2;
2819
2820other:
2821 if (n_tokens)
2822 goto error;
2823
2824 free(s0);
2825 return entry;
2826
2827error:
2828 table_entry_free(entry);
2829 free(s0);
2830 if (is_blank_or_comment)
2831 *is_blank_or_comment = blank_or_comment;
2832 return NULL;
2833}
2834
2835struct rte_swx_table_entry *
2836rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2837 const char *learner_name,
2838 const char *string,
2839 int *is_blank_or_comment)
2840{
2841 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2842 struct learner *l;
2843 struct action *action;
2844 struct rte_swx_table_entry *entry = NULL;
2845 char *s0 = NULL, *s;
2846 uint32_t n_tokens = 0, arg_offset = 0, i;
2847 int blank_or_comment = 0;
2848
2849
2850 if (!ctl)
2851 goto error;
2852
2853 if (!learner_name || !learner_name[0])
2854 goto error;
2855
2856 l = learner_find(ctl, learner_name);
2857 if (!l)
2858 goto error;
2859
2860 if (!string || !string[0])
2861 goto error;
2862
2863
2864 s0 = strdup(string);
2865 if (!s0)
2866 goto error;
2867
2868 entry = learner_default_entry_alloc(l);
2869 if (!entry)
2870 goto error;
2871
2872
2873 for (s = s0; ; ) {
2874 char *token;
2875
2876 token = strtok_r(s, " \f\n\r\t\v", &s);
2877 if (!token || token_is_comment(token))
2878 break;
2879
2880 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2881 goto error;
2882
2883 token_array[n_tokens] = token;
2884 n_tokens++;
2885 }
2886
2887 if (!n_tokens) {
2888 blank_or_comment = 1;
2889 goto error;
2890 }
2891
2892 tokens = token_array;
2893
2894
2895
2896
2897 if (!(n_tokens && !strcmp(tokens[0], "action")))
2898 goto other;
2899
2900 if (n_tokens < 2)
2901 goto error;
2902
2903 action = action_find(ctl, tokens[1]);
2904 if (!action)
2905 goto error;
2906
2907 if (n_tokens < 2 + action->info.n_args * 2)
2908 goto error;
2909
2910
2911 entry->action_id = action - ctl->actions;
2912
2913
2914 for (i = 0; i < action->info.n_args; i++) {
2915 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2916 char *arg_name, *arg_val;
2917 uint64_t val;
2918
2919 arg_name = tokens[2 + i * 2];
2920 arg_val = tokens[2 + i * 2 + 1];
2921
2922 if (strcmp(arg_name, arg->name))
2923 goto error;
2924
2925 val = strtoull(arg_val, &arg_val, 0);
2926 if (arg_val[0])
2927 goto error;
2928
2929
2930 if (arg->is_network_byte_order)
2931 val = field_hton(val, arg->n_bits);
2932
2933
2934 memcpy(&entry->action_data[arg_offset],
2935 (uint8_t *)&val,
2936 arg->n_bits / 8);
2937
2938 arg_offset += arg->n_bits / 8;
2939 }
2940
2941 tokens += 2 + action->info.n_args * 2;
2942 n_tokens -= 2 + action->info.n_args * 2;
2943
2944other:
2945 if (n_tokens)
2946 goto error;
2947
2948 free(s0);
2949 return entry;
2950
2951error:
2952 table_entry_free(entry);
2953 free(s0);
2954 if (is_blank_or_comment)
2955 *is_blank_or_comment = blank_or_comment;
2956 return NULL;
2957}
2958
2959static void
2960table_entry_printf(FILE *f,
2961 struct rte_swx_ctl_pipeline *ctl,
2962 struct table *table,
2963 struct rte_swx_table_entry *entry)
2964{
2965 struct action *action = &ctl->actions[entry->action_id];
2966 uint32_t i;
2967
2968 fprintf(f, "match ");
2969 for (i = 0; i < table->params.key_size; i++)
2970 fprintf(f, "%02x", entry->key[i]);
2971
2972 if (entry->key_mask) {
2973 fprintf(f, "/");
2974 for (i = 0; i < table->params.key_size; i++)
2975 fprintf(f, "%02x", entry->key_mask[i]);
2976 }
2977
2978 fprintf(f, " priority %u", entry->key_priority);
2979
2980 fprintf(f, " action %s ", action->info.name);
2981 for (i = 0; i < action->data_size; i++)
2982 fprintf(f, "%02x", entry->action_data[i]);
2983
2984 fprintf(f, "\n");
2985}
2986
2987int
2988rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2989 struct rte_swx_ctl_pipeline *ctl,
2990 const char *table_name)
2991{
2992 struct table *table;
2993 struct rte_swx_table_entry *entry;
2994 uint32_t n_entries = 0, i;
2995
2996 if (!f || !ctl || !table_name || !table_name[0])
2997 return -EINVAL;
2998
2999 table = table_find(ctl, table_name);
3000 if (!table)
3001 return -EINVAL;
3002
3003
3004 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3005 table->info.name,
3006 table->params.key_size,
3007 table->params.key_offset);
3008
3009 for (i = 0; i < table->params.key_size; i++)
3010 fprintf(f, "%02x", table->params.key_mask0[i]);
3011
3012 fprintf(f, "], action data size %u bytes\n",
3013 table->params.action_data_size);
3014
3015
3016 TAILQ_FOREACH(entry, &table->entries, node) {
3017 table_entry_printf(f, ctl, table, entry);
3018 n_entries++;
3019 }
3020
3021 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3022 table_entry_printf(f, ctl, table, entry);
3023 n_entries++;
3024 }
3025
3026 TAILQ_FOREACH(entry, &table->pending_delete, node) {
3027 table_entry_printf(f, ctl, table, entry);
3028 n_entries++;
3029 }
3030
3031 fprintf(f, "# Table %s currently has %u entries.\n",
3032 table_name,
3033 n_entries);
3034 return 0;
3035}
3036
3037int
3038rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3039 struct rte_swx_ctl_pipeline *ctl,
3040 const char *selector_name)
3041{
3042 struct selector *s;
3043 uint32_t group_id;
3044
3045 if (!f || !ctl || !selector_name || !selector_name[0])
3046 return -EINVAL;
3047
3048 s = selector_find(ctl, selector_name);
3049 if (!s)
3050 return -EINVAL;
3051
3052
3053 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3054 s->info.name,
3055 s->info.n_groups_max,
3056 s->info.n_members_per_group_max);
3057
3058
3059 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3060 struct rte_swx_table_selector_group *group = s->groups[group_id];
3061 struct rte_swx_table_selector_member *m;
3062 uint32_t n_members = 0;
3063
3064 fprintf(f, "Group %u = [", group_id);
3065
3066
3067 if (group)
3068 TAILQ_FOREACH(m, &group->members, node) {
3069 fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3070 n_members++;
3071 }
3072
3073
3074 if (!n_members)
3075 fprintf(f, "0:1 ");
3076
3077 fprintf(f, "]\n");
3078 }
3079
3080 return 0;
3081}
3082