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