86b58e21dc2c4a337b3c5f7086a2706e8a6a37d0
[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         new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1450         CHECK(new_entry, ENOMEM);
1451
1452         /* The new entry is found in the table->entries list:
1453          * - Add the new entry to the table->pending_modify1 list;
1454          * - Move the existing entry from the table->entries list to the
1455          *   table->pending_modify0 list.
1456          */
1457         existing_entry = table_entries_find(table, entry);
1458         if (existing_entry) {
1459                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1460                                   new_entry,
1461                                   node);
1462
1463                 TAILQ_REMOVE(&table->entries,
1464                              existing_entry,
1465                              node);
1466
1467                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1468                                   existing_entry,
1469                                   node);
1470
1471                 return 0;
1472         }
1473
1474         /* The new entry is found in the table->pending_add list:
1475          * - Replace the entry in the table->pending_add list with the new entry
1476          *   (and free the replaced entry).
1477          */
1478         existing_entry = table_pending_add_find(table, entry);
1479         if (existing_entry) {
1480                 TAILQ_INSERT_AFTER(&table->pending_add,
1481                                    existing_entry,
1482                                    new_entry,
1483                                    node);
1484
1485                 TAILQ_REMOVE(&table->pending_add,
1486                              existing_entry,
1487                              node);
1488
1489                 table_entry_free(existing_entry);
1490
1491                 return 0;
1492         }
1493
1494         /* The new entry is found in the table->pending_modify1 list:
1495          * - Replace the entry in the table->pending_modify1 list with the new
1496          *   entry (and free the replaced entry).
1497          */
1498         existing_entry = table_pending_modify1_find(table, entry);
1499         if (existing_entry) {
1500                 TAILQ_INSERT_AFTER(&table->pending_modify1,
1501                                    existing_entry,
1502                                    new_entry,
1503                                    node);
1504
1505                 TAILQ_REMOVE(&table->pending_modify1,
1506                              existing_entry,
1507                              node);
1508
1509                 table_entry_free(existing_entry);
1510
1511                 return 0;
1512         }
1513
1514         /* The new entry is found in the table->pending_delete list:
1515          * - Add the new entry to the table->pending_modify1 list;
1516          * - Move the existing entry from the table->pending_delete list to the
1517          *   table->pending_modify0 list.
1518          */
1519         existing_entry = table_pending_delete_find(table, entry);
1520         if (existing_entry) {
1521                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1522                                   new_entry,
1523                                   node);
1524
1525                 TAILQ_REMOVE(&table->pending_delete,
1526                              existing_entry,
1527                              node);
1528
1529                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1530                                   existing_entry,
1531                                   node);
1532
1533                 return 0;
1534         }
1535
1536         /* The new entry is not found in any of the above lists:
1537          * - Add the new entry to the table->pending_add list.
1538          */
1539         TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1540
1541         return 0;
1542 }
1543
1544 int
1545 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1546                                         const char *table_name,
1547                                         struct rte_swx_table_entry *entry)
1548 {
1549         struct table *table;
1550         struct rte_swx_table_entry *existing_entry;
1551         uint32_t table_id;
1552
1553         CHECK(ctl, EINVAL);
1554
1555         CHECK(table_name && table_name[0], EINVAL);
1556         table = table_find(ctl, table_name);
1557         CHECK(table, EINVAL);
1558         table_id = table - ctl->tables;
1559
1560         CHECK(entry, EINVAL);
1561         CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1562
1563         /* The entry is found in the table->entries list:
1564          * - Move the existing entry from the table->entries list to to the
1565          *   table->pending_delete list.
1566          */
1567         existing_entry = table_entries_find(table, entry);
1568         if (existing_entry) {
1569                 TAILQ_REMOVE(&table->entries,
1570                              existing_entry,
1571                              node);
1572
1573                 TAILQ_INSERT_TAIL(&table->pending_delete,
1574                                   existing_entry,
1575                                   node);
1576
1577                 return 0;
1578         }
1579
1580         /* The entry is found in the table->pending_add list:
1581          * - Remove the entry from the table->pending_add list and free it.
1582          */
1583         existing_entry = table_pending_add_find(table, entry);
1584         if (existing_entry) {
1585                 TAILQ_REMOVE(&table->pending_add,
1586                              existing_entry,
1587                              node);
1588
1589                 table_entry_free(existing_entry);
1590         }
1591
1592         /* The entry is found in the table->pending_modify1 list:
1593          * - Free the entry in the table->pending_modify1 list;
1594          * - Move the existing entry from the table->pending_modify0 list to the
1595          *   table->pending_delete list.
1596          */
1597         existing_entry = table_pending_modify1_find(table, entry);
1598         if (existing_entry) {
1599                 struct rte_swx_table_entry *real_existing_entry;
1600
1601                 TAILQ_REMOVE(&table->pending_modify1,
1602                              existing_entry,
1603                              node);
1604
1605                 table_entry_free(existing_entry);
1606
1607                 real_existing_entry = table_pending_modify0_find(table, entry);
1608                 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1609
1610                 TAILQ_REMOVE(&table->pending_modify0,
1611                              real_existing_entry,
1612                              node);
1613
1614                 TAILQ_INSERT_TAIL(&table->pending_delete,
1615                                   real_existing_entry,
1616                                   node);
1617
1618                 return 0;
1619         }
1620
1621         /* The entry is found in the table->pending_delete list:
1622          * - Do nothing: the existing entry is already in the
1623          *   table->pending_delete list, i.e. already marked for delete, so
1624          *   simply keep it there as it is.
1625          */
1626
1627         /* The entry is not found in any of the above lists:
1628          * - Do nothing: no existing entry to delete.
1629          */
1630
1631         return 0;
1632 }
1633
1634 int
1635 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1636                                              const char *table_name,
1637                                              struct rte_swx_table_entry *entry)
1638 {
1639         struct table *table;
1640         struct rte_swx_table_entry *new_entry;
1641         uint32_t table_id;
1642
1643         CHECK(ctl, EINVAL);
1644
1645         CHECK(table_name && table_name[0], EINVAL);
1646         table = table_find(ctl, table_name);
1647         CHECK(table, EINVAL);
1648         table_id = table - ctl->tables;
1649         CHECK(!table->info.default_action_is_const, EINVAL);
1650
1651         CHECK(entry, EINVAL);
1652         CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1653
1654         new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1655         CHECK(new_entry, ENOMEM);
1656
1657         table_pending_default_free(table);
1658
1659         table->pending_default = new_entry;
1660         return 0;
1661 }
1662
1663
1664 static void
1665 table_entry_list_free(struct rte_swx_table_entry_list *list)
1666 {
1667         for ( ; ; ) {
1668                 struct rte_swx_table_entry *entry;
1669
1670                 entry = TAILQ_FIRST(list);
1671                 if (!entry)
1672                         break;
1673
1674                 TAILQ_REMOVE(list, entry, node);
1675                 table_entry_free(entry);
1676         }
1677 }
1678
1679 static int
1680 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1681                            uint32_t table_id,
1682                            struct rte_swx_table_entry_list *dst,
1683                            struct rte_swx_table_entry_list *src)
1684 {
1685         struct rte_swx_table_entry *src_entry;
1686
1687         TAILQ_FOREACH(src_entry, src, node) {
1688                 struct rte_swx_table_entry *dst_entry;
1689
1690                 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1691                 if (!dst_entry)
1692                         goto error;
1693
1694                 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1695         }
1696
1697         return 0;
1698
1699 error:
1700         table_entry_list_free(dst);
1701         return -ENOMEM;
1702 }
1703
1704 /* This commit stage contains all the operations that can fail; in case ANY of
1705  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1706  */
1707 static int
1708 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1709                uint32_t table_id,
1710                uint32_t after_swap)
1711 {
1712         struct table *table = &ctl->tables[table_id];
1713         struct rte_swx_table_state *ts = &ctl->ts[table_id];
1714         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1715
1716         if (table->is_stub || !table_is_update_pending(table, 0))
1717                 return 0;
1718
1719         /*
1720          * Current table supports incremental update.
1721          */
1722         if (table->ops.add) {
1723                 /* Reset counters. */
1724                 table->n_add = 0;
1725                 table->n_modify = 0;
1726                 table->n_delete = 0;
1727
1728                 /* Add pending rules. */
1729                 struct rte_swx_table_entry *entry;
1730
1731                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1732                         int status;
1733
1734                         status = table->ops.add(ts_next->obj, entry);
1735                         if (status)
1736                                 return status;
1737
1738                         table->n_add++;
1739                 }
1740
1741                 /* Modify pending rules. */
1742                 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1743                         int status;
1744
1745                         status = table->ops.add(ts_next->obj, entry);
1746                         if (status)
1747                                 return status;
1748
1749                         table->n_modify++;
1750                 }
1751
1752                 /* Delete pending rules. */
1753                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1754                         int status;
1755
1756                         status = table->ops.del(ts_next->obj, entry);
1757                         if (status)
1758                                 return status;
1759
1760                         table->n_delete++;
1761                 }
1762
1763                 return 0;
1764         }
1765
1766         /*
1767          * Current table does NOT support incremental update.
1768          */
1769         if (!after_swap) {
1770                 struct rte_swx_table_entry_list list;
1771                 int status;
1772
1773                 /* Create updated list of entries included. */
1774                 TAILQ_INIT(&list);
1775
1776                 status = table_entry_list_duplicate(ctl,
1777                                                     table_id,
1778                                                     &list,
1779                                                     &table->entries);
1780                 if (status)
1781                         goto error;
1782
1783                 status = table_entry_list_duplicate(ctl,
1784                                                     table_id,
1785                                                     &list,
1786                                                     &table->pending_add);
1787                 if (status)
1788                         goto error;
1789
1790                 status = table_entry_list_duplicate(ctl,
1791                                                     table_id,
1792                                                     &list,
1793                                                     &table->pending_modify1);
1794                 if (status)
1795                         goto error;
1796
1797                 /* Create new table object with the updates included. */
1798                 ts_next->obj = table->ops.create(&table->params,
1799                                                  &list,
1800                                                  table->info.args,
1801                                                  ctl->numa_node);
1802                 if (!ts_next->obj) {
1803                         status = -ENODEV;
1804                         goto error;
1805                 }
1806
1807                 table_entry_list_free(&list);
1808
1809                 return 0;
1810
1811 error:
1812                 table_entry_list_free(&list);
1813                 return status;
1814         }
1815
1816         /* Free the old table object. */
1817         if (ts_next->obj && table->ops.free)
1818                 table->ops.free(ts_next->obj);
1819
1820         /* Copy over the new table object. */
1821         ts_next->obj = ts->obj;
1822
1823         return 0;
1824 }
1825
1826 /* This commit stage contains all the operations that cannot fail. They are
1827  * executed only if the previous stage was successful for ALL the tables. Hence,
1828  * none of these operations has to be rolled back for ANY table.
1829  */
1830 static void
1831 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1832 {
1833         struct table *table = &ctl->tables[table_id];
1834         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1835         struct action *a;
1836         uint8_t *action_data;
1837         uint64_t action_id;
1838
1839         /* Copy the pending default entry. */
1840         if (!table->pending_default)
1841                 return;
1842
1843         action_id = table->pending_default->action_id;
1844         action_data = table->pending_default->action_data;
1845         a = &ctl->actions[action_id];
1846
1847         if (a->data_size)
1848                 memcpy(ts_next->default_action_data, action_data, a->data_size);
1849
1850         ts_next->default_action_id = action_id;
1851 }
1852
1853 /* This last commit stage is simply finalizing a successful commit operation.
1854  * This stage is only executed if all the previous stages were successful. This
1855  * stage cannot fail.
1856  */
1857 static void
1858 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1859 {
1860         struct table *table = &ctl->tables[table_id];
1861
1862         /* Move all the pending add entries to the table, as they are now part
1863          * of the table.
1864          */
1865         table_pending_add_admit(table);
1866
1867         /* Move all the pending modify1 entries to table, are they are now part
1868          * of the table. Free up all the pending modify0 entries, as they are no
1869          * longer part of the table.
1870          */
1871         table_pending_modify1_admit(table);
1872         table_pending_modify0_free(table);
1873
1874         /* Free up all the pending delete entries, as they are no longer part of
1875          * the table.
1876          */
1877         table_pending_delete_free(table);
1878
1879         /* Free up the pending default entry, as it is now part of the table. */
1880         table_pending_default_free(table);
1881 }
1882
1883 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1884  * commit operations that can fail did fail for ANY table. It reverts ALL the
1885  * tables to their state before the commit started, as if the commit never
1886  * happened.
1887  */
1888 static void
1889 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1890 {
1891         struct table *table = &ctl->tables[table_id];
1892         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1893
1894         if (table->is_stub || !table_is_update_pending(table, 0))
1895                 return;
1896
1897         if (table->ops.add) {
1898                 struct rte_swx_table_entry *entry;
1899
1900                 /* Add back all the entries that were just deleted. */
1901                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1902                         if (!table->n_delete)
1903                                 break;
1904
1905                         table->ops.add(ts_next->obj, entry);
1906                         table->n_delete--;
1907                 }
1908
1909                 /* Add back the old copy for all the entries that were just
1910                  * modified.
1911                  */
1912                 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1913                         if (!table->n_modify)
1914                                 break;
1915
1916                         table->ops.add(ts_next->obj, entry);
1917                         table->n_modify--;
1918                 }
1919
1920                 /* Delete all the entries that were just added. */
1921                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1922                         if (!table->n_add)
1923                                 break;
1924
1925                         table->ops.del(ts_next->obj, entry);
1926                         table->n_add--;
1927                 }
1928         } else {
1929                 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1930
1931                 /* Free the new table object, as update was cancelled. */
1932                 if (ts_next->obj && table->ops.free)
1933                         table->ops.free(ts_next->obj);
1934
1935                 /* Reinstate the old table object. */
1936                 ts_next->obj = ts->obj;
1937         }
1938 }
1939
1940 /* This stage is conditionally executed (as instructed by the user) after a
1941  * failed commit operation to remove ALL the pending work for ALL the tables.
1942  */
1943 static void
1944 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1945 {
1946         struct table *table = &ctl->tables[table_id];
1947
1948         /* Free up all the pending add entries, as none of them is part of the
1949          * table.
1950          */
1951         table_pending_add_free(table);
1952
1953         /* Free up all the pending modify1 entries, as none of them made it to
1954          * the table. Add back all the pending modify0 entries, as none of them
1955          * was deleted from the table.
1956          */
1957         table_pending_modify1_free(table);
1958         table_pending_modify0_admit(table);
1959
1960         /* Add back all the pending delete entries, as none of them was deleted
1961          * from the table.
1962          */
1963         table_pending_delete_admit(table);
1964
1965         /* Free up the pending default entry, as it is no longer going to be
1966          * added to the table.
1967          */
1968         table_pending_default_free(table);
1969 }
1970
1971 int
1972 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1973                                         const char *selector_name,
1974                                         uint32_t *group_id)
1975 {
1976         struct selector *s;
1977         uint32_t i;
1978
1979         /* Check input arguments. */
1980         if (!ctl || !selector_name || !selector_name[0] || !group_id)
1981                 return -EINVAL;
1982
1983         s = selector_find(ctl, selector_name);
1984         if (!s)
1985                 return -EINVAL;
1986
1987         /* Find an unused group. */
1988         for (i = 0; i < s->info.n_groups_max; i++)
1989                 if (!s->groups_added[i]) {
1990                         *group_id = i;
1991                         s->groups_added[i] = 1;
1992                         return 0;
1993                 }
1994
1995         return -ENOSPC;
1996 }
1997
1998 int
1999 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2000                                            const char *selector_name,
2001                                            uint32_t group_id)
2002 {
2003         struct selector *s;
2004         struct rte_swx_table_selector_group *group;
2005
2006         /* Check input arguments. */
2007         if (!ctl || !selector_name || !selector_name[0])
2008                 return -EINVAL;
2009
2010         s = selector_find(ctl, selector_name);
2011         if (!s ||
2012            (group_id >= s->info.n_groups_max) ||
2013            !s->groups_added[group_id])
2014                 return -EINVAL;
2015
2016         /* Check if this group is already scheduled for deletion. */
2017         if (s->groups_pending_delete[group_id])
2018                 return 0;
2019
2020         /* Initialize the pending group, if needed. */
2021         if (!s->pending_groups[group_id]) {
2022                 int status;
2023
2024                 status = selector_group_duplicate_to_pending(s, group_id);
2025                 if (status)
2026                         return status;
2027         }
2028
2029         group = s->pending_groups[group_id];
2030
2031         /* Schedule removal of all the members from the current group. */
2032         for ( ; ; ) {
2033                 struct rte_swx_table_selector_member *m;
2034
2035                 m = TAILQ_FIRST(&group->members);
2036                 if (!m)
2037                         break;
2038
2039                 TAILQ_REMOVE(&group->members, m, node);
2040                 free(m);
2041         }
2042
2043         /* Schedule the group for deletion. */
2044         s->groups_pending_delete[group_id] = 1;
2045
2046         return 0;
2047 }
2048
2049 int
2050 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2051                                                const char *selector_name,
2052                                                uint32_t group_id,
2053                                                uint32_t member_id,
2054                                                uint32_t member_weight)
2055 {
2056         struct selector *s;
2057         struct rte_swx_table_selector_group *group;
2058         struct rte_swx_table_selector_member *m;
2059
2060         if (!member_weight)
2061                 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2062                                                                          selector_name,
2063                                                                          group_id,
2064                                                                          member_id);
2065
2066         /* Check input arguments. */
2067         if (!ctl || !selector_name || !selector_name[0])
2068                 return -EINVAL;
2069
2070         s = selector_find(ctl, selector_name);
2071         if (!s ||
2072            (group_id >= s->info.n_groups_max) ||
2073            !s->groups_added[group_id] ||
2074            s->groups_pending_delete[group_id])
2075                 return -EINVAL;
2076
2077         /* Initialize the pending group, if needed. */
2078         if (!s->pending_groups[group_id]) {
2079                 int status;
2080
2081                 status = selector_group_duplicate_to_pending(s, group_id);
2082                 if (status)
2083                         return status;
2084         }
2085
2086         group = s->pending_groups[group_id];
2087
2088         /* If this member is already in this group, then simply update its weight and return. */
2089         TAILQ_FOREACH(m, &group->members, node)
2090                 if (m->member_id == member_id) {
2091                         m->member_weight = member_weight;
2092                         return 0;
2093                 }
2094
2095         /* Add new member to this group. */
2096         m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2097         if (!m)
2098                 return -ENOMEM;
2099
2100         m->member_id = member_id;
2101         m->member_weight = member_weight;
2102
2103         TAILQ_INSERT_TAIL(&group->members, m, node);
2104
2105         return 0;
2106 }
2107
2108 int
2109 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2110                                                   const char *selector_name,
2111                                                   uint32_t group_id __rte_unused,
2112                                                   uint32_t member_id __rte_unused)
2113 {
2114         struct selector *s;
2115         struct rte_swx_table_selector_group *group;
2116         struct rte_swx_table_selector_member *m;
2117
2118         /* Check input arguments. */
2119         if (!ctl || !selector_name || !selector_name[0])
2120                 return -EINVAL;
2121
2122         s = selector_find(ctl, selector_name);
2123         if (!s ||
2124             (group_id >= s->info.n_groups_max) ||
2125             !s->groups_added[group_id] ||
2126             s->groups_pending_delete[group_id])
2127                 return -EINVAL;
2128
2129         /* Initialize the pending group, if needed. */
2130         if (!s->pending_groups[group_id]) {
2131                 int status;
2132
2133                 status = selector_group_duplicate_to_pending(s, group_id);
2134                 if (status)
2135                         return status;
2136         }
2137
2138         group = s->pending_groups[group_id];
2139
2140         /* Look for this member in the group and remove it, if found. */
2141         TAILQ_FOREACH(m, &group->members, node)
2142                 if (m->member_id == member_id) {
2143                         TAILQ_REMOVE(&group->members, m, node);
2144                         free(m);
2145                         return 0;
2146                 }
2147
2148         return 0;
2149 }
2150
2151 static int
2152 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2153 {
2154         struct selector *s = &ctl->selectors[selector_id];
2155         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2156         uint32_t group_id;
2157
2158         /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2159          * mirror copy (ts_next->obj).
2160          */
2161         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2162                 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2163                 int status;
2164
2165                 /* Skip this group if no change needed. */
2166                 if (!group)
2167                         continue;
2168
2169                 /* Apply the pending changes for the current group. */
2170                 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2171                 if (status)
2172                         return status;
2173         }
2174
2175         return 0;
2176 }
2177
2178 static void
2179 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2180 {
2181         struct selector *s = &ctl->selectors[selector_id];
2182         uint32_t group_id;
2183
2184         /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2185          * records (s->groups[group_id).
2186          */
2187         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2188                 struct rte_swx_table_selector_group *g = s->groups[group_id];
2189                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2190
2191                 /* Skip this group if no change needed. */
2192                 if (!gp)
2193                         continue;
2194
2195                 /* Transition the pending changes to stable. */
2196                 s->groups[group_id] = gp;
2197                 s->pending_groups[group_id] = NULL;
2198
2199                 /* Free the old group member list. */
2200                 if (!g)
2201                         continue;
2202
2203                 for ( ; ; ) {
2204                         struct rte_swx_table_selector_member *m;
2205
2206                         m = TAILQ_FIRST(&g->members);
2207                         if (!m)
2208                                 break;
2209
2210                         TAILQ_REMOVE(&g->members, m, node);
2211                         free(m);
2212                 }
2213
2214                 free(g);
2215         }
2216
2217         /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2218          * s->groups_added[group_id].
2219          */
2220         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2221                 if (s->groups_pending_delete[group_id]) {
2222                         s->groups_added[group_id] = 0;
2223                         s->groups_pending_delete[group_id] = 0;
2224                 }
2225 }
2226
2227 static void
2228 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2229 {
2230         struct selector *s = &ctl->selectors[selector_id];
2231         struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2232         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2233         uint32_t group_id;
2234
2235         /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2236         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2237                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2238
2239                 if (gp) {
2240                         ts_next->obj = ts->obj;
2241                         break;
2242                 }
2243         }
2244 }
2245
2246 static void
2247 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2248 {
2249         struct selector *s = &ctl->selectors[selector_id];
2250         uint32_t group_id;
2251
2252         /* Discard any pending group member changes (s->pending_groups[group_id]). */
2253         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2254                 selector_pending_group_members_free(s, group_id);
2255
2256         /* Discard any pending group deletions. */
2257         memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2258 }
2259
2260 static struct rte_swx_table_entry *
2261 learner_default_entry_alloc(struct learner *l)
2262 {
2263         struct rte_swx_table_entry *entry;
2264
2265         entry = calloc(1, sizeof(struct rte_swx_table_entry));
2266         if (!entry)
2267                 goto error;
2268
2269         /* action_data. */
2270         if (l->action_data_size) {
2271                 entry->action_data = calloc(1, l->action_data_size);
2272                 if (!entry->action_data)
2273                         goto error;
2274         }
2275
2276         return entry;
2277
2278 error:
2279         table_entry_free(entry);
2280         return NULL;
2281 }
2282
2283 static int
2284 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2285                             uint32_t learner_id,
2286                             struct rte_swx_table_entry *entry)
2287 {
2288         struct learner *l = &ctl->learners[learner_id];
2289         struct action *a;
2290         uint32_t i;
2291
2292         CHECK(entry, EINVAL);
2293
2294         /* action_id. */
2295         for (i = 0; i < l->info.n_actions; i++)
2296                 if (entry->action_id == l->actions[i].action_id)
2297                         break;
2298
2299         CHECK(i < l->info.n_actions, EINVAL);
2300
2301         /* action_data. */
2302         a = &ctl->actions[entry->action_id];
2303         CHECK(!(a->data_size && !entry->action_data), EINVAL);
2304
2305         return 0;
2306 }
2307
2308 static struct rte_swx_table_entry *
2309 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2310                                 uint32_t learner_id,
2311                                 struct rte_swx_table_entry *entry)
2312 {
2313         struct learner *l = &ctl->learners[learner_id];
2314         struct rte_swx_table_entry *new_entry = NULL;
2315         struct action *a;
2316         uint32_t i;
2317
2318         if (!entry)
2319                 goto error;
2320
2321         new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2322         if (!new_entry)
2323                 goto error;
2324
2325         /* action_id. */
2326         for (i = 0; i < l->info.n_actions; i++)
2327                 if (entry->action_id == l->actions[i].action_id)
2328                         break;
2329
2330         if (i >= l->info.n_actions)
2331                 goto error;
2332
2333         new_entry->action_id = entry->action_id;
2334
2335         /* action_data. */
2336         a = &ctl->actions[entry->action_id];
2337         if (a->data_size && !entry->action_data)
2338                 goto error;
2339
2340         /* The table layer provisions a constant action data size per
2341          * entry, which should be the largest data size for all the
2342          * actions enabled for the current table, and attempts to copy
2343          * this many bytes each time a table entry is added, even if the
2344          * specific action requires less data or even no data at all,
2345          * hence we always have to allocate the max.
2346          */
2347         new_entry->action_data = calloc(1, l->action_data_size);
2348         if (!new_entry->action_data)
2349                 goto error;
2350
2351         if (a->data_size)
2352                 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2353
2354         return new_entry;
2355
2356 error:
2357         table_entry_free(new_entry);
2358         return NULL;
2359 }
2360
2361 int
2362 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2363                                                const char *learner_name,
2364                                                struct rte_swx_table_entry *entry)
2365 {
2366         struct learner *l;
2367         struct rte_swx_table_entry *new_entry;
2368         uint32_t learner_id;
2369
2370         CHECK(ctl, EINVAL);
2371
2372         CHECK(learner_name && learner_name[0], EINVAL);
2373         l = learner_find(ctl, learner_name);
2374         CHECK(l, EINVAL);
2375         learner_id = l - ctl->learners;
2376         CHECK(!l->info.default_action_is_const, EINVAL);
2377
2378         CHECK(entry, EINVAL);
2379         CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2380
2381         new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2382         CHECK(new_entry, ENOMEM);
2383
2384         learner_pending_default_free(l);
2385
2386         l->pending_default = new_entry;
2387         return 0;
2388 }
2389
2390 static void
2391 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2392 {
2393         struct learner *l = &ctl->learners[learner_id];
2394         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2395                 ctl->info.n_selectors + learner_id];
2396         struct action *a;
2397         uint8_t *action_data;
2398         uint64_t action_id;
2399
2400         /* Copy the pending default entry. */
2401         if (!l->pending_default)
2402                 return;
2403
2404         action_id = l->pending_default->action_id;
2405         action_data = l->pending_default->action_data;
2406         a = &ctl->actions[action_id];
2407
2408         if (a->data_size)
2409                 memcpy(ts_next->default_action_data, action_data, a->data_size);
2410
2411         ts_next->default_action_id = action_id;
2412 }
2413
2414 static void
2415 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2416 {
2417         struct learner *l = &ctl->learners[learner_id];
2418
2419         /* Free up the pending default entry, as it is now part of the table. */
2420         learner_pending_default_free(l);
2421 }
2422
2423 static void
2424 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2425 {
2426         struct learner *l = &ctl->learners[learner_id];
2427
2428         /* Free up the pending default entry, as it is no longer going to be added to the table. */
2429         learner_pending_default_free(l);
2430 }
2431
2432 int
2433 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2434 {
2435         struct rte_swx_table_state *ts;
2436         int status = 0;
2437         uint32_t i;
2438
2439         CHECK(ctl, EINVAL);
2440
2441         /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2442          * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2443          * We must be able to fully revert all the changes that can fail as if they never happened.
2444          */
2445         for (i = 0; i < ctl->info.n_tables; i++) {
2446                 status = table_rollfwd0(ctl, i, 0);
2447                 if (status)
2448                         goto rollback;
2449         }
2450
2451         for (i = 0; i < ctl->info.n_selectors; i++) {
2452                 status = selector_rollfwd(ctl, i);
2453                 if (status)
2454                         goto rollback;
2455         }
2456
2457         /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2458          * onwards, the transaction is guaranteed to be successful.
2459          */
2460         for (i = 0; i < ctl->info.n_tables; i++)
2461                 table_rollfwd1(ctl, i);
2462
2463         for (i = 0; i < ctl->info.n_learners; i++)
2464                 learner_rollfwd(ctl, i);
2465
2466         /* Swap the table state for the data plane. The current ts and ts_next
2467          * become the new ts_next and ts, respectively.
2468          */
2469         rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2470         usleep(100);
2471         ts = ctl->ts;
2472         ctl->ts = ctl->ts_next;
2473         ctl->ts_next = ts;
2474
2475         /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2476          * the current ts_next in sync with the current ts. Since the changes that can fail did
2477          * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2478          * current ts_next, hence no error checking is needed.
2479          */
2480         for (i = 0; i < ctl->info.n_tables; i++) {
2481                 table_rollfwd0(ctl, i, 1);
2482                 table_rollfwd1(ctl, i);
2483                 table_rollfwd2(ctl, i);
2484         }
2485
2486         for (i = 0; i < ctl->info.n_selectors; i++) {
2487                 selector_rollfwd(ctl, i);
2488                 selector_rollfwd_finalize(ctl, i);
2489         }
2490
2491         for (i = 0; i < ctl->info.n_learners; i++) {
2492                 learner_rollfwd(ctl, i);
2493                 learner_rollfwd_finalize(ctl, i);
2494         }
2495
2496         return 0;
2497
2498 rollback:
2499         for (i = 0; i < ctl->info.n_tables; i++) {
2500                 table_rollback(ctl, i);
2501                 if (abort_on_fail)
2502                         table_abort(ctl, i);
2503         }
2504
2505         for (i = 0; i < ctl->info.n_selectors; i++) {
2506                 selector_rollback(ctl, i);
2507                 if (abort_on_fail)
2508                         selector_abort(ctl, i);
2509         }
2510
2511         if (abort_on_fail)
2512                 for (i = 0; i < ctl->info.n_learners; i++)
2513                         learner_abort(ctl, i);
2514
2515         return status;
2516 }
2517
2518 void
2519 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2520 {
2521         uint32_t i;
2522
2523         if (!ctl)
2524                 return;
2525
2526         for (i = 0; i < ctl->info.n_tables; i++)
2527                 table_abort(ctl, i);
2528
2529         for (i = 0; i < ctl->info.n_selectors; i++)
2530                 selector_abort(ctl, i);
2531
2532         for (i = 0; i < ctl->info.n_learners; i++)
2533                 learner_abort(ctl, i);
2534 }
2535
2536 static int
2537 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2538 {
2539         uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2540
2541         if (!mask) {
2542                 *prefix_length = 0;
2543                 return 0;
2544         }
2545
2546         /* Count trailing zero bits. */
2547         for (i = 0; i < 64; i++) {
2548                 if (mask & (1LLU << i))
2549                         break;
2550
2551                 n_trailing_zeros++;
2552         }
2553
2554         /* Count the one bits that follow. */
2555         for ( ; i < 64; i++) {
2556                 if (!(mask & (1LLU << i)))
2557                         break;
2558
2559                 n_ones++;
2560         }
2561
2562         /* Check that no more one bits are present */
2563         for ( ; i < 64; i++)
2564                 if (mask & (1LLU << i))
2565                         return -EINVAL;
2566
2567         /* Check that the input mask is a prefix or the right length. */
2568         if (n_ones + n_trailing_zeros != mask_length)
2569                 return -EINVAL;
2570
2571         *prefix_length = n_ones;
2572         return 0;
2573 }
2574
2575 static int
2576 token_is_comment(const char *token)
2577 {
2578         if ((token[0] == '#') ||
2579             (token[0] == ';') ||
2580             ((token[0] == '/') && (token[1] == '/')))
2581                 return 1; /* TRUE. */
2582
2583         return 0; /* FALSE. */
2584 }
2585
2586 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2587
2588 struct rte_swx_table_entry *
2589 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2590                                       const char *table_name,
2591                                       const char *string,
2592                                       int *is_blank_or_comment)
2593 {
2594         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2595         struct table *table;
2596         struct action *action;
2597         struct rte_swx_table_entry *entry = NULL;
2598         char *s0 = NULL, *s;
2599         uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2600         int lpm = 0, blank_or_comment = 0;
2601
2602         /* Check input arguments. */
2603         if (!ctl)
2604                 goto error;
2605
2606         if (!table_name || !table_name[0])
2607                 goto error;
2608
2609         table = table_find(ctl, table_name);
2610         if (!table)
2611                 goto error;
2612
2613         if (!string || !string[0])
2614                 goto error;
2615
2616         /* Memory allocation. */
2617         s0 = strdup(string);
2618         if (!s0)
2619                 goto error;
2620
2621         entry = table_entry_alloc(table);
2622         if (!entry)
2623                 goto error;
2624
2625         /* Parse the string into tokens. */
2626         for (s = s0; ; ) {
2627                 char *token;
2628
2629                 token = strtok_r(s, " \f\n\r\t\v", &s);
2630                 if (!token || token_is_comment(token))
2631                         break;
2632
2633                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2634                         goto error;
2635
2636                 token_array[n_tokens] = token;
2637                 n_tokens++;
2638         }
2639
2640         if (!n_tokens) {
2641                 blank_or_comment = 1;
2642                 goto error;
2643         }
2644
2645         tokens = token_array;
2646
2647         /*
2648          * Match.
2649          */
2650         if (!(n_tokens && !strcmp(tokens[0], "match")))
2651                 goto action;
2652
2653         if (n_tokens < 1 + table->info.n_match_fields)
2654                 goto error;
2655
2656         for (i = 0; i < table->info.n_match_fields; i++) {
2657                 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2658                 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2659                 uint64_t val, mask = UINT64_MAX;
2660                 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2661
2662                 /*
2663                  * Mask.
2664                  */
2665                 mf_mask = strchr(mf_val, '/');
2666                 if (mf_mask) {
2667                         *mf_mask = 0;
2668                         mf_mask++;
2669
2670                         /* Parse. */
2671                         mask = strtoull(mf_mask, &mf_mask, 0);
2672                         if (mf_mask[0])
2673                                 goto error;
2674
2675                         /* LPM. */
2676                         if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2677                                 int status;
2678
2679                                 lpm = 1;
2680
2681                                 lpm_prefix_length_max = mf->n_bits;
2682
2683                                 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2684                                 if (status)
2685                                         goto error;
2686                         }
2687
2688                         /* Endianness conversion. */
2689                         if (mf->is_header)
2690                                 mask = field_hton(mask, mf->n_bits);
2691                 }
2692
2693                 /* Copy to entry. */
2694                 if (entry->key_mask)
2695                         memcpy(&entry->key_mask[offset],
2696                                (uint8_t *)&mask,
2697                                mf->n_bits / 8);
2698
2699                 /*
2700                  * Value.
2701                  */
2702                 /* Parse. */
2703                 val = strtoull(mf_val, &mf_val, 0);
2704                 if (mf_val[0])
2705                         goto error;
2706
2707                 /* Endianness conversion. */
2708                 if (mf->is_header)
2709                         val = field_hton(val, mf->n_bits);
2710
2711                 /* Copy to entry. */
2712                 memcpy(&entry->key[offset],
2713                        (uint8_t *)&val,
2714                        mf->n_bits / 8);
2715         }
2716
2717         tokens += 1 + table->info.n_match_fields;
2718         n_tokens -= 1 + table->info.n_match_fields;
2719
2720         /*
2721          * Match priority.
2722          */
2723         if (n_tokens && !strcmp(tokens[0], "priority")) {
2724                 char *priority = tokens[1];
2725                 uint32_t val;
2726
2727                 if (n_tokens < 2)
2728                         goto error;
2729
2730                 /* Parse. */
2731                 val = strtoul(priority, &priority, 0);
2732                 if (priority[0])
2733                         goto error;
2734
2735                 /* Copy to entry. */
2736                 entry->key_priority = val;
2737
2738                 tokens += 2;
2739                 n_tokens -= 2;
2740         }
2741
2742         /* LPM. */
2743         if (lpm)
2744                 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2745
2746         /*
2747          * Action.
2748          */
2749 action:
2750         if (!(n_tokens && !strcmp(tokens[0], "action")))
2751                 goto other;
2752
2753         if (n_tokens < 2)
2754                 goto error;
2755
2756         action = action_find(ctl, tokens[1]);
2757         if (!action)
2758                 goto error;
2759
2760         if (n_tokens < 2 + action->info.n_args * 2)
2761                 goto error;
2762
2763         /* action_id. */
2764         entry->action_id = action - ctl->actions;
2765
2766         /* action_data. */
2767         for (i = 0; i < action->info.n_args; i++) {
2768                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2769                 char *arg_name, *arg_val;
2770                 uint64_t val;
2771
2772                 arg_name = tokens[2 + i * 2];
2773                 arg_val = tokens[2 + i * 2 + 1];
2774
2775                 if (strcmp(arg_name, arg->name))
2776                         goto error;
2777
2778                 val = strtoull(arg_val, &arg_val, 0);
2779                 if (arg_val[0])
2780                         goto error;
2781
2782                 /* Endianness conversion. */
2783                 if (arg->is_network_byte_order)
2784                         val = field_hton(val, arg->n_bits);
2785
2786                 /* Copy to entry. */
2787                 memcpy(&entry->action_data[arg_offset],
2788                        (uint8_t *)&val,
2789                        arg->n_bits / 8);
2790
2791                 arg_offset += arg->n_bits / 8;
2792         }
2793
2794         tokens += 2 + action->info.n_args * 2;
2795         n_tokens -= 2 + action->info.n_args * 2;
2796
2797 other:
2798         if (n_tokens)
2799                 goto error;
2800
2801         free(s0);
2802         return entry;
2803
2804 error:
2805         table_entry_free(entry);
2806         free(s0);
2807         if (is_blank_or_comment)
2808                 *is_blank_or_comment = blank_or_comment;
2809         return NULL;
2810 }
2811
2812 struct rte_swx_table_entry *
2813 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2814                                                 const char *learner_name,
2815                                                 const char *string,
2816                                                 int *is_blank_or_comment)
2817 {
2818         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2819         struct learner *l;
2820         struct action *action;
2821         struct rte_swx_table_entry *entry = NULL;
2822         char *s0 = NULL, *s;
2823         uint32_t n_tokens = 0, arg_offset = 0, i;
2824         int blank_or_comment = 0;
2825
2826         /* Check input arguments. */
2827         if (!ctl)
2828                 goto error;
2829
2830         if (!learner_name || !learner_name[0])
2831                 goto error;
2832
2833         l = learner_find(ctl, learner_name);
2834         if (!l)
2835                 goto error;
2836
2837         if (!string || !string[0])
2838                 goto error;
2839
2840         /* Memory allocation. */
2841         s0 = strdup(string);
2842         if (!s0)
2843                 goto error;
2844
2845         entry = learner_default_entry_alloc(l);
2846         if (!entry)
2847                 goto error;
2848
2849         /* Parse the string into tokens. */
2850         for (s = s0; ; ) {
2851                 char *token;
2852
2853                 token = strtok_r(s, " \f\n\r\t\v", &s);
2854                 if (!token || token_is_comment(token))
2855                         break;
2856
2857                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2858                         goto error;
2859
2860                 token_array[n_tokens] = token;
2861                 n_tokens++;
2862         }
2863
2864         if (!n_tokens) {
2865                 blank_or_comment = 1;
2866                 goto error;
2867         }
2868
2869         tokens = token_array;
2870
2871         /*
2872          * Action.
2873          */
2874         if (!(n_tokens && !strcmp(tokens[0], "action")))
2875                 goto other;
2876
2877         if (n_tokens < 2)
2878                 goto error;
2879
2880         action = action_find(ctl, tokens[1]);
2881         if (!action)
2882                 goto error;
2883
2884         if (n_tokens < 2 + action->info.n_args * 2)
2885                 goto error;
2886
2887         /* action_id. */
2888         entry->action_id = action - ctl->actions;
2889
2890         /* action_data. */
2891         for (i = 0; i < action->info.n_args; i++) {
2892                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2893                 char *arg_name, *arg_val;
2894                 uint64_t val;
2895
2896                 arg_name = tokens[2 + i * 2];
2897                 arg_val = tokens[2 + i * 2 + 1];
2898
2899                 if (strcmp(arg_name, arg->name))
2900                         goto error;
2901
2902                 val = strtoull(arg_val, &arg_val, 0);
2903                 if (arg_val[0])
2904                         goto error;
2905
2906                 /* Endianness conversion. */
2907                 if (arg->is_network_byte_order)
2908                         val = field_hton(val, arg->n_bits);
2909
2910                 /* Copy to entry. */
2911                 memcpy(&entry->action_data[arg_offset],
2912                        (uint8_t *)&val,
2913                        arg->n_bits / 8);
2914
2915                 arg_offset += arg->n_bits / 8;
2916         }
2917
2918         tokens += 2 + action->info.n_args * 2;
2919         n_tokens -= 2 + action->info.n_args * 2;
2920
2921 other:
2922         if (n_tokens)
2923                 goto error;
2924
2925         free(s0);
2926         return entry;
2927
2928 error:
2929         table_entry_free(entry);
2930         free(s0);
2931         if (is_blank_or_comment)
2932                 *is_blank_or_comment = blank_or_comment;
2933         return NULL;
2934 }
2935
2936 static void
2937 table_entry_printf(FILE *f,
2938                    struct rte_swx_ctl_pipeline *ctl,
2939                    struct table *table,
2940                    struct rte_swx_table_entry *entry)
2941 {
2942         struct action *action = &ctl->actions[entry->action_id];
2943         uint32_t i;
2944
2945         fprintf(f, "match ");
2946         for (i = 0; i < table->params.key_size; i++)
2947                 fprintf(f, "%02x", entry->key[i]);
2948
2949         if (entry->key_mask) {
2950                 fprintf(f, "/");
2951                 for (i = 0; i < table->params.key_size; i++)
2952                         fprintf(f, "%02x", entry->key_mask[i]);
2953         }
2954
2955         fprintf(f, " priority %u", entry->key_priority);
2956
2957         fprintf(f, " action %s ", action->info.name);
2958         for (i = 0; i < action->data_size; i++)
2959                 fprintf(f, "%02x", entry->action_data[i]);
2960
2961         fprintf(f, "\n");
2962 }
2963
2964 int
2965 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2966                                    struct rte_swx_ctl_pipeline *ctl,
2967                                    const char *table_name)
2968 {
2969         struct table *table;
2970         struct rte_swx_table_entry *entry;
2971         uint32_t n_entries = 0, i;
2972
2973         if (!f || !ctl || !table_name || !table_name[0])
2974                 return -EINVAL;
2975
2976         table = table_find(ctl, table_name);
2977         if (!table)
2978                 return -EINVAL;
2979
2980         /* Table. */
2981         fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2982                 table->info.name,
2983                 table->params.key_size,
2984                 table->params.key_offset);
2985
2986         for (i = 0; i < table->params.key_size; i++)
2987                 fprintf(f, "%02x", table->params.key_mask0[i]);
2988
2989         fprintf(f, "], action data size %u bytes\n",
2990                 table->params.action_data_size);
2991
2992         /* Table entries. */
2993         TAILQ_FOREACH(entry, &table->entries, node) {
2994                 table_entry_printf(f, ctl, table, entry);
2995                 n_entries++;
2996         }
2997
2998         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2999                 table_entry_printf(f, ctl, table, entry);
3000                 n_entries++;
3001         }
3002
3003         TAILQ_FOREACH(entry, &table->pending_delete, node) {
3004                 table_entry_printf(f, ctl, table, entry);
3005                 n_entries++;
3006         }
3007
3008         fprintf(f, "# Table %s currently has %u entries.\n",
3009                 table_name,
3010                 n_entries);
3011         return 0;
3012 }
3013
3014 int
3015 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3016                                       struct rte_swx_ctl_pipeline *ctl,
3017                                       const char *selector_name)
3018 {
3019         struct selector *s;
3020         uint32_t group_id;
3021
3022         if (!f || !ctl || !selector_name || !selector_name[0])
3023                 return -EINVAL;
3024
3025         s = selector_find(ctl, selector_name);
3026         if (!s)
3027                 return -EINVAL;
3028
3029         /* Selector. */
3030         fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3031                 s->info.name,
3032                 s->info.n_groups_max,
3033                 s->info.n_members_per_group_max);
3034
3035         /* Groups. */
3036         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3037                 struct rte_swx_table_selector_group *group = s->groups[group_id];
3038                 struct rte_swx_table_selector_member *m;
3039                 uint32_t n_members = 0;
3040
3041                 fprintf(f, "Group %u = [", group_id);
3042
3043                 /* Non-empty group. */
3044                 if (group)
3045                         TAILQ_FOREACH(m, &group->members, node) {
3046                                 fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3047                                 n_members++;
3048                         }
3049
3050                 /* Empty group. */
3051                 if (!n_members)
3052                         fprintf(f, "0:1 ");
3053
3054                 fprintf(f, "]\n");
3055         }
3056
3057         return 0;
3058 }