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