1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
3 */
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <sys/queue.h>
9 #include <unistd.h>
10
11 #include <rte_common.h>
12 #include <rte_byteorder.h>
13 #include <rte_tailq.h>
14 #include <rte_eal_memconfig.h>
15
16 #include <rte_swx_table_selector.h>
17
18 #include "rte_swx_ctl.h"
19
20 #define CHECK(condition, err_code) \
21 do { \
22 if (!(condition)) \
23 return -(err_code); \
24 } while (0)
25
26 #define ntoh64(x) rte_be_to_cpu_64(x)
27 #define hton64(x) rte_cpu_to_be_64(x)
28
29 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
30 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
31 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
32 #else
33 #define field_ntoh(val, n_bits) (val)
34 #define field_hton(val, n_bits) (val)
35 #endif
36
37 struct action {
38 struct rte_swx_ctl_action_info info;
39 struct rte_swx_ctl_action_arg_info *args;
40 uint32_t data_size;
41 };
42
43 struct table {
44 struct rte_swx_ctl_table_info info;
45 struct rte_swx_ctl_table_match_field_info *mf;
46
47 /* Match field with the smallest offset. */
48 struct rte_swx_ctl_table_match_field_info *mf_first;
49
50 /* Match field with the biggest offset. */
51 struct rte_swx_ctl_table_match_field_info *mf_last;
52
53 struct rte_swx_ctl_table_action_info *actions;
54 struct rte_swx_table_ops ops;
55 struct rte_swx_table_params params;
56
57 /* Set of "stable" keys: these keys are currently part of the table;
58 * these keys will be preserved with no action data changes after the
59 * next commit.
60 */
61 struct rte_swx_table_entry_list entries;
62
63 /* Set of new keys: these keys are currently NOT part of the table;
64 * these keys will be added to the table on the next commit, if
65 * the commit operation is successful.
66 */
67 struct rte_swx_table_entry_list pending_add;
68
69 /* Set of keys to be modified: these keys are currently part of the
70 * table; these keys are still going to be part of the table after the
71 * next commit, but their action data will be modified if the commit
72 * operation is successful. The modify0 list contains the keys with the
73 * current action data, the modify1 list contains the keys with the
74 * modified action data.
75 */
76 struct rte_swx_table_entry_list pending_modify0;
77 struct rte_swx_table_entry_list pending_modify1;
78
79 /* Set of keys to be deleted: these keys are currently part of the
80 * table; these keys are to be deleted from the table on the next
81 * commit, if the commit operation is successful.
82 */
83 struct rte_swx_table_entry_list pending_delete;
84
85 /* The pending default action: this is NOT the current default action;
86 * this will be the new default action after the next commit, if the
87 * next commit operation is successful.
88 */
89 struct rte_swx_table_entry *pending_default;
90
91 int is_stub;
92 uint32_t n_add;
93 uint32_t n_modify;
94 uint32_t n_delete;
95 };
96
97 struct selector {
98 /* Selector table info. */
99 struct rte_swx_ctl_selector_info info;
100
101 /* group_id field. */
102 struct rte_swx_ctl_table_match_field_info group_id_field;
103
104 /* selector fields. */
105 struct rte_swx_ctl_table_match_field_info *selector_fields;
106
107 /* member_id field. */
108 struct rte_swx_ctl_table_match_field_info member_id_field;
109
110 /* Current selector table. Array of info.n_groups_max elements.*/
111 struct rte_swx_table_selector_group **groups;
112
113 /* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
114 */
115 struct rte_swx_table_selector_group **pending_groups;
116
117 /* Valid flag per group. Array of n_groups_max elements. */
118 int *groups_added;
119
120 /* Pending delete flag per group. Group deletion is subject to the next commit. Array of
121 * info.n_groups_max elements.
122 */
123 int *groups_pending_delete;
124
125 /* Params. */
126 struct rte_swx_table_selector_params params;
127 };
128
129 struct learner {
130 struct rte_swx_ctl_learner_info info;
131 struct rte_swx_ctl_table_match_field_info *mf;
132 struct rte_swx_ctl_table_action_info *actions;
133 uint32_t action_data_size;
134
135 /* The pending default action: this is NOT the current default action;
136 * this will be the new default action after the next commit, if the
137 * next commit operation is successful.
138 */
139 struct rte_swx_table_entry *pending_default;
140 };
141
142 struct rte_swx_ctl_pipeline {
143 struct rte_swx_ctl_pipeline_info info;
144 struct rte_swx_pipeline *p;
145 struct action *actions;
146 struct table *tables;
147 struct selector *selectors;
148 struct learner *learners;
149 struct rte_swx_table_state *ts;
150 struct rte_swx_table_state *ts_next;
151 int numa_node;
152 };
153
154 static struct action *
action_find(struct rte_swx_ctl_pipeline * ctl,const char * action_name)155 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
156 {
157 uint32_t i;
158
159 for (i = 0; i < ctl->info.n_actions; i++) {
160 struct action *a = &ctl->actions[i];
161
162 if (!strcmp(action_name, a->info.name))
163 return a;
164 }
165
166 return NULL;
167 }
168
169 static void
action_free(struct rte_swx_ctl_pipeline * ctl)170 action_free(struct rte_swx_ctl_pipeline *ctl)
171 {
172 uint32_t i;
173
174 if (!ctl->actions)
175 return;
176
177 for (i = 0; i < ctl->info.n_actions; i++) {
178 struct action *action = &ctl->actions[i];
179
180 free(action->args);
181 }
182
183 free(ctl->actions);
184 ctl->actions = NULL;
185 }
186
187 static struct table *
table_find(struct rte_swx_ctl_pipeline * ctl,const char * table_name)188 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
189 {
190 uint32_t i;
191
192 for (i = 0; i < ctl->info.n_tables; i++) {
193 struct table *table = &ctl->tables[i];
194
195 if (!strcmp(table_name, table->info.name))
196 return table;
197 }
198
199 return NULL;
200 }
201
202 static int
table_params_get(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)203 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
204 {
205 struct table *table = &ctl->tables[table_id];
206 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
207 uint8_t *key_mask = NULL;
208 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
209 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
210
211 if (table->info.n_match_fields) {
212 uint32_t n_match_fields_em = 0, i;
213
214 /* Find first (smallest offset) and last (biggest offset) match fields. */
215 first = &table->mf[0];
216 last = &table->mf[0];
217
218 for (i = 1; i < table->info.n_match_fields; i++) {
219 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
220
221 if (f->offset < first->offset)
222 first = f;
223
224 if (f->offset > last->offset)
225 last = f;
226 }
227
228 /* match_type. */
229 for (i = 0; i < table->info.n_match_fields; i++) {
230 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
231
232 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
233 n_match_fields_em++;
234 }
235
236 if (n_match_fields_em == table->info.n_match_fields)
237 match_type = RTE_SWX_TABLE_MATCH_EXACT;
238
239 /* key_offset. */
240 key_offset = first->offset / 8;
241
242 /* key_size. */
243 key_size = (last->offset + last->n_bits - first->offset) / 8;
244
245 /* key_mask. */
246 key_mask = calloc(1, key_size);
247 CHECK(key_mask, ENOMEM);
248
249 for (i = 0; i < table->info.n_match_fields; i++) {
250 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
251 uint32_t start;
252 size_t size;
253
254 start = (f->offset - first->offset) / 8;
255 size = f->n_bits / 8;
256
257 memset(&key_mask[start], 0xFF, size);
258 }
259 }
260
261 /* action_data_size. */
262 for (i = 0; i < table->info.n_actions; i++) {
263 uint32_t action_id = table->actions[i].action_id;
264 struct action *a = &ctl->actions[action_id];
265
266 if (a->data_size > action_data_size)
267 action_data_size = a->data_size;
268 }
269
270 /* Fill in. */
271 table->params.match_type = match_type;
272 table->params.key_size = key_size;
273 table->params.key_offset = key_offset;
274 table->params.key_mask0 = key_mask;
275 table->params.action_data_size = action_data_size;
276 table->params.hash_func = table->info.hash_func;
277 table->params.n_keys_max = table->info.size;
278
279 table->mf_first = first;
280 table->mf_last = last;
281
282 return 0;
283 }
284
285 static void
table_entry_free(struct rte_swx_table_entry * entry)286 table_entry_free(struct rte_swx_table_entry *entry)
287 {
288 if (!entry)
289 return;
290
291 free(entry->key);
292 free(entry->key_mask);
293 free(entry->action_data);
294 free(entry);
295 }
296
297 static struct rte_swx_table_entry *
table_entry_alloc(struct table * table)298 table_entry_alloc(struct table *table)
299 {
300 struct rte_swx_table_entry *entry;
301
302 entry = calloc(1, sizeof(struct rte_swx_table_entry));
303 if (!entry)
304 goto error;
305
306 /* key, key_mask. */
307 if (!table->is_stub) {
308 entry->key = calloc(1, table->params.key_size);
309 if (!entry->key)
310 goto error;
311
312 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
313 entry->key_mask = calloc(1, table->params.key_size);
314 if (!entry->key_mask)
315 goto error;
316 }
317 }
318
319 /* action_data. */
320 if (table->params.action_data_size) {
321 entry->action_data = calloc(1, table->params.action_data_size);
322 if (!entry->action_data)
323 goto error;
324 }
325
326 return entry;
327
328 error:
329 table_entry_free(entry);
330 return NULL;
331 }
332
333 static int
table_entry_key_check_em(struct table * table,struct rte_swx_table_entry * entry)334 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
335 {
336 uint8_t *key_mask0 = table->params.key_mask0;
337 uint32_t key_size = table->params.key_size, i;
338
339 if (!entry->key_mask)
340 return 0;
341
342 for (i = 0; i < key_size; i++) {
343 uint8_t km0 = key_mask0[i];
344 uint8_t km = entry->key_mask[i];
345
346 if ((km & km0) != km0)
347 return -EINVAL;
348 }
349
350 return 0;
351 }
352
353 static int
table_entry_check(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_check,int data_check)354 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
355 uint32_t table_id,
356 struct rte_swx_table_entry *entry,
357 int key_check,
358 int data_check)
359 {
360 struct table *table = &ctl->tables[table_id];
361 int status;
362
363 CHECK(entry, EINVAL);
364
365 if (key_check && !table->is_stub) {
366 /* key. */
367 CHECK(entry->key, EINVAL);
368
369 /* key_mask. */
370 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
371 status = table_entry_key_check_em(table, entry);
372 if (status)
373 return status;
374 }
375 }
376
377 if (data_check) {
378 struct action *a;
379 struct rte_swx_ctl_table_action_info *tai;
380 uint32_t i;
381
382 /* action_id. */
383 for (i = 0; i < table->info.n_actions; i++) {
384 tai = &table->actions[i];
385
386 if (entry->action_id == tai->action_id)
387 break;
388 }
389
390 CHECK(i < table->info.n_actions, EINVAL);
391
392 /* action_data. */
393 a = &ctl->actions[entry->action_id];
394 CHECK(!(a->data_size && !entry->action_data), EINVAL);
395
396 /* When both key_check and data_check are true, we are interested in both the entry
397 * key and data, which means the operation is _regular_ table entry add.
398 */
399 if (key_check && !tai->action_is_for_table_entries)
400 return -EINVAL;
401
402 /* When key_check is false while data_check is true, we are only interested in the
403 * entry data, which means the operation is _default_ table entry add.
404 */
405 if (!key_check && !tai->action_is_for_default_entry)
406 return -EINVAL;
407 }
408
409 return 0;
410 }
411
412 static struct rte_swx_table_entry *
table_entry_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_duplicate,int data_duplicate)413 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
414 uint32_t table_id,
415 struct rte_swx_table_entry *entry,
416 int key_duplicate,
417 int data_duplicate)
418 {
419 struct table *table = &ctl->tables[table_id];
420 struct rte_swx_table_entry *new_entry = NULL;
421
422 if (!entry)
423 goto error;
424
425 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
426 if (!new_entry)
427 goto error;
428
429 if (key_duplicate && !table->is_stub) {
430 /* key. */
431 if (!entry->key)
432 goto error;
433
434 new_entry->key = malloc(table->params.key_size);
435 if (!new_entry->key)
436 goto error;
437
438 memcpy(new_entry->key, entry->key, table->params.key_size);
439
440 /* key_signature. */
441 new_entry->key_signature = entry->key_signature;
442
443 /* key_mask. */
444 if (entry->key_mask) {
445 new_entry->key_mask = malloc(table->params.key_size);
446 if (!new_entry->key_mask)
447 goto error;
448
449 memcpy(new_entry->key_mask,
450 entry->key_mask,
451 table->params.key_size);
452 }
453
454 /* key_priority. */
455 new_entry->key_priority = entry->key_priority;
456 }
457
458 if (data_duplicate) {
459 struct action *a;
460 uint32_t i;
461
462 /* action_id. */
463 for (i = 0; i < table->info.n_actions; i++)
464 if (entry->action_id == table->actions[i].action_id)
465 break;
466
467 if (i >= table->info.n_actions)
468 goto error;
469
470 new_entry->action_id = entry->action_id;
471
472 /* action_data. */
473 a = &ctl->actions[entry->action_id];
474 if (a->data_size && !entry->action_data)
475 goto error;
476
477 /* The table layer provisions a constant action data size per
478 * entry, which should be the largest data size for all the
479 * actions enabled for the current table, and attempts to copy
480 * this many bytes each time a table entry is added, even if the
481 * specific action requires less data or even no data at all,
482 * hence we always have to allocate the max.
483 */
484 new_entry->action_data = calloc(1, table->params.action_data_size);
485 if (!new_entry->action_data)
486 goto error;
487
488 if (a->data_size)
489 memcpy(new_entry->action_data,
490 entry->action_data,
491 a->data_size);
492 }
493
494 return new_entry;
495
496 error:
497 table_entry_free(new_entry);
498 return NULL;
499 }
500
501 static int
table_entry_keycmp(struct table * table,struct rte_swx_table_entry * e0,struct rte_swx_table_entry * e1)502 table_entry_keycmp(struct table *table,
503 struct rte_swx_table_entry *e0,
504 struct rte_swx_table_entry *e1)
505 {
506 uint32_t key_size = table->params.key_size;
507 uint32_t i;
508
509 for (i = 0; i < key_size; i++) {
510 uint8_t *key_mask0 = table->params.key_mask0;
511 uint8_t km0, km[2], k[2];
512
513 km0 = key_mask0 ? key_mask0[i] : 0xFF;
514
515 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
516 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
517
518 k[0] = e0->key[i];
519 k[1] = e1->key[i];
520
521 /* Mask comparison. */
522 if ((km[0] & km0) != (km[1] & km0))
523 return 1; /* Not equal. */
524
525 /* Value comparison. */
526 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
527 return 1; /* Not equal. */
528 }
529
530 return 0; /* Equal. */
531 }
532
533 static struct rte_swx_table_entry *
table_entries_find(struct table * table,struct rte_swx_table_entry * entry)534 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
535 {
536 struct rte_swx_table_entry *e;
537
538 TAILQ_FOREACH(e, &table->entries, node)
539 if (!table_entry_keycmp(table, entry, e))
540 return e; /* Found. */
541
542 return NULL; /* Not found. */
543 }
544
545 static void
table_entries_free(struct table * table)546 table_entries_free(struct table *table)
547 {
548 for ( ; ; ) {
549 struct rte_swx_table_entry *entry;
550
551 entry = TAILQ_FIRST(&table->entries);
552 if (!entry)
553 break;
554
555 TAILQ_REMOVE(&table->entries, entry, node);
556 table_entry_free(entry);
557 }
558 }
559
560 static struct rte_swx_table_entry *
table_pending_add_find(struct table * table,struct rte_swx_table_entry * entry)561 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
562 {
563 struct rte_swx_table_entry *e;
564
565 TAILQ_FOREACH(e, &table->pending_add, node)
566 if (!table_entry_keycmp(table, entry, e))
567 return e; /* Found. */
568
569 return NULL; /* Not found. */
570 }
571
572 static void
table_pending_add_admit(struct table * table)573 table_pending_add_admit(struct table *table)
574 {
575 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
576 }
577
578 static void
table_pending_add_free(struct table * table)579 table_pending_add_free(struct table *table)
580 {
581 for ( ; ; ) {
582 struct rte_swx_table_entry *entry;
583
584 entry = TAILQ_FIRST(&table->pending_add);
585 if (!entry)
586 break;
587
588 TAILQ_REMOVE(&table->pending_add, entry, node);
589 table_entry_free(entry);
590 }
591 }
592
593 static struct rte_swx_table_entry *
table_pending_modify0_find(struct table * table,struct rte_swx_table_entry * entry)594 table_pending_modify0_find(struct table *table,
595 struct rte_swx_table_entry *entry)
596 {
597 struct rte_swx_table_entry *e;
598
599 TAILQ_FOREACH(e, &table->pending_modify0, node)
600 if (!table_entry_keycmp(table, entry, e))
601 return e; /* Found. */
602
603 return NULL; /* Not found. */
604 }
605
606 static void
table_pending_modify0_admit(struct table * table)607 table_pending_modify0_admit(struct table *table)
608 {
609 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
610 }
611
612 static void
table_pending_modify0_free(struct table * table)613 table_pending_modify0_free(struct table *table)
614 {
615 for ( ; ; ) {
616 struct rte_swx_table_entry *entry;
617
618 entry = TAILQ_FIRST(&table->pending_modify0);
619 if (!entry)
620 break;
621
622 TAILQ_REMOVE(&table->pending_modify0, entry, node);
623 table_entry_free(entry);
624 }
625 }
626
627 static struct rte_swx_table_entry *
table_pending_modify1_find(struct table * table,struct rte_swx_table_entry * entry)628 table_pending_modify1_find(struct table *table,
629 struct rte_swx_table_entry *entry)
630 {
631 struct rte_swx_table_entry *e;
632
633 TAILQ_FOREACH(e, &table->pending_modify1, node)
634 if (!table_entry_keycmp(table, entry, e))
635 return e; /* Found. */
636
637 return NULL; /* Not found. */
638 }
639
640 static void
table_pending_modify1_admit(struct table * table)641 table_pending_modify1_admit(struct table *table)
642 {
643 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
644 }
645
646 static void
table_pending_modify1_free(struct table * table)647 table_pending_modify1_free(struct table *table)
648 {
649 for ( ; ; ) {
650 struct rte_swx_table_entry *entry;
651
652 entry = TAILQ_FIRST(&table->pending_modify1);
653 if (!entry)
654 break;
655
656 TAILQ_REMOVE(&table->pending_modify1, entry, node);
657 table_entry_free(entry);
658 }
659 }
660
661 static struct rte_swx_table_entry *
table_pending_delete_find(struct table * table,struct rte_swx_table_entry * entry)662 table_pending_delete_find(struct table *table,
663 struct rte_swx_table_entry *entry)
664 {
665 struct rte_swx_table_entry *e;
666
667 TAILQ_FOREACH(e, &table->pending_delete, node)
668 if (!table_entry_keycmp(table, entry, e))
669 return e; /* Found. */
670
671 return NULL; /* Not found. */
672 }
673
674 static void
table_pending_delete_admit(struct table * table)675 table_pending_delete_admit(struct table *table)
676 {
677 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
678 }
679
680 static void
table_pending_delete_free(struct table * table)681 table_pending_delete_free(struct table *table)
682 {
683 for ( ; ; ) {
684 struct rte_swx_table_entry *entry;
685
686 entry = TAILQ_FIRST(&table->pending_delete);
687 if (!entry)
688 break;
689
690 TAILQ_REMOVE(&table->pending_delete, entry, node);
691 table_entry_free(entry);
692 }
693 }
694
695 static void
table_pending_default_free(struct table * table)696 table_pending_default_free(struct table *table)
697 {
698 if (!table->pending_default)
699 return;
700
701 free(table->pending_default->action_data);
702 free(table->pending_default);
703 table->pending_default = NULL;
704 }
705
706 static int
table_is_update_pending(struct table * table,int consider_pending_default)707 table_is_update_pending(struct table *table, int consider_pending_default)
708 {
709 struct rte_swx_table_entry *e;
710 uint32_t n = 0;
711
712 /* Pending add. */
713 TAILQ_FOREACH(e, &table->pending_add, node)
714 n++;
715
716 /* Pending modify. */
717 TAILQ_FOREACH(e, &table->pending_modify1, node)
718 n++;
719
720 /* Pending delete. */
721 TAILQ_FOREACH(e, &table->pending_delete, node)
722 n++;
723
724 /* Pending default. */
725 if (consider_pending_default && table->pending_default)
726 n++;
727
728 return n;
729 }
730
731 static void
table_free(struct rte_swx_ctl_pipeline * ctl)732 table_free(struct rte_swx_ctl_pipeline *ctl)
733 {
734 uint32_t i;
735
736 if (!ctl->tables)
737 return;
738
739 for (i = 0; i < ctl->info.n_tables; i++) {
740 struct table *table = &ctl->tables[i];
741
742 free(table->mf);
743 free(table->actions);
744 free(table->params.key_mask0);
745
746 table_entries_free(table);
747 table_pending_add_free(table);
748 table_pending_modify0_free(table);
749 table_pending_modify1_free(table);
750 table_pending_delete_free(table);
751 table_pending_default_free(table);
752 }
753
754 free(ctl->tables);
755 ctl->tables = NULL;
756 }
757
758 static void
selector_group_members_free(struct selector * s,uint32_t group_id)759 selector_group_members_free(struct selector *s, uint32_t group_id)
760 {
761 struct rte_swx_table_selector_group *group = s->groups[group_id];
762
763 if (!group)
764 return;
765
766 for ( ; ; ) {
767 struct rte_swx_table_selector_member *m;
768
769 m = TAILQ_FIRST(&group->members);
770 if (!m)
771 break;
772
773 TAILQ_REMOVE(&group->members, m, node);
774 free(m);
775 }
776
777 free(group);
778 s->groups[group_id] = NULL;
779 }
780
781 static void
selector_pending_group_members_free(struct selector * s,uint32_t group_id)782 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
783 {
784 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
785
786 if (!group)
787 return;
788
789 for ( ; ; ) {
790 struct rte_swx_table_selector_member *m;
791
792 m = TAILQ_FIRST(&group->members);
793 if (!m)
794 break;
795
796 TAILQ_REMOVE(&group->members, m, node);
797 free(m);
798 }
799
800 free(group);
801 s->pending_groups[group_id] = NULL;
802 }
803
804 static int
selector_group_duplicate_to_pending(struct selector * s,uint32_t group_id)805 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
806 {
807 struct rte_swx_table_selector_group *g, *gp;
808 struct rte_swx_table_selector_member *m;
809
810 selector_pending_group_members_free(s, group_id);
811
812 g = s->groups[group_id];
813 gp = s->pending_groups[group_id];
814
815 if (!gp) {
816 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
817 if (!gp)
818 goto error;
819
820 TAILQ_INIT(&gp->members);
821
822 s->pending_groups[group_id] = gp;
823 }
824
825 if (!g)
826 return 0;
827
828 TAILQ_FOREACH(m, &g->members, node) {
829 struct rte_swx_table_selector_member *mp;
830
831 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
832 if (!mp)
833 goto error;
834
835 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
836
837 TAILQ_INSERT_TAIL(&gp->members, mp, node);
838 }
839
840 return 0;
841
842 error:
843 selector_pending_group_members_free(s, group_id);
844 return -ENOMEM;
845 }
846
847 static void
selector_free(struct rte_swx_ctl_pipeline * ctl)848 selector_free(struct rte_swx_ctl_pipeline *ctl)
849 {
850 uint32_t i;
851
852 if (!ctl->selectors)
853 return;
854
855 for (i = 0; i < ctl->info.n_selectors; i++) {
856 struct selector *s = &ctl->selectors[i];
857 uint32_t i;
858
859 /* selector_fields. */
860 free(s->selector_fields);
861
862 /* groups. */
863 if (s->groups)
864 for (i = 0; i < s->info.n_groups_max; i++)
865 selector_group_members_free(s, i);
866
867 free(s->groups);
868
869 /* pending_groups. */
870 if (s->pending_groups)
871 for (i = 0; i < s->info.n_groups_max; i++)
872 selector_pending_group_members_free(s, i);
873
874 free(s->pending_groups);
875
876 /* groups_added. */
877 free(s->groups_added);
878
879 /* groups_pending_delete. */
880 free(s->groups_pending_delete);
881
882 /* params. */
883 free(s->params.selector_mask);
884 }
885
886 free(ctl->selectors);
887 ctl->selectors = NULL;
888 }
889
890 static struct selector *
selector_find(struct rte_swx_ctl_pipeline * ctl,const char * selector_name)891 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
892 {
893 uint32_t i;
894
895 for (i = 0; i < ctl->info.n_selectors; i++) {
896 struct selector *s = &ctl->selectors[i];
897
898 if (!strcmp(selector_name, s->info.name))
899 return s;
900 }
901
902 return NULL;
903 }
904
905 static int
selector_params_get(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)906 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
907 {
908 struct selector *s = &ctl->selectors[selector_id];
909 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
910 uint8_t *selector_mask = NULL;
911 uint32_t selector_size = 0, selector_offset = 0, i;
912
913 /* Find first (smallest offset) and last (biggest offset) match fields. */
914 first = &s->selector_fields[0];
915 last = &s->selector_fields[0];
916
917 for (i = 1; i < s->info.n_selector_fields; i++) {
918 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
919
920 if (f->offset < first->offset)
921 first = f;
922
923 if (f->offset > last->offset)
924 last = f;
925 }
926
927 /* selector_offset. */
928 selector_offset = first->offset / 8;
929
930 /* selector_size. */
931 selector_size = (last->offset + last->n_bits - first->offset) / 8;
932
933 /* selector_mask. */
934 selector_mask = calloc(1, selector_size);
935 if (!selector_mask)
936 return -ENOMEM;
937
938 for (i = 0; i < s->info.n_selector_fields; i++) {
939 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
940 uint32_t start;
941 size_t size;
942
943 start = (f->offset - first->offset) / 8;
944 size = f->n_bits / 8;
945
946 memset(&selector_mask[start], 0xFF, size);
947 }
948
949 /* Fill in. */
950 s->params.group_id_offset = s->group_id_field.offset / 8;
951 s->params.selector_size = selector_size;
952 s->params.selector_offset = selector_offset;
953 s->params.selector_mask = selector_mask;
954 s->params.member_id_offset = s->member_id_field.offset / 8;
955 s->params.n_groups_max = s->info.n_groups_max;
956 s->params.n_members_per_group_max = s->info.n_members_per_group_max;
957
958 return 0;
959 }
960
961 static void
learner_pending_default_free(struct learner * l)962 learner_pending_default_free(struct learner *l)
963 {
964 if (!l->pending_default)
965 return;
966
967 free(l->pending_default->action_data);
968 free(l->pending_default);
969 l->pending_default = NULL;
970 }
971
972
973 static void
learner_free(struct rte_swx_ctl_pipeline * ctl)974 learner_free(struct rte_swx_ctl_pipeline *ctl)
975 {
976 uint32_t i;
977
978 if (!ctl->learners)
979 return;
980
981 for (i = 0; i < ctl->info.n_learners; i++) {
982 struct learner *l = &ctl->learners[i];
983
984 free(l->mf);
985 free(l->actions);
986
987 learner_pending_default_free(l);
988 }
989
990 free(ctl->learners);
991 ctl->learners = NULL;
992 }
993
994 static struct learner *
learner_find(struct rte_swx_ctl_pipeline * ctl,const char * learner_name)995 learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
996 {
997 uint32_t i;
998
999 for (i = 0; i < ctl->info.n_learners; i++) {
1000 struct learner *l = &ctl->learners[i];
1001
1002 if (!strcmp(learner_name, l->info.name))
1003 return l;
1004 }
1005
1006 return NULL;
1007 }
1008
1009 static uint32_t
learner_action_data_size_get(struct rte_swx_ctl_pipeline * ctl,struct learner * l)1010 learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1011 {
1012 uint32_t action_data_size = 0, i;
1013
1014 for (i = 0; i < l->info.n_actions; i++) {
1015 uint32_t action_id = l->actions[i].action_id;
1016 struct action *a = &ctl->actions[action_id];
1017
1018 if (a->data_size > action_data_size)
1019 action_data_size = a->data_size;
1020 }
1021
1022 return action_data_size;
1023 }
1024
1025 static void
table_state_free(struct rte_swx_ctl_pipeline * ctl)1026 table_state_free(struct rte_swx_ctl_pipeline *ctl)
1027 {
1028 uint32_t table_base_index, selector_base_index, learner_base_index, i;
1029
1030 if (!ctl->ts_next)
1031 return;
1032
1033 /* For each table, free its table state. */
1034 table_base_index = 0;
1035 for (i = 0; i < ctl->info.n_tables; i++) {
1036 struct table *table = &ctl->tables[i];
1037 struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
1038
1039 /* Default action data. */
1040 free(ts->default_action_data);
1041
1042 /* Table object. */
1043 if (!table->is_stub && table->ops.free && ts->obj)
1044 table->ops.free(ts->obj);
1045 }
1046
1047 /* For each selector table, free its table state. */
1048 selector_base_index = ctl->info.n_tables;
1049 for (i = 0; i < ctl->info.n_selectors; i++) {
1050 struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1051
1052 /* Table object. */
1053 rte_swx_table_selector_free(ts->obj);
1054 }
1055
1056 /* For each learner table, free its table state. */
1057 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1058 for (i = 0; i < ctl->info.n_learners; i++) {
1059 struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
1060
1061 /* Default action data. */
1062 free(ts->default_action_data);
1063 }
1064
1065 free(ctl->ts_next);
1066 ctl->ts_next = NULL;
1067 }
1068
1069 static int
table_state_create(struct rte_swx_ctl_pipeline * ctl)1070 table_state_create(struct rte_swx_ctl_pipeline *ctl)
1071 {
1072 uint32_t table_base_index, selector_base_index, learner_base_index, i;
1073 int status = 0;
1074
1075 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
1076 sizeof(struct rte_swx_table_state));
1077 if (!ctl->ts_next) {
1078 status = -ENOMEM;
1079 goto error;
1080 }
1081
1082 /* Tables. */
1083 table_base_index = 0;
1084 for (i = 0; i < ctl->info.n_tables; i++) {
1085 struct table *table = &ctl->tables[i];
1086 struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1087 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
1088
1089 /* Table object. */
1090 if (!table->is_stub && table->ops.add) {
1091 ts_next->obj = table->ops.create(&table->params,
1092 &table->entries,
1093 table->info.args,
1094 ctl->numa_node);
1095 if (!ts_next->obj) {
1096 status = -ENODEV;
1097 goto error;
1098 }
1099 }
1100
1101 if (!table->is_stub && !table->ops.add)
1102 ts_next->obj = ts->obj;
1103
1104 /* Default action data: duplicate from current table state. */
1105 ts_next->default_action_data =
1106 malloc(table->params.action_data_size);
1107 if (!ts_next->default_action_data) {
1108 status = -ENOMEM;
1109 goto error;
1110 }
1111
1112 memcpy(ts_next->default_action_data,
1113 ts->default_action_data,
1114 table->params.action_data_size);
1115
1116 ts_next->default_action_id = ts->default_action_id;
1117 }
1118
1119 /* Selector tables. */
1120 selector_base_index = ctl->info.n_tables;
1121 for (i = 0; i < ctl->info.n_selectors; i++) {
1122 struct selector *s = &ctl->selectors[i];
1123 struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1124
1125 /* Table object. */
1126 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1127 if (!ts_next->obj) {
1128 status = -ENODEV;
1129 goto error;
1130 }
1131 }
1132
1133 /* Learner tables. */
1134 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
1135 for (i = 0; i < ctl->info.n_learners; i++) {
1136 struct learner *l = &ctl->learners[i];
1137 struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1138 struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
1139
1140 /* Table object: duplicate from the current table state. */
1141 ts_next->obj = ts->obj;
1142
1143 /* Default action data: duplicate from the current table state. */
1144 ts_next->default_action_data = malloc(l->action_data_size);
1145 if (!ts_next->default_action_data) {
1146 status = -ENOMEM;
1147 goto error;
1148 }
1149
1150 memcpy(ts_next->default_action_data,
1151 ts->default_action_data,
1152 l->action_data_size);
1153
1154 ts_next->default_action_id = ts->default_action_id;
1155 }
1156
1157 return 0;
1158
1159 error:
1160 table_state_free(ctl);
1161 return status;
1162 }
1163
1164 /* Global list of pipeline instances. */
1165 TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
1166
1167 static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
1168 .name = "RTE_SWX_CTL_PIPELINE",
1169 };
1170
EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)1171 EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
1172
1173 struct rte_swx_ctl_pipeline *
1174 rte_swx_ctl_pipeline_find(const char *name)
1175 {
1176 struct rte_swx_ctl_pipeline_list *ctl_list;
1177 struct rte_tailq_entry *te = NULL;
1178
1179 if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
1180 return NULL;
1181
1182 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1183
1184 rte_mcfg_tailq_read_lock();
1185
1186 TAILQ_FOREACH(te, ctl_list, next) {
1187 struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
1188
1189 if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
1190 rte_mcfg_tailq_read_unlock();
1191 return ctl;
1192 }
1193 }
1194
1195 rte_mcfg_tailq_read_unlock();
1196 return NULL;
1197 }
1198
1199 static int
ctl_register(struct rte_swx_ctl_pipeline * ctl)1200 ctl_register(struct rte_swx_ctl_pipeline *ctl)
1201 {
1202 struct rte_swx_ctl_pipeline_list *ctl_list;
1203 struct rte_tailq_entry *te = NULL;
1204
1205 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1206
1207 rte_mcfg_tailq_write_lock();
1208
1209 TAILQ_FOREACH(te, ctl_list, next) {
1210 struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
1211
1212 if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
1213 rte_mcfg_tailq_write_unlock();
1214 return -EEXIST;
1215 }
1216 }
1217
1218 te = calloc(1, sizeof(struct rte_tailq_entry));
1219 if (!te) {
1220 rte_mcfg_tailq_write_unlock();
1221 return -ENOMEM;
1222 }
1223
1224 te->data = (void *)ctl;
1225 TAILQ_INSERT_TAIL(ctl_list, te, next);
1226 rte_mcfg_tailq_write_unlock();
1227 return 0;
1228 }
1229
1230 static void
ctl_unregister(struct rte_swx_ctl_pipeline * ctl)1231 ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
1232 {
1233 struct rte_swx_ctl_pipeline_list *ctl_list;
1234 struct rte_tailq_entry *te = NULL;
1235
1236 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1237
1238 rte_mcfg_tailq_write_lock();
1239
1240 TAILQ_FOREACH(te, ctl_list, next) {
1241 if (te->data == (void *)ctl) {
1242 TAILQ_REMOVE(ctl_list, te, next);
1243 rte_mcfg_tailq_write_unlock();
1244 free(te);
1245 return;
1246 }
1247 }
1248
1249 rte_mcfg_tailq_write_unlock();
1250 }
1251
1252 void
rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline * ctl)1253 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1254 {
1255 if (!ctl)
1256 return;
1257
1258 if (ctl->info.name[0])
1259 ctl_unregister(ctl);
1260
1261 action_free(ctl);
1262
1263 table_state_free(ctl);
1264
1265 learner_free(ctl);
1266
1267 selector_free(ctl);
1268
1269 table_free(ctl);
1270
1271 free(ctl);
1272 }
1273
1274 struct rte_swx_ctl_pipeline *
rte_swx_ctl_pipeline_create(struct rte_swx_pipeline * p)1275 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1276 {
1277 struct rte_swx_ctl_pipeline *ctl = NULL;
1278 uint32_t i;
1279 int status;
1280
1281 if (!p)
1282 goto error;
1283
1284 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1285 if (!ctl)
1286 goto error;
1287
1288 /* info. */
1289 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1290 if (status)
1291 goto error;
1292
1293 /* numa_node. */
1294 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1295 if (status)
1296 goto error;
1297
1298 /* p. */
1299 ctl->p = p;
1300
1301 /* actions. */
1302 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1303 if (!ctl->actions)
1304 goto error;
1305
1306 for (i = 0; i < ctl->info.n_actions; i++) {
1307 struct action *a = &ctl->actions[i];
1308 uint32_t j;
1309
1310 /* info. */
1311 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1312 if (status)
1313 goto error;
1314
1315 /* args. */
1316 a->args = calloc(a->info.n_args,
1317 sizeof(struct rte_swx_ctl_action_arg_info));
1318 if (!a->args)
1319 goto error;
1320
1321 for (j = 0; j < a->info.n_args; j++) {
1322 status = rte_swx_ctl_action_arg_info_get(p,
1323 i,
1324 j,
1325 &a->args[j]);
1326 if (status)
1327 goto error;
1328 }
1329
1330 /* data_size. */
1331 for (j = 0; j < a->info.n_args; j++) {
1332 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1333
1334 a->data_size += info->n_bits;
1335 }
1336
1337 a->data_size = (a->data_size + 7) / 8;
1338 }
1339
1340 /* tables. */
1341 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1342 if (!ctl->tables)
1343 goto error;
1344
1345 for (i = 0; i < ctl->info.n_tables; i++) {
1346 struct table *t = &ctl->tables[i];
1347
1348 TAILQ_INIT(&t->entries);
1349 TAILQ_INIT(&t->pending_add);
1350 TAILQ_INIT(&t->pending_modify0);
1351 TAILQ_INIT(&t->pending_modify1);
1352 TAILQ_INIT(&t->pending_delete);
1353 }
1354
1355 for (i = 0; i < ctl->info.n_tables; i++) {
1356 struct table *t = &ctl->tables[i];
1357 uint32_t j;
1358
1359 /* info. */
1360 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1361 if (status)
1362 goto error;
1363
1364 /* mf. */
1365 t->mf = calloc(t->info.n_match_fields,
1366 sizeof(struct rte_swx_ctl_table_match_field_info));
1367 if (!t->mf)
1368 goto error;
1369
1370 for (j = 0; j < t->info.n_match_fields; j++) {
1371 status = rte_swx_ctl_table_match_field_info_get(p,
1372 i,
1373 j,
1374 &t->mf[j]);
1375 if (status)
1376 goto error;
1377 }
1378
1379 /* actions. */
1380 t->actions = calloc(t->info.n_actions,
1381 sizeof(struct rte_swx_ctl_table_action_info));
1382 if (!t->actions)
1383 goto error;
1384
1385 for (j = 0; j < t->info.n_actions; j++) {
1386 status = rte_swx_ctl_table_action_info_get(p,
1387 i,
1388 j,
1389 &t->actions[j]);
1390 if (status ||
1391 t->actions[j].action_id >= ctl->info.n_actions)
1392 goto error;
1393 }
1394
1395 /* ops, is_stub. */
1396 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1397 if (status)
1398 goto error;
1399
1400 if ((t->is_stub && t->info.n_match_fields) ||
1401 (!t->is_stub && !t->info.n_match_fields))
1402 goto error;
1403
1404 /* params. */
1405 status = table_params_get(ctl, i);
1406 if (status)
1407 goto error;
1408 }
1409
1410 /* selector tables. */
1411 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1412 if (!ctl->selectors)
1413 goto error;
1414
1415 for (i = 0; i < ctl->info.n_selectors; i++) {
1416 struct selector *s = &ctl->selectors[i];
1417 uint32_t j;
1418
1419 /* info. */
1420 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1421 if (status)
1422 goto error;
1423
1424 /* group_id field. */
1425 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1426 i,
1427 &s->group_id_field);
1428 if (status)
1429 goto error;
1430
1431 /* selector fields. */
1432 s->selector_fields = calloc(s->info.n_selector_fields,
1433 sizeof(struct rte_swx_ctl_table_match_field_info));
1434 if (!s->selector_fields)
1435 goto error;
1436
1437 for (j = 0; j < s->info.n_selector_fields; j++) {
1438 status = rte_swx_ctl_selector_field_info_get(p,
1439 i,
1440 j,
1441 &s->selector_fields[j]);
1442 if (status)
1443 goto error;
1444 }
1445
1446 /* member_id field. */
1447 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1448 i,
1449 &s->member_id_field);
1450 if (status)
1451 goto error;
1452
1453 /* groups. */
1454 s->groups = calloc(s->info.n_groups_max,
1455 sizeof(struct rte_swx_table_selector_group *));
1456 if (!s->groups)
1457 goto error;
1458
1459 /* pending_groups. */
1460 s->pending_groups = calloc(s->info.n_groups_max,
1461 sizeof(struct rte_swx_table_selector_group *));
1462 if (!s->pending_groups)
1463 goto error;
1464
1465 /* groups_added. */
1466 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1467 if (!s->groups_added)
1468 goto error;
1469
1470 /* groups_pending_delete. */
1471 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1472 if (!s->groups_pending_delete)
1473 goto error;
1474
1475 /* params. */
1476 status = selector_params_get(ctl, i);
1477 if (status)
1478 goto error;
1479 }
1480
1481 /* learner tables. */
1482 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1483 if (!ctl->learners)
1484 goto error;
1485
1486 for (i = 0; i < ctl->info.n_learners; i++) {
1487 struct learner *l = &ctl->learners[i];
1488 uint32_t j;
1489
1490 /* info. */
1491 status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1492 if (status)
1493 goto error;
1494
1495 /* mf. */
1496 l->mf = calloc(l->info.n_match_fields,
1497 sizeof(struct rte_swx_ctl_table_match_field_info));
1498 if (!l->mf)
1499 goto error;
1500
1501 for (j = 0; j < l->info.n_match_fields; j++) {
1502 status = rte_swx_ctl_learner_match_field_info_get(p,
1503 i,
1504 j,
1505 &l->mf[j]);
1506 if (status)
1507 goto error;
1508 }
1509
1510 /* actions. */
1511 l->actions = calloc(l->info.n_actions,
1512 sizeof(struct rte_swx_ctl_table_action_info));
1513 if (!l->actions)
1514 goto error;
1515
1516 for (j = 0; j < l->info.n_actions; j++) {
1517 status = rte_swx_ctl_learner_action_info_get(p,
1518 i,
1519 j,
1520 &l->actions[j]);
1521 if (status || l->actions[j].action_id >= ctl->info.n_actions)
1522 goto error;
1523 }
1524
1525 /* action_data_size. */
1526 l->action_data_size = learner_action_data_size_get(ctl, l);
1527 }
1528
1529 /* ts. */
1530 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1531 if (status)
1532 goto error;
1533
1534 /* ts_next. */
1535 status = table_state_create(ctl);
1536 if (status)
1537 goto error;
1538
1539 if (ctl->info.name[0]) {
1540 status = ctl_register(ctl);
1541 if (status)
1542 goto error;
1543 }
1544
1545 return ctl;
1546
1547 error:
1548 rte_swx_ctl_pipeline_free(ctl);
1549 return NULL;
1550 }
1551
1552 int
rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)1553 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1554 const char *table_name,
1555 struct rte_swx_table_entry *entry)
1556 {
1557 struct table *table;
1558 struct rte_swx_table_entry *new_entry, *existing_entry;
1559 uint32_t table_id;
1560
1561 CHECK(ctl, EINVAL);
1562 CHECK(table_name && table_name[0], EINVAL);
1563
1564 table = table_find(ctl, table_name);
1565 CHECK(table, EINVAL);
1566 table_id = table - ctl->tables;
1567
1568 CHECK(entry, EINVAL);
1569 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1570
1571 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1572 CHECK(new_entry, ENOMEM);
1573
1574 /* The new entry is found in the table->entries list:
1575 * - Add the new entry to the table->pending_modify1 list;
1576 * - Move the existing entry from the table->entries list to the
1577 * table->pending_modify0 list.
1578 */
1579 existing_entry = table_entries_find(table, entry);
1580 if (existing_entry) {
1581 TAILQ_INSERT_TAIL(&table->pending_modify1,
1582 new_entry,
1583 node);
1584
1585 TAILQ_REMOVE(&table->entries,
1586 existing_entry,
1587 node);
1588
1589 TAILQ_INSERT_TAIL(&table->pending_modify0,
1590 existing_entry,
1591 node);
1592
1593 return 0;
1594 }
1595
1596 /* The new entry is found in the table->pending_add list:
1597 * - Replace the entry in the table->pending_add list with the new entry
1598 * (and free the replaced entry).
1599 */
1600 existing_entry = table_pending_add_find(table, entry);
1601 if (existing_entry) {
1602 TAILQ_INSERT_AFTER(&table->pending_add,
1603 existing_entry,
1604 new_entry,
1605 node);
1606
1607 TAILQ_REMOVE(&table->pending_add,
1608 existing_entry,
1609 node);
1610
1611 table_entry_free(existing_entry);
1612
1613 return 0;
1614 }
1615
1616 /* The new entry is found in the table->pending_modify1 list:
1617 * - Replace the entry in the table->pending_modify1 list with the new
1618 * entry (and free the replaced entry).
1619 */
1620 existing_entry = table_pending_modify1_find(table, entry);
1621 if (existing_entry) {
1622 TAILQ_INSERT_AFTER(&table->pending_modify1,
1623 existing_entry,
1624 new_entry,
1625 node);
1626
1627 TAILQ_REMOVE(&table->pending_modify1,
1628 existing_entry,
1629 node);
1630
1631 table_entry_free(existing_entry);
1632
1633 return 0;
1634 }
1635
1636 /* The new entry is found in the table->pending_delete list:
1637 * - Add the new entry to the table->pending_modify1 list;
1638 * - Move the existing entry from the table->pending_delete list to the
1639 * table->pending_modify0 list.
1640 */
1641 existing_entry = table_pending_delete_find(table, entry);
1642 if (existing_entry) {
1643 TAILQ_INSERT_TAIL(&table->pending_modify1,
1644 new_entry,
1645 node);
1646
1647 TAILQ_REMOVE(&table->pending_delete,
1648 existing_entry,
1649 node);
1650
1651 TAILQ_INSERT_TAIL(&table->pending_modify0,
1652 existing_entry,
1653 node);
1654
1655 return 0;
1656 }
1657
1658 /* The new entry is not found in any of the above lists:
1659 * - Add the new entry to the table->pending_add list.
1660 */
1661 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1662
1663 return 0;
1664 }
1665
1666 int
rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)1667 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1668 const char *table_name,
1669 struct rte_swx_table_entry *entry)
1670 {
1671 struct table *table;
1672 struct rte_swx_table_entry *existing_entry;
1673 uint32_t table_id;
1674
1675 CHECK(ctl, EINVAL);
1676
1677 CHECK(table_name && table_name[0], EINVAL);
1678 table = table_find(ctl, table_name);
1679 CHECK(table, EINVAL);
1680 table_id = table - ctl->tables;
1681
1682 CHECK(entry, EINVAL);
1683 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1684
1685 /* The entry is found in the table->entries list:
1686 * - Move the existing entry from the table->entries list to the
1687 * table->pending_delete list.
1688 */
1689 existing_entry = table_entries_find(table, entry);
1690 if (existing_entry) {
1691 TAILQ_REMOVE(&table->entries,
1692 existing_entry,
1693 node);
1694
1695 TAILQ_INSERT_TAIL(&table->pending_delete,
1696 existing_entry,
1697 node);
1698
1699 return 0;
1700 }
1701
1702 /* The entry is found in the table->pending_add list:
1703 * - Remove the entry from the table->pending_add list and free it.
1704 */
1705 existing_entry = table_pending_add_find(table, entry);
1706 if (existing_entry) {
1707 TAILQ_REMOVE(&table->pending_add,
1708 existing_entry,
1709 node);
1710
1711 table_entry_free(existing_entry);
1712 }
1713
1714 /* The entry is found in the table->pending_modify1 list:
1715 * - Free the entry in the table->pending_modify1 list;
1716 * - Move the existing entry from the table->pending_modify0 list to the
1717 * table->pending_delete list.
1718 */
1719 existing_entry = table_pending_modify1_find(table, entry);
1720 if (existing_entry) {
1721 struct rte_swx_table_entry *real_existing_entry;
1722
1723 TAILQ_REMOVE(&table->pending_modify1,
1724 existing_entry,
1725 node);
1726
1727 table_entry_free(existing_entry);
1728
1729 real_existing_entry = table_pending_modify0_find(table, entry);
1730 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1731
1732 TAILQ_REMOVE(&table->pending_modify0,
1733 real_existing_entry,
1734 node);
1735
1736 TAILQ_INSERT_TAIL(&table->pending_delete,
1737 real_existing_entry,
1738 node);
1739
1740 return 0;
1741 }
1742
1743 /* The entry is found in the table->pending_delete list:
1744 * - Do nothing: the existing entry is already in the
1745 * table->pending_delete list, i.e. already marked for delete, so
1746 * simply keep it there as it is.
1747 */
1748
1749 /* The entry is not found in any of the above lists:
1750 * - Do nothing: no existing entry to delete.
1751 */
1752
1753 return 0;
1754 }
1755
1756 int
rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)1757 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1758 const char *table_name,
1759 struct rte_swx_table_entry *entry)
1760 {
1761 struct table *table;
1762 struct rte_swx_table_entry *new_entry;
1763 uint32_t table_id;
1764
1765 CHECK(ctl, EINVAL);
1766
1767 CHECK(table_name && table_name[0], EINVAL);
1768 table = table_find(ctl, table_name);
1769 CHECK(table, EINVAL);
1770 table_id = table - ctl->tables;
1771 CHECK(!table->info.default_action_is_const, EINVAL);
1772
1773 CHECK(entry, EINVAL);
1774 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1775
1776 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1777 CHECK(new_entry, ENOMEM);
1778
1779 table_pending_default_free(table);
1780
1781 table->pending_default = new_entry;
1782 return 0;
1783 }
1784
1785
1786 static void
table_entry_list_free(struct rte_swx_table_entry_list * list)1787 table_entry_list_free(struct rte_swx_table_entry_list *list)
1788 {
1789 for ( ; ; ) {
1790 struct rte_swx_table_entry *entry;
1791
1792 entry = TAILQ_FIRST(list);
1793 if (!entry)
1794 break;
1795
1796 TAILQ_REMOVE(list, entry, node);
1797 table_entry_free(entry);
1798 }
1799 }
1800
1801 static int
table_entry_list_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry_list * dst,struct rte_swx_table_entry_list * src)1802 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1803 uint32_t table_id,
1804 struct rte_swx_table_entry_list *dst,
1805 struct rte_swx_table_entry_list *src)
1806 {
1807 struct rte_swx_table_entry *src_entry;
1808
1809 TAILQ_FOREACH(src_entry, src, node) {
1810 struct rte_swx_table_entry *dst_entry;
1811
1812 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1813 if (!dst_entry)
1814 goto error;
1815
1816 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1817 }
1818
1819 return 0;
1820
1821 error:
1822 table_entry_list_free(dst);
1823 return -ENOMEM;
1824 }
1825
1826 /* This commit stage contains all the operations that can fail; in case ANY of
1827 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1828 */
1829 static int
table_rollfwd0(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,uint32_t after_swap)1830 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1831 uint32_t table_id,
1832 uint32_t after_swap)
1833 {
1834 struct table *table = &ctl->tables[table_id];
1835 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1836 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1837
1838 if (table->is_stub || !table_is_update_pending(table, 0))
1839 return 0;
1840
1841 /*
1842 * Current table supports incremental update.
1843 */
1844 if (table->ops.add) {
1845 /* Reset counters. */
1846 table->n_add = 0;
1847 table->n_modify = 0;
1848 table->n_delete = 0;
1849
1850 /* Add pending rules. */
1851 struct rte_swx_table_entry *entry;
1852
1853 TAILQ_FOREACH(entry, &table->pending_add, node) {
1854 int status;
1855
1856 status = table->ops.add(ts_next->obj, entry);
1857 if (status)
1858 return status;
1859
1860 table->n_add++;
1861 }
1862
1863 /* Modify pending rules. */
1864 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1865 int status;
1866
1867 status = table->ops.add(ts_next->obj, entry);
1868 if (status)
1869 return status;
1870
1871 table->n_modify++;
1872 }
1873
1874 /* Delete pending rules. */
1875 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1876 int status;
1877
1878 status = table->ops.del(ts_next->obj, entry);
1879 if (status)
1880 return status;
1881
1882 table->n_delete++;
1883 }
1884
1885 return 0;
1886 }
1887
1888 /*
1889 * Current table does NOT support incremental update.
1890 */
1891 if (!after_swap) {
1892 struct rte_swx_table_entry_list list;
1893 int status;
1894
1895 /* Create updated list of entries included. */
1896 TAILQ_INIT(&list);
1897
1898 status = table_entry_list_duplicate(ctl,
1899 table_id,
1900 &list,
1901 &table->entries);
1902 if (status)
1903 goto error;
1904
1905 status = table_entry_list_duplicate(ctl,
1906 table_id,
1907 &list,
1908 &table->pending_add);
1909 if (status)
1910 goto error;
1911
1912 status = table_entry_list_duplicate(ctl,
1913 table_id,
1914 &list,
1915 &table->pending_modify1);
1916 if (status)
1917 goto error;
1918
1919 /* Create new table object with the updates included. */
1920 ts_next->obj = table->ops.create(&table->params,
1921 &list,
1922 table->info.args,
1923 ctl->numa_node);
1924 if (!ts_next->obj) {
1925 status = -ENODEV;
1926 goto error;
1927 }
1928
1929 table_entry_list_free(&list);
1930
1931 return 0;
1932
1933 error:
1934 table_entry_list_free(&list);
1935 return status;
1936 }
1937
1938 /* Free the old table object. */
1939 if (ts_next->obj && table->ops.free)
1940 table->ops.free(ts_next->obj);
1941
1942 /* Copy over the new table object. */
1943 ts_next->obj = ts->obj;
1944
1945 return 0;
1946 }
1947
1948 /* This commit stage contains all the operations that cannot fail. They are
1949 * executed only if the previous stage was successful for ALL the tables. Hence,
1950 * none of these operations has to be rolled back for ANY table.
1951 */
1952 static void
table_rollfwd1(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1953 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1954 {
1955 struct table *table = &ctl->tables[table_id];
1956 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1957 struct action *a;
1958 uint8_t *action_data;
1959 uint64_t action_id;
1960
1961 /* Copy the pending default entry. */
1962 if (!table->pending_default)
1963 return;
1964
1965 action_id = table->pending_default->action_id;
1966 action_data = table->pending_default->action_data;
1967 a = &ctl->actions[action_id];
1968
1969 if (a->data_size)
1970 memcpy(ts_next->default_action_data, action_data, a->data_size);
1971
1972 ts_next->default_action_id = action_id;
1973 }
1974
1975 /* This last commit stage is simply finalizing a successful commit operation.
1976 * This stage is only executed if all the previous stages were successful. This
1977 * stage cannot fail.
1978 */
1979 static void
table_rollfwd2(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)1980 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1981 {
1982 struct table *table = &ctl->tables[table_id];
1983
1984 /* Move all the pending add entries to the table, as they are now part
1985 * of the table.
1986 */
1987 table_pending_add_admit(table);
1988
1989 /* Move all the pending modify1 entries to table, are they are now part
1990 * of the table. Free up all the pending modify0 entries, as they are no
1991 * longer part of the table.
1992 */
1993 table_pending_modify1_admit(table);
1994 table_pending_modify0_free(table);
1995
1996 /* Free up all the pending delete entries, as they are no longer part of
1997 * the table.
1998 */
1999 table_pending_delete_free(table);
2000
2001 /* Free up the pending default entry, as it is now part of the table. */
2002 table_pending_default_free(table);
2003 }
2004
2005 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
2006 * commit operations that can fail did fail for ANY table. It reverts ALL the
2007 * tables to their state before the commit started, as if the commit never
2008 * happened.
2009 */
2010 static void
table_rollback(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)2011 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2012 {
2013 struct table *table = &ctl->tables[table_id];
2014 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
2015
2016 if (table->is_stub || !table_is_update_pending(table, 0))
2017 return;
2018
2019 if (table->ops.add) {
2020 struct rte_swx_table_entry *entry;
2021
2022 /* Add back all the entries that were just deleted. */
2023 TAILQ_FOREACH(entry, &table->pending_delete, node) {
2024 if (!table->n_delete)
2025 break;
2026
2027 table->ops.add(ts_next->obj, entry);
2028 table->n_delete--;
2029 }
2030
2031 /* Add back the old copy for all the entries that were just
2032 * modified.
2033 */
2034 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2035 if (!table->n_modify)
2036 break;
2037
2038 table->ops.add(ts_next->obj, entry);
2039 table->n_modify--;
2040 }
2041
2042 /* Delete all the entries that were just added. */
2043 TAILQ_FOREACH(entry, &table->pending_add, node) {
2044 if (!table->n_add)
2045 break;
2046
2047 table->ops.del(ts_next->obj, entry);
2048 table->n_add--;
2049 }
2050 } else {
2051 struct rte_swx_table_state *ts = &ctl->ts[table_id];
2052
2053 /* Free the new table object, as update was cancelled. */
2054 if (ts_next->obj && table->ops.free)
2055 table->ops.free(ts_next->obj);
2056
2057 /* Reinstate the old table object. */
2058 ts_next->obj = ts->obj;
2059 }
2060 }
2061
2062 /* This stage is conditionally executed (as instructed by the user) after a
2063 * failed commit operation to remove ALL the pending work for ALL the tables.
2064 */
2065 static void
table_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)2066 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
2067 {
2068 struct table *table = &ctl->tables[table_id];
2069
2070 /* Free up all the pending add entries, as none of them is part of the
2071 * table.
2072 */
2073 table_pending_add_free(table);
2074
2075 /* Free up all the pending modify1 entries, as none of them made it to
2076 * the table. Add back all the pending modify0 entries, as none of them
2077 * was deleted from the table.
2078 */
2079 table_pending_modify1_free(table);
2080 table_pending_modify0_admit(table);
2081
2082 /* Add back all the pending delete entries, as none of them was deleted
2083 * from the table.
2084 */
2085 table_pending_delete_admit(table);
2086
2087 /* Free up the pending default entry, as it is no longer going to be
2088 * added to the table.
2089 */
2090 table_pending_default_free(table);
2091 }
2092
2093 int
rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t * group_id)2094 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
2095 const char *selector_name,
2096 uint32_t *group_id)
2097 {
2098 struct selector *s;
2099 uint32_t i;
2100
2101 /* Check input arguments. */
2102 if (!ctl || !selector_name || !selector_name[0] || !group_id)
2103 return -EINVAL;
2104
2105 s = selector_find(ctl, selector_name);
2106 if (!s)
2107 return -EINVAL;
2108
2109 /* Find an unused group. */
2110 for (i = 0; i < s->info.n_groups_max; i++)
2111 if (!s->groups_added[i]) {
2112 *group_id = i;
2113 s->groups_added[i] = 1;
2114 return 0;
2115 }
2116
2117 return -ENOSPC;
2118 }
2119
2120 int
rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id)2121 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2122 const char *selector_name,
2123 uint32_t group_id)
2124 {
2125 struct selector *s;
2126 struct rte_swx_table_selector_group *group;
2127
2128 /* Check input arguments. */
2129 if (!ctl || !selector_name || !selector_name[0])
2130 return -EINVAL;
2131
2132 s = selector_find(ctl, selector_name);
2133 if (!s ||
2134 (group_id >= s->info.n_groups_max) ||
2135 !s->groups_added[group_id])
2136 return -EINVAL;
2137
2138 /* Check if this group is already scheduled for deletion. */
2139 if (s->groups_pending_delete[group_id])
2140 return 0;
2141
2142 /* Initialize the pending group, if needed. */
2143 if (!s->pending_groups[group_id]) {
2144 int status;
2145
2146 status = selector_group_duplicate_to_pending(s, group_id);
2147 if (status)
2148 return status;
2149 }
2150
2151 group = s->pending_groups[group_id];
2152
2153 /* Schedule removal of all the members from the current group. */
2154 for ( ; ; ) {
2155 struct rte_swx_table_selector_member *m;
2156
2157 m = TAILQ_FIRST(&group->members);
2158 if (!m)
2159 break;
2160
2161 TAILQ_REMOVE(&group->members, m, node);
2162 free(m);
2163 }
2164
2165 /* Schedule the group for deletion. */
2166 s->groups_pending_delete[group_id] = 1;
2167
2168 return 0;
2169 }
2170
2171 int
rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id,uint32_t member_id,uint32_t member_weight)2172 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2173 const char *selector_name,
2174 uint32_t group_id,
2175 uint32_t member_id,
2176 uint32_t member_weight)
2177 {
2178 struct selector *s;
2179 struct rte_swx_table_selector_group *group;
2180 struct rte_swx_table_selector_member *m;
2181
2182 if (!member_weight)
2183 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2184 selector_name,
2185 group_id,
2186 member_id);
2187
2188 /* Check input arguments. */
2189 if (!ctl || !selector_name || !selector_name[0])
2190 return -EINVAL;
2191
2192 s = selector_find(ctl, selector_name);
2193 if (!s ||
2194 (group_id >= s->info.n_groups_max) ||
2195 !s->groups_added[group_id] ||
2196 s->groups_pending_delete[group_id])
2197 return -EINVAL;
2198
2199 /* Initialize the pending group, if needed. */
2200 if (!s->pending_groups[group_id]) {
2201 int status;
2202
2203 status = selector_group_duplicate_to_pending(s, group_id);
2204 if (status)
2205 return status;
2206 }
2207
2208 group = s->pending_groups[group_id];
2209
2210 /* If this member is already in this group, then simply update its weight and return. */
2211 TAILQ_FOREACH(m, &group->members, node)
2212 if (m->member_id == member_id) {
2213 m->member_weight = member_weight;
2214 return 0;
2215 }
2216
2217 /* Add new member to this group. */
2218 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2219 if (!m)
2220 return -ENOMEM;
2221
2222 m->member_id = member_id;
2223 m->member_weight = member_weight;
2224
2225 TAILQ_INSERT_TAIL(&group->members, m, node);
2226
2227 return 0;
2228 }
2229
2230 int
rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id __rte_unused,uint32_t member_id __rte_unused)2231 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2232 const char *selector_name,
2233 uint32_t group_id __rte_unused,
2234 uint32_t member_id __rte_unused)
2235 {
2236 struct selector *s;
2237 struct rte_swx_table_selector_group *group;
2238 struct rte_swx_table_selector_member *m;
2239
2240 /* Check input arguments. */
2241 if (!ctl || !selector_name || !selector_name[0])
2242 return -EINVAL;
2243
2244 s = selector_find(ctl, selector_name);
2245 if (!s ||
2246 (group_id >= s->info.n_groups_max) ||
2247 !s->groups_added[group_id] ||
2248 s->groups_pending_delete[group_id])
2249 return -EINVAL;
2250
2251 /* Initialize the pending group, if needed. */
2252 if (!s->pending_groups[group_id]) {
2253 int status;
2254
2255 status = selector_group_duplicate_to_pending(s, group_id);
2256 if (status)
2257 return status;
2258 }
2259
2260 group = s->pending_groups[group_id];
2261
2262 /* Look for this member in the group and remove it, if found. */
2263 TAILQ_FOREACH(m, &group->members, node)
2264 if (m->member_id == member_id) {
2265 TAILQ_REMOVE(&group->members, m, node);
2266 free(m);
2267 return 0;
2268 }
2269
2270 return 0;
2271 }
2272
2273 static int
selector_rollfwd(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2274 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2275 {
2276 struct selector *s = &ctl->selectors[selector_id];
2277 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2278 uint32_t group_id;
2279
2280 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2281 * mirror copy (ts_next->obj).
2282 */
2283 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2284 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2285 int status;
2286
2287 /* Skip this group if no change needed. */
2288 if (!group)
2289 continue;
2290
2291 /* Apply the pending changes for the current group. */
2292 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2293 if (status)
2294 return status;
2295 }
2296
2297 return 0;
2298 }
2299
2300 static void
selector_rollfwd_finalize(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2301 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2302 {
2303 struct selector *s = &ctl->selectors[selector_id];
2304 uint32_t group_id;
2305
2306 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2307 * records (s->groups[group_id).
2308 */
2309 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2310 struct rte_swx_table_selector_group *g = s->groups[group_id];
2311 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2312
2313 /* Skip this group if no change needed. */
2314 if (!gp)
2315 continue;
2316
2317 /* Transition the pending changes to stable. */
2318 s->groups[group_id] = gp;
2319 s->pending_groups[group_id] = NULL;
2320
2321 /* Free the old group member list. */
2322 if (!g)
2323 continue;
2324
2325 for ( ; ; ) {
2326 struct rte_swx_table_selector_member *m;
2327
2328 m = TAILQ_FIRST(&g->members);
2329 if (!m)
2330 break;
2331
2332 TAILQ_REMOVE(&g->members, m, node);
2333 free(m);
2334 }
2335
2336 free(g);
2337 }
2338
2339 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2340 * s->groups_added[group_id].
2341 */
2342 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2343 if (s->groups_pending_delete[group_id]) {
2344 s->groups_added[group_id] = 0;
2345 s->groups_pending_delete[group_id] = 0;
2346 }
2347 }
2348
2349 static void
selector_rollback(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2350 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2351 {
2352 struct selector *s = &ctl->selectors[selector_id];
2353 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2354 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2355 uint32_t group_id;
2356
2357 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2358 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2359 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2360
2361 if (gp) {
2362 ts_next->obj = ts->obj;
2363 break;
2364 }
2365 }
2366 }
2367
2368 static void
selector_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2369 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2370 {
2371 struct selector *s = &ctl->selectors[selector_id];
2372 uint32_t group_id;
2373
2374 /* Discard any pending group member changes (s->pending_groups[group_id]). */
2375 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2376 selector_pending_group_members_free(s, group_id);
2377
2378 /* Discard any pending group deletions. */
2379 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2380 }
2381
2382 static struct rte_swx_table_entry *
learner_default_entry_alloc(struct learner * l)2383 learner_default_entry_alloc(struct learner *l)
2384 {
2385 struct rte_swx_table_entry *entry;
2386
2387 entry = calloc(1, sizeof(struct rte_swx_table_entry));
2388 if (!entry)
2389 goto error;
2390
2391 /* action_data. */
2392 if (l->action_data_size) {
2393 entry->action_data = calloc(1, l->action_data_size);
2394 if (!entry->action_data)
2395 goto error;
2396 }
2397
2398 return entry;
2399
2400 error:
2401 table_entry_free(entry);
2402 return NULL;
2403 }
2404
2405 static int
learner_default_entry_check(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id,struct rte_swx_table_entry * entry)2406 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2407 uint32_t learner_id,
2408 struct rte_swx_table_entry *entry)
2409 {
2410 struct learner *l = &ctl->learners[learner_id];
2411 struct action *a;
2412 uint32_t i;
2413
2414 CHECK(entry, EINVAL);
2415
2416 /* action_id. */
2417 for (i = 0; i < l->info.n_actions; i++)
2418 if (entry->action_id == l->actions[i].action_id)
2419 break;
2420
2421 CHECK(i < l->info.n_actions, EINVAL);
2422
2423 /* action_data. */
2424 a = &ctl->actions[entry->action_id];
2425 CHECK(!(a->data_size && !entry->action_data), EINVAL);
2426
2427 return 0;
2428 }
2429
2430 static struct rte_swx_table_entry *
learner_default_entry_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id,struct rte_swx_table_entry * entry)2431 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2432 uint32_t learner_id,
2433 struct rte_swx_table_entry *entry)
2434 {
2435 struct learner *l = &ctl->learners[learner_id];
2436 struct rte_swx_table_entry *new_entry = NULL;
2437 struct action *a;
2438 uint32_t i;
2439
2440 if (!entry)
2441 goto error;
2442
2443 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2444 if (!new_entry)
2445 goto error;
2446
2447 /* action_id. */
2448 for (i = 0; i < l->info.n_actions; i++)
2449 if (entry->action_id == l->actions[i].action_id)
2450 break;
2451
2452 if (i >= l->info.n_actions)
2453 goto error;
2454
2455 new_entry->action_id = entry->action_id;
2456
2457 /* action_data. */
2458 a = &ctl->actions[entry->action_id];
2459 if (a->data_size && !entry->action_data)
2460 goto error;
2461
2462 /* The table layer provisions a constant action data size per
2463 * entry, which should be the largest data size for all the
2464 * actions enabled for the current table, and attempts to copy
2465 * this many bytes each time a table entry is added, even if the
2466 * specific action requires less data or even no data at all,
2467 * hence we always have to allocate the max.
2468 */
2469 new_entry->action_data = calloc(1, l->action_data_size);
2470 if (!new_entry->action_data)
2471 goto error;
2472
2473 if (a->data_size)
2474 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2475
2476 return new_entry;
2477
2478 error:
2479 table_entry_free(new_entry);
2480 return NULL;
2481 }
2482
2483 int
rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * learner_name,struct rte_swx_table_entry * entry)2484 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2485 const char *learner_name,
2486 struct rte_swx_table_entry *entry)
2487 {
2488 struct learner *l;
2489 struct rte_swx_table_entry *new_entry;
2490 uint32_t learner_id;
2491
2492 CHECK(ctl, EINVAL);
2493
2494 CHECK(learner_name && learner_name[0], EINVAL);
2495 l = learner_find(ctl, learner_name);
2496 CHECK(l, EINVAL);
2497 learner_id = l - ctl->learners;
2498 CHECK(!l->info.default_action_is_const, EINVAL);
2499
2500 CHECK(entry, EINVAL);
2501 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2502
2503 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2504
2505 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2506 CHECK(new_entry, ENOMEM);
2507
2508 learner_pending_default_free(l);
2509
2510 l->pending_default = new_entry;
2511 return 0;
2512 }
2513
2514 static void
learner_rollfwd(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)2515 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2516 {
2517 struct learner *l = &ctl->learners[learner_id];
2518 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2519 ctl->info.n_selectors + learner_id];
2520 struct action *a;
2521 uint8_t *action_data;
2522 uint64_t action_id;
2523
2524 /* Copy the pending default entry. */
2525 if (!l->pending_default)
2526 return;
2527
2528 action_id = l->pending_default->action_id;
2529 action_data = l->pending_default->action_data;
2530 a = &ctl->actions[action_id];
2531
2532 if (a->data_size)
2533 memcpy(ts_next->default_action_data, action_data, a->data_size);
2534
2535 ts_next->default_action_id = action_id;
2536 }
2537
2538 static void
learner_rollfwd_finalize(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)2539 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2540 {
2541 struct learner *l = &ctl->learners[learner_id];
2542
2543 /* Free up the pending default entry, as it is now part of the table. */
2544 learner_pending_default_free(l);
2545 }
2546
2547 static void
learner_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)2548 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2549 {
2550 struct learner *l = &ctl->learners[learner_id];
2551
2552 /* Free up the pending default entry, as it is no longer going to be added to the table. */
2553 learner_pending_default_free(l);
2554 }
2555
2556 int
rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline * ctl,int abort_on_fail)2557 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2558 {
2559 struct rte_swx_table_state *ts;
2560 int status = 0;
2561 uint32_t i;
2562
2563 CHECK(ctl, EINVAL);
2564
2565 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2566 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2567 * We must be able to fully revert all the changes that can fail as if they never happened.
2568 */
2569 for (i = 0; i < ctl->info.n_tables; i++) {
2570 status = table_rollfwd0(ctl, i, 0);
2571 if (status)
2572 goto rollback;
2573 }
2574
2575 for (i = 0; i < ctl->info.n_selectors; i++) {
2576 status = selector_rollfwd(ctl, i);
2577 if (status)
2578 goto rollback;
2579 }
2580
2581 /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2582 * onwards, the transaction is guaranteed to be successful.
2583 */
2584 for (i = 0; i < ctl->info.n_tables; i++)
2585 table_rollfwd1(ctl, i);
2586
2587 for (i = 0; i < ctl->info.n_learners; i++)
2588 learner_rollfwd(ctl, i);
2589
2590 /* Swap the table state for the data plane. The current ts and ts_next
2591 * become the new ts_next and ts, respectively.
2592 */
2593 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2594 usleep(100);
2595 ts = ctl->ts;
2596 ctl->ts = ctl->ts_next;
2597 ctl->ts_next = ts;
2598
2599 /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2600 * the current ts_next in sync with the current ts. Since the changes that can fail did
2601 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2602 * current ts_next, hence no error checking is needed.
2603 */
2604 for (i = 0; i < ctl->info.n_tables; i++) {
2605 table_rollfwd0(ctl, i, 1);
2606 table_rollfwd1(ctl, i);
2607 table_rollfwd2(ctl, i);
2608 }
2609
2610 for (i = 0; i < ctl->info.n_selectors; i++) {
2611 selector_rollfwd(ctl, i);
2612 selector_rollfwd_finalize(ctl, i);
2613 }
2614
2615 for (i = 0; i < ctl->info.n_learners; i++) {
2616 learner_rollfwd(ctl, i);
2617 learner_rollfwd_finalize(ctl, i);
2618 }
2619
2620 return 0;
2621
2622 rollback:
2623 for (i = 0; i < ctl->info.n_tables; i++) {
2624 table_rollback(ctl, i);
2625 if (abort_on_fail)
2626 table_abort(ctl, i);
2627 }
2628
2629 for (i = 0; i < ctl->info.n_selectors; i++) {
2630 selector_rollback(ctl, i);
2631 if (abort_on_fail)
2632 selector_abort(ctl, i);
2633 }
2634
2635 if (abort_on_fail)
2636 for (i = 0; i < ctl->info.n_learners; i++)
2637 learner_abort(ctl, i);
2638
2639 return status;
2640 }
2641
2642 void
rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline * ctl)2643 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2644 {
2645 uint32_t i;
2646
2647 if (!ctl)
2648 return;
2649
2650 for (i = 0; i < ctl->info.n_tables; i++)
2651 table_abort(ctl, i);
2652
2653 for (i = 0; i < ctl->info.n_selectors; i++)
2654 selector_abort(ctl, i);
2655
2656 for (i = 0; i < ctl->info.n_learners; i++)
2657 learner_abort(ctl, i);
2658 }
2659
2660 static int
mask_to_prefix(uint64_t mask,uint32_t mask_length,uint32_t * prefix_length)2661 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2662 {
2663 uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2664
2665 if (!mask) {
2666 *prefix_length = 0;
2667 return 0;
2668 }
2669
2670 /* Count trailing zero bits. */
2671 for (i = 0; i < 64; i++) {
2672 if (mask & (1LLU << i))
2673 break;
2674
2675 n_trailing_zeros++;
2676 }
2677
2678 /* Count the one bits that follow. */
2679 for ( ; i < 64; i++) {
2680 if (!(mask & (1LLU << i)))
2681 break;
2682
2683 n_ones++;
2684 }
2685
2686 /* Check that no more one bits are present */
2687 for ( ; i < 64; i++)
2688 if (mask & (1LLU << i))
2689 return -EINVAL;
2690
2691 /* Check that the input mask is a prefix or the right length. */
2692 if (n_ones + n_trailing_zeros != mask_length)
2693 return -EINVAL;
2694
2695 *prefix_length = n_ones;
2696 return 0;
2697 }
2698
2699 static int
large_mask_to_prefix(uint8_t * mask,uint32_t n_mask_bytes,uint32_t * prefix_length)2700 large_mask_to_prefix(uint8_t *mask, uint32_t n_mask_bytes, uint32_t *prefix_length)
2701 {
2702 uint32_t pl, i;
2703
2704 /* Check input arguments. */
2705 if (!mask || !n_mask_bytes || !prefix_length)
2706 return -EINVAL;
2707
2708 /* Count leading bits of one. */
2709 for (i = 0; i < n_mask_bytes * 8; i++) {
2710 uint32_t byte_id = i / 8;
2711 uint32_t bit_id = i & 7;
2712
2713 uint32_t byte = mask[byte_id];
2714 uint32_t bit = byte & (1 << (7 - bit_id));
2715
2716 if (!bit)
2717 break;
2718 }
2719
2720 /* Save the potential prefix length. */
2721 pl = i;
2722
2723 /* Check that all remaining bits are zeros. */
2724 for ( ; i < n_mask_bytes * 8; i++) {
2725 uint32_t byte_id = i / 8;
2726 uint32_t bit_id = i & 7;
2727
2728 uint32_t byte = mask[byte_id];
2729 uint32_t bit = byte & (1 << (7 - bit_id));
2730
2731 if (bit)
2732 break;
2733 }
2734
2735 if (i < n_mask_bytes * 8)
2736 return -EINVAL;
2737
2738 *prefix_length = pl;
2739 return 0;
2740 }
2741
2742 static int
char_to_hex(char c,uint8_t * val)2743 char_to_hex(char c, uint8_t *val)
2744 {
2745 if (c >= '0' && c <= '9') {
2746 *val = c - '0';
2747 return 0;
2748 }
2749
2750 if (c >= 'A' && c <= 'F') {
2751 *val = c - 'A' + 10;
2752 return 0;
2753 }
2754
2755 if (c >= 'a' && c <= 'f') {
2756 *val = c - 'a' + 10;
2757 return 0;
2758 }
2759
2760 return -EINVAL;
2761 }
2762
2763 static int
hex_string_parse(char * src,uint8_t * dst,uint32_t n_dst_bytes)2764 hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
2765 {
2766 uint32_t i;
2767
2768 /* Check input arguments. */
2769 if (!src || !src[0] || !dst || !n_dst_bytes)
2770 return -EINVAL;
2771
2772 /* Skip any leading "0x" or "0X" in the src string. */
2773 if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
2774 src += 2;
2775
2776 /* Convert each group of two hex characters in the src string to one byte in dst array. */
2777 for (i = 0; i < n_dst_bytes; i++) {
2778 uint8_t a, b;
2779 int status;
2780
2781 status = char_to_hex(*src, &a);
2782 if (status)
2783 return status;
2784 src++;
2785
2786 status = char_to_hex(*src, &b);
2787 if (status)
2788 return status;
2789 src++;
2790
2791 dst[i] = a * 16 + b;
2792 }
2793
2794 /* Check for the end of the src string. */
2795 if (*src)
2796 return -EINVAL;
2797
2798 return 0;
2799 }
2800
2801 static int
table_entry_match_field_read(struct table * table,struct rte_swx_table_entry * entry,uint32_t mf_id,char * mf_val,char * mf_mask,int * lpm,uint32_t * lpm_prefix_length_max,uint32_t * lpm_prefix_length)2802 table_entry_match_field_read(struct table *table,
2803 struct rte_swx_table_entry *entry,
2804 uint32_t mf_id,
2805 char *mf_val,
2806 char *mf_mask,
2807 int *lpm,
2808 uint32_t *lpm_prefix_length_max,
2809 uint32_t *lpm_prefix_length)
2810 {
2811 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2812 uint64_t val, mask = UINT64_MAX;
2813 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2814
2815 /*
2816 * Mask.
2817 */
2818 if (mf_mask) {
2819 /* Parse. */
2820 mask = strtoull(mf_mask, &mf_mask, 0);
2821 if (mf_mask[0])
2822 return -EINVAL;
2823
2824 /* LPM. */
2825 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2826 int status;
2827
2828 *lpm = 1;
2829
2830 *lpm_prefix_length_max = mf->n_bits;
2831
2832 status = mask_to_prefix(mask, mf->n_bits, lpm_prefix_length);
2833 if (status)
2834 return status;
2835 }
2836
2837 /* Endianness conversion. */
2838 if (mf->is_header)
2839 mask = field_hton(mask, mf->n_bits);
2840 }
2841
2842 /* Copy to entry. */
2843 if (entry->key_mask)
2844 memcpy(&entry->key_mask[offset], (uint8_t *)&mask, mf->n_bits / 8);
2845
2846 /*
2847 * Value.
2848 */
2849 /* Parse. */
2850 val = strtoull(mf_val, &mf_val, 0);
2851 if (mf_val[0])
2852 return -EINVAL;
2853
2854 /* Endianness conversion. */
2855 if (mf->is_header)
2856 val = field_hton(val, mf->n_bits);
2857
2858 /* Copy to entry. */
2859 memcpy(&entry->key[offset], (uint8_t *)&val, mf->n_bits / 8);
2860
2861 return 0;
2862 }
2863
2864 static int
table_entry_action_argument_read(struct action * action,struct rte_swx_table_entry * entry,uint32_t arg_id,uint32_t arg_offset,char * arg_val)2865 table_entry_action_argument_read(struct action *action,
2866 struct rte_swx_table_entry *entry,
2867 uint32_t arg_id,
2868 uint32_t arg_offset,
2869 char *arg_val)
2870 {
2871 struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2872 uint64_t val;
2873
2874 val = strtoull(arg_val, &arg_val, 0);
2875 if (arg_val[0])
2876 return -EINVAL;
2877
2878 /* Endianness conversion. */
2879 if (arg->is_network_byte_order)
2880 val = field_hton(val, arg->n_bits);
2881
2882 /* Copy to entry. */
2883 memcpy(&entry->action_data[arg_offset],
2884 (uint8_t *)&val,
2885 arg->n_bits / 8);
2886
2887 return 0;
2888 }
2889
2890 static int
table_entry_large_match_field_read(struct table * table,struct rte_swx_table_entry * entry,uint32_t mf_id,char * mf_val,char * mf_mask,int * lpm,uint32_t * lpm_prefix_length_max,uint32_t * lpm_prefix_length)2891 table_entry_large_match_field_read(struct table *table,
2892 struct rte_swx_table_entry *entry,
2893 uint32_t mf_id,
2894 char *mf_val,
2895 char *mf_mask,
2896 int *lpm,
2897 uint32_t *lpm_prefix_length_max,
2898 uint32_t *lpm_prefix_length)
2899 {
2900 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2901 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2902 int status;
2903
2904 /*
2905 * Mask.
2906 */
2907 if (!entry->key_mask)
2908 goto value;
2909
2910 if (!mf_mask) {
2911 /* Set mask to all-ones. */
2912 memset(&entry->key_mask[offset], 0xFF, mf->n_bits / 8);
2913 goto value;
2914 }
2915
2916 /* Parse. */
2917 status = hex_string_parse(mf_mask, &entry->key_mask[offset], mf->n_bits / 8);
2918 if (status)
2919 return -EINVAL;
2920
2921 /* LPM. */
2922 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2923 *lpm = 1;
2924
2925 *lpm_prefix_length_max = mf->n_bits;
2926
2927 status = large_mask_to_prefix(&entry->key_mask[offset],
2928 mf->n_bits / 8,
2929 lpm_prefix_length);
2930 if (status)
2931 return status;
2932 }
2933
2934 /*
2935 * Value.
2936 */
2937 value:
2938 /* Parse. */
2939 status = hex_string_parse(mf_val, &entry->key[offset], mf->n_bits / 8);
2940 if (status)
2941 return -EINVAL;
2942
2943 return 0;
2944 }
2945
2946 static int
table_entry_large_action_argument_read(struct action * action,struct rte_swx_table_entry * entry,uint32_t arg_id,uint32_t arg_offset,char * arg_val)2947 table_entry_large_action_argument_read(struct action *action,
2948 struct rte_swx_table_entry *entry,
2949 uint32_t arg_id,
2950 uint32_t arg_offset,
2951 char *arg_val)
2952 {
2953 struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2954 int status;
2955
2956 status = hex_string_parse(arg_val, &entry->action_data[arg_offset], arg->n_bits / 8);
2957 if (status)
2958 return -EINVAL;
2959
2960 return 0;
2961 }
2962
2963 static int
token_is_comment(const char * token)2964 token_is_comment(const char *token)
2965 {
2966 if ((token[0] == '#') ||
2967 (token[0] == ';') ||
2968 ((token[0] == '/') && (token[1] == '/')))
2969 return 1; /* TRUE. */
2970
2971 return 0; /* FALSE. */
2972 }
2973
2974 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2975
2976 struct rte_swx_table_entry *
rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline * ctl,const char * table_name,const char * string,int * is_blank_or_comment)2977 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2978 const char *table_name,
2979 const char *string,
2980 int *is_blank_or_comment)
2981 {
2982 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2983 struct table *table;
2984 struct action *action;
2985 struct rte_swx_table_entry *entry = NULL;
2986 char *s0 = NULL, *s;
2987 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2988 int lpm = 0, blank_or_comment = 0;
2989
2990 /* Check input arguments. */
2991 if (!ctl)
2992 goto error;
2993
2994 if (!table_name || !table_name[0])
2995 goto error;
2996
2997 table = table_find(ctl, table_name);
2998 if (!table)
2999 goto error;
3000
3001 if (!string || !string[0])
3002 goto error;
3003
3004 /* Memory allocation. */
3005 s0 = strdup(string);
3006 if (!s0)
3007 goto error;
3008
3009 entry = table_entry_alloc(table);
3010 if (!entry)
3011 goto error;
3012
3013 /* Parse the string into tokens. */
3014 for (s = s0; ; ) {
3015 char *token;
3016
3017 token = strtok_r(s, " \f\n\r\t\v", &s);
3018 if (!token || token_is_comment(token))
3019 break;
3020
3021 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3022 goto error;
3023
3024 token_array[n_tokens] = token;
3025 n_tokens++;
3026 }
3027
3028 if (!n_tokens) {
3029 blank_or_comment = 1;
3030 goto error;
3031 }
3032
3033 tokens = token_array;
3034
3035 /*
3036 * Match.
3037 */
3038 if (!(n_tokens && !strcmp(tokens[0], "match")))
3039 goto action;
3040
3041 if (n_tokens < 1 + table->info.n_match_fields)
3042 goto error;
3043
3044 for (i = 0; i < table->info.n_match_fields; i++) {
3045 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
3046 char *mf_val = tokens[1 + i], *mf_mask = NULL;
3047 int status;
3048
3049 mf_mask = strchr(mf_val, '/');
3050 if (mf_mask) {
3051 *mf_mask = 0;
3052 mf_mask++;
3053 }
3054
3055 if (mf->n_bits <= 64)
3056 status = table_entry_match_field_read(table,
3057 entry,
3058 i,
3059 mf_val,
3060 mf_mask,
3061 &lpm,
3062 &lpm_prefix_length_max,
3063 &lpm_prefix_length);
3064 else
3065 status = table_entry_large_match_field_read(table,
3066 entry,
3067 i,
3068 mf_val,
3069 mf_mask,
3070 &lpm,
3071 &lpm_prefix_length_max,
3072 &lpm_prefix_length);
3073 if (status)
3074 goto error;
3075
3076 }
3077
3078 tokens += 1 + table->info.n_match_fields;
3079 n_tokens -= 1 + table->info.n_match_fields;
3080
3081 /*
3082 * Match priority.
3083 */
3084 if (n_tokens && !strcmp(tokens[0], "priority")) {
3085 char *priority = tokens[1];
3086 uint32_t val;
3087
3088 if (n_tokens < 2)
3089 goto error;
3090
3091 /* Parse. */
3092 val = strtoul(priority, &priority, 0);
3093 if (priority[0])
3094 goto error;
3095
3096 /* Copy to entry. */
3097 entry->key_priority = val;
3098
3099 tokens += 2;
3100 n_tokens -= 2;
3101 }
3102
3103 /* LPM. */
3104 if (lpm)
3105 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
3106
3107 /*
3108 * Action.
3109 */
3110 action:
3111 if (!(n_tokens && !strcmp(tokens[0], "action")))
3112 goto other;
3113
3114 if (n_tokens < 2)
3115 goto error;
3116
3117 action = action_find(ctl, tokens[1]);
3118 if (!action)
3119 goto error;
3120
3121 if (n_tokens < 2 + action->info.n_args * 2)
3122 goto error;
3123
3124 /* action_id. */
3125 entry->action_id = action - ctl->actions;
3126
3127 /* action_data. */
3128 for (i = 0; i < action->info.n_args; i++) {
3129 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3130 char *arg_name, *arg_val;
3131 int status;
3132
3133 arg_name = tokens[2 + i * 2];
3134 arg_val = tokens[2 + i * 2 + 1];
3135
3136 if (strcmp(arg_name, arg->name))
3137 goto error;
3138
3139 if (arg->n_bits <= 64)
3140 status = table_entry_action_argument_read(action,
3141 entry,
3142 i,
3143 arg_offset,
3144 arg_val);
3145 else
3146 status = table_entry_large_action_argument_read(action,
3147 entry,
3148 i,
3149 arg_offset,
3150 arg_val);
3151 if (status)
3152 goto error;
3153
3154 arg_offset += arg->n_bits / 8;
3155 }
3156
3157 tokens += 2 + action->info.n_args * 2;
3158 n_tokens -= 2 + action->info.n_args * 2;
3159
3160 other:
3161 if (n_tokens)
3162 goto error;
3163
3164 free(s0);
3165 return entry;
3166
3167 error:
3168 table_entry_free(entry);
3169 free(s0);
3170 if (is_blank_or_comment)
3171 *is_blank_or_comment = blank_or_comment;
3172 return NULL;
3173 }
3174
3175 struct rte_swx_table_entry *
rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline * ctl,const char * learner_name,const char * string,int * is_blank_or_comment)3176 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
3177 const char *learner_name,
3178 const char *string,
3179 int *is_blank_or_comment)
3180 {
3181 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
3182 struct learner *l;
3183 struct action *action;
3184 struct rte_swx_table_entry *entry = NULL;
3185 char *s0 = NULL, *s;
3186 uint32_t n_tokens = 0, arg_offset = 0, i;
3187 int blank_or_comment = 0;
3188
3189 /* Check input arguments. */
3190 if (!ctl)
3191 goto error;
3192
3193 if (!learner_name || !learner_name[0])
3194 goto error;
3195
3196 l = learner_find(ctl, learner_name);
3197 if (!l)
3198 goto error;
3199
3200 if (!string || !string[0])
3201 goto error;
3202
3203 /* Memory allocation. */
3204 s0 = strdup(string);
3205 if (!s0)
3206 goto error;
3207
3208 entry = learner_default_entry_alloc(l);
3209 if (!entry)
3210 goto error;
3211
3212 /* Parse the string into tokens. */
3213 for (s = s0; ; ) {
3214 char *token;
3215
3216 token = strtok_r(s, " \f\n\r\t\v", &s);
3217 if (!token || token_is_comment(token))
3218 break;
3219
3220 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
3221 goto error;
3222
3223 token_array[n_tokens] = token;
3224 n_tokens++;
3225 }
3226
3227 if (!n_tokens) {
3228 blank_or_comment = 1;
3229 goto error;
3230 }
3231
3232 tokens = token_array;
3233
3234 /*
3235 * Action.
3236 */
3237 if (!(n_tokens && !strcmp(tokens[0], "action")))
3238 goto other;
3239
3240 if (n_tokens < 2)
3241 goto error;
3242
3243 action = action_find(ctl, tokens[1]);
3244 if (!action)
3245 goto error;
3246
3247 if (n_tokens < 2 + action->info.n_args * 2)
3248 goto error;
3249
3250 /* action_id. */
3251 entry->action_id = action - ctl->actions;
3252
3253 /* action_data. */
3254 for (i = 0; i < action->info.n_args; i++) {
3255 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
3256 char *arg_name, *arg_val;
3257 uint64_t val;
3258
3259 arg_name = tokens[2 + i * 2];
3260 arg_val = tokens[2 + i * 2 + 1];
3261
3262 if (strcmp(arg_name, arg->name))
3263 goto error;
3264
3265 val = strtoull(arg_val, &arg_val, 0);
3266 if (arg_val[0])
3267 goto error;
3268
3269 /* Endianness conversion. */
3270 if (arg->is_network_byte_order)
3271 val = field_hton(val, arg->n_bits);
3272
3273 /* Copy to entry. */
3274 memcpy(&entry->action_data[arg_offset],
3275 (uint8_t *)&val,
3276 arg->n_bits / 8);
3277
3278 arg_offset += arg->n_bits / 8;
3279 }
3280
3281 tokens += 2 + action->info.n_args * 2;
3282 n_tokens -= 2 + action->info.n_args * 2;
3283
3284 other:
3285 if (n_tokens)
3286 goto error;
3287
3288 free(s0);
3289 return entry;
3290
3291 error:
3292 table_entry_free(entry);
3293 free(s0);
3294 if (is_blank_or_comment)
3295 *is_blank_or_comment = blank_or_comment;
3296 return NULL;
3297 }
3298
3299 static void
table_entry_printf(FILE * f,struct rte_swx_ctl_pipeline * ctl,struct table * table,struct rte_swx_table_entry * entry)3300 table_entry_printf(FILE *f,
3301 struct rte_swx_ctl_pipeline *ctl,
3302 struct table *table,
3303 struct rte_swx_table_entry *entry)
3304 {
3305 struct action *action = &ctl->actions[entry->action_id];
3306 uint32_t i;
3307
3308 fprintf(f, "match ");
3309 for (i = 0; i < table->params.key_size; i++)
3310 fprintf(f, "%02x", entry->key[i]);
3311
3312 if (entry->key_mask) {
3313 fprintf(f, "/");
3314 for (i = 0; i < table->params.key_size; i++)
3315 fprintf(f, "%02x", entry->key_mask[i]);
3316 }
3317
3318 fprintf(f, " priority %u", entry->key_priority);
3319
3320 fprintf(f, " action %s ", action->info.name);
3321 for (i = 0; i < action->data_size; i++)
3322 fprintf(f, "%02x", entry->action_data[i]);
3323
3324 fprintf(f, "\n");
3325 }
3326
3327 int
rte_swx_ctl_pipeline_table_fprintf(FILE * f,struct rte_swx_ctl_pipeline * ctl,const char * table_name)3328 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
3329 struct rte_swx_ctl_pipeline *ctl,
3330 const char *table_name)
3331 {
3332 struct table *table;
3333 struct rte_swx_table_entry *entry;
3334 uint32_t n_entries = 0, i;
3335
3336 if (!f || !ctl || !table_name || !table_name[0])
3337 return -EINVAL;
3338
3339 table = table_find(ctl, table_name);
3340 if (!table)
3341 return -EINVAL;
3342
3343 /* Table. */
3344 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3345 table->info.name,
3346 table->params.key_size,
3347 table->params.key_offset);
3348
3349 for (i = 0; i < table->params.key_size; i++)
3350 fprintf(f, "%02x", table->params.key_mask0[i]);
3351
3352 fprintf(f, "], action data size %u bytes\n",
3353 table->params.action_data_size);
3354
3355 /* Table entries. */
3356 TAILQ_FOREACH(entry, &table->entries, node) {
3357 table_entry_printf(f, ctl, table, entry);
3358 n_entries++;
3359 }
3360
3361 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3362 table_entry_printf(f, ctl, table, entry);
3363 n_entries++;
3364 }
3365
3366 TAILQ_FOREACH(entry, &table->pending_delete, node) {
3367 table_entry_printf(f, ctl, table, entry);
3368 n_entries++;
3369 }
3370
3371 fprintf(f, "# Table %s currently has %u entries.\n",
3372 table_name,
3373 n_entries);
3374 return 0;
3375 }
3376
3377 int
rte_swx_ctl_pipeline_selector_fprintf(FILE * f,struct rte_swx_ctl_pipeline * ctl,const char * selector_name)3378 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3379 struct rte_swx_ctl_pipeline *ctl,
3380 const char *selector_name)
3381 {
3382 struct selector *s;
3383 uint32_t group_id;
3384
3385 if (!f || !ctl || !selector_name || !selector_name[0])
3386 return -EINVAL;
3387
3388 s = selector_find(ctl, selector_name);
3389 if (!s)
3390 return -EINVAL;
3391
3392 /* Selector. */
3393 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3394 s->info.name,
3395 s->info.n_groups_max,
3396 s->info.n_members_per_group_max);
3397
3398 /* Groups. */
3399 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3400 struct rte_swx_table_selector_group *group = s->groups[group_id];
3401 struct rte_swx_table_selector_member *m;
3402 uint32_t n_members = 0;
3403
3404 fprintf(f, "Group %u = [", group_id);
3405
3406 /* Non-empty group. */
3407 if (group)
3408 TAILQ_FOREACH(m, &group->members, node) {
3409 fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3410 n_members++;
3411 }
3412
3413 /* Empty group. */
3414 if (!n_members)
3415 fprintf(f, "0:1 ");
3416
3417 fprintf(f, "]\n");
3418 }
3419
3420 return 0;
3421 }
3422