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;
126 struct rte_swx_ctl_pipeline {
127 struct rte_swx_ctl_pipeline_info info;
128 struct rte_swx_pipeline *p;
129 struct action *actions;
130 struct table *tables;
131 struct selector *selectors;
132 struct rte_swx_table_state *ts;
133 struct rte_swx_table_state *ts_next;
137 static struct action *
138 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
142 for (i = 0; i < ctl->info.n_actions; i++) {
143 struct action *a = &ctl->actions[i];
145 if (!strcmp(action_name, a->info.name))
153 action_free(struct rte_swx_ctl_pipeline *ctl)
160 for (i = 0; i < ctl->info.n_actions; i++) {
161 struct action *action = &ctl->actions[i];
170 static struct table *
171 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
175 for (i = 0; i < ctl->info.n_tables; i++) {
176 struct table *table = &ctl->tables[i];
178 if (!strcmp(table_name, table->info.name))
186 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
188 struct table *table = &ctl->tables[table_id];
189 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
190 uint8_t *key_mask = NULL;
191 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
192 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
194 if (table->info.n_match_fields) {
195 uint32_t n_match_fields_em = 0, i;
197 /* Find first (smallest offset) and last (biggest offset) match fields. */
198 first = &table->mf[0];
199 last = &table->mf[0];
201 for (i = 1; i < table->info.n_match_fields; i++) {
202 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
204 if (f->offset < first->offset)
207 if (f->offset > last->offset)
212 for (i = 0; i < table->info.n_match_fields; i++) {
213 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
215 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
219 if (n_match_fields_em == table->info.n_match_fields)
220 match_type = RTE_SWX_TABLE_MATCH_EXACT;
221 else if ((n_match_fields_em == table->info.n_match_fields - 1) &&
222 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
223 match_type = RTE_SWX_TABLE_MATCH_LPM;
226 key_offset = first->offset / 8;
229 key_size = (last->offset + last->n_bits - first->offset) / 8;
232 key_mask = calloc(1, key_size);
233 CHECK(key_mask, ENOMEM);
235 for (i = 0; i < table->info.n_match_fields; i++) {
236 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
240 start = (f->offset - first->offset) / 8;
241 size = f->n_bits / 8;
243 memset(&key_mask[start], 0xFF, size);
247 /* action_data_size. */
248 for (i = 0; i < table->info.n_actions; i++) {
249 uint32_t action_id = table->actions[i].action_id;
250 struct action *a = &ctl->actions[action_id];
252 if (a->data_size > action_data_size)
253 action_data_size = a->data_size;
257 table->params.match_type = match_type;
258 table->params.key_size = key_size;
259 table->params.key_offset = key_offset;
260 table->params.key_mask0 = key_mask;
261 table->params.action_data_size = action_data_size;
262 table->params.n_keys_max = table->info.size;
264 table->mf_first = first;
265 table->mf_last = last;
271 table_entry_free(struct rte_swx_table_entry *entry)
277 free(entry->key_mask);
278 free(entry->action_data);
282 static struct rte_swx_table_entry *
283 table_entry_alloc(struct table *table)
285 struct rte_swx_table_entry *entry;
287 entry = calloc(1, sizeof(struct rte_swx_table_entry));
292 if (!table->is_stub) {
293 entry->key = calloc(1, table->params.key_size);
297 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
298 entry->key_mask = calloc(1, table->params.key_size);
299 if (!entry->key_mask)
305 if (table->params.action_data_size) {
306 entry->action_data = calloc(1, table->params.action_data_size);
307 if (!entry->action_data)
314 table_entry_free(entry);
319 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
321 uint8_t *key_mask0 = table->params.key_mask0;
322 uint32_t key_size = table->params.key_size, i;
324 if (!entry->key_mask)
327 for (i = 0; i < key_size; i++) {
328 uint8_t km0 = key_mask0[i];
329 uint8_t km = entry->key_mask[i];
331 if ((km & km0) != km0)
339 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
341 struct rte_swx_table_entry *entry,
345 struct table *table = &ctl->tables[table_id];
348 CHECK(entry, EINVAL);
351 if (table->is_stub) {
353 CHECK(!entry->key, EINVAL);
356 CHECK(!entry->key_mask, EINVAL);
359 CHECK(entry->key, EINVAL);
362 switch (table->params.match_type) {
363 case RTE_SWX_TABLE_MATCH_WILDCARD:
366 case RTE_SWX_TABLE_MATCH_LPM:
367 /* TBD Check that key mask is prefix. */
370 case RTE_SWX_TABLE_MATCH_EXACT:
371 status = table_entry_key_check_em(table, entry);
387 for (i = 0; i < table->info.n_actions; i++)
388 if (entry->action_id == table->actions[i].action_id)
391 CHECK(i < table->info.n_actions, EINVAL);
394 a = &ctl->actions[entry->action_id];
395 CHECK(!(a->data_size && !entry->action_data), EINVAL);
401 static struct rte_swx_table_entry *
402 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
404 struct rte_swx_table_entry *entry,
408 struct table *table = &ctl->tables[table_id];
409 struct rte_swx_table_entry *new_entry = NULL;
414 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
418 if (key_duplicate && !table->is_stub) {
423 new_entry->key = malloc(table->params.key_size);
427 memcpy(new_entry->key, entry->key, table->params.key_size);
430 new_entry->key_signature = entry->key_signature;
433 if (entry->key_mask) {
434 new_entry->key_mask = malloc(table->params.key_size);
435 if (!new_entry->key_mask)
438 memcpy(new_entry->key_mask,
440 table->params.key_size);
444 new_entry->key_priority = entry->key_priority;
447 if (data_duplicate) {
452 for (i = 0; i < table->info.n_actions; i++)
453 if (entry->action_id == table->actions[i].action_id)
456 if (i >= table->info.n_actions)
459 new_entry->action_id = entry->action_id;
462 a = &ctl->actions[entry->action_id];
463 if (a->data_size && !entry->action_data)
466 /* The table layer provisions a constant action data size per
467 * entry, which should be the largest data size for all the
468 * actions enabled for the current table, and attempts to copy
469 * this many bytes each time a table entry is added, even if the
470 * specific action requires less data or even no data at all,
471 * hence we always have to allocate the max.
473 new_entry->action_data = calloc(1, table->params.action_data_size);
474 if (!new_entry->action_data)
478 memcpy(new_entry->action_data,
486 table_entry_free(new_entry);
491 table_entry_keycmp(struct table *table,
492 struct rte_swx_table_entry *e0,
493 struct rte_swx_table_entry *e1)
495 uint32_t key_size = table->params.key_size;
498 for (i = 0; i < key_size; i++) {
499 uint8_t *key_mask0 = table->params.key_mask0;
500 uint8_t km0, km[2], k[2];
502 km0 = key_mask0 ? key_mask0[i] : 0xFF;
504 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
505 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
510 /* Mask comparison. */
511 if ((km[0] & km0) != (km[1] & km0))
512 return 1; /* Not equal. */
514 /* Value comparison. */
515 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
516 return 1; /* Not equal. */
519 return 0; /* Equal. */
522 static struct rte_swx_table_entry *
523 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
525 struct rte_swx_table_entry *e;
527 TAILQ_FOREACH(e, &table->entries, node)
528 if (!table_entry_keycmp(table, entry, e))
529 return e; /* Found. */
531 return NULL; /* Not found. */
535 table_entries_free(struct table *table)
538 struct rte_swx_table_entry *entry;
540 entry = TAILQ_FIRST(&table->entries);
544 TAILQ_REMOVE(&table->entries, entry, node);
545 table_entry_free(entry);
549 static struct rte_swx_table_entry *
550 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
552 struct rte_swx_table_entry *e;
554 TAILQ_FOREACH(e, &table->pending_add, node)
555 if (!table_entry_keycmp(table, entry, e))
556 return e; /* Found. */
558 return NULL; /* Not found. */
562 table_pending_add_admit(struct table *table)
564 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
568 table_pending_add_free(struct table *table)
571 struct rte_swx_table_entry *entry;
573 entry = TAILQ_FIRST(&table->pending_add);
577 TAILQ_REMOVE(&table->pending_add, entry, node);
578 table_entry_free(entry);
582 static struct rte_swx_table_entry *
583 table_pending_modify0_find(struct table *table,
584 struct rte_swx_table_entry *entry)
586 struct rte_swx_table_entry *e;
588 TAILQ_FOREACH(e, &table->pending_modify0, node)
589 if (!table_entry_keycmp(table, entry, e))
590 return e; /* Found. */
592 return NULL; /* Not found. */
596 table_pending_modify0_admit(struct table *table)
598 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
602 table_pending_modify0_free(struct table *table)
605 struct rte_swx_table_entry *entry;
607 entry = TAILQ_FIRST(&table->pending_modify0);
611 TAILQ_REMOVE(&table->pending_modify0, entry, node);
612 table_entry_free(entry);
616 static struct rte_swx_table_entry *
617 table_pending_modify1_find(struct table *table,
618 struct rte_swx_table_entry *entry)
620 struct rte_swx_table_entry *e;
622 TAILQ_FOREACH(e, &table->pending_modify1, node)
623 if (!table_entry_keycmp(table, entry, e))
624 return e; /* Found. */
626 return NULL; /* Not found. */
630 table_pending_modify1_admit(struct table *table)
632 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
636 table_pending_modify1_free(struct table *table)
639 struct rte_swx_table_entry *entry;
641 entry = TAILQ_FIRST(&table->pending_modify1);
645 TAILQ_REMOVE(&table->pending_modify1, entry, node);
646 table_entry_free(entry);
650 static struct rte_swx_table_entry *
651 table_pending_delete_find(struct table *table,
652 struct rte_swx_table_entry *entry)
654 struct rte_swx_table_entry *e;
656 TAILQ_FOREACH(e, &table->pending_delete, node)
657 if (!table_entry_keycmp(table, entry, e))
658 return e; /* Found. */
660 return NULL; /* Not found. */
664 table_pending_delete_admit(struct table *table)
666 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
670 table_pending_delete_free(struct table *table)
673 struct rte_swx_table_entry *entry;
675 entry = TAILQ_FIRST(&table->pending_delete);
679 TAILQ_REMOVE(&table->pending_delete, entry, node);
680 table_entry_free(entry);
685 table_pending_default_free(struct table *table)
687 if (!table->pending_default)
690 free(table->pending_default->action_data);
691 free(table->pending_default);
692 table->pending_default = NULL;
696 table_is_update_pending(struct table *table, int consider_pending_default)
698 struct rte_swx_table_entry *e;
702 TAILQ_FOREACH(e, &table->pending_add, node)
705 /* Pending modify. */
706 TAILQ_FOREACH(e, &table->pending_modify1, node)
709 /* Pending delete. */
710 TAILQ_FOREACH(e, &table->pending_delete, node)
713 /* Pending default. */
714 if (consider_pending_default && table->pending_default)
721 table_free(struct rte_swx_ctl_pipeline *ctl)
728 for (i = 0; i < ctl->info.n_tables; i++) {
729 struct table *table = &ctl->tables[i];
732 free(table->actions);
733 free(table->params.key_mask0);
735 table_entries_free(table);
736 table_pending_add_free(table);
737 table_pending_modify0_free(table);
738 table_pending_modify1_free(table);
739 table_pending_delete_free(table);
740 table_pending_default_free(table);
748 selector_group_members_free(struct selector *s, uint32_t group_id)
750 struct rte_swx_table_selector_group *group = s->groups[group_id];
756 struct rte_swx_table_selector_member *m;
758 m = TAILQ_FIRST(&group->members);
762 TAILQ_REMOVE(&group->members, m, node);
767 s->groups[group_id] = NULL;
771 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
773 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
779 struct rte_swx_table_selector_member *m;
781 m = TAILQ_FIRST(&group->members);
785 TAILQ_REMOVE(&group->members, m, node);
790 s->pending_groups[group_id] = NULL;
794 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
796 struct rte_swx_table_selector_group *g, *gp;
797 struct rte_swx_table_selector_member *m;
799 selector_pending_group_members_free(s, group_id);
801 g = s->groups[group_id];
802 gp = s->pending_groups[group_id];
805 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
809 TAILQ_INIT(&gp->members);
811 s->pending_groups[group_id] = gp;
817 TAILQ_FOREACH(m, &g->members, node) {
818 struct rte_swx_table_selector_member *mp;
820 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
824 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
826 TAILQ_INSERT_TAIL(&gp->members, mp, node);
832 selector_pending_group_members_free(s, group_id);
837 selector_free(struct rte_swx_ctl_pipeline *ctl)
844 for (i = 0; i < ctl->info.n_selectors; i++) {
845 struct selector *s = &ctl->selectors[i];
848 /* selector_fields. */
849 free(s->selector_fields);
853 for (i = 0; i < s->info.n_groups_max; i++)
854 selector_group_members_free(s, i);
858 /* pending_groups. */
859 if (s->pending_groups)
860 for (i = 0; i < s->info.n_groups_max; i++)
861 selector_pending_group_members_free(s, i);
863 free(s->pending_groups);
866 free(s->groups_added);
868 /* groups_pending_delete. */
869 free(s->groups_pending_delete);
872 free(s->params.selector_mask);
875 free(ctl->selectors);
876 ctl->selectors = NULL;
879 static struct selector *
880 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
884 for (i = 0; i < ctl->info.n_selectors; i++) {
885 struct selector *s = &ctl->selectors[i];
887 if (!strcmp(selector_name, s->info.name))
895 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
897 struct selector *s = &ctl->selectors[selector_id];
898 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
899 uint8_t *selector_mask = NULL;
900 uint32_t selector_size = 0, selector_offset = 0, i;
902 /* Find first (smallest offset) and last (biggest offset) match fields. */
903 first = &s->selector_fields[0];
904 last = &s->selector_fields[0];
906 for (i = 1; i < s->info.n_selector_fields; i++) {
907 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
909 if (f->offset < first->offset)
912 if (f->offset > last->offset)
916 /* selector_offset. */
917 selector_offset = first->offset / 8;
920 selector_size = (last->offset + last->n_bits - first->offset) / 8;
923 selector_mask = calloc(1, selector_size);
927 for (i = 0; i < s->info.n_selector_fields; i++) {
928 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
932 start = (f->offset - first->offset) / 8;
933 size = f->n_bits / 8;
935 memset(&selector_mask[start], 0xFF, size);
939 s->params.group_id_offset = s->group_id_field.offset / 8;
940 s->params.selector_size = selector_size;
941 s->params.selector_offset = selector_offset;
942 s->params.selector_mask = selector_mask;
943 s->params.member_id_offset = s->member_id_field.offset / 8;
944 s->params.n_groups_max = s->info.n_groups_max;
945 s->params.n_members_per_group_max = s->info.n_members_per_group_max;
951 table_state_free(struct rte_swx_ctl_pipeline *ctl)
958 /* For each table, free its table state. */
959 for (i = 0; i < ctl->info.n_tables; i++) {
960 struct table *table = &ctl->tables[i];
961 struct rte_swx_table_state *ts = &ctl->ts_next[i];
963 /* Default action data. */
964 free(ts->default_action_data);
967 if (!table->is_stub && table->ops.free && ts->obj)
968 table->ops.free(ts->obj);
971 /* For each selector table, free its table state. */
972 for (i = 0; i < ctl->info.n_selectors; i++) {
973 struct rte_swx_table_state *ts = &ctl->ts_next[i];
977 rte_swx_table_selector_free(ts->obj);
985 table_state_create(struct rte_swx_ctl_pipeline *ctl)
990 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
991 sizeof(struct rte_swx_table_state));
998 for (i = 0; i < ctl->info.n_tables; i++) {
999 struct table *table = &ctl->tables[i];
1000 struct rte_swx_table_state *ts = &ctl->ts[i];
1001 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
1004 if (!table->is_stub && table->ops.add) {
1005 ts_next->obj = table->ops.create(&table->params,
1009 if (!ts_next->obj) {
1015 if (!table->is_stub && !table->ops.add)
1016 ts_next->obj = ts->obj;
1018 /* Default action data: duplicate from current table state. */
1019 ts_next->default_action_data =
1020 malloc(table->params.action_data_size);
1021 if (!ts_next->default_action_data) {
1026 memcpy(ts_next->default_action_data,
1027 ts->default_action_data,
1028 table->params.action_data_size);
1030 ts_next->default_action_id = ts->default_action_id;
1033 /* Selector tables. */
1034 for (i = 0; i < ctl->info.n_selectors; i++) {
1035 struct selector *s = &ctl->selectors[i];
1036 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
1039 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1040 if (!ts_next->obj) {
1049 table_state_free(ctl);
1054 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1061 table_state_free(ctl);
1070 struct rte_swx_ctl_pipeline *
1071 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1073 struct rte_swx_ctl_pipeline *ctl = NULL;
1080 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1085 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1090 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1098 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1102 for (i = 0; i < ctl->info.n_actions; i++) {
1103 struct action *a = &ctl->actions[i];
1107 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1112 a->args = calloc(a->info.n_args,
1113 sizeof(struct rte_swx_ctl_action_arg_info));
1117 for (j = 0; j < a->info.n_args; j++) {
1118 status = rte_swx_ctl_action_arg_info_get(p,
1127 for (j = 0; j < a->info.n_args; j++) {
1128 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1130 a->data_size += info->n_bits;
1133 a->data_size = (a->data_size + 7) / 8;
1137 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1141 for (i = 0; i < ctl->info.n_tables; i++) {
1142 struct table *t = &ctl->tables[i];
1144 TAILQ_INIT(&t->entries);
1145 TAILQ_INIT(&t->pending_add);
1146 TAILQ_INIT(&t->pending_modify0);
1147 TAILQ_INIT(&t->pending_modify1);
1148 TAILQ_INIT(&t->pending_delete);
1151 for (i = 0; i < ctl->info.n_tables; i++) {
1152 struct table *t = &ctl->tables[i];
1156 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1161 t->mf = calloc(t->info.n_match_fields,
1162 sizeof(struct rte_swx_ctl_table_match_field_info));
1166 for (j = 0; j < t->info.n_match_fields; j++) {
1167 status = rte_swx_ctl_table_match_field_info_get(p,
1176 t->actions = calloc(t->info.n_actions,
1177 sizeof(struct rte_swx_ctl_table_action_info));
1181 for (j = 0; j < t->info.n_actions; j++) {
1182 status = rte_swx_ctl_table_action_info_get(p,
1187 t->actions[j].action_id >= ctl->info.n_actions)
1192 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1196 if ((t->is_stub && t->info.n_match_fields) ||
1197 (!t->is_stub && !t->info.n_match_fields))
1201 status = table_params_get(ctl, i);
1206 /* selector tables. */
1207 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1208 if (!ctl->selectors)
1211 for (i = 0; i < ctl->info.n_selectors; i++) {
1212 struct selector *s = &ctl->selectors[i];
1216 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1220 /* group_id field. */
1221 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1223 &s->group_id_field);
1227 /* selector fields. */
1228 s->selector_fields = calloc(s->info.n_selector_fields,
1229 sizeof(struct rte_swx_ctl_table_match_field_info));
1230 if (!s->selector_fields)
1233 for (j = 0; j < s->info.n_selector_fields; j++) {
1234 status = rte_swx_ctl_selector_field_info_get(p,
1237 &s->selector_fields[j]);
1242 /* member_id field. */
1243 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1245 &s->member_id_field);
1250 s->groups = calloc(s->info.n_groups_max,
1251 sizeof(struct rte_swx_table_selector_group *));
1255 /* pending_groups. */
1256 s->pending_groups = calloc(s->info.n_groups_max,
1257 sizeof(struct rte_swx_table_selector_group *));
1258 if (!s->pending_groups)
1262 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1263 if (!s->groups_added)
1266 /* groups_pending_delete. */
1267 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1268 if (!s->groups_pending_delete)
1272 status = selector_params_get(ctl, i);
1278 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1283 status = table_state_create(ctl);
1290 rte_swx_ctl_pipeline_free(ctl);
1295 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1296 const char *table_name,
1297 struct rte_swx_table_entry *entry)
1299 struct table *table;
1300 struct rte_swx_table_entry *new_entry, *existing_entry;
1304 CHECK(table_name && table_name[0], EINVAL);
1306 table = table_find(ctl, table_name);
1307 CHECK(table, EINVAL);
1308 table_id = table - ctl->tables;
1310 CHECK(entry, EINVAL);
1311 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1313 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1314 CHECK(new_entry, ENOMEM);
1316 /* The new entry is found in the table->entries list:
1317 * - Add the new entry to the table->pending_modify1 list;
1318 * - Move the existing entry from the table->entries list to the
1319 * table->pending_modify0 list.
1321 existing_entry = table_entries_find(table, entry);
1322 if (existing_entry) {
1323 TAILQ_INSERT_TAIL(&table->pending_modify1,
1327 TAILQ_REMOVE(&table->entries,
1331 TAILQ_INSERT_TAIL(&table->pending_modify0,
1338 /* The new entry is found in the table->pending_add list:
1339 * - Replace the entry in the table->pending_add list with the new entry
1340 * (and free the replaced entry).
1342 existing_entry = table_pending_add_find(table, entry);
1343 if (existing_entry) {
1344 TAILQ_INSERT_AFTER(&table->pending_add,
1349 TAILQ_REMOVE(&table->pending_add,
1353 table_entry_free(existing_entry);
1358 /* The new entry is found in the table->pending_modify1 list:
1359 * - Replace the entry in the table->pending_modify1 list with the new
1360 * entry (and free the replaced entry).
1362 existing_entry = table_pending_modify1_find(table, entry);
1363 if (existing_entry) {
1364 TAILQ_INSERT_AFTER(&table->pending_modify1,
1369 TAILQ_REMOVE(&table->pending_modify1,
1373 table_entry_free(existing_entry);
1378 /* The new entry is found in the table->pending_delete list:
1379 * - Add the new entry to the table->pending_modify1 list;
1380 * - Move the existing entry from the table->pending_delete list to the
1381 * table->pending_modify0 list.
1383 existing_entry = table_pending_delete_find(table, entry);
1384 if (existing_entry) {
1385 TAILQ_INSERT_TAIL(&table->pending_modify1,
1389 TAILQ_REMOVE(&table->pending_delete,
1393 TAILQ_INSERT_TAIL(&table->pending_modify0,
1400 /* The new entry is not found in any of the above lists:
1401 * - Add the new entry to the table->pending_add list.
1403 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1409 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1410 const char *table_name,
1411 struct rte_swx_table_entry *entry)
1413 struct table *table;
1414 struct rte_swx_table_entry *existing_entry;
1419 CHECK(table_name && table_name[0], EINVAL);
1420 table = table_find(ctl, table_name);
1421 CHECK(table, EINVAL);
1422 table_id = table - ctl->tables;
1424 CHECK(entry, EINVAL);
1425 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1427 /* The entry is found in the table->entries list:
1428 * - Move the existing entry from the table->entries list to to the
1429 * table->pending_delete list.
1431 existing_entry = table_entries_find(table, entry);
1432 if (existing_entry) {
1433 TAILQ_REMOVE(&table->entries,
1437 TAILQ_INSERT_TAIL(&table->pending_delete,
1444 /* The entry is found in the table->pending_add list:
1445 * - Remove the entry from the table->pending_add list and free it.
1447 existing_entry = table_pending_add_find(table, entry);
1448 if (existing_entry) {
1449 TAILQ_REMOVE(&table->pending_add,
1453 table_entry_free(existing_entry);
1456 /* The entry is found in the table->pending_modify1 list:
1457 * - Free the entry in the table->pending_modify1 list;
1458 * - Move the existing entry from the table->pending_modify0 list to the
1459 * table->pending_delete list.
1461 existing_entry = table_pending_modify1_find(table, entry);
1462 if (existing_entry) {
1463 struct rte_swx_table_entry *real_existing_entry;
1465 TAILQ_REMOVE(&table->pending_modify1,
1469 table_entry_free(existing_entry);
1471 real_existing_entry = table_pending_modify0_find(table, entry);
1472 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1474 TAILQ_REMOVE(&table->pending_modify0,
1475 real_existing_entry,
1478 TAILQ_INSERT_TAIL(&table->pending_delete,
1479 real_existing_entry,
1485 /* The entry is found in the table->pending_delete list:
1486 * - Do nothing: the existing entry is already in the
1487 * table->pending_delete list, i.e. already marked for delete, so
1488 * simply keep it there as it is.
1491 /* The entry is not found in any of the above lists:
1492 * - Do nothing: no existing entry to delete.
1499 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1500 const char *table_name,
1501 struct rte_swx_table_entry *entry)
1503 struct table *table;
1504 struct rte_swx_table_entry *new_entry;
1509 CHECK(table_name && table_name[0], EINVAL);
1510 table = table_find(ctl, table_name);
1511 CHECK(table, EINVAL);
1512 table_id = table - ctl->tables;
1513 CHECK(!table->info.default_action_is_const, EINVAL);
1515 CHECK(entry, EINVAL);
1516 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1518 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1519 CHECK(new_entry, ENOMEM);
1521 table_pending_default_free(table);
1523 table->pending_default = new_entry;
1529 table_entry_list_free(struct rte_swx_table_entry_list *list)
1532 struct rte_swx_table_entry *entry;
1534 entry = TAILQ_FIRST(list);
1538 TAILQ_REMOVE(list, entry, node);
1539 table_entry_free(entry);
1544 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1546 struct rte_swx_table_entry_list *dst,
1547 struct rte_swx_table_entry_list *src)
1549 struct rte_swx_table_entry *src_entry;
1551 TAILQ_FOREACH(src_entry, src, node) {
1552 struct rte_swx_table_entry *dst_entry;
1554 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1558 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1564 table_entry_list_free(dst);
1568 /* This commit stage contains all the operations that can fail; in case ANY of
1569 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1572 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1574 uint32_t after_swap)
1576 struct table *table = &ctl->tables[table_id];
1577 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1578 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1580 if (table->is_stub || !table_is_update_pending(table, 0))
1584 * Current table supports incremental update.
1586 if (table->ops.add) {
1587 /* Reset counters. */
1589 table->n_modify = 0;
1590 table->n_delete = 0;
1592 /* Add pending rules. */
1593 struct rte_swx_table_entry *entry;
1595 TAILQ_FOREACH(entry, &table->pending_add, node) {
1598 status = table->ops.add(ts_next->obj, entry);
1605 /* Modify pending rules. */
1606 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1609 status = table->ops.add(ts_next->obj, entry);
1616 /* Delete pending rules. */
1617 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1620 status = table->ops.del(ts_next->obj, entry);
1631 * Current table does NOT support incremental update.
1634 struct rte_swx_table_entry_list list;
1637 /* Create updated list of entries included. */
1640 status = table_entry_list_duplicate(ctl,
1647 status = table_entry_list_duplicate(ctl,
1650 &table->pending_add);
1654 status = table_entry_list_duplicate(ctl,
1657 &table->pending_modify1);
1661 /* Create new table object with the updates included. */
1662 ts_next->obj = table->ops.create(&table->params,
1666 if (!ts_next->obj) {
1671 table_entry_list_free(&list);
1676 table_entry_list_free(&list);
1680 /* Free the old table object. */
1681 if (ts_next->obj && table->ops.free)
1682 table->ops.free(ts_next->obj);
1684 /* Copy over the new table object. */
1685 ts_next->obj = ts->obj;
1690 /* This commit stage contains all the operations that cannot fail. They are
1691 * executed only if the previous stage was successful for ALL the tables. Hence,
1692 * none of these operations has to be rolled back for ANY table.
1695 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1697 struct table *table = &ctl->tables[table_id];
1698 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1700 uint8_t *action_data;
1703 /* Copy the pending default entry. */
1704 if (!table->pending_default)
1707 action_id = table->pending_default->action_id;
1708 action_data = table->pending_default->action_data;
1709 a = &ctl->actions[action_id];
1711 memcpy(ts_next->default_action_data,
1715 ts_next->default_action_id = action_id;
1718 /* This last commit stage is simply finalizing a successful commit operation.
1719 * This stage is only executed if all the previous stages were successful. This
1720 * stage cannot fail.
1723 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1725 struct table *table = &ctl->tables[table_id];
1727 /* Move all the pending add entries to the table, as they are now part
1730 table_pending_add_admit(table);
1732 /* Move all the pending modify1 entries to table, are they are now part
1733 * of the table. Free up all the pending modify0 entries, as they are no
1734 * longer part of the table.
1736 table_pending_modify1_admit(table);
1737 table_pending_modify0_free(table);
1739 /* Free up all the pending delete entries, as they are no longer part of
1742 table_pending_delete_free(table);
1744 /* Free up the pending default entry, as it is now part of the table. */
1745 table_pending_default_free(table);
1748 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1749 * commit operations that can fail did fail for ANY table. It reverts ALL the
1750 * tables to their state before the commit started, as if the commit never
1754 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1756 struct table *table = &ctl->tables[table_id];
1757 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1759 if (table->is_stub || !table_is_update_pending(table, 0))
1762 if (table->ops.add) {
1763 struct rte_swx_table_entry *entry;
1765 /* Add back all the entries that were just deleted. */
1766 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1767 if (!table->n_delete)
1770 table->ops.add(ts_next->obj, entry);
1774 /* Add back the old copy for all the entries that were just
1777 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1778 if (!table->n_modify)
1781 table->ops.add(ts_next->obj, entry);
1785 /* Delete all the entries that were just added. */
1786 TAILQ_FOREACH(entry, &table->pending_add, node) {
1790 table->ops.del(ts_next->obj, entry);
1794 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1796 /* Free the new table object, as update was cancelled. */
1797 if (ts_next->obj && table->ops.free)
1798 table->ops.free(ts_next->obj);
1800 /* Reinstate the old table object. */
1801 ts_next->obj = ts->obj;
1805 /* This stage is conditionally executed (as instructed by the user) after a
1806 * failed commit operation to remove ALL the pending work for ALL the tables.
1809 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1811 struct table *table = &ctl->tables[table_id];
1813 /* Free up all the pending add entries, as none of them is part of the
1816 table_pending_add_free(table);
1818 /* Free up all the pending modify1 entries, as none of them made it to
1819 * the table. Add back all the pending modify0 entries, as none of them
1820 * was deleted from the table.
1822 table_pending_modify1_free(table);
1823 table_pending_modify0_admit(table);
1825 /* Add back all the pending delete entries, as none of them was deleted
1828 table_pending_delete_admit(table);
1830 /* Free up the pending default entry, as it is no longer going to be
1831 * added to the table.
1833 table_pending_default_free(table);
1837 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1838 const char *selector_name,
1844 /* Check input arguments. */
1845 if (!ctl || !selector_name || !selector_name[0] || !group_id)
1848 s = selector_find(ctl, selector_name);
1852 /* Find an unused group. */
1853 for (i = 0; i < s->info.n_groups_max; i++)
1854 if (!s->groups_added[i]) {
1856 s->groups_added[i] = 1;
1864 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
1865 const char *selector_name,
1869 struct rte_swx_table_selector_group *group;
1871 /* Check input arguments. */
1872 if (!ctl || !selector_name || !selector_name[0])
1875 s = selector_find(ctl, selector_name);
1877 (group_id >= s->info.n_groups_max) ||
1878 !s->groups_added[group_id])
1881 /* Check if this group is already scheduled for deletion. */
1882 if (s->groups_pending_delete[group_id])
1885 /* Initialize the pending group, if needed. */
1886 if (!s->pending_groups[group_id]) {
1889 status = selector_group_duplicate_to_pending(s, group_id);
1894 group = s->pending_groups[group_id];
1896 /* Schedule removal of all the members from the current group. */
1898 struct rte_swx_table_selector_member *m;
1900 m = TAILQ_FIRST(&group->members);
1904 TAILQ_REMOVE(&group->members, m, node);
1908 /* Schedule the group for deletion. */
1909 s->groups_pending_delete[group_id] = 1;
1915 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
1916 const char *selector_name,
1919 uint32_t member_weight)
1922 struct rte_swx_table_selector_group *group;
1923 struct rte_swx_table_selector_member *m;
1926 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
1931 /* Check input arguments. */
1932 if (!ctl || !selector_name || !selector_name[0])
1935 s = selector_find(ctl, selector_name);
1937 (group_id >= s->info.n_groups_max) ||
1938 !s->groups_added[group_id] ||
1939 s->groups_pending_delete[group_id])
1942 /* Initialize the pending group, if needed. */
1943 if (!s->pending_groups[group_id]) {
1946 status = selector_group_duplicate_to_pending(s, group_id);
1951 group = s->pending_groups[group_id];
1953 /* If this member is already in this group, then simply update its weight and return. */
1954 TAILQ_FOREACH(m, &group->members, node)
1955 if (m->member_id == member_id) {
1956 m->member_weight = member_weight;
1960 /* Add new member to this group. */
1961 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
1965 m->member_id = member_id;
1966 m->member_weight = member_weight;
1968 TAILQ_INSERT_TAIL(&group->members, m, node);
1974 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
1975 const char *selector_name,
1976 uint32_t group_id __rte_unused,
1977 uint32_t member_id __rte_unused)
1980 struct rte_swx_table_selector_group *group;
1981 struct rte_swx_table_selector_member *m;
1983 /* Check input arguments. */
1984 if (!ctl || !selector_name || !selector_name[0])
1987 s = selector_find(ctl, selector_name);
1989 (group_id >= s->info.n_groups_max) ||
1990 !s->groups_added[group_id] ||
1991 s->groups_pending_delete[group_id])
1994 /* Initialize the pending group, if needed. */
1995 if (!s->pending_groups[group_id]) {
1998 status = selector_group_duplicate_to_pending(s, group_id);
2003 group = s->pending_groups[group_id];
2005 /* Look for this member in the group and remove it, if found. */
2006 TAILQ_FOREACH(m, &group->members, node)
2007 if (m->member_id == member_id) {
2008 TAILQ_REMOVE(&group->members, m, node);
2017 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2019 struct selector *s = &ctl->selectors[selector_id];
2020 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2023 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2024 * mirror copy (ts_next->obj).
2026 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2027 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2030 /* Skip this group if no change needed. */
2034 /* Apply the pending changes for the current group. */
2035 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2044 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2046 struct selector *s = &ctl->selectors[selector_id];
2049 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2050 * records (s->groups[group_id).
2052 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2053 struct rte_swx_table_selector_group *g = s->groups[group_id];
2054 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2056 /* Skip this group if no change needed. */
2060 /* Transition the pending changes to stable. */
2061 s->groups[group_id] = gp;
2062 s->pending_groups[group_id] = NULL;
2064 /* Free the old group member list. */
2069 struct rte_swx_table_selector_member *m;
2071 m = TAILQ_FIRST(&g->members);
2075 TAILQ_REMOVE(&g->members, m, node);
2082 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2083 * s->groups_added[group_id].
2085 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2086 if (s->groups_pending_delete[group_id]) {
2087 s->groups_added[group_id] = 0;
2088 s->groups_pending_delete[group_id] = 0;
2093 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2095 struct selector *s = &ctl->selectors[selector_id];
2096 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2097 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2100 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2101 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2102 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2105 ts_next->obj = ts->obj;
2112 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2114 struct selector *s = &ctl->selectors[selector_id];
2117 /* Discard any pending group member changes (s->pending_groups[group_id]). */
2118 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2119 selector_pending_group_members_free(s, group_id);
2121 /* Discard any pending group deletions. */
2122 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2126 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2128 struct rte_swx_table_state *ts;
2134 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2135 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2137 for (i = 0; i < ctl->info.n_tables; i++) {
2138 status = table_rollfwd0(ctl, i, 0);
2143 for (i = 0; i < ctl->info.n_selectors; i++) {
2144 status = selector_rollfwd(ctl, i);
2149 for (i = 0; i < ctl->info.n_tables; i++)
2150 table_rollfwd1(ctl, i);
2152 /* Swap the table state for the data plane. The current ts and ts_next
2153 * become the new ts_next and ts, respectively.
2155 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2158 ctl->ts = ctl->ts_next;
2161 /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2162 * the current ts_next in sync with the current ts. Since the changes that can fail did
2163 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2164 * current ts_next, hence no error checking is needed.
2166 for (i = 0; i < ctl->info.n_tables; i++) {
2167 table_rollfwd0(ctl, i, 1);
2168 table_rollfwd1(ctl, i);
2169 table_rollfwd2(ctl, i);
2172 for (i = 0; i < ctl->info.n_selectors; i++) {
2173 selector_rollfwd(ctl, i);
2174 selector_rollfwd_finalize(ctl, i);
2180 for (i = 0; i < ctl->info.n_tables; i++) {
2181 table_rollback(ctl, i);
2183 table_abort(ctl, i);
2186 for (i = 0; i < ctl->info.n_selectors; i++) {
2187 selector_rollback(ctl, i);
2189 selector_abort(ctl, i);
2196 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2203 for (i = 0; i < ctl->info.n_tables; i++)
2204 table_abort(ctl, i);
2206 for (i = 0; i < ctl->info.n_selectors; i++)
2207 selector_abort(ctl, i);
2211 token_is_comment(const char *token)
2213 if ((token[0] == '#') ||
2214 (token[0] == ';') ||
2215 ((token[0] == '/') && (token[1] == '/')))
2216 return 1; /* TRUE. */
2218 return 0; /* FALSE. */
2221 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2223 struct rte_swx_table_entry *
2224 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2225 const char *table_name,
2227 int *is_blank_or_comment)
2229 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2230 struct table *table;
2231 struct action *action;
2232 struct rte_swx_table_entry *entry = NULL;
2233 char *s0 = NULL, *s;
2234 uint32_t n_tokens = 0, arg_offset = 0, i;
2235 int blank_or_comment = 0;
2237 /* Check input arguments. */
2241 if (!table_name || !table_name[0])
2244 table = table_find(ctl, table_name);
2248 if (!string || !string[0])
2251 /* Memory allocation. */
2252 s0 = strdup(string);
2256 entry = table_entry_alloc(table);
2260 /* Parse the string into tokens. */
2264 token = strtok_r(s, " \f\n\r\t\v", &s);
2265 if (!token || token_is_comment(token))
2268 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2271 token_array[n_tokens] = token;
2276 blank_or_comment = 1;
2280 tokens = token_array;
2285 if (!(n_tokens && !strcmp(tokens[0], "match")))
2288 if (n_tokens < 1 + table->info.n_match_fields)
2291 for (i = 0; i < table->info.n_match_fields; i++) {
2292 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2293 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2294 uint64_t val, mask = UINT64_MAX;
2295 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2300 mf_mask = strchr(mf_val, '/');
2306 mask = strtoull(mf_mask, &mf_mask, 0);
2310 /* Endianness conversion. */
2312 mask = field_hton(mask, mf->n_bits);
2315 /* Copy to entry. */
2316 if (entry->key_mask)
2317 memcpy(&entry->key_mask[offset],
2325 val = strtoull(mf_val, &mf_val, 0);
2329 /* Endianness conversion. */
2331 val = field_hton(val, mf->n_bits);
2333 /* Copy to entry. */
2334 memcpy(&entry->key[offset],
2339 tokens += 1 + table->info.n_match_fields;
2340 n_tokens -= 1 + table->info.n_match_fields;
2345 if (n_tokens && !strcmp(tokens[0], "priority")) {
2346 char *priority = tokens[1];
2353 val = strtoul(priority, &priority, 0);
2357 /* Copy to entry. */
2358 entry->key_priority = val;
2368 if (!(n_tokens && !strcmp(tokens[0], "action")))
2374 action = action_find(ctl, tokens[1]);
2378 if (n_tokens < 2 + action->info.n_args * 2)
2382 entry->action_id = action - ctl->actions;
2385 for (i = 0; i < action->info.n_args; i++) {
2386 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2387 char *arg_name, *arg_val;
2390 arg_name = tokens[2 + i * 2];
2391 arg_val = tokens[2 + i * 2 + 1];
2393 if (strcmp(arg_name, arg->name))
2396 val = strtoull(arg_val, &arg_val, 0);
2400 /* Endianness conversion. */
2401 if (arg->is_network_byte_order)
2402 val = field_hton(val, arg->n_bits);
2404 /* Copy to entry. */
2405 memcpy(&entry->action_data[arg_offset],
2409 arg_offset += arg->n_bits / 8;
2412 tokens += 2 + action->info.n_args * 2;
2413 n_tokens -= 2 + action->info.n_args * 2;
2423 table_entry_free(entry);
2425 if (is_blank_or_comment)
2426 *is_blank_or_comment = blank_or_comment;
2431 table_entry_printf(FILE *f,
2432 struct rte_swx_ctl_pipeline *ctl,
2433 struct table *table,
2434 struct rte_swx_table_entry *entry)
2436 struct action *action = &ctl->actions[entry->action_id];
2439 fprintf(f, "match ");
2440 for (i = 0; i < table->params.key_size; i++)
2441 fprintf(f, "%02x", entry->key[i]);
2443 if (entry->key_mask) {
2445 for (i = 0; i < table->params.key_size; i++)
2446 fprintf(f, "%02x", entry->key_mask[i]);
2449 fprintf(f, " priority %u", entry->key_priority);
2451 fprintf(f, " action %s ", action->info.name);
2452 for (i = 0; i < action->data_size; i++)
2453 fprintf(f, "%02x", entry->action_data[i]);
2459 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2460 struct rte_swx_ctl_pipeline *ctl,
2461 const char *table_name)
2463 struct table *table;
2464 struct rte_swx_table_entry *entry;
2465 uint32_t n_entries = 0, i;
2467 if (!f || !ctl || !table_name || !table_name[0])
2470 table = table_find(ctl, table_name);
2475 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2477 table->params.key_size,
2478 table->params.key_offset);
2480 for (i = 0; i < table->params.key_size; i++)
2481 fprintf(f, "%02x", table->params.key_mask0[i]);
2483 fprintf(f, "], action data size %u bytes\n",
2484 table->params.action_data_size);
2486 /* Table entries. */
2487 TAILQ_FOREACH(entry, &table->entries, node) {
2488 table_entry_printf(f, ctl, table, entry);
2492 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2493 table_entry_printf(f, ctl, table, entry);
2497 TAILQ_FOREACH(entry, &table->pending_delete, node) {
2498 table_entry_printf(f, ctl, table, entry);
2502 fprintf(f, "# Table %s currently has %u entries.\n",
2509 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
2510 struct rte_swx_ctl_pipeline *ctl,
2511 const char *selector_name)
2516 if (!f || !ctl || !selector_name || !selector_name[0])
2519 s = selector_find(ctl, selector_name);
2524 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
2526 s->info.n_groups_max,
2527 s->info.n_members_per_group_max);
2530 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2531 struct rte_swx_table_selector_group *group = s->groups[group_id];
2532 struct rte_swx_table_selector_member *m;
2533 uint32_t n_members = 0;
2535 fprintf(f, "Group %u = [", group_id);
2537 /* Non-empty group. */
2539 TAILQ_FOREACH(m, &group->members, node) {
2540 fprintf(f, "%u:%u ", m->member_id, m->member_weight);