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;
223 key_offset = first->offset / 8;
226 key_size = (last->offset + last->n_bits - first->offset) / 8;
229 key_mask = calloc(1, key_size);
230 CHECK(key_mask, ENOMEM);
232 for (i = 0; i < table->info.n_match_fields; i++) {
233 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
237 start = (f->offset - first->offset) / 8;
238 size = f->n_bits / 8;
240 memset(&key_mask[start], 0xFF, size);
244 /* action_data_size. */
245 for (i = 0; i < table->info.n_actions; i++) {
246 uint32_t action_id = table->actions[i].action_id;
247 struct action *a = &ctl->actions[action_id];
249 if (a->data_size > action_data_size)
250 action_data_size = a->data_size;
254 table->params.match_type = match_type;
255 table->params.key_size = key_size;
256 table->params.key_offset = key_offset;
257 table->params.key_mask0 = key_mask;
258 table->params.action_data_size = action_data_size;
259 table->params.n_keys_max = table->info.size;
261 table->mf_first = first;
262 table->mf_last = last;
268 table_entry_free(struct rte_swx_table_entry *entry)
274 free(entry->key_mask);
275 free(entry->action_data);
279 static struct rte_swx_table_entry *
280 table_entry_alloc(struct table *table)
282 struct rte_swx_table_entry *entry;
284 entry = calloc(1, sizeof(struct rte_swx_table_entry));
289 if (!table->is_stub) {
290 entry->key = calloc(1, table->params.key_size);
294 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
295 entry->key_mask = calloc(1, table->params.key_size);
296 if (!entry->key_mask)
302 if (table->params.action_data_size) {
303 entry->action_data = calloc(1, table->params.action_data_size);
304 if (!entry->action_data)
311 table_entry_free(entry);
316 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
318 uint8_t *key_mask0 = table->params.key_mask0;
319 uint32_t key_size = table->params.key_size, i;
321 if (!entry->key_mask)
324 for (i = 0; i < key_size; i++) {
325 uint8_t km0 = key_mask0[i];
326 uint8_t km = entry->key_mask[i];
328 if ((km & km0) != km0)
336 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
338 struct rte_swx_table_entry *entry,
342 struct table *table = &ctl->tables[table_id];
345 CHECK(entry, EINVAL);
347 if (key_check && !table->is_stub) {
349 CHECK(entry->key, EINVAL);
352 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
353 status = table_entry_key_check_em(table, entry);
364 for (i = 0; i < table->info.n_actions; i++)
365 if (entry->action_id == table->actions[i].action_id)
368 CHECK(i < table->info.n_actions, EINVAL);
371 a = &ctl->actions[entry->action_id];
372 CHECK(!(a->data_size && !entry->action_data), EINVAL);
378 static struct rte_swx_table_entry *
379 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
381 struct rte_swx_table_entry *entry,
385 struct table *table = &ctl->tables[table_id];
386 struct rte_swx_table_entry *new_entry = NULL;
391 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
395 if (key_duplicate && !table->is_stub) {
400 new_entry->key = malloc(table->params.key_size);
404 memcpy(new_entry->key, entry->key, table->params.key_size);
407 new_entry->key_signature = entry->key_signature;
410 if (entry->key_mask) {
411 new_entry->key_mask = malloc(table->params.key_size);
412 if (!new_entry->key_mask)
415 memcpy(new_entry->key_mask,
417 table->params.key_size);
421 new_entry->key_priority = entry->key_priority;
424 if (data_duplicate) {
429 for (i = 0; i < table->info.n_actions; i++)
430 if (entry->action_id == table->actions[i].action_id)
433 if (i >= table->info.n_actions)
436 new_entry->action_id = entry->action_id;
439 a = &ctl->actions[entry->action_id];
440 if (a->data_size && !entry->action_data)
443 /* The table layer provisions a constant action data size per
444 * entry, which should be the largest data size for all the
445 * actions enabled for the current table, and attempts to copy
446 * this many bytes each time a table entry is added, even if the
447 * specific action requires less data or even no data at all,
448 * hence we always have to allocate the max.
450 new_entry->action_data = calloc(1, table->params.action_data_size);
451 if (!new_entry->action_data)
455 memcpy(new_entry->action_data,
463 table_entry_free(new_entry);
468 table_entry_keycmp(struct table *table,
469 struct rte_swx_table_entry *e0,
470 struct rte_swx_table_entry *e1)
472 uint32_t key_size = table->params.key_size;
475 for (i = 0; i < key_size; i++) {
476 uint8_t *key_mask0 = table->params.key_mask0;
477 uint8_t km0, km[2], k[2];
479 km0 = key_mask0 ? key_mask0[i] : 0xFF;
481 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
482 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
487 /* Mask comparison. */
488 if ((km[0] & km0) != (km[1] & km0))
489 return 1; /* Not equal. */
491 /* Value comparison. */
492 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
493 return 1; /* Not equal. */
496 return 0; /* Equal. */
499 static struct rte_swx_table_entry *
500 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
502 struct rte_swx_table_entry *e;
504 TAILQ_FOREACH(e, &table->entries, node)
505 if (!table_entry_keycmp(table, entry, e))
506 return e; /* Found. */
508 return NULL; /* Not found. */
512 table_entries_free(struct table *table)
515 struct rte_swx_table_entry *entry;
517 entry = TAILQ_FIRST(&table->entries);
521 TAILQ_REMOVE(&table->entries, entry, node);
522 table_entry_free(entry);
526 static struct rte_swx_table_entry *
527 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
529 struct rte_swx_table_entry *e;
531 TAILQ_FOREACH(e, &table->pending_add, node)
532 if (!table_entry_keycmp(table, entry, e))
533 return e; /* Found. */
535 return NULL; /* Not found. */
539 table_pending_add_admit(struct table *table)
541 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
545 table_pending_add_free(struct table *table)
548 struct rte_swx_table_entry *entry;
550 entry = TAILQ_FIRST(&table->pending_add);
554 TAILQ_REMOVE(&table->pending_add, entry, node);
555 table_entry_free(entry);
559 static struct rte_swx_table_entry *
560 table_pending_modify0_find(struct table *table,
561 struct rte_swx_table_entry *entry)
563 struct rte_swx_table_entry *e;
565 TAILQ_FOREACH(e, &table->pending_modify0, node)
566 if (!table_entry_keycmp(table, entry, e))
567 return e; /* Found. */
569 return NULL; /* Not found. */
573 table_pending_modify0_admit(struct table *table)
575 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
579 table_pending_modify0_free(struct table *table)
582 struct rte_swx_table_entry *entry;
584 entry = TAILQ_FIRST(&table->pending_modify0);
588 TAILQ_REMOVE(&table->pending_modify0, entry, node);
589 table_entry_free(entry);
593 static struct rte_swx_table_entry *
594 table_pending_modify1_find(struct table *table,
595 struct rte_swx_table_entry *entry)
597 struct rte_swx_table_entry *e;
599 TAILQ_FOREACH(e, &table->pending_modify1, node)
600 if (!table_entry_keycmp(table, entry, e))
601 return e; /* Found. */
603 return NULL; /* Not found. */
607 table_pending_modify1_admit(struct table *table)
609 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
613 table_pending_modify1_free(struct table *table)
616 struct rte_swx_table_entry *entry;
618 entry = TAILQ_FIRST(&table->pending_modify1);
622 TAILQ_REMOVE(&table->pending_modify1, entry, node);
623 table_entry_free(entry);
627 static struct rte_swx_table_entry *
628 table_pending_delete_find(struct table *table,
629 struct rte_swx_table_entry *entry)
631 struct rte_swx_table_entry *e;
633 TAILQ_FOREACH(e, &table->pending_delete, node)
634 if (!table_entry_keycmp(table, entry, e))
635 return e; /* Found. */
637 return NULL; /* Not found. */
641 table_pending_delete_admit(struct table *table)
643 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
647 table_pending_delete_free(struct table *table)
650 struct rte_swx_table_entry *entry;
652 entry = TAILQ_FIRST(&table->pending_delete);
656 TAILQ_REMOVE(&table->pending_delete, entry, node);
657 table_entry_free(entry);
662 table_pending_default_free(struct table *table)
664 if (!table->pending_default)
667 free(table->pending_default->action_data);
668 free(table->pending_default);
669 table->pending_default = NULL;
673 table_is_update_pending(struct table *table, int consider_pending_default)
675 struct rte_swx_table_entry *e;
679 TAILQ_FOREACH(e, &table->pending_add, node)
682 /* Pending modify. */
683 TAILQ_FOREACH(e, &table->pending_modify1, node)
686 /* Pending delete. */
687 TAILQ_FOREACH(e, &table->pending_delete, node)
690 /* Pending default. */
691 if (consider_pending_default && table->pending_default)
698 table_free(struct rte_swx_ctl_pipeline *ctl)
705 for (i = 0; i < ctl->info.n_tables; i++) {
706 struct table *table = &ctl->tables[i];
709 free(table->actions);
710 free(table->params.key_mask0);
712 table_entries_free(table);
713 table_pending_add_free(table);
714 table_pending_modify0_free(table);
715 table_pending_modify1_free(table);
716 table_pending_delete_free(table);
717 table_pending_default_free(table);
725 selector_group_members_free(struct selector *s, uint32_t group_id)
727 struct rte_swx_table_selector_group *group = s->groups[group_id];
733 struct rte_swx_table_selector_member *m;
735 m = TAILQ_FIRST(&group->members);
739 TAILQ_REMOVE(&group->members, m, node);
744 s->groups[group_id] = NULL;
748 selector_pending_group_members_free(struct selector *s, uint32_t group_id)
750 struct rte_swx_table_selector_group *group = s->pending_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->pending_groups[group_id] = NULL;
771 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
773 struct rte_swx_table_selector_group *g, *gp;
774 struct rte_swx_table_selector_member *m;
776 selector_pending_group_members_free(s, group_id);
778 g = s->groups[group_id];
779 gp = s->pending_groups[group_id];
782 gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
786 TAILQ_INIT(&gp->members);
788 s->pending_groups[group_id] = gp;
794 TAILQ_FOREACH(m, &g->members, node) {
795 struct rte_swx_table_selector_member *mp;
797 mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
801 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
803 TAILQ_INSERT_TAIL(&gp->members, mp, node);
809 selector_pending_group_members_free(s, group_id);
814 selector_free(struct rte_swx_ctl_pipeline *ctl)
821 for (i = 0; i < ctl->info.n_selectors; i++) {
822 struct selector *s = &ctl->selectors[i];
825 /* selector_fields. */
826 free(s->selector_fields);
830 for (i = 0; i < s->info.n_groups_max; i++)
831 selector_group_members_free(s, i);
835 /* pending_groups. */
836 if (s->pending_groups)
837 for (i = 0; i < s->info.n_groups_max; i++)
838 selector_pending_group_members_free(s, i);
840 free(s->pending_groups);
843 free(s->groups_added);
845 /* groups_pending_delete. */
846 free(s->groups_pending_delete);
849 free(s->params.selector_mask);
852 free(ctl->selectors);
853 ctl->selectors = NULL;
856 static struct selector *
857 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
861 for (i = 0; i < ctl->info.n_selectors; i++) {
862 struct selector *s = &ctl->selectors[i];
864 if (!strcmp(selector_name, s->info.name))
872 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
874 struct selector *s = &ctl->selectors[selector_id];
875 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
876 uint8_t *selector_mask = NULL;
877 uint32_t selector_size = 0, selector_offset = 0, i;
879 /* Find first (smallest offset) and last (biggest offset) match fields. */
880 first = &s->selector_fields[0];
881 last = &s->selector_fields[0];
883 for (i = 1; i < s->info.n_selector_fields; i++) {
884 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
886 if (f->offset < first->offset)
889 if (f->offset > last->offset)
893 /* selector_offset. */
894 selector_offset = first->offset / 8;
897 selector_size = (last->offset + last->n_bits - first->offset) / 8;
900 selector_mask = calloc(1, selector_size);
904 for (i = 0; i < s->info.n_selector_fields; i++) {
905 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
909 start = (f->offset - first->offset) / 8;
910 size = f->n_bits / 8;
912 memset(&selector_mask[start], 0xFF, size);
916 s->params.group_id_offset = s->group_id_field.offset / 8;
917 s->params.selector_size = selector_size;
918 s->params.selector_offset = selector_offset;
919 s->params.selector_mask = selector_mask;
920 s->params.member_id_offset = s->member_id_field.offset / 8;
921 s->params.n_groups_max = s->info.n_groups_max;
922 s->params.n_members_per_group_max = s->info.n_members_per_group_max;
928 table_state_free(struct rte_swx_ctl_pipeline *ctl)
935 /* For each table, free its table state. */
936 for (i = 0; i < ctl->info.n_tables; i++) {
937 struct table *table = &ctl->tables[i];
938 struct rte_swx_table_state *ts = &ctl->ts_next[i];
940 /* Default action data. */
941 free(ts->default_action_data);
944 if (!table->is_stub && table->ops.free && ts->obj)
945 table->ops.free(ts->obj);
948 /* For each selector table, free its table state. */
949 for (i = 0; i < ctl->info.n_selectors; i++) {
950 struct rte_swx_table_state *ts = &ctl->ts_next[i];
954 rte_swx_table_selector_free(ts->obj);
962 table_state_create(struct rte_swx_ctl_pipeline *ctl)
967 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
968 sizeof(struct rte_swx_table_state));
975 for (i = 0; i < ctl->info.n_tables; i++) {
976 struct table *table = &ctl->tables[i];
977 struct rte_swx_table_state *ts = &ctl->ts[i];
978 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
981 if (!table->is_stub && table->ops.add) {
982 ts_next->obj = table->ops.create(&table->params,
992 if (!table->is_stub && !table->ops.add)
993 ts_next->obj = ts->obj;
995 /* Default action data: duplicate from current table state. */
996 ts_next->default_action_data =
997 malloc(table->params.action_data_size);
998 if (!ts_next->default_action_data) {
1003 memcpy(ts_next->default_action_data,
1004 ts->default_action_data,
1005 table->params.action_data_size);
1007 ts_next->default_action_id = ts->default_action_id;
1010 /* Selector tables. */
1011 for (i = 0; i < ctl->info.n_selectors; i++) {
1012 struct selector *s = &ctl->selectors[i];
1013 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
1016 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1017 if (!ts_next->obj) {
1026 table_state_free(ctl);
1031 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
1038 table_state_free(ctl);
1047 struct rte_swx_ctl_pipeline *
1048 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
1050 struct rte_swx_ctl_pipeline *ctl = NULL;
1057 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
1062 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
1067 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
1075 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
1079 for (i = 0; i < ctl->info.n_actions; i++) {
1080 struct action *a = &ctl->actions[i];
1084 status = rte_swx_ctl_action_info_get(p, i, &a->info);
1089 a->args = calloc(a->info.n_args,
1090 sizeof(struct rte_swx_ctl_action_arg_info));
1094 for (j = 0; j < a->info.n_args; j++) {
1095 status = rte_swx_ctl_action_arg_info_get(p,
1104 for (j = 0; j < a->info.n_args; j++) {
1105 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
1107 a->data_size += info->n_bits;
1110 a->data_size = (a->data_size + 7) / 8;
1114 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
1118 for (i = 0; i < ctl->info.n_tables; i++) {
1119 struct table *t = &ctl->tables[i];
1121 TAILQ_INIT(&t->entries);
1122 TAILQ_INIT(&t->pending_add);
1123 TAILQ_INIT(&t->pending_modify0);
1124 TAILQ_INIT(&t->pending_modify1);
1125 TAILQ_INIT(&t->pending_delete);
1128 for (i = 0; i < ctl->info.n_tables; i++) {
1129 struct table *t = &ctl->tables[i];
1133 status = rte_swx_ctl_table_info_get(p, i, &t->info);
1138 t->mf = calloc(t->info.n_match_fields,
1139 sizeof(struct rte_swx_ctl_table_match_field_info));
1143 for (j = 0; j < t->info.n_match_fields; j++) {
1144 status = rte_swx_ctl_table_match_field_info_get(p,
1153 t->actions = calloc(t->info.n_actions,
1154 sizeof(struct rte_swx_ctl_table_action_info));
1158 for (j = 0; j < t->info.n_actions; j++) {
1159 status = rte_swx_ctl_table_action_info_get(p,
1164 t->actions[j].action_id >= ctl->info.n_actions)
1169 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
1173 if ((t->is_stub && t->info.n_match_fields) ||
1174 (!t->is_stub && !t->info.n_match_fields))
1178 status = table_params_get(ctl, i);
1183 /* selector tables. */
1184 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1185 if (!ctl->selectors)
1188 for (i = 0; i < ctl->info.n_selectors; i++) {
1189 struct selector *s = &ctl->selectors[i];
1193 status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1197 /* group_id field. */
1198 status = rte_swx_ctl_selector_group_id_field_info_get(p,
1200 &s->group_id_field);
1204 /* selector fields. */
1205 s->selector_fields = calloc(s->info.n_selector_fields,
1206 sizeof(struct rte_swx_ctl_table_match_field_info));
1207 if (!s->selector_fields)
1210 for (j = 0; j < s->info.n_selector_fields; j++) {
1211 status = rte_swx_ctl_selector_field_info_get(p,
1214 &s->selector_fields[j]);
1219 /* member_id field. */
1220 status = rte_swx_ctl_selector_member_id_field_info_get(p,
1222 &s->member_id_field);
1227 s->groups = calloc(s->info.n_groups_max,
1228 sizeof(struct rte_swx_table_selector_group *));
1232 /* pending_groups. */
1233 s->pending_groups = calloc(s->info.n_groups_max,
1234 sizeof(struct rte_swx_table_selector_group *));
1235 if (!s->pending_groups)
1239 s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1240 if (!s->groups_added)
1243 /* groups_pending_delete. */
1244 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1245 if (!s->groups_pending_delete)
1249 status = selector_params_get(ctl, i);
1255 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
1260 status = table_state_create(ctl);
1267 rte_swx_ctl_pipeline_free(ctl);
1272 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
1273 const char *table_name,
1274 struct rte_swx_table_entry *entry)
1276 struct table *table;
1277 struct rte_swx_table_entry *new_entry, *existing_entry;
1281 CHECK(table_name && table_name[0], EINVAL);
1283 table = table_find(ctl, table_name);
1284 CHECK(table, EINVAL);
1285 table_id = table - ctl->tables;
1287 CHECK(entry, EINVAL);
1288 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
1290 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
1291 CHECK(new_entry, ENOMEM);
1293 /* The new entry is found in the table->entries list:
1294 * - Add the new entry to the table->pending_modify1 list;
1295 * - Move the existing entry from the table->entries list to the
1296 * table->pending_modify0 list.
1298 existing_entry = table_entries_find(table, entry);
1299 if (existing_entry) {
1300 TAILQ_INSERT_TAIL(&table->pending_modify1,
1304 TAILQ_REMOVE(&table->entries,
1308 TAILQ_INSERT_TAIL(&table->pending_modify0,
1315 /* The new entry is found in the table->pending_add list:
1316 * - Replace the entry in the table->pending_add list with the new entry
1317 * (and free the replaced entry).
1319 existing_entry = table_pending_add_find(table, entry);
1320 if (existing_entry) {
1321 TAILQ_INSERT_AFTER(&table->pending_add,
1326 TAILQ_REMOVE(&table->pending_add,
1330 table_entry_free(existing_entry);
1335 /* The new entry is found in the table->pending_modify1 list:
1336 * - Replace the entry in the table->pending_modify1 list with the new
1337 * entry (and free the replaced entry).
1339 existing_entry = table_pending_modify1_find(table, entry);
1340 if (existing_entry) {
1341 TAILQ_INSERT_AFTER(&table->pending_modify1,
1346 TAILQ_REMOVE(&table->pending_modify1,
1350 table_entry_free(existing_entry);
1355 /* The new entry is found in the table->pending_delete list:
1356 * - Add the new entry to the table->pending_modify1 list;
1357 * - Move the existing entry from the table->pending_delete list to the
1358 * table->pending_modify0 list.
1360 existing_entry = table_pending_delete_find(table, entry);
1361 if (existing_entry) {
1362 TAILQ_INSERT_TAIL(&table->pending_modify1,
1366 TAILQ_REMOVE(&table->pending_delete,
1370 TAILQ_INSERT_TAIL(&table->pending_modify0,
1377 /* The new entry is not found in any of the above lists:
1378 * - Add the new entry to the table->pending_add list.
1380 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1386 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1387 const char *table_name,
1388 struct rte_swx_table_entry *entry)
1390 struct table *table;
1391 struct rte_swx_table_entry *existing_entry;
1396 CHECK(table_name && table_name[0], EINVAL);
1397 table = table_find(ctl, table_name);
1398 CHECK(table, EINVAL);
1399 table_id = table - ctl->tables;
1401 CHECK(entry, EINVAL);
1402 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1404 /* The entry is found in the table->entries list:
1405 * - Move the existing entry from the table->entries list to to the
1406 * table->pending_delete list.
1408 existing_entry = table_entries_find(table, entry);
1409 if (existing_entry) {
1410 TAILQ_REMOVE(&table->entries,
1414 TAILQ_INSERT_TAIL(&table->pending_delete,
1421 /* The entry is found in the table->pending_add list:
1422 * - Remove the entry from the table->pending_add list and free it.
1424 existing_entry = table_pending_add_find(table, entry);
1425 if (existing_entry) {
1426 TAILQ_REMOVE(&table->pending_add,
1430 table_entry_free(existing_entry);
1433 /* The entry is found in the table->pending_modify1 list:
1434 * - Free the entry in the table->pending_modify1 list;
1435 * - Move the existing entry from the table->pending_modify0 list to the
1436 * table->pending_delete list.
1438 existing_entry = table_pending_modify1_find(table, entry);
1439 if (existing_entry) {
1440 struct rte_swx_table_entry *real_existing_entry;
1442 TAILQ_REMOVE(&table->pending_modify1,
1446 table_entry_free(existing_entry);
1448 real_existing_entry = table_pending_modify0_find(table, entry);
1449 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1451 TAILQ_REMOVE(&table->pending_modify0,
1452 real_existing_entry,
1455 TAILQ_INSERT_TAIL(&table->pending_delete,
1456 real_existing_entry,
1462 /* The entry is found in the table->pending_delete list:
1463 * - Do nothing: the existing entry is already in the
1464 * table->pending_delete list, i.e. already marked for delete, so
1465 * simply keep it there as it is.
1468 /* The entry is not found in any of the above lists:
1469 * - Do nothing: no existing entry to delete.
1476 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1477 const char *table_name,
1478 struct rte_swx_table_entry *entry)
1480 struct table *table;
1481 struct rte_swx_table_entry *new_entry;
1486 CHECK(table_name && table_name[0], EINVAL);
1487 table = table_find(ctl, table_name);
1488 CHECK(table, EINVAL);
1489 table_id = table - ctl->tables;
1490 CHECK(!table->info.default_action_is_const, EINVAL);
1492 CHECK(entry, EINVAL);
1493 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1495 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1496 CHECK(new_entry, ENOMEM);
1498 table_pending_default_free(table);
1500 table->pending_default = new_entry;
1506 table_entry_list_free(struct rte_swx_table_entry_list *list)
1509 struct rte_swx_table_entry *entry;
1511 entry = TAILQ_FIRST(list);
1515 TAILQ_REMOVE(list, entry, node);
1516 table_entry_free(entry);
1521 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1523 struct rte_swx_table_entry_list *dst,
1524 struct rte_swx_table_entry_list *src)
1526 struct rte_swx_table_entry *src_entry;
1528 TAILQ_FOREACH(src_entry, src, node) {
1529 struct rte_swx_table_entry *dst_entry;
1531 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1535 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1541 table_entry_list_free(dst);
1545 /* This commit stage contains all the operations that can fail; in case ANY of
1546 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1549 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1551 uint32_t after_swap)
1553 struct table *table = &ctl->tables[table_id];
1554 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1555 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1557 if (table->is_stub || !table_is_update_pending(table, 0))
1561 * Current table supports incremental update.
1563 if (table->ops.add) {
1564 /* Reset counters. */
1566 table->n_modify = 0;
1567 table->n_delete = 0;
1569 /* Add pending rules. */
1570 struct rte_swx_table_entry *entry;
1572 TAILQ_FOREACH(entry, &table->pending_add, node) {
1575 status = table->ops.add(ts_next->obj, entry);
1582 /* Modify pending rules. */
1583 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1586 status = table->ops.add(ts_next->obj, entry);
1593 /* Delete pending rules. */
1594 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1597 status = table->ops.del(ts_next->obj, entry);
1608 * Current table does NOT support incremental update.
1611 struct rte_swx_table_entry_list list;
1614 /* Create updated list of entries included. */
1617 status = table_entry_list_duplicate(ctl,
1624 status = table_entry_list_duplicate(ctl,
1627 &table->pending_add);
1631 status = table_entry_list_duplicate(ctl,
1634 &table->pending_modify1);
1638 /* Create new table object with the updates included. */
1639 ts_next->obj = table->ops.create(&table->params,
1643 if (!ts_next->obj) {
1648 table_entry_list_free(&list);
1653 table_entry_list_free(&list);
1657 /* Free the old table object. */
1658 if (ts_next->obj && table->ops.free)
1659 table->ops.free(ts_next->obj);
1661 /* Copy over the new table object. */
1662 ts_next->obj = ts->obj;
1667 /* This commit stage contains all the operations that cannot fail. They are
1668 * executed only if the previous stage was successful for ALL the tables. Hence,
1669 * none of these operations has to be rolled back for ANY table.
1672 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1674 struct table *table = &ctl->tables[table_id];
1675 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1677 uint8_t *action_data;
1680 /* Copy the pending default entry. */
1681 if (!table->pending_default)
1684 action_id = table->pending_default->action_id;
1685 action_data = table->pending_default->action_data;
1686 a = &ctl->actions[action_id];
1688 memcpy(ts_next->default_action_data,
1692 ts_next->default_action_id = action_id;
1695 /* This last commit stage is simply finalizing a successful commit operation.
1696 * This stage is only executed if all the previous stages were successful. This
1697 * stage cannot fail.
1700 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1702 struct table *table = &ctl->tables[table_id];
1704 /* Move all the pending add entries to the table, as they are now part
1707 table_pending_add_admit(table);
1709 /* Move all the pending modify1 entries to table, are they are now part
1710 * of the table. Free up all the pending modify0 entries, as they are no
1711 * longer part of the table.
1713 table_pending_modify1_admit(table);
1714 table_pending_modify0_free(table);
1716 /* Free up all the pending delete entries, as they are no longer part of
1719 table_pending_delete_free(table);
1721 /* Free up the pending default entry, as it is now part of the table. */
1722 table_pending_default_free(table);
1725 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1726 * commit operations that can fail did fail for ANY table. It reverts ALL the
1727 * tables to their state before the commit started, as if the commit never
1731 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1733 struct table *table = &ctl->tables[table_id];
1734 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1736 if (table->is_stub || !table_is_update_pending(table, 0))
1739 if (table->ops.add) {
1740 struct rte_swx_table_entry *entry;
1742 /* Add back all the entries that were just deleted. */
1743 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1744 if (!table->n_delete)
1747 table->ops.add(ts_next->obj, entry);
1751 /* Add back the old copy for all the entries that were just
1754 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1755 if (!table->n_modify)
1758 table->ops.add(ts_next->obj, entry);
1762 /* Delete all the entries that were just added. */
1763 TAILQ_FOREACH(entry, &table->pending_add, node) {
1767 table->ops.del(ts_next->obj, entry);
1771 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1773 /* Free the new table object, as update was cancelled. */
1774 if (ts_next->obj && table->ops.free)
1775 table->ops.free(ts_next->obj);
1777 /* Reinstate the old table object. */
1778 ts_next->obj = ts->obj;
1782 /* This stage is conditionally executed (as instructed by the user) after a
1783 * failed commit operation to remove ALL the pending work for ALL the tables.
1786 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1788 struct table *table = &ctl->tables[table_id];
1790 /* Free up all the pending add entries, as none of them is part of the
1793 table_pending_add_free(table);
1795 /* Free up all the pending modify1 entries, as none of them made it to
1796 * the table. Add back all the pending modify0 entries, as none of them
1797 * was deleted from the table.
1799 table_pending_modify1_free(table);
1800 table_pending_modify0_admit(table);
1802 /* Add back all the pending delete entries, as none of them was deleted
1805 table_pending_delete_admit(table);
1807 /* Free up the pending default entry, as it is no longer going to be
1808 * added to the table.
1810 table_pending_default_free(table);
1814 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
1815 const char *selector_name,
1821 /* Check input arguments. */
1822 if (!ctl || !selector_name || !selector_name[0] || !group_id)
1825 s = selector_find(ctl, selector_name);
1829 /* Find an unused group. */
1830 for (i = 0; i < s->info.n_groups_max; i++)
1831 if (!s->groups_added[i]) {
1833 s->groups_added[i] = 1;
1841 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
1842 const char *selector_name,
1846 struct rte_swx_table_selector_group *group;
1848 /* Check input arguments. */
1849 if (!ctl || !selector_name || !selector_name[0])
1852 s = selector_find(ctl, selector_name);
1854 (group_id >= s->info.n_groups_max) ||
1855 !s->groups_added[group_id])
1858 /* Check if this group is already scheduled for deletion. */
1859 if (s->groups_pending_delete[group_id])
1862 /* Initialize the pending group, if needed. */
1863 if (!s->pending_groups[group_id]) {
1866 status = selector_group_duplicate_to_pending(s, group_id);
1871 group = s->pending_groups[group_id];
1873 /* Schedule removal of all the members from the current group. */
1875 struct rte_swx_table_selector_member *m;
1877 m = TAILQ_FIRST(&group->members);
1881 TAILQ_REMOVE(&group->members, m, node);
1885 /* Schedule the group for deletion. */
1886 s->groups_pending_delete[group_id] = 1;
1892 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
1893 const char *selector_name,
1896 uint32_t member_weight)
1899 struct rte_swx_table_selector_group *group;
1900 struct rte_swx_table_selector_member *m;
1903 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
1908 /* Check input arguments. */
1909 if (!ctl || !selector_name || !selector_name[0])
1912 s = selector_find(ctl, selector_name);
1914 (group_id >= s->info.n_groups_max) ||
1915 !s->groups_added[group_id] ||
1916 s->groups_pending_delete[group_id])
1919 /* Initialize the pending group, if needed. */
1920 if (!s->pending_groups[group_id]) {
1923 status = selector_group_duplicate_to_pending(s, group_id);
1928 group = s->pending_groups[group_id];
1930 /* If this member is already in this group, then simply update its weight and return. */
1931 TAILQ_FOREACH(m, &group->members, node)
1932 if (m->member_id == member_id) {
1933 m->member_weight = member_weight;
1937 /* Add new member to this group. */
1938 m = calloc(1, sizeof(struct rte_swx_table_selector_member));
1942 m->member_id = member_id;
1943 m->member_weight = member_weight;
1945 TAILQ_INSERT_TAIL(&group->members, m, node);
1951 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
1952 const char *selector_name,
1953 uint32_t group_id __rte_unused,
1954 uint32_t member_id __rte_unused)
1957 struct rte_swx_table_selector_group *group;
1958 struct rte_swx_table_selector_member *m;
1960 /* Check input arguments. */
1961 if (!ctl || !selector_name || !selector_name[0])
1964 s = selector_find(ctl, selector_name);
1966 (group_id >= s->info.n_groups_max) ||
1967 !s->groups_added[group_id] ||
1968 s->groups_pending_delete[group_id])
1971 /* Initialize the pending group, if needed. */
1972 if (!s->pending_groups[group_id]) {
1975 status = selector_group_duplicate_to_pending(s, group_id);
1980 group = s->pending_groups[group_id];
1982 /* Look for this member in the group and remove it, if found. */
1983 TAILQ_FOREACH(m, &group->members, node)
1984 if (m->member_id == member_id) {
1985 TAILQ_REMOVE(&group->members, m, node);
1994 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
1996 struct selector *s = &ctl->selectors[selector_id];
1997 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2000 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2001 * mirror copy (ts_next->obj).
2003 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2004 struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2007 /* Skip this group if no change needed. */
2011 /* Apply the pending changes for the current group. */
2012 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2021 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2023 struct selector *s = &ctl->selectors[selector_id];
2026 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2027 * records (s->groups[group_id).
2029 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2030 struct rte_swx_table_selector_group *g = s->groups[group_id];
2031 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2033 /* Skip this group if no change needed. */
2037 /* Transition the pending changes to stable. */
2038 s->groups[group_id] = gp;
2039 s->pending_groups[group_id] = NULL;
2041 /* Free the old group member list. */
2046 struct rte_swx_table_selector_member *m;
2048 m = TAILQ_FIRST(&g->members);
2052 TAILQ_REMOVE(&g->members, m, node);
2059 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2060 * s->groups_added[group_id].
2062 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2063 if (s->groups_pending_delete[group_id]) {
2064 s->groups_added[group_id] = 0;
2065 s->groups_pending_delete[group_id] = 0;
2070 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2072 struct selector *s = &ctl->selectors[selector_id];
2073 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2074 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2077 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2078 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2079 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2082 ts_next->obj = ts->obj;
2089 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2091 struct selector *s = &ctl->selectors[selector_id];
2094 /* Discard any pending group member changes (s->pending_groups[group_id]). */
2095 for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2096 selector_pending_group_members_free(s, group_id);
2098 /* Discard any pending group deletions. */
2099 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2103 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
2105 struct rte_swx_table_state *ts;
2111 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2112 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
2114 for (i = 0; i < ctl->info.n_tables; i++) {
2115 status = table_rollfwd0(ctl, i, 0);
2120 for (i = 0; i < ctl->info.n_selectors; i++) {
2121 status = selector_rollfwd(ctl, i);
2126 for (i = 0; i < ctl->info.n_tables; i++)
2127 table_rollfwd1(ctl, i);
2129 /* Swap the table state for the data plane. The current ts and ts_next
2130 * become the new ts_next and ts, respectively.
2132 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
2135 ctl->ts = ctl->ts_next;
2138 /* Operate the changes on the current ts_next, which is the previous ts, in order to get
2139 * the current ts_next in sync with the current ts. Since the changes that can fail did
2140 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2141 * current ts_next, hence no error checking is needed.
2143 for (i = 0; i < ctl->info.n_tables; i++) {
2144 table_rollfwd0(ctl, i, 1);
2145 table_rollfwd1(ctl, i);
2146 table_rollfwd2(ctl, i);
2149 for (i = 0; i < ctl->info.n_selectors; i++) {
2150 selector_rollfwd(ctl, i);
2151 selector_rollfwd_finalize(ctl, i);
2157 for (i = 0; i < ctl->info.n_tables; i++) {
2158 table_rollback(ctl, i);
2160 table_abort(ctl, i);
2163 for (i = 0; i < ctl->info.n_selectors; i++) {
2164 selector_rollback(ctl, i);
2166 selector_abort(ctl, i);
2173 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
2180 for (i = 0; i < ctl->info.n_tables; i++)
2181 table_abort(ctl, i);
2183 for (i = 0; i < ctl->info.n_selectors; i++)
2184 selector_abort(ctl, i);
2188 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2190 uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2197 /* Count trailing zero bits. */
2198 for (i = 0; i < 64; i++) {
2199 if (mask & (1LLU << i))
2205 /* Count the one bits that follow. */
2206 for ( ; i < 64; i++) {
2207 if (!(mask & (1LLU << i)))
2213 /* Check that no more one bits are present */
2214 for ( ; i < 64; i++)
2215 if (mask & (1LLU << i))
2218 /* Check that the input mask is a prefix or the right length. */
2219 if (n_ones + n_trailing_zeros != mask_length)
2222 *prefix_length = n_ones;
2227 token_is_comment(const char *token)
2229 if ((token[0] == '#') ||
2230 (token[0] == ';') ||
2231 ((token[0] == '/') && (token[1] == '/')))
2232 return 1; /* TRUE. */
2234 return 0; /* FALSE. */
2237 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
2239 struct rte_swx_table_entry *
2240 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
2241 const char *table_name,
2243 int *is_blank_or_comment)
2245 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
2246 struct table *table;
2247 struct action *action;
2248 struct rte_swx_table_entry *entry = NULL;
2249 char *s0 = NULL, *s;
2250 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2251 int lpm = 0, blank_or_comment = 0;
2253 /* Check input arguments. */
2257 if (!table_name || !table_name[0])
2260 table = table_find(ctl, table_name);
2264 if (!string || !string[0])
2267 /* Memory allocation. */
2268 s0 = strdup(string);
2272 entry = table_entry_alloc(table);
2276 /* Parse the string into tokens. */
2280 token = strtok_r(s, " \f\n\r\t\v", &s);
2281 if (!token || token_is_comment(token))
2284 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
2287 token_array[n_tokens] = token;
2292 blank_or_comment = 1;
2296 tokens = token_array;
2301 if (!(n_tokens && !strcmp(tokens[0], "match")))
2304 if (n_tokens < 1 + table->info.n_match_fields)
2307 for (i = 0; i < table->info.n_match_fields; i++) {
2308 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
2309 char *mf_val = tokens[1 + i], *mf_mask = NULL;
2310 uint64_t val, mask = UINT64_MAX;
2311 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2316 mf_mask = strchr(mf_val, '/');
2322 mask = strtoull(mf_mask, &mf_mask, 0);
2327 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2332 lpm_prefix_length_max = mf->n_bits;
2334 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length);
2339 /* Endianness conversion. */
2341 mask = field_hton(mask, mf->n_bits);
2344 /* Copy to entry. */
2345 if (entry->key_mask)
2346 memcpy(&entry->key_mask[offset],
2354 val = strtoull(mf_val, &mf_val, 0);
2358 /* Endianness conversion. */
2360 val = field_hton(val, mf->n_bits);
2362 /* Copy to entry. */
2363 memcpy(&entry->key[offset],
2368 tokens += 1 + table->info.n_match_fields;
2369 n_tokens -= 1 + table->info.n_match_fields;
2374 if (n_tokens && !strcmp(tokens[0], "priority")) {
2375 char *priority = tokens[1];
2382 val = strtoul(priority, &priority, 0);
2386 /* Copy to entry. */
2387 entry->key_priority = val;
2395 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
2401 if (!(n_tokens && !strcmp(tokens[0], "action")))
2407 action = action_find(ctl, tokens[1]);
2411 if (n_tokens < 2 + action->info.n_args * 2)
2415 entry->action_id = action - ctl->actions;
2418 for (i = 0; i < action->info.n_args; i++) {
2419 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
2420 char *arg_name, *arg_val;
2423 arg_name = tokens[2 + i * 2];
2424 arg_val = tokens[2 + i * 2 + 1];
2426 if (strcmp(arg_name, arg->name))
2429 val = strtoull(arg_val, &arg_val, 0);
2433 /* Endianness conversion. */
2434 if (arg->is_network_byte_order)
2435 val = field_hton(val, arg->n_bits);
2437 /* Copy to entry. */
2438 memcpy(&entry->action_data[arg_offset],
2442 arg_offset += arg->n_bits / 8;
2445 tokens += 2 + action->info.n_args * 2;
2446 n_tokens -= 2 + action->info.n_args * 2;
2456 table_entry_free(entry);
2458 if (is_blank_or_comment)
2459 *is_blank_or_comment = blank_or_comment;
2464 table_entry_printf(FILE *f,
2465 struct rte_swx_ctl_pipeline *ctl,
2466 struct table *table,
2467 struct rte_swx_table_entry *entry)
2469 struct action *action = &ctl->actions[entry->action_id];
2472 fprintf(f, "match ");
2473 for (i = 0; i < table->params.key_size; i++)
2474 fprintf(f, "%02x", entry->key[i]);
2476 if (entry->key_mask) {
2478 for (i = 0; i < table->params.key_size; i++)
2479 fprintf(f, "%02x", entry->key_mask[i]);
2482 fprintf(f, " priority %u", entry->key_priority);
2484 fprintf(f, " action %s ", action->info.name);
2485 for (i = 0; i < action->data_size; i++)
2486 fprintf(f, "%02x", entry->action_data[i]);
2492 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
2493 struct rte_swx_ctl_pipeline *ctl,
2494 const char *table_name)
2496 struct table *table;
2497 struct rte_swx_table_entry *entry;
2498 uint32_t n_entries = 0, i;
2500 if (!f || !ctl || !table_name || !table_name[0])
2503 table = table_find(ctl, table_name);
2508 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
2510 table->params.key_size,
2511 table->params.key_offset);
2513 for (i = 0; i < table->params.key_size; i++)
2514 fprintf(f, "%02x", table->params.key_mask0[i]);
2516 fprintf(f, "], action data size %u bytes\n",
2517 table->params.action_data_size);
2519 /* Table entries. */
2520 TAILQ_FOREACH(entry, &table->entries, node) {
2521 table_entry_printf(f, ctl, table, entry);
2525 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
2526 table_entry_printf(f, ctl, table, entry);
2530 TAILQ_FOREACH(entry, &table->pending_delete, node) {
2531 table_entry_printf(f, ctl, table, entry);
2535 fprintf(f, "# Table %s currently has %u entries.\n",
2542 rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
2543 struct rte_swx_ctl_pipeline *ctl,
2544 const char *selector_name)
2549 if (!f || !ctl || !selector_name || !selector_name[0])
2552 s = selector_find(ctl, selector_name);
2557 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
2559 s->info.n_groups_max,
2560 s->info.n_members_per_group_max);
2563 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2564 struct rte_swx_table_selector_group *group = s->groups[group_id];
2565 struct rte_swx_table_selector_member *m;
2566 uint32_t n_members = 0;
2568 fprintf(f, "Group %u = [", group_id);
2570 /* Non-empty group. */
2572 TAILQ_FOREACH(m, &group->members, node) {
2573 fprintf(f, "%u:%u ", m->member_id, m->member_weight);