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_ctl.h"
14
15#define CHECK(condition, err_code) \
16do { \
17 if (!(condition)) \
18 return -(err_code); \
19} while (0)
20
21#define ntoh64(x) rte_be_to_cpu_64(x)
22#define hton64(x) rte_cpu_to_be_64(x)
23
24#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
25#define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
26#define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
27#else
28#define field_ntoh(val, n_bits) (val)
29#define field_hton(val, n_bits) (val)
30#endif
31
32struct action {
33 struct rte_swx_ctl_action_info info;
34 struct rte_swx_ctl_action_arg_info *args;
35 uint32_t data_size;
36};
37
38struct table {
39 struct rte_swx_ctl_table_info info;
40 struct rte_swx_ctl_table_match_field_info *mf;
41
42
43 struct rte_swx_ctl_table_match_field_info *mf_first;
44
45
46 struct rte_swx_ctl_table_match_field_info *mf_last;
47
48 struct rte_swx_ctl_table_action_info *actions;
49 struct rte_swx_table_ops ops;
50 struct rte_swx_table_params params;
51
52
53
54
55
56 struct rte_swx_table_entry_list entries;
57
58
59
60
61
62 struct rte_swx_table_entry_list pending_add;
63
64
65
66
67
68
69
70
71 struct rte_swx_table_entry_list pending_modify0;
72 struct rte_swx_table_entry_list pending_modify1;
73
74
75
76
77
78 struct rte_swx_table_entry_list pending_delete;
79
80
81
82
83
84 struct rte_swx_table_entry *pending_default;
85
86 int is_stub;
87 uint32_t n_add;
88 uint32_t n_modify;
89 uint32_t n_delete;
90};
91
92struct rte_swx_ctl_pipeline {
93 struct rte_swx_ctl_pipeline_info info;
94 struct rte_swx_pipeline *p;
95 struct action *actions;
96 struct table *tables;
97 struct rte_swx_table_state *ts;
98 struct rte_swx_table_state *ts_next;
99 int numa_node;
100};
101
102static struct action *
103action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
104{
105 uint32_t i;
106
107 for (i = 0; i < ctl->info.n_actions; i++) {
108 struct action *a = &ctl->actions[i];
109
110 if (!strcmp(action_name, a->info.name))
111 return a;
112 }
113
114 return NULL;
115}
116
117static void
118action_free(struct rte_swx_ctl_pipeline *ctl)
119{
120 uint32_t i;
121
122 if (!ctl->actions)
123 return;
124
125 for (i = 0; i < ctl->info.n_actions; i++) {
126 struct action *action = &ctl->actions[i];
127
128 free(action->args);
129 }
130
131 free(ctl->actions);
132 ctl->actions = NULL;
133}
134
135static struct table *
136table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
137{
138 uint32_t i;
139
140 for (i = 0; i < ctl->info.n_tables; i++) {
141 struct table *table = &ctl->tables[i];
142
143 if (!strcmp(table_name, table->info.name))
144 return table;
145 }
146
147 return NULL;
148}
149
150static int
151table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
152{
153 struct table *table = &ctl->tables[table_id];
154 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
155 uint8_t *key_mask = NULL;
156 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
157 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
158
159 if (table->info.n_match_fields) {
160 uint32_t n_match_fields_em = 0, i;
161
162
163 first = &table->mf[0];
164 last = &table->mf[0];
165
166 for (i = 1; i < table->info.n_match_fields; i++) {
167 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
168
169 if (f->offset < first->offset)
170 first = f;
171
172 if (f->offset > last->offset)
173 last = f;
174 }
175
176
177 for (i = 0; i < table->info.n_match_fields; i++) {
178 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
179
180 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
181 n_match_fields_em++;
182 }
183
184 if (n_match_fields_em == table->info.n_match_fields)
185 match_type = RTE_SWX_TABLE_MATCH_EXACT;
186 else if ((n_match_fields_em == table->info.n_match_fields - 1) &&
187 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
188 match_type = RTE_SWX_TABLE_MATCH_LPM;
189
190
191 key_offset = first->offset / 8;
192
193
194 key_size = (last->offset + last->n_bits - first->offset) / 8;
195
196
197 key_mask = calloc(1, key_size);
198 CHECK(key_mask, ENOMEM);
199
200 for (i = 0; i < table->info.n_match_fields; i++) {
201 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
202 uint32_t start;
203 size_t size;
204
205 start = (f->offset - first->offset) / 8;
206 size = f->n_bits / 8;
207
208 memset(&key_mask[start], 0xFF, size);
209 }
210 }
211
212
213 for (i = 0; i < table->info.n_actions; i++) {
214 uint32_t action_id = table->actions[i].action_id;
215 struct action *a = &ctl->actions[action_id];
216
217 if (a->data_size > action_data_size)
218 action_data_size = a->data_size;
219 }
220
221
222 table->params.match_type = match_type;
223 table->params.key_size = key_size;
224 table->params.key_offset = key_offset;
225 table->params.key_mask0 = key_mask;
226 table->params.action_data_size = action_data_size;
227 table->params.n_keys_max = table->info.size;
228
229 table->mf_first = first;
230 table->mf_last = last;
231
232 return 0;
233}
234
235static void
236table_entry_free(struct rte_swx_table_entry *entry)
237{
238 if (!entry)
239 return;
240
241 free(entry->key);
242 free(entry->key_mask);
243 free(entry->action_data);
244 free(entry);
245}
246
247static struct rte_swx_table_entry *
248table_entry_alloc(struct table *table)
249{
250 struct rte_swx_table_entry *entry;
251
252 entry = calloc(1, sizeof(struct rte_swx_table_entry));
253 if (!entry)
254 goto error;
255
256
257 if (!table->is_stub) {
258 entry->key = calloc(1, table->params.key_size);
259 if (!entry->key)
260 goto error;
261
262 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
263 entry->key_mask = calloc(1, table->params.key_size);
264 if (!entry->key_mask)
265 goto error;
266 }
267 }
268
269
270 if (table->params.action_data_size) {
271 entry->action_data = calloc(1, table->params.action_data_size);
272 if (!entry->action_data)
273 goto error;
274 }
275
276 return entry;
277
278error:
279 table_entry_free(entry);
280 return NULL;
281}
282
283static int
284table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
285{
286 uint8_t *key_mask0 = table->params.key_mask0;
287 uint32_t key_size = table->params.key_size, i;
288
289 if (!entry->key_mask)
290 return 0;
291
292 for (i = 0; i < key_size; i++) {
293 uint8_t km0 = key_mask0[i];
294 uint8_t km = entry->key_mask[i];
295
296 if ((km & km0) != km0)
297 return -EINVAL;
298 }
299
300 return 0;
301}
302
303static int
304table_entry_check(struct rte_swx_ctl_pipeline *ctl,
305 uint32_t table_id,
306 struct rte_swx_table_entry *entry,
307 int key_check,
308 int data_check)
309{
310 struct table *table = &ctl->tables[table_id];
311 int status;
312
313 CHECK(entry, EINVAL);
314
315 if (key_check) {
316 if (table->is_stub) {
317
318 CHECK(!entry->key, EINVAL);
319
320
321 CHECK(!entry->key_mask, EINVAL);
322 } else {
323
324 CHECK(entry->key, EINVAL);
325
326
327 switch (table->params.match_type) {
328 case RTE_SWX_TABLE_MATCH_WILDCARD:
329 break;
330
331 case RTE_SWX_TABLE_MATCH_LPM:
332
333 break;
334
335 case RTE_SWX_TABLE_MATCH_EXACT:
336 status = table_entry_key_check_em(table, entry);
337 if (status)
338 return status;
339 break;
340
341 default:
342 CHECK(0, EINVAL);
343 }
344 }
345 }
346
347 if (data_check) {
348 struct action *a;
349 uint32_t i;
350
351
352 for (i = 0; i < table->info.n_actions; i++)
353 if (entry->action_id == table->actions[i].action_id)
354 break;
355
356 CHECK(i < table->info.n_actions, EINVAL);
357
358
359 a = &ctl->actions[entry->action_id];
360 CHECK(!(a->data_size && !entry->action_data), EINVAL);
361 }
362
363 return 0;
364}
365
366static struct rte_swx_table_entry *
367table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
368 uint32_t table_id,
369 struct rte_swx_table_entry *entry,
370 int key_duplicate,
371 int data_duplicate)
372{
373 struct table *table = &ctl->tables[table_id];
374 struct rte_swx_table_entry *new_entry = NULL;
375
376 if (!entry)
377 goto error;
378
379 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
380 if (!new_entry)
381 goto error;
382
383 if (key_duplicate && !table->is_stub) {
384
385 if (!entry->key)
386 goto error;
387
388 new_entry->key = malloc(table->params.key_size);
389 if (!new_entry->key)
390 goto error;
391
392 memcpy(new_entry->key, entry->key, table->params.key_size);
393
394
395 new_entry->key_signature = entry->key_signature;
396
397
398 if (entry->key_mask) {
399 new_entry->key_mask = malloc(table->params.key_size);
400 if (!new_entry->key_mask)
401 goto error;
402
403 memcpy(new_entry->key_mask,
404 entry->key_mask,
405 table->params.key_size);
406 }
407
408
409 new_entry->key_priority = entry->key_priority;
410 }
411
412 if (data_duplicate) {
413 struct action *a;
414 uint32_t i;
415
416
417 for (i = 0; i < table->info.n_actions; i++)
418 if (entry->action_id == table->actions[i].action_id)
419 break;
420
421 if (i >= table->info.n_actions)
422 goto error;
423
424 new_entry->action_id = entry->action_id;
425
426
427 a = &ctl->actions[entry->action_id];
428 if (a->data_size && !entry->action_data)
429 goto error;
430
431
432
433
434
435
436
437
438 new_entry->action_data = calloc(1, table->params.action_data_size);
439 if (!new_entry->action_data)
440 goto error;
441
442 if (a->data_size)
443 memcpy(new_entry->action_data,
444 entry->action_data,
445 a->data_size);
446 }
447
448 return new_entry;
449
450error:
451 table_entry_free(new_entry);
452 return NULL;
453}
454
455static int
456table_entry_keycmp(struct table *table,
457 struct rte_swx_table_entry *e0,
458 struct rte_swx_table_entry *e1)
459{
460 uint32_t key_size = table->params.key_size;
461 uint32_t i;
462
463 for (i = 0; i < key_size; i++) {
464 uint8_t *key_mask0 = table->params.key_mask0;
465 uint8_t km0, km[2], k[2];
466
467 km0 = key_mask0 ? key_mask0[i] : 0xFF;
468
469 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
470 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
471
472 k[0] = e0->key[i];
473 k[1] = e1->key[i];
474
475
476 if ((km[0] & km0) != (km[1] & km0))
477 return 1;
478
479
480 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
481 return 1;
482 }
483
484 return 0;
485}
486
487static struct rte_swx_table_entry *
488table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
489{
490 struct rte_swx_table_entry *e;
491
492 TAILQ_FOREACH(e, &table->entries, node)
493 if (!table_entry_keycmp(table, entry, e))
494 return e;
495
496 return NULL;
497}
498
499static void
500table_entries_free(struct table *table)
501{
502 for ( ; ; ) {
503 struct rte_swx_table_entry *entry;
504
505 entry = TAILQ_FIRST(&table->entries);
506 if (!entry)
507 break;
508
509 TAILQ_REMOVE(&table->entries, entry, node);
510 table_entry_free(entry);
511 }
512}
513
514static struct rte_swx_table_entry *
515table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
516{
517 struct rte_swx_table_entry *e;
518
519 TAILQ_FOREACH(e, &table->pending_add, node)
520 if (!table_entry_keycmp(table, entry, e))
521 return e;
522
523 return NULL;
524}
525
526static void
527table_pending_add_admit(struct table *table)
528{
529 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
530}
531
532static void
533table_pending_add_free(struct table *table)
534{
535 for ( ; ; ) {
536 struct rte_swx_table_entry *entry;
537
538 entry = TAILQ_FIRST(&table->pending_add);
539 if (!entry)
540 break;
541
542 TAILQ_REMOVE(&table->pending_add, entry, node);
543 table_entry_free(entry);
544 }
545}
546
547static struct rte_swx_table_entry *
548table_pending_modify0_find(struct table *table,
549 struct rte_swx_table_entry *entry)
550{
551 struct rte_swx_table_entry *e;
552
553 TAILQ_FOREACH(e, &table->pending_modify0, node)
554 if (!table_entry_keycmp(table, entry, e))
555 return e;
556
557 return NULL;
558}
559
560static void
561table_pending_modify0_admit(struct table *table)
562{
563 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
564}
565
566static void
567table_pending_modify0_free(struct table *table)
568{
569 for ( ; ; ) {
570 struct rte_swx_table_entry *entry;
571
572 entry = TAILQ_FIRST(&table->pending_modify0);
573 if (!entry)
574 break;
575
576 TAILQ_REMOVE(&table->pending_modify0, entry, node);
577 table_entry_free(entry);
578 }
579}
580
581static struct rte_swx_table_entry *
582table_pending_modify1_find(struct table *table,
583 struct rte_swx_table_entry *entry)
584{
585 struct rte_swx_table_entry *e;
586
587 TAILQ_FOREACH(e, &table->pending_modify1, node)
588 if (!table_entry_keycmp(table, entry, e))
589 return e;
590
591 return NULL;
592}
593
594static void
595table_pending_modify1_admit(struct table *table)
596{
597 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
598}
599
600static void
601table_pending_modify1_free(struct table *table)
602{
603 for ( ; ; ) {
604 struct rte_swx_table_entry *entry;
605
606 entry = TAILQ_FIRST(&table->pending_modify1);
607 if (!entry)
608 break;
609
610 TAILQ_REMOVE(&table->pending_modify1, entry, node);
611 table_entry_free(entry);
612 }
613}
614
615static struct rte_swx_table_entry *
616table_pending_delete_find(struct table *table,
617 struct rte_swx_table_entry *entry)
618{
619 struct rte_swx_table_entry *e;
620
621 TAILQ_FOREACH(e, &table->pending_delete, node)
622 if (!table_entry_keycmp(table, entry, e))
623 return e;
624
625 return NULL;
626}
627
628static void
629table_pending_delete_admit(struct table *table)
630{
631 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
632}
633
634static void
635table_pending_delete_free(struct table *table)
636{
637 for ( ; ; ) {
638 struct rte_swx_table_entry *entry;
639
640 entry = TAILQ_FIRST(&table->pending_delete);
641 if (!entry)
642 break;
643
644 TAILQ_REMOVE(&table->pending_delete, entry, node);
645 table_entry_free(entry);
646 }
647}
648
649static void
650table_pending_default_free(struct table *table)
651{
652 if (!table->pending_default)
653 return;
654
655 free(table->pending_default->action_data);
656 free(table->pending_default);
657 table->pending_default = NULL;
658}
659
660static int
661table_is_update_pending(struct table *table, int consider_pending_default)
662{
663 struct rte_swx_table_entry *e;
664 uint32_t n = 0;
665
666
667 TAILQ_FOREACH(e, &table->pending_add, node)
668 n++;
669
670
671 TAILQ_FOREACH(e, &table->pending_modify1, node)
672 n++;
673
674
675 TAILQ_FOREACH(e, &table->pending_delete, node)
676 n++;
677
678
679 if (consider_pending_default && table->pending_default)
680 n++;
681
682 return n;
683}
684
685static void
686table_free(struct rte_swx_ctl_pipeline *ctl)
687{
688 uint32_t i;
689
690 if (!ctl->tables)
691 return;
692
693 for (i = 0; i < ctl->info.n_tables; i++) {
694 struct table *table = &ctl->tables[i];
695
696 free(table->mf);
697 free(table->actions);
698 free(table->params.key_mask0);
699
700 table_entries_free(table);
701 table_pending_add_free(table);
702 table_pending_modify0_free(table);
703 table_pending_modify1_free(table);
704 table_pending_delete_free(table);
705 table_pending_default_free(table);
706 }
707
708 free(ctl->tables);
709 ctl->tables = NULL;
710}
711
712static void
713table_state_free(struct rte_swx_ctl_pipeline *ctl)
714{
715 uint32_t i;
716
717 if (!ctl->ts_next)
718 return;
719
720
721 for (i = 0; i < ctl->info.n_tables; i++) {
722 struct table *table = &ctl->tables[i];
723 struct rte_swx_table_state *ts = &ctl->ts_next[i];
724
725
726 free(ts->default_action_data);
727
728
729 if (!table->is_stub && table->ops.free && ts->obj)
730 table->ops.free(ts->obj);
731 }
732
733 free(ctl->ts_next);
734 ctl->ts_next = NULL;
735}
736
737static int
738table_state_create(struct rte_swx_ctl_pipeline *ctl)
739{
740 int status = 0;
741 uint32_t i;
742
743 ctl->ts_next = calloc(ctl->info.n_tables,
744 sizeof(struct rte_swx_table_state));
745 if (!ctl->ts_next) {
746 status = -ENOMEM;
747 goto error;
748 }
749
750 for (i = 0; i < ctl->info.n_tables; i++) {
751 struct table *table = &ctl->tables[i];
752 struct rte_swx_table_state *ts = &ctl->ts[i];
753 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
754
755
756 if (!table->is_stub && table->ops.add) {
757 ts_next->obj = table->ops.create(&table->params,
758 &table->entries,
759 table->info.args,
760 ctl->numa_node);
761 if (!ts_next->obj) {
762 status = -ENODEV;
763 goto error;
764 }
765 }
766
767 if (!table->is_stub && !table->ops.add)
768 ts_next->obj = ts->obj;
769
770
771 ts_next->default_action_data =
772 malloc(table->params.action_data_size);
773 if (!ts_next->default_action_data) {
774 status = -ENOMEM;
775 goto error;
776 }
777
778 memcpy(ts_next->default_action_data,
779 ts->default_action_data,
780 table->params.action_data_size);
781
782 ts_next->default_action_id = ts->default_action_id;
783 }
784
785 return 0;
786
787error:
788 table_state_free(ctl);
789 return status;
790}
791
792void
793rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
794{
795 if (!ctl)
796 return;
797
798 action_free(ctl);
799
800 table_state_free(ctl);
801
802 table_free(ctl);
803
804 free(ctl);
805}
806
807struct rte_swx_ctl_pipeline *
808rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
809{
810 struct rte_swx_ctl_pipeline *ctl = NULL;
811 uint32_t i;
812 int status;
813
814 if (!p)
815 goto error;
816
817 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
818 if (!ctl)
819 goto error;
820
821
822 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
823 if (status)
824 goto error;
825
826
827 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
828 if (status)
829 goto error;
830
831
832 ctl->p = p;
833
834
835 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
836 if (!ctl->actions)
837 goto error;
838
839 for (i = 0; i < ctl->info.n_actions; i++) {
840 struct action *a = &ctl->actions[i];
841 uint32_t j;
842
843
844 status = rte_swx_ctl_action_info_get(p, i, &a->info);
845 if (status)
846 goto error;
847
848
849 a->args = calloc(a->info.n_args,
850 sizeof(struct rte_swx_ctl_action_arg_info));
851 if (!a->args)
852 goto error;
853
854 for (j = 0; j < a->info.n_args; j++) {
855 status = rte_swx_ctl_action_arg_info_get(p,
856 i,
857 j,
858 &a->args[j]);
859 if (status)
860 goto error;
861 }
862
863
864 for (j = 0; j < a->info.n_args; j++) {
865 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
866
867 a->data_size += info->n_bits;
868 }
869
870 a->data_size = (a->data_size + 7) / 8;
871 }
872
873
874 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
875 if (!ctl->tables)
876 goto error;
877
878 for (i = 0; i < ctl->info.n_tables; i++) {
879 struct table *t = &ctl->tables[i];
880
881 TAILQ_INIT(&t->entries);
882 TAILQ_INIT(&t->pending_add);
883 TAILQ_INIT(&t->pending_modify0);
884 TAILQ_INIT(&t->pending_modify1);
885 TAILQ_INIT(&t->pending_delete);
886 }
887
888 for (i = 0; i < ctl->info.n_tables; i++) {
889 struct table *t = &ctl->tables[i];
890 uint32_t j;
891
892
893 status = rte_swx_ctl_table_info_get(p, i, &t->info);
894 if (status)
895 goto error;
896
897
898 t->mf = calloc(t->info.n_match_fields,
899 sizeof(struct rte_swx_ctl_table_match_field_info));
900 if (!t->mf)
901 goto error;
902
903 for (j = 0; j < t->info.n_match_fields; j++) {
904 status = rte_swx_ctl_table_match_field_info_get(p,
905 i,
906 j,
907 &t->mf[j]);
908 if (status)
909 goto error;
910 }
911
912
913 t->actions = calloc(t->info.n_actions,
914 sizeof(struct rte_swx_ctl_table_action_info));
915 if (!t->actions)
916 goto error;
917
918 for (j = 0; j < t->info.n_actions; j++) {
919 status = rte_swx_ctl_table_action_info_get(p,
920 i,
921 j,
922 &t->actions[j]);
923 if (status ||
924 t->actions[j].action_id >= ctl->info.n_actions)
925 goto error;
926 }
927
928
929 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
930 if (status)
931 goto error;
932
933 if ((t->is_stub && t->info.n_match_fields) ||
934 (!t->is_stub && !t->info.n_match_fields))
935 goto error;
936
937
938 status = table_params_get(ctl, i);
939 if (status)
940 goto error;
941 }
942
943
944 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
945 if (status)
946 goto error;
947
948
949 status = table_state_create(ctl);
950 if (status)
951 goto error;
952
953 return ctl;
954
955error:
956 rte_swx_ctl_pipeline_free(ctl);
957 return NULL;
958}
959
960int
961rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
962 const char *table_name,
963 struct rte_swx_table_entry *entry)
964{
965 struct table *table;
966 struct rte_swx_table_entry *new_entry, *existing_entry;
967 uint32_t table_id;
968
969 CHECK(ctl, EINVAL);
970 CHECK(table_name && table_name[0], EINVAL);
971
972 table = table_find(ctl, table_name);
973 CHECK(table, EINVAL);
974 table_id = table - ctl->tables;
975
976 CHECK(entry, EINVAL);
977 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
978
979 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
980 CHECK(new_entry, ENOMEM);
981
982
983
984
985
986
987 existing_entry = table_entries_find(table, entry);
988 if (existing_entry) {
989 TAILQ_INSERT_TAIL(&table->pending_modify1,
990 new_entry,
991 node);
992
993 TAILQ_REMOVE(&table->entries,
994 existing_entry,
995 node);
996
997 TAILQ_INSERT_TAIL(&table->pending_modify0,
998 existing_entry,
999 node);
1000
1001 return 0;
1002 }
1003
1004
1005
1006
1007
1008 existing_entry = table_pending_add_find(table, entry);
1009 if (existing_entry) {
1010 TAILQ_INSERT_AFTER(&table->pending_add,
1011 existing_entry,
1012 new_entry,
1013 node);
1014
1015 TAILQ_REMOVE(&table->pending_add,
1016 existing_entry,
1017 node);
1018
1019 table_entry_free(existing_entry);
1020
1021 return 0;
1022 }
1023
1024
1025
1026
1027
1028 existing_entry = table_pending_modify1_find(table, entry);
1029 if (existing_entry) {
1030 TAILQ_INSERT_AFTER(&table->pending_modify1,
1031 existing_entry,
1032 new_entry,
1033 node);
1034
1035 TAILQ_REMOVE(&table->pending_modify1,
1036 existing_entry,
1037 node);
1038
1039 table_entry_free(existing_entry);
1040
1041 return 0;
1042 }
1043
1044
1045
1046
1047
1048
1049 existing_entry = table_pending_delete_find(table, entry);
1050 if (existing_entry) {
1051 TAILQ_INSERT_TAIL(&table->pending_modify1,
1052 new_entry,
1053 node);
1054
1055 TAILQ_REMOVE(&table->pending_delete,
1056 existing_entry,
1057 node);
1058
1059 TAILQ_INSERT_TAIL(&table->pending_modify0,
1060 existing_entry,
1061 node);
1062
1063 return 0;
1064 }
1065
1066
1067
1068
1069 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1070
1071 return 0;
1072}
1073
1074int
1075rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1076 const char *table_name,
1077 struct rte_swx_table_entry *entry)
1078{
1079 struct table *table;
1080 struct rte_swx_table_entry *existing_entry;
1081 uint32_t table_id;
1082
1083 CHECK(ctl, EINVAL);
1084
1085 CHECK(table_name && table_name[0], EINVAL);
1086 table = table_find(ctl, table_name);
1087 CHECK(table, EINVAL);
1088 table_id = table - ctl->tables;
1089
1090 CHECK(entry, EINVAL);
1091 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1092
1093
1094
1095
1096
1097 existing_entry = table_entries_find(table, entry);
1098 if (existing_entry) {
1099 TAILQ_REMOVE(&table->entries,
1100 existing_entry,
1101 node);
1102
1103 TAILQ_INSERT_TAIL(&table->pending_delete,
1104 existing_entry,
1105 node);
1106
1107 return 0;
1108 }
1109
1110
1111
1112
1113 existing_entry = table_pending_add_find(table, entry);
1114 if (existing_entry) {
1115 TAILQ_REMOVE(&table->pending_add,
1116 existing_entry,
1117 node);
1118
1119 table_entry_free(existing_entry);
1120 }
1121
1122
1123
1124
1125
1126
1127 existing_entry = table_pending_modify1_find(table, entry);
1128 if (existing_entry) {
1129 struct rte_swx_table_entry *real_existing_entry;
1130
1131 TAILQ_REMOVE(&table->pending_modify1,
1132 existing_entry,
1133 node);
1134
1135 table_entry_free(existing_entry);
1136
1137 real_existing_entry = table_pending_modify0_find(table, entry);
1138 CHECK(real_existing_entry, EINVAL);
1139
1140 TAILQ_REMOVE(&table->pending_modify0,
1141 real_existing_entry,
1142 node);
1143
1144 TAILQ_INSERT_TAIL(&table->pending_delete,
1145 real_existing_entry,
1146 node);
1147
1148 return 0;
1149 }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 return 0;
1162}
1163
1164int
1165rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1166 const char *table_name,
1167 struct rte_swx_table_entry *entry)
1168{
1169 struct table *table;
1170 struct rte_swx_table_entry *new_entry;
1171 uint32_t table_id;
1172
1173 CHECK(ctl, EINVAL);
1174
1175 CHECK(table_name && table_name[0], EINVAL);
1176 table = table_find(ctl, table_name);
1177 CHECK(table, EINVAL);
1178 table_id = table - ctl->tables;
1179 CHECK(!table->info.default_action_is_const, EINVAL);
1180
1181 CHECK(entry, EINVAL);
1182 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1183
1184 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1185 CHECK(new_entry, ENOMEM);
1186
1187 table_pending_default_free(table);
1188
1189 table->pending_default = new_entry;
1190 return 0;
1191}
1192
1193
1194static void
1195table_entry_list_free(struct rte_swx_table_entry_list *list)
1196{
1197 for ( ; ; ) {
1198 struct rte_swx_table_entry *entry;
1199
1200 entry = TAILQ_FIRST(list);
1201 if (!entry)
1202 break;
1203
1204 TAILQ_REMOVE(list, entry, node);
1205 table_entry_free(entry);
1206 }
1207}
1208
1209static int
1210table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1211 uint32_t table_id,
1212 struct rte_swx_table_entry_list *dst,
1213 struct rte_swx_table_entry_list *src)
1214{
1215 struct rte_swx_table_entry *src_entry;
1216
1217 TAILQ_FOREACH(src_entry, src, node) {
1218 struct rte_swx_table_entry *dst_entry;
1219
1220 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1221 if (!dst_entry)
1222 goto error;
1223
1224 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1225 }
1226
1227 return 0;
1228
1229error:
1230 table_entry_list_free(dst);
1231 return -ENOMEM;
1232}
1233
1234
1235
1236
1237static int
1238table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1239 uint32_t table_id,
1240 uint32_t after_swap)
1241{
1242 struct table *table = &ctl->tables[table_id];
1243 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1244 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1245
1246 if (table->is_stub || !table_is_update_pending(table, 0))
1247 return 0;
1248
1249
1250
1251
1252 if (table->ops.add) {
1253
1254 table->n_add = 0;
1255 table->n_modify = 0;
1256 table->n_delete = 0;
1257
1258
1259 struct rte_swx_table_entry *entry;
1260
1261 TAILQ_FOREACH(entry, &table->pending_add, node) {
1262 int status;
1263
1264 status = table->ops.add(ts_next->obj, entry);
1265 if (status)
1266 return status;
1267
1268 table->n_add++;
1269 }
1270
1271
1272 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1273 int status;
1274
1275 status = table->ops.add(ts_next->obj, entry);
1276 if (status)
1277 return status;
1278
1279 table->n_modify++;
1280 }
1281
1282
1283 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1284 int status;
1285
1286 status = table->ops.del(ts_next->obj, entry);
1287 if (status)
1288 return status;
1289
1290 table->n_delete++;
1291 }
1292
1293 return 0;
1294 }
1295
1296
1297
1298
1299 if (!after_swap) {
1300 struct rte_swx_table_entry_list list;
1301 int status;
1302
1303
1304 TAILQ_INIT(&list);
1305
1306 status = table_entry_list_duplicate(ctl,
1307 table_id,
1308 &list,
1309 &table->entries);
1310 if (status)
1311 goto error;
1312
1313 status = table_entry_list_duplicate(ctl,
1314 table_id,
1315 &list,
1316 &table->pending_add);
1317 if (status)
1318 goto error;
1319
1320 status = table_entry_list_duplicate(ctl,
1321 table_id,
1322 &list,
1323 &table->pending_modify1);
1324 if (status)
1325 goto error;
1326
1327
1328 ts_next->obj = table->ops.create(&table->params,
1329 &list,
1330 table->info.args,
1331 ctl->numa_node);
1332 if (!ts_next->obj) {
1333 status = -ENODEV;
1334 goto error;
1335 }
1336
1337 table_entry_list_free(&list);
1338
1339 return 0;
1340
1341error:
1342 table_entry_list_free(&list);
1343 return status;
1344 }
1345
1346
1347 if (ts_next->obj && table->ops.free)
1348 table->ops.free(ts_next->obj);
1349
1350
1351 ts_next->obj = ts->obj;
1352
1353 return 0;
1354}
1355
1356
1357
1358
1359
1360static void
1361table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1362{
1363 struct table *table = &ctl->tables[table_id];
1364 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1365 struct action *a;
1366 uint8_t *action_data;
1367 uint64_t action_id;
1368
1369
1370 if (!table->pending_default)
1371 return;
1372
1373 action_id = table->pending_default->action_id;
1374 action_data = table->pending_default->action_data;
1375 a = &ctl->actions[action_id];
1376
1377 memcpy(ts_next->default_action_data,
1378 action_data,
1379 a->data_size);
1380
1381 ts_next->default_action_id = action_id;
1382}
1383
1384
1385
1386
1387
1388static void
1389table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1390{
1391 struct table *table = &ctl->tables[table_id];
1392
1393
1394
1395
1396 table_pending_add_admit(table);
1397
1398
1399
1400
1401
1402 table_pending_modify1_admit(table);
1403 table_pending_modify0_free(table);
1404
1405
1406
1407
1408 table_pending_delete_free(table);
1409
1410
1411 table_pending_default_free(table);
1412}
1413
1414
1415
1416
1417
1418
1419static void
1420table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1421{
1422 struct table *table = &ctl->tables[table_id];
1423 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1424
1425 if (table->is_stub || !table_is_update_pending(table, 0))
1426 return;
1427
1428 if (table->ops.add) {
1429 struct rte_swx_table_entry *entry;
1430
1431
1432 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1433 if (!table->n_delete)
1434 break;
1435
1436 table->ops.add(ts_next->obj, entry);
1437 table->n_delete--;
1438 }
1439
1440
1441
1442
1443 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1444 if (!table->n_modify)
1445 break;
1446
1447 table->ops.add(ts_next->obj, entry);
1448 table->n_modify--;
1449 }
1450
1451
1452 TAILQ_FOREACH(entry, &table->pending_add, node) {
1453 if (!table->n_add)
1454 break;
1455
1456 table->ops.del(ts_next->obj, entry);
1457 table->n_add--;
1458 }
1459 } else {
1460 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1461
1462
1463 if (ts_next->obj && table->ops.free)
1464 table->ops.free(ts_next->obj);
1465
1466
1467 ts_next->obj = ts->obj;
1468 }
1469}
1470
1471
1472
1473
1474static void
1475table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1476{
1477 struct table *table = &ctl->tables[table_id];
1478
1479
1480
1481
1482 table_pending_add_free(table);
1483
1484
1485
1486
1487
1488 table_pending_modify1_free(table);
1489 table_pending_modify0_admit(table);
1490
1491
1492
1493
1494 table_pending_delete_admit(table);
1495
1496
1497
1498
1499 table_pending_default_free(table);
1500}
1501
1502int
1503rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1504{
1505 struct rte_swx_table_state *ts;
1506 int status = 0;
1507 uint32_t i;
1508
1509 CHECK(ctl, EINVAL);
1510
1511
1512
1513
1514 for (i = 0; i < ctl->info.n_tables; i++) {
1515 status = table_rollfwd0(ctl, i, 0);
1516 if (status)
1517 goto rollback;
1518 }
1519
1520 for (i = 0; i < ctl->info.n_tables; i++)
1521 table_rollfwd1(ctl, i);
1522
1523
1524
1525
1526 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1527 usleep(100);
1528 ts = ctl->ts;
1529 ctl->ts = ctl->ts_next;
1530 ctl->ts_next = ts;
1531
1532
1533
1534 for (i = 0; i < ctl->info.n_tables; i++) {
1535 table_rollfwd0(ctl, i, 1);
1536 table_rollfwd1(ctl, i);
1537 table_rollfwd2(ctl, i);
1538 }
1539
1540 return 0;
1541
1542rollback:
1543 for (i = 0; i < ctl->info.n_tables; i++) {
1544 table_rollback(ctl, i);
1545 if (abort_on_fail)
1546 table_abort(ctl, i);
1547 }
1548
1549 return status;
1550}
1551
1552void
1553rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1554{
1555 uint32_t i;
1556
1557 if (!ctl)
1558 return;
1559
1560 for (i = 0; i < ctl->info.n_tables; i++)
1561 table_abort(ctl, i);
1562}
1563
1564static int
1565token_is_comment(const char *token)
1566{
1567 if ((token[0] == '#') ||
1568 (token[0] == ';') ||
1569 ((token[0] == '/') && (token[1] == '/')))
1570 return 1;
1571
1572 return 0;
1573}
1574
1575#define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1576
1577struct rte_swx_table_entry *
1578rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1579 const char *table_name,
1580 const char *string,
1581 int *is_blank_or_comment)
1582{
1583 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1584 struct table *table;
1585 struct action *action;
1586 struct rte_swx_table_entry *entry = NULL;
1587 char *s0 = NULL, *s;
1588 uint32_t n_tokens = 0, arg_offset = 0, i;
1589 int blank_or_comment = 0;
1590
1591
1592 if (!ctl)
1593 goto error;
1594
1595 if (!table_name || !table_name[0])
1596 goto error;
1597
1598 table = table_find(ctl, table_name);
1599 if (!table)
1600 goto error;
1601
1602 if (!string || !string[0])
1603 goto error;
1604
1605
1606 s0 = strdup(string);
1607 if (!s0)
1608 goto error;
1609
1610 entry = table_entry_alloc(table);
1611 if (!entry)
1612 goto error;
1613
1614
1615 for (s = s0; ; ) {
1616 char *token;
1617
1618 token = strtok_r(s, " \f\n\r\t\v", &s);
1619 if (!token || token_is_comment(token))
1620 break;
1621
1622 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1623 goto error;
1624
1625 token_array[n_tokens] = token;
1626 n_tokens++;
1627 }
1628
1629 if (!n_tokens) {
1630 blank_or_comment = 1;
1631 goto error;
1632 }
1633
1634 tokens = token_array;
1635
1636
1637
1638
1639 if (n_tokens && strcmp(tokens[0], "match"))
1640 goto action;
1641
1642 if (n_tokens < 1 + table->info.n_match_fields)
1643 goto error;
1644
1645 for (i = 0; i < table->info.n_match_fields; i++) {
1646 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1647 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1648 uint64_t val, mask = UINT64_MAX;
1649 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
1650
1651
1652
1653
1654 mf_mask = strchr(mf_val, '/');
1655 if (mf_mask) {
1656 *mf_mask = 0;
1657 mf_mask++;
1658
1659
1660 mask = strtoull(mf_mask, &mf_mask, 0);
1661 if (mf_mask[0])
1662 goto error;
1663
1664
1665 if (mf->is_header)
1666 mask = field_hton(mask, mf->n_bits);
1667 }
1668
1669
1670 if (entry->key_mask)
1671 memcpy(&entry->key_mask[offset],
1672 (uint8_t *)&mask,
1673 mf->n_bits / 8);
1674
1675
1676
1677
1678
1679 val = strtoull(mf_val, &mf_val, 0);
1680 if (mf_val[0])
1681 goto error;
1682
1683
1684 if (mf->is_header)
1685 val = field_hton(val, mf->n_bits);
1686
1687
1688 memcpy(&entry->key[offset],
1689 (uint8_t *)&val,
1690 mf->n_bits / 8);
1691 }
1692
1693 tokens += 1 + table->info.n_match_fields;
1694 n_tokens -= 1 + table->info.n_match_fields;
1695
1696
1697
1698
1699 if (n_tokens && !strcmp(tokens[0], "priority")) {
1700 char *priority = tokens[1];
1701 uint32_t val;
1702
1703 if (n_tokens < 2)
1704 goto error;
1705
1706
1707 val = strtoul(priority, &priority, 0);
1708 if (priority[0])
1709 goto error;
1710
1711
1712 entry->key_priority = val;
1713
1714 tokens += 2;
1715 n_tokens -= 2;
1716 }
1717
1718
1719
1720
1721action:
1722 if (n_tokens && strcmp(tokens[0], "action"))
1723 goto other;
1724
1725 if (n_tokens < 2)
1726 goto error;
1727
1728 action = action_find(ctl, tokens[1]);
1729 if (!action)
1730 goto error;
1731
1732 if (n_tokens < 2 + action->info.n_args * 2)
1733 goto error;
1734
1735
1736 entry->action_id = action - ctl->actions;
1737
1738
1739 for (i = 0; i < action->info.n_args; i++) {
1740 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1741 char *arg_name, *arg_val;
1742 uint64_t val;
1743
1744 arg_name = tokens[2 + i * 2];
1745 arg_val = tokens[2 + i * 2 + 1];
1746
1747 if (strcmp(arg_name, arg->name))
1748 goto error;
1749
1750 val = strtoull(arg_val, &arg_val, 0);
1751 if (arg_val[0])
1752 goto error;
1753
1754
1755 if (arg->is_network_byte_order)
1756 val = field_hton(val, arg->n_bits);
1757
1758
1759 memcpy(&entry->action_data[arg_offset],
1760 (uint8_t *)&val,
1761 arg->n_bits / 8);
1762
1763 arg_offset += arg->n_bits / 8;
1764 }
1765
1766 tokens += 2 + action->info.n_args * 2;
1767 n_tokens -= 2 + action->info.n_args * 2;
1768
1769other:
1770 if (n_tokens)
1771 goto error;
1772
1773 free(s0);
1774 return entry;
1775
1776error:
1777 table_entry_free(entry);
1778 free(s0);
1779 if (is_blank_or_comment)
1780 *is_blank_or_comment = blank_or_comment;
1781 return NULL;
1782}
1783
1784static void
1785table_entry_printf(FILE *f,
1786 struct rte_swx_ctl_pipeline *ctl,
1787 struct table *table,
1788 struct rte_swx_table_entry *entry)
1789{
1790 struct action *action = &ctl->actions[entry->action_id];
1791 uint32_t i;
1792
1793 fprintf(f, "match ");
1794 for (i = 0; i < table->params.key_size; i++)
1795 fprintf(f, "%02x", entry->key[i]);
1796
1797 if (entry->key_mask) {
1798 fprintf(f, "/");
1799 for (i = 0; i < table->params.key_size; i++)
1800 fprintf(f, "%02x", entry->key_mask[i]);
1801 }
1802
1803 fprintf(f, " priority %u", entry->key_priority);
1804
1805 fprintf(f, " action %s ", action->info.name);
1806 for (i = 0; i < action->data_size; i++)
1807 fprintf(f, "%02x", entry->action_data[i]);
1808
1809 fprintf(f, "\n");
1810}
1811
1812int
1813rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1814 struct rte_swx_ctl_pipeline *ctl,
1815 const char *table_name)
1816{
1817 struct table *table;
1818 struct rte_swx_table_entry *entry;
1819 uint32_t n_entries = 0, i;
1820
1821 if (!f || !ctl || !table_name || !table_name[0])
1822 return -EINVAL;
1823
1824 table = table_find(ctl, table_name);
1825 if (!table)
1826 return -EINVAL;
1827
1828
1829 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1830 table->info.name,
1831 table->params.key_size,
1832 table->params.key_offset);
1833
1834 for (i = 0; i < table->params.key_size; i++)
1835 fprintf(f, "%02x", table->params.key_mask0[i]);
1836
1837 fprintf(f, "], action data size %u bytes\n",
1838 table->params.action_data_size);
1839
1840
1841 TAILQ_FOREACH(entry, &table->entries, node) {
1842 table_entry_printf(f, ctl, table, entry);
1843 n_entries++;
1844 }
1845
1846 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1847 table_entry_printf(f, ctl, table, entry);
1848 n_entries++;
1849 }
1850
1851 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1852 table_entry_printf(f, ctl, table, entry);
1853 n_entries++;
1854 }
1855
1856 fprintf(f, "# Table %s currently has %u entries.\n",
1857 table_name,
1858 n_entries);
1859 return 0;
1860}
1861