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 if (data_duplicate) {
396 for (i = 0; i < table->info.n_actions; i++)
397 if (entry->action_id == table->actions[i].action_id)
400 if (i >= table->info.n_actions)
403 new_entry->action_id = entry->action_id;
406 a = &ctl->actions[entry->action_id];
407 if (a->data_size && !entry->action_data)
410 /* The table layer provisions a constant action data size per
411 * entry, which should be the largest data size for all the
412 * actions enabled for the current table, and attempts to copy
413 * this many bytes each time a table entry is added, even if the
414 * specific action requires less data or even no data at all,
415 * hence we always have to allocate the max.
417 new_entry->action_data = calloc(1, table->params.action_data_size);
418 if (!new_entry->action_data)
422 memcpy(new_entry->action_data,
430 table_entry_free(new_entry);
435 table_entry_keycmp(struct table *table,
436 struct rte_swx_table_entry *e0,
437 struct rte_swx_table_entry *e1)
439 uint32_t key_size = table->params.key_size;
442 for (i = 0; i < key_size; i++) {
443 uint8_t *key_mask0 = table->params.key_mask0;
444 uint8_t km0, km[2], k[2];
446 km0 = key_mask0 ? key_mask0[i] : 0xFF;
448 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
449 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
454 /* Mask comparison. */
455 if ((km[0] & km0) != (km[1] & km0))
456 return 1; /* Not equal. */
458 /* Value comparison. */
459 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
460 return 1; /* Not equal. */
463 return 0; /* Equal. */
466 static struct rte_swx_table_entry *
467 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
469 struct rte_swx_table_entry *e;
471 TAILQ_FOREACH(e, &table->entries, node)
472 if (!table_entry_keycmp(table, entry, e))
473 return e; /* Found. */
475 return NULL; /* Not found. */
479 table_entries_free(struct table *table)
482 struct rte_swx_table_entry *entry;
484 entry = TAILQ_FIRST(&table->entries);
488 TAILQ_REMOVE(&table->entries, entry, node);
489 table_entry_free(entry);
493 static struct rte_swx_table_entry *
494 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
496 struct rte_swx_table_entry *e;
498 TAILQ_FOREACH(e, &table->pending_add, node)
499 if (!table_entry_keycmp(table, entry, e))
500 return e; /* Found. */
502 return NULL; /* Not found. */
506 table_pending_add_admit(struct table *table)
508 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
512 table_pending_add_free(struct table *table)
515 struct rte_swx_table_entry *entry;
517 entry = TAILQ_FIRST(&table->pending_add);
521 TAILQ_REMOVE(&table->pending_add, entry, node);
522 table_entry_free(entry);
526 static struct rte_swx_table_entry *
527 table_pending_modify0_find(struct table *table,
528 struct rte_swx_table_entry *entry)
530 struct rte_swx_table_entry *e;
532 TAILQ_FOREACH(e, &table->pending_modify0, node)
533 if (!table_entry_keycmp(table, entry, e))
534 return e; /* Found. */
536 return NULL; /* Not found. */
540 table_pending_modify0_admit(struct table *table)
542 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
546 table_pending_modify0_free(struct table *table)
549 struct rte_swx_table_entry *entry;
551 entry = TAILQ_FIRST(&table->pending_modify0);
555 TAILQ_REMOVE(&table->pending_modify0, entry, node);
556 table_entry_free(entry);
560 static struct rte_swx_table_entry *
561 table_pending_modify1_find(struct table *table,
562 struct rte_swx_table_entry *entry)
564 struct rte_swx_table_entry *e;
566 TAILQ_FOREACH(e, &table->pending_modify1, node)
567 if (!table_entry_keycmp(table, entry, e))
568 return e; /* Found. */
570 return NULL; /* Not found. */
574 table_pending_modify1_admit(struct table *table)
576 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
580 table_pending_modify1_free(struct table *table)
583 struct rte_swx_table_entry *entry;
585 entry = TAILQ_FIRST(&table->pending_modify1);
589 TAILQ_REMOVE(&table->pending_modify1, entry, node);
590 table_entry_free(entry);
594 static struct rte_swx_table_entry *
595 table_pending_delete_find(struct table *table,
596 struct rte_swx_table_entry *entry)
598 struct rte_swx_table_entry *e;
600 TAILQ_FOREACH(e, &table->pending_delete, node)
601 if (!table_entry_keycmp(table, entry, e))
602 return e; /* Found. */
604 return NULL; /* Not found. */
608 table_pending_delete_admit(struct table *table)
610 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
614 table_pending_delete_free(struct table *table)
617 struct rte_swx_table_entry *entry;
619 entry = TAILQ_FIRST(&table->pending_delete);
623 TAILQ_REMOVE(&table->pending_delete, entry, node);
624 table_entry_free(entry);
629 table_pending_default_free(struct table *table)
631 if (!table->pending_default)
634 free(table->pending_default->action_data);
635 free(table->pending_default);
636 table->pending_default = NULL;
640 table_is_update_pending(struct table *table, int consider_pending_default)
642 struct rte_swx_table_entry *e;
646 TAILQ_FOREACH(e, &table->pending_add, node)
649 /* Pending modify. */
650 TAILQ_FOREACH(e, &table->pending_modify1, node)
653 /* Pending delete. */
654 TAILQ_FOREACH(e, &table->pending_delete, node)
657 /* Pending default. */
658 if (consider_pending_default && table->pending_default)
665 table_free(struct rte_swx_ctl_pipeline *ctl)
672 for (i = 0; i < ctl->info.n_tables; i++) {
673 struct table *table = &ctl->tables[i];
676 free(table->actions);
677 free(table->params.key_mask0);
679 table_entries_free(table);
680 table_pending_add_free(table);
681 table_pending_modify0_free(table);
682 table_pending_modify1_free(table);
683 table_pending_delete_free(table);
684 table_pending_default_free(table);
692 table_state_free(struct rte_swx_ctl_pipeline *ctl)
699 /* For each table, free its table state. */
700 for (i = 0; i < ctl->info.n_tables; i++) {
701 struct table *table = &ctl->tables[i];
702 struct rte_swx_table_state *ts = &ctl->ts_next[i];
704 /* Default action data. */
705 free(ts->default_action_data);
708 if (!table->is_stub && table->ops.free && ts->obj)
709 table->ops.free(ts->obj);
717 table_state_create(struct rte_swx_ctl_pipeline *ctl)
722 ctl->ts_next = calloc(ctl->info.n_tables,
723 sizeof(struct rte_swx_table_state));
729 for (i = 0; i < ctl->info.n_tables; i++) {
730 struct table *table = &ctl->tables[i];
731 struct rte_swx_table_state *ts = &ctl->ts[i];
732 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
735 if (!table->is_stub && table->ops.add) {
736 ts_next->obj = table->ops.create(&table->params,
746 if (!table->is_stub && !table->ops.add)
747 ts_next->obj = ts->obj;
749 /* Default action data: duplicate from current table state. */
750 ts_next->default_action_data =
751 malloc(table->params.action_data_size);
752 if (!ts_next->default_action_data) {
757 memcpy(ts_next->default_action_data,
758 ts->default_action_data,
759 table->params.action_data_size);
761 ts_next->default_action_id = ts->default_action_id;
767 table_state_free(ctl);
772 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
779 table_state_free(ctl);
786 struct rte_swx_ctl_pipeline *
787 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
789 struct rte_swx_ctl_pipeline *ctl = NULL;
796 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
801 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
806 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
814 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
818 for (i = 0; i < ctl->info.n_actions; i++) {
819 struct action *a = &ctl->actions[i];
823 status = rte_swx_ctl_action_info_get(p, i, &a->info);
828 a->args = calloc(a->info.n_args,
829 sizeof(struct rte_swx_ctl_action_arg_info));
833 for (j = 0; j < a->info.n_args; j++) {
834 status = rte_swx_ctl_action_arg_info_get(p,
843 for (j = 0; j < a->info.n_args; j++) {
844 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
846 a->data_size += info->n_bits;
849 a->data_size = (a->data_size + 7) / 8;
853 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
857 for (i = 0; i < ctl->info.n_tables; i++) {
858 struct table *t = &ctl->tables[i];
860 TAILQ_INIT(&t->entries);
861 TAILQ_INIT(&t->pending_add);
862 TAILQ_INIT(&t->pending_modify0);
863 TAILQ_INIT(&t->pending_modify1);
864 TAILQ_INIT(&t->pending_delete);
867 for (i = 0; i < ctl->info.n_tables; i++) {
868 struct table *t = &ctl->tables[i];
872 status = rte_swx_ctl_table_info_get(p, i, &t->info);
877 t->mf = calloc(t->info.n_match_fields,
878 sizeof(struct rte_swx_ctl_table_match_field_info));
882 for (j = 0; j < t->info.n_match_fields; j++) {
883 status = rte_swx_ctl_table_match_field_info_get(p,
892 t->actions = calloc(t->info.n_actions,
893 sizeof(struct rte_swx_ctl_table_action_info));
897 for (j = 0; j < t->info.n_actions; j++) {
898 status = rte_swx_ctl_table_action_info_get(p,
903 t->actions[j].action_id >= ctl->info.n_actions)
908 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
912 if ((t->is_stub && t->info.n_match_fields) ||
913 (!t->is_stub && !t->info.n_match_fields))
917 status = table_params_get(ctl, i);
923 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
928 status = table_state_create(ctl);
935 rte_swx_ctl_pipeline_free(ctl);
940 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
941 const char *table_name,
942 struct rte_swx_table_entry *entry)
945 struct rte_swx_table_entry *new_entry, *existing_entry;
949 CHECK(table_name && table_name[0], EINVAL);
951 table = table_find(ctl, table_name);
952 CHECK(table, EINVAL);
953 table_id = table - ctl->tables;
955 CHECK(entry, EINVAL);
956 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
958 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
959 CHECK(new_entry, ENOMEM);
961 /* The new entry is found in the table->entries list:
962 * - Add the new entry to the table->pending_modify1 list;
963 * - Move the existing entry from the table->entries list to the
964 * table->pending_modify0 list.
966 existing_entry = table_entries_find(table, entry);
967 if (existing_entry) {
968 TAILQ_INSERT_TAIL(&table->pending_modify1,
972 TAILQ_REMOVE(&table->entries,
976 TAILQ_INSERT_TAIL(&table->pending_modify0,
983 /* The new entry is found in the table->pending_add list:
984 * - Replace the entry in the table->pending_add list with the new entry
985 * (and free the replaced entry).
987 existing_entry = table_pending_add_find(table, entry);
988 if (existing_entry) {
989 TAILQ_INSERT_AFTER(&table->pending_add,
994 TAILQ_REMOVE(&table->pending_add,
998 table_entry_free(existing_entry);
1003 /* The new entry is found in the table->pending_modify1 list:
1004 * - Replace the entry in the table->pending_modify1 list with the new
1005 * entry (and free the replaced entry).
1007 existing_entry = table_pending_modify1_find(table, entry);
1008 if (existing_entry) {
1009 TAILQ_INSERT_AFTER(&table->pending_modify1,
1014 TAILQ_REMOVE(&table->pending_modify1,
1018 table_entry_free(existing_entry);
1023 /* The new entry is found in the table->pending_delete list:
1024 * - Add the new entry to the table->pending_modify1 list;
1025 * - Move the existing entry from the table->pending_delete list to the
1026 * table->pending_modify0 list.
1028 existing_entry = table_pending_delete_find(table, entry);
1029 if (existing_entry) {
1030 TAILQ_INSERT_TAIL(&table->pending_modify1,
1034 TAILQ_REMOVE(&table->pending_delete,
1038 TAILQ_INSERT_TAIL(&table->pending_modify0,
1045 /* The new entry is not found in any of the above lists:
1046 * - Add the new entry to the table->pending_add list.
1048 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1054 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1055 const char *table_name,
1056 struct rte_swx_table_entry *entry)
1058 struct table *table;
1059 struct rte_swx_table_entry *existing_entry;
1064 CHECK(table_name && table_name[0], EINVAL);
1065 table = table_find(ctl, table_name);
1066 CHECK(table, EINVAL);
1067 table_id = table - ctl->tables;
1069 CHECK(entry, EINVAL);
1070 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1072 /* The entry is found in the table->entries list:
1073 * - Move the existing entry from the table->entries list to to the
1074 * table->pending_delete list.
1076 existing_entry = table_entries_find(table, entry);
1077 if (existing_entry) {
1078 TAILQ_REMOVE(&table->entries,
1082 TAILQ_INSERT_TAIL(&table->pending_delete,
1089 /* The entry is found in the table->pending_add list:
1090 * - Remove the entry from the table->pending_add list and free it.
1092 existing_entry = table_pending_add_find(table, entry);
1093 if (existing_entry) {
1094 TAILQ_REMOVE(&table->pending_add,
1098 table_entry_free(existing_entry);
1101 /* The entry is found in the table->pending_modify1 list:
1102 * - Free the entry in the table->pending_modify1 list;
1103 * - Move the existing entry from the table->pending_modify0 list to the
1104 * table->pending_delete list.
1106 existing_entry = table_pending_modify1_find(table, entry);
1107 if (existing_entry) {
1108 struct rte_swx_table_entry *real_existing_entry;
1110 TAILQ_REMOVE(&table->pending_modify1,
1114 table_entry_free(existing_entry);
1116 real_existing_entry = table_pending_modify0_find(table, entry);
1117 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1119 TAILQ_REMOVE(&table->pending_modify0,
1120 real_existing_entry,
1123 TAILQ_INSERT_TAIL(&table->pending_delete,
1124 real_existing_entry,
1130 /* The entry is found in the table->pending_delete list:
1131 * - Do nothing: the existing entry is already in the
1132 * table->pending_delete list, i.e. already marked for delete, so
1133 * simply keep it there as it is.
1136 /* The entry is not found in any of the above lists:
1137 * - Do nothing: no existing entry to delete.
1144 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1145 const char *table_name,
1146 struct rte_swx_table_entry *entry)
1148 struct table *table;
1149 struct rte_swx_table_entry *new_entry;
1154 CHECK(table_name && table_name[0], EINVAL);
1155 table = table_find(ctl, table_name);
1156 CHECK(table, EINVAL);
1157 table_id = table - ctl->tables;
1158 CHECK(!table->info.default_action_is_const, EINVAL);
1160 CHECK(entry, EINVAL);
1161 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1163 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1164 CHECK(new_entry, ENOMEM);
1166 table_pending_default_free(table);
1168 table->pending_default = new_entry;
1174 table_entry_list_free(struct rte_swx_table_entry_list *list)
1177 struct rte_swx_table_entry *entry;
1179 entry = TAILQ_FIRST(list);
1183 TAILQ_REMOVE(list, entry, node);
1184 table_entry_free(entry);
1189 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1191 struct rte_swx_table_entry_list *dst,
1192 struct rte_swx_table_entry_list *src)
1194 struct rte_swx_table_entry *src_entry;
1196 TAILQ_FOREACH(src_entry, src, node) {
1197 struct rte_swx_table_entry *dst_entry;
1199 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1203 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1209 table_entry_list_free(dst);
1213 /* This commit stage contains all the operations that can fail; in case ANY of
1214 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1217 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1219 uint32_t after_swap)
1221 struct table *table = &ctl->tables[table_id];
1222 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1223 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1225 if (table->is_stub || !table_is_update_pending(table, 0))
1229 * Current table supports incremental update.
1231 if (table->ops.add) {
1232 /* Reset counters. */
1234 table->n_modify = 0;
1235 table->n_delete = 0;
1237 /* Add pending rules. */
1238 struct rte_swx_table_entry *entry;
1240 TAILQ_FOREACH(entry, &table->pending_add, node) {
1243 status = table->ops.add(ts_next->obj, entry);
1250 /* Modify pending rules. */
1251 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1254 status = table->ops.add(ts_next->obj, entry);
1261 /* Delete pending rules. */
1262 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1265 status = table->ops.del(ts_next->obj, entry);
1276 * Current table does NOT support incremental update.
1279 struct rte_swx_table_entry_list list;
1282 /* Create updated list of entries included. */
1285 status = table_entry_list_duplicate(ctl,
1292 status = table_entry_list_duplicate(ctl,
1295 &table->pending_add);
1299 status = table_entry_list_duplicate(ctl,
1302 &table->pending_modify1);
1306 /* Create new table object with the updates included. */
1307 ts_next->obj = table->ops.create(&table->params,
1311 if (!ts_next->obj) {
1316 table_entry_list_free(&list);
1321 table_entry_list_free(&list);
1325 /* Free the old table object. */
1326 if (ts_next->obj && table->ops.free)
1327 table->ops.free(ts_next->obj);
1329 /* Copy over the new table object. */
1330 ts_next->obj = ts->obj;
1335 /* This commit stage contains all the operations that cannot fail. They are
1336 * executed only if the previous stage was successful for ALL the tables. Hence,
1337 * none of these operations has to be rolled back for ANY table.
1340 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1342 struct table *table = &ctl->tables[table_id];
1343 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1345 uint8_t *action_data;
1348 /* Copy the pending default entry. */
1349 if (!table->pending_default)
1352 action_id = table->pending_default->action_id;
1353 action_data = table->pending_default->action_data;
1354 a = &ctl->actions[action_id];
1356 memcpy(ts_next->default_action_data,
1360 ts_next->default_action_id = action_id;
1363 /* This last commit stage is simply finalizing a successful commit operation.
1364 * This stage is only executed if all the previous stages were successful. This
1365 * stage cannot fail.
1368 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1370 struct table *table = &ctl->tables[table_id];
1372 /* Move all the pending add entries to the table, as they are now part
1375 table_pending_add_admit(table);
1377 /* Move all the pending modify1 entries to table, are they are now part
1378 * of the table. Free up all the pending modify0 entries, as they are no
1379 * longer part of the table.
1381 table_pending_modify1_admit(table);
1382 table_pending_modify0_free(table);
1384 /* Free up all the pending delete entries, as they are no longer part of
1387 table_pending_delete_free(table);
1389 /* Free up the pending default entry, as it is now part of the table. */
1390 table_pending_default_free(table);
1393 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1394 * commit operations that can fail did fail for ANY table. It reverts ALL the
1395 * tables to their state before the commit started, as if the commit never
1399 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1401 struct table *table = &ctl->tables[table_id];
1402 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1404 if (table->is_stub || !table_is_update_pending(table, 0))
1407 if (table->ops.add) {
1408 struct rte_swx_table_entry *entry;
1410 /* Add back all the entries that were just deleted. */
1411 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1412 if (!table->n_delete)
1415 table->ops.add(ts_next->obj, entry);
1419 /* Add back the old copy for all the entries that were just
1422 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1423 if (!table->n_modify)
1426 table->ops.add(ts_next->obj, entry);
1430 /* Delete all the entries that were just added. */
1431 TAILQ_FOREACH(entry, &table->pending_add, node) {
1435 table->ops.del(ts_next->obj, entry);
1439 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1441 /* Free the new table object, as update was cancelled. */
1442 if (ts_next->obj && table->ops.free)
1443 table->ops.free(ts_next->obj);
1445 /* Reinstate the old table object. */
1446 ts_next->obj = ts->obj;
1450 /* This stage is conditionally executed (as instructed by the user) after a
1451 * failed commit operation to remove ALL the pending work for ALL the tables.
1454 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1456 struct table *table = &ctl->tables[table_id];
1458 /* Free up all the pending add entries, as none of them is part of the
1461 table_pending_add_free(table);
1463 /* Free up all the pending modify1 entries, as none of them made it to
1464 * the table. Add back all the pending modify0 entries, as none of them
1465 * was deleted from the table.
1467 table_pending_modify1_free(table);
1468 table_pending_modify0_admit(table);
1470 /* Add back all the pending delete entries, as none of them was deleted
1473 table_pending_delete_admit(table);
1475 /* Free up the pending default entry, as it is no longer going to be
1476 * added to the table.
1478 table_pending_default_free(table);
1482 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1484 struct rte_swx_table_state *ts;
1490 /* Operate the changes on the current ts_next before it becomes the new
1493 for (i = 0; i < ctl->info.n_tables; i++) {
1494 status = table_rollfwd0(ctl, i, 0);
1499 for (i = 0; i < ctl->info.n_tables; i++)
1500 table_rollfwd1(ctl, i);
1502 /* Swap the table state for the data plane. The current ts and ts_next
1503 * become the new ts_next and ts, respectively.
1505 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1508 ctl->ts = ctl->ts_next;
1511 /* Operate the changes on the current ts_next, which is the previous ts.
1513 for (i = 0; i < ctl->info.n_tables; i++) {
1514 table_rollfwd0(ctl, i, 1);
1515 table_rollfwd1(ctl, i);
1516 table_rollfwd2(ctl, i);
1522 for (i = 0; i < ctl->info.n_tables; i++) {
1523 table_rollback(ctl, i);
1525 table_abort(ctl, i);
1532 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1539 for (i = 0; i < ctl->info.n_tables; i++)
1540 table_abort(ctl, i);
1544 token_is_comment(const char *token)
1546 if ((token[0] == '#') ||
1547 (token[0] == ';') ||
1548 ((token[0] == '/') && (token[1] == '/')))
1549 return 1; /* TRUE. */
1551 return 0; /* FALSE. */
1554 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1556 struct rte_swx_table_entry *
1557 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1558 const char *table_name,
1560 int *is_blank_or_comment)
1562 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1563 struct table *table;
1564 struct action *action;
1565 struct rte_swx_table_entry *entry = NULL;
1566 char *s0 = NULL, *s;
1567 uint32_t n_tokens = 0, arg_offset = 0, i;
1568 int blank_or_comment = 0;
1570 /* Check input arguments. */
1574 if (!table_name || !table_name[0])
1577 table = table_find(ctl, table_name);
1581 if (!string || !string[0])
1584 /* Memory allocation. */
1585 s0 = strdup(string);
1589 entry = table_entry_alloc(table);
1593 /* Parse the string into tokens. */
1597 token = strtok_r(s, " \f\n\r\t\v", &s);
1598 if (!token || token_is_comment(token))
1601 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1604 token_array[n_tokens] = token;
1609 blank_or_comment = 1;
1613 tokens = token_array;
1618 if (n_tokens && strcmp(tokens[0], "match"))
1621 if (n_tokens < 1 + table->info.n_match_fields)
1624 for (i = 0; i < table->info.n_match_fields; i++) {
1625 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1626 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1627 uint64_t val, mask = UINT64_MAX;
1628 uint32_t offset = (mf->offset - table->mf[0].offset) / 8;
1633 mf_mask = strchr(mf_val, '/');
1639 mask = strtoull(mf_mask, &mf_mask, 0);
1643 /* Endianness conversion. */
1645 mask = field_hton(mask, mf->n_bits);
1648 /* Copy to entry. */
1649 if (entry->key_mask)
1650 memcpy(&entry->key_mask[offset],
1658 val = strtoull(mf_val, &mf_val, 0);
1662 /* Endianness conversion. */
1664 val = field_hton(val, mf->n_bits);
1666 /* Copy to entry. */
1667 memcpy(&entry->key[offset],
1672 tokens += 1 + table->info.n_match_fields;
1673 n_tokens -= 1 + table->info.n_match_fields;
1679 if (n_tokens && strcmp(tokens[0], "action"))
1685 action = action_find(ctl, tokens[1]);
1689 if (n_tokens < 2 + action->info.n_args * 2)
1693 entry->action_id = action - ctl->actions;
1696 for (i = 0; i < action->info.n_args; i++) {
1697 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1698 char *arg_name, *arg_val;
1702 arg_name = tokens[2 + i * 2];
1703 arg_val = tokens[2 + i * 2 + 1];
1705 if (strcmp(arg_name, arg->name) ||
1706 (strlen(arg_val) < 4) ||
1707 ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1708 (arg_val[1] != '(') ||
1709 (arg_val[strlen(arg_val) - 1] != ')'))
1712 if (arg_val[0] == 'N')
1715 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1716 arg_val += 2; /* Remove the "H(" or "N(". */
1718 val = strtoull(arg_val, &arg_val, 0);
1722 /* Endianness conversion. */
1724 val = field_hton(val, arg->n_bits);
1726 /* Copy to entry. */
1727 memcpy(&entry->action_data[arg_offset],
1731 arg_offset += arg->n_bits / 8;
1734 tokens += 2 + action->info.n_args * 2;
1735 n_tokens -= 2 + action->info.n_args * 2;
1745 table_entry_free(entry);
1747 if (is_blank_or_comment)
1748 *is_blank_or_comment = blank_or_comment;
1753 table_entry_printf(FILE *f,
1754 struct rte_swx_ctl_pipeline *ctl,
1755 struct table *table,
1756 struct rte_swx_table_entry *entry)
1758 struct action *action = &ctl->actions[entry->action_id];
1761 fprintf(f, "match ");
1762 for (i = 0; i < table->params.key_size; i++)
1763 fprintf(f, "%02x", entry->key[i]);
1765 if (entry->key_mask) {
1767 for (i = 0; i < table->params.key_size; i++)
1768 fprintf(f, "%02x", entry->key_mask[i]);
1771 fprintf(f, " action %s ", action->info.name);
1772 for (i = 0; i < action->data_size; i++)
1773 fprintf(f, "%02x", entry->action_data[i]);
1779 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1780 struct rte_swx_ctl_pipeline *ctl,
1781 const char *table_name)
1783 struct table *table;
1784 struct rte_swx_table_entry *entry;
1785 uint32_t n_entries = 0, i;
1787 if (!f || !ctl || !table_name || !table_name[0])
1790 table = table_find(ctl, table_name);
1795 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1797 table->params.key_size,
1798 table->params.key_offset);
1800 for (i = 0; i < table->params.key_size; i++)
1801 fprintf(f, "%02x", table->params.key_mask0[i]);
1803 fprintf(f, "], action data size %u bytes\n",
1804 table->params.action_data_size);
1806 /* Table entries. */
1807 TAILQ_FOREACH(entry, &table->entries, node) {
1808 table_entry_printf(f, ctl, table, entry);
1812 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1813 table_entry_printf(f, ctl, table, entry);
1817 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1818 table_entry_printf(f, ctl, table, entry);
1822 fprintf(f, "# Table %s currently has %u entries.\n",