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);
375 struct rte_swx_ctl_table_action_info *tai;
379 for (i = 0; i < table->info.n_actions; i++) {
380 tai = &table->actions[i];
382 if (entry->action_id == tai->action_id)
386 CHECK(i < table->info.n_actions, EINVAL);
389 a = &ctl->actions[entry->action_id];
390 CHECK(!(a->data_size && !entry->action_data), EINVAL);
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.
395 if (key_check && !tai->action_is_for_table_entries)
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.
401 if (!key_check && !tai->action_is_for_default_entry)
408 static struct rte_swx_table_entry *
409 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
411 struct rte_swx_table_entry *entry,
415 struct table *table = &ctl->tables[table_id];
416 struct rte_swx_table_entry *new_entry = NULL;
421 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
425 if (key_duplicate && !table->is_stub) {
430 new_entry->key = malloc(table->params.key_size);
434 memcpy(new_entry->key, entry->key, table->params.key_size);
437 new_entry->key_signature = entry->key_signature;
440 if (entry->key_mask) {
441 new_entry->key_mask = malloc(table->params.key_size);
442 if (!new_entry->key_mask)
445 memcpy(new_entry->key_mask,
447 table->params.key_size);
451 new_entry->key_priority = entry->key_priority;
454 if (data_duplicate) {
459 for (i = 0; i < table->info.n_actions; i++)
460 if (entry->action_id == table->actions[i].action_id)
463 if (i >= table->info.n_actions)
466 new_entry->action_id = entry->action_id;
469 a = &ctl->actions[entry->action_id];
470 if (a->data_size && !entry->action_data)
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.
480 new_entry->action_data = calloc(1, table->params.action_data_size);
481 if (!new_entry->action_data)
485 memcpy(new_entry->action_data,
493 table_entry_free(new_entry);
498 table_entry_keycmp(struct table *table,
499 struct rte_swx_table_entry *e0,
500 struct rte_swx_table_entry *e1)
502 uint32_t key_size = table->params.key_size;
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];
509 km0 = key_mask0 ? key_mask0[i] : 0xFF;
511 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
512 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
517 /* Mask comparison. */
518 if ((km[0] & km0) != (km[1] & km0))
519 return 1; /* Not equal. */
521 /* Value comparison. */
522 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
523 return 1; /* Not equal. */
526 return 0; /* Equal. */
529 static struct rte_swx_table_entry *
530 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
532 struct rte_swx_table_entry *e;
534 TAILQ_FOREACH(e, &table->entries, node)
535 if (!table_entry_keycmp(table, entry, e))
536 return e; /* Found. */
538 return NULL; /* Not found. */
542 table_entries_free(struct table *table)
545 struct rte_swx_table_entry *entry;
547 entry = TAILQ_FIRST(&table->entries);
551 TAILQ_REMOVE(&table->entries, entry, node);
552 table_entry_free(entry);
556 static struct rte_swx_table_entry *
557 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
559 struct rte_swx_table_entry *e;
561 TAILQ_FOREACH(e, &table->pending_add, node)
562 if (!table_entry_keycmp(table, entry, e))
563 return e; /* Found. */
565 return NULL; /* Not found. */
569 table_pending_add_admit(struct table *table)
571 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
575 table_pending_add_free(struct table *table)
578 struct rte_swx_table_entry *entry;
580 entry = TAILQ_FIRST(&table->pending_add);
584 TAILQ_REMOVE(&table->pending_add, entry, node);
585 table_entry_free(entry);
589 static struct rte_swx_table_entry *
590 table_pending_modify0_find(struct table *table,
591 struct rte_swx_table_entry *entry)
593 struct rte_swx_table_entry *e;
595 TAILQ_FOREACH(e, &table->pending_modify0, node)
596 if (!table_entry_keycmp(table, entry, e))
597 return e; /* Found. */
599 return NULL; /* Not found. */
603 table_pending_modify0_admit(struct table *table)
605 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
609 table_pending_modify0_free(struct table *table)
612 struct rte_swx_table_entry *entry;
614 entry = TAILQ_FIRST(&table->pending_modify0);
618 TAILQ_REMOVE(&table->pending_modify0, entry, node);
619 table_entry_free(entry);
623 static struct rte_swx_table_entry *
624 table_pending_modify1_find(struct table *table,
625 struct rte_swx_table_entry *entry)
627 struct rte_swx_table_entry *e;
629 TAILQ_FOREACH(e, &table->pending_modify1, node)
630 if (!table_entry_keycmp(table, entry, e))
631 return e; /* Found. */
633 return NULL; /* Not found. */
637 table_pending_modify1_admit(struct table *table)
639 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
643 table_pending_modify1_free(struct table *table)
646 struct rte_swx_table_entry *entry;
648 entry = TAILQ_FIRST(&table->pending_modify1);
652 TAILQ_REMOVE(&table->pending_modify1, entry, node);
653 table_entry_free(entry);
657 static struct rte_swx_table_entry *
658 table_pending_delete_find(struct table *table,
659 struct rte_swx_table_entry *entry)
661 struct rte_swx_table_entry *e;
663 TAILQ_FOREACH(e, &table->pending_delete, node)
664 if (!table_entry_keycmp(table, entry, e))
665 return e; /* Found. */
667 return NULL; /* Not found. */
671 table_pending_delete_admit(struct table *table)
673 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
677 table_pending_delete_free(struct table *table)
680 struct rte_swx_table_entry *entry;
682 entry = TAILQ_FIRST(&table->pending_delete);
686 TAILQ_REMOVE(&table->pending_delete, entry, node);
687 table_entry_free(entry);
692 table_pending_default_free(struct table *table)
694 if (!table->pending_default)
697 free(table->pending_default->action_data);
698 free(table->pending_default);
699 table->pending_default = NULL;
703 table_is_update_pending(struct table *table, int consider_pending_default)
705 struct rte_swx_table_entry *e;
709 TAILQ_FOREACH(e, &table->pending_add, node)
712 /* Pending modify. */
713 TAILQ_FOREACH(e, &table->pending_modify1, node)
716 /* Pending delete. */
717 TAILQ_FOREACH(e, &table->pending_delete, node)
720 /* Pending default. */
721 if (consider_pending_default && table->pending_default)
728 table_free(struct rte_swx_ctl_pipeline *ctl)
735 for (i = 0; i < ctl->info.n_tables; i++) {
736 struct table *table = &ctl->tables[i];
739 free(table->actions);
740 free(table->params.key_mask0);
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);
755 selector_group_members_free(struct selector *s, uint32_t group_id)
757 struct rte_swx_table_selector_group *group = s->groups[group_id];
763 struct rte_swx_table_selector_member *m;
765 m = TAILQ_FIRST(&group->members);
769 TAILQ_REMOVE(&group->members, m, node);
774 s->groups[group_id] = NULL;
778 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
780 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
786 struct rte_swx_table_selector_member *m;
788 m = TAILQ_FIRST(&group->members);
792 TAILQ_REMOVE(&group->members, m, node);
797 s->pending_groups[group_id] = NULL;
801 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
803 struct rte_swx_table_selector_group *g, *gp;
804 struct rte_swx_table_selector_member *m;
806 selector_pending_group_members_free(s, group_id);
808 g = s->groups[group_id];
809 gp = s->pending_groups[group_id];
812 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
816 TAILQ_INIT(&gp->members);
818 s->pending_groups[group_id] = gp;
824 TAILQ_FOREACH(m, &g->members, node) {
825 struct rte_swx_table_selector_member *mp;
827 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
831 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
833 TAILQ_INSERT_TAIL(&gp->members, mp, node);
839 selector_pending_group_members_free(s, group_id);
844 selector_free(struct rte_swx_ctl_pipeline *ctl)
851 for (i = 0; i < ctl->info.n_selectors; i++) {
852 struct selector *s = &ctl->selectors[i];
855 /* selector_fields. */
856 free(s->selector_fields);
860 for (i = 0; i < s->info.n_groups_max; i++)
861 selector_group_members_free(s, i);
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);
870 free(s->pending_groups);
873 free(s->groups_added);
875 /* groups_pending_delete. */
876 free(s->groups_pending_delete);
879 free(s->params.selector_mask);
882 free(ctl->selectors);
883 ctl->selectors = NULL;
886 static struct selector *
887 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
891 for (i = 0; i < ctl->info.n_selectors; i++) {
892 struct selector *s = &ctl->selectors[i];
894 if (!strcmp(selector_name, s->info.name))
902 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
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;
909 /* Find first (smallest offset) and last (biggest offset) match fields. */
910 first = &s->selector_fields[0];
911 last = &s->selector_fields[0];
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];
916 if (f->offset < first->offset)
919 if (f->offset > last->offset)
923 /* selector_offset. */
924 selector_offset = first->offset / 8;
927 selector_size = (last->offset + last->n_bits - first->offset) / 8;
930 selector_mask = calloc(1, selector_size);
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];
939 start = (f->offset - first->offset) / 8;
940 size = f->n_bits / 8;
942 memset(&selector_mask[start], 0xFF, size);
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;
958 learner_pending_default_free(struct learner *l)
960 if (!l->pending_default)
963 free(l->pending_default->action_data);
964 free(l->pending_default);
965 l->pending_default = NULL;
970 learner_free(struct rte_swx_ctl_pipeline *ctl)
977 for (i = 0; i < ctl->info.n_learners; i++) {
978 struct learner *l = &ctl->learners[i];
983 learner_pending_default_free(l);
987 ctl->learners = NULL;
990 static struct learner *
991 learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
995 for (i = 0; i < ctl->info.n_learners; i++) {
996 struct learner *l = &ctl->learners[i];
998 if (!strcmp(learner_name, l->info.name))
1006 learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
1008 uint32_t action_data_size = 0, i;
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];
1014 if (a->data_size > action_data_size)
1015 action_data_size = a->data_size;
1018 return action_data_size;
1022 table_state_free(struct rte_swx_ctl_pipeline *ctl)
1024 uint32_t table_base_index, selector_base_index, learner_base_index, i;
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];
1035 /* Default action data. */
1036 free(ts->default_action_data);
1039 if (!table->is_stub && table->ops.free && ts->obj)
1040 table->ops.free(ts->obj);
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];
1050 rte_swx_table_selector_free(ts->obj);
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];
1058 /* Default action data. */
1059 free(ts->default_action_data);
1063 ctl->ts_next = NULL;
1067 table_state_create(struct rte_swx_ctl_pipeline *ctl)
1069 uint32_t table_base_index, selector_base_index, learner_base_index, i;
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) {
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];
1087 if (!table->is_stub && table->ops.add) {
1088 ts_next->obj = table->ops.create(&table->params,
1092 if (!ts_next->obj) {
1098 if (!table->is_stub && !table->ops.add)
1099 ts_next->obj = ts->obj;
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) {
1109 memcpy(ts_next->default_action_data,
1110 ts->default_action_data,
1111 table->params.action_data_size);
1113 ts_next->default_action_id = ts->default_action_id;
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];
1123 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1124 if (!ts_next->obj) {
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];
1137 /* Table object: duplicate from the current table state. */
1138 ts_next->obj = ts->obj;
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) {
1147 memcpy(ts_next->default_action_data,
1148 ts->default_action_data,
1149 l->action_data_size);
1151 ts_next->default_action_id = ts->default_action_id;
1157 table_state_free(ctl);
1162 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1169 table_state_free(ctl);
1180 struct rte_swx_ctl_pipeline *
1181 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1183 struct rte_swx_ctl_pipeline *ctl = NULL;
1190 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1195 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1200 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1208 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1212 for (i = 0; i < ctl->info.n_actions; i++) {
1213 struct action *a = &ctl->actions[i];
1217 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1222 a->args = calloc(a->info.n_args,
1223 sizeof(struct rte_swx_ctl_action_arg_info));
1227 for (j = 0; j < a->info.n_args; j++) {
1228 status = rte_swx_ctl_action_arg_info_get(p,
1237 for (j = 0; j < a->info.n_args; j++) {
1238 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1240 a->data_size += info->n_bits;
1243 a->data_size = (a->data_size + 7) / 8;
1247 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1251 for (i = 0; i < ctl->info.n_tables; i++) {
1252 struct table *t = &ctl->tables[i];
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);
1261 for (i = 0; i < ctl->info.n_tables; i++) {
1262 struct table *t = &ctl->tables[i];
1266 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1271 t->mf = calloc(t->info.n_match_fields,
1272 sizeof(struct rte_swx_ctl_table_match_field_info));
1276 for (j = 0; j < t->info.n_match_fields; j++) {
1277 status = rte_swx_ctl_table_match_field_info_get(p,
1286 t->actions = calloc(t->info.n_actions,
1287 sizeof(struct rte_swx_ctl_table_action_info));
1291 for (j = 0; j < t->info.n_actions; j++) {
1292 status = rte_swx_ctl_table_action_info_get(p,
1297 t->actions[j].action_id >= ctl->info.n_actions)
1302 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1306 if ((t->is_stub && t->info.n_match_fields) ||
1307 (!t->is_stub && !t->info.n_match_fields))
1311 status = table_params_get(ctl, i);
1316 /* selector tables. */
1317 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1318 if (!ctl->selectors)
1321 for (i = 0; i < ctl->info.n_selectors; i++) {
1322 struct selector *s = &ctl->selectors[i];
1326 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1330 /* group_id field. */
1331 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1333 &s->group_id_field);
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)
1343 for (j = 0; j < s->info.n_selector_fields; j++) {
1344 status = rte_swx_ctl_selector_field_info_get(p,
1347 &s->selector_fields[j]);
1352 /* member_id field. */
1353 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1355 &s->member_id_field);
1360 s->groups = calloc(s->info.n_groups_max,
1361 sizeof(struct rte_swx_table_selector_group *));
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)
1372 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1373 if (!s->groups_added)
1376 /* groups_pending_delete. */
1377 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1378 if (!s->groups_pending_delete)
1382 status = selector_params_get(ctl, i);
1387 /* learner tables. */
1388 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
1392 for (i = 0; i < ctl->info.n_learners; i++) {
1393 struct learner *l = &ctl->learners[i];
1397 status = rte_swx_ctl_learner_info_get(p, i, &l->info);
1402 l->mf = calloc(l->info.n_match_fields,
1403 sizeof(struct rte_swx_ctl_table_match_field_info));
1407 for (j = 0; j < l->info.n_match_fields; j++) {
1408 status = rte_swx_ctl_learner_match_field_info_get(p,
1417 l->actions = calloc(l->info.n_actions,
1418 sizeof(struct rte_swx_ctl_table_action_info));
1422 for (j = 0; j < l->info.n_actions; j++) {
1423 status = rte_swx_ctl_learner_action_info_get(p,
1427 if (status || l->actions[j].action_id >= ctl->info.n_actions)
1431 /* action_data_size. */
1432 l->action_data_size = learner_action_data_size_get(ctl, l);
1436 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1441 status = table_state_create(ctl);
1448 rte_swx_ctl_pipeline_free(ctl);
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)
1457 struct table *table;
1458 struct rte_swx_table_entry *new_entry, *existing_entry;
1462 CHECK(table_name && table_name[0], EINVAL);
1464 table = table_find(ctl, table_name);
1465 CHECK(table, EINVAL);
1466 table_id = table - ctl->tables;
1468 CHECK(entry, EINVAL);
1469 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1471 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1472 CHECK(new_entry, ENOMEM);
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.
1479 existing_entry = table_entries_find(table, entry);
1480 if (existing_entry) {
1481 TAILQ_INSERT_TAIL(&table->pending_modify1,
1485 TAILQ_REMOVE(&table->entries,
1489 TAILQ_INSERT_TAIL(&table->pending_modify0,
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).
1500 existing_entry = table_pending_add_find(table, entry);
1501 if (existing_entry) {
1502 TAILQ_INSERT_AFTER(&table->pending_add,
1507 TAILQ_REMOVE(&table->pending_add,
1511 table_entry_free(existing_entry);
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).
1520 existing_entry = table_pending_modify1_find(table, entry);
1521 if (existing_entry) {
1522 TAILQ_INSERT_AFTER(&table->pending_modify1,
1527 TAILQ_REMOVE(&table->pending_modify1,
1531 table_entry_free(existing_entry);
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.
1541 existing_entry = table_pending_delete_find(table, entry);
1542 if (existing_entry) {
1543 TAILQ_INSERT_TAIL(&table->pending_modify1,
1547 TAILQ_REMOVE(&table->pending_delete,
1551 TAILQ_INSERT_TAIL(&table->pending_modify0,
1558 /* The new entry is not found in any of the above lists:
1559 * - Add the new entry to the table->pending_add list.
1561 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
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)
1571 struct table *table;
1572 struct rte_swx_table_entry *existing_entry;
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;
1582 CHECK(entry, EINVAL);
1583 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
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.
1589 existing_entry = table_entries_find(table, entry);
1590 if (existing_entry) {
1591 TAILQ_REMOVE(&table->entries,
1595 TAILQ_INSERT_TAIL(&table->pending_delete,
1602 /* The entry is found in the table->pending_add list:
1603 * - Remove the entry from the table->pending_add list and free it.
1605 existing_entry = table_pending_add_find(table, entry);
1606 if (existing_entry) {
1607 TAILQ_REMOVE(&table->pending_add,
1611 table_entry_free(existing_entry);
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.
1619 existing_entry = table_pending_modify1_find(table, entry);
1620 if (existing_entry) {
1621 struct rte_swx_table_entry *real_existing_entry;
1623 TAILQ_REMOVE(&table->pending_modify1,
1627 table_entry_free(existing_entry);
1629 real_existing_entry = table_pending_modify0_find(table, entry);
1630 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1632 TAILQ_REMOVE(&table->pending_modify0,
1633 real_existing_entry,
1636 TAILQ_INSERT_TAIL(&table->pending_delete,
1637 real_existing_entry,
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.
1649 /* The entry is not found in any of the above lists:
1650 * - Do nothing: no existing entry to delete.
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)
1661 struct table *table;
1662 struct rte_swx_table_entry *new_entry;
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);
1673 CHECK(entry, EINVAL);
1674 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1676 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1677 CHECK(new_entry, ENOMEM);
1679 table_pending_default_free(table);
1681 table->pending_default = new_entry;
1687 table_entry_list_free(struct rte_swx_table_entry_list *list)
1690 struct rte_swx_table_entry *entry;
1692 entry = TAILQ_FIRST(list);
1696 TAILQ_REMOVE(list, entry, node);
1697 table_entry_free(entry);
1702 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1704 struct rte_swx_table_entry_list *dst,
1705 struct rte_swx_table_entry_list *src)
1707 struct rte_swx_table_entry *src_entry;
1709 TAILQ_FOREACH(src_entry, src, node) {
1710 struct rte_swx_table_entry *dst_entry;
1712 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1716 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1722 table_entry_list_free(dst);
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.
1730 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1732 uint32_t after_swap)
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];
1738 if (table->is_stub || !table_is_update_pending(table, 0))
1742 * Current table supports incremental update.
1744 if (table->ops.add) {
1745 /* Reset counters. */
1747 table->n_modify = 0;
1748 table->n_delete = 0;
1750 /* Add pending rules. */
1751 struct rte_swx_table_entry *entry;
1753 TAILQ_FOREACH(entry, &table->pending_add, node) {
1756 status = table->ops.add(ts_next->obj, entry);
1763 /* Modify pending rules. */
1764 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1767 status = table->ops.add(ts_next->obj, entry);
1774 /* Delete pending rules. */
1775 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1778 status = table->ops.del(ts_next->obj, entry);
1789 * Current table does NOT support incremental update.
1792 struct rte_swx_table_entry_list list;
1795 /* Create updated list of entries included. */
1798 status = table_entry_list_duplicate(ctl,
1805 status = table_entry_list_duplicate(ctl,
1808 &table->pending_add);
1812 status = table_entry_list_duplicate(ctl,
1815 &table->pending_modify1);
1819 /* Create new table object with the updates included. */
1820 ts_next->obj = table->ops.create(&table->params,
1824 if (!ts_next->obj) {
1829 table_entry_list_free(&list);
1834 table_entry_list_free(&list);
1838 /* Free the old table object. */
1839 if (ts_next->obj && table->ops.free)
1840 table->ops.free(ts_next->obj);
1842 /* Copy over the new table object. */
1843 ts_next->obj = ts->obj;
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.
1853 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1855 struct table *table = &ctl->tables[table_id];
1856 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1858 uint8_t *action_data;
1861 /* Copy the pending default entry. */
1862 if (!table->pending_default)
1865 action_id = table->pending_default->action_id;
1866 action_data = table->pending_default->action_data;
1867 a = &ctl->actions[action_id];
1870 memcpy(ts_next->default_action_data, action_data, a->data_size);
1872 ts_next->default_action_id = action_id;
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.
1880 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1882 struct table *table = &ctl->tables[table_id];
1884 /* Move all the pending add entries to the table, as they are now part
1887 table_pending_add_admit(table);
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.
1893 table_pending_modify1_admit(table);
1894 table_pending_modify0_free(table);
1896 /* Free up all the pending delete entries, as they are no longer part of
1899 table_pending_delete_free(table);
1901 /* Free up the pending default entry, as it is now part of the table. */
1902 table_pending_default_free(table);
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
1911 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1913 struct table *table = &ctl->tables[table_id];
1914 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1916 if (table->is_stub || !table_is_update_pending(table, 0))
1919 if (table->ops.add) {
1920 struct rte_swx_table_entry *entry;
1922 /* Add back all the entries that were just deleted. */
1923 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1924 if (!table->n_delete)
1927 table->ops.add(ts_next->obj, entry);
1931 /* Add back the old copy for all the entries that were just
1934 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1935 if (!table->n_modify)
1938 table->ops.add(ts_next->obj, entry);
1942 /* Delete all the entries that were just added. */
1943 TAILQ_FOREACH(entry, &table->pending_add, node) {
1947 table->ops.del(ts_next->obj, entry);
1951 struct rte_swx_table_state *ts = &ctl->ts[table_id];
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);
1957 /* Reinstate the old table object. */
1958 ts_next->obj = ts->obj;
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.
1966 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1968 struct table *table = &ctl->tables[table_id];
1970 /* Free up all the pending add entries, as none of them is part of the
1973 table_pending_add_free(table);
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.
1979 table_pending_modify1_free(table);
1980 table_pending_modify0_admit(table);
1982 /* Add back all the pending delete entries, as none of them was deleted
1985 table_pending_delete_admit(table);
1987 /* Free up the pending default entry, as it is no longer going to be
1988 * added to the table.
1990 table_pending_default_free(table);
1994 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1995 const char *selector_name,
2001 /* Check input arguments. */
2002 if (!ctl || !selector_name || !selector_name[0] || !group_id)
2005 s = selector_find(ctl, selector_name);
2009 /* Find an unused group. */
2010 for (i = 0; i < s->info.n_groups_max; i++)
2011 if (!s->groups_added[i]) {
2013 s->groups_added[i] = 1;
2021 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2022 const char *selector_name,
2026 struct rte_swx_table_selector_group *group;
2028 /* Check input arguments. */
2029 if (!ctl || !selector_name || !selector_name[0])
2032 s = selector_find(ctl, selector_name);
2034 (group_id >= s->info.n_groups_max) ||
2035 !s->groups_added[group_id])
2038 /* Check if this group is already scheduled for deletion. */
2039 if (s->groups_pending_delete[group_id])
2042 /* Initialize the pending group, if needed. */
2043 if (!s->pending_groups[group_id]) {
2046 status = selector_group_duplicate_to_pending(s, group_id);
2051 group = s->pending_groups[group_id];
2053 /* Schedule removal of all the members from the current group. */
2055 struct rte_swx_table_selector_member *m;
2057 m = TAILQ_FIRST(&group->members);
2061 TAILQ_REMOVE(&group->members, m, node);
2065 /* Schedule the group for deletion. */
2066 s->groups_pending_delete[group_id] = 1;
2072 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2073 const char *selector_name,
2076 uint32_t member_weight)
2079 struct rte_swx_table_selector_group *group;
2080 struct rte_swx_table_selector_member *m;
2083 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2088 /* Check input arguments. */
2089 if (!ctl || !selector_name || !selector_name[0])
2092 s = selector_find(ctl, selector_name);
2094 (group_id >= s->info.n_groups_max) ||
2095 !s->groups_added[group_id] ||
2096 s->groups_pending_delete[group_id])
2099 /* Initialize the pending group, if needed. */
2100 if (!s->pending_groups[group_id]) {
2103 status = selector_group_duplicate_to_pending(s, group_id);
2108 group = s->pending_groups[group_id];
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;
2117 /* Add new member to this group. */
2118 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2122 m->member_id = member_id;
2123 m->member_weight = member_weight;
2125 TAILQ_INSERT_TAIL(&group->members, m, node);
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)
2137 struct rte_swx_table_selector_group *group;
2138 struct rte_swx_table_selector_member *m;
2140 /* Check input arguments. */
2141 if (!ctl || !selector_name || !selector_name[0])
2144 s = selector_find(ctl, selector_name);
2146 (group_id >= s->info.n_groups_max) ||
2147 !s->groups_added[group_id] ||
2148 s->groups_pending_delete[group_id])
2151 /* Initialize the pending group, if needed. */
2152 if (!s->pending_groups[group_id]) {
2155 status = selector_group_duplicate_to_pending(s, group_id);
2160 group = s->pending_groups[group_id];
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);
2174 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
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];
2180 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2181 * mirror copy (ts_next->obj).
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];
2187 /* Skip this group if no change needed. */
2191 /* Apply the pending changes for the current group. */
2192 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2201 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2203 struct selector *s = &ctl->selectors[selector_id];
2206 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2207 * records (s->groups[group_id).
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];
2213 /* Skip this group if no change needed. */
2217 /* Transition the pending changes to stable. */
2218 s->groups[group_id] = gp;
2219 s->pending_groups[group_id] = NULL;
2221 /* Free the old group member list. */
2226 struct rte_swx_table_selector_member *m;
2228 m = TAILQ_FIRST(&g->members);
2232 TAILQ_REMOVE(&g->members, m, node);
2239 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2240 * s->groups_added[group_id].
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;
2250 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
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];
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];
2262 ts_next->obj = ts->obj;
2269 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2271 struct selector *s = &ctl->selectors[selector_id];
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);
2278 /* Discard any pending group deletions. */
2279 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2282 static struct rte_swx_table_entry *
2283 learner_default_entry_alloc(struct learner *l)
2285 struct rte_swx_table_entry *entry;
2287 entry = calloc(1, sizeof(struct rte_swx_table_entry));
2292 if (l->action_data_size) {
2293 entry->action_data = calloc(1, l->action_data_size);
2294 if (!entry->action_data)
2301 table_entry_free(entry);
2306 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
2307 uint32_t learner_id,
2308 struct rte_swx_table_entry *entry)
2310 struct learner *l = &ctl->learners[learner_id];
2314 CHECK(entry, EINVAL);
2317 for (i = 0; i < l->info.n_actions; i++)
2318 if (entry->action_id == l->actions[i].action_id)
2321 CHECK(i < l->info.n_actions, EINVAL);
2324 a = &ctl->actions[entry->action_id];
2325 CHECK(!(a->data_size && !entry->action_data), EINVAL);
2330 static struct rte_swx_table_entry *
2331 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
2332 uint32_t learner_id,
2333 struct rte_swx_table_entry *entry)
2335 struct learner *l = &ctl->learners[learner_id];
2336 struct rte_swx_table_entry *new_entry = NULL;
2343 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
2348 for (i = 0; i < l->info.n_actions; i++)
2349 if (entry->action_id == l->actions[i].action_id)
2352 if (i >= l->info.n_actions)
2355 new_entry->action_id = entry->action_id;
2358 a = &ctl->actions[entry->action_id];
2359 if (a->data_size && !entry->action_data)
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.
2369 new_entry->action_data = calloc(1, l->action_data_size);
2370 if (!new_entry->action_data)
2374 memcpy(new_entry->action_data, entry->action_data, a->data_size);
2379 table_entry_free(new_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)
2389 struct rte_swx_table_entry *new_entry;
2390 uint32_t learner_id;
2394 CHECK(learner_name && learner_name[0], EINVAL);
2395 l = learner_find(ctl, learner_name);
2397 learner_id = l - ctl->learners;
2398 CHECK(!l->info.default_action_is_const, EINVAL);
2400 CHECK(entry, EINVAL);
2401 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
2403 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2405 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
2406 CHECK(new_entry, ENOMEM);
2408 learner_pending_default_free(l);
2410 l->pending_default = new_entry;
2415 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
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];
2421 uint8_t *action_data;
2424 /* Copy the pending default entry. */
2425 if (!l->pending_default)
2428 action_id = l->pending_default->action_id;
2429 action_data = l->pending_default->action_data;
2430 a = &ctl->actions[action_id];
2433 memcpy(ts_next->default_action_data, action_data, a->data_size);
2435 ts_next->default_action_id = action_id;
2439 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2441 struct learner *l = &ctl->learners[learner_id];
2443 /* Free up the pending default entry, as it is now part of the table. */
2444 learner_pending_default_free(l);
2448 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
2450 struct learner *l = &ctl->learners[learner_id];
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);
2457 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2459 struct rte_swx_table_state *ts;
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.
2469 for (i = 0; i < ctl->info.n_tables; i++) {
2470 status = table_rollfwd0(ctl, i, 0);
2475 for (i = 0; i < ctl->info.n_selectors; i++) {
2476 status = selector_rollfwd(ctl, i);
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.
2484 for (i = 0; i < ctl->info.n_tables; i++)
2485 table_rollfwd1(ctl, i);
2487 for (i = 0; i < ctl->info.n_learners; i++)
2488 learner_rollfwd(ctl, i);
2490 /* Swap the table state for the data plane. The current ts and ts_next
2491 * become the new ts_next and ts, respectively.
2493 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2496 ctl->ts = ctl->ts_next;
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.
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);
2510 for (i = 0; i < ctl->info.n_selectors; i++) {
2511 selector_rollfwd(ctl, i);
2512 selector_rollfwd_finalize(ctl, i);
2515 for (i = 0; i < ctl->info.n_learners; i++) {
2516 learner_rollfwd(ctl, i);
2517 learner_rollfwd_finalize(ctl, i);
2523 for (i = 0; i < ctl->info.n_tables; i++) {
2524 table_rollback(ctl, i);
2526 table_abort(ctl, i);
2529 for (i = 0; i < ctl->info.n_selectors; i++) {
2530 selector_rollback(ctl, i);
2532 selector_abort(ctl, i);
2536 for (i = 0; i < ctl->info.n_learners; i++)
2537 learner_abort(ctl, i);
2543 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2550 for (i = 0; i < ctl->info.n_tables; i++)
2551 table_abort(ctl, i);
2553 for (i = 0; i < ctl->info.n_selectors; i++)
2554 selector_abort(ctl, i);
2556 for (i = 0; i < ctl->info.n_learners; i++)
2557 learner_abort(ctl, i);
2561 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2563 uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2570 /* Count trailing zero bits. */
2571 for (i = 0; i < 64; i++) {
2572 if (mask & (1LLU << i))
2578 /* Count the one bits that follow. */
2579 for ( ; i < 64; i++) {
2580 if (!(mask & (1LLU << i)))
2586 /* Check that no more one bits are present */
2587 for ( ; i < 64; i++)
2588 if (mask & (1LLU << i))
2591 /* Check that the input mask is a prefix or the right length. */
2592 if (n_ones + n_trailing_zeros != mask_length)
2595 *prefix_length = n_ones;
2600 token_is_comment(const char *token)
2602 if ((token[0] == '#') ||
2603 (token[0] == ';') ||
2604 ((token[0] == '/') && (token[1] == '/')))
2605 return 1; /* TRUE. */
2607 return 0; /* FALSE. */
2610 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2612 struct rte_swx_table_entry *
2613 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2614 const char *table_name,
2616 int *is_blank_or_comment)
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;
2626 /* Check input arguments. */
2630 if (!table_name || !table_name[0])
2633 table = table_find(ctl, table_name);
2637 if (!string || !string[0])
2640 /* Memory allocation. */
2641 s0 = strdup(string);
2645 entry = table_entry_alloc(table);
2649 /* Parse the string into tokens. */
2653 token = strtok_r(s, " \f\n\r\t\v", &s);
2654 if (!token || token_is_comment(token))
2657 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2660 token_array[n_tokens] = token;
2665 blank_or_comment = 1;
2669 tokens = token_array;
2674 if (!(n_tokens && !strcmp(tokens[0], "match")))
2677 if (n_tokens < 1 + table->info.n_match_fields)
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;
2689 mf_mask = strchr(mf_val, '/');
2695 mask = strtoull(mf_mask, &mf_mask, 0);
2700 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2705 lpm_prefix_length_max = mf->n_bits;
2707 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2712 /* Endianness conversion. */
2714 mask = field_hton(mask, mf->n_bits);
2717 /* Copy to entry. */
2718 if (entry->key_mask)
2719 memcpy(&entry->key_mask[offset],
2727 val = strtoull(mf_val, &mf_val, 0);
2731 /* Endianness conversion. */
2733 val = field_hton(val, mf->n_bits);
2735 /* Copy to entry. */
2736 memcpy(&entry->key[offset],
2741 tokens += 1 + table->info.n_match_fields;
2742 n_tokens -= 1 + table->info.n_match_fields;
2747 if (n_tokens && !strcmp(tokens[0], "priority")) {
2748 char *priority = tokens[1];
2755 val = strtoul(priority, &priority, 0);
2759 /* Copy to entry. */
2760 entry->key_priority = val;
2768 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2774 if (!(n_tokens && !strcmp(tokens[0], "action")))
2780 action = action_find(ctl, tokens[1]);
2784 if (n_tokens < 2 + action->info.n_args * 2)
2788 entry->action_id = action - ctl->actions;
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;
2796 arg_name = tokens[2 + i * 2];
2797 arg_val = tokens[2 + i * 2 + 1];
2799 if (strcmp(arg_name, arg->name))
2802 val = strtoull(arg_val, &arg_val, 0);
2806 /* Endianness conversion. */
2807 if (arg->is_network_byte_order)
2808 val = field_hton(val, arg->n_bits);
2810 /* Copy to entry. */
2811 memcpy(&entry->action_data[arg_offset],
2815 arg_offset += arg->n_bits / 8;
2818 tokens += 2 + action->info.n_args * 2;
2819 n_tokens -= 2 + action->info.n_args * 2;
2829 table_entry_free(entry);
2831 if (is_blank_or_comment)
2832 *is_blank_or_comment = blank_or_comment;
2836 struct rte_swx_table_entry *
2837 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
2838 const char *learner_name,
2840 int *is_blank_or_comment)
2842 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
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;
2850 /* Check input arguments. */
2854 if (!learner_name || !learner_name[0])
2857 l = learner_find(ctl, learner_name);
2861 if (!string || !string[0])
2864 /* Memory allocation. */
2865 s0 = strdup(string);
2869 entry = learner_default_entry_alloc(l);
2873 /* Parse the string into tokens. */
2877 token = strtok_r(s, " \f\n\r\t\v", &s);
2878 if (!token || token_is_comment(token))
2881 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2884 token_array[n_tokens] = token;
2889 blank_or_comment = 1;
2893 tokens = token_array;
2898 if (!(n_tokens && !strcmp(tokens[0], "action")))
2904 action = action_find(ctl, tokens[1]);
2908 if (n_tokens < 2 + action->info.n_args * 2)
2912 entry->action_id = action - ctl->actions;
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;
2920 arg_name = tokens[2 + i * 2];
2921 arg_val = tokens[2 + i * 2 + 1];
2923 if (strcmp(arg_name, arg->name))
2926 val = strtoull(arg_val, &arg_val, 0);
2930 /* Endianness conversion. */
2931 if (arg->is_network_byte_order)
2932 val = field_hton(val, arg->n_bits);
2934 /* Copy to entry. */
2935 memcpy(&entry->action_data[arg_offset],
2939 arg_offset += arg->n_bits / 8;
2942 tokens += 2 + action->info.n_args * 2;
2943 n_tokens -= 2 + action->info.n_args * 2;
2953 table_entry_free(entry);
2955 if (is_blank_or_comment)
2956 *is_blank_or_comment = blank_or_comment;
2961 table_entry_printf(FILE *f,
2962 struct rte_swx_ctl_pipeline *ctl,
2963 struct table *table,
2964 struct rte_swx_table_entry *entry)
2966 struct action *action = &ctl->actions[entry->action_id];
2969 fprintf(f, "match ");
2970 for (i = 0; i < table->params.key_size; i++)
2971 fprintf(f, "%02x", entry->key[i]);
2973 if (entry->key_mask) {
2975 for (i = 0; i < table->params.key_size; i++)
2976 fprintf(f, "%02x", entry->key_mask[i]);
2979 fprintf(f, " priority %u", entry->key_priority);
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]);
2989 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2990 struct rte_swx_ctl_pipeline *ctl,
2991 const char *table_name)
2993 struct table *table;
2994 struct rte_swx_table_entry *entry;
2995 uint32_t n_entries = 0, i;
2997 if (!f || !ctl || !table_name || !table_name[0])
3000 table = table_find(ctl, table_name);
3005 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
3007 table->params.key_size,
3008 table->params.key_offset);
3010 for (i = 0; i < table->params.key_size; i++)
3011 fprintf(f, "%02x", table->params.key_mask0[i]);
3013 fprintf(f, "], action data size %u bytes\n",
3014 table->params.action_data_size);
3016 /* Table entries. */
3017 TAILQ_FOREACH(entry, &table->entries, node) {
3018 table_entry_printf(f, ctl, table, entry);
3022 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
3023 table_entry_printf(f, ctl, table, entry);
3027 TAILQ_FOREACH(entry, &table->pending_delete, node) {
3028 table_entry_printf(f, ctl, table, entry);
3032 fprintf(f, "# Table %s currently has %u entries.\n",
3039 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3040 struct rte_swx_ctl_pipeline *ctl,
3041 const char *selector_name)
3046 if (!f || !ctl || !selector_name || !selector_name[0])
3049 s = selector_find(ctl, selector_name);
3054 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3056 s->info.n_groups_max,
3057 s->info.n_members_per_group_max);
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;
3065 fprintf(f, "Group %u = [", group_id);
3067 /* Non-empty group. */
3069 TAILQ_FOREACH(m, &group->members, node) {
3070 fprintf(f, "%u:%u ", m->member_id, m->member_weight);