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_ctl.h"
15 #define CHECK(condition, err_code) \
21 #define ntoh64(x) rte_be_to_cpu_64(x)
22 #define hton64(x) rte_cpu_to_be_64(x)
24 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
25 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
26 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
28 #define field_ntoh(val, n_bits) (val)
29 #define field_hton(val, n_bits) (val)
33 struct rte_swx_ctl_action_info info;
34 struct rte_swx_ctl_action_arg_info *args;
39 struct rte_swx_ctl_table_info info;
40 struct rte_swx_ctl_table_match_field_info *mf;
42 /* Match field with the smallest offset. */
43 struct rte_swx_ctl_table_match_field_info *mf_first;
45 /* Match field with the biggest offset. */
46 struct rte_swx_ctl_table_match_field_info *mf_last;
48 struct rte_swx_ctl_table_action_info *actions;
49 struct rte_swx_table_ops ops;
50 struct rte_swx_table_params params;
52 /* Set of "stable" keys: these keys are currently part of the table;
53 * these keys will be preserved with no action data changes after the
56 struct rte_swx_table_entry_list entries;
58 /* Set of new keys: these keys are currently NOT part of the table;
59 * these keys will be added to the table on the next commit, if
60 * the commit operation is successful.
62 struct rte_swx_table_entry_list pending_add;
64 /* Set of keys to be modified: these keys are currently part of the
65 * table; these keys are still going to be part of the table after the
66 * next commit, but their action data will be modified if the commit
67 * operation is successful. The modify0 list contains the keys with the
68 * current action data, the modify1 list contains the keys with the
69 * modified action data.
71 struct rte_swx_table_entry_list pending_modify0;
72 struct rte_swx_table_entry_list pending_modify1;
74 /* Set of keys to be deleted: these keys are currently part of the
75 * table; these keys are to be deleted from the table on the next
76 * commit, if the commit operation is successful.
78 struct rte_swx_table_entry_list pending_delete;
80 /* The pending default action: this is NOT the current default action;
81 * this will be the new default action after the next commit, if the
82 * next commit operation is successful.
84 struct rte_swx_table_entry *pending_default;
92 struct rte_swx_ctl_pipeline {
93 struct rte_swx_ctl_pipeline_info info;
94 struct rte_swx_pipeline *p;
95 struct action *actions;
97 struct rte_swx_table_state *ts;
98 struct rte_swx_table_state *ts_next;
102 static struct action *
103 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
107 for (i = 0; i < ctl->info.n_actions; i++) {
108 struct action *a = &ctl->actions[i];
110 if (!strcmp(action_name, a->info.name))
118 action_free(struct rte_swx_ctl_pipeline *ctl)
125 for (i = 0; i < ctl->info.n_actions; i++) {
126 struct action *action = &ctl->actions[i];
135 static struct table *
136 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
140 for (i = 0; i < ctl->info.n_tables; i++) {
141 struct table *table = &ctl->tables[i];
143 if (!strcmp(table_name, table->info.name))
151 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
153 struct table *table = &ctl->tables[table_id];
154 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
155 uint8_t *key_mask = NULL;
156 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
157 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
159 if (table->info.n_match_fields) {
160 uint32_t n_match_fields_em = 0, i;
162 /* Find first (smallest offset) and last (biggest offset) match fields. */
163 first = &table->mf[0];
164 last = &table->mf[0];
166 for (i = 1; i < table->info.n_match_fields; i++) {
167 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
169 if (f->offset < first->offset)
172 if (f->offset > last->offset)
177 for (i = 0; i < table->info.n_match_fields; i++) {
178 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
180 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
184 if (n_match_fields_em == table->info.n_match_fields)
185 match_type = RTE_SWX_TABLE_MATCH_EXACT;
186 else if ((n_match_fields_em == table->info.n_match_fields - 1) &&
187 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
188 match_type = RTE_SWX_TABLE_MATCH_LPM;
191 key_offset = first->offset / 8;
194 key_size = (last->offset + last->n_bits - first->offset) / 8;
197 key_mask = calloc(1, key_size);
198 CHECK(key_mask, ENOMEM);
200 for (i = 0; i < table->info.n_match_fields; i++) {
201 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
205 start = (f->offset - first->offset) / 8;
206 size = f->n_bits / 8;
208 memset(&key_mask[start], 0xFF, size);
212 /* action_data_size. */
213 for (i = 0; i < table->info.n_actions; i++) {
214 uint32_t action_id = table->actions[i].action_id;
215 struct action *a = &ctl->actions[action_id];
217 if (a->data_size > action_data_size)
218 action_data_size = a->data_size;
222 table->params.match_type = match_type;
223 table->params.key_size = key_size;
224 table->params.key_offset = key_offset;
225 table->params.key_mask0 = key_mask;
226 table->params.action_data_size = action_data_size;
227 table->params.n_keys_max = table->info.size;
229 table->mf_first = first;
230 table->mf_last = last;
236 table_entry_free(struct rte_swx_table_entry *entry)
242 free(entry->key_mask);
243 free(entry->action_data);
247 static struct rte_swx_table_entry *
248 table_entry_alloc(struct table *table)
250 struct rte_swx_table_entry *entry;
252 entry = calloc(1, sizeof(struct rte_swx_table_entry));
257 if (!table->is_stub) {
258 entry->key = calloc(1, table->params.key_size);
262 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
263 entry->key_mask = calloc(1, table->params.key_size);
264 if (!entry->key_mask)
270 if (table->params.action_data_size) {
271 entry->action_data = calloc(1, table->params.action_data_size);
272 if (!entry->action_data)
279 table_entry_free(entry);
284 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
286 uint8_t *key_mask0 = table->params.key_mask0;
287 uint32_t key_size = table->params.key_size, i;
289 if (!entry->key_mask)
292 for (i = 0; i < key_size; i++) {
293 uint8_t km0 = key_mask0[i];
294 uint8_t km = entry->key_mask[i];
296 if ((km & km0) != km0)
304 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
306 struct rte_swx_table_entry *entry,
310 struct table *table = &ctl->tables[table_id];
313 CHECK(entry, EINVAL);
316 if (table->is_stub) {
318 CHECK(!entry->key, EINVAL);
321 CHECK(!entry->key_mask, EINVAL);
324 CHECK(entry->key, EINVAL);
327 switch (table->params.match_type) {
328 case RTE_SWX_TABLE_MATCH_WILDCARD:
331 case RTE_SWX_TABLE_MATCH_LPM:
332 /* TBD Check that key mask is prefix. */
335 case RTE_SWX_TABLE_MATCH_EXACT:
336 status = table_entry_key_check_em(table, entry);
352 for (i = 0; i < table->info.n_actions; i++)
353 if (entry->action_id == table->actions[i].action_id)
356 CHECK(i < table->info.n_actions, EINVAL);
359 a = &ctl->actions[entry->action_id];
360 CHECK(!(a->data_size && !entry->action_data), EINVAL);
366 static struct rte_swx_table_entry *
367 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
369 struct rte_swx_table_entry *entry,
373 struct table *table = &ctl->tables[table_id];
374 struct rte_swx_table_entry *new_entry = NULL;
379 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
383 if (key_duplicate && !table->is_stub) {
388 new_entry->key = malloc(table->params.key_size);
392 memcpy(new_entry->key, entry->key, table->params.key_size);
395 new_entry->key_signature = entry->key_signature;
398 if (entry->key_mask) {
399 new_entry->key_mask = malloc(table->params.key_size);
400 if (!new_entry->key_mask)
403 memcpy(new_entry->key_mask,
405 table->params.key_size);
409 new_entry->key_priority = entry->key_priority;
412 if (data_duplicate) {
417 for (i = 0; i < table->info.n_actions; i++)
418 if (entry->action_id == table->actions[i].action_id)
421 if (i >= table->info.n_actions)
424 new_entry->action_id = entry->action_id;
427 a = &ctl->actions[entry->action_id];
428 if (a->data_size && !entry->action_data)
431 /* The table layer provisions a constant action data size per
432 * entry, which should be the largest data size for all the
433 * actions enabled for the current table, and attempts to copy
434 * this many bytes each time a table entry is added, even if the
435 * specific action requires less data or even no data at all,
436 * hence we always have to allocate the max.
438 new_entry->action_data = calloc(1, table->params.action_data_size);
439 if (!new_entry->action_data)
443 memcpy(new_entry->action_data,
451 table_entry_free(new_entry);
456 table_entry_keycmp(struct table *table,
457 struct rte_swx_table_entry *e0,
458 struct rte_swx_table_entry *e1)
460 uint32_t key_size = table->params.key_size;
463 for (i = 0; i < key_size; i++) {
464 uint8_t *key_mask0 = table->params.key_mask0;
465 uint8_t km0, km[2], k[2];
467 km0 = key_mask0 ? key_mask0[i] : 0xFF;
469 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
470 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
475 /* Mask comparison. */
476 if ((km[0] & km0) != (km[1] & km0))
477 return 1; /* Not equal. */
479 /* Value comparison. */
480 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
481 return 1; /* Not equal. */
484 return 0; /* Equal. */
487 static struct rte_swx_table_entry *
488 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
490 struct rte_swx_table_entry *e;
492 TAILQ_FOREACH(e, &table->entries, node)
493 if (!table_entry_keycmp(table, entry, e))
494 return e; /* Found. */
496 return NULL; /* Not found. */
500 table_entries_free(struct table *table)
503 struct rte_swx_table_entry *entry;
505 entry = TAILQ_FIRST(&table->entries);
509 TAILQ_REMOVE(&table->entries, entry, node);
510 table_entry_free(entry);
514 static struct rte_swx_table_entry *
515 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
517 struct rte_swx_table_entry *e;
519 TAILQ_FOREACH(e, &table->pending_add, node)
520 if (!table_entry_keycmp(table, entry, e))
521 return e; /* Found. */
523 return NULL; /* Not found. */
527 table_pending_add_admit(struct table *table)
529 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
533 table_pending_add_free(struct table *table)
536 struct rte_swx_table_entry *entry;
538 entry = TAILQ_FIRST(&table->pending_add);
542 TAILQ_REMOVE(&table->pending_add, entry, node);
543 table_entry_free(entry);
547 static struct rte_swx_table_entry *
548 table_pending_modify0_find(struct table *table,
549 struct rte_swx_table_entry *entry)
551 struct rte_swx_table_entry *e;
553 TAILQ_FOREACH(e, &table->pending_modify0, node)
554 if (!table_entry_keycmp(table, entry, e))
555 return e; /* Found. */
557 return NULL; /* Not found. */
561 table_pending_modify0_admit(struct table *table)
563 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
567 table_pending_modify0_free(struct table *table)
570 struct rte_swx_table_entry *entry;
572 entry = TAILQ_FIRST(&table->pending_modify0);
576 TAILQ_REMOVE(&table->pending_modify0, entry, node);
577 table_entry_free(entry);
581 static struct rte_swx_table_entry *
582 table_pending_modify1_find(struct table *table,
583 struct rte_swx_table_entry *entry)
585 struct rte_swx_table_entry *e;
587 TAILQ_FOREACH(e, &table->pending_modify1, node)
588 if (!table_entry_keycmp(table, entry, e))
589 return e; /* Found. */
591 return NULL; /* Not found. */
595 table_pending_modify1_admit(struct table *table)
597 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
601 table_pending_modify1_free(struct table *table)
604 struct rte_swx_table_entry *entry;
606 entry = TAILQ_FIRST(&table->pending_modify1);
610 TAILQ_REMOVE(&table->pending_modify1, entry, node);
611 table_entry_free(entry);
615 static struct rte_swx_table_entry *
616 table_pending_delete_find(struct table *table,
617 struct rte_swx_table_entry *entry)
619 struct rte_swx_table_entry *e;
621 TAILQ_FOREACH(e, &table->pending_delete, node)
622 if (!table_entry_keycmp(table, entry, e))
623 return e; /* Found. */
625 return NULL; /* Not found. */
629 table_pending_delete_admit(struct table *table)
631 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
635 table_pending_delete_free(struct table *table)
638 struct rte_swx_table_entry *entry;
640 entry = TAILQ_FIRST(&table->pending_delete);
644 TAILQ_REMOVE(&table->pending_delete, entry, node);
645 table_entry_free(entry);
650 table_pending_default_free(struct table *table)
652 if (!table->pending_default)
655 free(table->pending_default->action_data);
656 free(table->pending_default);
657 table->pending_default = NULL;
661 table_is_update_pending(struct table *table, int consider_pending_default)
663 struct rte_swx_table_entry *e;
667 TAILQ_FOREACH(e, &table->pending_add, node)
670 /* Pending modify. */
671 TAILQ_FOREACH(e, &table->pending_modify1, node)
674 /* Pending delete. */
675 TAILQ_FOREACH(e, &table->pending_delete, node)
678 /* Pending default. */
679 if (consider_pending_default && table->pending_default)
686 table_free(struct rte_swx_ctl_pipeline *ctl)
693 for (i = 0; i < ctl->info.n_tables; i++) {
694 struct table *table = &ctl->tables[i];
697 free(table->actions);
698 free(table->params.key_mask0);
700 table_entries_free(table);
701 table_pending_add_free(table);
702 table_pending_modify0_free(table);
703 table_pending_modify1_free(table);
704 table_pending_delete_free(table);
705 table_pending_default_free(table);
713 table_state_free(struct rte_swx_ctl_pipeline *ctl)
720 /* For each table, free its table state. */
721 for (i = 0; i < ctl->info.n_tables; i++) {
722 struct table *table = &ctl->tables[i];
723 struct rte_swx_table_state *ts = &ctl->ts_next[i];
725 /* Default action data. */
726 free(ts->default_action_data);
729 if (!table->is_stub && table->ops.free && ts->obj)
730 table->ops.free(ts->obj);
738 table_state_create(struct rte_swx_ctl_pipeline *ctl)
743 ctl->ts_next = calloc(ctl->info.n_tables,
744 sizeof(struct rte_swx_table_state));
750 for (i = 0; i < ctl->info.n_tables; i++) {
751 struct table *table = &ctl->tables[i];
752 struct rte_swx_table_state *ts = &ctl->ts[i];
753 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
756 if (!table->is_stub && table->ops.add) {
757 ts_next->obj = table->ops.create(&table->params,
767 if (!table->is_stub && !table->ops.add)
768 ts_next->obj = ts->obj;
770 /* Default action data: duplicate from current table state. */
771 ts_next->default_action_data =
772 malloc(table->params.action_data_size);
773 if (!ts_next->default_action_data) {
778 memcpy(ts_next->default_action_data,
779 ts->default_action_data,
780 table->params.action_data_size);
782 ts_next->default_action_id = ts->default_action_id;
788 table_state_free(ctl);
793 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
800 table_state_free(ctl);
807 struct rte_swx_ctl_pipeline *
808 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
810 struct rte_swx_ctl_pipeline *ctl = NULL;
817 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
822 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
827 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
835 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
839 for (i = 0; i < ctl->info.n_actions; i++) {
840 struct action *a = &ctl->actions[i];
844 status = rte_swx_ctl_action_info_get(p, i, &a->info);
849 a->args = calloc(a->info.n_args,
850 sizeof(struct rte_swx_ctl_action_arg_info));
854 for (j = 0; j < a->info.n_args; j++) {
855 status = rte_swx_ctl_action_arg_info_get(p,
864 for (j = 0; j < a->info.n_args; j++) {
865 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
867 a->data_size += info->n_bits;
870 a->data_size = (a->data_size + 7) / 8;
874 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
878 for (i = 0; i < ctl->info.n_tables; i++) {
879 struct table *t = &ctl->tables[i];
881 TAILQ_INIT(&t->entries);
882 TAILQ_INIT(&t->pending_add);
883 TAILQ_INIT(&t->pending_modify0);
884 TAILQ_INIT(&t->pending_modify1);
885 TAILQ_INIT(&t->pending_delete);
888 for (i = 0; i < ctl->info.n_tables; i++) {
889 struct table *t = &ctl->tables[i];
893 status = rte_swx_ctl_table_info_get(p, i, &t->info);
898 t->mf = calloc(t->info.n_match_fields,
899 sizeof(struct rte_swx_ctl_table_match_field_info));
903 for (j = 0; j < t->info.n_match_fields; j++) {
904 status = rte_swx_ctl_table_match_field_info_get(p,
913 t->actions = calloc(t->info.n_actions,
914 sizeof(struct rte_swx_ctl_table_action_info));
918 for (j = 0; j < t->info.n_actions; j++) {
919 status = rte_swx_ctl_table_action_info_get(p,
924 t->actions[j].action_id >= ctl->info.n_actions)
929 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
933 if ((t->is_stub && t->info.n_match_fields) ||
934 (!t->is_stub && !t->info.n_match_fields))
938 status = table_params_get(ctl, i);
944 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
949 status = table_state_create(ctl);
956 rte_swx_ctl_pipeline_free(ctl);
961 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
962 const char *table_name,
963 struct rte_swx_table_entry *entry)
966 struct rte_swx_table_entry *new_entry, *existing_entry;
970 CHECK(table_name && table_name[0], EINVAL);
972 table = table_find(ctl, table_name);
973 CHECK(table, EINVAL);
974 table_id = table - ctl->tables;
976 CHECK(entry, EINVAL);
977 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
979 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
980 CHECK(new_entry, ENOMEM);
982 /* The new entry is found in the table->entries list:
983 * - Add the new entry to the table->pending_modify1 list;
984 * - Move the existing entry from the table->entries list to the
985 * table->pending_modify0 list.
987 existing_entry = table_entries_find(table, entry);
988 if (existing_entry) {
989 TAILQ_INSERT_TAIL(&table->pending_modify1,
993 TAILQ_REMOVE(&table->entries,
997 TAILQ_INSERT_TAIL(&table->pending_modify0,
1004 /* The new entry is found in the table->pending_add list:
1005 * - Replace the entry in the table->pending_add list with the new entry
1006 * (and free the replaced entry).
1008 existing_entry = table_pending_add_find(table, entry);
1009 if (existing_entry) {
1010 TAILQ_INSERT_AFTER(&table->pending_add,
1015 TAILQ_REMOVE(&table->pending_add,
1019 table_entry_free(existing_entry);
1024 /* The new entry is found in the table->pending_modify1 list:
1025 * - Replace the entry in the table->pending_modify1 list with the new
1026 * entry (and free the replaced entry).
1028 existing_entry = table_pending_modify1_find(table, entry);
1029 if (existing_entry) {
1030 TAILQ_INSERT_AFTER(&table->pending_modify1,
1035 TAILQ_REMOVE(&table->pending_modify1,
1039 table_entry_free(existing_entry);
1044 /* The new entry is found in the table->pending_delete list:
1045 * - Add the new entry to the table->pending_modify1 list;
1046 * - Move the existing entry from the table->pending_delete list to the
1047 * table->pending_modify0 list.
1049 existing_entry = table_pending_delete_find(table, entry);
1050 if (existing_entry) {
1051 TAILQ_INSERT_TAIL(&table->pending_modify1,
1055 TAILQ_REMOVE(&table->pending_delete,
1059 TAILQ_INSERT_TAIL(&table->pending_modify0,
1066 /* The new entry is not found in any of the above lists:
1067 * - Add the new entry to the table->pending_add list.
1069 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1075 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1076 const char *table_name,
1077 struct rte_swx_table_entry *entry)
1079 struct table *table;
1080 struct rte_swx_table_entry *existing_entry;
1085 CHECK(table_name && table_name[0], EINVAL);
1086 table = table_find(ctl, table_name);
1087 CHECK(table, EINVAL);
1088 table_id = table - ctl->tables;
1090 CHECK(entry, EINVAL);
1091 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1093 /* The entry is found in the table->entries list:
1094 * - Move the existing entry from the table->entries list to to the
1095 * table->pending_delete list.
1097 existing_entry = table_entries_find(table, entry);
1098 if (existing_entry) {
1099 TAILQ_REMOVE(&table->entries,
1103 TAILQ_INSERT_TAIL(&table->pending_delete,
1110 /* The entry is found in the table->pending_add list:
1111 * - Remove the entry from the table->pending_add list and free it.
1113 existing_entry = table_pending_add_find(table, entry);
1114 if (existing_entry) {
1115 TAILQ_REMOVE(&table->pending_add,
1119 table_entry_free(existing_entry);
1122 /* The entry is found in the table->pending_modify1 list:
1123 * - Free the entry in the table->pending_modify1 list;
1124 * - Move the existing entry from the table->pending_modify0 list to the
1125 * table->pending_delete list.
1127 existing_entry = table_pending_modify1_find(table, entry);
1128 if (existing_entry) {
1129 struct rte_swx_table_entry *real_existing_entry;
1131 TAILQ_REMOVE(&table->pending_modify1,
1135 table_entry_free(existing_entry);
1137 real_existing_entry = table_pending_modify0_find(table, entry);
1138 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1140 TAILQ_REMOVE(&table->pending_modify0,
1141 real_existing_entry,
1144 TAILQ_INSERT_TAIL(&table->pending_delete,
1145 real_existing_entry,
1151 /* The entry is found in the table->pending_delete list:
1152 * - Do nothing: the existing entry is already in the
1153 * table->pending_delete list, i.e. already marked for delete, so
1154 * simply keep it there as it is.
1157 /* The entry is not found in any of the above lists:
1158 * - Do nothing: no existing entry to delete.
1165 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1166 const char *table_name,
1167 struct rte_swx_table_entry *entry)
1169 struct table *table;
1170 struct rte_swx_table_entry *new_entry;
1175 CHECK(table_name && table_name[0], EINVAL);
1176 table = table_find(ctl, table_name);
1177 CHECK(table, EINVAL);
1178 table_id = table - ctl->tables;
1179 CHECK(!table->info.default_action_is_const, EINVAL);
1181 CHECK(entry, EINVAL);
1182 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1184 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1185 CHECK(new_entry, ENOMEM);
1187 table_pending_default_free(table);
1189 table->pending_default = new_entry;
1195 table_entry_list_free(struct rte_swx_table_entry_list *list)
1198 struct rte_swx_table_entry *entry;
1200 entry = TAILQ_FIRST(list);
1204 TAILQ_REMOVE(list, entry, node);
1205 table_entry_free(entry);
1210 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1212 struct rte_swx_table_entry_list *dst,
1213 struct rte_swx_table_entry_list *src)
1215 struct rte_swx_table_entry *src_entry;
1217 TAILQ_FOREACH(src_entry, src, node) {
1218 struct rte_swx_table_entry *dst_entry;
1220 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1224 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1230 table_entry_list_free(dst);
1234 /* This commit stage contains all the operations that can fail; in case ANY of
1235 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1238 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1240 uint32_t after_swap)
1242 struct table *table = &ctl->tables[table_id];
1243 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1244 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1246 if (table->is_stub || !table_is_update_pending(table, 0))
1250 * Current table supports incremental update.
1252 if (table->ops.add) {
1253 /* Reset counters. */
1255 table->n_modify = 0;
1256 table->n_delete = 0;
1258 /* Add pending rules. */
1259 struct rte_swx_table_entry *entry;
1261 TAILQ_FOREACH(entry, &table->pending_add, node) {
1264 status = table->ops.add(ts_next->obj, entry);
1271 /* Modify pending rules. */
1272 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1275 status = table->ops.add(ts_next->obj, entry);
1282 /* Delete pending rules. */
1283 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1286 status = table->ops.del(ts_next->obj, entry);
1297 * Current table does NOT support incremental update.
1300 struct rte_swx_table_entry_list list;
1303 /* Create updated list of entries included. */
1306 status = table_entry_list_duplicate(ctl,
1313 status = table_entry_list_duplicate(ctl,
1316 &table->pending_add);
1320 status = table_entry_list_duplicate(ctl,
1323 &table->pending_modify1);
1327 /* Create new table object with the updates included. */
1328 ts_next->obj = table->ops.create(&table->params,
1332 if (!ts_next->obj) {
1337 table_entry_list_free(&list);
1342 table_entry_list_free(&list);
1346 /* Free the old table object. */
1347 if (ts_next->obj && table->ops.free)
1348 table->ops.free(ts_next->obj);
1350 /* Copy over the new table object. */
1351 ts_next->obj = ts->obj;
1356 /* This commit stage contains all the operations that cannot fail. They are
1357 * executed only if the previous stage was successful for ALL the tables. Hence,
1358 * none of these operations has to be rolled back for ANY table.
1361 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1363 struct table *table = &ctl->tables[table_id];
1364 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1366 uint8_t *action_data;
1369 /* Copy the pending default entry. */
1370 if (!table->pending_default)
1373 action_id = table->pending_default->action_id;
1374 action_data = table->pending_default->action_data;
1375 a = &ctl->actions[action_id];
1377 memcpy(ts_next->default_action_data,
1381 ts_next->default_action_id = action_id;
1384 /* This last commit stage is simply finalizing a successful commit operation.
1385 * This stage is only executed if all the previous stages were successful. This
1386 * stage cannot fail.
1389 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1391 struct table *table = &ctl->tables[table_id];
1393 /* Move all the pending add entries to the table, as they are now part
1396 table_pending_add_admit(table);
1398 /* Move all the pending modify1 entries to table, are they are now part
1399 * of the table. Free up all the pending modify0 entries, as they are no
1400 * longer part of the table.
1402 table_pending_modify1_admit(table);
1403 table_pending_modify0_free(table);
1405 /* Free up all the pending delete entries, as they are no longer part of
1408 table_pending_delete_free(table);
1410 /* Free up the pending default entry, as it is now part of the table. */
1411 table_pending_default_free(table);
1414 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1415 * commit operations that can fail did fail for ANY table. It reverts ALL the
1416 * tables to their state before the commit started, as if the commit never
1420 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1422 struct table *table = &ctl->tables[table_id];
1423 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1425 if (table->is_stub || !table_is_update_pending(table, 0))
1428 if (table->ops.add) {
1429 struct rte_swx_table_entry *entry;
1431 /* Add back all the entries that were just deleted. */
1432 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1433 if (!table->n_delete)
1436 table->ops.add(ts_next->obj, entry);
1440 /* Add back the old copy for all the entries that were just
1443 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1444 if (!table->n_modify)
1447 table->ops.add(ts_next->obj, entry);
1451 /* Delete all the entries that were just added. */
1452 TAILQ_FOREACH(entry, &table->pending_add, node) {
1456 table->ops.del(ts_next->obj, entry);
1460 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1462 /* Free the new table object, as update was cancelled. */
1463 if (ts_next->obj && table->ops.free)
1464 table->ops.free(ts_next->obj);
1466 /* Reinstate the old table object. */
1467 ts_next->obj = ts->obj;
1471 /* This stage is conditionally executed (as instructed by the user) after a
1472 * failed commit operation to remove ALL the pending work for ALL the tables.
1475 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1477 struct table *table = &ctl->tables[table_id];
1479 /* Free up all the pending add entries, as none of them is part of the
1482 table_pending_add_free(table);
1484 /* Free up all the pending modify1 entries, as none of them made it to
1485 * the table. Add back all the pending modify0 entries, as none of them
1486 * was deleted from the table.
1488 table_pending_modify1_free(table);
1489 table_pending_modify0_admit(table);
1491 /* Add back all the pending delete entries, as none of them was deleted
1494 table_pending_delete_admit(table);
1496 /* Free up the pending default entry, as it is no longer going to be
1497 * added to the table.
1499 table_pending_default_free(table);
1503 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1505 struct rte_swx_table_state *ts;
1511 /* Operate the changes on the current ts_next before it becomes the new
1514 for (i = 0; i < ctl->info.n_tables; i++) {
1515 status = table_rollfwd0(ctl, i, 0);
1520 for (i = 0; i < ctl->info.n_tables; i++)
1521 table_rollfwd1(ctl, i);
1523 /* Swap the table state for the data plane. The current ts and ts_next
1524 * become the new ts_next and ts, respectively.
1526 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1529 ctl->ts = ctl->ts_next;
1532 /* Operate the changes on the current ts_next, which is the previous ts.
1534 for (i = 0; i < ctl->info.n_tables; i++) {
1535 table_rollfwd0(ctl, i, 1);
1536 table_rollfwd1(ctl, i);
1537 table_rollfwd2(ctl, i);
1543 for (i = 0; i < ctl->info.n_tables; i++) {
1544 table_rollback(ctl, i);
1546 table_abort(ctl, i);
1553 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1560 for (i = 0; i < ctl->info.n_tables; i++)
1561 table_abort(ctl, i);
1565 token_is_comment(const char *token)
1567 if ((token[0] == '#') ||
1568 (token[0] == ';') ||
1569 ((token[0] == '/') && (token[1] == '/')))
1570 return 1; /* TRUE. */
1572 return 0; /* FALSE. */
1575 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1577 struct rte_swx_table_entry *
1578 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1579 const char *table_name,
1581 int *is_blank_or_comment)
1583 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1584 struct table *table;
1585 struct action *action;
1586 struct rte_swx_table_entry *entry = NULL;
1587 char *s0 = NULL, *s;
1588 uint32_t n_tokens = 0, arg_offset = 0, i;
1589 int blank_or_comment = 0;
1591 /* Check input arguments. */
1595 if (!table_name || !table_name[0])
1598 table = table_find(ctl, table_name);
1602 if (!string || !string[0])
1605 /* Memory allocation. */
1606 s0 = strdup(string);
1610 entry = table_entry_alloc(table);
1614 /* Parse the string into tokens. */
1618 token = strtok_r(s, " \f\n\r\t\v", &s);
1619 if (!token || token_is_comment(token))
1622 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1625 token_array[n_tokens] = token;
1630 blank_or_comment = 1;
1634 tokens = token_array;
1639 if (n_tokens && strcmp(tokens[0], "match"))
1642 if (n_tokens < 1 + table->info.n_match_fields)
1645 for (i = 0; i < table->info.n_match_fields; i++) {
1646 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1647 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1648 uint64_t val, mask = UINT64_MAX;
1649 uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
1654 mf_mask = strchr(mf_val, '/');
1660 mask = strtoull(mf_mask, &mf_mask, 0);
1664 /* Endianness conversion. */
1666 mask = field_hton(mask, mf->n_bits);
1669 /* Copy to entry. */
1670 if (entry->key_mask)
1671 memcpy(&entry->key_mask[offset],
1679 val = strtoull(mf_val, &mf_val, 0);
1683 /* Endianness conversion. */
1685 val = field_hton(val, mf->n_bits);
1687 /* Copy to entry. */
1688 memcpy(&entry->key[offset],
1693 tokens += 1 + table->info.n_match_fields;
1694 n_tokens -= 1 + table->info.n_match_fields;
1699 if (n_tokens && !strcmp(tokens[0], "priority")) {
1700 char *priority = tokens[1];
1707 val = strtoul(priority, &priority, 0);
1711 /* Copy to entry. */
1712 entry->key_priority = val;
1722 if (n_tokens && strcmp(tokens[0], "action"))
1728 action = action_find(ctl, tokens[1]);
1732 if (n_tokens < 2 + action->info.n_args * 2)
1736 entry->action_id = action - ctl->actions;
1739 for (i = 0; i < action->info.n_args; i++) {
1740 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1741 char *arg_name, *arg_val;
1744 arg_name = tokens[2 + i * 2];
1745 arg_val = tokens[2 + i * 2 + 1];
1747 if (strcmp(arg_name, arg->name))
1750 val = strtoull(arg_val, &arg_val, 0);
1754 /* Endianness conversion. */
1755 if (arg->is_network_byte_order)
1756 val = field_hton(val, arg->n_bits);
1758 /* Copy to entry. */
1759 memcpy(&entry->action_data[arg_offset],
1763 arg_offset += arg->n_bits / 8;
1766 tokens += 2 + action->info.n_args * 2;
1767 n_tokens -= 2 + action->info.n_args * 2;
1777 table_entry_free(entry);
1779 if (is_blank_or_comment)
1780 *is_blank_or_comment = blank_or_comment;
1785 table_entry_printf(FILE *f,
1786 struct rte_swx_ctl_pipeline *ctl,
1787 struct table *table,
1788 struct rte_swx_table_entry *entry)
1790 struct action *action = &ctl->actions[entry->action_id];
1793 fprintf(f, "match ");
1794 for (i = 0; i < table->params.key_size; i++)
1795 fprintf(f, "%02x", entry->key[i]);
1797 if (entry->key_mask) {
1799 for (i = 0; i < table->params.key_size; i++)
1800 fprintf(f, "%02x", entry->key_mask[i]);
1803 fprintf(f, " priority %u", entry->key_priority);
1805 fprintf(f, " action %s ", action->info.name);
1806 for (i = 0; i < action->data_size; i++)
1807 fprintf(f, "%02x", entry->action_data[i]);
1813 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1814 struct rte_swx_ctl_pipeline *ctl,
1815 const char *table_name)
1817 struct table *table;
1818 struct rte_swx_table_entry *entry;
1819 uint32_t n_entries = 0, i;
1821 if (!f || !ctl || !table_name || !table_name[0])
1824 table = table_find(ctl, table_name);
1829 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1831 table->params.key_size,
1832 table->params.key_offset);
1834 for (i = 0; i < table->params.key_size; i++)
1835 fprintf(f, "%02x", table->params.key_mask0[i]);
1837 fprintf(f, "], action data size %u bytes\n",
1838 table->params.action_data_size);
1840 /* Table entries. */
1841 TAILQ_FOREACH(entry, &table->entries, node) {
1842 table_entry_printf(f, ctl, table, entry);
1846 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1847 table_entry_printf(f, ctl, table, entry);
1851 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1852 table_entry_printf(f, ctl, table, entry);
1856 fprintf(f, "# Table %s currently has %u entries.\n",