1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
10 #include <rte_common.h>
11 #include <rte_byteorder.h>
13 #include <rte_swx_table_selector.h>
15 #include "rte_swx_ctl.h"
17 #define CHECK(condition, err_code) \
23 #define ntoh64(x) rte_be_to_cpu_64(x)
24 #define hton64(x) rte_cpu_to_be_64(x)
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)))
30 #define field_ntoh(val, n_bits) (val)
31 #define field_hton(val, n_bits) (val)
35 struct rte_swx_ctl_action_info info;
36 struct rte_swx_ctl_action_arg_info *args;
41 struct rte_swx_ctl_table_info info;
42 struct rte_swx_ctl_table_match_field_info *mf;
44 /* Match field with the smallest offset. */
45 struct rte_swx_ctl_table_match_field_info *mf_first;
47 /* Match field with the biggest offset. */
48 struct rte_swx_ctl_table_match_field_info *mf_last;
50 struct rte_swx_ctl_table_action_info *actions;
51 struct rte_swx_table_ops ops;
52 struct rte_swx_table_params params;
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
58 struct rte_swx_table_entry_list entries;
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.
64 struct rte_swx_table_entry_list pending_add;
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.
73 struct rte_swx_table_entry_list pending_modify0;
74 struct rte_swx_table_entry_list pending_modify1;
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.
80 struct rte_swx_table_entry_list pending_delete;
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.
86 struct rte_swx_table_entry *pending_default;
95 /* Selector table info. */
96 struct rte_swx_ctl_selector_info info;
99 struct rte_swx_ctl_table_match_field_info group_id_field;
101 /* selector fields. */
102 struct rte_swx_ctl_table_match_field_info *selector_fields;
104 /* member_id field. */
105 struct rte_swx_ctl_table_match_field_info member_id_field;
107 /* Current selector table. Array of info.n_groups_max elements.*/
108 struct rte_swx_table_selector_group **groups;
110 /* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
112 struct rte_swx_table_selector_group **pending_groups;
114 /* Valid flag per group. Array of n_groups_max elements. */
117 /* Pending delete flag per group. Group deletion is subject to the next commit. Array of
118 * info.n_groups_max elements.
120 int *groups_pending_delete;
123 struct rte_swx_table_selector_params params;
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;
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.
136 struct rte_swx_table_entry *pending_default;
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;
151 static struct action *
152 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
156 for (i = 0; i < ctl->info.n_actions; i++) {
157 struct action *a = &ctl->actions[i];
159 if (!strcmp(action_name, a->info.name))
167 action_free(struct rte_swx_ctl_pipeline *ctl)
174 for (i = 0; i < ctl->info.n_actions; i++) {
175 struct action *action = &ctl->actions[i];
184 static struct table *
185 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
189 for (i = 0; i < ctl->info.n_tables; i++) {
190 struct table *table = &ctl->tables[i];
192 if (!strcmp(table_name, table->info.name))
200 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
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;
208 if (table->info.n_match_fields) {
209 uint32_t n_match_fields_em = 0, i;
211 /* Find first (smallest offset) and last (biggest offset) match fields. */
212 first = &table->mf[0];
213 last = &table->mf[0];
215 for (i = 1; i < table->info.n_match_fields; i++) {
216 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
218 if (f->offset < first->offset)
221 if (f->offset > last->offset)
226 for (i = 0; i < table->info.n_match_fields; i++) {
227 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
229 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
233 if (n_match_fields_em == table->info.n_match_fields)
234 match_type = RTE_SWX_TABLE_MATCH_EXACT;
237 key_offset = first->offset / 8;
240 key_size = (last->offset + last->n_bits - first->offset) / 8;
243 key_mask = calloc(1, key_size);
244 CHECK(key_mask, ENOMEM);
246 for (i = 0; i < table->info.n_match_fields; i++) {
247 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
251 start = (f->offset - first->offset) / 8;
252 size = f->n_bits / 8;
254 memset(&key_mask[start], 0xFF, size);
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];
263 if (a->data_size > action_data_size)
264 action_data_size = a->data_size;
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;
275 table->mf_first = first;
276 table->mf_last = last;
282 table_entry_free(struct rte_swx_table_entry *entry)
288 free(entry->key_mask);
289 free(entry->action_data);
293 static struct rte_swx_table_entry *
294 table_entry_alloc(struct table *table)
296 struct rte_swx_table_entry *entry;
298 entry = calloc(1, sizeof(struct rte_swx_table_entry));
303 if (!table->is_stub) {
304 entry->key = calloc(1, table->params.key_size);
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)
316 if (table->params.action_data_size) {
317 entry->action_data = calloc(1, table->params.action_data_size);
318 if (!entry->action_data)
325 table_entry_free(entry);
330 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
332 uint8_t *key_mask0 = table->params.key_mask0;
333 uint32_t key_size = table->params.key_size, i;
335 if (!entry->key_mask)
338 for (i = 0; i < key_size; i++) {
339 uint8_t km0 = key_mask0[i];
340 uint8_t km = entry->key_mask[i];
342 if ((km & km0) != km0)
350 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
352 struct rte_swx_table_entry *entry,
356 struct table *table = &ctl->tables[table_id];
359 CHECK(entry, EINVAL);
361 if (key_check && !table->is_stub) {
363 CHECK(entry->key, EINVAL);
366 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
367 status = table_entry_key_check_em(table, entry);
378 for (i = 0; i < table->info.n_actions; i++)
379 if (entry->action_id == table->actions[i].action_id)
382 CHECK(i < table->info.n_actions, EINVAL);
385 a = &ctl->actions[entry->action_id];
386 CHECK(!(a->data_size && !entry->action_data), EINVAL);
392 static struct rte_swx_table_entry *
393 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
395 struct rte_swx_table_entry *entry,
399 struct table *table = &ctl->tables[table_id];
400 struct rte_swx_table_entry *new_entry = NULL;
405 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
409 if (key_duplicate && !table->is_stub) {
414 new_entry->key = malloc(table->params.key_size);
418 memcpy(new_entry->key, entry->key, table->params.key_size);
421 new_entry->key_signature = entry->key_signature;
424 if (entry->key_mask) {
425 new_entry->key_mask = malloc(table->params.key_size);
426 if (!new_entry->key_mask)
429 memcpy(new_entry->key_mask,
431 table->params.key_size);
435 new_entry->key_priority = entry->key_priority;
438 if (data_duplicate) {
443 for (i = 0; i < table->info.n_actions; i++)
444 if (entry->action_id == table->actions[i].action_id)
447 if (i >= table->info.n_actions)
450 new_entry->action_id = entry->action_id;
453 a = &ctl->actions[entry->action_id];
454 if (a->data_size && !entry->action_data)
457 /* The table layer provisions a constant action data size per
458 * entry, which should be the largest data size for all the
459 * actions enabled for the current table, and attempts to copy
460 * this many bytes each time a table entry is added, even if the
461 * specific action requires less data or even no data at all,
462 * hence we always have to allocate the max.
464 new_entry->action_data = calloc(1, table->params.action_data_size);
465 if (!new_entry->action_data)
469 memcpy(new_entry->action_data,
477 table_entry_free(new_entry);
482 table_entry_keycmp(struct table *table,
483 struct rte_swx_table_entry *e0,
484 struct rte_swx_table_entry *e1)
486 uint32_t key_size = table->params.key_size;
489 for (i = 0; i < key_size; i++) {
490 uint8_t *key_mask0 = table->params.key_mask0;
491 uint8_t km0, km[2], k[2];
493 km0 = key_mask0 ? key_mask0[i] : 0xFF;
495 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
496 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
501 /* Mask comparison. */
502 if ((km[0] & km0) != (km[1] & km0))
503 return 1; /* Not equal. */
505 /* Value comparison. */
506 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
507 return 1; /* Not equal. */
510 return 0; /* Equal. */
513 static struct rte_swx_table_entry *
514 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
516 struct rte_swx_table_entry *e;
518 TAILQ_FOREACH(e, &table->entries, node)
519 if (!table_entry_keycmp(table, entry, e))
520 return e; /* Found. */
522 return NULL; /* Not found. */
526 table_entries_free(struct table *table)
529 struct rte_swx_table_entry *entry;
531 entry = TAILQ_FIRST(&table->entries);
535 TAILQ_REMOVE(&table->entries, entry, node);
536 table_entry_free(entry);
540 static struct rte_swx_table_entry *
541 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
543 struct rte_swx_table_entry *e;
545 TAILQ_FOREACH(e, &table->pending_add, node)
546 if (!table_entry_keycmp(table, entry, e))
547 return e; /* Found. */
549 return NULL; /* Not found. */
553 table_pending_add_admit(struct table *table)
555 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
559 table_pending_add_free(struct table *table)
562 struct rte_swx_table_entry *entry;
564 entry = TAILQ_FIRST(&table->pending_add);
568 TAILQ_REMOVE(&table->pending_add, entry, node);
569 table_entry_free(entry);
573 static struct rte_swx_table_entry *
574 table_pending_modify0_find(struct table *table,
575 struct rte_swx_table_entry *entry)
577 struct rte_swx_table_entry *e;
579 TAILQ_FOREACH(e, &table->pending_modify0, node)
580 if (!table_entry_keycmp(table, entry, e))
581 return e; /* Found. */
583 return NULL; /* Not found. */
587 table_pending_modify0_admit(struct table *table)
589 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
593 table_pending_modify0_free(struct table *table)
596 struct rte_swx_table_entry *entry;
598 entry = TAILQ_FIRST(&table->pending_modify0);
602 TAILQ_REMOVE(&table->pending_modify0, entry, node);
603 table_entry_free(entry);
607 static struct rte_swx_table_entry *
608 table_pending_modify1_find(struct table *table,
609 struct rte_swx_table_entry *entry)
611 struct rte_swx_table_entry *e;
613 TAILQ_FOREACH(e, &table->pending_modify1, node)
614 if (!table_entry_keycmp(table, entry, e))
615 return e; /* Found. */
617 return NULL; /* Not found. */
621 table_pending_modify1_admit(struct table *table)
623 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
627 table_pending_modify1_free(struct table *table)
630 struct rte_swx_table_entry *entry;
632 entry = TAILQ_FIRST(&table->pending_modify1);
636 TAILQ_REMOVE(&table->pending_modify1, entry, node);
637 table_entry_free(entry);
641 static struct rte_swx_table_entry *
642 table_pending_delete_find(struct table *table,
643 struct rte_swx_table_entry *entry)
645 struct rte_swx_table_entry *e;
647 TAILQ_FOREACH(e, &table->pending_delete, node)
648 if (!table_entry_keycmp(table, entry, e))
649 return e; /* Found. */
651 return NULL; /* Not found. */
655 table_pending_delete_admit(struct table *table)
657 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
661 table_pending_delete_free(struct table *table)
664 struct rte_swx_table_entry *entry;
666 entry = TAILQ_FIRST(&table->pending_delete);
670 TAILQ_REMOVE(&table->pending_delete, entry, node);
671 table_entry_free(entry);
676 table_pending_default_free(struct table *table)
678 if (!table->pending_default)
681 free(table->pending_default->action_data);
682 free(table->pending_default);
683 table->pending_default = NULL;
687 table_is_update_pending(struct table *table, int consider_pending_default)
689 struct rte_swx_table_entry *e;
693 TAILQ_FOREACH(e, &table->pending_add, node)
696 /* Pending modify. */
697 TAILQ_FOREACH(e, &table->pending_modify1, node)
700 /* Pending delete. */
701 TAILQ_FOREACH(e, &table->pending_delete, node)
704 /* Pending default. */
705 if (consider_pending_default && table->pending_default)
712 table_free(struct rte_swx_ctl_pipeline *ctl)
719 for (i = 0; i < ctl->info.n_tables; i++) {
720 struct table *table = &ctl->tables[i];
723 free(table->actions);
724 free(table->params.key_mask0);
726 table_entries_free(table);
727 table_pending_add_free(table);
728 table_pending_modify0_free(table);
729 table_pending_modify1_free(table);
730 table_pending_delete_free(table);
731 table_pending_default_free(table);
739 selector_group_members_free(struct selector *s, uint32_t group_id)
741 struct rte_swx_table_selector_group *group = s->groups[group_id];
747 struct rte_swx_table_selector_member *m;
749 m = TAILQ_FIRST(&group->members);
753 TAILQ_REMOVE(&group->members, m, node);
758 s->groups[group_id] = NULL;
762 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
764 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
770 struct rte_swx_table_selector_member *m;
772 m = TAILQ_FIRST(&group->members);
776 TAILQ_REMOVE(&group->members, m, node);
781 s->pending_groups[group_id] = NULL;
785 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
787 struct rte_swx_table_selector_group *g, *gp;
788 struct rte_swx_table_selector_member *m;
790 selector_pending_group_members_free(s, group_id);
792 g = s->groups[group_id];
793 gp = s->pending_groups[group_id];
796 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
800 TAILQ_INIT(&gp->members);
802 s->pending_groups[group_id] = gp;
808 TAILQ_FOREACH(m, &g->members, node) {
809 struct rte_swx_table_selector_member *mp;
811 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
815 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
817 TAILQ_INSERT_TAIL(&gp->members, mp, node);
823 selector_pending_group_members_free(s, group_id);
828 selector_free(struct rte_swx_ctl_pipeline *ctl)
835 for (i = 0; i < ctl->info.n_selectors; i++) {
836 struct selector *s = &ctl->selectors[i];
839 /* selector_fields. */
840 free(s->selector_fields);
844 for (i = 0; i < s->info.n_groups_max; i++)
845 selector_group_members_free(s, i);
849 /* pending_groups. */
850 if (s->pending_groups)
851 for (i = 0; i < s->info.n_groups_max; i++)
852 selector_pending_group_members_free(s, i);
854 free(s->pending_groups);
857 free(s->groups_added);
859 /* groups_pending_delete. */
860 free(s->groups_pending_delete);
863 free(s->params.selector_mask);
866 free(ctl->selectors);
867 ctl->selectors = NULL;
870 static struct selector *
871 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
875 for (i = 0; i < ctl->info.n_selectors; i++) {
876 struct selector *s = &ctl->selectors[i];
878 if (!strcmp(selector_name, s->info.name))
886 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
888 struct selector *s = &ctl->selectors[selector_id];
889 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
890 uint8_t *selector_mask = NULL;
891 uint32_t selector_size = 0, selector_offset = 0, i;
893 /* Find first (smallest offset) and last (biggest offset) match fields. */
894 first = &s->selector_fields[0];
895 last = &s->selector_fields[0];
897 for (i = 1; i < s->info.n_selector_fields; i++) {
898 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
900 if (f->offset < first->offset)
903 if (f->offset > last->offset)
907 /* selector_offset. */
908 selector_offset = first->offset / 8;
911 selector_size = (last->offset + last->n_bits - first->offset) / 8;
914 selector_mask = calloc(1, selector_size);
918 for (i = 0; i < s->info.n_selector_fields; i++) {
919 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
923 start = (f->offset - first->offset) / 8;
924 size = f->n_bits / 8;
926 memset(&selector_mask[start], 0xFF, size);
930 s->params.group_id_offset = s->group_id_field.offset / 8;
931 s->params.selector_size = selector_size;
932 s->params.selector_offset = selector_offset;
933 s->params.selector_mask = selector_mask;
934 s->params.member_id_offset = s->member_id_field.offset / 8;
935 s->params.n_groups_max = s->info.n_groups_max;
936 s->params.n_members_per_group_max = s->info.n_members_per_group_max;
942 learner_pending_default_free(struct learner *l)
944 if (!l->pending_default)
947 free(l->pending_default->action_data);
948 free(l->pending_default);
949 l->pending_default = NULL;
954 learner_free(struct rte_swx_ctl_pipeline *ctl)
961 for (i = 0; i < ctl->info.n_learners; i++) {
962 struct learner *l = &ctl->learners[i];
967 learner_pending_default_free(l);
971 ctl->learners = NULL;
974 static struct learner *
975 learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
979 for (i = 0; i < ctl->info.n_learners; i++) {
980 struct learner *l = &ctl->learners[i];
982 if (!strcmp(learner_name, l->info.name))
990 learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
992 uint32_t action_data_size = 0, i;
994 for (i = 0; i < l->info.n_actions; i++) {
995 uint32_t action_id = l->actions[i].action_id;
996 struct action *a = &ctl->actions[action_id];
998 if (a->data_size > action_data_size)
999 action_data_size = a->data_size;
1002 return action_data_size;
1006 table_state_free(struct rte_swx_ctl_pipeline *ctl)
1013 /* For each table, free its table state. */
1014 for (i = 0; i < ctl->info.n_tables; i++) {
1015 struct table *table = &ctl->tables[i];
1016 struct rte_swx_table_state *ts = &ctl->ts_next[i];
1018 /* Default action data. */
1019 free(ts->default_action_data);
1022 if (!table->is_stub && table->ops.free && ts->obj)
1023 table->ops.free(ts->obj);
1026 /* For each selector table, free its table state. */
1027 for (i = 0; i < ctl->info.n_selectors; i++) {
1028 struct rte_swx_table_state *ts = &ctl->ts_next[i];
1032 rte_swx_table_selector_free(ts->obj);
1035 /* For each learner table, free its table state. */
1036 for (i = 0; i < ctl->info.n_learners; i++) {
1037 struct rte_swx_table_state *ts = &ctl->ts_next[i];
1039 /* Default action data. */
1040 free(ts->default_action_data);
1044 ctl->ts_next = NULL;
1048 table_state_create(struct rte_swx_ctl_pipeline *ctl)
1053 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
1054 sizeof(struct rte_swx_table_state));
1055 if (!ctl->ts_next) {
1061 for (i = 0; i < ctl->info.n_tables; i++) {
1062 struct table *table = &ctl->tables[i];
1063 struct rte_swx_table_state *ts = &ctl->ts[i];
1064 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
1067 if (!table->is_stub && table->ops.add) {
1068 ts_next->obj = table->ops.create(&table->params,
1072 if (!ts_next->obj) {
1078 if (!table->is_stub && !table->ops.add)
1079 ts_next->obj = ts->obj;
1081 /* Default action data: duplicate from current table state. */
1082 ts_next->default_action_data =
1083 malloc(table->params.action_data_size);
1084 if (!ts_next->default_action_data) {
1089 memcpy(ts_next->default_action_data,
1090 ts->default_action_data,
1091 table->params.action_data_size);
1093 ts_next->default_action_id = ts->default_action_id;
1096 /* Selector tables. */
1097 for (i = 0; i < ctl->info.n_selectors; i++) {
1098 struct selector *s = &ctl->selectors[i];
1099 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
1102 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1103 if (!ts_next->obj) {
1109 /* Learner tables. */
1110 for (i = 0; i < ctl->info.n_learners; i++) {
1111 struct learner *l = &ctl->learners[i];
1112 struct rte_swx_table_state *ts = &ctl->ts[i];
1113 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
1115 /* Table object: duplicate from the current table state. */
1116 ts_next->obj = ts->obj;
1118 /* Default action data: duplicate from the current table state. */
1119 ts_next->default_action_data = malloc(l->action_data_size);
1120 if (!ts_next->default_action_data) {
1125 memcpy(ts_next->default_action_data,
1126 ts->default_action_data,
1127 l->action_data_size);
1129 ts_next->default_action_id = ts->default_action_id;
1135 table_state_free(ctl);
1140 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1147 table_state_free(ctl);
1158 struct rte_swx_ctl_pipeline *
1159 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1161 struct rte_swx_ctl_pipeline *ctl = NULL;
1168 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1173 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1178 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1186 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1190 for (i = 0; i < ctl->info.n_actions; i++) {
1191 struct action *a = &ctl->actions[i];
1195 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1200 a->args = calloc(a->info.n_args,
1201 sizeof(struct rte_swx_ctl_action_arg_info));
1205 for (j = 0; j < a->info.n_args; j++) {
1206 status = rte_swx_ctl_action_arg_info_get(p,
1215 for (j = 0; j < a->info.n_args; j++) {
1216 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1218 a->data_size += info->n_bits;
1221 a->data_size = (a->data_size + 7) / 8;
1225 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1229 for (i = 0; i < ctl->info.n_tables; i++) {
1230 struct table *t = &ctl->tables[i];
1232 TAILQ_INIT(&t->entries);
1233 TAILQ_INIT(&t->pending_add);
1234 TAILQ_INIT(&t->pending_modify0);
1235 TAILQ_INIT(&t->pending_modify1);
1236 TAILQ_INIT(&t->pending_delete);
1239 for (i = 0; i < ctl->info.n_tables; i++) {
1240 struct table *t = &ctl->tables[i];
1244 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1249 t->mf = calloc(t->info.n_match_fields,
1250 sizeof(struct rte_swx_ctl_table_match_field_info));
1254 for (j = 0; j < t->info.n_match_fields; j++) {
1255 status = rte_swx_ctl_table_match_field_info_get(p,
1264 t->actions = calloc(t->info.n_actions,
1265 sizeof(struct rte_swx_ctl_table_action_info));
1269 for (j = 0; j < t->info.n_actions; j++) {
1270 status = rte_swx_ctl_table_action_info_get(p,
1275 t->actions[j].action_id >= ctl->info.n_actions)
1280 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1284 if ((t->is_stub && t->info.n_match_fields) ||
1285 (!t->is_stub && !t->info.n_match_fields))
1289 status = table_params_get(ctl, i);
1294 /* selector tables. */
1295 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1296 if (!ctl->selectors)
1299 for (i = 0; i < ctl->info.n_selectors; i++) {
1300 struct selector *s = &ctl->selectors[i];
1304 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1308 /* group_id field. */
1309 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1311 &s->group_id_field);
1315 /* selector fields. */
1316 s->selector_fields = calloc(s->info.n_selector_fields,
1317 sizeof(struct rte_swx_ctl_table_match_field_info));
1318 if (!s->selector_fields)
1321 for (j = 0; j < s->info.n_selector_fields; j++) {
1322 status = rte_swx_ctl_selector_field_info_get(p,
1325 &s->selector_fields[j]);
1330 /* member_id field. */
1331 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1333 &s->member_id_field);
1338 s->groups = calloc(s->info.n_groups_max,
1339 sizeof(struct rte_swx_table_selector_group *));
1343 /* pending_groups. */
1344 s->pending_groups = calloc(s->info.n_groups_max,
1345 sizeof(struct rte_swx_table_selector_group *));
1346 if (!s->pending_groups)
1350 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1351 if (!s->groups_added)
1354 /* groups_pending_delete. */
1355 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1356 if (!s->groups_pending_delete)
1360 status = selector_params_get(ctl, i);
1365 /* learner tables. */
1366 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1370 for (i = 0; i < ctl->info.n_learners; i++) {
1371 struct learner *l = &ctl->learners[i];
1375 status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1380 l->mf = calloc(l->info.n_match_fields,
1381 sizeof(struct rte_swx_ctl_table_match_field_info));
1385 for (j = 0; j < l->info.n_match_fields; j++) {
1386 status = rte_swx_ctl_learner_match_field_info_get(p,
1395 l->actions = calloc(l->info.n_actions,
1396 sizeof(struct rte_swx_ctl_table_action_info));
1400 for (j = 0; j < l->info.n_actions; j++) {
1401 status = rte_swx_ctl_learner_action_info_get(p,
1405 if (status || l->actions[j].action_id >= ctl->info.n_actions)
1409 /* action_data_size. */
1410 l->action_data_size = learner_action_data_size_get(ctl, l);
1414 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1419 status = table_state_create(ctl);
1426 rte_swx_ctl_pipeline_free(ctl);
1431 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1432 const char *table_name,
1433 struct rte_swx_table_entry *entry)
1435 struct table *table;
1436 struct rte_swx_table_entry *new_entry, *existing_entry;
1440 CHECK(table_name && table_name[0], EINVAL);
1442 table = table_find(ctl, table_name);
1443 CHECK(table, EINVAL);
1444 table_id = table - ctl->tables;
1446 CHECK(entry, EINVAL);
1447 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1449 CHECK(table->actions[entry->action_id].action_is_for_table_entries, EINVAL);
1451 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1452 CHECK(new_entry, ENOMEM);
1454 /* The new entry is found in the table->entries list:
1455 * - Add the new entry to the table->pending_modify1 list;
1456 * - Move the existing entry from the table->entries list to the
1457 * table->pending_modify0 list.
1459 existing_entry = table_entries_find(table, entry);
1460 if (existing_entry) {
1461 TAILQ_INSERT_TAIL(&table->pending_modify1,
1465 TAILQ_REMOVE(&table->entries,
1469 TAILQ_INSERT_TAIL(&table->pending_modify0,
1476 /* The new entry is found in the table->pending_add list:
1477 * - Replace the entry in the table->pending_add list with the new entry
1478 * (and free the replaced entry).
1480 existing_entry = table_pending_add_find(table, entry);
1481 if (existing_entry) {
1482 TAILQ_INSERT_AFTER(&table->pending_add,
1487 TAILQ_REMOVE(&table->pending_add,
1491 table_entry_free(existing_entry);
1496 /* The new entry is found in the table->pending_modify1 list:
1497 * - Replace the entry in the table->pending_modify1 list with the new
1498 * entry (and free the replaced entry).
1500 existing_entry = table_pending_modify1_find(table, entry);
1501 if (existing_entry) {
1502 TAILQ_INSERT_AFTER(&table->pending_modify1,
1507 TAILQ_REMOVE(&table->pending_modify1,
1511 table_entry_free(existing_entry);
1516 /* The new entry is found in the table->pending_delete list:
1517 * - Add the new entry to the table->pending_modify1 list;
1518 * - Move the existing entry from the table->pending_delete list to the
1519 * table->pending_modify0 list.
1521 existing_entry = table_pending_delete_find(table, entry);
1522 if (existing_entry) {
1523 TAILQ_INSERT_TAIL(&table->pending_modify1,
1527 TAILQ_REMOVE(&table->pending_delete,
1531 TAILQ_INSERT_TAIL(&table->pending_modify0,
1538 /* The new entry is not found in any of the above lists:
1539 * - Add the new entry to the table->pending_add list.
1541 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1547 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1548 const char *table_name,
1549 struct rte_swx_table_entry *entry)
1551 struct table *table;
1552 struct rte_swx_table_entry *existing_entry;
1557 CHECK(table_name && table_name[0], EINVAL);
1558 table = table_find(ctl, table_name);
1559 CHECK(table, EINVAL);
1560 table_id = table - ctl->tables;
1562 CHECK(entry, EINVAL);
1563 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1565 /* The entry is found in the table->entries list:
1566 * - Move the existing entry from the table->entries list to to the
1567 * table->pending_delete list.
1569 existing_entry = table_entries_find(table, entry);
1570 if (existing_entry) {
1571 TAILQ_REMOVE(&table->entries,
1575 TAILQ_INSERT_TAIL(&table->pending_delete,
1582 /* The entry is found in the table->pending_add list:
1583 * - Remove the entry from the table->pending_add list and free it.
1585 existing_entry = table_pending_add_find(table, entry);
1586 if (existing_entry) {
1587 TAILQ_REMOVE(&table->pending_add,
1591 table_entry_free(existing_entry);
1594 /* The entry is found in the table->pending_modify1 list:
1595 * - Free the entry in the table->pending_modify1 list;
1596 * - Move the existing entry from the table->pending_modify0 list to the
1597 * table->pending_delete list.
1599 existing_entry = table_pending_modify1_find(table, entry);
1600 if (existing_entry) {
1601 struct rte_swx_table_entry *real_existing_entry;
1603 TAILQ_REMOVE(&table->pending_modify1,
1607 table_entry_free(existing_entry);
1609 real_existing_entry = table_pending_modify0_find(table, entry);
1610 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1612 TAILQ_REMOVE(&table->pending_modify0,
1613 real_existing_entry,
1616 TAILQ_INSERT_TAIL(&table->pending_delete,
1617 real_existing_entry,
1623 /* The entry is found in the table->pending_delete list:
1624 * - Do nothing: the existing entry is already in the
1625 * table->pending_delete list, i.e. already marked for delete, so
1626 * simply keep it there as it is.
1629 /* The entry is not found in any of the above lists:
1630 * - Do nothing: no existing entry to delete.
1637 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1638 const char *table_name,
1639 struct rte_swx_table_entry *entry)
1641 struct table *table;
1642 struct rte_swx_table_entry *new_entry;
1647 CHECK(table_name && table_name[0], EINVAL);
1648 table = table_find(ctl, table_name);
1649 CHECK(table, EINVAL);
1650 table_id = table - ctl->tables;
1651 CHECK(!table->info.default_action_is_const, EINVAL);
1653 CHECK(entry, EINVAL);
1654 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1656 CHECK(table->actions[entry->action_id].action_is_for_default_entry, EINVAL);
1658 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1659 CHECK(new_entry, ENOMEM);
1661 table_pending_default_free(table);
1663 table->pending_default = new_entry;
1669 table_entry_list_free(struct rte_swx_table_entry_list *list)
1672 struct rte_swx_table_entry *entry;
1674 entry = TAILQ_FIRST(list);
1678 TAILQ_REMOVE(list, entry, node);
1679 table_entry_free(entry);
1684 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1686 struct rte_swx_table_entry_list *dst,
1687 struct rte_swx_table_entry_list *src)
1689 struct rte_swx_table_entry *src_entry;
1691 TAILQ_FOREACH(src_entry, src, node) {
1692 struct rte_swx_table_entry *dst_entry;
1694 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1698 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1704 table_entry_list_free(dst);
1708 /* This commit stage contains all the operations that can fail; in case ANY of
1709 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1712 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1714 uint32_t after_swap)
1716 struct table *table = &ctl->tables[table_id];
1717 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1718 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1720 if (table->is_stub || !table_is_update_pending(table, 0))
1724 * Current table supports incremental update.
1726 if (table->ops.add) {
1727 /* Reset counters. */
1729 table->n_modify = 0;
1730 table->n_delete = 0;
1732 /* Add pending rules. */
1733 struct rte_swx_table_entry *entry;
1735 TAILQ_FOREACH(entry, &table->pending_add, node) {
1738 status = table->ops.add(ts_next->obj, entry);
1745 /* Modify pending rules. */
1746 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1749 status = table->ops.add(ts_next->obj, entry);
1756 /* Delete pending rules. */
1757 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1760 status = table->ops.del(ts_next->obj, entry);
1771 * Current table does NOT support incremental update.
1774 struct rte_swx_table_entry_list list;
1777 /* Create updated list of entries included. */
1780 status = table_entry_list_duplicate(ctl,
1787 status = table_entry_list_duplicate(ctl,
1790 &table->pending_add);
1794 status = table_entry_list_duplicate(ctl,
1797 &table->pending_modify1);
1801 /* Create new table object with the updates included. */
1802 ts_next->obj = table->ops.create(&table->params,
1806 if (!ts_next->obj) {
1811 table_entry_list_free(&list);
1816 table_entry_list_free(&list);
1820 /* Free the old table object. */
1821 if (ts_next->obj && table->ops.free)
1822 table->ops.free(ts_next->obj);
1824 /* Copy over the new table object. */
1825 ts_next->obj = ts->obj;
1830 /* This commit stage contains all the operations that cannot fail. They are
1831 * executed only if the previous stage was successful for ALL the tables. Hence,
1832 * none of these operations has to be rolled back for ANY table.
1835 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1837 struct table *table = &ctl->tables[table_id];
1838 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1840 uint8_t *action_data;
1843 /* Copy the pending default entry. */
1844 if (!table->pending_default)
1847 action_id = table->pending_default->action_id;
1848 action_data = table->pending_default->action_data;
1849 a = &ctl->actions[action_id];
1852 memcpy(ts_next->default_action_data, action_data, a->data_size);
1854 ts_next->default_action_id = action_id;
1857 /* This last commit stage is simply finalizing a successful commit operation.
1858 * This stage is only executed if all the previous stages were successful. This
1859 * stage cannot fail.
1862 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1864 struct table *table = &ctl->tables[table_id];
1866 /* Move all the pending add entries to the table, as they are now part
1869 table_pending_add_admit(table);
1871 /* Move all the pending modify1 entries to table, are they are now part
1872 * of the table. Free up all the pending modify0 entries, as they are no
1873 * longer part of the table.
1875 table_pending_modify1_admit(table);
1876 table_pending_modify0_free(table);
1878 /* Free up all the pending delete entries, as they are no longer part of
1881 table_pending_delete_free(table);
1883 /* Free up the pending default entry, as it is now part of the table. */
1884 table_pending_default_free(table);
1887 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1888 * commit operations that can fail did fail for ANY table. It reverts ALL the
1889 * tables to their state before the commit started, as if the commit never
1893 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1895 struct table *table = &ctl->tables[table_id];
1896 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1898 if (table->is_stub || !table_is_update_pending(table, 0))
1901 if (table->ops.add) {
1902 struct rte_swx_table_entry *entry;
1904 /* Add back all the entries that were just deleted. */
1905 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1906 if (!table->n_delete)
1909 table->ops.add(ts_next->obj, entry);
1913 /* Add back the old copy for all the entries that were just
1916 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1917 if (!table->n_modify)
1920 table->ops.add(ts_next->obj, entry);
1924 /* Delete all the entries that were just added. */
1925 TAILQ_FOREACH(entry, &table->pending_add, node) {
1929 table->ops.del(ts_next->obj, entry);
1933 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1935 /* Free the new table object, as update was cancelled. */
1936 if (ts_next->obj && table->ops.free)
1937 table->ops.free(ts_next->obj);
1939 /* Reinstate the old table object. */
1940 ts_next->obj = ts->obj;
1944 /* This stage is conditionally executed (as instructed by the user) after a
1945 * failed commit operation to remove ALL the pending work for ALL the tables.
1948 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1950 struct table *table = &ctl->tables[table_id];
1952 /* Free up all the pending add entries, as none of them is part of the
1955 table_pending_add_free(table);
1957 /* Free up all the pending modify1 entries, as none of them made it to
1958 * the table. Add back all the pending modify0 entries, as none of them
1959 * was deleted from the table.
1961 table_pending_modify1_free(table);
1962 table_pending_modify0_admit(table);
1964 /* Add back all the pending delete entries, as none of them was deleted
1967 table_pending_delete_admit(table);
1969 /* Free up the pending default entry, as it is no longer going to be
1970 * added to the table.
1972 table_pending_default_free(table);
1976 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1977 const char *selector_name,
1983 /* Check input arguments. */
1984 if (!ctl || !selector_name || !selector_name[0] || !group_id)
1987 s = selector_find(ctl, selector_name);
1991 /* Find an unused group. */
1992 for (i = 0; i < s->info.n_groups_max; i++)
1993 if (!s->groups_added[i]) {
1995 s->groups_added[i] = 1;
2003 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2004 const char *selector_name,
2008 struct rte_swx_table_selector_group *group;
2010 /* Check input arguments. */
2011 if (!ctl || !selector_name || !selector_name[0])
2014 s = selector_find(ctl, selector_name);
2016 (group_id >= s->info.n_groups_max) ||
2017 !s->groups_added[group_id])
2020 /* Check if this group is already scheduled for deletion. */
2021 if (s->groups_pending_delete[group_id])
2024 /* Initialize the pending group, if needed. */
2025 if (!s->pending_groups[group_id]) {
2028 status = selector_group_duplicate_to_pending(s, group_id);
2033 group = s->pending_groups[group_id];
2035 /* Schedule removal of all the members from the current group. */
2037 struct rte_swx_table_selector_member *m;
2039 m = TAILQ_FIRST(&group->members);
2043 TAILQ_REMOVE(&group->members, m, node);
2047 /* Schedule the group for deletion. */
2048 s->groups_pending_delete[group_id] = 1;
2054 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2055 const char *selector_name,
2058 uint32_t member_weight)
2061 struct rte_swx_table_selector_group *group;
2062 struct rte_swx_table_selector_member *m;
2065 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2070 /* Check input arguments. */
2071 if (!ctl || !selector_name || !selector_name[0])
2074 s = selector_find(ctl, selector_name);
2076 (group_id >= s->info.n_groups_max) ||
2077 !s->groups_added[group_id] ||
2078 s->groups_pending_delete[group_id])
2081 /* Initialize the pending group, if needed. */
2082 if (!s->pending_groups[group_id]) {
2085 status = selector_group_duplicate_to_pending(s, group_id);
2090 group = s->pending_groups[group_id];
2092 /* If this member is already in this group, then simply update its weight and return. */
2093 TAILQ_FOREACH(m, &group->members, node)
2094 if (m->member_id == member_id) {
2095 m->member_weight = member_weight;
2099 /* Add new member to this group. */
2100 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2104 m->member_id = member_id;
2105 m->member_weight = member_weight;
2107 TAILQ_INSERT_TAIL(&group->members, m, node);
2113 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2114 const char *selector_name,
2115 uint32_t group_id __rte_unused,
2116 uint32_t member_id __rte_unused)
2119 struct rte_swx_table_selector_group *group;
2120 struct rte_swx_table_selector_member *m;
2122 /* Check input arguments. */
2123 if (!ctl || !selector_name || !selector_name[0])
2126 s = selector_find(ctl, selector_name);
2128 (group_id >= s->info.n_groups_max) ||
2129 !s->groups_added[group_id] ||
2130 s->groups_pending_delete[group_id])
2133 /* Initialize the pending group, if needed. */
2134 if (!s->pending_groups[group_id]) {
2137 status = selector_group_duplicate_to_pending(s, group_id);
2142 group = s->pending_groups[group_id];
2144 /* Look for this member in the group and remove it, if found. */
2145 TAILQ_FOREACH(m, &group->members, node)
2146 if (m->member_id == member_id) {
2147 TAILQ_REMOVE(&group->members, m, node);
2156 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2158 struct selector *s = &ctl->selectors[selector_id];
2159 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2162 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2163 * mirror copy (ts_next->obj).
2165 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2166 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2169 /* Skip this group if no change needed. */
2173 /* Apply the pending changes for the current group. */
2174 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2183 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2185 struct selector *s = &ctl->selectors[selector_id];
2188 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2189 * records (s->groups[group_id).
2191 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2192 struct rte_swx_table_selector_group *g = s->groups[group_id];
2193 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2195 /* Skip this group if no change needed. */
2199 /* Transition the pending changes to stable. */
2200 s->groups[group_id] = gp;
2201 s->pending_groups[group_id] = NULL;
2203 /* Free the old group member list. */
2208 struct rte_swx_table_selector_member *m;
2210 m = TAILQ_FIRST(&g->members);
2214 TAILQ_REMOVE(&g->members, m, node);
2221 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2222 * s->groups_added[group_id].
2224 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2225 if (s->groups_pending_delete[group_id]) {
2226 s->groups_added[group_id] = 0;
2227 s->groups_pending_delete[group_id] = 0;
2232 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2234 struct selector *s = &ctl->selectors[selector_id];
2235 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2236 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2239 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2240 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2241 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2244 ts_next->obj = ts->obj;
2251 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2253 struct selector *s = &ctl->selectors[selector_id];
2256 /* Discard any pending group member changes (s->pending_groups[group_id]). */
2257 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2258 selector_pending_group_members_free(s, group_id);
2260 /* Discard any pending group deletions. */
2261 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2264 static struct rte_swx_table_entry *
2265 learner_default_entry_alloc(struct learner *l)
2267 struct rte_swx_table_entry *entry;
2269 entry = calloc(1, sizeof(struct rte_swx_table_entry));
2274 if (l->action_data_size) {
2275 entry->action_data = calloc(1, l->action_data_size);
2276 if (!entry->action_data)
2283 table_entry_free(entry);
2288 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2289 uint32_t learner_id,
2290 struct rte_swx_table_entry *entry)
2292 struct learner *l = &ctl->learners[learner_id];
2296 CHECK(entry, EINVAL);
2299 for (i = 0; i < l->info.n_actions; i++)
2300 if (entry->action_id == l->actions[i].action_id)
2303 CHECK(i < l->info.n_actions, EINVAL);
2306 a = &ctl->actions[entry->action_id];
2307 CHECK(!(a->data_size && !entry->action_data), EINVAL);
2312 static struct rte_swx_table_entry *
2313 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2314 uint32_t learner_id,
2315 struct rte_swx_table_entry *entry)
2317 struct learner *l = &ctl->learners[learner_id];
2318 struct rte_swx_table_entry *new_entry = NULL;
2325 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2330 for (i = 0; i < l->info.n_actions; i++)
2331 if (entry->action_id == l->actions[i].action_id)
2334 if (i >= l->info.n_actions)
2337 new_entry->action_id = entry->action_id;
2340 a = &ctl->actions[entry->action_id];
2341 if (a->data_size && !entry->action_data)
2344 /* The table layer provisions a constant action data size per
2345 * entry, which should be the largest data size for all the
2346 * actions enabled for the current table, and attempts to copy
2347 * this many bytes each time a table entry is added, even if the
2348 * specific action requires less data or even no data at all,
2349 * hence we always have to allocate the max.
2351 new_entry->action_data = calloc(1, l->action_data_size);
2352 if (!new_entry->action_data)
2356 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2361 table_entry_free(new_entry);
2366 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
2367 const char *learner_name,
2368 struct rte_swx_table_entry *entry)
2371 struct rte_swx_table_entry *new_entry;
2372 uint32_t learner_id;
2376 CHECK(learner_name && learner_name[0], EINVAL);
2377 l = learner_find(ctl, learner_name);
2379 learner_id = l - ctl->learners;
2380 CHECK(!l->info.default_action_is_const, EINVAL);
2382 CHECK(entry, EINVAL);
2383 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2385 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2387 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2388 CHECK(new_entry, ENOMEM);
2390 learner_pending_default_free(l);
2392 l->pending_default = new_entry;
2397 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2399 struct learner *l = &ctl->learners[learner_id];
2400 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
2401 ctl->info.n_selectors + learner_id];
2403 uint8_t *action_data;
2406 /* Copy the pending default entry. */
2407 if (!l->pending_default)
2410 action_id = l->pending_default->action_id;
2411 action_data = l->pending_default->action_data;
2412 a = &ctl->actions[action_id];
2415 memcpy(ts_next->default_action_data, action_data, a->data_size);
2417 ts_next->default_action_id = action_id;
2421 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2423 struct learner *l = &ctl->learners[learner_id];
2425 /* Free up the pending default entry, as it is now part of the table. */
2426 learner_pending_default_free(l);
2430 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2432 struct learner *l = &ctl->learners[learner_id];
2434 /* Free up the pending default entry, as it is no longer going to be added to the table. */
2435 learner_pending_default_free(l);
2439 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2441 struct rte_swx_table_state *ts;
2447 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2448 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2449 * We must be able to fully revert all the changes that can fail as if they never happened.
2451 for (i = 0; i < ctl->info.n_tables; i++) {
2452 status = table_rollfwd0(ctl, i, 0);
2457 for (i = 0; i < ctl->info.n_selectors; i++) {
2458 status = selector_rollfwd(ctl, i);
2463 /* Second, operate all the changes that cannot fail. Since nothing can fail from this point
2464 * onwards, the transaction is guaranteed to be successful.
2466 for (i = 0; i < ctl->info.n_tables; i++)
2467 table_rollfwd1(ctl, i);
2469 for (i = 0; i < ctl->info.n_learners; i++)
2470 learner_rollfwd(ctl, i);
2472 /* Swap the table state for the data plane. The current ts and ts_next
2473 * become the new ts_next and ts, respectively.
2475 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2478 ctl->ts = ctl->ts_next;
2481 /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2482 * the current ts_next in sync with the current ts. Since the changes that can fail did
2483 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2484 * current ts_next, hence no error checking is needed.
2486 for (i = 0; i < ctl->info.n_tables; i++) {
2487 table_rollfwd0(ctl, i, 1);
2488 table_rollfwd1(ctl, i);
2489 table_rollfwd2(ctl, i);
2492 for (i = 0; i < ctl->info.n_selectors; i++) {
2493 selector_rollfwd(ctl, i);
2494 selector_rollfwd_finalize(ctl, i);
2497 for (i = 0; i < ctl->info.n_learners; i++) {
2498 learner_rollfwd(ctl, i);
2499 learner_rollfwd_finalize(ctl, i);
2505 for (i = 0; i < ctl->info.n_tables; i++) {
2506 table_rollback(ctl, i);
2508 table_abort(ctl, i);
2511 for (i = 0; i < ctl->info.n_selectors; i++) {
2512 selector_rollback(ctl, i);
2514 selector_abort(ctl, i);
2518 for (i = 0; i < ctl->info.n_learners; i++)
2519 learner_abort(ctl, i);
2525 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2532 for (i = 0; i < ctl->info.n_tables; i++)
2533 table_abort(ctl, i);
2535 for (i = 0; i < ctl->info.n_selectors; i++)
2536 selector_abort(ctl, i);
2538 for (i = 0; i < ctl->info.n_learners; i++)
2539 learner_abort(ctl, i);
2543 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2545 uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2552 /* Count trailing zero bits. */
2553 for (i = 0; i < 64; i++) {
2554 if (mask & (1LLU << i))
2560 /* Count the one bits that follow. */
2561 for ( ; i < 64; i++) {
2562 if (!(mask & (1LLU << i)))
2568 /* Check that no more one bits are present */
2569 for ( ; i < 64; i++)
2570 if (mask & (1LLU << i))
2573 /* Check that the input mask is a prefix or the right length. */
2574 if (n_ones + n_trailing_zeros != mask_length)
2577 *prefix_length = n_ones;
2582 token_is_comment(const char *token)
2584 if ((token[0] == '#') ||
2585 (token[0] == ';') ||
2586 ((token[0] == '/') && (token[1] == '/')))
2587 return 1; /* TRUE. */
2589 return 0; /* FALSE. */
2592 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2594 struct rte_swx_table_entry *
2595 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2596 const char *table_name,
2598 int *is_blank_or_comment)
2600 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2601 struct table *table;
2602 struct action *action;
2603 struct rte_swx_table_entry *entry = NULL;
2604 char *s0 = NULL, *s;
2605 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2606 int lpm = 0, blank_or_comment = 0;
2608 /* Check input arguments. */
2612 if (!table_name || !table_name[0])
2615 table = table_find(ctl, table_name);
2619 if (!string || !string[0])
2622 /* Memory allocation. */
2623 s0 = strdup(string);
2627 entry = table_entry_alloc(table);
2631 /* Parse the string into tokens. */
2635 token = strtok_r(s, " \f\n\r\t\v", &s);
2636 if (!token || token_is_comment(token))
2639 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2642 token_array[n_tokens] = token;
2647 blank_or_comment = 1;
2651 tokens = token_array;
2656 if (!(n_tokens && !strcmp(tokens[0], "match")))
2659 if (n_tokens < 1 + table->info.n_match_fields)
2662 for (i = 0; i < table->info.n_match_fields; i++) {
2663 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2664 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2665 uint64_t val, mask = UINT64_MAX;
2666 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2671 mf_mask = strchr(mf_val, '/');
2677 mask = strtoull(mf_mask, &mf_mask, 0);
2682 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2687 lpm_prefix_length_max = mf->n_bits;
2689 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2694 /* Endianness conversion. */
2696 mask = field_hton(mask, mf->n_bits);
2699 /* Copy to entry. */
2700 if (entry->key_mask)
2701 memcpy(&entry->key_mask[offset],
2709 val = strtoull(mf_val, &mf_val, 0);
2713 /* Endianness conversion. */
2715 val = field_hton(val, mf->n_bits);
2717 /* Copy to entry. */
2718 memcpy(&entry->key[offset],
2723 tokens += 1 + table->info.n_match_fields;
2724 n_tokens -= 1 + table->info.n_match_fields;
2729 if (n_tokens && !strcmp(tokens[0], "priority")) {
2730 char *priority = tokens[1];
2737 val = strtoul(priority, &priority, 0);
2741 /* Copy to entry. */
2742 entry->key_priority = val;
2750 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2756 if (!(n_tokens && !strcmp(tokens[0], "action")))
2762 action = action_find(ctl, tokens[1]);
2766 if (n_tokens < 2 + action->info.n_args * 2)
2770 entry->action_id = action - ctl->actions;
2773 for (i = 0; i < action->info.n_args; i++) {
2774 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2775 char *arg_name, *arg_val;
2778 arg_name = tokens[2 + i * 2];
2779 arg_val = tokens[2 + i * 2 + 1];
2781 if (strcmp(arg_name, arg->name))
2784 val = strtoull(arg_val, &arg_val, 0);
2788 /* Endianness conversion. */
2789 if (arg->is_network_byte_order)
2790 val = field_hton(val, arg->n_bits);
2792 /* Copy to entry. */
2793 memcpy(&entry->action_data[arg_offset],
2797 arg_offset += arg->n_bits / 8;
2800 tokens += 2 + action->info.n_args * 2;
2801 n_tokens -= 2 + action->info.n_args * 2;
2811 table_entry_free(entry);
2813 if (is_blank_or_comment)
2814 *is_blank_or_comment = blank_or_comment;
2818 struct rte_swx_table_entry *
2819 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2820 const char *learner_name,
2822 int *is_blank_or_comment)
2824 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2826 struct action *action;
2827 struct rte_swx_table_entry *entry = NULL;
2828 char *s0 = NULL, *s;
2829 uint32_t n_tokens = 0, arg_offset = 0, i;
2830 int blank_or_comment = 0;
2832 /* Check input arguments. */
2836 if (!learner_name || !learner_name[0])
2839 l = learner_find(ctl, learner_name);
2843 if (!string || !string[0])
2846 /* Memory allocation. */
2847 s0 = strdup(string);
2851 entry = learner_default_entry_alloc(l);
2855 /* Parse the string into tokens. */
2859 token = strtok_r(s, " \f\n\r\t\v", &s);
2860 if (!token || token_is_comment(token))
2863 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2866 token_array[n_tokens] = token;
2871 blank_or_comment = 1;
2875 tokens = token_array;
2880 if (!(n_tokens && !strcmp(tokens[0], "action")))
2886 action = action_find(ctl, tokens[1]);
2890 if (n_tokens < 2 + action->info.n_args * 2)
2894 entry->action_id = action - ctl->actions;
2897 for (i = 0; i < action->info.n_args; i++) {
2898 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2899 char *arg_name, *arg_val;
2902 arg_name = tokens[2 + i * 2];
2903 arg_val = tokens[2 + i * 2 + 1];
2905 if (strcmp(arg_name, arg->name))
2908 val = strtoull(arg_val, &arg_val, 0);
2912 /* Endianness conversion. */
2913 if (arg->is_network_byte_order)
2914 val = field_hton(val, arg->n_bits);
2916 /* Copy to entry. */
2917 memcpy(&entry->action_data[arg_offset],
2921 arg_offset += arg->n_bits / 8;
2924 tokens += 2 + action->info.n_args * 2;
2925 n_tokens -= 2 + action->info.n_args * 2;
2935 table_entry_free(entry);
2937 if (is_blank_or_comment)
2938 *is_blank_or_comment = blank_or_comment;
2943 table_entry_printf(FILE *f,
2944 struct rte_swx_ctl_pipeline *ctl,
2945 struct table *table,
2946 struct rte_swx_table_entry *entry)
2948 struct action *action = &ctl->actions[entry->action_id];
2951 fprintf(f, "match ");
2952 for (i = 0; i < table->params.key_size; i++)
2953 fprintf(f, "%02x", entry->key[i]);
2955 if (entry->key_mask) {
2957 for (i = 0; i < table->params.key_size; i++)
2958 fprintf(f, "%02x", entry->key_mask[i]);
2961 fprintf(f, " priority %u", entry->key_priority);
2963 fprintf(f, " action %s ", action->info.name);
2964 for (i = 0; i < action->data_size; i++)
2965 fprintf(f, "%02x", entry->action_data[i]);
2971 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2972 struct rte_swx_ctl_pipeline *ctl,
2973 const char *table_name)
2975 struct table *table;
2976 struct rte_swx_table_entry *entry;
2977 uint32_t n_entries = 0, i;
2979 if (!f || !ctl || !table_name || !table_name[0])
2982 table = table_find(ctl, table_name);
2987 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2989 table->params.key_size,
2990 table->params.key_offset);
2992 for (i = 0; i < table->params.key_size; i++)
2993 fprintf(f, "%02x", table->params.key_mask0[i]);
2995 fprintf(f, "], action data size %u bytes\n",
2996 table->params.action_data_size);
2998 /* Table entries. */
2999 TAILQ_FOREACH(entry, &table->entries, node) {
3000 table_entry_printf(f, ctl, table, entry);
3004 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3005 table_entry_printf(f, ctl, table, entry);
3009 TAILQ_FOREACH(entry, &table->pending_delete, node) {
3010 table_entry_printf(f, ctl, table, entry);
3014 fprintf(f, "# Table %s currently has %u entries.\n",
3021 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3022 struct rte_swx_ctl_pipeline *ctl,
3023 const char *selector_name)
3028 if (!f || !ctl || !selector_name || !selector_name[0])
3031 s = selector_find(ctl, selector_name);
3036 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3038 s->info.n_groups_max,
3039 s->info.n_members_per_group_max);
3042 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3043 struct rte_swx_table_selector_group *group = s->groups[group_id];
3044 struct rte_swx_table_selector_member *m;
3045 uint32_t n_members = 0;
3047 fprintf(f, "Group %u = [", group_id);
3049 /* Non-empty group. */
3051 TAILQ_FOREACH(m, &group->members, node) {
3052 fprintf(f, "%u:%u ", m->member_id, m->member_weight);