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