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