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