net/mlx5: fix using flow tunnel before null check
[dpdk.git] / lib / librte_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_ctl.h"
14
15 #define CHECK(condition, err_code)                                             \
16 do {                                                                           \
17         if (!(condition))                                                      \
18                 return -(err_code);                                            \
19 } while (0)
20
21 #define ntoh64(x) rte_be_to_cpu_64(x)
22 #define hton64(x) rte_cpu_to_be_64(x)
23
24 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
25 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
26 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
27 #else
28 #define field_ntoh(val, n_bits) (val)
29 #define field_hton(val, n_bits) (val)
30 #endif
31
32 struct action {
33         struct rte_swx_ctl_action_info info;
34         struct rte_swx_ctl_action_arg_info *args;
35         uint32_t data_size;
36 };
37
38 struct table {
39         struct rte_swx_ctl_table_info info;
40         struct rte_swx_ctl_table_match_field_info *mf;
41         struct rte_swx_ctl_table_action_info *actions;
42         struct rte_swx_table_ops ops;
43         struct rte_swx_table_params params;
44
45         /* Set of "stable" keys: these keys are currently part of the table;
46          * these keys will be preserved with no action data changes after the
47          * next commit.
48          */
49         struct rte_swx_table_entry_list entries;
50
51         /* Set of new keys: these keys are currently NOT part of the table;
52          * these keys will be added to the table on the next commit, if
53          * the commit operation is successful.
54          */
55         struct rte_swx_table_entry_list pending_add;
56
57         /* Set of keys to be modified: these keys are currently part of the
58          * table; these keys are still going to be part of the table after the
59          * next commit, but their action data will be modified if the commit
60          * operation is successful. The modify0 list contains the keys with the
61          * current action data, the modify1 list contains the keys with the
62          * modified action data.
63          */
64         struct rte_swx_table_entry_list pending_modify0;
65         struct rte_swx_table_entry_list pending_modify1;
66
67         /* Set of keys to be deleted: these keys are currently part of the
68          * table; these keys are to be deleted from the table on the next
69          * commit, if the commit operation is successful.
70          */
71         struct rte_swx_table_entry_list pending_delete;
72
73         /* The pending default action: this is NOT the current default action;
74          * this will be the new default action after the next commit, if the
75          * next commit operation is successful.
76          */
77         struct rte_swx_table_entry *pending_default;
78
79         int is_stub;
80         uint32_t n_add;
81         uint32_t n_modify;
82         uint32_t n_delete;
83 };
84
85 struct rte_swx_ctl_pipeline {
86         struct rte_swx_ctl_pipeline_info info;
87         struct rte_swx_pipeline *p;
88         struct action *actions;
89         struct table *tables;
90         struct rte_swx_table_state *ts;
91         struct rte_swx_table_state *ts_next;
92         int numa_node;
93 };
94
95 static struct action *
96 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
97 {
98         uint32_t i;
99
100         for (i = 0; i < ctl->info.n_actions; i++) {
101                 struct action *a = &ctl->actions[i];
102
103                 if (!strcmp(action_name, a->info.name))
104                         return a;
105         }
106
107         return NULL;
108 }
109
110 static void
111 action_free(struct rte_swx_ctl_pipeline *ctl)
112 {
113         uint32_t i;
114
115         if (!ctl->actions)
116                 return;
117
118         for (i = 0; i < ctl->info.n_actions; i++) {
119                 struct action *action = &ctl->actions[i];
120
121                 free(action->args);
122         }
123
124         free(ctl->actions);
125         ctl->actions = NULL;
126 }
127
128 static struct table *
129 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
130 {
131         uint32_t i;
132
133         for (i = 0; i < ctl->info.n_tables; i++) {
134                 struct table *table = &ctl->tables[i];
135
136                 if (!strcmp(table_name, table->info.name))
137                         return table;
138         }
139
140         return NULL;
141 }
142
143 static int
144 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
145 {
146         struct table *table = &ctl->tables[table_id];
147         uint8_t *key_mask = NULL;
148         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
149         uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
150
151         if (table->info.n_match_fields) {
152                 struct rte_swx_ctl_table_match_field_info *first, *last;
153                 uint32_t i;
154
155                 first = &table->mf[0];
156                 last = &table->mf[table->info.n_match_fields - 1];
157
158                 /* match_type. */
159                 for (i = 0; i < table->info.n_match_fields; i++) {
160                         struct rte_swx_ctl_table_match_field_info *f;
161
162                         f = &table->mf[i];
163                         if (f->match_type != RTE_SWX_TABLE_MATCH_EXACT)
164                                 break;
165                 }
166
167                 if (i == table->info.n_match_fields)
168                         match_type = RTE_SWX_TABLE_MATCH_EXACT;
169                 else if ((i == table->info.n_match_fields - 1) &&
170                          (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
171                         match_type = RTE_SWX_TABLE_MATCH_LPM;
172
173                 /* key_offset. */
174                 key_offset = first->offset / 8;
175
176                 /* key_size. */
177                 key_size = (last->offset + last->n_bits - first->offset) / 8;
178
179                 /* key_mask. */
180                 key_mask = calloc(1, key_size);
181                 CHECK(key_mask, ENOMEM);
182
183                 for (i = 0; i < table->info.n_match_fields; i++) {
184                         struct rte_swx_ctl_table_match_field_info *f;
185                         uint32_t start;
186                         size_t size;
187
188                         f = &table->mf[i];
189                         start = (f->offset - first->offset) / 8;
190                         size = f->n_bits / 8;
191
192                         memset(&key_mask[start], 0xFF, size);
193                 }
194         }
195
196         /* action_data_size. */
197         for (i = 0; i < table->info.n_actions; i++) {
198                 uint32_t action_id = table->actions[i].action_id;
199                 struct action *a = &ctl->actions[action_id];
200
201                 if (a->data_size > action_data_size)
202                         action_data_size = a->data_size;
203         }
204
205         /* Fill in. */
206         table->params.match_type = match_type;
207         table->params.key_size = key_size;
208         table->params.key_offset = key_offset;
209         table->params.key_mask0 = key_mask;
210         table->params.action_data_size = action_data_size;
211         table->params.n_keys_max = table->info.size;
212
213         return 0;
214 }
215
216 static void
217 table_entry_free(struct rte_swx_table_entry *entry)
218 {
219         if (!entry)
220                 return;
221
222         free(entry->key);
223         free(entry->key_mask);
224         free(entry->action_data);
225         free(entry);
226 }
227
228 static struct rte_swx_table_entry *
229 table_entry_alloc(struct table *table)
230 {
231         struct rte_swx_table_entry *entry;
232
233         entry = calloc(1, sizeof(struct rte_swx_table_entry));
234         if (!entry)
235                 goto error;
236
237         /* key, key_mask. */
238         if (!table->is_stub) {
239                 entry->key = calloc(1, table->params.key_size);
240                 if (!entry->key)
241                         goto error;
242
243                 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
244                         entry->key_mask = calloc(1, table->params.key_size);
245                         if (!entry->key_mask)
246                                 goto error;
247                 }
248         }
249
250         /* action_data. */
251         if (table->params.action_data_size) {
252                 entry->action_data = calloc(1, table->params.action_data_size);
253                 if (!entry->action_data)
254                         goto error;
255         }
256
257         return entry;
258
259 error:
260         table_entry_free(entry);
261         return NULL;
262 }
263
264 static int
265 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
266 {
267         uint8_t *key_mask0 = table->params.key_mask0;
268         uint32_t key_size = table->params.key_size, i;
269
270         if (!entry->key_mask)
271                 return 0;
272
273         for (i = 0; i < key_size; i++) {
274                 uint8_t km0 = key_mask0[i];
275                 uint8_t km = entry->key_mask[i];
276
277                 if ((km & km0) != km0)
278                         return -EINVAL;
279         }
280
281         return 0;
282 }
283
284 static int
285 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
286                   uint32_t table_id,
287                   struct rte_swx_table_entry *entry,
288                   int key_check,
289                   int data_check)
290 {
291         struct table *table = &ctl->tables[table_id];
292         int status;
293
294         CHECK(entry, EINVAL);
295
296         if (key_check) {
297                 if (table->is_stub) {
298                         /* key. */
299                         CHECK(!entry->key, EINVAL);
300
301                         /* key_mask. */
302                         CHECK(!entry->key_mask, EINVAL);
303                 } else {
304                         /* key. */
305                         CHECK(entry->key, EINVAL);
306
307                         /* key_mask. */
308                         switch (table->params.match_type) {
309                         case RTE_SWX_TABLE_MATCH_WILDCARD:
310                                 break;
311
312                         case RTE_SWX_TABLE_MATCH_LPM:
313                                 /* TBD Check that key mask is prefix. */
314                                 break;
315
316                         case RTE_SWX_TABLE_MATCH_EXACT:
317                                 status = table_entry_key_check_em(table, entry);
318                                 if (status)
319                                         return status;
320                                 break;
321
322                         default:
323                                 CHECK(0, EINVAL);
324                         }
325                 }
326         }
327
328         if (data_check) {
329                 struct action *a;
330                 uint32_t i;
331
332                 /* action_id. */
333                 for (i = 0; i < table->info.n_actions; i++)
334                         if (entry->action_id == table->actions[i].action_id)
335                                 break;
336
337                 CHECK(i < table->info.n_actions, EINVAL);
338
339                 /* action_data. */
340                 a = &ctl->actions[entry->action_id];
341                 CHECK((a->data_size && entry->action_data) ||
342                       (!a->data_size && !entry->action_data), EINVAL);
343         }
344
345         return 0;
346 }
347
348 static struct rte_swx_table_entry *
349 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
350                       uint32_t table_id,
351                       struct rte_swx_table_entry *entry,
352                       int key_duplicate,
353                       int data_duplicate)
354 {
355         struct table *table = &ctl->tables[table_id];
356         struct rte_swx_table_entry *new_entry = NULL;
357
358         if (!entry)
359                 goto error;
360
361         new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
362         if (!new_entry)
363                 goto error;
364
365         if (key_duplicate && !table->is_stub) {
366                 /* key. */
367                 if (!entry->key)
368                         goto error;
369
370                 new_entry->key = malloc(table->params.key_size);
371                 if (!new_entry->key)
372                         goto error;
373
374                 memcpy(new_entry->key, entry->key, table->params.key_size);
375
376                 /* key_signature. */
377                 new_entry->key_signature = entry->key_signature;
378
379                 /* key_mask. */
380                 if (entry->key_mask) {
381                         new_entry->key_mask = malloc(table->params.key_size);
382                         if (!new_entry->key_mask)
383                                 goto error;
384
385                         memcpy(new_entry->key_mask,
386                                entry->key_mask,
387                                table->params.key_size);
388                 }
389
390                 /* key_priority. */
391                 new_entry->key_priority = entry->key_priority;
392         }
393
394         if (data_duplicate) {
395                 struct action *a;
396                 uint32_t i;
397
398                 /* action_id. */
399                 for (i = 0; i < table->info.n_actions; i++)
400                         if (entry->action_id == table->actions[i].action_id)
401                                 break;
402
403                 if (i >= table->info.n_actions)
404                         goto error;
405
406                 new_entry->action_id = entry->action_id;
407
408                 /* action_data. */
409                 a = &ctl->actions[entry->action_id];
410                 if (a->data_size && !entry->action_data)
411                         goto error;
412
413                 /* The table layer provisions a constant action data size per
414                  * entry, which should be the largest data size for all the
415                  * actions enabled for the current table, and attempts to copy
416                  * this many bytes each time a table entry is added, even if the
417                  * specific action requires less data or even no data at all,
418                  * hence we always have to allocate the max.
419                  */
420                 new_entry->action_data = calloc(1, table->params.action_data_size);
421                 if (!new_entry->action_data)
422                         goto error;
423
424                 if (a->data_size)
425                         memcpy(new_entry->action_data,
426                                entry->action_data,
427                                a->data_size);
428         }
429
430         return new_entry;
431
432 error:
433         table_entry_free(new_entry);
434         return NULL;
435 }
436
437 static int
438 table_entry_keycmp(struct table *table,
439                    struct rte_swx_table_entry *e0,
440                    struct rte_swx_table_entry *e1)
441 {
442         uint32_t key_size = table->params.key_size;
443         uint32_t i;
444
445         for (i = 0; i < key_size; i++) {
446                 uint8_t *key_mask0 = table->params.key_mask0;
447                 uint8_t km0, km[2], k[2];
448
449                 km0 = key_mask0 ? key_mask0[i] : 0xFF;
450
451                 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
452                 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
453
454                 k[0] = e0->key[i];
455                 k[1] = e1->key[i];
456
457                 /* Mask comparison. */
458                 if ((km[0] & km0) != (km[1] & km0))
459                         return 1; /* Not equal. */
460
461                 /* Value comparison. */
462                 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
463                         return 1; /* Not equal. */
464         }
465
466         return 0; /* Equal. */
467 }
468
469 static struct rte_swx_table_entry *
470 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
471 {
472         struct rte_swx_table_entry *e;
473
474         TAILQ_FOREACH(e, &table->entries, node)
475                 if (!table_entry_keycmp(table, entry, e))
476                         return e; /* Found. */
477
478         return NULL; /* Not found. */
479 }
480
481 static void
482 table_entries_free(struct table *table)
483 {
484         for ( ; ; ) {
485                 struct rte_swx_table_entry *entry;
486
487                 entry = TAILQ_FIRST(&table->entries);
488                 if (!entry)
489                         break;
490
491                 TAILQ_REMOVE(&table->entries, entry, node);
492                 table_entry_free(entry);
493         }
494 }
495
496 static struct rte_swx_table_entry *
497 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
498 {
499         struct rte_swx_table_entry *e;
500
501         TAILQ_FOREACH(e, &table->pending_add, node)
502                 if (!table_entry_keycmp(table, entry, e))
503                         return e; /* Found. */
504
505         return NULL; /* Not found. */
506 }
507
508 static void
509 table_pending_add_admit(struct table *table)
510 {
511         TAILQ_CONCAT(&table->entries, &table->pending_add, node);
512 }
513
514 static void
515 table_pending_add_free(struct table *table)
516 {
517         for ( ; ; ) {
518                 struct rte_swx_table_entry *entry;
519
520                 entry = TAILQ_FIRST(&table->pending_add);
521                 if (!entry)
522                         break;
523
524                 TAILQ_REMOVE(&table->pending_add, entry, node);
525                 table_entry_free(entry);
526         }
527 }
528
529 static struct rte_swx_table_entry *
530 table_pending_modify0_find(struct table *table,
531                            struct rte_swx_table_entry *entry)
532 {
533         struct rte_swx_table_entry *e;
534
535         TAILQ_FOREACH(e, &table->pending_modify0, node)
536                 if (!table_entry_keycmp(table, entry, e))
537                         return e; /* Found. */
538
539         return NULL; /* Not found. */
540 }
541
542 static void
543 table_pending_modify0_admit(struct table *table)
544 {
545         TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
546 }
547
548 static void
549 table_pending_modify0_free(struct table *table)
550 {
551         for ( ; ; ) {
552                 struct rte_swx_table_entry *entry;
553
554                 entry = TAILQ_FIRST(&table->pending_modify0);
555                 if (!entry)
556                         break;
557
558                 TAILQ_REMOVE(&table->pending_modify0, entry, node);
559                 table_entry_free(entry);
560         }
561 }
562
563 static struct rte_swx_table_entry *
564 table_pending_modify1_find(struct table *table,
565                            struct rte_swx_table_entry *entry)
566 {
567         struct rte_swx_table_entry *e;
568
569         TAILQ_FOREACH(e, &table->pending_modify1, node)
570                 if (!table_entry_keycmp(table, entry, e))
571                         return e; /* Found. */
572
573         return NULL; /* Not found. */
574 }
575
576 static void
577 table_pending_modify1_admit(struct table *table)
578 {
579         TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
580 }
581
582 static void
583 table_pending_modify1_free(struct table *table)
584 {
585         for ( ; ; ) {
586                 struct rte_swx_table_entry *entry;
587
588                 entry = TAILQ_FIRST(&table->pending_modify1);
589                 if (!entry)
590                         break;
591
592                 TAILQ_REMOVE(&table->pending_modify1, entry, node);
593                 table_entry_free(entry);
594         }
595 }
596
597 static struct rte_swx_table_entry *
598 table_pending_delete_find(struct table *table,
599                           struct rte_swx_table_entry *entry)
600 {
601         struct rte_swx_table_entry *e;
602
603         TAILQ_FOREACH(e, &table->pending_delete, node)
604                 if (!table_entry_keycmp(table, entry, e))
605                         return e; /* Found. */
606
607         return NULL; /* Not found. */
608 }
609
610 static void
611 table_pending_delete_admit(struct table *table)
612 {
613         TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
614 }
615
616 static void
617 table_pending_delete_free(struct table *table)
618 {
619         for ( ; ; ) {
620                 struct rte_swx_table_entry *entry;
621
622                 entry = TAILQ_FIRST(&table->pending_delete);
623                 if (!entry)
624                         break;
625
626                 TAILQ_REMOVE(&table->pending_delete, entry, node);
627                 table_entry_free(entry);
628         }
629 }
630
631 static void
632 table_pending_default_free(struct table *table)
633 {
634         if (!table->pending_default)
635                 return;
636
637         free(table->pending_default->action_data);
638         free(table->pending_default);
639         table->pending_default = NULL;
640 }
641
642 static int
643 table_is_update_pending(struct table *table, int consider_pending_default)
644 {
645         struct rte_swx_table_entry *e;
646         uint32_t n = 0;
647
648         /* Pending add. */
649         TAILQ_FOREACH(e, &table->pending_add, node)
650                 n++;
651
652         /* Pending modify. */
653         TAILQ_FOREACH(e, &table->pending_modify1, node)
654                 n++;
655
656         /* Pending delete. */
657         TAILQ_FOREACH(e, &table->pending_delete, node)
658                 n++;
659
660         /* Pending default. */
661         if (consider_pending_default && table->pending_default)
662                 n++;
663
664         return n;
665 }
666
667 static void
668 table_free(struct rte_swx_ctl_pipeline *ctl)
669 {
670         uint32_t i;
671
672         if (!ctl->tables)
673                 return;
674
675         for (i = 0; i < ctl->info.n_tables; i++) {
676                 struct table *table = &ctl->tables[i];
677
678                 free(table->mf);
679                 free(table->actions);
680                 free(table->params.key_mask0);
681
682                 table_entries_free(table);
683                 table_pending_add_free(table);
684                 table_pending_modify0_free(table);
685                 table_pending_modify1_free(table);
686                 table_pending_delete_free(table);
687                 table_pending_default_free(table);
688         }
689
690         free(ctl->tables);
691         ctl->tables = NULL;
692 }
693
694 static void
695 table_state_free(struct rte_swx_ctl_pipeline *ctl)
696 {
697         uint32_t i;
698
699         if (!ctl->ts_next)
700                 return;
701
702         /* For each table, free its table state. */
703         for (i = 0; i < ctl->info.n_tables; i++) {
704                 struct table *table = &ctl->tables[i];
705                 struct rte_swx_table_state *ts = &ctl->ts_next[i];
706
707                 /* Default action data. */
708                 free(ts->default_action_data);
709
710                 /* Table object. */
711                 if (!table->is_stub && table->ops.free && ts->obj)
712                         table->ops.free(ts->obj);
713         }
714
715         free(ctl->ts_next);
716         ctl->ts_next = NULL;
717 }
718
719 static int
720 table_state_create(struct rte_swx_ctl_pipeline *ctl)
721 {
722         int status = 0;
723         uint32_t i;
724
725         ctl->ts_next = calloc(ctl->info.n_tables,
726                               sizeof(struct rte_swx_table_state));
727         if (!ctl->ts_next) {
728                 status = -ENOMEM;
729                 goto error;
730         }
731
732         for (i = 0; i < ctl->info.n_tables; i++) {
733                 struct table *table = &ctl->tables[i];
734                 struct rte_swx_table_state *ts = &ctl->ts[i];
735                 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
736
737                 /* Table object. */
738                 if (!table->is_stub && table->ops.add) {
739                         ts_next->obj = table->ops.create(&table->params,
740                                                          &table->entries,
741                                                          table->info.args,
742                                                          ctl->numa_node);
743                         if (!ts_next->obj) {
744                                 status = -ENODEV;
745                                 goto error;
746                         }
747                 }
748
749                 if (!table->is_stub && !table->ops.add)
750                         ts_next->obj = ts->obj;
751
752                 /* Default action data: duplicate from current table state. */
753                 ts_next->default_action_data =
754                         malloc(table->params.action_data_size);
755                 if (!ts_next->default_action_data) {
756                         status = -ENOMEM;
757                         goto error;
758                 }
759
760                 memcpy(ts_next->default_action_data,
761                        ts->default_action_data,
762                        table->params.action_data_size);
763
764                 ts_next->default_action_id = ts->default_action_id;
765         }
766
767         return 0;
768
769 error:
770         table_state_free(ctl);
771         return status;
772 }
773
774 void
775 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
776 {
777         if (!ctl)
778                 return;
779
780         action_free(ctl);
781
782         table_state_free(ctl);
783
784         table_free(ctl);
785
786         free(ctl);
787 }
788
789 struct rte_swx_ctl_pipeline *
790 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
791 {
792         struct rte_swx_ctl_pipeline *ctl = NULL;
793         uint32_t i;
794         int status;
795
796         if (!p)
797                 goto error;
798
799         ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
800         if (!ctl)
801                 goto error;
802
803         /* info. */
804         status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
805         if (status)
806                 goto error;
807
808         /* numa_node. */
809         status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
810         if (status)
811                 goto error;
812
813         /* p. */
814         ctl->p = p;
815
816         /* actions. */
817         ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
818         if (!ctl->actions)
819                 goto error;
820
821         for (i = 0; i < ctl->info.n_actions; i++) {
822                 struct action *a = &ctl->actions[i];
823                 uint32_t j;
824
825                 /* info. */
826                 status = rte_swx_ctl_action_info_get(p, i, &a->info);
827                 if (status)
828                         goto error;
829
830                 /* args. */
831                 a->args = calloc(a->info.n_args,
832                                  sizeof(struct rte_swx_ctl_action_arg_info));
833                 if (!a->args)
834                         goto error;
835
836                 for (j = 0; j < a->info.n_args; j++) {
837                         status = rte_swx_ctl_action_arg_info_get(p,
838                                                                  i,
839                                                                  j,
840                                                                  &a->args[j]);
841                         if (status)
842                                 goto error;
843                 }
844
845                 /* data_size. */
846                 for (j = 0; j < a->info.n_args; j++) {
847                         struct rte_swx_ctl_action_arg_info *info = &a->args[j];
848
849                         a->data_size += info->n_bits;
850                 }
851
852                 a->data_size = (a->data_size + 7) / 8;
853         }
854
855         /* tables. */
856         ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
857         if (!ctl->tables)
858                 goto error;
859
860         for (i = 0; i < ctl->info.n_tables; i++) {
861                 struct table *t = &ctl->tables[i];
862
863                 TAILQ_INIT(&t->entries);
864                 TAILQ_INIT(&t->pending_add);
865                 TAILQ_INIT(&t->pending_modify0);
866                 TAILQ_INIT(&t->pending_modify1);
867                 TAILQ_INIT(&t->pending_delete);
868         }
869
870         for (i = 0; i < ctl->info.n_tables; i++) {
871                 struct table *t = &ctl->tables[i];
872                 uint32_t j;
873
874                 /* info. */
875                 status = rte_swx_ctl_table_info_get(p, i, &t->info);
876                 if (status)
877                         goto error;
878
879                 /* mf. */
880                 t->mf = calloc(t->info.n_match_fields,
881                         sizeof(struct rte_swx_ctl_table_match_field_info));
882                 if (!t->mf)
883                         goto error;
884
885                 for (j = 0; j < t->info.n_match_fields; j++) {
886                         status = rte_swx_ctl_table_match_field_info_get(p,
887                                 i,
888                                 j,
889                                 &t->mf[j]);
890                         if (status)
891                                 goto error;
892                 }
893
894                 /* actions. */
895                 t->actions = calloc(t->info.n_actions,
896                         sizeof(struct rte_swx_ctl_table_action_info));
897                 if (!t->actions)
898                         goto error;
899
900                 for (j = 0; j < t->info.n_actions; j++) {
901                         status = rte_swx_ctl_table_action_info_get(p,
902                                 i,
903                                 j,
904                                 &t->actions[j]);
905                         if (status ||
906                             t->actions[j].action_id >= ctl->info.n_actions)
907                                 goto error;
908                 }
909
910                 /* ops, is_stub. */
911                 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
912                 if (status)
913                         goto error;
914
915                 if ((t->is_stub && t->info.n_match_fields) ||
916                     (!t->is_stub && !t->info.n_match_fields))
917                         goto error;
918
919                 /* params. */
920                 status = table_params_get(ctl, i);
921                 if (status)
922                         goto error;
923         }
924
925         /* ts. */
926         status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
927         if (status)
928                 goto error;
929
930         /* ts_next. */
931         status = table_state_create(ctl);
932         if (status)
933                 goto error;
934
935         return ctl;
936
937 error:
938         rte_swx_ctl_pipeline_free(ctl);
939         return NULL;
940 }
941
942 int
943 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
944                                      const char *table_name,
945                                      struct rte_swx_table_entry *entry)
946 {
947         struct table *table;
948         struct rte_swx_table_entry *new_entry, *existing_entry;
949         uint32_t table_id;
950
951         CHECK(ctl, EINVAL);
952         CHECK(table_name && table_name[0], EINVAL);
953
954         table = table_find(ctl, table_name);
955         CHECK(table, EINVAL);
956         table_id = table - ctl->tables;
957
958         CHECK(entry, EINVAL);
959         CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
960
961         new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
962         CHECK(new_entry, ENOMEM);
963
964         /* The new entry is found in the table->entries list:
965          * - Add the new entry to the table->pending_modify1 list;
966          * - Move the existing entry from the table->entries list to the
967          *   table->pending_modify0 list.
968          */
969         existing_entry = table_entries_find(table, entry);
970         if (existing_entry) {
971                 TAILQ_INSERT_TAIL(&table->pending_modify1,
972                                   new_entry,
973                                   node);
974
975                 TAILQ_REMOVE(&table->entries,
976                              existing_entry,
977                              node);
978
979                 TAILQ_INSERT_TAIL(&table->pending_modify0,
980                                   existing_entry,
981                                   node);
982
983                 return 0;
984         }
985
986         /* The new entry is found in the table->pending_add list:
987          * - Replace the entry in the table->pending_add list with the new entry
988          *   (and free the replaced entry).
989          */
990         existing_entry = table_pending_add_find(table, entry);
991         if (existing_entry) {
992                 TAILQ_INSERT_AFTER(&table->pending_add,
993                                    existing_entry,
994                                    new_entry,
995                                    node);
996
997                 TAILQ_REMOVE(&table->pending_add,
998                              existing_entry,
999                              node);
1000
1001                 table_entry_free(existing_entry);
1002
1003                 return 0;
1004         }
1005
1006         /* The new entry is found in the table->pending_modify1 list:
1007          * - Replace the entry in the table->pending_modify1 list with the new
1008          *   entry (and free the replaced entry).
1009          */
1010         existing_entry = table_pending_modify1_find(table, entry);
1011         if (existing_entry) {
1012                 TAILQ_INSERT_AFTER(&table->pending_modify1,
1013                                    existing_entry,
1014                                    new_entry,
1015                                    node);
1016
1017                 TAILQ_REMOVE(&table->pending_modify1,
1018                              existing_entry,
1019                              node);
1020
1021                 table_entry_free(existing_entry);
1022
1023                 return 0;
1024         }
1025
1026         /* The new entry is found in the table->pending_delete list:
1027          * - Add the new entry to the table->pending_modify1 list;
1028          * - Move the existing entry from the table->pending_delete list to the
1029          *   table->pending_modify0 list.
1030          */
1031         existing_entry = table_pending_delete_find(table, entry);
1032         if (existing_entry) {
1033                 TAILQ_INSERT_TAIL(&table->pending_modify1,
1034                                   new_entry,
1035                                   node);
1036
1037                 TAILQ_REMOVE(&table->pending_delete,
1038                              existing_entry,
1039                              node);
1040
1041                 TAILQ_INSERT_TAIL(&table->pending_modify0,
1042                                   existing_entry,
1043                                   node);
1044
1045                 return 0;
1046         }
1047
1048         /* The new entry is not found in any of the above lists:
1049          * - Add the new entry to the table->pending_add list.
1050          */
1051         TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1052
1053         return 0;
1054 }
1055
1056 int
1057 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1058                                         const char *table_name,
1059                                         struct rte_swx_table_entry *entry)
1060 {
1061         struct table *table;
1062         struct rte_swx_table_entry *existing_entry;
1063         uint32_t table_id;
1064
1065         CHECK(ctl, EINVAL);
1066
1067         CHECK(table_name && table_name[0], EINVAL);
1068         table = table_find(ctl, table_name);
1069         CHECK(table, EINVAL);
1070         table_id = table - ctl->tables;
1071
1072         CHECK(entry, EINVAL);
1073         CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1074
1075         /* The entry is found in the table->entries list:
1076          * - Move the existing entry from the table->entries list to to the
1077          *   table->pending_delete list.
1078          */
1079         existing_entry = table_entries_find(table, entry);
1080         if (existing_entry) {
1081                 TAILQ_REMOVE(&table->entries,
1082                              existing_entry,
1083                              node);
1084
1085                 TAILQ_INSERT_TAIL(&table->pending_delete,
1086                                   existing_entry,
1087                                   node);
1088
1089                 return 0;
1090         }
1091
1092         /* The entry is found in the table->pending_add list:
1093          * - Remove the entry from the table->pending_add list and free it.
1094          */
1095         existing_entry = table_pending_add_find(table, entry);
1096         if (existing_entry) {
1097                 TAILQ_REMOVE(&table->pending_add,
1098                              existing_entry,
1099                              node);
1100
1101                 table_entry_free(existing_entry);
1102         }
1103
1104         /* The entry is found in the table->pending_modify1 list:
1105          * - Free the entry in the table->pending_modify1 list;
1106          * - Move the existing entry from the table->pending_modify0 list to the
1107          *   table->pending_delete list.
1108          */
1109         existing_entry = table_pending_modify1_find(table, entry);
1110         if (existing_entry) {
1111                 struct rte_swx_table_entry *real_existing_entry;
1112
1113                 TAILQ_REMOVE(&table->pending_modify1,
1114                              existing_entry,
1115                              node);
1116
1117                 table_entry_free(existing_entry);
1118
1119                 real_existing_entry = table_pending_modify0_find(table, entry);
1120                 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1121
1122                 TAILQ_REMOVE(&table->pending_modify0,
1123                              real_existing_entry,
1124                              node);
1125
1126                 TAILQ_INSERT_TAIL(&table->pending_delete,
1127                                   real_existing_entry,
1128                                   node);
1129
1130                 return 0;
1131         }
1132
1133         /* The entry is found in the table->pending_delete list:
1134          * - Do nothing: the existing entry is already in the
1135          *   table->pending_delete list, i.e. already marked for delete, so
1136          *   simply keep it there as it is.
1137          */
1138
1139         /* The entry is not found in any of the above lists:
1140          * - Do nothing: no existing entry to delete.
1141          */
1142
1143         return 0;
1144 }
1145
1146 int
1147 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1148                                              const char *table_name,
1149                                              struct rte_swx_table_entry *entry)
1150 {
1151         struct table *table;
1152         struct rte_swx_table_entry *new_entry;
1153         uint32_t table_id;
1154
1155         CHECK(ctl, EINVAL);
1156
1157         CHECK(table_name && table_name[0], EINVAL);
1158         table = table_find(ctl, table_name);
1159         CHECK(table, EINVAL);
1160         table_id = table - ctl->tables;
1161         CHECK(!table->info.default_action_is_const, EINVAL);
1162
1163         CHECK(entry, EINVAL);
1164         CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1165
1166         new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1167         CHECK(new_entry, ENOMEM);
1168
1169         table_pending_default_free(table);
1170
1171         table->pending_default = new_entry;
1172         return 0;
1173 }
1174
1175
1176 static void
1177 table_entry_list_free(struct rte_swx_table_entry_list *list)
1178 {
1179         for ( ; ; ) {
1180                 struct rte_swx_table_entry *entry;
1181
1182                 entry = TAILQ_FIRST(list);
1183                 if (!entry)
1184                         break;
1185
1186                 TAILQ_REMOVE(list, entry, node);
1187                 table_entry_free(entry);
1188         }
1189 }
1190
1191 static int
1192 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1193                            uint32_t table_id,
1194                            struct rte_swx_table_entry_list *dst,
1195                            struct rte_swx_table_entry_list *src)
1196 {
1197         struct rte_swx_table_entry *src_entry;
1198
1199         TAILQ_FOREACH(src_entry, src, node) {
1200                 struct rte_swx_table_entry *dst_entry;
1201
1202                 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1203                 if (!dst_entry)
1204                         goto error;
1205
1206                 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1207         }
1208
1209         return 0;
1210
1211 error:
1212         table_entry_list_free(dst);
1213         return -ENOMEM;
1214 }
1215
1216 /* This commit stage contains all the operations that can fail; in case ANY of
1217  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1218  */
1219 static int
1220 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1221                uint32_t table_id,
1222                uint32_t after_swap)
1223 {
1224         struct table *table = &ctl->tables[table_id];
1225         struct rte_swx_table_state *ts = &ctl->ts[table_id];
1226         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1227
1228         if (table->is_stub || !table_is_update_pending(table, 0))
1229                 return 0;
1230
1231         /*
1232          * Current table supports incremental update.
1233          */
1234         if (table->ops.add) {
1235                 /* Reset counters. */
1236                 table->n_add = 0;
1237                 table->n_modify = 0;
1238                 table->n_delete = 0;
1239
1240                 /* Add pending rules. */
1241                 struct rte_swx_table_entry *entry;
1242
1243                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1244                         int status;
1245
1246                         status = table->ops.add(ts_next->obj, entry);
1247                         if (status)
1248                                 return status;
1249
1250                         table->n_add++;
1251                 }
1252
1253                 /* Modify pending rules. */
1254                 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1255                         int status;
1256
1257                         status = table->ops.add(ts_next->obj, entry);
1258                         if (status)
1259                                 return status;
1260
1261                         table->n_modify++;
1262                 }
1263
1264                 /* Delete pending rules. */
1265                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1266                         int status;
1267
1268                         status = table->ops.del(ts_next->obj, entry);
1269                         if (status)
1270                                 return status;
1271
1272                         table->n_delete++;
1273                 }
1274
1275                 return 0;
1276         }
1277
1278         /*
1279          * Current table does NOT support incremental update.
1280          */
1281         if (!after_swap) {
1282                 struct rte_swx_table_entry_list list;
1283                 int status;
1284
1285                 /* Create updated list of entries included. */
1286                 TAILQ_INIT(&list);
1287
1288                 status = table_entry_list_duplicate(ctl,
1289                                                     table_id,
1290                                                     &list,
1291                                                     &table->entries);
1292                 if (status)
1293                         goto error;
1294
1295                 status = table_entry_list_duplicate(ctl,
1296                                                     table_id,
1297                                                     &list,
1298                                                     &table->pending_add);
1299                 if (status)
1300                         goto error;
1301
1302                 status = table_entry_list_duplicate(ctl,
1303                                                     table_id,
1304                                                     &list,
1305                                                     &table->pending_modify1);
1306                 if (status)
1307                         goto error;
1308
1309                 /* Create new table object with the updates included. */
1310                 ts_next->obj = table->ops.create(&table->params,
1311                                                  &list,
1312                                                  table->info.args,
1313                                                  ctl->numa_node);
1314                 if (!ts_next->obj) {
1315                         status = -ENODEV;
1316                         goto error;
1317                 }
1318
1319                 table_entry_list_free(&list);
1320
1321                 return 0;
1322
1323 error:
1324                 table_entry_list_free(&list);
1325                 return status;
1326         }
1327
1328         /* Free the old table object. */
1329         if (ts_next->obj && table->ops.free)
1330                 table->ops.free(ts_next->obj);
1331
1332         /* Copy over the new table object. */
1333         ts_next->obj = ts->obj;
1334
1335         return 0;
1336 }
1337
1338 /* This commit stage contains all the operations that cannot fail. They are
1339  * executed only if the previous stage was successful for ALL the tables. Hence,
1340  * none of these operations has to be rolled back for ANY table.
1341  */
1342 static void
1343 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1344 {
1345         struct table *table = &ctl->tables[table_id];
1346         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1347         struct action *a;
1348         uint8_t *action_data;
1349         uint64_t action_id;
1350
1351         /* Copy the pending default entry. */
1352         if (!table->pending_default)
1353                 return;
1354
1355         action_id = table->pending_default->action_id;
1356         action_data = table->pending_default->action_data;
1357         a = &ctl->actions[action_id];
1358
1359         memcpy(ts_next->default_action_data,
1360                action_data,
1361                a->data_size);
1362
1363         ts_next->default_action_id = action_id;
1364 }
1365
1366 /* This last commit stage is simply finalizing a successful commit operation.
1367  * This stage is only executed if all the previous stages were successful. This
1368  * stage cannot fail.
1369  */
1370 static void
1371 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1372 {
1373         struct table *table = &ctl->tables[table_id];
1374
1375         /* Move all the pending add entries to the table, as they are now part
1376          * of the table.
1377          */
1378         table_pending_add_admit(table);
1379
1380         /* Move all the pending modify1 entries to table, are they are now part
1381          * of the table. Free up all the pending modify0 entries, as they are no
1382          * longer part of the table.
1383          */
1384         table_pending_modify1_admit(table);
1385         table_pending_modify0_free(table);
1386
1387         /* Free up all the pending delete entries, as they are no longer part of
1388          * the table.
1389          */
1390         table_pending_delete_free(table);
1391
1392         /* Free up the pending default entry, as it is now part of the table. */
1393         table_pending_default_free(table);
1394 }
1395
1396 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1397  * commit operations that can fail did fail for ANY table. It reverts ALL the
1398  * tables to their state before the commit started, as if the commit never
1399  * happened.
1400  */
1401 static void
1402 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1403 {
1404         struct table *table = &ctl->tables[table_id];
1405         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1406
1407         if (table->is_stub || !table_is_update_pending(table, 0))
1408                 return;
1409
1410         if (table->ops.add) {
1411                 struct rte_swx_table_entry *entry;
1412
1413                 /* Add back all the entries that were just deleted. */
1414                 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1415                         if (!table->n_delete)
1416                                 break;
1417
1418                         table->ops.add(ts_next->obj, entry);
1419                         table->n_delete--;
1420                 }
1421
1422                 /* Add back the old copy for all the entries that were just
1423                  * modified.
1424                  */
1425                 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1426                         if (!table->n_modify)
1427                                 break;
1428
1429                         table->ops.add(ts_next->obj, entry);
1430                         table->n_modify--;
1431                 }
1432
1433                 /* Delete all the entries that were just added. */
1434                 TAILQ_FOREACH(entry, &table->pending_add, node) {
1435                         if (!table->n_add)
1436                                 break;
1437
1438                         table->ops.del(ts_next->obj, entry);
1439                         table->n_add--;
1440                 }
1441         } else {
1442                 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1443
1444                 /* Free the new table object, as update was cancelled. */
1445                 if (ts_next->obj && table->ops.free)
1446                         table->ops.free(ts_next->obj);
1447
1448                 /* Reinstate the old table object. */
1449                 ts_next->obj = ts->obj;
1450         }
1451 }
1452
1453 /* This stage is conditionally executed (as instructed by the user) after a
1454  * failed commit operation to remove ALL the pending work for ALL the tables.
1455  */
1456 static void
1457 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1458 {
1459         struct table *table = &ctl->tables[table_id];
1460
1461         /* Free up all the pending add entries, as none of them is part of the
1462          * table.
1463          */
1464         table_pending_add_free(table);
1465
1466         /* Free up all the pending modify1 entries, as none of them made it to
1467          * the table. Add back all the pending modify0 entries, as none of them
1468          * was deleted from the table.
1469          */
1470         table_pending_modify1_free(table);
1471         table_pending_modify0_admit(table);
1472
1473         /* Add back all the pending delete entries, as none of them was deleted
1474          * from the table.
1475          */
1476         table_pending_delete_admit(table);
1477
1478         /* Free up the pending default entry, as it is no longer going to be
1479          * added to the table.
1480          */
1481         table_pending_default_free(table);
1482 }
1483
1484 int
1485 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1486 {
1487         struct rte_swx_table_state *ts;
1488         int status = 0;
1489         uint32_t i;
1490
1491         CHECK(ctl, EINVAL);
1492
1493         /* Operate the changes on the current ts_next before it becomes the new
1494          * ts.
1495          */
1496         for (i = 0; i < ctl->info.n_tables; i++) {
1497                 status = table_rollfwd0(ctl, i, 0);
1498                 if (status)
1499                         goto rollback;
1500         }
1501
1502         for (i = 0; i < ctl->info.n_tables; i++)
1503                 table_rollfwd1(ctl, i);
1504
1505         /* Swap the table state for the data plane. The current ts and ts_next
1506          * become the new ts_next and ts, respectively.
1507          */
1508         rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1509         usleep(100);
1510         ts = ctl->ts;
1511         ctl->ts = ctl->ts_next;
1512         ctl->ts_next = ts;
1513
1514         /* Operate the changes on the current ts_next, which is the previous ts.
1515          */
1516         for (i = 0; i < ctl->info.n_tables; i++) {
1517                 table_rollfwd0(ctl, i, 1);
1518                 table_rollfwd1(ctl, i);
1519                 table_rollfwd2(ctl, i);
1520         }
1521
1522         return 0;
1523
1524 rollback:
1525         for (i = 0; i < ctl->info.n_tables; i++) {
1526                 table_rollback(ctl, i);
1527                 if (abort_on_fail)
1528                         table_abort(ctl, i);
1529         }
1530
1531         return status;
1532 }
1533
1534 void
1535 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1536 {
1537         uint32_t i;
1538
1539         if (!ctl)
1540                 return;
1541
1542         for (i = 0; i < ctl->info.n_tables; i++)
1543                 table_abort(ctl, i);
1544 }
1545
1546 static int
1547 token_is_comment(const char *token)
1548 {
1549         if ((token[0] == '#') ||
1550             (token[0] == ';') ||
1551             ((token[0] == '/') && (token[1] == '/')))
1552                 return 1; /* TRUE. */
1553
1554         return 0; /* FALSE. */
1555 }
1556
1557 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1558
1559 struct rte_swx_table_entry *
1560 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1561                                       const char *table_name,
1562                                       const char *string,
1563                                       int *is_blank_or_comment)
1564 {
1565         char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1566         struct table *table;
1567         struct action *action;
1568         struct rte_swx_table_entry *entry = NULL;
1569         char *s0 = NULL, *s;
1570         uint32_t n_tokens = 0, arg_offset = 0, i;
1571         int blank_or_comment = 0;
1572
1573         /* Check input arguments. */
1574         if (!ctl)
1575                 goto error;
1576
1577         if (!table_name || !table_name[0])
1578                 goto error;
1579
1580         table = table_find(ctl, table_name);
1581         if (!table)
1582                 goto error;
1583
1584         if (!string || !string[0])
1585                 goto error;
1586
1587         /* Memory allocation. */
1588         s0 = strdup(string);
1589         if (!s0)
1590                 goto error;
1591
1592         entry = table_entry_alloc(table);
1593         if (!entry)
1594                 goto error;
1595
1596         /* Parse the string into tokens. */
1597         for (s = s0; ; ) {
1598                 char *token;
1599
1600                 token = strtok_r(s, " \f\n\r\t\v", &s);
1601                 if (!token || token_is_comment(token))
1602                         break;
1603
1604                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1605                         goto error;
1606
1607                 token_array[n_tokens] = token;
1608                 n_tokens++;
1609         }
1610
1611         if (!n_tokens) {
1612                 blank_or_comment = 1;
1613                 goto error;
1614         }
1615
1616         tokens = token_array;
1617
1618         /*
1619          * Match.
1620          */
1621         if (n_tokens && strcmp(tokens[0], "match"))
1622                 goto action;
1623
1624         if (n_tokens < 1 + table->info.n_match_fields)
1625                 goto error;
1626
1627         for (i = 0; i < table->info.n_match_fields; i++) {
1628                 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1629                 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1630                 uint64_t val, mask = UINT64_MAX;
1631                 uint32_t offset = (mf->offset - table->mf[0].offset) / 8;
1632
1633                 /*
1634                  * Mask.
1635                  */
1636                 mf_mask = strchr(mf_val, '/');
1637                 if (mf_mask) {
1638                         *mf_mask = 0;
1639                         mf_mask++;
1640
1641                         /* Parse. */
1642                         mask = strtoull(mf_mask, &mf_mask, 0);
1643                         if (mf_mask[0])
1644                                 goto error;
1645
1646                         /* Endianness conversion. */
1647                         if (mf->is_header)
1648                                 mask = field_hton(mask, mf->n_bits);
1649                 }
1650
1651                 /* Copy to entry. */
1652                 if (entry->key_mask)
1653                         memcpy(&entry->key_mask[offset],
1654                                (uint8_t *)&mask,
1655                                mf->n_bits / 8);
1656
1657                 /*
1658                  * Value.
1659                  */
1660                 /* Parse. */
1661                 val = strtoull(mf_val, &mf_val, 0);
1662                 if (mf_val[0])
1663                         goto error;
1664
1665                 /* Endianness conversion. */
1666                 if (mf->is_header)
1667                         val = field_hton(val, mf->n_bits);
1668
1669                 /* Copy to entry. */
1670                 memcpy(&entry->key[offset],
1671                        (uint8_t *)&val,
1672                        mf->n_bits / 8);
1673         }
1674
1675         tokens += 1 + table->info.n_match_fields;
1676         n_tokens -= 1 + table->info.n_match_fields;
1677
1678         /*
1679          * Match priority.
1680          */
1681         if (n_tokens && !strcmp(tokens[0], "priority")) {
1682                 char *priority = tokens[1];
1683                 uint32_t val;
1684
1685                 if (n_tokens < 2)
1686                         goto error;
1687
1688                 /* Parse. */
1689                 val = strtoul(priority, &priority, 0);
1690                 if (priority[0])
1691                         goto error;
1692
1693                 /* Copy to entry. */
1694                 entry->key_priority = val;
1695
1696                 tokens += 2;
1697                 n_tokens -= 2;
1698         }
1699
1700         /*
1701          * Action.
1702          */
1703 action:
1704         if (n_tokens && strcmp(tokens[0], "action"))
1705                 goto other;
1706
1707         if (n_tokens < 2)
1708                 goto error;
1709
1710         action = action_find(ctl, tokens[1]);
1711         if (!action)
1712                 goto error;
1713
1714         if (n_tokens < 2 + action->info.n_args * 2)
1715                 goto error;
1716
1717         /* action_id. */
1718         entry->action_id = action - ctl->actions;
1719
1720         /* action_data. */
1721         for (i = 0; i < action->info.n_args; i++) {
1722                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1723                 char *arg_name, *arg_val;
1724                 uint64_t val;
1725                 int is_nbo = 0;
1726
1727                 arg_name = tokens[2 + i * 2];
1728                 arg_val = tokens[2 + i * 2 + 1];
1729
1730                 if (strcmp(arg_name, arg->name) ||
1731                     (strlen(arg_val) < 4) ||
1732                     ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1733                     (arg_val[1] != '(') ||
1734                     (arg_val[strlen(arg_val) - 1] != ')'))
1735                         goto error;
1736
1737                 if (arg_val[0] == 'N')
1738                         is_nbo = 1;
1739
1740                 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1741                 arg_val += 2; /* Remove the "H(" or "N(". */
1742
1743                 val = strtoull(arg_val, &arg_val, 0);
1744                 if (arg_val[0])
1745                         goto error;
1746
1747                 /* Endianness conversion. */
1748                 if (is_nbo)
1749                         val = field_hton(val, arg->n_bits);
1750
1751                 /* Copy to entry. */
1752                 memcpy(&entry->action_data[arg_offset],
1753                        (uint8_t *)&val,
1754                        arg->n_bits / 8);
1755
1756                 arg_offset += arg->n_bits / 8;
1757         }
1758
1759         tokens += 2 + action->info.n_args * 2;
1760         n_tokens -= 2 + action->info.n_args * 2;
1761
1762 other:
1763         if (n_tokens)
1764                 goto error;
1765
1766         free(s0);
1767         return entry;
1768
1769 error:
1770         table_entry_free(entry);
1771         free(s0);
1772         if (is_blank_or_comment)
1773                 *is_blank_or_comment = blank_or_comment;
1774         return NULL;
1775 }
1776
1777 static void
1778 table_entry_printf(FILE *f,
1779                    struct rte_swx_ctl_pipeline *ctl,
1780                    struct table *table,
1781                    struct rte_swx_table_entry *entry)
1782 {
1783         struct action *action = &ctl->actions[entry->action_id];
1784         uint32_t i;
1785
1786         fprintf(f, "match ");
1787         for (i = 0; i < table->params.key_size; i++)
1788                 fprintf(f, "%02x", entry->key[i]);
1789
1790         if (entry->key_mask) {
1791                 fprintf(f, "/");
1792                 for (i = 0; i < table->params.key_size; i++)
1793                         fprintf(f, "%02x", entry->key_mask[i]);
1794         }
1795
1796         fprintf(f, " priority %u", entry->key_priority);
1797
1798         fprintf(f, " action %s ", action->info.name);
1799         for (i = 0; i < action->data_size; i++)
1800                 fprintf(f, "%02x", entry->action_data[i]);
1801
1802         fprintf(f, "\n");
1803 }
1804
1805 int
1806 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1807                                    struct rte_swx_ctl_pipeline *ctl,
1808                                    const char *table_name)
1809 {
1810         struct table *table;
1811         struct rte_swx_table_entry *entry;
1812         uint32_t n_entries = 0, i;
1813
1814         if (!f || !ctl || !table_name || !table_name[0])
1815                 return -EINVAL;
1816
1817         table = table_find(ctl, table_name);
1818         if (!table)
1819                 return -EINVAL;
1820
1821         /* Table. */
1822         fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1823                 table->info.name,
1824                 table->params.key_size,
1825                 table->params.key_offset);
1826
1827         for (i = 0; i < table->params.key_size; i++)
1828                 fprintf(f, "%02x", table->params.key_mask0[i]);
1829
1830         fprintf(f, "], action data size %u bytes\n",
1831                 table->params.action_data_size);
1832
1833         /* Table entries. */
1834         TAILQ_FOREACH(entry, &table->entries, node) {
1835                 table_entry_printf(f, ctl, table, entry);
1836                 n_entries++;
1837         }
1838
1839         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1840                 table_entry_printf(f, ctl, table, entry);
1841                 n_entries++;
1842         }
1843
1844         TAILQ_FOREACH(entry, &table->pending_delete, node) {
1845                 table_entry_printf(f, ctl, table, entry);
1846                 n_entries++;
1847         }
1848
1849         fprintf(f, "# Table %s currently has %u entries.\n",
1850                 table_name,
1851                 n_entries);
1852         return 0;
1853 }