ethdev: bring in async queue-based flow rules operations
[dpdk.git] / lib / pipeline / rte_swx_ctl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
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)                                             \
18 do {                                                                           \
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
34 struct 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
40 struct table {
41         struct rte_swx_ctl_table_info info;
42         struct rte_swx_ctl_table_match_field_info *mf;
43
44         /* Match field with the smallest offset. */
45         struct rte_swx_ctl_table_match_field_info *mf_first;
46
47         /* Match field with the biggest offset. */
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         /* Set of "stable" keys: these keys are currently part of the table;
55          * these keys will be preserved with no action data changes after the
56          * next commit.
57          */
58         struct rte_swx_table_entry_list entries;
59
60         /* Set of new keys: these keys are currently NOT part of the table;
61          * these keys will be added to the table on the next commit, if
62          * the commit operation is successful.
63          */
64         struct rte_swx_table_entry_list pending_add;
65
66         /* Set of keys to be modified: these keys are currently part of the
67          * table; these keys are still going to be part of the table after the
68          * next commit, but their action data will be modified if the commit
69          * operation is successful. The modify0 list contains the keys with the
70          * current action data, the modify1 list contains the keys with the
71          * modified action data.
72          */
73         struct rte_swx_table_entry_list pending_modify0;
74         struct rte_swx_table_entry_list pending_modify1;
75
76         /* Set of keys to be deleted: these keys are currently part of the
77          * table; these keys are to be deleted from the table on the next
78          * commit, if the commit operation is successful.
79          */
80         struct rte_swx_table_entry_list pending_delete;
81
82         /* The pending default action: this is NOT the current default action;
83          * this will be the new default action after the next commit, if the
84          * next commit operation is successful.
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
94 struct selector {
95         /* Selector table info. */
96         struct rte_swx_ctl_selector_info info;
97
98         /* group_id field. */
99         struct rte_swx_ctl_table_match_field_info group_id_field;
100
101         /* selector fields. */
102         struct rte_swx_ctl_table_match_field_info *selector_fields;
103
104         /* member_id field. */
105         struct rte_swx_ctl_table_match_field_info member_id_field;
106
107         /* Current selector table. Array of info.n_groups_max elements.*/
108         struct rte_swx_table_selector_group **groups;
109
110         /* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
111          */
112         struct rte_swx_table_selector_group **pending_groups;
113
114         /* Valid flag per group. Array of n_groups_max elements. */
115         int *groups_added;
116
117         /* Pending delete flag per group. Group deletion is subject to the next commit. Array of
118          * info.n_groups_max elements.
119          */
120         int *groups_pending_delete;
121
122         /* Params. */
123         struct rte_swx_table_selector_params params;
124 };
125
126 struct 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         /* The pending default action: this is NOT the current default action;
133          * this will be the new default action after the next commit, if the
134          * next commit operation is successful.
135          */
136         struct rte_swx_table_entry *pending_default;
137 };
138
139 struct 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
151 static struct action *
152 action_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
166 static void
167 action_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
184 static struct table *
185 table_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
199 static int
200 table_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                 /* Find first (smallest offset) and last (biggest offset) match fields. */
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                 /* match_type. */
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                 /* key_offset. */
237                 key_offset = first->offset / 8;
238
239                 /* key_size. */
240                 key_size = (last->offset + last->n_bits - first->offset) / 8;
241
242                 /* key_mask. */
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         /* action_data_size. */
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         /* Fill in. */
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
281 static void
282 table_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
293 static struct rte_swx_table_entry *
294 table_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         /* key, key_mask. */
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         /* action_data. */
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
324 error:
325         table_entry_free(entry);
326         return NULL;
327 }
328
329 static int
330 table_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
349 static int
350 table_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                 /* key. */
363                 CHECK(entry->key, EINVAL);
364
365                 /* key_mask. */
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                 /* action_id. */
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                 /* action_data. */
389                 a = &ctl->actions[entry->action_id];
390                 CHECK(!(a->data_size && !entry->action_data), EINVAL);
391
392                 /* When both key_check and data_check are true, we are interested in both the entry
393                  * key and data, which means the operation is _regular_ table entry add.
394                  */
395                 if (key_check && !tai->action_is_for_table_entries)
396                         return -EINVAL;
397
398                 /* When key_check is false while data_check is true, we are only interested in the
399                  * entry data, which means the operation is _default_ table entry add.
400                  */
401                 if (!key_check && !tai->action_is_for_default_entry)
402                         return -EINVAL;
403         }
404
405         return 0;
406 }
407
408 static struct rte_swx_table_entry *
409 table_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                 /* key. */
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                 /* key_signature. */
437                 new_entry->key_signature = entry->key_signature;
438
439                 /* key_mask. */
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                 /* key_priority. */
451                 new_entry->key_priority = entry->key_priority;
452         }
453
454         if (data_duplicate) {
455                 struct action *a;
456                 uint32_t i;
457
458                 /* action_id. */
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                 /* action_data. */
469                 a = &ctl->actions[entry->action_id];
470                 if (a->data_size && !entry->action_data)
471                         goto error;
472
473                 /* The table layer provisions a constant action data size per
474                  * entry, which should be the largest data size for all the
475                  * actions enabled for the current table, and attempts to copy
476                  * this many bytes each time a table entry is added, even if the
477                  * specific action requires less data or even no data at all,
478                  * hence we always have to allocate the max.
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
492 error:
493         table_entry_free(new_entry);
494         return NULL;
495 }
496
497 static int
498 table_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                 /* Mask comparison. */
518                 if ((km[0] & km0) != (km[1] & km0))
519                         return 1; /* Not equal. */
520
521                 /* Value comparison. */
522                 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
523                         return 1; /* Not equal. */
524         }
525
526         return 0; /* Equal. */
527 }
528
529 static struct rte_swx_table_entry *
530 table_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; /* Found. */
537
538         return NULL; /* Not found. */
539 }
540
541 static void
542 table_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
556 static struct rte_swx_table_entry *
557 table_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; /* Found. */
564
565         return NULL; /* Not found. */
566 }
567
568 static void
569 table_pending_add_admit(struct table *table)
570 {
571         TAILQ_CONCAT(&table->entries, &table->pending_add, node);
572 }
573
574 static void
575 table_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
589 static struct rte_swx_table_entry *
590 table_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; /* Found. */
598
599         return NULL; /* Not found. */
600 }
601
602 static void
603 table_pending_modify0_admit(struct table *table)
604 {
605         TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
606 }
607
608 static void
609 table_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
623 static struct rte_swx_table_entry *
624 table_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; /* Found. */
632
633         return NULL; /* Not found. */
634 }
635
636 static void
637 table_pending_modify1_admit(struct table *table)
638 {
639         TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
640 }
641
642 static void
643 table_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
657 static struct rte_swx_table_entry *
658 table_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; /* Found. */
666
667         return NULL; /* Not found. */
668 }
669
670 static void
671 table_pending_delete_admit(struct table *table)
672 {
673         TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
674 }
675
676 static void
677 table_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
691 static void
692 table_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
702 static int
703 table_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         /* Pending add. */
709         TAILQ_FOREACH(e, &table->pending_add, node)
710                 n++;
711
712         /* Pending modify. */
713         TAILQ_FOREACH(e, &table->pending_modify1, node)
714                 n++;
715
716         /* Pending delete. */
717         TAILQ_FOREACH(e, &table->pending_delete, node)
718                 n++;
719
720         /* Pending default. */
721         if (consider_pending_default && table->pending_default)
722                 n++;
723
724         return n;
725 }
726
727 static void
728 table_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
754 static void
755 selector_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
777 static void
778 selector_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
800 static int
801 selector_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
838 error:
839         selector_pending_group_members_free(s, group_id);
840         return -ENOMEM;
841 }
842
843 static void
844 selector_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                 /* selector_fields. */
856                 free(s->selector_fields);
857
858                 /* groups. */
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                 /* pending_groups. */
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                 /* groups_added. */
873                 free(s->groups_added);
874
875                 /* groups_pending_delete. */
876                 free(s->groups_pending_delete);
877
878                 /* params. */
879                 free(s->params.selector_mask);
880         }
881
882         free(ctl->selectors);
883         ctl->selectors = NULL;
884 }
885
886 static struct selector *
887 selector_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
901 static int
902 selector_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         /* Find first (smallest offset) and last (biggest offset) match fields. */
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         /* selector_offset. */
924         selector_offset = first->offset / 8;
925
926         /* selector_size. */
927         selector_size = (last->offset + last->n_bits - first->offset) / 8;
928
929         /* selector_mask. */
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         /* Fill in. */
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
957 static void
958 learner_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
969 static void
970 learner_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
990 static struct learner *
991 learner_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
1005 static uint32_t
1006 learner_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
1021 static void
1022 table_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         /* For each table, free its table state. */
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                 /* Default action data. */
1036                 free(ts->default_action_data);
1037
1038                 /* Table object. */
1039                 if (!table->is_stub && table->ops.free && ts->obj)
1040                         table->ops.free(ts->obj);
1041         }
1042
1043         /* For each selector table, free its table state. */
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                 /* Table object. */
1049                 if (ts->obj)
1050                         rte_swx_table_selector_free(ts->obj);
1051         }
1052
1053         /* For each learner table, free its table state. */
1054         learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1055         for (i = 0; i < ctl->info.n_learners; i++) {
1056                 struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1057
1058                 /* Default action data. */
1059                 free(ts->default_action_data);
1060         }
1061
1062         free(ctl->ts_next);
1063         ctl->ts_next = NULL;
1064 }
1065
1066 static int
1067 table_state_create(struct rte_swx_ctl_pipeline *ctl)
1068 {
1069         uint32_t table_base_index, selector_base_index, learner_base_index, i;
1070         int status = 0;
1071
1072         ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1073                               sizeof(struct rte_swx_table_state));
1074         if (!ctl->ts_next) {
1075                 status = -ENOMEM;
1076                 goto error;
1077         }
1078
1079         /* Tables. */
1080         table_base_index = 0;
1081         for (i = 0; i < ctl->info.n_tables; i++) {
1082                 struct table *table = &ctl->tables[i];
1083                 struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1084                 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1085
1086                 /* Table object. */
1087                 if (!table->is_stub && table->ops.add) {
1088                         ts_next->obj = table->ops.create(&table->params,
1089                                                          &table->entries,
1090                                                          table->info.args,
1091                                                          ctl->numa_node);
1092                         if (!ts_next->obj) {
1093                                 status = -ENODEV;
1094                                 goto error;
1095                         }
1096                 }
1097
1098                 if (!table->is_stub && !table->ops.add)
1099                         ts_next->obj = ts->obj;
1100
1101                 /* Default action data: duplicate from current table state. */
1102                 ts_next->default_action_data =
1103                         malloc(table->params.action_data_size);
1104                 if (!ts_next->default_action_data) {
1105                         status = -ENOMEM;
1106                         goto error;
1107                 }
1108
1109                 memcpy(ts_next->default_action_data,
1110                        ts->default_action_data,
1111                        table->params.action_data_size);
1112
1113                 ts_next->default_action_id = ts->default_action_id;
1114         }
1115
1116         /* Selector tables. */
1117         selector_base_index = ctl->info.n_tables;
1118         for (i = 0; i < ctl->info.n_selectors; i++) {
1119                 struct selector *s = &ctl->selectors[i];
1120                 struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1121
1122                 /* Table object. */
1123                 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1124                 if (!ts_next->obj) {
1125                         status = -ENODEV;
1126                         goto error;
1127                 }
1128         }
1129
1130         /* Learner tables. */
1131         learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1132         for (i = 0; i < ctl->info.n_learners; i++) {
1133                 struct learner *l = &ctl->learners[i];
1134                 struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1135                 struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1136
1137                 /* Table object: duplicate from the current table state. */
1138                 ts_next->obj = ts->obj;
1139
1140                 /* Default action data: duplicate from the current table state. */
1141                 ts_next->default_action_data = malloc(l->action_data_size);
1142                 if (!ts_next->default_action_data) {
1143                         status = -ENOMEM;
1144                         goto error;
1145                 }
1146
1147                 memcpy(ts_next->default_action_data,
1148                        ts->default_action_data,
1149                        l->action_data_size);
1150
1151                 ts_next->default_action_id = ts->default_action_id;
1152         }
1153
1154         return 0;
1155
1156 error:
1157         table_state_free(ctl);
1158         return status;
1159 }
1160
1161 void
1162 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1163 {
1164         if (!ctl)
1165                 return;
1166
1167         action_free(ctl);
1168
1169         table_state_free(ctl);
1170
1171         learner_free(ctl);
1172
1173         selector_free(ctl);
1174
1175         table_free(ctl);
1176
1177         free(ctl);
1178 }
1179
1180 struct rte_swx_ctl_pipeline *
1181 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1182 {
1183         struct rte_swx_ctl_pipeline *ctl = NULL;
1184         uint32_t i;
1185         int status;
1186
1187         if (!p)
1188                 goto error;
1189
1190         ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1191         if (!ctl)
1192                 goto error;
1193
1194         /* info. */
1195         status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1196         if (status)
1197                 goto error;
1198
1199         /* numa_node. */
1200         status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1201         if (status)
1202                 goto error;
1203
1204         /* p. */
1205         ctl->p = p;
1206
1207         /* actions. */
1208         ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1209         if (!ctl->actions)
1210                 goto error;
1211
1212         for (i = 0; i < ctl->info.n_actions; i++) {
1213                 struct action *a = &ctl->actions[i];
1214                 uint32_t j;
1215
1216                 /* info. */
1217                 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1218                 if (status)
1219                         goto error;
1220
1221                 /* args. */
1222                 a->args = calloc(a->info.n_args,
1223                                  sizeof(struct rte_swx_ctl_action_arg_info));
1224                 if (!a->args)
1225                         goto error;
1226
1227                 for (j = 0; j < a->info.n_args; j++) {
1228                         status = rte_swx_ctl_action_arg_info_get(p,
1229                                                                  i,
1230                                                                  j,
1231                                                                  &a->args[j]);
1232                         if (status)
1233                                 goto error;
1234                 }
1235
1236                 /* data_size. */
1237                 for (j = 0; j < a->info.n_args; j++) {
1238                         struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1239
1240                         a->data_size += info->n_bits;
1241                 }
1242
1243                 a->data_size = (a->data_size + 7) / 8;
1244         }
1245
1246         /* tables. */
1247         ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1248         if (!ctl->tables)
1249                 goto error;
1250
1251         for (i = 0; i < ctl->info.n_tables; i++) {
1252                 struct table *t = &ctl->tables[i];
1253
1254                 TAILQ_INIT(&t->entries);
1255                 TAILQ_INIT(&t->pending_add);
1256                 TAILQ_INIT(&t->pending_modify0);
1257                 TAILQ_INIT(&t->pending_modify1);
1258                 TAILQ_INIT(&t->pending_delete);
1259         }
1260
1261         for (i = 0; i < ctl->info.n_tables; i++) {
1262                 struct table *t = &ctl->tables[i];
1263                 uint32_t j;
1264
1265                 /* info. */
1266                 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1267                 if (status)
1268                         goto error;
1269
1270                 /* mf. */
1271                 t->mf = calloc(t->info.n_match_fields,
1272                         sizeof(struct rte_swx_ctl_table_match_field_info));
1273                 if (!t->mf)
1274                         goto error;
1275
1276                 for (j = 0; j < t->info.n_match_fields; j++) {
1277                         status = rte_swx_ctl_table_match_field_info_get(p,
1278                                 i,
1279                                 j,
1280                                 &t->mf[j]);
1281                         if (status)
1282                                 goto error;
1283                 }
1284
1285                 /* actions. */
1286                 t->actions = calloc(t->info.n_actions,
1287                         sizeof(struct rte_swx_ctl_table_action_info));
1288                 if (!t->actions)
1289                         goto error;
1290
1291                 for (j = 0; j < t->info.n_actions; j++) {
1292                         status = rte_swx_ctl_table_action_info_get(p,
1293                                 i,
1294                                 j,
1295                                 &t->actions[j]);
1296                         if (status ||
1297                             t->actions[j].action_id >= ctl->info.n_actions)
1298                                 goto error;
1299                 }
1300
1301                 /* ops, is_stub. */
1302                 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1303                 if (status)
1304                         goto error;
1305
1306                 if ((t->is_stub && t->info.n_match_fields) ||
1307                     (!t->is_stub && !t->info.n_match_fields))
1308                         goto error;
1309
1310                 /* params. */
1311                 status = table_params_get(ctl, i);
1312                 if (status)
1313                         goto error;
1314         }
1315
1316         /* selector tables. */
1317         ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1318         if (!ctl->selectors)
1319                 goto error;
1320
1321         for (i = 0; i < ctl->info.n_selectors; i++) {
1322                 struct selector *s = &ctl->selectors[i];
1323                 uint32_t j;
1324
1325                 /* info. */
1326                 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1327                 if (status)
1328                         goto error;
1329
1330                 /* group_id field. */
1331                 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1332                         i,
1333                         &s->group_id_field);
1334                 if (status)
1335                         goto error;
1336
1337                 /* selector fields. */
1338                 s->selector_fields = calloc(s->info.n_selector_fields,
1339                         sizeof(struct rte_swx_ctl_table_match_field_info));
1340                 if (!s->selector_fields)
1341                         goto error;
1342
1343                 for (j = 0; j < s->info.n_selector_fields; j++) {
1344                         status = rte_swx_ctl_selector_field_info_get(p,
1345                                 i,
1346                                 j,
1347                                 &s->selector_fields[j]);
1348                         if (status)
1349                                 goto error;
1350                 }
1351
1352                 /* member_id field. */
1353                 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1354                         i,
1355                         &s->member_id_field);
1356                 if (status)
1357                         goto error;
1358
1359                 /* groups. */
1360                 s->groups = calloc(s->info.n_groups_max,
1361                         sizeof(struct rte_swx_table_selector_group *));
1362                 if (!s->groups)
1363                         goto error;
1364
1365                 /* pending_groups. */
1366                 s->pending_groups = calloc(s->info.n_groups_max,
1367                         sizeof(struct rte_swx_table_selector_group *));
1368                 if (!s->pending_groups)
1369                         goto error;
1370
1371                 /* groups_added. */
1372                 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1373                 if (!s->groups_added)
1374                         goto error;
1375
1376                 /* groups_pending_delete. */
1377                 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1378                 if (!s->groups_pending_delete)
1379                         goto error;
1380
1381                 /* params. */
1382                 status = selector_params_get(ctl, i);
1383                 if (status)
1384                         goto error;
1385         }
1386
1387         /* learner tables. */
1388         ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1389         if (!ctl->learners)
1390                 goto error;
1391
1392         for (i = 0; i < ctl->info.n_learners; i++) {
1393                 struct learner *l = &ctl->learners[i];
1394                 uint32_t j;
1395
1396                 /* info. */
1397                 status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1398                 if (status)
1399                         goto error;
1400
1401                 /* mf. */
1402                 l->mf = calloc(l->info.n_match_fields,
1403                                sizeof(struct rte_swx_ctl_table_match_field_info));
1404                 if (!l->mf)
1405                         goto error;
1406
1407                 for (j = 0; j < l->info.n_match_fields; j++) {
1408                         status = rte_swx_ctl_learner_match_field_info_get(p,
1409                                 i,
1410                                 j,
1411                                 &l->mf[j]);
1412                         if (status)
1413                                 goto error;
1414                 }
1415
1416                 /* actions. */
1417                 l->actions = calloc(l->info.n_actions,
1418                         sizeof(struct rte_swx_ctl_table_action_info));
1419                 if (!l->actions)
1420                         goto error;
1421
1422                 for (j = 0; j < l->info.n_actions; j++) {
1423                         status = rte_swx_ctl_learner_action_info_get(p,
1424                                 i,
1425                                 j,
1426                                 &l->actions[j]);
1427                         if (status || l->actions[j].action_id >= ctl->info.n_actions)
1428                                 goto error;
1429                 }
1430
1431                 /* action_data_size. */
1432                 l->action_data_size = learner_action_data_size_get(ctl, l);
1433         }
1434
1435         /* ts. */
1436         status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1437         if (status)
1438                 goto error;
1439
1440         /* ts_next. */
1441         status = table_state_create(ctl);
1442         if (status)
1443                 goto error;
1444
1445         return ctl;
1446
1447 error:
1448         rte_swx_ctl_pipeline_free(ctl);
1449         return NULL;
1450 }
1451
1452 int
1453 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1454                                      const char *table_name,
1455                                      struct rte_swx_table_entry *entry)
1456 {
1457         struct table *table;
1458         struct rte_swx_table_entry *new_entry, *existing_entry;
1459         uint32_t table_id;
1460
1461         CHECK(ctl, EINVAL);
1462         CHECK(table_name && table_name[0], EINVAL);
1463
1464         table = table_find(ctl, table_name);
1465         CHECK(table, EINVAL);
1466         table_id = table - ctl->tables;
1467
1468         CHECK(entry, EINVAL);
1469         CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1470
1471         new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1472         CHECK(new_entry, ENOMEM);
1473
1474         /* The new entry is found in the table->entries list:
1475          * - Add the new entry to the table->pending_modify1 list;
1476          * - Move the existing entry from the table->entries list to the
1477          *   table->pending_modify0 list.
1478          */
1479         existing_entry = table_entries_find(table, entry);
1480         if (existing_entry) {
1481                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1482                                   new_entry,
1483                                   node);
1484
1485                 TAILQ_REMOVE(&table->entries,
1486                              existing_entry,
1487                              node);
1488
1489                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1490                                   existing_entry,
1491                                   node);
1492
1493                 return 0;
1494         }
1495
1496         /* The new entry is found in the table->pending_add list:
1497          * - Replace the entry in the table->pending_add list with the new entry
1498          *   (and free the replaced entry).
1499          */
1500         existing_entry = table_pending_add_find(table, entry);
1501         if (existing_entry) {
1502                 TAILQ_INSERT_AFTER(&table->pending_add,
1503                                    existing_entry,
1504                                    new_entry,
1505                                    node);
1506
1507                 TAILQ_REMOVE(&table->pending_add,
1508                              existing_entry,
1509                              node);
1510
1511                 table_entry_free(existing_entry);
1512
1513                 return 0;
1514         }
1515
1516         /* The new entry is found in the table->pending_modify1 list:
1517          * - Replace the entry in the table->pending_modify1 list with the new
1518          *   entry (and free the replaced entry).
1519          */
1520         existing_entry = table_pending_modify1_find(table, entry);
1521         if (existing_entry) {
1522                 TAILQ_INSERT_AFTER(&table->pending_modify1,
1523                                    existing_entry,
1524                                    new_entry,
1525                                    node);
1526
1527                 TAILQ_REMOVE(&table->pending_modify1,
1528                              existing_entry,
1529                              node);
1530
1531                 table_entry_free(existing_entry);
1532
1533                 return 0;
1534         }
1535
1536         /* The new entry is found in the table->pending_delete list:
1537          * - Add the new entry to the table->pending_modify1 list;
1538          * - Move the existing entry from the table->pending_delete list to the
1539          *   table->pending_modify0 list.
1540          */
1541         existing_entry = table_pending_delete_find(table, entry);
1542         if (existing_entry) {
1543                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1544                                   new_entry,
1545                                   node);
1546
1547                 TAILQ_REMOVE(&table->pending_delete,
1548                              existing_entry,
1549                              node);
1550
1551                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1552                                   existing_entry,
1553                                   node);
1554
1555                 return 0;
1556         }
1557
1558         /* The new entry is not found in any of the above lists:
1559          * - Add the new entry to the table->pending_add list.
1560          */
1561         TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1562
1563         return 0;
1564 }
1565
1566 int
1567 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1568                                         const char *table_name,
1569                                         struct rte_swx_table_entry *entry)
1570 {
1571         struct table *table;
1572         struct rte_swx_table_entry *existing_entry;
1573         uint32_t table_id;
1574
1575         CHECK(ctl, EINVAL);
1576
1577         CHECK(table_name && table_name[0], EINVAL);
1578         table = table_find(ctl, table_name);
1579         CHECK(table, EINVAL);
1580         table_id = table - ctl->tables;
1581
1582         CHECK(entry, EINVAL);
1583         CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1584
1585         /* The entry is found in the table->entries list:
1586          * - Move the existing entry from the table->entries list to to the
1587          *   table->pending_delete list.
1588          */
1589         existing_entry = table_entries_find(table, entry);
1590         if (existing_entry) {
1591                 TAILQ_REMOVE(&table->entries,
1592                              existing_entry,
1593                              node);
1594
1595                 TAILQ_INSERT_TAIL(&table->pending_delete,
1596                                   existing_entry,
1597                                   node);
1598
1599                 return 0;
1600         }
1601
1602         /* The entry is found in the table->pending_add list:
1603          * - Remove the entry from the table->pending_add list and free it.
1604          */
1605         existing_entry = table_pending_add_find(table, entry);
1606         if (existing_entry) {
1607                 TAILQ_REMOVE(&table->pending_add,
1608                              existing_entry,
1609                              node);
1610
1611                 table_entry_free(existing_entry);
1612         }
1613
1614         /* The entry is found in the table->pending_modify1 list:
1615          * - Free the entry in the table->pending_modify1 list;
1616          * - Move the existing entry from the table->pending_modify0 list to the
1617          *   table->pending_delete list.
1618          */
1619         existing_entry = table_pending_modify1_find(table, entry);
1620         if (existing_entry) {
1621                 struct rte_swx_table_entry *real_existing_entry;
1622
1623                 TAILQ_REMOVE(&table->pending_modify1,
1624                              existing_entry,
1625                              node);
1626
1627                 table_entry_free(existing_entry);
1628
1629                 real_existing_entry = table_pending_modify0_find(table, entry);
1630                 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1631
1632                 TAILQ_REMOVE(&table->pending_modify0,
1633                              real_existing_entry,
1634                              node);
1635
1636                 TAILQ_INSERT_TAIL(&table->pending_delete,
1637                                   real_existing_entry,
1638                                   node);
1639
1640                 return 0;
1641         }
1642
1643         /* The entry is found in the table->pending_delete list:
1644          * - Do nothing: the existing entry is already in the
1645          *   table->pending_delete list, i.e. already marked for delete, so
1646          *   simply keep it there as it is.
1647          */
1648
1649         /* The entry is not found in any of the above lists:
1650          * - Do nothing: no existing entry to delete.
1651          */
1652
1653         return 0;
1654 }
1655
1656 int
1657 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1658                                              const char *table_name,
1659                                              struct rte_swx_table_entry *entry)
1660 {
1661         struct table *table;
1662         struct rte_swx_table_entry *new_entry;
1663         uint32_t table_id;
1664
1665         CHECK(ctl, EINVAL);
1666
1667         CHECK(table_name && table_name[0], EINVAL);
1668         table = table_find(ctl, table_name);
1669         CHECK(table, EINVAL);
1670         table_id = table - ctl->tables;
1671         CHECK(!table->info.default_action_is_const, EINVAL);
1672
1673         CHECK(entry, EINVAL);
1674         CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1675
1676         new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1677         CHECK(new_entry, ENOMEM);
1678
1679         table_pending_default_free(table);
1680
1681         table->pending_default = new_entry;
1682         return 0;
1683 }
1684
1685
1686 static void
1687 table_entry_list_free(struct rte_swx_table_entry_list *list)
1688 {
1689         for ( ; ; ) {
1690                 struct rte_swx_table_entry *entry;
1691
1692                 entry = TAILQ_FIRST(list);
1693                 if (!entry)
1694                         break;
1695
1696                 TAILQ_REMOVE(list, entry, node);
1697                 table_entry_free(entry);
1698         }
1699 }
1700
1701 static int
1702 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1703                            uint32_t table_id,
1704                            struct rte_swx_table_entry_list *dst,
1705                            struct rte_swx_table_entry_list *src)
1706 {
1707         struct rte_swx_table_entry *src_entry;
1708
1709         TAILQ_FOREACH(src_entry, src, node) {
1710                 struct rte_swx_table_entry *dst_entry;
1711
1712                 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1713                 if (!dst_entry)
1714                         goto error;
1715
1716                 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1717         }
1718
1719         return 0;
1720
1721 error:
1722         table_entry_list_free(dst);
1723         return -ENOMEM;
1724 }
1725
1726 /* This commit stage contains all the operations that can fail; in case ANY of
1727  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1728  */
1729 static int
1730 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1731                uint32_t table_id,
1732                uint32_t after_swap)
1733 {
1734         struct table *table = &ctl->tables[table_id];
1735         struct rte_swx_table_state *ts = &ctl->ts[table_id];
1736         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1737
1738         if (table->is_stub || !table_is_update_pending(table, 0))
1739                 return 0;
1740
1741         /*
1742          * Current table supports incremental update.
1743          */
1744         if (table->ops.add) {
1745                 /* Reset counters. */
1746                 table->n_add = 0;
1747                 table->n_modify = 0;
1748                 table->n_delete = 0;
1749
1750                 /* Add pending rules. */
1751                 struct rte_swx_table_entry *entry;
1752
1753                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1754                         int status;
1755
1756                         status = table->ops.add(ts_next->obj, entry);
1757                         if (status)
1758                                 return status;
1759
1760                         table->n_add++;
1761                 }
1762
1763                 /* Modify pending rules. */
1764                 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1765                         int status;
1766
1767                         status = table->ops.add(ts_next->obj, entry);
1768                         if (status)
1769                                 return status;
1770
1771                         table->n_modify++;
1772                 }
1773
1774                 /* Delete pending rules. */
1775                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1776                         int status;
1777
1778                         status = table->ops.del(ts_next->obj, entry);
1779                         if (status)
1780                                 return status;
1781
1782                         table->n_delete++;
1783                 }
1784
1785                 return 0;
1786         }
1787
1788         /*
1789          * Current table does NOT support incremental update.
1790          */
1791         if (!after_swap) {
1792                 struct rte_swx_table_entry_list list;
1793                 int status;
1794
1795                 /* Create updated list of entries included. */
1796                 TAILQ_INIT(&list);
1797
1798                 status = table_entry_list_duplicate(ctl,
1799                                                     table_id,
1800                                                     &list,
1801                                                     &table->entries);
1802                 if (status)
1803                         goto error;
1804
1805                 status = table_entry_list_duplicate(ctl,
1806                                                     table_id,
1807                                                     &list,
1808                                                     &table->pending_add);
1809                 if (status)
1810                         goto error;
1811
1812                 status = table_entry_list_duplicate(ctl,
1813                                                     table_id,
1814                                                     &list,
1815                                                     &table->pending_modify1);
1816                 if (status)
1817                         goto error;
1818
1819                 /* Create new table object with the updates included. */
1820                 ts_next->obj = table->ops.create(&table->params,
1821                                                  &list,
1822                                                  table->info.args,
1823                                                  ctl->numa_node);
1824                 if (!ts_next->obj) {
1825                         status = -ENODEV;
1826                         goto error;
1827                 }
1828
1829                 table_entry_list_free(&list);
1830
1831                 return 0;
1832
1833 error:
1834                 table_entry_list_free(&list);
1835                 return status;
1836         }
1837
1838         /* Free the old table object. */
1839         if (ts_next->obj && table->ops.free)
1840                 table->ops.free(ts_next->obj);
1841
1842         /* Copy over the new table object. */
1843         ts_next->obj = ts->obj;
1844
1845         return 0;
1846 }
1847
1848 /* This commit stage contains all the operations that cannot fail. They are
1849  * executed only if the previous stage was successful for ALL the tables. Hence,
1850  * none of these operations has to be rolled back for ANY table.
1851  */
1852 static void
1853 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1854 {
1855         struct table *table = &ctl->tables[table_id];
1856         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1857         struct action *a;
1858         uint8_t *action_data;
1859         uint64_t action_id;
1860
1861         /* Copy the pending default entry. */
1862         if (!table->pending_default)
1863                 return;
1864
1865         action_id = table->pending_default->action_id;
1866         action_data = table->pending_default->action_data;
1867         a = &ctl->actions[action_id];
1868
1869         if (a->data_size)
1870                 memcpy(ts_next->default_action_data, action_data, a->data_size);
1871
1872         ts_next->default_action_id = action_id;
1873 }
1874
1875 /* This last commit stage is simply finalizing a successful commit operation.
1876  * This stage is only executed if all the previous stages were successful. This
1877  * stage cannot fail.
1878  */
1879 static void
1880 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1881 {
1882         struct table *table = &ctl->tables[table_id];
1883
1884         /* Move all the pending add entries to the table, as they are now part
1885          * of the table.
1886          */
1887         table_pending_add_admit(table);
1888
1889         /* Move all the pending modify1 entries to table, are they are now part
1890          * of the table. Free up all the pending modify0 entries, as they are no
1891          * longer part of the table.
1892          */
1893         table_pending_modify1_admit(table);
1894         table_pending_modify0_free(table);
1895
1896         /* Free up all the pending delete entries, as they are no longer part of
1897          * the table.
1898          */
1899         table_pending_delete_free(table);
1900
1901         /* Free up the pending default entry, as it is now part of the table. */
1902         table_pending_default_free(table);
1903 }
1904
1905 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1906  * commit operations that can fail did fail for ANY table. It reverts ALL the
1907  * tables to their state before the commit started, as if the commit never
1908  * happened.
1909  */
1910 static void
1911 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1912 {
1913         struct table *table = &ctl->tables[table_id];
1914         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1915
1916         if (table->is_stub || !table_is_update_pending(table, 0))
1917                 return;
1918
1919         if (table->ops.add) {
1920                 struct rte_swx_table_entry *entry;
1921
1922                 /* Add back all the entries that were just deleted. */
1923                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1924                         if (!table->n_delete)
1925                                 break;
1926
1927                         table->ops.add(ts_next->obj, entry);
1928                         table->n_delete--;
1929                 }
1930
1931                 /* Add back the old copy for all the entries that were just
1932                  * modified.
1933                  */
1934                 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1935                         if (!table->n_modify)
1936                                 break;
1937
1938                         table->ops.add(ts_next->obj, entry);
1939                         table->n_modify--;
1940                 }
1941
1942                 /* Delete all the entries that were just added. */
1943                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1944                         if (!table->n_add)
1945                                 break;
1946
1947                         table->ops.del(ts_next->obj, entry);
1948                         table->n_add--;
1949                 }
1950         } else {
1951                 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1952
1953                 /* Free the new table object, as update was cancelled. */
1954                 if (ts_next->obj && table->ops.free)
1955                         table->ops.free(ts_next->obj);
1956
1957                 /* Reinstate the old table object. */
1958                 ts_next->obj = ts->obj;
1959         }
1960 }
1961
1962 /* This stage is conditionally executed (as instructed by the user) after a
1963  * failed commit operation to remove ALL the pending work for ALL the tables.
1964  */
1965 static void
1966 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1967 {
1968         struct table *table = &ctl->tables[table_id];
1969
1970         /* Free up all the pending add entries, as none of them is part of the
1971          * table.
1972          */
1973         table_pending_add_free(table);
1974
1975         /* Free up all the pending modify1 entries, as none of them made it to
1976          * the table. Add back all the pending modify0 entries, as none of them
1977          * was deleted from the table.
1978          */
1979         table_pending_modify1_free(table);
1980         table_pending_modify0_admit(table);
1981
1982         /* Add back all the pending delete entries, as none of them was deleted
1983          * from the table.
1984          */
1985         table_pending_delete_admit(table);
1986
1987         /* Free up the pending default entry, as it is no longer going to be
1988          * added to the table.
1989          */
1990         table_pending_default_free(table);
1991 }
1992
1993 int
1994 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1995                                         const char *selector_name,
1996                                         uint32_t *group_id)
1997 {
1998         struct selector *s;
1999         uint32_t i;
2000
2001         /* Check input arguments. */
2002         if (!ctl || !selector_name || !selector_name[0] || !group_id)
2003                 return -EINVAL;
2004
2005         s = selector_find(ctl, selector_name);
2006         if (!s)
2007                 return -EINVAL;
2008
2009         /* Find an unused group. */
2010         for (i = 0; i < s->info.n_groups_max; i++)
2011                 if (!s->groups_added[i]) {
2012                         *group_id = i;
2013                         s->groups_added[i] = 1;
2014                         return 0;
2015                 }
2016
2017         return -ENOSPC;
2018 }
2019
2020 int
2021 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2022                                            const char *selector_name,
2023                                            uint32_t group_id)
2024 {
2025         struct selector *s;
2026         struct rte_swx_table_selector_group *group;
2027
2028         /* Check input arguments. */
2029         if (!ctl || !selector_name || !selector_name[0])
2030                 return -EINVAL;
2031
2032         s = selector_find(ctl, selector_name);
2033         if (!s ||
2034            (group_id >= s->info.n_groups_max) ||
2035            !s->groups_added[group_id])
2036                 return -EINVAL;
2037
2038         /* Check if this group is already scheduled for deletion. */
2039         if (s->groups_pending_delete[group_id])
2040                 return 0;
2041
2042         /* Initialize the pending group, if needed. */
2043         if (!s->pending_groups[group_id]) {
2044                 int status;
2045
2046                 status = selector_group_duplicate_to_pending(s, group_id);
2047                 if (status)
2048                         return status;
2049         }
2050
2051         group = s->pending_groups[group_id];
2052
2053         /* Schedule removal of all the members from the current group. */
2054         for ( ; ; ) {
2055                 struct rte_swx_table_selector_member *m;
2056
2057                 m = TAILQ_FIRST(&group->members);
2058                 if (!m)
2059                         break;
2060
2061                 TAILQ_REMOVE(&group->members, m, node);
2062                 free(m);
2063         }
2064
2065         /* Schedule the group for deletion. */
2066         s->groups_pending_delete[group_id] = 1;
2067
2068         return 0;
2069 }
2070
2071 int
2072 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2073                                                const char *selector_name,
2074                                                uint32_t group_id,
2075                                                uint32_t member_id,
2076                                                uint32_t member_weight)
2077 {
2078         struct selector *s;
2079         struct rte_swx_table_selector_group *group;
2080         struct rte_swx_table_selector_member *m;
2081
2082         if (!member_weight)
2083                 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2084                                                                          selector_name,
2085                                                                          group_id,
2086                                                                          member_id);
2087
2088         /* Check input arguments. */
2089         if (!ctl || !selector_name || !selector_name[0])
2090                 return -EINVAL;
2091
2092         s = selector_find(ctl, selector_name);
2093         if (!s ||
2094            (group_id >= s->info.n_groups_max) ||
2095            !s->groups_added[group_id] ||
2096            s->groups_pending_delete[group_id])
2097                 return -EINVAL;
2098
2099         /* Initialize the pending group, if needed. */
2100         if (!s->pending_groups[group_id]) {
2101                 int status;
2102
2103                 status = selector_group_duplicate_to_pending(s, group_id);
2104                 if (status)
2105                         return status;
2106         }
2107
2108         group = s->pending_groups[group_id];
2109
2110         /* If this member is already in this group, then simply update its weight and return. */
2111         TAILQ_FOREACH(m, &group->members, node)
2112                 if (m->member_id == member_id) {
2113                         m->member_weight = member_weight;
2114                         return 0;
2115                 }
2116
2117         /* Add new member to this group. */
2118         m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2119         if (!m)
2120                 return -ENOMEM;
2121
2122         m->member_id = member_id;
2123         m->member_weight = member_weight;
2124
2125         TAILQ_INSERT_TAIL(&group->members, m, node);
2126
2127         return 0;
2128 }
2129
2130 int
2131 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2132                                                   const char *selector_name,
2133                                                   uint32_t group_id __rte_unused,
2134                                                   uint32_t member_id __rte_unused)
2135 {
2136         struct selector *s;
2137         struct rte_swx_table_selector_group *group;
2138         struct rte_swx_table_selector_member *m;
2139
2140         /* Check input arguments. */
2141         if (!ctl || !selector_name || !selector_name[0])
2142                 return -EINVAL;
2143
2144         s = selector_find(ctl, selector_name);
2145         if (!s ||
2146             (group_id >= s->info.n_groups_max) ||
2147             !s->groups_added[group_id] ||
2148             s->groups_pending_delete[group_id])
2149                 return -EINVAL;
2150
2151         /* Initialize the pending group, if needed. */
2152         if (!s->pending_groups[group_id]) {
2153                 int status;
2154
2155                 status = selector_group_duplicate_to_pending(s, group_id);
2156                 if (status)
2157                         return status;
2158         }
2159
2160         group = s->pending_groups[group_id];
2161
2162         /* Look for this member in the group and remove it, if found. */
2163         TAILQ_FOREACH(m, &group->members, node)
2164                 if (m->member_id == member_id) {
2165                         TAILQ_REMOVE(&group->members, m, node);
2166                         free(m);
2167                         return 0;
2168                 }
2169
2170         return 0;
2171 }
2172
2173 static int
2174 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2175 {
2176         struct selector *s = &ctl->selectors[selector_id];
2177         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2178         uint32_t group_id;
2179
2180         /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2181          * mirror copy (ts_next->obj).
2182          */
2183         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2184                 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2185                 int status;
2186
2187                 /* Skip this group if no change needed. */
2188                 if (!group)
2189                         continue;
2190
2191                 /* Apply the pending changes for the current group. */
2192                 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2193                 if (status)
2194                         return status;
2195         }
2196
2197         return 0;
2198 }
2199
2200 static void
2201 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2202 {
2203         struct selector *s = &ctl->selectors[selector_id];
2204         uint32_t group_id;
2205
2206         /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2207          * records (s->groups[group_id).
2208          */
2209         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2210                 struct rte_swx_table_selector_group *g = s->groups[group_id];
2211                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2212
2213                 /* Skip this group if no change needed. */
2214                 if (!gp)
2215                         continue;
2216
2217                 /* Transition the pending changes to stable. */
2218                 s->groups[group_id] = gp;
2219                 s->pending_groups[group_id] = NULL;
2220
2221                 /* Free the old group member list. */
2222                 if (!g)
2223                         continue;
2224
2225                 for ( ; ; ) {
2226                         struct rte_swx_table_selector_member *m;
2227
2228                         m = TAILQ_FIRST(&g->members);
2229                         if (!m)
2230                                 break;
2231
2232                         TAILQ_REMOVE(&g->members, m, node);
2233                         free(m);
2234                 }
2235
2236                 free(g);
2237         }
2238
2239         /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2240          * s->groups_added[group_id].
2241          */
2242         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2243                 if (s->groups_pending_delete[group_id]) {
2244                         s->groups_added[group_id] = 0;
2245                         s->groups_pending_delete[group_id] = 0;
2246                 }
2247 }
2248
2249 static void
2250 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2251 {
2252         struct selector *s = &ctl->selectors[selector_id];
2253         struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2254         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2255         uint32_t group_id;
2256
2257         /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2258         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2259                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2260
2261                 if (gp) {
2262                         ts_next->obj = ts->obj;
2263                         break;
2264                 }
2265         }
2266 }
2267
2268 static void
2269 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2270 {
2271         struct selector *s = &ctl->selectors[selector_id];
2272         uint32_t group_id;
2273
2274         /* Discard any pending group member changes (s->pending_groups[group_id]). */
2275         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2276                 selector_pending_group_members_free(s, group_id);
2277
2278         /* Discard any pending group deletions. */
2279         memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2280 }
2281
2282 static struct rte_swx_table_entry *
2283 learner_default_entry_alloc(struct learner *l)
2284 {
2285         struct rte_swx_table_entry *entry;
2286
2287         entry = calloc(1, sizeof(struct rte_swx_table_entry));
2288         if (!entry)
2289                 goto error;
2290
2291         /* action_data. */
2292         if (l->action_data_size) {
2293                 entry->action_data = calloc(1, l->action_data_size);
2294                 if (!entry->action_data)
2295                         goto error;
2296         }
2297
2298         return entry;
2299
2300 error:
2301         table_entry_free(entry);
2302         return NULL;
2303 }
2304
2305 static int
2306 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2307                             uint32_t learner_id,
2308                             struct rte_swx_table_entry *entry)
2309 {
2310         struct learner *l = &ctl->learners[learner_id];
2311         struct action *a;
2312         uint32_t i;
2313
2314         CHECK(entry, EINVAL);
2315
2316         /* action_id. */
2317         for (i = 0; i < l->info.n_actions; i++)
2318                 if (entry->action_id == l->actions[i].action_id)
2319                         break;
2320
2321         CHECK(i < l->info.n_actions, EINVAL);
2322
2323         /* action_data. */
2324         a = &ctl->actions[entry->action_id];
2325         CHECK(!(a->data_size && !entry->action_data), EINVAL);
2326
2327         return 0;
2328 }
2329
2330 static struct rte_swx_table_entry *
2331 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2332                                 uint32_t learner_id,
2333                                 struct rte_swx_table_entry *entry)
2334 {
2335         struct learner *l = &ctl->learners[learner_id];
2336         struct rte_swx_table_entry *new_entry = NULL;
2337         struct action *a;
2338         uint32_t i;
2339
2340         if (!entry)
2341                 goto error;
2342
2343         new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2344         if (!new_entry)
2345                 goto error;
2346
2347         /* action_id. */
2348         for (i = 0; i < l->info.n_actions; i++)
2349                 if (entry->action_id == l->actions[i].action_id)
2350                         break;
2351
2352         if (i >= l->info.n_actions)
2353                 goto error;
2354
2355         new_entry->action_id = entry->action_id;
2356
2357         /* action_data. */
2358         a = &ctl->actions[entry->action_id];
2359         if (a->data_size && !entry->action_data)
2360                 goto error;
2361
2362         /* The table layer provisions a constant action data size per
2363          * entry, which should be the largest data size for all the
2364          * actions enabled for the current table, and attempts to copy
2365          * this many bytes each time a table entry is added, even if the
2366          * specific action requires less data or even no data at all,
2367          * hence we always have to allocate the max.
2368          */
2369         new_entry->action_data = calloc(1, l->action_data_size);
2370         if (!new_entry->action_data)
2371                 goto error;
2372
2373         if (a->data_size)
2374                 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2375
2376         return new_entry;
2377
2378 error:
2379         table_entry_free(new_entry);
2380         return NULL;
2381 }
2382
2383 int
2384 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2385                                                const char *learner_name,
2386                                                struct rte_swx_table_entry *entry)
2387 {
2388         struct learner *l;
2389         struct rte_swx_table_entry *new_entry;
2390         uint32_t learner_id;
2391
2392         CHECK(ctl, EINVAL);
2393
2394         CHECK(learner_name && learner_name[0], EINVAL);
2395         l = learner_find(ctl, learner_name);
2396         CHECK(l, EINVAL);
2397         learner_id = l - ctl->learners;
2398         CHECK(!l->info.default_action_is_const, EINVAL);
2399
2400         CHECK(entry, EINVAL);
2401         CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2402
2403         CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2404
2405         new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2406         CHECK(new_entry, ENOMEM);
2407
2408         learner_pending_default_free(l);
2409
2410         l->pending_default = new_entry;
2411         return 0;
2412 }
2413
2414 static void
2415 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2416 {
2417         struct learner *l = &ctl->learners[learner_id];
2418         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2419                 ctl->info.n_selectors + learner_id];
2420         struct action *a;
2421         uint8_t *action_data;
2422         uint64_t action_id;
2423
2424         /* Copy the pending default entry. */
2425         if (!l->pending_default)
2426                 return;
2427
2428         action_id = l->pending_default->action_id;
2429         action_data = l->pending_default->action_data;
2430         a = &ctl->actions[action_id];
2431
2432         if (a->data_size)
2433                 memcpy(ts_next->default_action_data, action_data, a->data_size);
2434
2435         ts_next->default_action_id = action_id;
2436 }
2437
2438 static void
2439 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2440 {
2441         struct learner *l = &ctl->learners[learner_id];
2442
2443         /* Free up the pending default entry, as it is now part of the table. */
2444         learner_pending_default_free(l);
2445 }
2446
2447 static void
2448 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2449 {
2450         struct learner *l = &ctl->learners[learner_id];
2451
2452         /* Free up the pending default entry, as it is no longer going to be added to the table. */
2453         learner_pending_default_free(l);
2454 }
2455
2456 int
2457 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2458 {
2459         struct rte_swx_table_state *ts;
2460         int status = 0;
2461         uint32_t i;
2462
2463         CHECK(ctl, EINVAL);
2464
2465         /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2466          * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2467          * We must be able to fully revert all the changes that can fail as if they never happened.
2468          */
2469         for (i = 0; i < ctl->info.n_tables; i++) {
2470                 status = table_rollfwd0(ctl, i, 0);
2471                 if (status)
2472                         goto rollback;
2473         }
2474
2475         for (i = 0; i < ctl->info.n_selectors; i++) {
2476                 status = selector_rollfwd(ctl, i);
2477                 if (status)
2478                         goto rollback;
2479         }
2480
2481         /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2482          * onwards, the transaction is guaranteed to be successful.
2483          */
2484         for (i = 0; i < ctl->info.n_tables; i++)
2485                 table_rollfwd1(ctl, i);
2486
2487         for (i = 0; i < ctl->info.n_learners; i++)
2488                 learner_rollfwd(ctl, i);
2489
2490         /* Swap the table state for the data plane. The current ts and ts_next
2491          * become the new ts_next and ts, respectively.
2492          */
2493         rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2494         usleep(100);
2495         ts = ctl->ts;
2496         ctl->ts = ctl->ts_next;
2497         ctl->ts_next = ts;
2498
2499         /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2500          * the current ts_next in sync with the current ts. Since the changes that can fail did
2501          * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2502          * current ts_next, hence no error checking is needed.
2503          */
2504         for (i = 0; i < ctl->info.n_tables; i++) {
2505                 table_rollfwd0(ctl, i, 1);
2506                 table_rollfwd1(ctl, i);
2507                 table_rollfwd2(ctl, i);
2508         }
2509
2510         for (i = 0; i < ctl->info.n_selectors; i++) {
2511                 selector_rollfwd(ctl, i);
2512                 selector_rollfwd_finalize(ctl, i);
2513         }
2514
2515         for (i = 0; i < ctl->info.n_learners; i++) {
2516                 learner_rollfwd(ctl, i);
2517                 learner_rollfwd_finalize(ctl, i);
2518         }
2519
2520         return 0;
2521
2522 rollback:
2523         for (i = 0; i < ctl->info.n_tables; i++) {
2524                 table_rollback(ctl, i);
2525                 if (abort_on_fail)
2526                         table_abort(ctl, i);
2527         }
2528
2529         for (i = 0; i < ctl->info.n_selectors; i++) {
2530                 selector_rollback(ctl, i);
2531                 if (abort_on_fail)
2532                         selector_abort(ctl, i);
2533         }
2534
2535         if (abort_on_fail)
2536                 for (i = 0; i < ctl->info.n_learners; i++)
2537                         learner_abort(ctl, i);
2538
2539         return status;
2540 }
2541
2542 void
2543 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2544 {
2545         uint32_t i;
2546
2547         if (!ctl)
2548                 return;
2549
2550         for (i = 0; i < ctl->info.n_tables; i++)
2551                 table_abort(ctl, i);
2552
2553         for (i = 0; i < ctl->info.n_selectors; i++)
2554                 selector_abort(ctl, i);
2555
2556         for (i = 0; i < ctl->info.n_learners; i++)
2557                 learner_abort(ctl, i);
2558 }
2559
2560 static int
2561 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2562 {
2563         uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2564
2565         if (!mask) {
2566                 *prefix_length = 0;
2567                 return 0;
2568         }
2569
2570         /* Count trailing zero bits. */
2571         for (i = 0; i < 64; i++) {
2572                 if (mask & (1LLU << i))
2573                         break;
2574
2575                 n_trailing_zeros++;
2576         }
2577
2578         /* Count the one bits that follow. */
2579         for ( ; i < 64; i++) {
2580                 if (!(mask & (1LLU << i)))
2581                         break;
2582
2583                 n_ones++;
2584         }
2585
2586         /* Check that no more one bits are present */
2587         for ( ; i < 64; i++)
2588                 if (mask & (1LLU << i))
2589                         return -EINVAL;
2590
2591         /* Check that the input mask is a prefix or the right length. */
2592         if (n_ones + n_trailing_zeros != mask_length)
2593                 return -EINVAL;
2594
2595         *prefix_length = n_ones;
2596         return 0;
2597 }
2598
2599 static int
2600 token_is_comment(const char *token)
2601 {
2602         if ((token[0] == '#') ||
2603             (token[0] == ';') ||
2604             ((token[0] == '/') && (token[1] == '/')))
2605                 return 1; /* TRUE. */
2606
2607         return 0; /* FALSE. */
2608 }
2609
2610 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2611
2612 struct rte_swx_table_entry *
2613 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2614                                       const char *table_name,
2615                                       const char *string,
2616                                       int *is_blank_or_comment)
2617 {
2618         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2619         struct table *table;
2620         struct action *action;
2621         struct rte_swx_table_entry *entry = NULL;
2622         char *s0 = NULL, *s;
2623         uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2624         int lpm = 0, blank_or_comment = 0;
2625
2626         /* Check input arguments. */
2627         if (!ctl)
2628                 goto error;
2629
2630         if (!table_name || !table_name[0])
2631                 goto error;
2632
2633         table = table_find(ctl, table_name);
2634         if (!table)
2635                 goto error;
2636
2637         if (!string || !string[0])
2638                 goto error;
2639
2640         /* Memory allocation. */
2641         s0 = strdup(string);
2642         if (!s0)
2643                 goto error;
2644
2645         entry = table_entry_alloc(table);
2646         if (!entry)
2647                 goto error;
2648
2649         /* Parse the string into tokens. */
2650         for (s = s0; ; ) {
2651                 char *token;
2652
2653                 token = strtok_r(s, " \f\n\r\t\v", &s);
2654                 if (!token || token_is_comment(token))
2655                         break;
2656
2657                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2658                         goto error;
2659
2660                 token_array[n_tokens] = token;
2661                 n_tokens++;
2662         }
2663
2664         if (!n_tokens) {
2665                 blank_or_comment = 1;
2666                 goto error;
2667         }
2668
2669         tokens = token_array;
2670
2671         /*
2672          * Match.
2673          */
2674         if (!(n_tokens && !strcmp(tokens[0], "match")))
2675                 goto action;
2676
2677         if (n_tokens < 1 + table->info.n_match_fields)
2678                 goto error;
2679
2680         for (i = 0; i < table->info.n_match_fields; i++) {
2681                 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2682                 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2683                 uint64_t val, mask = UINT64_MAX;
2684                 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2685
2686                 /*
2687                  * Mask.
2688                  */
2689                 mf_mask = strchr(mf_val, '/');
2690                 if (mf_mask) {
2691                         *mf_mask = 0;
2692                         mf_mask++;
2693
2694                         /* Parse. */
2695                         mask = strtoull(mf_mask, &mf_mask, 0);
2696                         if (mf_mask[0])
2697                                 goto error;
2698
2699                         /* LPM. */
2700                         if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2701                                 int status;
2702
2703                                 lpm = 1;
2704
2705                                 lpm_prefix_length_max = mf->n_bits;
2706
2707                                 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2708                                 if (status)
2709                                         goto error;
2710                         }
2711
2712                         /* Endianness conversion. */
2713                         if (mf->is_header)
2714                                 mask = field_hton(mask, mf->n_bits);
2715                 }
2716
2717                 /* Copy to entry. */
2718                 if (entry->key_mask)
2719                         memcpy(&entry->key_mask[offset],
2720                                (uint8_t *)&mask,
2721                                mf->n_bits / 8);
2722
2723                 /*
2724                  * Value.
2725                  */
2726                 /* Parse. */
2727                 val = strtoull(mf_val, &mf_val, 0);
2728                 if (mf_val[0])
2729                         goto error;
2730
2731                 /* Endianness conversion. */
2732                 if (mf->is_header)
2733                         val = field_hton(val, mf->n_bits);
2734
2735                 /* Copy to entry. */
2736                 memcpy(&entry->key[offset],
2737                        (uint8_t *)&val,
2738                        mf->n_bits / 8);
2739         }
2740
2741         tokens += 1 + table->info.n_match_fields;
2742         n_tokens -= 1 + table->info.n_match_fields;
2743
2744         /*
2745          * Match priority.
2746          */
2747         if (n_tokens && !strcmp(tokens[0], "priority")) {
2748                 char *priority = tokens[1];
2749                 uint32_t val;
2750
2751                 if (n_tokens < 2)
2752                         goto error;
2753
2754                 /* Parse. */
2755                 val = strtoul(priority, &priority, 0);
2756                 if (priority[0])
2757                         goto error;
2758
2759                 /* Copy to entry. */
2760                 entry->key_priority = val;
2761
2762                 tokens += 2;
2763                 n_tokens -= 2;
2764         }
2765
2766         /* LPM. */
2767         if (lpm)
2768                 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2769
2770         /*
2771          * Action.
2772          */
2773 action:
2774         if (!(n_tokens && !strcmp(tokens[0], "action")))
2775                 goto other;
2776
2777         if (n_tokens < 2)
2778                 goto error;
2779
2780         action = action_find(ctl, tokens[1]);
2781         if (!action)
2782                 goto error;
2783
2784         if (n_tokens < 2 + action->info.n_args * 2)
2785                 goto error;
2786
2787         /* action_id. */
2788         entry->action_id = action - ctl->actions;
2789
2790         /* action_data. */
2791         for (i = 0; i < action->info.n_args; i++) {
2792                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2793                 char *arg_name, *arg_val;
2794                 uint64_t val;
2795
2796                 arg_name = tokens[2 + i * 2];
2797                 arg_val = tokens[2 + i * 2 + 1];
2798
2799                 if (strcmp(arg_name, arg->name))
2800                         goto error;
2801
2802                 val = strtoull(arg_val, &arg_val, 0);
2803                 if (arg_val[0])
2804                         goto error;
2805
2806                 /* Endianness conversion. */
2807                 if (arg->is_network_byte_order)
2808                         val = field_hton(val, arg->n_bits);
2809
2810                 /* Copy to entry. */
2811                 memcpy(&entry->action_data[arg_offset],
2812                        (uint8_t *)&val,
2813                        arg->n_bits / 8);
2814
2815                 arg_offset += arg->n_bits / 8;
2816         }
2817
2818         tokens += 2 + action->info.n_args * 2;
2819         n_tokens -= 2 + action->info.n_args * 2;
2820
2821 other:
2822         if (n_tokens)
2823                 goto error;
2824
2825         free(s0);
2826         return entry;
2827
2828 error:
2829         table_entry_free(entry);
2830         free(s0);
2831         if (is_blank_or_comment)
2832                 *is_blank_or_comment = blank_or_comment;
2833         return NULL;
2834 }
2835
2836 struct rte_swx_table_entry *
2837 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2838                                                 const char *learner_name,
2839                                                 const char *string,
2840                                                 int *is_blank_or_comment)
2841 {
2842         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2843         struct learner *l;
2844         struct action *action;
2845         struct rte_swx_table_entry *entry = NULL;
2846         char *s0 = NULL, *s;
2847         uint32_t n_tokens = 0, arg_offset = 0, i;
2848         int blank_or_comment = 0;
2849
2850         /* Check input arguments. */
2851         if (!ctl)
2852                 goto error;
2853
2854         if (!learner_name || !learner_name[0])
2855                 goto error;
2856
2857         l = learner_find(ctl, learner_name);
2858         if (!l)
2859                 goto error;
2860
2861         if (!string || !string[0])
2862                 goto error;
2863
2864         /* Memory allocation. */
2865         s0 = strdup(string);
2866         if (!s0)
2867                 goto error;
2868
2869         entry = learner_default_entry_alloc(l);
2870         if (!entry)
2871                 goto error;
2872
2873         /* Parse the string into tokens. */
2874         for (s = s0; ; ) {
2875                 char *token;
2876
2877                 token = strtok_r(s, " \f\n\r\t\v", &s);
2878                 if (!token || token_is_comment(token))
2879                         break;
2880
2881                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2882                         goto error;
2883
2884                 token_array[n_tokens] = token;
2885                 n_tokens++;
2886         }
2887
2888         if (!n_tokens) {
2889                 blank_or_comment = 1;
2890                 goto error;
2891         }
2892
2893         tokens = token_array;
2894
2895         /*
2896          * Action.
2897          */
2898         if (!(n_tokens && !strcmp(tokens[0], "action")))
2899                 goto other;
2900
2901         if (n_tokens < 2)
2902                 goto error;
2903
2904         action = action_find(ctl, tokens[1]);
2905         if (!action)
2906                 goto error;
2907
2908         if (n_tokens < 2 + action->info.n_args * 2)
2909                 goto error;
2910
2911         /* action_id. */
2912         entry->action_id = action - ctl->actions;
2913
2914         /* action_data. */
2915         for (i = 0; i < action->info.n_args; i++) {
2916                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2917                 char *arg_name, *arg_val;
2918                 uint64_t val;
2919
2920                 arg_name = tokens[2 + i * 2];
2921                 arg_val = tokens[2 + i * 2 + 1];
2922
2923                 if (strcmp(arg_name, arg->name))
2924                         goto error;
2925
2926                 val = strtoull(arg_val, &arg_val, 0);
2927                 if (arg_val[0])
2928                         goto error;
2929
2930                 /* Endianness conversion. */
2931                 if (arg->is_network_byte_order)
2932                         val = field_hton(val, arg->n_bits);
2933
2934                 /* Copy to entry. */
2935                 memcpy(&entry->action_data[arg_offset],
2936                        (uint8_t *)&val,
2937                        arg->n_bits / 8);
2938
2939                 arg_offset += arg->n_bits / 8;
2940         }
2941
2942         tokens += 2 + action->info.n_args * 2;
2943         n_tokens -= 2 + action->info.n_args * 2;
2944
2945 other:
2946         if (n_tokens)
2947                 goto error;
2948
2949         free(s0);
2950         return entry;
2951
2952 error:
2953         table_entry_free(entry);
2954         free(s0);
2955         if (is_blank_or_comment)
2956                 *is_blank_or_comment = blank_or_comment;
2957         return NULL;
2958 }
2959
2960 static void
2961 table_entry_printf(FILE *f,
2962                    struct rte_swx_ctl_pipeline *ctl,
2963                    struct table *table,
2964                    struct rte_swx_table_entry *entry)
2965 {
2966         struct action *action = &ctl->actions[entry->action_id];
2967         uint32_t i;
2968
2969         fprintf(f, "match ");
2970         for (i = 0; i < table->params.key_size; i++)
2971                 fprintf(f, "%02x", entry->key[i]);
2972
2973         if (entry->key_mask) {
2974                 fprintf(f, "/");
2975                 for (i = 0; i < table->params.key_size; i++)
2976                         fprintf(f, "%02x", entry->key_mask[i]);
2977         }
2978
2979         fprintf(f, " priority %u", entry->key_priority);
2980
2981         fprintf(f, " action %s ", action->info.name);
2982         for (i = 0; i < action->data_size; i++)
2983                 fprintf(f, "%02x", entry->action_data[i]);
2984
2985         fprintf(f, "\n");
2986 }
2987
2988 int
2989 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2990                                    struct rte_swx_ctl_pipeline *ctl,
2991                                    const char *table_name)
2992 {
2993         struct table *table;
2994         struct rte_swx_table_entry *entry;
2995         uint32_t n_entries = 0, i;
2996
2997         if (!f || !ctl || !table_name || !table_name[0])
2998                 return -EINVAL;
2999
3000         table = table_find(ctl, table_name);
3001         if (!table)
3002                 return -EINVAL;
3003
3004         /* Table. */
3005         fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3006                 table->info.name,
3007                 table->params.key_size,
3008                 table->params.key_offset);
3009
3010         for (i = 0; i < table->params.key_size; i++)
3011                 fprintf(f, "%02x", table->params.key_mask0[i]);
3012
3013         fprintf(f, "], action data size %u bytes\n",
3014                 table->params.action_data_size);
3015
3016         /* Table entries. */
3017         TAILQ_FOREACH(entry, &table->entries, node) {
3018                 table_entry_printf(f, ctl, table, entry);
3019                 n_entries++;
3020         }
3021
3022         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3023                 table_entry_printf(f, ctl, table, entry);
3024                 n_entries++;
3025         }
3026
3027         TAILQ_FOREACH(entry, &table->pending_delete, node) {
3028                 table_entry_printf(f, ctl, table, entry);
3029                 n_entries++;
3030         }
3031
3032         fprintf(f, "# Table %s currently has %u entries.\n",
3033                 table_name,
3034                 n_entries);
3035         return 0;
3036 }
3037
3038 int
3039 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3040                                       struct rte_swx_ctl_pipeline *ctl,
3041                                       const char *selector_name)
3042 {
3043         struct selector *s;
3044         uint32_t group_id;
3045
3046         if (!f || !ctl || !selector_name || !selector_name[0])
3047                 return -EINVAL;
3048
3049         s = selector_find(ctl, selector_name);
3050         if (!s)
3051                 return -EINVAL;
3052
3053         /* Selector. */
3054         fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3055                 s->info.name,
3056                 s->info.n_groups_max,
3057                 s->info.n_members_per_group_max);
3058
3059         /* Groups. */
3060         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3061                 struct rte_swx_table_selector_group *group = s->groups[group_id];
3062                 struct rte_swx_table_selector_member *m;
3063                 uint32_t n_members = 0;
3064
3065                 fprintf(f, "Group %u = [", group_id);
3066
3067                 /* Non-empty group. */
3068                 if (group)
3069                         TAILQ_FOREACH(m, &group->members, node) {
3070                                 fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3071                                 n_members++;
3072                         }
3073
3074                 /* Empty group. */
3075                 if (!n_members)
3076                         fprintf(f, "0:1 ");
3077
3078                 fprintf(f, "]\n");
3079         }
3080
3081         return 0;
3082 }