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