pipeline: add SWX table update high level API
[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         struct rte_swx_table_entry_list entries;
46         struct rte_swx_table_entry_list pending_add;
47         struct rte_swx_table_entry_list pending_modify0;
48         struct rte_swx_table_entry_list pending_modify1;
49         struct rte_swx_table_entry_list pending_delete;
50         struct rte_swx_table_entry *pending_default;
51
52         int is_stub;
53         uint32_t n_add;
54         uint32_t n_modify;
55         uint32_t n_delete;
56 };
57
58 struct rte_swx_ctl_pipeline {
59         struct rte_swx_ctl_pipeline_info info;
60         struct rte_swx_pipeline *p;
61         struct action *actions;
62         struct table *tables;
63         struct rte_swx_table_state *ts;
64         struct rte_swx_table_state *ts_next;
65         int numa_node;
66 };
67
68 static struct action *
69 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
70 {
71         uint32_t i;
72
73         for (i = 0; i < ctl->info.n_actions; i++) {
74                 struct action *a = &ctl->actions[i];
75
76                 if (!strcmp(action_name, a->info.name))
77                         return a;
78         }
79
80         return NULL;
81 }
82
83 static void
84 action_free(struct rte_swx_ctl_pipeline *ctl)
85 {
86         uint32_t i;
87
88         if (!ctl->actions)
89                 return;
90
91         for (i = 0; i < ctl->info.n_actions; i++) {
92                 struct action *action = &ctl->actions[i];
93
94                 free(action->args);
95         }
96
97         free(ctl->actions);
98         ctl->actions = NULL;
99 }
100
101 static struct table *
102 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
103 {
104         uint32_t i;
105
106         for (i = 0; i < ctl->info.n_tables; i++) {
107                 struct table *table = &ctl->tables[i];
108
109                 if (!strcmp(table_name, table->info.name))
110                         return table;
111         }
112
113         return NULL;
114 }
115
116 static int
117 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
118 {
119         struct table *table = &ctl->tables[table_id];
120         uint8_t *key_mask = NULL;
121         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
122         uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
123
124         if (table->info.n_match_fields) {
125                 struct rte_swx_ctl_table_match_field_info *first, *last;
126                 uint32_t i;
127
128                 first = &table->mf[0];
129                 last = &table->mf[table->info.n_match_fields - 1];
130
131                 /* match_type. */
132                 for (i = 0; i < table->info.n_match_fields; i++) {
133                         struct rte_swx_ctl_table_match_field_info *f;
134
135                         f = &table->mf[i];
136                         if (f->match_type != RTE_SWX_TABLE_MATCH_EXACT)
137                                 break;
138                 }
139
140                 if (i == table->info.n_match_fields)
141                         match_type = RTE_SWX_TABLE_MATCH_EXACT;
142                 else if ((i == table->info.n_match_fields - 1) &&
143                          (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
144                         match_type = RTE_SWX_TABLE_MATCH_LPM;
145
146                 /* key_offset. */
147                 key_offset = first->offset / 8;
148
149                 /* key_size. */
150                 key_size = (last->offset + last->n_bits - first->offset) / 8;
151
152                 /* key_mask. */
153                 key_mask = calloc(1, key_size);
154                 CHECK(key_mask, ENOMEM);
155
156                 for (i = 0; i < table->info.n_match_fields; i++) {
157                         struct rte_swx_ctl_table_match_field_info *f;
158                         uint32_t start;
159                         size_t size;
160
161                         f = &table->mf[i];
162                         start = (f->offset - first->offset) / 8;
163                         size = f->n_bits / 8;
164
165                         memset(&key_mask[start], 0xFF, size);
166                 }
167         }
168
169         /* action_data_size. */
170         for (i = 0; i < table->info.n_actions; i++) {
171                 uint32_t action_id = table->actions[i].action_id;
172                 struct action *a = &ctl->actions[action_id];
173
174                 if (a->data_size > action_data_size)
175                         action_data_size = a->data_size;
176         }
177
178         /* Fill in. */
179         table->params.match_type = match_type;
180         table->params.key_size = key_size;
181         table->params.key_offset = key_offset;
182         table->params.key_mask0 = key_mask;
183         table->params.action_data_size = action_data_size;
184         table->params.n_keys_max = table->info.size;
185
186         return 0;
187 }
188
189 static void
190 table_entry_free(struct rte_swx_table_entry *entry)
191 {
192         if (!entry)
193                 return;
194
195         free(entry->key);
196         free(entry->key_mask);
197         free(entry->action_data);
198         free(entry);
199 }
200
201 static struct rte_swx_table_entry *
202 table_entry_alloc(struct table *table)
203 {
204         struct rte_swx_table_entry *entry;
205
206         entry = calloc(1, sizeof(struct rte_swx_table_entry));
207         if (!entry)
208                 goto error;
209
210         /* key, key_mask. */
211         if (!table->is_stub) {
212                 entry->key = calloc(1, table->params.key_size);
213                 if (!entry->key)
214                         goto error;
215
216                 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
217                         entry->key_mask = calloc(1, table->params.key_size);
218                         if (!entry->key_mask)
219                                 goto error;
220                 }
221         }
222
223         /* action_data. */
224         if (table->params.action_data_size) {
225                 entry->action_data = calloc(1, table->params.action_data_size);
226                 if (!entry->action_data)
227                         goto error;
228         }
229
230         return entry;
231
232 error:
233         table_entry_free(entry);
234         return NULL;
235 }
236
237 static int
238 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
239                   uint32_t table_id,
240                   struct rte_swx_table_entry *entry,
241                   int key_check,
242                   int data_check)
243 {
244         struct table *table = &ctl->tables[table_id];
245
246         CHECK(entry, EINVAL);
247
248         if (key_check) {
249                 if (table->is_stub) {
250                         /* key. */
251                         CHECK(!entry->key, EINVAL);
252
253                         /* key_mask. */
254                         CHECK(!entry->key_mask, EINVAL);
255                 } else {
256                         /* key. */
257                         CHECK(entry->key, EINVAL);
258
259                         /* key_mask. */
260                         switch (table->params.match_type) {
261                         case RTE_SWX_TABLE_MATCH_WILDCARD:
262                                 break;
263
264                         case RTE_SWX_TABLE_MATCH_LPM:
265                                 /* TBD Check that key mask is prefix. */
266                                 break;
267
268                         case RTE_SWX_TABLE_MATCH_EXACT:
269                                 CHECK(!entry->key_mask, EINVAL);
270                                 break;
271
272                         default:
273                                 CHECK(0, EINVAL);
274                         }
275                 }
276         }
277
278         if (data_check) {
279                 struct action *a;
280                 uint32_t i;
281
282                 /* action_id. */
283                 for (i = 0; i < table->info.n_actions; i++)
284                         if (entry->action_id == table->actions[i].action_id)
285                                 break;
286
287                 CHECK(i < table->info.n_actions, EINVAL);
288
289                 /* action_data. */
290                 a = &ctl->actions[entry->action_id];
291                 CHECK((a->data_size && entry->action_data) ||
292                       (!a->data_size && !entry->action_data), EINVAL);
293         }
294
295         return 0;
296 }
297
298 static struct rte_swx_table_entry *
299 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
300                       uint32_t table_id,
301                       struct rte_swx_table_entry *entry,
302                       int key_duplicate,
303                       int data_duplicate)
304 {
305         struct table *table = &ctl->tables[table_id];
306         struct rte_swx_table_entry *new_entry = NULL;
307
308         if (!entry)
309                 goto error;
310
311         new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
312         if (!new_entry)
313                 goto error;
314
315         if (key_duplicate && !table->is_stub) {
316                 /* key. */
317                 if (!entry->key)
318                         goto error;
319
320                 new_entry->key = malloc(table->params.key_size);
321                 if (!new_entry->key)
322                         goto error;
323
324                 memcpy(new_entry->key, entry->key, table->params.key_size);
325
326                 /* key_signature. */
327                 new_entry->key_signature = entry->key_signature;
328
329                 /* key_mask. */
330                 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
331                         if (!entry->key_mask)
332                                 goto error;
333
334                         new_entry->key_mask = malloc(table->params.key_size);
335                         if (!new_entry->key_mask)
336                                 goto error;
337
338                         memcpy(new_entry->key_mask,
339                                entry->key_mask,
340                                table->params.key_size);
341                 }
342         }
343
344         if (data_duplicate) {
345                 struct action *a;
346                 uint32_t i;
347
348                 /* action_id. */
349                 for (i = 0; i < table->info.n_actions; i++)
350                         if (entry->action_id == table->actions[i].action_id)
351                                 break;
352
353                 if (i >= table->info.n_actions)
354                         goto error;
355
356                 new_entry->action_id = entry->action_id;
357
358                 /* action_data. */
359                 a = &ctl->actions[entry->action_id];
360                 if (a->data_size) {
361                         if (!entry->action_data)
362                                 goto error;
363
364                         new_entry->action_data = malloc(a->data_size);
365                         if (!new_entry->action_data)
366                                 goto error;
367
368                         memcpy(new_entry->action_data,
369                                entry->action_data,
370                                a->data_size);
371                 }
372         }
373
374         return entry;
375
376 error:
377         table_entry_free(new_entry);
378         return NULL;
379 }
380
381 static int
382 entry_keycmp_em(struct rte_swx_table_entry *e0,
383                 struct rte_swx_table_entry *e1,
384                 uint32_t key_size)
385 {
386         if (e0->key_signature != e1->key_signature)
387                 return 1; /* Not equal. */
388
389         if (memcmp(e0->key, e1->key, key_size))
390                 return 1; /* Not equal. */
391
392         return 0; /* Equal */
393 }
394
395 static int
396 entry_keycmp_wm(struct rte_swx_table_entry *e0 __rte_unused,
397                 struct rte_swx_table_entry *e1 __rte_unused,
398                 uint32_t key_size __rte_unused)
399 {
400         /* TBD */
401
402         return 1; /* Not equal */
403 }
404
405 static int
406 entry_keycmp_lpm(struct rte_swx_table_entry *e0 __rte_unused,
407                  struct rte_swx_table_entry *e1 __rte_unused,
408                  uint32_t key_size __rte_unused)
409 {
410         /* TBD */
411
412         return 1; /* Not equal */
413 }
414
415 static int
416 table_entry_keycmp(struct table *table,
417                    struct rte_swx_table_entry *e0,
418                    struct rte_swx_table_entry *e1)
419 {
420         switch (table->params.match_type) {
421         case RTE_SWX_TABLE_MATCH_EXACT:
422                 return entry_keycmp_em(e0, e1, table->params.key_size);
423
424         case RTE_SWX_TABLE_MATCH_WILDCARD:
425                 return entry_keycmp_wm(e0, e1, table->params.key_size);
426
427         case RTE_SWX_TABLE_MATCH_LPM:
428                 return entry_keycmp_lpm(e0, e1, table->params.key_size);
429
430         default:
431                 return 1; /* Not equal. */
432         }
433 }
434
435 static struct rte_swx_table_entry *
436 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
437 {
438         struct rte_swx_table_entry *e;
439
440         TAILQ_FOREACH(e, &table->entries, node)
441                 if (!table_entry_keycmp(table, entry, e))
442                         return e; /* Found. */
443
444         return NULL; /* Not found. */
445 }
446
447 static void
448 table_entries_free(struct table *table)
449 {
450         for ( ; ; ) {
451                 struct rte_swx_table_entry *entry;
452
453                 entry = TAILQ_FIRST(&table->entries);
454                 if (!entry)
455                         break;
456
457                 TAILQ_REMOVE(&table->entries, entry, node);
458                 table_entry_free(entry);
459         }
460 }
461
462 static struct rte_swx_table_entry *
463 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
464 {
465         struct rte_swx_table_entry *e;
466
467         TAILQ_FOREACH(e, &table->pending_add, node)
468                 if (!table_entry_keycmp(table, entry, e))
469                         return e; /* Found. */
470
471         return NULL; /* Not found. */
472 }
473
474 static void
475 table_pending_add_admit(struct table *table)
476 {
477         TAILQ_CONCAT(&table->entries, &table->pending_add, node);
478 }
479
480 static void
481 table_pending_add_free(struct table *table)
482 {
483         for ( ; ; ) {
484                 struct rte_swx_table_entry *entry;
485
486                 entry = TAILQ_FIRST(&table->pending_add);
487                 if (!entry)
488                         break;
489
490                 TAILQ_REMOVE(&table->pending_add, entry, node);
491                 table_entry_free(entry);
492         }
493 }
494
495 static struct rte_swx_table_entry *
496 table_pending_modify0_find(struct table *table,
497                            struct rte_swx_table_entry *entry)
498 {
499         struct rte_swx_table_entry *e;
500
501         TAILQ_FOREACH(e, &table->pending_modify0, node)
502                 if (!table_entry_keycmp(table, entry, e))
503                         return e; /* Found. */
504
505         return NULL; /* Not found. */
506 }
507
508 static void
509 table_pending_modify0_admit(struct table *table)
510 {
511         TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
512 }
513
514 static void
515 table_pending_modify0_free(struct table *table)
516 {
517         for ( ; ; ) {
518                 struct rte_swx_table_entry *entry;
519
520                 entry = TAILQ_FIRST(&table->pending_modify0);
521                 if (!entry)
522                         break;
523
524                 TAILQ_REMOVE(&table->pending_modify0, entry, node);
525                 table_entry_free(entry);
526         }
527 }
528
529 static struct rte_swx_table_entry *
530 table_pending_modify1_find(struct table *table,
531                            struct rte_swx_table_entry *entry)
532 {
533         struct rte_swx_table_entry *e;
534
535         TAILQ_FOREACH(e, &table->pending_modify1, node)
536                 if (!table_entry_keycmp(table, entry, e))
537                         return e; /* Found. */
538
539         return NULL; /* Not found. */
540 }
541
542 static void
543 table_pending_modify1_admit(struct table *table)
544 {
545         TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
546 }
547
548 static void
549 table_pending_modify1_free(struct table *table)
550 {
551         for ( ; ; ) {
552                 struct rte_swx_table_entry *entry;
553
554                 entry = TAILQ_FIRST(&table->pending_modify1);
555                 if (!entry)
556                         break;
557
558                 TAILQ_REMOVE(&table->pending_modify1, entry, node);
559                 table_entry_free(entry);
560         }
561 }
562
563 static struct rte_swx_table_entry *
564 table_pending_delete_find(struct table *table,
565                           struct rte_swx_table_entry *entry)
566 {
567         struct rte_swx_table_entry *e;
568
569         TAILQ_FOREACH(e, &table->pending_delete, node)
570                 if (!table_entry_keycmp(table, entry, e))
571                         return e; /* Found. */
572
573         return NULL; /* Not found. */
574 }
575
576 static void
577 table_pending_delete_admit(struct table *table)
578 {
579         TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
580 }
581
582 static void
583 table_pending_delete_free(struct table *table)
584 {
585         for ( ; ; ) {
586                 struct rte_swx_table_entry *entry;
587
588                 entry = TAILQ_FIRST(&table->pending_delete);
589                 if (!entry)
590                         break;
591
592                 TAILQ_REMOVE(&table->pending_delete, entry, node);
593                 table_entry_free(entry);
594         }
595 }
596
597 static void
598 table_pending_default_free(struct table *table)
599 {
600         if (!table->pending_default)
601                 return;
602
603         free(table->pending_default->action_data);
604         free(table->pending_default);
605         table->pending_default = NULL;
606 }
607
608 static void
609 table_free(struct rte_swx_ctl_pipeline *ctl)
610 {
611         uint32_t i;
612
613         if (!ctl->tables)
614                 return;
615
616         for (i = 0; i < ctl->info.n_tables; i++) {
617                 struct table *table = &ctl->tables[i];
618
619                 free(table->mf);
620                 free(table->actions);
621                 free(table->params.key_mask0);
622
623                 table_entries_free(table);
624                 table_pending_add_free(table);
625                 table_pending_modify0_free(table);
626                 table_pending_modify1_free(table);
627                 table_pending_delete_free(table);
628                 table_pending_default_free(table);
629         }
630
631         free(ctl->tables);
632         ctl->tables = NULL;
633 }
634
635 static void
636 table_state_free(struct rte_swx_ctl_pipeline *ctl)
637 {
638         uint32_t i;
639
640         if (!ctl->ts_next)
641                 return;
642
643         /* For each table, free its table state. */
644         for (i = 0; i < ctl->info.n_tables; i++) {
645                 struct table *table = &ctl->tables[i];
646                 struct rte_swx_table_state *ts = &ctl->ts_next[i];
647
648                 /* Default action data. */
649                 free(ts->default_action_data);
650
651                 /* Table object. */
652                 if (!table->is_stub && table->ops.free && ts->obj)
653                         table->ops.free(ts->obj);
654         }
655
656         free(ctl->ts_next);
657         ctl->ts_next = NULL;
658 }
659
660 static int
661 table_state_create(struct rte_swx_ctl_pipeline *ctl)
662 {
663         int status = 0;
664         uint32_t i;
665
666         ctl->ts_next = calloc(ctl->info.n_tables,
667                               sizeof(struct rte_swx_table_state));
668         if (!ctl->ts_next) {
669                 status = -ENOMEM;
670                 goto error;
671         }
672
673         for (i = 0; i < ctl->info.n_tables; i++) {
674                 struct table *table = &ctl->tables[i];
675                 struct rte_swx_table_state *ts = &ctl->ts[i];
676                 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
677
678                 /* Table object. */
679                 if (!table->is_stub) {
680                         ts_next->obj = table->ops.create(&table->params,
681                                                          &table->entries,
682                                                          table->info.args,
683                                                          ctl->numa_node);
684                         if (!ts_next->obj) {
685                                 status = -ENODEV;
686                                 goto error;
687                         }
688                 }
689
690                 /* Default action data: duplicate from current table state. */
691                 ts_next->default_action_data =
692                         malloc(table->params.action_data_size);
693                 if (!ts_next->default_action_data) {
694                         status = -ENOMEM;
695                         goto error;
696                 }
697
698                 memcpy(ts_next->default_action_data,
699                        ts->default_action_data,
700                        table->params.action_data_size);
701
702                 ts_next->default_action_id = ts->default_action_id;
703         }
704
705         return 0;
706
707 error:
708         table_state_free(ctl);
709         return status;
710 }
711
712 void
713 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
714 {
715         if (!ctl)
716                 return;
717
718         action_free(ctl);
719
720         table_state_free(ctl);
721
722         table_free(ctl);
723
724         free(ctl);
725 }
726
727 struct rte_swx_ctl_pipeline *
728 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
729 {
730         struct rte_swx_ctl_pipeline *ctl = NULL;
731         uint32_t i;
732         int status;
733
734         if (!p)
735                 goto error;
736
737         ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
738         if (!ctl)
739                 goto error;
740
741         /* info. */
742         status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
743         if (status)
744                 goto error;
745
746         /* numa_node. */
747         status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
748         if (status)
749                 goto error;
750
751         /* p. */
752         ctl->p = p;
753
754         /* actions. */
755         ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
756         if (!ctl->actions)
757                 goto error;
758
759         for (i = 0; i < ctl->info.n_actions; i++) {
760                 struct action *a = &ctl->actions[i];
761                 uint32_t j;
762
763                 /* info. */
764                 status = rte_swx_ctl_action_info_get(p, i, &a->info);
765                 if (status)
766                         goto error;
767
768                 /* args. */
769                 a->args = calloc(a->info.n_args,
770                                  sizeof(struct rte_swx_ctl_action_arg_info));
771                 if (!a->args)
772                         goto error;
773
774                 for (j = 0; j < a->info.n_args; j++) {
775                         status = rte_swx_ctl_action_arg_info_get(p,
776                                                                  i,
777                                                                  j,
778                                                                  &a->args[j]);
779                         if (status)
780                                 goto error;
781                 }
782
783                 /* data_size. */
784                 for (j = 0; j < a->info.n_args; j++) {
785                         struct rte_swx_ctl_action_arg_info *info = &a->args[j];
786
787                         a->data_size += info->n_bits;
788                 }
789
790                 a->data_size = (a->data_size + 7) / 8;
791         }
792
793         /* tables. */
794         ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
795         if (!ctl->tables)
796                 goto error;
797
798         for (i = 0; i < ctl->info.n_tables; i++) {
799                 struct table *t = &ctl->tables[i];
800
801                 TAILQ_INIT(&t->entries);
802                 TAILQ_INIT(&t->pending_add);
803                 TAILQ_INIT(&t->pending_modify0);
804                 TAILQ_INIT(&t->pending_modify1);
805                 TAILQ_INIT(&t->pending_delete);
806         }
807
808         for (i = 0; i < ctl->info.n_tables; i++) {
809                 struct table *t = &ctl->tables[i];
810                 uint32_t j;
811
812                 /* info. */
813                 status = rte_swx_ctl_table_info_get(p, i, &t->info);
814                 if (status)
815                         goto error;
816
817                 /* mf. */
818                 t->mf = calloc(t->info.n_match_fields,
819                         sizeof(struct rte_swx_ctl_table_match_field_info));
820                 if (!t->mf)
821                         goto error;
822
823                 for (j = 0; j < t->info.n_match_fields; j++) {
824                         status = rte_swx_ctl_table_match_field_info_get(p,
825                                 i,
826                                 j,
827                                 &t->mf[j]);
828                         if (status)
829                                 goto error;
830                 }
831
832                 /* actions. */
833                 t->actions = calloc(t->info.n_actions,
834                         sizeof(struct rte_swx_ctl_table_action_info));
835                 if (!t->actions)
836                         goto error;
837
838                 for (j = 0; j < t->info.n_actions; j++) {
839                         status = rte_swx_ctl_table_action_info_get(p,
840                                 i,
841                                 j,
842                                 &t->actions[j]);
843                         if (status ||
844                             t->actions[j].action_id >= ctl->info.n_actions)
845                                 goto error;
846                 }
847
848                 /* ops, is_stub. */
849                 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
850                 if (status)
851                         goto error;
852
853                 if ((t->is_stub && t->info.n_match_fields) ||
854                     (!t->is_stub && !t->info.n_match_fields))
855                         goto error;
856
857                 /* params. */
858                 status = table_params_get(ctl, i);
859                 if (status)
860                         goto error;
861         }
862
863         /* ts. */
864         status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
865         if (status)
866                 goto error;
867
868         /* ts_next. */
869         status = table_state_create(ctl);
870         if (status)
871                 goto error;
872
873         return ctl;
874
875 error:
876         rte_swx_ctl_pipeline_free(ctl);
877         return NULL;
878 }
879
880 int
881 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
882                                      const char *table_name,
883                                      struct rte_swx_table_entry *entry)
884 {
885         struct table *table;
886         struct rte_swx_table_entry *new_entry, *existing_entry;
887         uint32_t table_id;
888
889         CHECK(ctl, EINVAL);
890         CHECK(table_name && table_name[0], EINVAL);
891
892         table = table_find(ctl, table_name);
893         CHECK(table, EINVAL);
894         table_id = table - ctl->tables;
895
896         new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
897         CHECK(new_entry, ENOMEM);
898
899         /* The new entry is found in the table->entries list:
900          * - Add the new entry to the table->pending_modify1 list;
901          * - Move the existing entry from the table->entries list to the
902          *   table->pending_modify0 list.
903          */
904         existing_entry = table_entries_find(table, entry);
905         if (existing_entry) {
906                 TAILQ_INSERT_TAIL(&table->pending_modify1,
907                                   new_entry,
908                                   node);
909
910                 TAILQ_REMOVE(&table->entries,
911                              existing_entry,
912                              node);
913
914                 TAILQ_INSERT_TAIL(&table->pending_modify0,
915                                   existing_entry,
916                                   node);
917
918                 return 0;
919         }
920
921         /* The new entry is found in the table->pending_add list:
922          * - Replace the entry in the table->pending_add list with the new entry
923          *   (and free the replaced entry).
924          */
925         existing_entry = table_pending_add_find(table, entry);
926         if (existing_entry) {
927                 TAILQ_INSERT_AFTER(&table->pending_add,
928                                    existing_entry,
929                                    new_entry,
930                                    node);
931
932                 TAILQ_REMOVE(&table->pending_add,
933                              existing_entry,
934                              node);
935
936                 table_entry_free(existing_entry);
937
938                 return 0;
939         }
940
941         /* The new entry is found in the table->pending_modify1 list:
942          * - Replace the entry in the table->pending_modify1 list with the new
943          *   entry (and free the replaced entry).
944          */
945         existing_entry = table_pending_modify1_find(table, entry);
946         if (existing_entry) {
947                 TAILQ_INSERT_AFTER(&table->pending_modify1,
948                                    existing_entry,
949                                    new_entry,
950                                    node);
951
952                 TAILQ_REMOVE(&table->pending_modify1,
953                              existing_entry,
954                              node);
955
956                 table_entry_free(existing_entry);
957
958                 return 0;
959         }
960
961         /* The new entry is found in the table->pending_delete list:
962          * - Add the new entry to the table->pending_modify1 list;
963          * - Move the existing entry from the table->pending_delete list to the
964          *   table->pending_modify0 list.
965          */
966         existing_entry = table_pending_delete_find(table, entry);
967         if (existing_entry) {
968                 TAILQ_INSERT_TAIL(&table->pending_modify1,
969                                   new_entry,
970                                   node);
971
972                 TAILQ_REMOVE(&table->pending_delete,
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 not found in any of the above lists:
984          * - Add the new entry to the table->pending_add list.
985          */
986         TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
987
988         return 0;
989 }
990
991 int
992 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
993                                         const char *table_name,
994                                         struct rte_swx_table_entry *entry)
995 {
996         struct table *table;
997         struct rte_swx_table_entry *existing_entry;
998         uint32_t table_id;
999
1000         CHECK(ctl, EINVAL);
1001
1002         CHECK(table_name && table_name[0], EINVAL);
1003         table = table_find(ctl, table_name);
1004         CHECK(table, EINVAL);
1005         table_id = table - ctl->tables;
1006
1007         CHECK(entry, EINVAL);
1008         CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1009
1010         /* The entry is found in the table->entries list:
1011          * - Move the existing entry from the table->entries list to to the
1012          *   table->pending_delete list.
1013          */
1014         existing_entry = table_entries_find(table, entry);
1015         if (existing_entry) {
1016                 TAILQ_REMOVE(&table->entries,
1017                              existing_entry,
1018                              node);
1019
1020                 TAILQ_INSERT_TAIL(&table->pending_delete,
1021                                   existing_entry,
1022                                   node);
1023
1024                 return 0;
1025         }
1026
1027         /* The entry is found in the table->pending_add list:
1028          * - Remove the entry from the table->pending_add list and free it.
1029          */
1030         existing_entry = table_pending_add_find(table, entry);
1031         if (existing_entry) {
1032                 TAILQ_REMOVE(&table->pending_add,
1033                              existing_entry,
1034                              node);
1035
1036                 table_entry_free(existing_entry);
1037         }
1038
1039         /* The entry is found in the table->pending_modify1 list:
1040          * - Free the entry in the table->pending_modify1 list;
1041          * - Move the existing entry from the table->pending_modify0 list to the
1042          *   table->pending_delete list.
1043          */
1044         existing_entry = table_pending_modify1_find(table, entry);
1045         if (existing_entry) {
1046                 struct rte_swx_table_entry *real_existing_entry;
1047
1048                 TAILQ_REMOVE(&table->pending_modify1,
1049                              existing_entry,
1050                              node);
1051
1052                 table_entry_free(existing_entry);
1053
1054                 real_existing_entry = table_pending_modify0_find(table, entry);
1055                 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1056
1057                 TAILQ_REMOVE(&table->pending_modify0,
1058                              real_existing_entry,
1059                              node);
1060
1061                 TAILQ_INSERT_TAIL(&table->pending_delete,
1062                                   real_existing_entry,
1063                                   node);
1064
1065                 return 0;
1066         }
1067
1068         /* The entry is found in the table->pending_delete list:
1069          * - Do nothing: the existing entry is already in the
1070          *   table->pending_delete list, i.e. already marked for delete, so
1071          *   simply keep it there as it is.
1072          */
1073
1074         /* The entry is not found in any of the above lists:
1075          * - Do nothing: no existing entry to delete.
1076          */
1077
1078         return 0;
1079 }
1080
1081 int
1082 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1083                                              const char *table_name,
1084                                              struct rte_swx_table_entry *entry)
1085 {
1086         struct table *table;
1087         struct rte_swx_table_entry *new_entry;
1088         uint32_t table_id;
1089
1090         CHECK(ctl, EINVAL);
1091
1092         CHECK(table_name && table_name[0], EINVAL);
1093         table = table_find(ctl, table_name);
1094         CHECK(table, EINVAL);
1095         table_id = table - ctl->tables;
1096         CHECK(!table->info.default_action_is_const, EINVAL);
1097
1098         new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1099         CHECK(new_entry, ENOMEM);
1100
1101         table_pending_default_free(table);
1102
1103         table->pending_default = new_entry;
1104         return 0;
1105 }
1106
1107 static int
1108 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1109 {
1110         struct table *table = &ctl->tables[table_id];
1111         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1112         struct rte_swx_table_entry *entry;
1113
1114         /* Reset counters. */
1115         table->n_add = 0;
1116         table->n_modify = 0;
1117         table->n_delete = 0;
1118
1119         /* Add pending rules. */
1120         TAILQ_FOREACH(entry, &table->pending_add, node) {
1121                 int status;
1122
1123                 status = table->ops.add(ts_next->obj, entry);
1124                 if (status)
1125                         return status;
1126
1127                 table->n_add++;
1128         }
1129
1130         /* Modify pending rules. */
1131         TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1132                 int status;
1133
1134                 status = table->ops.add(ts_next->obj, entry);
1135                 if (status)
1136                         return status;
1137
1138                 table->n_modify++;
1139         }
1140
1141         /* Delete pending rules. */
1142         TAILQ_FOREACH(entry, &table->pending_delete, node) {
1143                 int status;
1144
1145                 status = table->ops.del(ts_next->obj, entry);
1146                 if (status)
1147                         return status;
1148
1149                 table->n_delete++;
1150         }
1151
1152         return 0;
1153 }
1154
1155 static void
1156 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1157 {
1158         struct table *table = &ctl->tables[table_id];
1159         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1160         struct action *a;
1161         uint8_t *action_data;
1162         uint64_t action_id;
1163
1164         /* Copy the pending default entry. */
1165         if (!table->pending_default)
1166                 return;
1167
1168         action_id = table->pending_default->action_id;
1169         action_data = table->pending_default->action_data;
1170         a = &ctl->actions[action_id];
1171
1172         memcpy(ts_next->default_action_data,
1173                action_data,
1174                a->data_size);
1175
1176         ts_next->default_action_id = action_id;
1177 }
1178
1179 static void
1180 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1181 {
1182         struct table *table = &ctl->tables[table_id];
1183
1184         /* Move all the pending add entries to the table, as they are now part
1185          * of the table.
1186          */
1187         table_pending_add_admit(table);
1188
1189         /* Move all the pending modify1 entries to table, are they are now part
1190          * of the table. Free up all the pending modify0 entries, as they are no
1191          * longer part of the table.
1192          */
1193         table_pending_modify1_admit(table);
1194         table_pending_modify0_free(table);
1195
1196         /* Free up all the pending delete entries, as they are no longer part of
1197          * the table.
1198          */
1199         table_pending_delete_free(table);
1200
1201         /* Free up the pending default entry, as it is now part of the table. */
1202         table_pending_default_free(table);
1203 }
1204
1205 static void
1206 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1207 {
1208         struct table *table = &ctl->tables[table_id];
1209         struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1210         struct rte_swx_table_entry *entry;
1211
1212         /* Add back all the entries that were just deleted. */
1213         TAILQ_FOREACH(entry, &table->pending_delete, node) {
1214                 if (!table->n_delete)
1215                         break;
1216
1217                 table->ops.add(ts_next->obj, entry);
1218                 table->n_delete--;
1219         }
1220
1221         /* Add back the old copy for all the entries that were just
1222          * modified.
1223          */
1224         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1225                 if (!table->n_modify)
1226                         break;
1227
1228                 table->ops.add(ts_next->obj, entry);
1229                 table->n_modify--;
1230         }
1231
1232         /* Delete all the entries that were just added. */
1233         TAILQ_FOREACH(entry, &table->pending_add, node) {
1234                 if (!table->n_add)
1235                         break;
1236
1237                 table->ops.del(ts_next->obj, entry);
1238                 table->n_add--;
1239         }
1240 }
1241
1242 static void
1243 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1244 {
1245         struct table *table = &ctl->tables[table_id];
1246
1247         /* Free up all the pending add entries, as none of them is part of the
1248          * table.
1249          */
1250         table_pending_add_free(table);
1251
1252         /* Free up all the pending modify1 entries, as none of them made it to
1253          * the table. Add back all the pending modify0 entries, as none of them
1254          * was deleted from the table.
1255          */
1256         table_pending_modify1_free(table);
1257         table_pending_modify0_admit(table);
1258
1259         /* Add back all the pending delete entries, as none of them was deleted
1260          * from the table.
1261          */
1262         table_pending_delete_admit(table);
1263
1264         /* Free up the pending default entry, as it is no longer going to be
1265          * added to the table.
1266          */
1267         table_pending_default_free(table);
1268 }
1269
1270 int
1271 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1272 {
1273         struct rte_swx_table_state *ts;
1274         int status = 0;
1275         uint32_t i;
1276
1277         CHECK(ctl, EINVAL);
1278
1279         /* Operate the changes on the current ts_next before it becomes the new
1280          * ts.
1281          */
1282         for (i = 0; i < ctl->info.n_tables; i++) {
1283                 status = table_rollfwd0(ctl, i);
1284                 if (status)
1285                         goto rollback;
1286         }
1287
1288         for (i = 0; i < ctl->info.n_tables; i++)
1289                 table_rollfwd1(ctl, i);
1290
1291         /* Swap the table state for the data plane. The current ts and ts_next
1292          * become the new ts_next and ts, respectively.
1293          */
1294         rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1295         usleep(100);
1296         ts = ctl->ts;
1297         ctl->ts = ctl->ts_next;
1298         ctl->ts_next = ts;
1299
1300         /* Operate the changes on the current ts_next, which is the previous ts.
1301          */
1302         for (i = 0; i < ctl->info.n_tables; i++) {
1303                 table_rollfwd0(ctl, i);
1304                 table_rollfwd1(ctl, i);
1305                 table_rollfwd2(ctl, i);
1306         }
1307
1308         return 0;
1309
1310 rollback:
1311         for (i = 0; i < ctl->info.n_tables; i++) {
1312                 table_rollback(ctl, i);
1313                 if (abort_on_fail)
1314                         table_abort(ctl, i);
1315         }
1316
1317         return status;
1318 }
1319
1320 void
1321 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1322 {
1323         uint32_t i;
1324
1325         if (!ctl)
1326                 return;
1327
1328         for (i = 0; i < ctl->info.n_tables; i++)
1329                 table_abort(ctl, i);
1330 }
1331
1332 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1333
1334 struct rte_swx_table_entry *
1335 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1336                                       const char *table_name,
1337                                       const char *string)
1338 {
1339         char *tokens[RTE_SWX_CTL_ENTRY_TOKENS_MAX];
1340         struct table *table;
1341         struct action *action;
1342         struct rte_swx_table_entry *entry = NULL;
1343         char *s0 = NULL, *s;
1344         uint32_t n_tokens = 0, arg_offset = 0, i;
1345
1346         /* Check input arguments. */
1347         if (!ctl)
1348                 goto error;
1349
1350         if (!table_name || !table_name[0])
1351                 goto error;
1352
1353         table = table_find(ctl, table_name);
1354         if (!table)
1355                 goto error;
1356
1357         if (!string || !string[0])
1358                 goto error;
1359
1360         /* Memory allocation. */
1361         s0 = strdup(string);
1362         if (!s0)
1363                 goto error;
1364
1365         entry = table_entry_alloc(table);
1366         if (!entry)
1367                 goto error;
1368
1369         /* Parse the string into tokens. */
1370         for (s = s0; ; ) {
1371                 char *token;
1372
1373                 token = strtok_r(s, " \f\n\r\t\v", &s);
1374                 if (!token)
1375                         break;
1376
1377                 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1378                         goto error;
1379
1380                 tokens[n_tokens] = token;
1381                 n_tokens++;
1382         }
1383
1384         if ((n_tokens < 3 + table->info.n_match_fields) ||
1385             strcmp(tokens[0], "match") ||
1386             strcmp(tokens[1 + table->info.n_match_fields], "action"))
1387                 goto error;
1388
1389         action = action_find(ctl, tokens[2 + table->info.n_match_fields]);
1390         if (!action)
1391                 goto error;
1392
1393         if (n_tokens != 3 + table->info.n_match_fields +
1394             action->info.n_args * 2)
1395                 goto error;
1396
1397         /*
1398          * Match.
1399          */
1400         for (i = 0; i < table->info.n_match_fields; i++) {
1401                 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1402                 char *mf_val = tokens[1 + i];
1403                 uint64_t val;
1404
1405                 val = strtoull(mf_val, &mf_val, 0);
1406                 if (mf_val[0])
1407                         goto error;
1408
1409                 /* Endianness conversion. */
1410                 if (mf->is_header)
1411                         val = field_hton(val, mf->n_bits);
1412
1413                 /* Copy key and key_mask to entry. */
1414                 memcpy(&entry->key[(mf->offset - table->mf[0].offset) / 8],
1415                        (uint8_t *)&val,
1416                        mf->n_bits / 8);
1417
1418                 /* TBD Set entry->key_mask for wildcard and LPM tables. */
1419         }
1420
1421         /*
1422          * Action.
1423          */
1424         /* action_id. */
1425         entry->action_id = action - ctl->actions;
1426
1427         /* action_data. */
1428         for (i = 0; i < action->info.n_args; i++) {
1429                 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1430                 char *arg_name, *arg_val;
1431                 uint64_t val;
1432                 int is_nbo = 0;
1433
1434                 arg_name = tokens[3 + table->info.n_match_fields + i * 2];
1435                 arg_val = tokens[3 + table->info.n_match_fields + i * 2 + 1];
1436
1437                 if (strcmp(arg_name, arg->name) ||
1438                     (strlen(arg_val) < 4) ||
1439                     ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1440                     (arg_val[1] != '(') ||
1441                     (arg_val[strlen(arg_val) - 1] != ')'))
1442                         goto error;
1443
1444                 if (arg_val[0] == 'N')
1445                         is_nbo = 1;
1446
1447                 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1448                 arg_val += 2; /* Remove the "H(" or "N(". */
1449
1450                 val = strtoull(arg_val, &arg_val, 0);
1451                 if (arg_val[0])
1452                         goto error;
1453
1454                 /* Endianness conversion. */
1455                 if (is_nbo)
1456                         val = field_hton(val, arg->n_bits);
1457
1458                 /* Copy to entry. */
1459                 memcpy(&entry->action_data[arg_offset],
1460                        (uint8_t *)&val,
1461                        arg->n_bits / 8);
1462
1463                 arg_offset += arg->n_bits / 8;
1464         }
1465
1466         return entry;
1467
1468 error:
1469         table_entry_free(entry);
1470         free(s0);
1471         return NULL;
1472 }
1473
1474 int
1475 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1476                                    struct rte_swx_ctl_pipeline *ctl,
1477                                    const char *table_name)
1478 {
1479         struct table *table;
1480         struct rte_swx_table_entry *entry;
1481         uint32_t n_entries = 0, i;
1482
1483         if (!f || !ctl || !table_name || !table_name[0])
1484                 return -EINVAL;
1485
1486         table = table_find(ctl, table_name);
1487         if (!table)
1488                 return -EINVAL;
1489
1490         /* Table. */
1491         fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1492                 table->info.name,
1493                 table->params.key_size,
1494                 table->params.key_offset);
1495
1496         for (i = 0; i < table->params.key_size; i++)
1497                 fprintf(f, "%02x", table->params.key_mask0[i]);
1498
1499         fprintf(f, "], action data size %u bytes\n",
1500                 table->params.action_data_size);
1501
1502         /* Table entries. */
1503         TAILQ_FOREACH(entry, &table->entries, node) {
1504                 struct action *action = &ctl->actions[entry->action_id];
1505
1506                 fprintf(f, "match ");
1507                 for (i = 0; i < table->params.key_size; i++)
1508                         fprintf(f, "%02x", entry->key[i]);
1509
1510                 fprintf(f, " action %s ", action->info.name);
1511                 for (i = 0; i < action->data_size; i++)
1512                         fprintf(f, "%02x", entry->action_data[i]);
1513
1514                 fprintf(f, "\n");
1515                 n_entries++;
1516         }
1517
1518         TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1519                 struct action *action = &ctl->actions[entry->action_id];
1520
1521                 fprintf(f, "match ");
1522                 for (i = 0; i < table->params.key_size; i++)
1523                         fprintf(f, "%02x", entry->key[i]);
1524
1525                 fprintf(f, " action %s ", action->info.name);
1526                 for (i = 0; i < action->data_size; i++)
1527                         fprintf(f, "%02x", entry->action_data[i]);
1528
1529                 fprintf(f, "\n");
1530                 n_entries++;
1531         }
1532
1533         TAILQ_FOREACH(entry, &table->pending_delete, node) {
1534                 struct action *action = &ctl->actions[entry->action_id];
1535
1536                 fprintf(f, "match ");
1537                 for (i = 0; i < table->params.key_size; i++)
1538                         fprintf(f, "%02x", entry->key[i]);
1539
1540                 fprintf(f, " action %s ", action->info.name);
1541                 for (i = 0; i < action->data_size; i++)
1542                         fprintf(f, "%02x", entry->action_data[i]);
1543
1544                 fprintf(f, "\n");
1545                 n_entries++;
1546         }
1547
1548         fprintf(f, "# Table %s currently has %u entries.\n",
1549                 table_name,
1550                 n_entries);
1551         return 0;
1552 }