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