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;
41 struct rte_swx_ctl_table_action_info *actions;
42 struct rte_swx_table_ops ops;
43 struct rte_swx_table_params params;
45 /* Set of "stable" keys: these keys are currently part of the table;
46 * these keys will be preserved with no action data changes after the
49 struct rte_swx_table_entry_list entries;
51 /* Set of new keys: these keys are currently NOT part of the table;
52 * these keys will be added to the table on the next commit, if
53 * the commit operation is successful.
55 struct rte_swx_table_entry_list pending_add;
57 /* Set of keys to be modified: these keys are currently part of the
58 * table; these keys are still going to be part of the table after the
59 * next commit, but their action data will be modified if the commit
60 * operation is successful. The modify0 list contains the keys with the
61 * current action data, the modify1 list contains the keys with the
62 * modified action data.
64 struct rte_swx_table_entry_list pending_modify0;
65 struct rte_swx_table_entry_list pending_modify1;
67 /* Set of keys to be deleted: these keys are currently part of the
68 * table; these keys are to be deleted from the table on the next
69 * commit, if the commit operation is successful.
71 struct rte_swx_table_entry_list pending_delete;
73 /* The pending default action: this is NOT the current default action;
74 * this will be the new default action after the next commit, if the
75 * next commit operation is successful.
77 struct rte_swx_table_entry *pending_default;
85 struct rte_swx_ctl_pipeline {
86 struct rte_swx_ctl_pipeline_info info;
87 struct rte_swx_pipeline *p;
88 struct action *actions;
90 struct rte_swx_table_state *ts;
91 struct rte_swx_table_state *ts_next;
95 static struct action *
96 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
100 for (i = 0; i < ctl->info.n_actions; i++) {
101 struct action *a = &ctl->actions[i];
103 if (!strcmp(action_name, a->info.name))
111 action_free(struct rte_swx_ctl_pipeline *ctl)
118 for (i = 0; i < ctl->info.n_actions; i++) {
119 struct action *action = &ctl->actions[i];
128 static struct table *
129 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
133 for (i = 0; i < ctl->info.n_tables; i++) {
134 struct table *table = &ctl->tables[i];
136 if (!strcmp(table_name, table->info.name))
144 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
146 struct table *table = &ctl->tables[table_id];
147 uint8_t *key_mask = NULL;
148 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
149 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
151 if (table->info.n_match_fields) {
152 struct rte_swx_ctl_table_match_field_info *first, *last;
155 first = &table->mf[0];
156 last = &table->mf[table->info.n_match_fields - 1];
159 for (i = 0; i < table->info.n_match_fields; i++) {
160 struct rte_swx_ctl_table_match_field_info *f;
163 if (f->match_type != RTE_SWX_TABLE_MATCH_EXACT)
167 if (i == table->info.n_match_fields)
168 match_type = RTE_SWX_TABLE_MATCH_EXACT;
169 else if ((i == table->info.n_match_fields - 1) &&
170 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
171 match_type = RTE_SWX_TABLE_MATCH_LPM;
174 key_offset = first->offset / 8;
177 key_size = (last->offset + last->n_bits - first->offset) / 8;
180 key_mask = calloc(1, key_size);
181 CHECK(key_mask, ENOMEM);
183 for (i = 0; i < table->info.n_match_fields; i++) {
184 struct rte_swx_ctl_table_match_field_info *f;
189 start = (f->offset - first->offset) / 8;
190 size = f->n_bits / 8;
192 memset(&key_mask[start], 0xFF, size);
196 /* action_data_size. */
197 for (i = 0; i < table->info.n_actions; i++) {
198 uint32_t action_id = table->actions[i].action_id;
199 struct action *a = &ctl->actions[action_id];
201 if (a->data_size > action_data_size)
202 action_data_size = a->data_size;
206 table->params.match_type = match_type;
207 table->params.key_size = key_size;
208 table->params.key_offset = key_offset;
209 table->params.key_mask0 = key_mask;
210 table->params.action_data_size = action_data_size;
211 table->params.n_keys_max = table->info.size;
217 table_entry_free(struct rte_swx_table_entry *entry)
223 free(entry->key_mask);
224 free(entry->action_data);
228 static struct rte_swx_table_entry *
229 table_entry_alloc(struct table *table)
231 struct rte_swx_table_entry *entry;
233 entry = calloc(1, sizeof(struct rte_swx_table_entry));
238 if (!table->is_stub) {
239 entry->key = calloc(1, table->params.key_size);
243 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
244 entry->key_mask = calloc(1, table->params.key_size);
245 if (!entry->key_mask)
251 if (table->params.action_data_size) {
252 entry->action_data = calloc(1, table->params.action_data_size);
253 if (!entry->action_data)
260 table_entry_free(entry);
265 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
267 uint8_t *key_mask0 = table->params.key_mask0;
268 uint32_t key_size = table->params.key_size, i;
270 if (!entry->key_mask)
273 for (i = 0; i < key_size; i++) {
274 uint8_t km0 = key_mask0[i];
275 uint8_t km = entry->key_mask[i];
277 if ((km & km0) != km0)
285 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
287 struct rte_swx_table_entry *entry,
291 struct table *table = &ctl->tables[table_id];
294 CHECK(entry, EINVAL);
297 if (table->is_stub) {
299 CHECK(!entry->key, EINVAL);
302 CHECK(!entry->key_mask, EINVAL);
305 CHECK(entry->key, EINVAL);
308 switch (table->params.match_type) {
309 case RTE_SWX_TABLE_MATCH_WILDCARD:
312 case RTE_SWX_TABLE_MATCH_LPM:
313 /* TBD Check that key mask is prefix. */
316 case RTE_SWX_TABLE_MATCH_EXACT:
317 status = table_entry_key_check_em(table, entry);
333 for (i = 0; i < table->info.n_actions; i++)
334 if (entry->action_id == table->actions[i].action_id)
337 CHECK(i < table->info.n_actions, EINVAL);
340 a = &ctl->actions[entry->action_id];
341 CHECK((a->data_size && entry->action_data) ||
342 (!a->data_size && !entry->action_data), EINVAL);
348 static struct rte_swx_table_entry *
349 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
351 struct rte_swx_table_entry *entry,
355 struct table *table = &ctl->tables[table_id];
356 struct rte_swx_table_entry *new_entry = NULL;
361 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
365 if (key_duplicate && !table->is_stub) {
370 new_entry->key = malloc(table->params.key_size);
374 memcpy(new_entry->key, entry->key, table->params.key_size);
377 new_entry->key_signature = entry->key_signature;
380 if (entry->key_mask) {
381 new_entry->key_mask = malloc(table->params.key_size);
382 if (!new_entry->key_mask)
385 memcpy(new_entry->key_mask,
387 table->params.key_size);
391 new_entry->key_priority = entry->key_priority;
394 if (data_duplicate) {
399 for (i = 0; i < table->info.n_actions; i++)
400 if (entry->action_id == table->actions[i].action_id)
403 if (i >= table->info.n_actions)
406 new_entry->action_id = entry->action_id;
409 a = &ctl->actions[entry->action_id];
410 if (a->data_size && !entry->action_data)
413 /* The table layer provisions a constant action data size per
414 * entry, which should be the largest data size for all the
415 * actions enabled for the current table, and attempts to copy
416 * this many bytes each time a table entry is added, even if the
417 * specific action requires less data or even no data at all,
418 * hence we always have to allocate the max.
420 new_entry->action_data = calloc(1, table->params.action_data_size);
421 if (!new_entry->action_data)
425 memcpy(new_entry->action_data,
433 table_entry_free(new_entry);
438 table_entry_keycmp(struct table *table,
439 struct rte_swx_table_entry *e0,
440 struct rte_swx_table_entry *e1)
442 uint32_t key_size = table->params.key_size;
445 for (i = 0; i < key_size; i++) {
446 uint8_t *key_mask0 = table->params.key_mask0;
447 uint8_t km0, km[2], k[2];
449 km0 = key_mask0 ? key_mask0[i] : 0xFF;
451 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
452 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
457 /* Mask comparison. */
458 if ((km[0] & km0) != (km[1] & km0))
459 return 1; /* Not equal. */
461 /* Value comparison. */
462 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
463 return 1; /* Not equal. */
466 return 0; /* Equal. */
469 static struct rte_swx_table_entry *
470 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
472 struct rte_swx_table_entry *e;
474 TAILQ_FOREACH(e, &table->entries, node)
475 if (!table_entry_keycmp(table, entry, e))
476 return e; /* Found. */
478 return NULL; /* Not found. */
482 table_entries_free(struct table *table)
485 struct rte_swx_table_entry *entry;
487 entry = TAILQ_FIRST(&table->entries);
491 TAILQ_REMOVE(&table->entries, entry, node);
492 table_entry_free(entry);
496 static struct rte_swx_table_entry *
497 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
499 struct rte_swx_table_entry *e;
501 TAILQ_FOREACH(e, &table->pending_add, node)
502 if (!table_entry_keycmp(table, entry, e))
503 return e; /* Found. */
505 return NULL; /* Not found. */
509 table_pending_add_admit(struct table *table)
511 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
515 table_pending_add_free(struct table *table)
518 struct rte_swx_table_entry *entry;
520 entry = TAILQ_FIRST(&table->pending_add);
524 TAILQ_REMOVE(&table->pending_add, entry, node);
525 table_entry_free(entry);
529 static struct rte_swx_table_entry *
530 table_pending_modify0_find(struct table *table,
531 struct rte_swx_table_entry *entry)
533 struct rte_swx_table_entry *e;
535 TAILQ_FOREACH(e, &table->pending_modify0, node)
536 if (!table_entry_keycmp(table, entry, e))
537 return e; /* Found. */
539 return NULL; /* Not found. */
543 table_pending_modify0_admit(struct table *table)
545 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
549 table_pending_modify0_free(struct table *table)
552 struct rte_swx_table_entry *entry;
554 entry = TAILQ_FIRST(&table->pending_modify0);
558 TAILQ_REMOVE(&table->pending_modify0, entry, node);
559 table_entry_free(entry);
563 static struct rte_swx_table_entry *
564 table_pending_modify1_find(struct table *table,
565 struct rte_swx_table_entry *entry)
567 struct rte_swx_table_entry *e;
569 TAILQ_FOREACH(e, &table->pending_modify1, node)
570 if (!table_entry_keycmp(table, entry, e))
571 return e; /* Found. */
573 return NULL; /* Not found. */
577 table_pending_modify1_admit(struct table *table)
579 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
583 table_pending_modify1_free(struct table *table)
586 struct rte_swx_table_entry *entry;
588 entry = TAILQ_FIRST(&table->pending_modify1);
592 TAILQ_REMOVE(&table->pending_modify1, entry, node);
593 table_entry_free(entry);
597 static struct rte_swx_table_entry *
598 table_pending_delete_find(struct table *table,
599 struct rte_swx_table_entry *entry)
601 struct rte_swx_table_entry *e;
603 TAILQ_FOREACH(e, &table->pending_delete, node)
604 if (!table_entry_keycmp(table, entry, e))
605 return e; /* Found. */
607 return NULL; /* Not found. */
611 table_pending_delete_admit(struct table *table)
613 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
617 table_pending_delete_free(struct table *table)
620 struct rte_swx_table_entry *entry;
622 entry = TAILQ_FIRST(&table->pending_delete);
626 TAILQ_REMOVE(&table->pending_delete, entry, node);
627 table_entry_free(entry);
632 table_pending_default_free(struct table *table)
634 if (!table->pending_default)
637 free(table->pending_default->action_data);
638 free(table->pending_default);
639 table->pending_default = NULL;
643 table_is_update_pending(struct table *table, int consider_pending_default)
645 struct rte_swx_table_entry *e;
649 TAILQ_FOREACH(e, &table->pending_add, node)
652 /* Pending modify. */
653 TAILQ_FOREACH(e, &table->pending_modify1, node)
656 /* Pending delete. */
657 TAILQ_FOREACH(e, &table->pending_delete, node)
660 /* Pending default. */
661 if (consider_pending_default && table->pending_default)
668 table_free(struct rte_swx_ctl_pipeline *ctl)
675 for (i = 0; i < ctl->info.n_tables; i++) {
676 struct table *table = &ctl->tables[i];
679 free(table->actions);
680 free(table->params.key_mask0);
682 table_entries_free(table);
683 table_pending_add_free(table);
684 table_pending_modify0_free(table);
685 table_pending_modify1_free(table);
686 table_pending_delete_free(table);
687 table_pending_default_free(table);
695 table_state_free(struct rte_swx_ctl_pipeline *ctl)
702 /* For each table, free its table state. */
703 for (i = 0; i < ctl->info.n_tables; i++) {
704 struct table *table = &ctl->tables[i];
705 struct rte_swx_table_state *ts = &ctl->ts_next[i];
707 /* Default action data. */
708 free(ts->default_action_data);
711 if (!table->is_stub && table->ops.free && ts->obj)
712 table->ops.free(ts->obj);
720 table_state_create(struct rte_swx_ctl_pipeline *ctl)
725 ctl->ts_next = calloc(ctl->info.n_tables,
726 sizeof(struct rte_swx_table_state));
732 for (i = 0; i < ctl->info.n_tables; i++) {
733 struct table *table = &ctl->tables[i];
734 struct rte_swx_table_state *ts = &ctl->ts[i];
735 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
738 if (!table->is_stub && table->ops.add) {
739 ts_next->obj = table->ops.create(&table->params,
749 if (!table->is_stub && !table->ops.add)
750 ts_next->obj = ts->obj;
752 /* Default action data: duplicate from current table state. */
753 ts_next->default_action_data =
754 malloc(table->params.action_data_size);
755 if (!ts_next->default_action_data) {
760 memcpy(ts_next->default_action_data,
761 ts->default_action_data,
762 table->params.action_data_size);
764 ts_next->default_action_id = ts->default_action_id;
770 table_state_free(ctl);
775 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
782 table_state_free(ctl);
789 struct rte_swx_ctl_pipeline *
790 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
792 struct rte_swx_ctl_pipeline *ctl = NULL;
799 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
804 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
809 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
817 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
821 for (i = 0; i < ctl->info.n_actions; i++) {
822 struct action *a = &ctl->actions[i];
826 status = rte_swx_ctl_action_info_get(p, i, &a->info);
831 a->args = calloc(a->info.n_args,
832 sizeof(struct rte_swx_ctl_action_arg_info));
836 for (j = 0; j < a->info.n_args; j++) {
837 status = rte_swx_ctl_action_arg_info_get(p,
846 for (j = 0; j < a->info.n_args; j++) {
847 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
849 a->data_size += info->n_bits;
852 a->data_size = (a->data_size + 7) / 8;
856 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
860 for (i = 0; i < ctl->info.n_tables; i++) {
861 struct table *t = &ctl->tables[i];
863 TAILQ_INIT(&t->entries);
864 TAILQ_INIT(&t->pending_add);
865 TAILQ_INIT(&t->pending_modify0);
866 TAILQ_INIT(&t->pending_modify1);
867 TAILQ_INIT(&t->pending_delete);
870 for (i = 0; i < ctl->info.n_tables; i++) {
871 struct table *t = &ctl->tables[i];
875 status = rte_swx_ctl_table_info_get(p, i, &t->info);
880 t->mf = calloc(t->info.n_match_fields,
881 sizeof(struct rte_swx_ctl_table_match_field_info));
885 for (j = 0; j < t->info.n_match_fields; j++) {
886 status = rte_swx_ctl_table_match_field_info_get(p,
895 t->actions = calloc(t->info.n_actions,
896 sizeof(struct rte_swx_ctl_table_action_info));
900 for (j = 0; j < t->info.n_actions; j++) {
901 status = rte_swx_ctl_table_action_info_get(p,
906 t->actions[j].action_id >= ctl->info.n_actions)
911 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
915 if ((t->is_stub && t->info.n_match_fields) ||
916 (!t->is_stub && !t->info.n_match_fields))
920 status = table_params_get(ctl, i);
926 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
931 status = table_state_create(ctl);
938 rte_swx_ctl_pipeline_free(ctl);
943 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
944 const char *table_name,
945 struct rte_swx_table_entry *entry)
948 struct rte_swx_table_entry *new_entry, *existing_entry;
952 CHECK(table_name && table_name[0], EINVAL);
954 table = table_find(ctl, table_name);
955 CHECK(table, EINVAL);
956 table_id = table - ctl->tables;
958 CHECK(entry, EINVAL);
959 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
961 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
962 CHECK(new_entry, ENOMEM);
964 /* The new entry is found in the table->entries list:
965 * - Add the new entry to the table->pending_modify1 list;
966 * - Move the existing entry from the table->entries list to the
967 * table->pending_modify0 list.
969 existing_entry = table_entries_find(table, entry);
970 if (existing_entry) {
971 TAILQ_INSERT_TAIL(&table->pending_modify1,
975 TAILQ_REMOVE(&table->entries,
979 TAILQ_INSERT_TAIL(&table->pending_modify0,
986 /* The new entry is found in the table->pending_add list:
987 * - Replace the entry in the table->pending_add list with the new entry
988 * (and free the replaced entry).
990 existing_entry = table_pending_add_find(table, entry);
991 if (existing_entry) {
992 TAILQ_INSERT_AFTER(&table->pending_add,
997 TAILQ_REMOVE(&table->pending_add,
1001 table_entry_free(existing_entry);
1006 /* The new entry is found in the table->pending_modify1 list:
1007 * - Replace the entry in the table->pending_modify1 list with the new
1008 * entry (and free the replaced entry).
1010 existing_entry = table_pending_modify1_find(table, entry);
1011 if (existing_entry) {
1012 TAILQ_INSERT_AFTER(&table->pending_modify1,
1017 TAILQ_REMOVE(&table->pending_modify1,
1021 table_entry_free(existing_entry);
1026 /* The new entry is found in the table->pending_delete list:
1027 * - Add the new entry to the table->pending_modify1 list;
1028 * - Move the existing entry from the table->pending_delete list to the
1029 * table->pending_modify0 list.
1031 existing_entry = table_pending_delete_find(table, entry);
1032 if (existing_entry) {
1033 TAILQ_INSERT_TAIL(&table->pending_modify1,
1037 TAILQ_REMOVE(&table->pending_delete,
1041 TAILQ_INSERT_TAIL(&table->pending_modify0,
1048 /* The new entry is not found in any of the above lists:
1049 * - Add the new entry to the table->pending_add list.
1051 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1057 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1058 const char *table_name,
1059 struct rte_swx_table_entry *entry)
1061 struct table *table;
1062 struct rte_swx_table_entry *existing_entry;
1067 CHECK(table_name && table_name[0], EINVAL);
1068 table = table_find(ctl, table_name);
1069 CHECK(table, EINVAL);
1070 table_id = table - ctl->tables;
1072 CHECK(entry, EINVAL);
1073 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1075 /* The entry is found in the table->entries list:
1076 * - Move the existing entry from the table->entries list to to the
1077 * table->pending_delete list.
1079 existing_entry = table_entries_find(table, entry);
1080 if (existing_entry) {
1081 TAILQ_REMOVE(&table->entries,
1085 TAILQ_INSERT_TAIL(&table->pending_delete,
1092 /* The entry is found in the table->pending_add list:
1093 * - Remove the entry from the table->pending_add list and free it.
1095 existing_entry = table_pending_add_find(table, entry);
1096 if (existing_entry) {
1097 TAILQ_REMOVE(&table->pending_add,
1101 table_entry_free(existing_entry);
1104 /* The entry is found in the table->pending_modify1 list:
1105 * - Free the entry in the table->pending_modify1 list;
1106 * - Move the existing entry from the table->pending_modify0 list to the
1107 * table->pending_delete list.
1109 existing_entry = table_pending_modify1_find(table, entry);
1110 if (existing_entry) {
1111 struct rte_swx_table_entry *real_existing_entry;
1113 TAILQ_REMOVE(&table->pending_modify1,
1117 table_entry_free(existing_entry);
1119 real_existing_entry = table_pending_modify0_find(table, entry);
1120 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1122 TAILQ_REMOVE(&table->pending_modify0,
1123 real_existing_entry,
1126 TAILQ_INSERT_TAIL(&table->pending_delete,
1127 real_existing_entry,
1133 /* The entry is found in the table->pending_delete list:
1134 * - Do nothing: the existing entry is already in the
1135 * table->pending_delete list, i.e. already marked for delete, so
1136 * simply keep it there as it is.
1139 /* The entry is not found in any of the above lists:
1140 * - Do nothing: no existing entry to delete.
1147 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1148 const char *table_name,
1149 struct rte_swx_table_entry *entry)
1151 struct table *table;
1152 struct rte_swx_table_entry *new_entry;
1157 CHECK(table_name && table_name[0], EINVAL);
1158 table = table_find(ctl, table_name);
1159 CHECK(table, EINVAL);
1160 table_id = table - ctl->tables;
1161 CHECK(!table->info.default_action_is_const, EINVAL);
1163 CHECK(entry, EINVAL);
1164 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1166 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1167 CHECK(new_entry, ENOMEM);
1169 table_pending_default_free(table);
1171 table->pending_default = new_entry;
1177 table_entry_list_free(struct rte_swx_table_entry_list *list)
1180 struct rte_swx_table_entry *entry;
1182 entry = TAILQ_FIRST(list);
1186 TAILQ_REMOVE(list, entry, node);
1187 table_entry_free(entry);
1192 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1194 struct rte_swx_table_entry_list *dst,
1195 struct rte_swx_table_entry_list *src)
1197 struct rte_swx_table_entry *src_entry;
1199 TAILQ_FOREACH(src_entry, src, node) {
1200 struct rte_swx_table_entry *dst_entry;
1202 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1206 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1212 table_entry_list_free(dst);
1216 /* This commit stage contains all the operations that can fail; in case ANY of
1217 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1220 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1222 uint32_t after_swap)
1224 struct table *table = &ctl->tables[table_id];
1225 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1226 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1228 if (table->is_stub || !table_is_update_pending(table, 0))
1232 * Current table supports incremental update.
1234 if (table->ops.add) {
1235 /* Reset counters. */
1237 table->n_modify = 0;
1238 table->n_delete = 0;
1240 /* Add pending rules. */
1241 struct rte_swx_table_entry *entry;
1243 TAILQ_FOREACH(entry, &table->pending_add, node) {
1246 status = table->ops.add(ts_next->obj, entry);
1253 /* Modify pending rules. */
1254 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1257 status = table->ops.add(ts_next->obj, entry);
1264 /* Delete pending rules. */
1265 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1268 status = table->ops.del(ts_next->obj, entry);
1279 * Current table does NOT support incremental update.
1282 struct rte_swx_table_entry_list list;
1285 /* Create updated list of entries included. */
1288 status = table_entry_list_duplicate(ctl,
1295 status = table_entry_list_duplicate(ctl,
1298 &table->pending_add);
1302 status = table_entry_list_duplicate(ctl,
1305 &table->pending_modify1);
1309 /* Create new table object with the updates included. */
1310 ts_next->obj = table->ops.create(&table->params,
1314 if (!ts_next->obj) {
1319 table_entry_list_free(&list);
1324 table_entry_list_free(&list);
1328 /* Free the old table object. */
1329 if (ts_next->obj && table->ops.free)
1330 table->ops.free(ts_next->obj);
1332 /* Copy over the new table object. */
1333 ts_next->obj = ts->obj;
1338 /* This commit stage contains all the operations that cannot fail. They are
1339 * executed only if the previous stage was successful for ALL the tables. Hence,
1340 * none of these operations has to be rolled back for ANY table.
1343 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1345 struct table *table = &ctl->tables[table_id];
1346 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1348 uint8_t *action_data;
1351 /* Copy the pending default entry. */
1352 if (!table->pending_default)
1355 action_id = table->pending_default->action_id;
1356 action_data = table->pending_default->action_data;
1357 a = &ctl->actions[action_id];
1359 memcpy(ts_next->default_action_data,
1363 ts_next->default_action_id = action_id;
1366 /* This last commit stage is simply finalizing a successful commit operation.
1367 * This stage is only executed if all the previous stages were successful. This
1368 * stage cannot fail.
1371 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1373 struct table *table = &ctl->tables[table_id];
1375 /* Move all the pending add entries to the table, as they are now part
1378 table_pending_add_admit(table);
1380 /* Move all the pending modify1 entries to table, are they are now part
1381 * of the table. Free up all the pending modify0 entries, as they are no
1382 * longer part of the table.
1384 table_pending_modify1_admit(table);
1385 table_pending_modify0_free(table);
1387 /* Free up all the pending delete entries, as they are no longer part of
1390 table_pending_delete_free(table);
1392 /* Free up the pending default entry, as it is now part of the table. */
1393 table_pending_default_free(table);
1396 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1397 * commit operations that can fail did fail for ANY table. It reverts ALL the
1398 * tables to their state before the commit started, as if the commit never
1402 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1404 struct table *table = &ctl->tables[table_id];
1405 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1407 if (table->is_stub || !table_is_update_pending(table, 0))
1410 if (table->ops.add) {
1411 struct rte_swx_table_entry *entry;
1413 /* Add back all the entries that were just deleted. */
1414 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1415 if (!table->n_delete)
1418 table->ops.add(ts_next->obj, entry);
1422 /* Add back the old copy for all the entries that were just
1425 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1426 if (!table->n_modify)
1429 table->ops.add(ts_next->obj, entry);
1433 /* Delete all the entries that were just added. */
1434 TAILQ_FOREACH(entry, &table->pending_add, node) {
1438 table->ops.del(ts_next->obj, entry);
1442 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1444 /* Free the new table object, as update was cancelled. */
1445 if (ts_next->obj && table->ops.free)
1446 table->ops.free(ts_next->obj);
1448 /* Reinstate the old table object. */
1449 ts_next->obj = ts->obj;
1453 /* This stage is conditionally executed (as instructed by the user) after a
1454 * failed commit operation to remove ALL the pending work for ALL the tables.
1457 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1459 struct table *table = &ctl->tables[table_id];
1461 /* Free up all the pending add entries, as none of them is part of the
1464 table_pending_add_free(table);
1466 /* Free up all the pending modify1 entries, as none of them made it to
1467 * the table. Add back all the pending modify0 entries, as none of them
1468 * was deleted from the table.
1470 table_pending_modify1_free(table);
1471 table_pending_modify0_admit(table);
1473 /* Add back all the pending delete entries, as none of them was deleted
1476 table_pending_delete_admit(table);
1478 /* Free up the pending default entry, as it is no longer going to be
1479 * added to the table.
1481 table_pending_default_free(table);
1485 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1487 struct rte_swx_table_state *ts;
1493 /* Operate the changes on the current ts_next before it becomes the new
1496 for (i = 0; i < ctl->info.n_tables; i++) {
1497 status = table_rollfwd0(ctl, i, 0);
1502 for (i = 0; i < ctl->info.n_tables; i++)
1503 table_rollfwd1(ctl, i);
1505 /* Swap the table state for the data plane. The current ts and ts_next
1506 * become the new ts_next and ts, respectively.
1508 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1511 ctl->ts = ctl->ts_next;
1514 /* Operate the changes on the current ts_next, which is the previous ts.
1516 for (i = 0; i < ctl->info.n_tables; i++) {
1517 table_rollfwd0(ctl, i, 1);
1518 table_rollfwd1(ctl, i);
1519 table_rollfwd2(ctl, i);
1525 for (i = 0; i < ctl->info.n_tables; i++) {
1526 table_rollback(ctl, i);
1528 table_abort(ctl, i);
1535 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1542 for (i = 0; i < ctl->info.n_tables; i++)
1543 table_abort(ctl, i);
1547 token_is_comment(const char *token)
1549 if ((token[0] == '#') ||
1550 (token[0] == ';') ||
1551 ((token[0] == '/') && (token[1] == '/')))
1552 return 1; /* TRUE. */
1554 return 0; /* FALSE. */
1557 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1559 struct rte_swx_table_entry *
1560 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1561 const char *table_name,
1563 int *is_blank_or_comment)
1565 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1566 struct table *table;
1567 struct action *action;
1568 struct rte_swx_table_entry *entry = NULL;
1569 char *s0 = NULL, *s;
1570 uint32_t n_tokens = 0, arg_offset = 0, i;
1571 int blank_or_comment = 0;
1573 /* Check input arguments. */
1577 if (!table_name || !table_name[0])
1580 table = table_find(ctl, table_name);
1584 if (!string || !string[0])
1587 /* Memory allocation. */
1588 s0 = strdup(string);
1592 entry = table_entry_alloc(table);
1596 /* Parse the string into tokens. */
1600 token = strtok_r(s, " \f\n\r\t\v", &s);
1601 if (!token || token_is_comment(token))
1604 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1607 token_array[n_tokens] = token;
1612 blank_or_comment = 1;
1616 tokens = token_array;
1621 if (n_tokens && strcmp(tokens[0], "match"))
1624 if (n_tokens < 1 + table->info.n_match_fields)
1627 for (i = 0; i < table->info.n_match_fields; i++) {
1628 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1629 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1630 uint64_t val, mask = UINT64_MAX;
1631 uint32_t offset = (mf->offset - table->mf[0].offset) / 8;
1636 mf_mask = strchr(mf_val, '/');
1642 mask = strtoull(mf_mask, &mf_mask, 0);
1646 /* Endianness conversion. */
1648 mask = field_hton(mask, mf->n_bits);
1651 /* Copy to entry. */
1652 if (entry->key_mask)
1653 memcpy(&entry->key_mask[offset],
1661 val = strtoull(mf_val, &mf_val, 0);
1665 /* Endianness conversion. */
1667 val = field_hton(val, mf->n_bits);
1669 /* Copy to entry. */
1670 memcpy(&entry->key[offset],
1675 tokens += 1 + table->info.n_match_fields;
1676 n_tokens -= 1 + table->info.n_match_fields;
1681 if (n_tokens && !strcmp(tokens[0], "priority")) {
1682 char *priority = tokens[1];
1689 val = strtoul(priority, &priority, 0);
1693 /* Copy to entry. */
1694 entry->key_priority = val;
1704 if (n_tokens && strcmp(tokens[0], "action"))
1710 action = action_find(ctl, tokens[1]);
1714 if (n_tokens < 2 + action->info.n_args * 2)
1718 entry->action_id = action - ctl->actions;
1721 for (i = 0; i < action->info.n_args; i++) {
1722 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1723 char *arg_name, *arg_val;
1727 arg_name = tokens[2 + i * 2];
1728 arg_val = tokens[2 + i * 2 + 1];
1730 if (strcmp(arg_name, arg->name) ||
1731 (strlen(arg_val) < 4) ||
1732 ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1733 (arg_val[1] != '(') ||
1734 (arg_val[strlen(arg_val) - 1] != ')'))
1737 if (arg_val[0] == 'N')
1740 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1741 arg_val += 2; /* Remove the "H(" or "N(". */
1743 val = strtoull(arg_val, &arg_val, 0);
1747 /* Endianness conversion. */
1749 val = field_hton(val, arg->n_bits);
1751 /* Copy to entry. */
1752 memcpy(&entry->action_data[arg_offset],
1756 arg_offset += arg->n_bits / 8;
1759 tokens += 2 + action->info.n_args * 2;
1760 n_tokens -= 2 + action->info.n_args * 2;
1770 table_entry_free(entry);
1772 if (is_blank_or_comment)
1773 *is_blank_or_comment = blank_or_comment;
1778 table_entry_printf(FILE *f,
1779 struct rte_swx_ctl_pipeline *ctl,
1780 struct table *table,
1781 struct rte_swx_table_entry *entry)
1783 struct action *action = &ctl->actions[entry->action_id];
1786 fprintf(f, "match ");
1787 for (i = 0; i < table->params.key_size; i++)
1788 fprintf(f, "%02x", entry->key[i]);
1790 if (entry->key_mask) {
1792 for (i = 0; i < table->params.key_size; i++)
1793 fprintf(f, "%02x", entry->key_mask[i]);
1796 fprintf(f, " priority %u", entry->key_priority);
1798 fprintf(f, " action %s ", action->info.name);
1799 for (i = 0; i < action->data_size; i++)
1800 fprintf(f, "%02x", entry->action_data[i]);
1806 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1807 struct rte_swx_ctl_pipeline *ctl,
1808 const char *table_name)
1810 struct table *table;
1811 struct rte_swx_table_entry *entry;
1812 uint32_t n_entries = 0, i;
1814 if (!f || !ctl || !table_name || !table_name[0])
1817 table = table_find(ctl, table_name);
1822 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1824 table->params.key_size,
1825 table->params.key_offset);
1827 for (i = 0; i < table->params.key_size; i++)
1828 fprintf(f, "%02x", table->params.key_mask0[i]);
1830 fprintf(f, "], action data size %u bytes\n",
1831 table->params.action_data_size);
1833 /* Table entries. */
1834 TAILQ_FOREACH(entry, &table->entries, node) {
1835 table_entry_printf(f, ctl, table, entry);
1839 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1840 table_entry_printf(f, ctl, table, entry);
1844 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1845 table_entry_printf(f, ctl, table, entry);
1849 fprintf(f, "# Table %s currently has %u entries.\n",