pipeline: fix selector freeing
[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 rte_swx_ctl_pipeline {
127         struct rte_swx_ctl_pipeline_info info;
128         struct rte_swx_pipeline *p;
129         struct action *actions;
130         struct table *tables;
131         struct selector *selectors;
132         struct rte_swx_table_state *ts;
133         struct rte_swx_table_state *ts_next;
134         int numa_node;
135 };
136
137 static struct action *
138 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
139 {
140         uint32_t i;
141
142         for (i = 0; i < ctl->info.n_actions; i++) {
143                 struct action *a = &ctl->actions[i];
144
145                 if (!strcmp(action_name, a->info.name))
146                         return a;
147         }
148
149         return NULL;
150 }
151
152 static void
153 action_free(struct rte_swx_ctl_pipeline *ctl)
154 {
155         uint32_t i;
156
157         if (!ctl->actions)
158                 return;
159
160         for (i = 0; i < ctl->info.n_actions; i++) {
161                 struct action *action = &ctl->actions[i];
162
163                 free(action->args);
164         }
165
166         free(ctl->actions);
167         ctl->actions = NULL;
168 }
169
170 static struct table *
171 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
172 {
173         uint32_t i;
174
175         for (i = 0; i < ctl->info.n_tables; i++) {
176                 struct table *table = &ctl->tables[i];
177
178                 if (!strcmp(table_name, table->info.name))
179                         return table;
180         }
181
182         return NULL;
183 }
184
185 static int
186 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
187 {
188         struct table *table = &ctl->tables[table_id];
189         struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
190         uint8_t *key_mask = NULL;
191         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
192         uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
193
194         if (table->info.n_match_fields) {
195                 uint32_t n_match_fields_em = 0, i;
196
197                 /* Find first (smallest offset) and last (biggest offset) match fields. */
198                 first = &table->mf[0];
199                 last = &table->mf[0];
200
201                 for (i = 1; i < table->info.n_match_fields; i++) {
202                         struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
203
204                         if (f->offset < first->offset)
205                                 first = f;
206
207                         if (f->offset > last->offset)
208                                 last = f;
209                 }
210
211                 /* match_type. */
212                 for (i = 0; i < table->info.n_match_fields; i++) {
213                         struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
214
215                         if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
216                                 n_match_fields_em++;
217                 }
218
219                 if (n_match_fields_em == table->info.n_match_fields)
220                         match_type = RTE_SWX_TABLE_MATCH_EXACT;
221
222                 /* key_offset. */
223                 key_offset = first->offset / 8;
224
225                 /* key_size. */
226                 key_size = (last->offset + last->n_bits - first->offset) / 8;
227
228                 /* key_mask. */
229                 key_mask = calloc(1, key_size);
230                 CHECK(key_mask, ENOMEM);
231
232                 for (i = 0; i < table->info.n_match_fields; i++) {
233                         struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
234                         uint32_t start;
235                         size_t size;
236
237                         start = (f->offset - first->offset) / 8;
238                         size = f->n_bits / 8;
239
240                         memset(&key_mask[start], 0xFF, size);
241                 }
242         }
243
244         /* action_data_size. */
245         for (i = 0; i < table->info.n_actions; i++) {
246                 uint32_t action_id = table->actions[i].action_id;
247                 struct action *a = &ctl->actions[action_id];
248
249                 if (a->data_size > action_data_size)
250                         action_data_size = a->data_size;
251         }
252
253         /* Fill in. */
254         table->params.match_type = match_type;
255         table->params.key_size = key_size;
256         table->params.key_offset = key_offset;
257         table->params.key_mask0 = key_mask;
258         table->params.action_data_size = action_data_size;
259         table->params.n_keys_max = table->info.size;
260
261         table->mf_first = first;
262         table->mf_last = last;
263
264         return 0;
265 }
266
267 static void
268 table_entry_free(struct rte_swx_table_entry *entry)
269 {
270         if (!entry)
271                 return;
272
273         free(entry->key);
274         free(entry->key_mask);
275         free(entry->action_data);
276         free(entry);
277 }
278
279 static struct rte_swx_table_entry *
280 table_entry_alloc(struct table *table)
281 {
282         struct rte_swx_table_entry *entry;
283
284         entry = calloc(1, sizeof(struct rte_swx_table_entry));
285         if (!entry)
286                 goto error;
287
288         /* key, key_mask. */
289         if (!table->is_stub) {
290                 entry->key = calloc(1, table->params.key_size);
291                 if (!entry->key)
292                         goto error;
293
294                 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
295                         entry->key_mask = calloc(1, table->params.key_size);
296                         if (!entry->key_mask)
297                                 goto error;
298                 }
299         }
300
301         /* action_data. */
302         if (table->params.action_data_size) {
303                 entry->action_data = calloc(1, table->params.action_data_size);
304                 if (!entry->action_data)
305                         goto error;
306         }
307
308         return entry;
309
310 error:
311         table_entry_free(entry);
312         return NULL;
313 }
314
315 static int
316 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
317 {
318         uint8_t *key_mask0 = table->params.key_mask0;
319         uint32_t key_size = table->params.key_size, i;
320
321         if (!entry->key_mask)
322                 return 0;
323
324         for (i = 0; i < key_size; i++) {
325                 uint8_t km0 = key_mask0[i];
326                 uint8_t km = entry->key_mask[i];
327
328                 if ((km & km0) != km0)
329                         return -EINVAL;
330         }
331
332         return 0;
333 }
334
335 static int
336 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
337                   uint32_t table_id,
338                   struct rte_swx_table_entry *entry,
339                   int key_check,
340                   int data_check)
341 {
342         struct table *table = &ctl->tables[table_id];
343         int status;
344
345         CHECK(entry, EINVAL);
346
347         if (key_check && !table->is_stub) {
348                 /* key. */
349                 CHECK(entry->key, EINVAL);
350
351                 /* key_mask. */
352                 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
353                         status = table_entry_key_check_em(table, entry);
354                         if (status)
355                                 return status;
356                 }
357         }
358
359         if (data_check) {
360                 struct action *a;
361                 uint32_t i;
362
363                 /* action_id. */
364                 for (i = 0; i < table->info.n_actions; i++)
365                         if (entry->action_id == table->actions[i].action_id)
366                                 break;
367
368                 CHECK(i < table->info.n_actions, EINVAL);
369
370                 /* action_data. */
371                 a = &ctl->actions[entry->action_id];
372                 CHECK(!(a->data_size && !entry->action_data), EINVAL);
373         }
374
375         return 0;
376 }
377
378 static struct rte_swx_table_entry *
379 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
380                       uint32_t table_id,
381                       struct rte_swx_table_entry *entry,
382                       int key_duplicate,
383                       int data_duplicate)
384 {
385         struct table *table = &ctl->tables[table_id];
386         struct rte_swx_table_entry *new_entry = NULL;
387
388         if (!entry)
389                 goto error;
390
391         new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
392         if (!new_entry)
393                 goto error;
394
395         if (key_duplicate && !table->is_stub) {
396                 /* key. */
397                 if (!entry->key)
398                         goto error;
399
400                 new_entry->key = malloc(table->params.key_size);
401                 if (!new_entry->key)
402                         goto error;
403
404                 memcpy(new_entry->key, entry->key, table->params.key_size);
405
406                 /* key_signature. */
407                 new_entry->key_signature = entry->key_signature;
408
409                 /* key_mask. */
410                 if (entry->key_mask) {
411                         new_entry->key_mask = malloc(table->params.key_size);
412                         if (!new_entry->key_mask)
413                                 goto error;
414
415                         memcpy(new_entry->key_mask,
416                                entry->key_mask,
417                                table->params.key_size);
418                 }
419
420                 /* key_priority. */
421                 new_entry->key_priority = entry->key_priority;
422         }
423
424         if (data_duplicate) {
425                 struct action *a;
426                 uint32_t i;
427
428                 /* action_id. */
429                 for (i = 0; i < table->info.n_actions; i++)
430                         if (entry->action_id == table->actions[i].action_id)
431                                 break;
432
433                 if (i >= table->info.n_actions)
434                         goto error;
435
436                 new_entry->action_id = entry->action_id;
437
438                 /* action_data. */
439                 a = &ctl->actions[entry->action_id];
440                 if (a->data_size && !entry->action_data)
441                         goto error;
442
443                 /* The table layer provisions a constant action data size per
444                  * entry, which should be the largest data size for all the
445                  * actions enabled for the current table, and attempts to copy
446                  * this many bytes each time a table entry is added, even if the
447                  * specific action requires less data or even no data at all,
448                  * hence we always have to allocate the max.
449                  */
450                 new_entry->action_data = calloc(1, table->params.action_data_size);
451                 if (!new_entry->action_data)
452                         goto error;
453
454                 if (a->data_size)
455                         memcpy(new_entry->action_data,
456                                entry->action_data,
457                                a->data_size);
458         }
459
460         return new_entry;
461
462 error:
463         table_entry_free(new_entry);
464         return NULL;
465 }
466
467 static int
468 table_entry_keycmp(struct table *table,
469                    struct rte_swx_table_entry *e0,
470                    struct rte_swx_table_entry *e1)
471 {
472         uint32_t key_size = table->params.key_size;
473         uint32_t i;
474
475         for (i = 0; i < key_size; i++) {
476                 uint8_t *key_mask0 = table->params.key_mask0;
477                 uint8_t km0, km[2], k[2];
478
479                 km0 = key_mask0 ? key_mask0[i] : 0xFF;
480
481                 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
482                 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
483
484                 k[0] = e0->key[i];
485                 k[1] = e1->key[i];
486
487                 /* Mask comparison. */
488                 if ((km[0] & km0) != (km[1] & km0))
489                         return 1; /* Not equal. */
490
491                 /* Value comparison. */
492                 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
493                         return 1; /* Not equal. */
494         }
495
496         return 0; /* Equal. */
497 }
498
499 static struct rte_swx_table_entry *
500 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
501 {
502         struct rte_swx_table_entry *e;
503
504         TAILQ_FOREACH(e, &table->entries, node)
505                 if (!table_entry_keycmp(table, entry, e))
506                         return e; /* Found. */
507
508         return NULL; /* Not found. */
509 }
510
511 static void
512 table_entries_free(struct table *table)
513 {
514         for ( ; ; ) {
515                 struct rte_swx_table_entry *entry;
516
517                 entry = TAILQ_FIRST(&table->entries);
518                 if (!entry)
519                         break;
520
521                 TAILQ_REMOVE(&table->entries, entry, node);
522                 table_entry_free(entry);
523         }
524 }
525
526 static struct rte_swx_table_entry *
527 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
528 {
529         struct rte_swx_table_entry *e;
530
531         TAILQ_FOREACH(e, &table->pending_add, node)
532                 if (!table_entry_keycmp(table, entry, e))
533                         return e; /* Found. */
534
535         return NULL; /* Not found. */
536 }
537
538 static void
539 table_pending_add_admit(struct table *table)
540 {
541         TAILQ_CONCAT(&table->entries, &table->pending_add, node);
542 }
543
544 static void
545 table_pending_add_free(struct table *table)
546 {
547         for ( ; ; ) {
548                 struct rte_swx_table_entry *entry;
549
550                 entry = TAILQ_FIRST(&table->pending_add);
551                 if (!entry)
552                         break;
553
554                 TAILQ_REMOVE(&table->pending_add, entry, node);
555                 table_entry_free(entry);
556         }
557 }
558
559 static struct rte_swx_table_entry *
560 table_pending_modify0_find(struct table *table,
561                            struct rte_swx_table_entry *entry)
562 {
563         struct rte_swx_table_entry *e;
564
565         TAILQ_FOREACH(e, &table->pending_modify0, node)
566                 if (!table_entry_keycmp(table, entry, e))
567                         return e; /* Found. */
568
569         return NULL; /* Not found. */
570 }
571
572 static void
573 table_pending_modify0_admit(struct table *table)
574 {
575         TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
576 }
577
578 static void
579 table_pending_modify0_free(struct table *table)
580 {
581         for ( ; ; ) {
582                 struct rte_swx_table_entry *entry;
583
584                 entry = TAILQ_FIRST(&table->pending_modify0);
585                 if (!entry)
586                         break;
587
588                 TAILQ_REMOVE(&table->pending_modify0, entry, node);
589                 table_entry_free(entry);
590         }
591 }
592
593 static struct rte_swx_table_entry *
594 table_pending_modify1_find(struct table *table,
595                            struct rte_swx_table_entry *entry)
596 {
597         struct rte_swx_table_entry *e;
598
599         TAILQ_FOREACH(e, &table->pending_modify1, node)
600                 if (!table_entry_keycmp(table, entry, e))
601                         return e; /* Found. */
602
603         return NULL; /* Not found. */
604 }
605
606 static void
607 table_pending_modify1_admit(struct table *table)
608 {
609         TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
610 }
611
612 static void
613 table_pending_modify1_free(struct table *table)
614 {
615         for ( ; ; ) {
616                 struct rte_swx_table_entry *entry;
617
618                 entry = TAILQ_FIRST(&table->pending_modify1);
619                 if (!entry)
620                         break;
621
622                 TAILQ_REMOVE(&table->pending_modify1, entry, node);
623                 table_entry_free(entry);
624         }
625 }
626
627 static struct rte_swx_table_entry *
628 table_pending_delete_find(struct table *table,
629                           struct rte_swx_table_entry *entry)
630 {
631         struct rte_swx_table_entry *e;
632
633         TAILQ_FOREACH(e, &table->pending_delete, node)
634                 if (!table_entry_keycmp(table, entry, e))
635                         return e; /* Found. */
636
637         return NULL; /* Not found. */
638 }
639
640 static void
641 table_pending_delete_admit(struct table *table)
642 {
643         TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
644 }
645
646 static void
647 table_pending_delete_free(struct table *table)
648 {
649         for ( ; ; ) {
650                 struct rte_swx_table_entry *entry;
651
652                 entry = TAILQ_FIRST(&table->pending_delete);
653                 if (!entry)
654                         break;
655
656                 TAILQ_REMOVE(&table->pending_delete, entry, node);
657                 table_entry_free(entry);
658         }
659 }
660
661 static void
662 table_pending_default_free(struct table *table)
663 {
664         if (!table->pending_default)
665                 return;
666
667         free(table->pending_default->action_data);
668         free(table->pending_default);
669         table->pending_default = NULL;
670 }
671
672 static int
673 table_is_update_pending(struct table *table, int consider_pending_default)
674 {
675         struct rte_swx_table_entry *e;
676         uint32_t n = 0;
677
678         /* Pending add. */
679         TAILQ_FOREACH(e, &table->pending_add, node)
680                 n++;
681
682         /* Pending modify. */
683         TAILQ_FOREACH(e, &table->pending_modify1, node)
684                 n++;
685
686         /* Pending delete. */
687         TAILQ_FOREACH(e, &table->pending_delete, node)
688                 n++;
689
690         /* Pending default. */
691         if (consider_pending_default && table->pending_default)
692                 n++;
693
694         return n;
695 }
696
697 static void
698 table_free(struct rte_swx_ctl_pipeline *ctl)
699 {
700         uint32_t i;
701
702         if (!ctl->tables)
703                 return;
704
705         for (i = 0; i < ctl->info.n_tables; i++) {
706                 struct table *table = &ctl->tables[i];
707
708                 free(table->mf);
709                 free(table->actions);
710                 free(table->params.key_mask0);
711
712                 table_entries_free(table);
713                 table_pending_add_free(table);
714                 table_pending_modify0_free(table);
715                 table_pending_modify1_free(table);
716                 table_pending_delete_free(table);
717                 table_pending_default_free(table);
718         }
719
720         free(ctl->tables);
721         ctl->tables = NULL;
722 }
723
724 static void
725 selector_group_members_free(struct selector *s, uint32_t group_id)
726 {
727         struct rte_swx_table_selector_group *group = s->groups[group_id];
728
729         if (!group)
730                 return;
731
732         for ( ; ; ) {
733                 struct rte_swx_table_selector_member *m;
734
735                 m = TAILQ_FIRST(&group->members);
736                 if (!m)
737                         break;
738
739                 TAILQ_REMOVE(&group->members, m, node);
740                 free(m);
741         }
742
743         free(group);
744         s->groups[group_id] = NULL;
745 }
746
747 static void
748 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
749 {
750         struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
751
752         if (!group)
753                 return;
754
755         for ( ; ; ) {
756                 struct rte_swx_table_selector_member *m;
757
758                 m = TAILQ_FIRST(&group->members);
759                 if (!m)
760                         break;
761
762                 TAILQ_REMOVE(&group->members, m, node);
763                 free(m);
764         }
765
766         free(group);
767         s->pending_groups[group_id] = NULL;
768 }
769
770 static int
771 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
772 {
773         struct rte_swx_table_selector_group *g, *gp;
774         struct rte_swx_table_selector_member *m;
775
776         selector_pending_group_members_free(s, group_id);
777
778         g = s->groups[group_id];
779         gp = s->pending_groups[group_id];
780
781         if (!gp) {
782                 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
783                 if (!gp)
784                         goto error;
785
786                 TAILQ_INIT(&gp->members);
787
788                 s->pending_groups[group_id] = gp;
789         }
790
791         if (!g)
792                 return 0;
793
794         TAILQ_FOREACH(m, &g->members, node) {
795                 struct rte_swx_table_selector_member *mp;
796
797                 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
798                 if (!mp)
799                         goto error;
800
801                 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
802
803                 TAILQ_INSERT_TAIL(&gp->members, mp, node);
804         }
805
806         return 0;
807
808 error:
809         selector_pending_group_members_free(s, group_id);
810         return -ENOMEM;
811 }
812
813 static void
814 selector_free(struct rte_swx_ctl_pipeline *ctl)
815 {
816         uint32_t i;
817
818         if (!ctl->selectors)
819                 return;
820
821         for (i = 0; i < ctl->info.n_selectors; i++) {
822                 struct selector *s = &ctl->selectors[i];
823                 uint32_t i;
824
825                 /* selector_fields. */
826                 free(s->selector_fields);
827
828                 /* groups. */
829                 if (s->groups)
830                         for (i = 0; i < s->info.n_groups_max; i++)
831                                 selector_group_members_free(s, i);
832
833                 free(s->groups);
834
835                 /* pending_groups. */
836                 if (s->pending_groups)
837                         for (i = 0; i < s->info.n_groups_max; i++)
838                                 selector_pending_group_members_free(s, i);
839
840                 free(s->pending_groups);
841
842                 /* groups_added. */
843                 free(s->groups_added);
844
845                 /* groups_pending_delete. */
846                 free(s->groups_pending_delete);
847
848                 /* params. */
849                 free(s->params.selector_mask);
850         }
851
852         free(ctl->selectors);
853         ctl->selectors = NULL;
854 }
855
856 static struct selector *
857 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
858 {
859         uint32_t i;
860
861         for (i = 0; i < ctl->info.n_selectors; i++) {
862                 struct selector *s = &ctl->selectors[i];
863
864                 if (!strcmp(selector_name, s->info.name))
865                         return s;
866         }
867
868         return NULL;
869 }
870
871 static int
872 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
873 {
874         struct selector *s = &ctl->selectors[selector_id];
875         struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
876         uint8_t *selector_mask = NULL;
877         uint32_t selector_size = 0, selector_offset = 0, i;
878
879         /* Find first (smallest offset) and last (biggest offset) match fields. */
880         first = &s->selector_fields[0];
881         last = &s->selector_fields[0];
882
883         for (i = 1; i < s->info.n_selector_fields; i++) {
884                 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
885
886                 if (f->offset < first->offset)
887                         first = f;
888
889                 if (f->offset > last->offset)
890                         last = f;
891         }
892
893         /* selector_offset. */
894         selector_offset = first->offset / 8;
895
896         /* selector_size. */
897         selector_size = (last->offset + last->n_bits - first->offset) / 8;
898
899         /* selector_mask. */
900         selector_mask = calloc(1, selector_size);
901         if (!selector_mask)
902                 return -ENOMEM;
903
904         for (i = 0; i < s->info.n_selector_fields; i++) {
905                 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
906                 uint32_t start;
907                 size_t size;
908
909                 start = (f->offset - first->offset) / 8;
910                 size = f->n_bits / 8;
911
912                 memset(&selector_mask[start], 0xFF, size);
913         }
914
915         /* Fill in. */
916         s->params.group_id_offset = s->group_id_field.offset / 8;
917         s->params.selector_size = selector_size;
918         s->params.selector_offset = selector_offset;
919         s->params.selector_mask = selector_mask;
920         s->params.member_id_offset = s->member_id_field.offset / 8;
921         s->params.n_groups_max = s->info.n_groups_max;
922         s->params.n_members_per_group_max = s->info.n_members_per_group_max;
923
924         return 0;
925 }
926
927 static void
928 table_state_free(struct rte_swx_ctl_pipeline *ctl)
929 {
930         uint32_t i;
931
932         if (!ctl->ts_next)
933                 return;
934
935         /* For each table, free its table state. */
936         for (i = 0; i < ctl->info.n_tables; i++) {
937                 struct table *table = &ctl->tables[i];
938                 struct rte_swx_table_state *ts = &ctl->ts_next[i];
939
940                 /* Default action data. */
941                 free(ts->default_action_data);
942
943                 /* Table object. */
944                 if (!table->is_stub && table->ops.free && ts->obj)
945                         table->ops.free(ts->obj);
946         }
947
948         /* For each selector table, free its table state. */
949         for (i = 0; i < ctl->info.n_selectors; i++) {
950                 struct rte_swx_table_state *ts = &ctl->ts_next[i];
951
952                 /* Table object. */
953                 if (ts->obj)
954                         rte_swx_table_selector_free(ts->obj);
955         }
956
957         free(ctl->ts_next);
958         ctl->ts_next = NULL;
959 }
960
961 static int
962 table_state_create(struct rte_swx_ctl_pipeline *ctl)
963 {
964         int status = 0;
965         uint32_t i;
966
967         ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
968                               sizeof(struct rte_swx_table_state));
969         if (!ctl->ts_next) {
970                 status = -ENOMEM;
971                 goto error;
972         }
973
974         /* Tables. */
975         for (i = 0; i < ctl->info.n_tables; i++) {
976                 struct table *table = &ctl->tables[i];
977                 struct rte_swx_table_state *ts = &ctl->ts[i];
978                 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
979
980                 /* Table object. */
981                 if (!table->is_stub && table->ops.add) {
982                         ts_next->obj = table->ops.create(&table->params,
983                                                          &table->entries,
984                                                          table->info.args,
985                                                          ctl->numa_node);
986                         if (!ts_next->obj) {
987                                 status = -ENODEV;
988                                 goto error;
989                         }
990                 }
991
992                 if (!table->is_stub && !table->ops.add)
993                         ts_next->obj = ts->obj;
994
995                 /* Default action data: duplicate from current table state. */
996                 ts_next->default_action_data =
997                         malloc(table->params.action_data_size);
998                 if (!ts_next->default_action_data) {
999                         status = -ENOMEM;
1000                         goto error;
1001                 }
1002
1003                 memcpy(ts_next->default_action_data,
1004                        ts->default_action_data,
1005                        table->params.action_data_size);
1006
1007                 ts_next->default_action_id = ts->default_action_id;
1008         }
1009
1010         /* Selector tables. */
1011         for (i = 0; i < ctl->info.n_selectors; i++) {
1012                 struct selector *s = &ctl->selectors[i];
1013                 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
1014
1015                 /* Table object. */
1016                 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1017                 if (!ts_next->obj) {
1018                         status = -ENODEV;
1019                         goto error;
1020                 }
1021         }
1022
1023         return 0;
1024
1025 error:
1026         table_state_free(ctl);
1027         return status;
1028 }
1029
1030 void
1031 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1032 {
1033         if (!ctl)
1034                 return;
1035
1036         action_free(ctl);
1037
1038         table_state_free(ctl);
1039
1040         selector_free(ctl);
1041
1042         table_free(ctl);
1043
1044         free(ctl);
1045 }
1046
1047 struct rte_swx_ctl_pipeline *
1048 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1049 {
1050         struct rte_swx_ctl_pipeline *ctl = NULL;
1051         uint32_t i;
1052         int status;
1053
1054         if (!p)
1055                 goto error;
1056
1057         ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1058         if (!ctl)
1059                 goto error;
1060
1061         /* info. */
1062         status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1063         if (status)
1064                 goto error;
1065
1066         /* numa_node. */
1067         status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1068         if (status)
1069                 goto error;
1070
1071         /* p. */
1072         ctl->p = p;
1073
1074         /* actions. */
1075         ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1076         if (!ctl->actions)
1077                 goto error;
1078
1079         for (i = 0; i < ctl->info.n_actions; i++) {
1080                 struct action *a = &ctl->actions[i];
1081                 uint32_t j;
1082
1083                 /* info. */
1084                 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1085                 if (status)
1086                         goto error;
1087
1088                 /* args. */
1089                 a->args = calloc(a->info.n_args,
1090                                  sizeof(struct rte_swx_ctl_action_arg_info));
1091                 if (!a->args)
1092                         goto error;
1093
1094                 for (j = 0; j < a->info.n_args; j++) {
1095                         status = rte_swx_ctl_action_arg_info_get(p,
1096                                                                  i,
1097                                                                  j,
1098                                                                  &a->args[j]);
1099                         if (status)
1100                                 goto error;
1101                 }
1102
1103                 /* data_size. */
1104                 for (j = 0; j < a->info.n_args; j++) {
1105                         struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1106
1107                         a->data_size += info->n_bits;
1108                 }
1109
1110                 a->data_size = (a->data_size + 7) / 8;
1111         }
1112
1113         /* tables. */
1114         ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1115         if (!ctl->tables)
1116                 goto error;
1117
1118         for (i = 0; i < ctl->info.n_tables; i++) {
1119                 struct table *t = &ctl->tables[i];
1120
1121                 TAILQ_INIT(&t->entries);
1122                 TAILQ_INIT(&t->pending_add);
1123                 TAILQ_INIT(&t->pending_modify0);
1124                 TAILQ_INIT(&t->pending_modify1);
1125                 TAILQ_INIT(&t->pending_delete);
1126         }
1127
1128         for (i = 0; i < ctl->info.n_tables; i++) {
1129                 struct table *t = &ctl->tables[i];
1130                 uint32_t j;
1131
1132                 /* info. */
1133                 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1134                 if (status)
1135                         goto error;
1136
1137                 /* mf. */
1138                 t->mf = calloc(t->info.n_match_fields,
1139                         sizeof(struct rte_swx_ctl_table_match_field_info));
1140                 if (!t->mf)
1141                         goto error;
1142
1143                 for (j = 0; j < t->info.n_match_fields; j++) {
1144                         status = rte_swx_ctl_table_match_field_info_get(p,
1145                                 i,
1146                                 j,
1147                                 &t->mf[j]);
1148                         if (status)
1149                                 goto error;
1150                 }
1151
1152                 /* actions. */
1153                 t->actions = calloc(t->info.n_actions,
1154                         sizeof(struct rte_swx_ctl_table_action_info));
1155                 if (!t->actions)
1156                         goto error;
1157
1158                 for (j = 0; j < t->info.n_actions; j++) {
1159                         status = rte_swx_ctl_table_action_info_get(p,
1160                                 i,
1161                                 j,
1162                                 &t->actions[j]);
1163                         if (status ||
1164                             t->actions[j].action_id >= ctl->info.n_actions)
1165                                 goto error;
1166                 }
1167
1168                 /* ops, is_stub. */
1169                 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1170                 if (status)
1171                         goto error;
1172
1173                 if ((t->is_stub && t->info.n_match_fields) ||
1174                     (!t->is_stub && !t->info.n_match_fields))
1175                         goto error;
1176
1177                 /* params. */
1178                 status = table_params_get(ctl, i);
1179                 if (status)
1180                         goto error;
1181         }
1182
1183         /* selector tables. */
1184         ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1185         if (!ctl->selectors)
1186                 goto error;
1187
1188         for (i = 0; i < ctl->info.n_selectors; i++) {
1189                 struct selector *s = &ctl->selectors[i];
1190                 uint32_t j;
1191
1192                 /* info. */
1193                 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1194                 if (status)
1195                         goto error;
1196
1197                 /* group_id field. */
1198                 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1199                         i,
1200                         &s->group_id_field);
1201                 if (status)
1202                         goto error;
1203
1204                 /* selector fields. */
1205                 s->selector_fields = calloc(s->info.n_selector_fields,
1206                         sizeof(struct rte_swx_ctl_table_match_field_info));
1207                 if (!s->selector_fields)
1208                         goto error;
1209
1210                 for (j = 0; j < s->info.n_selector_fields; j++) {
1211                         status = rte_swx_ctl_selector_field_info_get(p,
1212                                 i,
1213                                 j,
1214                                 &s->selector_fields[j]);
1215                         if (status)
1216                                 goto error;
1217                 }
1218
1219                 /* member_id field. */
1220                 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1221                         i,
1222                         &s->member_id_field);
1223                 if (status)
1224                         goto error;
1225
1226                 /* groups. */
1227                 s->groups = calloc(s->info.n_groups_max,
1228                         sizeof(struct rte_swx_table_selector_group *));
1229                 if (!s->groups)
1230                         goto error;
1231
1232                 /* pending_groups. */
1233                 s->pending_groups = calloc(s->info.n_groups_max,
1234                         sizeof(struct rte_swx_table_selector_group *));
1235                 if (!s->pending_groups)
1236                         goto error;
1237
1238                 /* groups_added. */
1239                 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1240                 if (!s->groups_added)
1241                         goto error;
1242
1243                 /* groups_pending_delete. */
1244                 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1245                 if (!s->groups_pending_delete)
1246                         goto error;
1247
1248                 /* params. */
1249                 status = selector_params_get(ctl, i);
1250                 if (status)
1251                         goto error;
1252         }
1253
1254         /* ts. */
1255         status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1256         if (status)
1257                 goto error;
1258
1259         /* ts_next. */
1260         status = table_state_create(ctl);
1261         if (status)
1262                 goto error;
1263
1264         return ctl;
1265
1266 error:
1267         rte_swx_ctl_pipeline_free(ctl);
1268         return NULL;
1269 }
1270
1271 int
1272 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1273                                      const char *table_name,
1274                                      struct rte_swx_table_entry *entry)
1275 {
1276         struct table *table;
1277         struct rte_swx_table_entry *new_entry, *existing_entry;
1278         uint32_t table_id;
1279
1280         CHECK(ctl, EINVAL);
1281         CHECK(table_name && table_name[0], EINVAL);
1282
1283         table = table_find(ctl, table_name);
1284         CHECK(table, EINVAL);
1285         table_id = table - ctl->tables;
1286
1287         CHECK(entry, EINVAL);
1288         CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1289
1290         new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1291         CHECK(new_entry, ENOMEM);
1292
1293         /* The new entry is found in the table->entries list:
1294          * - Add the new entry to the table->pending_modify1 list;
1295          * - Move the existing entry from the table->entries list to the
1296          *   table->pending_modify0 list.
1297          */
1298         existing_entry = table_entries_find(table, entry);
1299         if (existing_entry) {
1300                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1301                                   new_entry,
1302                                   node);
1303
1304                 TAILQ_REMOVE(&table->entries,
1305                              existing_entry,
1306                              node);
1307
1308                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1309                                   existing_entry,
1310                                   node);
1311
1312                 return 0;
1313         }
1314
1315         /* The new entry is found in the table->pending_add list:
1316          * - Replace the entry in the table->pending_add list with the new entry
1317          *   (and free the replaced entry).
1318          */
1319         existing_entry = table_pending_add_find(table, entry);
1320         if (existing_entry) {
1321                 TAILQ_INSERT_AFTER(&table->pending_add,
1322                                    existing_entry,
1323                                    new_entry,
1324                                    node);
1325
1326                 TAILQ_REMOVE(&table->pending_add,
1327                              existing_entry,
1328                              node);
1329
1330                 table_entry_free(existing_entry);
1331
1332                 return 0;
1333         }
1334
1335         /* The new entry is found in the table->pending_modify1 list:
1336          * - Replace the entry in the table->pending_modify1 list with the new
1337          *   entry (and free the replaced entry).
1338          */
1339         existing_entry = table_pending_modify1_find(table, entry);
1340         if (existing_entry) {
1341                 TAILQ_INSERT_AFTER(&table->pending_modify1,
1342                                    existing_entry,
1343                                    new_entry,
1344                                    node);
1345
1346                 TAILQ_REMOVE(&table->pending_modify1,
1347                              existing_entry,
1348                              node);
1349
1350                 table_entry_free(existing_entry);
1351
1352                 return 0;
1353         }
1354
1355         /* The new entry is found in the table->pending_delete list:
1356          * - Add the new entry to the table->pending_modify1 list;
1357          * - Move the existing entry from the table->pending_delete list to the
1358          *   table->pending_modify0 list.
1359          */
1360         existing_entry = table_pending_delete_find(table, entry);
1361         if (existing_entry) {
1362                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1363                                   new_entry,
1364                                   node);
1365
1366                 TAILQ_REMOVE(&table->pending_delete,
1367                              existing_entry,
1368                              node);
1369
1370                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1371                                   existing_entry,
1372                                   node);
1373
1374                 return 0;
1375         }
1376
1377         /* The new entry is not found in any of the above lists:
1378          * - Add the new entry to the table->pending_add list.
1379          */
1380         TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1381
1382         return 0;
1383 }
1384
1385 int
1386 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1387                                         const char *table_name,
1388                                         struct rte_swx_table_entry *entry)
1389 {
1390         struct table *table;
1391         struct rte_swx_table_entry *existing_entry;
1392         uint32_t table_id;
1393
1394         CHECK(ctl, EINVAL);
1395
1396         CHECK(table_name && table_name[0], EINVAL);
1397         table = table_find(ctl, table_name);
1398         CHECK(table, EINVAL);
1399         table_id = table - ctl->tables;
1400
1401         CHECK(entry, EINVAL);
1402         CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1403
1404         /* The entry is found in the table->entries list:
1405          * - Move the existing entry from the table->entries list to to the
1406          *   table->pending_delete list.
1407          */
1408         existing_entry = table_entries_find(table, entry);
1409         if (existing_entry) {
1410                 TAILQ_REMOVE(&table->entries,
1411                              existing_entry,
1412                              node);
1413
1414                 TAILQ_INSERT_TAIL(&table->pending_delete,
1415                                   existing_entry,
1416                                   node);
1417
1418                 return 0;
1419         }
1420
1421         /* The entry is found in the table->pending_add list:
1422          * - Remove the entry from the table->pending_add list and free it.
1423          */
1424         existing_entry = table_pending_add_find(table, entry);
1425         if (existing_entry) {
1426                 TAILQ_REMOVE(&table->pending_add,
1427                              existing_entry,
1428                              node);
1429
1430                 table_entry_free(existing_entry);
1431         }
1432
1433         /* The entry is found in the table->pending_modify1 list:
1434          * - Free the entry in the table->pending_modify1 list;
1435          * - Move the existing entry from the table->pending_modify0 list to the
1436          *   table->pending_delete list.
1437          */
1438         existing_entry = table_pending_modify1_find(table, entry);
1439         if (existing_entry) {
1440                 struct rte_swx_table_entry *real_existing_entry;
1441
1442                 TAILQ_REMOVE(&table->pending_modify1,
1443                              existing_entry,
1444                              node);
1445
1446                 table_entry_free(existing_entry);
1447
1448                 real_existing_entry = table_pending_modify0_find(table, entry);
1449                 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1450
1451                 TAILQ_REMOVE(&table->pending_modify0,
1452                              real_existing_entry,
1453                              node);
1454
1455                 TAILQ_INSERT_TAIL(&table->pending_delete,
1456                                   real_existing_entry,
1457                                   node);
1458
1459                 return 0;
1460         }
1461
1462         /* The entry is found in the table->pending_delete list:
1463          * - Do nothing: the existing entry is already in the
1464          *   table->pending_delete list, i.e. already marked for delete, so
1465          *   simply keep it there as it is.
1466          */
1467
1468         /* The entry is not found in any of the above lists:
1469          * - Do nothing: no existing entry to delete.
1470          */
1471
1472         return 0;
1473 }
1474
1475 int
1476 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1477                                              const char *table_name,
1478                                              struct rte_swx_table_entry *entry)
1479 {
1480         struct table *table;
1481         struct rte_swx_table_entry *new_entry;
1482         uint32_t table_id;
1483
1484         CHECK(ctl, EINVAL);
1485
1486         CHECK(table_name && table_name[0], EINVAL);
1487         table = table_find(ctl, table_name);
1488         CHECK(table, EINVAL);
1489         table_id = table - ctl->tables;
1490         CHECK(!table->info.default_action_is_const, EINVAL);
1491
1492         CHECK(entry, EINVAL);
1493         CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1494
1495         new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1496         CHECK(new_entry, ENOMEM);
1497
1498         table_pending_default_free(table);
1499
1500         table->pending_default = new_entry;
1501         return 0;
1502 }
1503
1504
1505 static void
1506 table_entry_list_free(struct rte_swx_table_entry_list *list)
1507 {
1508         for ( ; ; ) {
1509                 struct rte_swx_table_entry *entry;
1510
1511                 entry = TAILQ_FIRST(list);
1512                 if (!entry)
1513                         break;
1514
1515                 TAILQ_REMOVE(list, entry, node);
1516                 table_entry_free(entry);
1517         }
1518 }
1519
1520 static int
1521 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1522                            uint32_t table_id,
1523                            struct rte_swx_table_entry_list *dst,
1524                            struct rte_swx_table_entry_list *src)
1525 {
1526         struct rte_swx_table_entry *src_entry;
1527
1528         TAILQ_FOREACH(src_entry, src, node) {
1529                 struct rte_swx_table_entry *dst_entry;
1530
1531                 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1532                 if (!dst_entry)
1533                         goto error;
1534
1535                 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1536         }
1537
1538         return 0;
1539
1540 error:
1541         table_entry_list_free(dst);
1542         return -ENOMEM;
1543 }
1544
1545 /* This commit stage contains all the operations that can fail; in case ANY of
1546  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1547  */
1548 static int
1549 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1550                uint32_t table_id,
1551                uint32_t after_swap)
1552 {
1553         struct table *table = &ctl->tables[table_id];
1554         struct rte_swx_table_state *ts = &ctl->ts[table_id];
1555         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1556
1557         if (table->is_stub || !table_is_update_pending(table, 0))
1558                 return 0;
1559
1560         /*
1561          * Current table supports incremental update.
1562          */
1563         if (table->ops.add) {
1564                 /* Reset counters. */
1565                 table->n_add = 0;
1566                 table->n_modify = 0;
1567                 table->n_delete = 0;
1568
1569                 /* Add pending rules. */
1570                 struct rte_swx_table_entry *entry;
1571
1572                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1573                         int status;
1574
1575                         status = table->ops.add(ts_next->obj, entry);
1576                         if (status)
1577                                 return status;
1578
1579                         table->n_add++;
1580                 }
1581
1582                 /* Modify pending rules. */
1583                 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1584                         int status;
1585
1586                         status = table->ops.add(ts_next->obj, entry);
1587                         if (status)
1588                                 return status;
1589
1590                         table->n_modify++;
1591                 }
1592
1593                 /* Delete pending rules. */
1594                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1595                         int status;
1596
1597                         status = table->ops.del(ts_next->obj, entry);
1598                         if (status)
1599                                 return status;
1600
1601                         table->n_delete++;
1602                 }
1603
1604                 return 0;
1605         }
1606
1607         /*
1608          * Current table does NOT support incremental update.
1609          */
1610         if (!after_swap) {
1611                 struct rte_swx_table_entry_list list;
1612                 int status;
1613
1614                 /* Create updated list of entries included. */
1615                 TAILQ_INIT(&list);
1616
1617                 status = table_entry_list_duplicate(ctl,
1618                                                     table_id,
1619                                                     &list,
1620                                                     &table->entries);
1621                 if (status)
1622                         goto error;
1623
1624                 status = table_entry_list_duplicate(ctl,
1625                                                     table_id,
1626                                                     &list,
1627                                                     &table->pending_add);
1628                 if (status)
1629                         goto error;
1630
1631                 status = table_entry_list_duplicate(ctl,
1632                                                     table_id,
1633                                                     &list,
1634                                                     &table->pending_modify1);
1635                 if (status)
1636                         goto error;
1637
1638                 /* Create new table object with the updates included. */
1639                 ts_next->obj = table->ops.create(&table->params,
1640                                                  &list,
1641                                                  table->info.args,
1642                                                  ctl->numa_node);
1643                 if (!ts_next->obj) {
1644                         status = -ENODEV;
1645                         goto error;
1646                 }
1647
1648                 table_entry_list_free(&list);
1649
1650                 return 0;
1651
1652 error:
1653                 table_entry_list_free(&list);
1654                 return status;
1655         }
1656
1657         /* Free the old table object. */
1658         if (ts_next->obj && table->ops.free)
1659                 table->ops.free(ts_next->obj);
1660
1661         /* Copy over the new table object. */
1662         ts_next->obj = ts->obj;
1663
1664         return 0;
1665 }
1666
1667 /* This commit stage contains all the operations that cannot fail. They are
1668  * executed only if the previous stage was successful for ALL the tables. Hence,
1669  * none of these operations has to be rolled back for ANY table.
1670  */
1671 static void
1672 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1673 {
1674         struct table *table = &ctl->tables[table_id];
1675         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1676         struct action *a;
1677         uint8_t *action_data;
1678         uint64_t action_id;
1679
1680         /* Copy the pending default entry. */
1681         if (!table->pending_default)
1682                 return;
1683
1684         action_id = table->pending_default->action_id;
1685         action_data = table->pending_default->action_data;
1686         a = &ctl->actions[action_id];
1687
1688         memcpy(ts_next->default_action_data,
1689                action_data,
1690                a->data_size);
1691
1692         ts_next->default_action_id = action_id;
1693 }
1694
1695 /* This last commit stage is simply finalizing a successful commit operation.
1696  * This stage is only executed if all the previous stages were successful. This
1697  * stage cannot fail.
1698  */
1699 static void
1700 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1701 {
1702         struct table *table = &ctl->tables[table_id];
1703
1704         /* Move all the pending add entries to the table, as they are now part
1705          * of the table.
1706          */
1707         table_pending_add_admit(table);
1708
1709         /* Move all the pending modify1 entries to table, are they are now part
1710          * of the table. Free up all the pending modify0 entries, as they are no
1711          * longer part of the table.
1712          */
1713         table_pending_modify1_admit(table);
1714         table_pending_modify0_free(table);
1715
1716         /* Free up all the pending delete entries, as they are no longer part of
1717          * the table.
1718          */
1719         table_pending_delete_free(table);
1720
1721         /* Free up the pending default entry, as it is now part of the table. */
1722         table_pending_default_free(table);
1723 }
1724
1725 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1726  * commit operations that can fail did fail for ANY table. It reverts ALL the
1727  * tables to their state before the commit started, as if the commit never
1728  * happened.
1729  */
1730 static void
1731 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1732 {
1733         struct table *table = &ctl->tables[table_id];
1734         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1735
1736         if (table->is_stub || !table_is_update_pending(table, 0))
1737                 return;
1738
1739         if (table->ops.add) {
1740                 struct rte_swx_table_entry *entry;
1741
1742                 /* Add back all the entries that were just deleted. */
1743                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1744                         if (!table->n_delete)
1745                                 break;
1746
1747                         table->ops.add(ts_next->obj, entry);
1748                         table->n_delete--;
1749                 }
1750
1751                 /* Add back the old copy for all the entries that were just
1752                  * modified.
1753                  */
1754                 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1755                         if (!table->n_modify)
1756                                 break;
1757
1758                         table->ops.add(ts_next->obj, entry);
1759                         table->n_modify--;
1760                 }
1761
1762                 /* Delete all the entries that were just added. */
1763                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1764                         if (!table->n_add)
1765                                 break;
1766
1767                         table->ops.del(ts_next->obj, entry);
1768                         table->n_add--;
1769                 }
1770         } else {
1771                 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1772
1773                 /* Free the new table object, as update was cancelled. */
1774                 if (ts_next->obj && table->ops.free)
1775                         table->ops.free(ts_next->obj);
1776
1777                 /* Reinstate the old table object. */
1778                 ts_next->obj = ts->obj;
1779         }
1780 }
1781
1782 /* This stage is conditionally executed (as instructed by the user) after a
1783  * failed commit operation to remove ALL the pending work for ALL the tables.
1784  */
1785 static void
1786 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1787 {
1788         struct table *table = &ctl->tables[table_id];
1789
1790         /* Free up all the pending add entries, as none of them is part of the
1791          * table.
1792          */
1793         table_pending_add_free(table);
1794
1795         /* Free up all the pending modify1 entries, as none of them made it to
1796          * the table. Add back all the pending modify0 entries, as none of them
1797          * was deleted from the table.
1798          */
1799         table_pending_modify1_free(table);
1800         table_pending_modify0_admit(table);
1801
1802         /* Add back all the pending delete entries, as none of them was deleted
1803          * from the table.
1804          */
1805         table_pending_delete_admit(table);
1806
1807         /* Free up the pending default entry, as it is no longer going to be
1808          * added to the table.
1809          */
1810         table_pending_default_free(table);
1811 }
1812
1813 int
1814 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1815                                         const char *selector_name,
1816                                         uint32_t *group_id)
1817 {
1818         struct selector *s;
1819         uint32_t i;
1820
1821         /* Check input arguments. */
1822         if (!ctl || !selector_name || !selector_name[0] || !group_id)
1823                 return -EINVAL;
1824
1825         s = selector_find(ctl, selector_name);
1826         if (!s)
1827                 return -EINVAL;
1828
1829         /* Find an unused group. */
1830         for (i = 0; i < s->info.n_groups_max; i++)
1831                 if (!s->groups_added[i]) {
1832                         *group_id = i;
1833                         s->groups_added[i] = 1;
1834                         return 0;
1835                 }
1836
1837         return -ENOSPC;
1838 }
1839
1840 int
1841 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
1842                                            const char *selector_name,
1843                                            uint32_t group_id)
1844 {
1845         struct selector *s;
1846         struct rte_swx_table_selector_group *group;
1847
1848         /* Check input arguments. */
1849         if (!ctl || !selector_name || !selector_name[0])
1850                 return -EINVAL;
1851
1852         s = selector_find(ctl, selector_name);
1853         if (!s ||
1854            (group_id >= s->info.n_groups_max) ||
1855            !s->groups_added[group_id])
1856                 return -EINVAL;
1857
1858         /* Check if this group is already scheduled for deletion. */
1859         if (s->groups_pending_delete[group_id])
1860                 return 0;
1861
1862         /* Initialize the pending group, if needed. */
1863         if (!s->pending_groups[group_id]) {
1864                 int status;
1865
1866                 status = selector_group_duplicate_to_pending(s, group_id);
1867                 if (status)
1868                         return status;
1869         }
1870
1871         group = s->pending_groups[group_id];
1872
1873         /* Schedule removal of all the members from the current group. */
1874         for ( ; ; ) {
1875                 struct rte_swx_table_selector_member *m;
1876
1877                 m = TAILQ_FIRST(&group->members);
1878                 if (!m)
1879                         break;
1880
1881                 TAILQ_REMOVE(&group->members, m, node);
1882                 free(m);
1883         }
1884
1885         /* Schedule the group for deletion. */
1886         s->groups_pending_delete[group_id] = 1;
1887
1888         return 0;
1889 }
1890
1891 int
1892 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
1893                                                const char *selector_name,
1894                                                uint32_t group_id,
1895                                                uint32_t member_id,
1896                                                uint32_t member_weight)
1897 {
1898         struct selector *s;
1899         struct rte_swx_table_selector_group *group;
1900         struct rte_swx_table_selector_member *m;
1901
1902         if (!member_weight)
1903                 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
1904                                                                          selector_name,
1905                                                                          group_id,
1906                                                                          member_id);
1907
1908         /* Check input arguments. */
1909         if (!ctl || !selector_name || !selector_name[0])
1910                 return -EINVAL;
1911
1912         s = selector_find(ctl, selector_name);
1913         if (!s ||
1914            (group_id >= s->info.n_groups_max) ||
1915            !s->groups_added[group_id] ||
1916            s->groups_pending_delete[group_id])
1917                 return -EINVAL;
1918
1919         /* Initialize the pending group, if needed. */
1920         if (!s->pending_groups[group_id]) {
1921                 int status;
1922
1923                 status = selector_group_duplicate_to_pending(s, group_id);
1924                 if (status)
1925                         return status;
1926         }
1927
1928         group = s->pending_groups[group_id];
1929
1930         /* If this member is already in this group, then simply update its weight and return. */
1931         TAILQ_FOREACH(m, &group->members, node)
1932                 if (m->member_id == member_id) {
1933                         m->member_weight = member_weight;
1934                         return 0;
1935                 }
1936
1937         /* Add new member to this group. */
1938         m = calloc(1, sizeof(struct rte_swx_table_selector_member));
1939         if (!m)
1940                 return -ENOMEM;
1941
1942         m->member_id = member_id;
1943         m->member_weight = member_weight;
1944
1945         TAILQ_INSERT_TAIL(&group->members, m, node);
1946
1947         return 0;
1948 }
1949
1950 int
1951 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
1952                                                   const char *selector_name,
1953                                                   uint32_t group_id __rte_unused,
1954                                                   uint32_t member_id __rte_unused)
1955 {
1956         struct selector *s;
1957         struct rte_swx_table_selector_group *group;
1958         struct rte_swx_table_selector_member *m;
1959
1960         /* Check input arguments. */
1961         if (!ctl || !selector_name || !selector_name[0])
1962                 return -EINVAL;
1963
1964         s = selector_find(ctl, selector_name);
1965         if (!s ||
1966             (group_id >= s->info.n_groups_max) ||
1967             !s->groups_added[group_id] ||
1968             s->groups_pending_delete[group_id])
1969                 return -EINVAL;
1970
1971         /* Initialize the pending group, if needed. */
1972         if (!s->pending_groups[group_id]) {
1973                 int status;
1974
1975                 status = selector_group_duplicate_to_pending(s, group_id);
1976                 if (status)
1977                         return status;
1978         }
1979
1980         group = s->pending_groups[group_id];
1981
1982         /* Look for this member in the group and remove it, if found. */
1983         TAILQ_FOREACH(m, &group->members, node)
1984                 if (m->member_id == member_id) {
1985                         TAILQ_REMOVE(&group->members, m, node);
1986                         free(m);
1987                         return 0;
1988                 }
1989
1990         return 0;
1991 }
1992
1993 static int
1994 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
1995 {
1996         struct selector *s = &ctl->selectors[selector_id];
1997         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
1998         uint32_t group_id;
1999
2000         /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2001          * mirror copy (ts_next->obj).
2002          */
2003         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2004                 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2005                 int status;
2006
2007                 /* Skip this group if no change needed. */
2008                 if (!group)
2009                         continue;
2010
2011                 /* Apply the pending changes for the current group. */
2012                 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2013                 if (status)
2014                         return status;
2015         }
2016
2017         return 0;
2018 }
2019
2020 static void
2021 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2022 {
2023         struct selector *s = &ctl->selectors[selector_id];
2024         uint32_t group_id;
2025
2026         /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2027          * records (s->groups[group_id).
2028          */
2029         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2030                 struct rte_swx_table_selector_group *g = s->groups[group_id];
2031                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2032
2033                 /* Skip this group if no change needed. */
2034                 if (!gp)
2035                         continue;
2036
2037                 /* Transition the pending changes to stable. */
2038                 s->groups[group_id] = gp;
2039                 s->pending_groups[group_id] = NULL;
2040
2041                 /* Free the old group member list. */
2042                 if (!g)
2043                         continue;
2044
2045                 for ( ; ; ) {
2046                         struct rte_swx_table_selector_member *m;
2047
2048                         m = TAILQ_FIRST(&g->members);
2049                         if (!m)
2050                                 break;
2051
2052                         TAILQ_REMOVE(&g->members, m, node);
2053                         free(m);
2054                 }
2055
2056                 free(g);
2057         }
2058
2059         /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2060          * s->groups_added[group_id].
2061          */
2062         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2063                 if (s->groups_pending_delete[group_id]) {
2064                         s->groups_added[group_id] = 0;
2065                         s->groups_pending_delete[group_id] = 0;
2066                 }
2067 }
2068
2069 static void
2070 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2071 {
2072         struct selector *s = &ctl->selectors[selector_id];
2073         struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2074         struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2075         uint32_t group_id;
2076
2077         /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2078         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2079                 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2080
2081                 if (gp) {
2082                         ts_next->obj = ts->obj;
2083                         break;
2084                 }
2085         }
2086 }
2087
2088 static void
2089 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2090 {
2091         struct selector *s = &ctl->selectors[selector_id];
2092         uint32_t group_id;
2093
2094         /* Discard any pending group member changes (s->pending_groups[group_id]). */
2095         for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2096                 selector_pending_group_members_free(s, group_id);
2097
2098         /* Discard any pending group deletions. */
2099         memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2100 }
2101
2102 int
2103 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2104 {
2105         struct rte_swx_table_state *ts;
2106         int status = 0;
2107         uint32_t i;
2108
2109         CHECK(ctl, EINVAL);
2110
2111         /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2112          * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2113          */
2114         for (i = 0; i < ctl->info.n_tables; i++) {
2115                 status = table_rollfwd0(ctl, i, 0);
2116                 if (status)
2117                         goto rollback;
2118         }
2119
2120         for (i = 0; i < ctl->info.n_selectors; i++) {
2121                 status = selector_rollfwd(ctl, i);
2122                 if (status)
2123                         goto rollback;
2124         }
2125
2126         for (i = 0; i < ctl->info.n_tables; i++)
2127                 table_rollfwd1(ctl, i);
2128
2129         /* Swap the table state for the data plane. The current ts and ts_next
2130          * become the new ts_next and ts, respectively.
2131          */
2132         rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2133         usleep(100);
2134         ts = ctl->ts;
2135         ctl->ts = ctl->ts_next;
2136         ctl->ts_next = ts;
2137
2138         /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2139          * the current ts_next in sync with the current ts. Since the changes that can fail did
2140          * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2141          * current ts_next, hence no error checking is needed.
2142          */
2143         for (i = 0; i < ctl->info.n_tables; i++) {
2144                 table_rollfwd0(ctl, i, 1);
2145                 table_rollfwd1(ctl, i);
2146                 table_rollfwd2(ctl, i);
2147         }
2148
2149         for (i = 0; i < ctl->info.n_selectors; i++) {
2150                 selector_rollfwd(ctl, i);
2151                 selector_rollfwd_finalize(ctl, i);
2152         }
2153
2154         return 0;
2155
2156 rollback:
2157         for (i = 0; i < ctl->info.n_tables; i++) {
2158                 table_rollback(ctl, i);
2159                 if (abort_on_fail)
2160                         table_abort(ctl, i);
2161         }
2162
2163         for (i = 0; i < ctl->info.n_selectors; i++) {
2164                 selector_rollback(ctl, i);
2165                 if (abort_on_fail)
2166                         selector_abort(ctl, i);
2167         }
2168
2169         return status;
2170 }
2171
2172 void
2173 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2174 {
2175         uint32_t i;
2176
2177         if (!ctl)
2178                 return;
2179
2180         for (i = 0; i < ctl->info.n_tables; i++)
2181                 table_abort(ctl, i);
2182
2183         for (i = 0; i < ctl->info.n_selectors; i++)
2184                 selector_abort(ctl, i);
2185 }
2186
2187 static int
2188 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2189 {
2190         uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2191
2192         if (!mask) {
2193                 *prefix_length = 0;
2194                 return 0;
2195         }
2196
2197         /* Count trailing zero bits. */
2198         for (i = 0; i < 64; i++) {
2199                 if (mask & (1LLU << i))
2200                         break;
2201
2202                 n_trailing_zeros++;
2203         }
2204
2205         /* Count the one bits that follow. */
2206         for ( ; i < 64; i++) {
2207                 if (!(mask & (1LLU << i)))
2208                         break;
2209
2210                 n_ones++;
2211         }
2212
2213         /* Check that no more one bits are present */
2214         for ( ; i < 64; i++)
2215                 if (mask & (1LLU << i))
2216                         return -EINVAL;
2217
2218         /* Check that the input mask is a prefix or the right length. */
2219         if (n_ones + n_trailing_zeros != mask_length)
2220                 return -EINVAL;
2221
2222         *prefix_length = n_ones;
2223         return 0;
2224 }
2225
2226 static int
2227 token_is_comment(const char *token)
2228 {
2229         if ((token[0] == '#') ||
2230             (token[0] == ';') ||
2231             ((token[0] == '/') && (token[1] == '/')))
2232                 return 1; /* TRUE. */
2233
2234         return 0; /* FALSE. */
2235 }
2236
2237 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2238
2239 struct rte_swx_table_entry *
2240 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2241                                       const char *table_name,
2242                                       const char *string,
2243                                       int *is_blank_or_comment)
2244 {
2245         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2246         struct table *table;
2247         struct action *action;
2248         struct rte_swx_table_entry *entry = NULL;
2249         char *s0 = NULL, *s;
2250         uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2251         int lpm = 0, blank_or_comment = 0;
2252
2253         /* Check input arguments. */
2254         if (!ctl)
2255                 goto error;
2256
2257         if (!table_name || !table_name[0])
2258                 goto error;
2259
2260         table = table_find(ctl, table_name);
2261         if (!table)
2262                 goto error;
2263
2264         if (!string || !string[0])
2265                 goto error;
2266
2267         /* Memory allocation. */
2268         s0 = strdup(string);
2269         if (!s0)
2270                 goto error;
2271
2272         entry = table_entry_alloc(table);
2273         if (!entry)
2274                 goto error;
2275
2276         /* Parse the string into tokens. */
2277         for (s = s0; ; ) {
2278                 char *token;
2279
2280                 token = strtok_r(s, " \f\n\r\t\v", &s);
2281                 if (!token || token_is_comment(token))
2282                         break;
2283
2284                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2285                         goto error;
2286
2287                 token_array[n_tokens] = token;
2288                 n_tokens++;
2289         }
2290
2291         if (!n_tokens) {
2292                 blank_or_comment = 1;
2293                 goto error;
2294         }
2295
2296         tokens = token_array;
2297
2298         /*
2299          * Match.
2300          */
2301         if (!(n_tokens && !strcmp(tokens[0], "match")))
2302                 goto action;
2303
2304         if (n_tokens < 1 + table->info.n_match_fields)
2305                 goto error;
2306
2307         for (i = 0; i < table->info.n_match_fields; i++) {
2308                 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2309                 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2310                 uint64_t val, mask = UINT64_MAX;
2311                 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2312
2313                 /*
2314                  * Mask.
2315                  */
2316                 mf_mask = strchr(mf_val, '/');
2317                 if (mf_mask) {
2318                         *mf_mask = 0;
2319                         mf_mask++;
2320
2321                         /* Parse. */
2322                         mask = strtoull(mf_mask, &mf_mask, 0);
2323                         if (mf_mask[0])
2324                                 goto error;
2325
2326                         /* LPM. */
2327                         if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2328                                 int status;
2329
2330                                 lpm = 1;
2331
2332                                 lpm_prefix_length_max = mf->n_bits;
2333
2334                                 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2335                                 if (status)
2336                                         goto error;
2337                         }
2338
2339                         /* Endianness conversion. */
2340                         if (mf->is_header)
2341                                 mask = field_hton(mask, mf->n_bits);
2342                 }
2343
2344                 /* Copy to entry. */
2345                 if (entry->key_mask)
2346                         memcpy(&entry->key_mask[offset],
2347                                (uint8_t *)&mask,
2348                                mf->n_bits / 8);
2349
2350                 /*
2351                  * Value.
2352                  */
2353                 /* Parse. */
2354                 val = strtoull(mf_val, &mf_val, 0);
2355                 if (mf_val[0])
2356                         goto error;
2357
2358                 /* Endianness conversion. */
2359                 if (mf->is_header)
2360                         val = field_hton(val, mf->n_bits);
2361
2362                 /* Copy to entry. */
2363                 memcpy(&entry->key[offset],
2364                        (uint8_t *)&val,
2365                        mf->n_bits / 8);
2366         }
2367
2368         tokens += 1 + table->info.n_match_fields;
2369         n_tokens -= 1 + table->info.n_match_fields;
2370
2371         /*
2372          * Match priority.
2373          */
2374         if (n_tokens && !strcmp(tokens[0], "priority")) {
2375                 char *priority = tokens[1];
2376                 uint32_t val;
2377
2378                 if (n_tokens < 2)
2379                         goto error;
2380
2381                 /* Parse. */
2382                 val = strtoul(priority, &priority, 0);
2383                 if (priority[0])
2384                         goto error;
2385
2386                 /* Copy to entry. */
2387                 entry->key_priority = val;
2388
2389                 tokens += 2;
2390                 n_tokens -= 2;
2391         }
2392
2393         /* LPM. */
2394         if (lpm)
2395                 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2396
2397         /*
2398          * Action.
2399          */
2400 action:
2401         if (!(n_tokens && !strcmp(tokens[0], "action")))
2402                 goto other;
2403
2404         if (n_tokens < 2)
2405                 goto error;
2406
2407         action = action_find(ctl, tokens[1]);
2408         if (!action)
2409                 goto error;
2410
2411         if (n_tokens < 2 + action->info.n_args * 2)
2412                 goto error;
2413
2414         /* action_id. */
2415         entry->action_id = action - ctl->actions;
2416
2417         /* action_data. */
2418         for (i = 0; i < action->info.n_args; i++) {
2419                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2420                 char *arg_name, *arg_val;
2421                 uint64_t val;
2422
2423                 arg_name = tokens[2 + i * 2];
2424                 arg_val = tokens[2 + i * 2 + 1];
2425
2426                 if (strcmp(arg_name, arg->name))
2427                         goto error;
2428
2429                 val = strtoull(arg_val, &arg_val, 0);
2430                 if (arg_val[0])
2431                         goto error;
2432
2433                 /* Endianness conversion. */
2434                 if (arg->is_network_byte_order)
2435                         val = field_hton(val, arg->n_bits);
2436
2437                 /* Copy to entry. */
2438                 memcpy(&entry->action_data[arg_offset],
2439                        (uint8_t *)&val,
2440                        arg->n_bits / 8);
2441
2442                 arg_offset += arg->n_bits / 8;
2443         }
2444
2445         tokens += 2 + action->info.n_args * 2;
2446         n_tokens -= 2 + action->info.n_args * 2;
2447
2448 other:
2449         if (n_tokens)
2450                 goto error;
2451
2452         free(s0);
2453         return entry;
2454
2455 error:
2456         table_entry_free(entry);
2457         free(s0);
2458         if (is_blank_or_comment)
2459                 *is_blank_or_comment = blank_or_comment;
2460         return NULL;
2461 }
2462
2463 static void
2464 table_entry_printf(FILE *f,
2465                    struct rte_swx_ctl_pipeline *ctl,
2466                    struct table *table,
2467                    struct rte_swx_table_entry *entry)
2468 {
2469         struct action *action = &ctl->actions[entry->action_id];
2470         uint32_t i;
2471
2472         fprintf(f, "match ");
2473         for (i = 0; i < table->params.key_size; i++)
2474                 fprintf(f, "%02x", entry->key[i]);
2475
2476         if (entry->key_mask) {
2477                 fprintf(f, "/");
2478                 for (i = 0; i < table->params.key_size; i++)
2479                         fprintf(f, "%02x", entry->key_mask[i]);
2480         }
2481
2482         fprintf(f, " priority %u", entry->key_priority);
2483
2484         fprintf(f, " action %s ", action->info.name);
2485         for (i = 0; i < action->data_size; i++)
2486                 fprintf(f, "%02x", entry->action_data[i]);
2487
2488         fprintf(f, "\n");
2489 }
2490
2491 int
2492 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2493                                    struct rte_swx_ctl_pipeline *ctl,
2494                                    const char *table_name)
2495 {
2496         struct table *table;
2497         struct rte_swx_table_entry *entry;
2498         uint32_t n_entries = 0, i;
2499
2500         if (!f || !ctl || !table_name || !table_name[0])
2501                 return -EINVAL;
2502
2503         table = table_find(ctl, table_name);
2504         if (!table)
2505                 return -EINVAL;
2506
2507         /* Table. */
2508         fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2509                 table->info.name,
2510                 table->params.key_size,
2511                 table->params.key_offset);
2512
2513         for (i = 0; i < table->params.key_size; i++)
2514                 fprintf(f, "%02x", table->params.key_mask0[i]);
2515
2516         fprintf(f, "], action data size %u bytes\n",
2517                 table->params.action_data_size);
2518
2519         /* Table entries. */
2520         TAILQ_FOREACH(entry, &table->entries, node) {
2521                 table_entry_printf(f, ctl, table, entry);
2522                 n_entries++;
2523         }
2524
2525         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2526                 table_entry_printf(f, ctl, table, entry);
2527                 n_entries++;
2528         }
2529
2530         TAILQ_FOREACH(entry, &table->pending_delete, node) {
2531                 table_entry_printf(f, ctl, table, entry);
2532                 n_entries++;
2533         }
2534
2535         fprintf(f, "# Table %s currently has %u entries.\n",
2536                 table_name,
2537                 n_entries);
2538         return 0;
2539 }
2540
2541 int
2542 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
2543                                       struct rte_swx_ctl_pipeline *ctl,
2544                                       const char *selector_name)
2545 {
2546         struct selector *s;
2547         uint32_t group_id;
2548
2549         if (!f || !ctl || !selector_name || !selector_name[0])
2550                 return -EINVAL;
2551
2552         s = selector_find(ctl, selector_name);
2553         if (!s)
2554                 return -EINVAL;
2555
2556         /* Selector. */
2557         fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
2558                 s->info.name,
2559                 s->info.n_groups_max,
2560                 s->info.n_members_per_group_max);
2561
2562         /* Groups. */
2563         for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2564                 struct rte_swx_table_selector_group *group = s->groups[group_id];
2565                 struct rte_swx_table_selector_member *m;
2566                 uint32_t n_members = 0;
2567
2568                 fprintf(f, "Group %u = [", group_id);
2569
2570                 /* Non-empty group. */
2571                 if (group)
2572                         TAILQ_FOREACH(m, &group->members, node) {
2573                                 fprintf(f, "%u:%u ", m->member_id, m->member_weight);
2574                                 n_members++;
2575                         }
2576
2577                 /* Empty group. */
2578                 if (!n_members)
2579                         fprintf(f, "0:1 ");
2580
2581                 fprintf(f, "]\n");
2582         }
2583
2584         return 0;
2585 }