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), EINVAL);
347 static struct rte_swx_table_entry *
348 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
350 struct rte_swx_table_entry *entry,
354 struct table *table = &ctl->tables[table_id];
355 struct rte_swx_table_entry *new_entry = NULL;
360 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
364 if (key_duplicate && !table->is_stub) {
369 new_entry->key = malloc(table->params.key_size);
373 memcpy(new_entry->key, entry->key, table->params.key_size);
376 new_entry->key_signature = entry->key_signature;
379 if (entry->key_mask) {
380 new_entry->key_mask = malloc(table->params.key_size);
381 if (!new_entry->key_mask)
384 memcpy(new_entry->key_mask,
386 table->params.key_size);
390 new_entry->key_priority = entry->key_priority;
393 if (data_duplicate) {
398 for (i = 0; i < table->info.n_actions; i++)
399 if (entry->action_id == table->actions[i].action_id)
402 if (i >= table->info.n_actions)
405 new_entry->action_id = entry->action_id;
408 a = &ctl->actions[entry->action_id];
409 if (a->data_size && !entry->action_data)
412 /* The table layer provisions a constant action data size per
413 * entry, which should be the largest data size for all the
414 * actions enabled for the current table, and attempts to copy
415 * this many bytes each time a table entry is added, even if the
416 * specific action requires less data or even no data at all,
417 * hence we always have to allocate the max.
419 new_entry->action_data = calloc(1, table->params.action_data_size);
420 if (!new_entry->action_data)
424 memcpy(new_entry->action_data,
432 table_entry_free(new_entry);
437 table_entry_keycmp(struct table *table,
438 struct rte_swx_table_entry *e0,
439 struct rte_swx_table_entry *e1)
441 uint32_t key_size = table->params.key_size;
444 for (i = 0; i < key_size; i++) {
445 uint8_t *key_mask0 = table->params.key_mask0;
446 uint8_t km0, km[2], k[2];
448 km0 = key_mask0 ? key_mask0[i] : 0xFF;
450 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
451 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
456 /* Mask comparison. */
457 if ((km[0] & km0) != (km[1] & km0))
458 return 1; /* Not equal. */
460 /* Value comparison. */
461 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
462 return 1; /* Not equal. */
465 return 0; /* Equal. */
468 static struct rte_swx_table_entry *
469 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
471 struct rte_swx_table_entry *e;
473 TAILQ_FOREACH(e, &table->entries, node)
474 if (!table_entry_keycmp(table, entry, e))
475 return e; /* Found. */
477 return NULL; /* Not found. */
481 table_entries_free(struct table *table)
484 struct rte_swx_table_entry *entry;
486 entry = TAILQ_FIRST(&table->entries);
490 TAILQ_REMOVE(&table->entries, entry, node);
491 table_entry_free(entry);
495 static struct rte_swx_table_entry *
496 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
498 struct rte_swx_table_entry *e;
500 TAILQ_FOREACH(e, &table->pending_add, node)
501 if (!table_entry_keycmp(table, entry, e))
502 return e; /* Found. */
504 return NULL; /* Not found. */
508 table_pending_add_admit(struct table *table)
510 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
514 table_pending_add_free(struct table *table)
517 struct rte_swx_table_entry *entry;
519 entry = TAILQ_FIRST(&table->pending_add);
523 TAILQ_REMOVE(&table->pending_add, entry, node);
524 table_entry_free(entry);
528 static struct rte_swx_table_entry *
529 table_pending_modify0_find(struct table *table,
530 struct rte_swx_table_entry *entry)
532 struct rte_swx_table_entry *e;
534 TAILQ_FOREACH(e, &table->pending_modify0, node)
535 if (!table_entry_keycmp(table, entry, e))
536 return e; /* Found. */
538 return NULL; /* Not found. */
542 table_pending_modify0_admit(struct table *table)
544 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
548 table_pending_modify0_free(struct table *table)
551 struct rte_swx_table_entry *entry;
553 entry = TAILQ_FIRST(&table->pending_modify0);
557 TAILQ_REMOVE(&table->pending_modify0, entry, node);
558 table_entry_free(entry);
562 static struct rte_swx_table_entry *
563 table_pending_modify1_find(struct table *table,
564 struct rte_swx_table_entry *entry)
566 struct rte_swx_table_entry *e;
568 TAILQ_FOREACH(e, &table->pending_modify1, node)
569 if (!table_entry_keycmp(table, entry, e))
570 return e; /* Found. */
572 return NULL; /* Not found. */
576 table_pending_modify1_admit(struct table *table)
578 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
582 table_pending_modify1_free(struct table *table)
585 struct rte_swx_table_entry *entry;
587 entry = TAILQ_FIRST(&table->pending_modify1);
591 TAILQ_REMOVE(&table->pending_modify1, entry, node);
592 table_entry_free(entry);
596 static struct rte_swx_table_entry *
597 table_pending_delete_find(struct table *table,
598 struct rte_swx_table_entry *entry)
600 struct rte_swx_table_entry *e;
602 TAILQ_FOREACH(e, &table->pending_delete, node)
603 if (!table_entry_keycmp(table, entry, e))
604 return e; /* Found. */
606 return NULL; /* Not found. */
610 table_pending_delete_admit(struct table *table)
612 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
616 table_pending_delete_free(struct table *table)
619 struct rte_swx_table_entry *entry;
621 entry = TAILQ_FIRST(&table->pending_delete);
625 TAILQ_REMOVE(&table->pending_delete, entry, node);
626 table_entry_free(entry);
631 table_pending_default_free(struct table *table)
633 if (!table->pending_default)
636 free(table->pending_default->action_data);
637 free(table->pending_default);
638 table->pending_default = NULL;
642 table_is_update_pending(struct table *table, int consider_pending_default)
644 struct rte_swx_table_entry *e;
648 TAILQ_FOREACH(e, &table->pending_add, node)
651 /* Pending modify. */
652 TAILQ_FOREACH(e, &table->pending_modify1, node)
655 /* Pending delete. */
656 TAILQ_FOREACH(e, &table->pending_delete, node)
659 /* Pending default. */
660 if (consider_pending_default && table->pending_default)
667 table_free(struct rte_swx_ctl_pipeline *ctl)
674 for (i = 0; i < ctl->info.n_tables; i++) {
675 struct table *table = &ctl->tables[i];
678 free(table->actions);
679 free(table->params.key_mask0);
681 table_entries_free(table);
682 table_pending_add_free(table);
683 table_pending_modify0_free(table);
684 table_pending_modify1_free(table);
685 table_pending_delete_free(table);
686 table_pending_default_free(table);
694 table_state_free(struct rte_swx_ctl_pipeline *ctl)
701 /* For each table, free its table state. */
702 for (i = 0; i < ctl->info.n_tables; i++) {
703 struct table *table = &ctl->tables[i];
704 struct rte_swx_table_state *ts = &ctl->ts_next[i];
706 /* Default action data. */
707 free(ts->default_action_data);
710 if (!table->is_stub && table->ops.free && ts->obj)
711 table->ops.free(ts->obj);
719 table_state_create(struct rte_swx_ctl_pipeline *ctl)
724 ctl->ts_next = calloc(ctl->info.n_tables,
725 sizeof(struct rte_swx_table_state));
731 for (i = 0; i < ctl->info.n_tables; i++) {
732 struct table *table = &ctl->tables[i];
733 struct rte_swx_table_state *ts = &ctl->ts[i];
734 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
737 if (!table->is_stub && table->ops.add) {
738 ts_next->obj = table->ops.create(&table->params,
748 if (!table->is_stub && !table->ops.add)
749 ts_next->obj = ts->obj;
751 /* Default action data: duplicate from current table state. */
752 ts_next->default_action_data =
753 malloc(table->params.action_data_size);
754 if (!ts_next->default_action_data) {
759 memcpy(ts_next->default_action_data,
760 ts->default_action_data,
761 table->params.action_data_size);
763 ts_next->default_action_id = ts->default_action_id;
769 table_state_free(ctl);
774 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
781 table_state_free(ctl);
788 struct rte_swx_ctl_pipeline *
789 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
791 struct rte_swx_ctl_pipeline *ctl = NULL;
798 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
803 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
808 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
816 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
820 for (i = 0; i < ctl->info.n_actions; i++) {
821 struct action *a = &ctl->actions[i];
825 status = rte_swx_ctl_action_info_get(p, i, &a->info);
830 a->args = calloc(a->info.n_args,
831 sizeof(struct rte_swx_ctl_action_arg_info));
835 for (j = 0; j < a->info.n_args; j++) {
836 status = rte_swx_ctl_action_arg_info_get(p,
845 for (j = 0; j < a->info.n_args; j++) {
846 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
848 a->data_size += info->n_bits;
851 a->data_size = (a->data_size + 7) / 8;
855 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
859 for (i = 0; i < ctl->info.n_tables; i++) {
860 struct table *t = &ctl->tables[i];
862 TAILQ_INIT(&t->entries);
863 TAILQ_INIT(&t->pending_add);
864 TAILQ_INIT(&t->pending_modify0);
865 TAILQ_INIT(&t->pending_modify1);
866 TAILQ_INIT(&t->pending_delete);
869 for (i = 0; i < ctl->info.n_tables; i++) {
870 struct table *t = &ctl->tables[i];
874 status = rte_swx_ctl_table_info_get(p, i, &t->info);
879 t->mf = calloc(t->info.n_match_fields,
880 sizeof(struct rte_swx_ctl_table_match_field_info));
884 for (j = 0; j < t->info.n_match_fields; j++) {
885 status = rte_swx_ctl_table_match_field_info_get(p,
894 t->actions = calloc(t->info.n_actions,
895 sizeof(struct rte_swx_ctl_table_action_info));
899 for (j = 0; j < t->info.n_actions; j++) {
900 status = rte_swx_ctl_table_action_info_get(p,
905 t->actions[j].action_id >= ctl->info.n_actions)
910 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
914 if ((t->is_stub && t->info.n_match_fields) ||
915 (!t->is_stub && !t->info.n_match_fields))
919 status = table_params_get(ctl, i);
925 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
930 status = table_state_create(ctl);
937 rte_swx_ctl_pipeline_free(ctl);
942 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
943 const char *table_name,
944 struct rte_swx_table_entry *entry)
947 struct rte_swx_table_entry *new_entry, *existing_entry;
951 CHECK(table_name && table_name[0], EINVAL);
953 table = table_find(ctl, table_name);
954 CHECK(table, EINVAL);
955 table_id = table - ctl->tables;
957 CHECK(entry, EINVAL);
958 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
960 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
961 CHECK(new_entry, ENOMEM);
963 /* The new entry is found in the table->entries list:
964 * - Add the new entry to the table->pending_modify1 list;
965 * - Move the existing entry from the table->entries list to the
966 * table->pending_modify0 list.
968 existing_entry = table_entries_find(table, entry);
969 if (existing_entry) {
970 TAILQ_INSERT_TAIL(&table->pending_modify1,
974 TAILQ_REMOVE(&table->entries,
978 TAILQ_INSERT_TAIL(&table->pending_modify0,
985 /* The new entry is found in the table->pending_add list:
986 * - Replace the entry in the table->pending_add list with the new entry
987 * (and free the replaced entry).
989 existing_entry = table_pending_add_find(table, entry);
990 if (existing_entry) {
991 TAILQ_INSERT_AFTER(&table->pending_add,
996 TAILQ_REMOVE(&table->pending_add,
1000 table_entry_free(existing_entry);
1005 /* The new entry is found in the table->pending_modify1 list:
1006 * - Replace the entry in the table->pending_modify1 list with the new
1007 * entry (and free the replaced entry).
1009 existing_entry = table_pending_modify1_find(table, entry);
1010 if (existing_entry) {
1011 TAILQ_INSERT_AFTER(&table->pending_modify1,
1016 TAILQ_REMOVE(&table->pending_modify1,
1020 table_entry_free(existing_entry);
1025 /* The new entry is found in the table->pending_delete list:
1026 * - Add the new entry to the table->pending_modify1 list;
1027 * - Move the existing entry from the table->pending_delete list to the
1028 * table->pending_modify0 list.
1030 existing_entry = table_pending_delete_find(table, entry);
1031 if (existing_entry) {
1032 TAILQ_INSERT_TAIL(&table->pending_modify1,
1036 TAILQ_REMOVE(&table->pending_delete,
1040 TAILQ_INSERT_TAIL(&table->pending_modify0,
1047 /* The new entry is not found in any of the above lists:
1048 * - Add the new entry to the table->pending_add list.
1050 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
1056 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1057 const char *table_name,
1058 struct rte_swx_table_entry *entry)
1060 struct table *table;
1061 struct rte_swx_table_entry *existing_entry;
1066 CHECK(table_name && table_name[0], EINVAL);
1067 table = table_find(ctl, table_name);
1068 CHECK(table, EINVAL);
1069 table_id = table - ctl->tables;
1071 CHECK(entry, EINVAL);
1072 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1074 /* The entry is found in the table->entries list:
1075 * - Move the existing entry from the table->entries list to to the
1076 * table->pending_delete list.
1078 existing_entry = table_entries_find(table, entry);
1079 if (existing_entry) {
1080 TAILQ_REMOVE(&table->entries,
1084 TAILQ_INSERT_TAIL(&table->pending_delete,
1091 /* The entry is found in the table->pending_add list:
1092 * - Remove the entry from the table->pending_add list and free it.
1094 existing_entry = table_pending_add_find(table, entry);
1095 if (existing_entry) {
1096 TAILQ_REMOVE(&table->pending_add,
1100 table_entry_free(existing_entry);
1103 /* The entry is found in the table->pending_modify1 list:
1104 * - Free the entry in the table->pending_modify1 list;
1105 * - Move the existing entry from the table->pending_modify0 list to the
1106 * table->pending_delete list.
1108 existing_entry = table_pending_modify1_find(table, entry);
1109 if (existing_entry) {
1110 struct rte_swx_table_entry *real_existing_entry;
1112 TAILQ_REMOVE(&table->pending_modify1,
1116 table_entry_free(existing_entry);
1118 real_existing_entry = table_pending_modify0_find(table, entry);
1119 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1121 TAILQ_REMOVE(&table->pending_modify0,
1122 real_existing_entry,
1125 TAILQ_INSERT_TAIL(&table->pending_delete,
1126 real_existing_entry,
1132 /* The entry is found in the table->pending_delete list:
1133 * - Do nothing: the existing entry is already in the
1134 * table->pending_delete list, i.e. already marked for delete, so
1135 * simply keep it there as it is.
1138 /* The entry is not found in any of the above lists:
1139 * - Do nothing: no existing entry to delete.
1146 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1147 const char *table_name,
1148 struct rte_swx_table_entry *entry)
1150 struct table *table;
1151 struct rte_swx_table_entry *new_entry;
1156 CHECK(table_name && table_name[0], EINVAL);
1157 table = table_find(ctl, table_name);
1158 CHECK(table, EINVAL);
1159 table_id = table - ctl->tables;
1160 CHECK(!table->info.default_action_is_const, EINVAL);
1162 CHECK(entry, EINVAL);
1163 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1165 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1166 CHECK(new_entry, ENOMEM);
1168 table_pending_default_free(table);
1170 table->pending_default = new_entry;
1176 table_entry_list_free(struct rte_swx_table_entry_list *list)
1179 struct rte_swx_table_entry *entry;
1181 entry = TAILQ_FIRST(list);
1185 TAILQ_REMOVE(list, entry, node);
1186 table_entry_free(entry);
1191 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
1193 struct rte_swx_table_entry_list *dst,
1194 struct rte_swx_table_entry_list *src)
1196 struct rte_swx_table_entry *src_entry;
1198 TAILQ_FOREACH(src_entry, src, node) {
1199 struct rte_swx_table_entry *dst_entry;
1201 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
1205 TAILQ_INSERT_TAIL(dst, dst_entry, node);
1211 table_entry_list_free(dst);
1215 /* This commit stage contains all the operations that can fail; in case ANY of
1216 * them fails for ANY table, ALL of them are rolled back for ALL the tables.
1219 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
1221 uint32_t after_swap)
1223 struct table *table = &ctl->tables[table_id];
1224 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1225 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1227 if (table->is_stub || !table_is_update_pending(table, 0))
1231 * Current table supports incremental update.
1233 if (table->ops.add) {
1234 /* Reset counters. */
1236 table->n_modify = 0;
1237 table->n_delete = 0;
1239 /* Add pending rules. */
1240 struct rte_swx_table_entry *entry;
1242 TAILQ_FOREACH(entry, &table->pending_add, node) {
1245 status = table->ops.add(ts_next->obj, entry);
1252 /* Modify pending rules. */
1253 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1256 status = table->ops.add(ts_next->obj, entry);
1263 /* Delete pending rules. */
1264 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1267 status = table->ops.del(ts_next->obj, entry);
1278 * Current table does NOT support incremental update.
1281 struct rte_swx_table_entry_list list;
1284 /* Create updated list of entries included. */
1287 status = table_entry_list_duplicate(ctl,
1294 status = table_entry_list_duplicate(ctl,
1297 &table->pending_add);
1301 status = table_entry_list_duplicate(ctl,
1304 &table->pending_modify1);
1308 /* Create new table object with the updates included. */
1309 ts_next->obj = table->ops.create(&table->params,
1313 if (!ts_next->obj) {
1318 table_entry_list_free(&list);
1323 table_entry_list_free(&list);
1327 /* Free the old table object. */
1328 if (ts_next->obj && table->ops.free)
1329 table->ops.free(ts_next->obj);
1331 /* Copy over the new table object. */
1332 ts_next->obj = ts->obj;
1337 /* This commit stage contains all the operations that cannot fail. They are
1338 * executed only if the previous stage was successful for ALL the tables. Hence,
1339 * none of these operations has to be rolled back for ANY table.
1342 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1344 struct table *table = &ctl->tables[table_id];
1345 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1347 uint8_t *action_data;
1350 /* Copy the pending default entry. */
1351 if (!table->pending_default)
1354 action_id = table->pending_default->action_id;
1355 action_data = table->pending_default->action_data;
1356 a = &ctl->actions[action_id];
1358 memcpy(ts_next->default_action_data,
1362 ts_next->default_action_id = action_id;
1365 /* This last commit stage is simply finalizing a successful commit operation.
1366 * This stage is only executed if all the previous stages were successful. This
1367 * stage cannot fail.
1370 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1372 struct table *table = &ctl->tables[table_id];
1374 /* Move all the pending add entries to the table, as they are now part
1377 table_pending_add_admit(table);
1379 /* Move all the pending modify1 entries to table, are they are now part
1380 * of the table. Free up all the pending modify0 entries, as they are no
1381 * longer part of the table.
1383 table_pending_modify1_admit(table);
1384 table_pending_modify0_free(table);
1386 /* Free up all the pending delete entries, as they are no longer part of
1389 table_pending_delete_free(table);
1391 /* Free up the pending default entry, as it is now part of the table. */
1392 table_pending_default_free(table);
1395 /* The rollback stage is only executed when the commit failed, i.e. ANY of the
1396 * commit operations that can fail did fail for ANY table. It reverts ALL the
1397 * tables to their state before the commit started, as if the commit never
1401 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1403 struct table *table = &ctl->tables[table_id];
1404 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1406 if (table->is_stub || !table_is_update_pending(table, 0))
1409 if (table->ops.add) {
1410 struct rte_swx_table_entry *entry;
1412 /* Add back all the entries that were just deleted. */
1413 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1414 if (!table->n_delete)
1417 table->ops.add(ts_next->obj, entry);
1421 /* Add back the old copy for all the entries that were just
1424 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1425 if (!table->n_modify)
1428 table->ops.add(ts_next->obj, entry);
1432 /* Delete all the entries that were just added. */
1433 TAILQ_FOREACH(entry, &table->pending_add, node) {
1437 table->ops.del(ts_next->obj, entry);
1441 struct rte_swx_table_state *ts = &ctl->ts[table_id];
1443 /* Free the new table object, as update was cancelled. */
1444 if (ts_next->obj && table->ops.free)
1445 table->ops.free(ts_next->obj);
1447 /* Reinstate the old table object. */
1448 ts_next->obj = ts->obj;
1452 /* This stage is conditionally executed (as instructed by the user) after a
1453 * failed commit operation to remove ALL the pending work for ALL the tables.
1456 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1458 struct table *table = &ctl->tables[table_id];
1460 /* Free up all the pending add entries, as none of them is part of the
1463 table_pending_add_free(table);
1465 /* Free up all the pending modify1 entries, as none of them made it to
1466 * the table. Add back all the pending modify0 entries, as none of them
1467 * was deleted from the table.
1469 table_pending_modify1_free(table);
1470 table_pending_modify0_admit(table);
1472 /* Add back all the pending delete entries, as none of them was deleted
1475 table_pending_delete_admit(table);
1477 /* Free up the pending default entry, as it is no longer going to be
1478 * added to the table.
1480 table_pending_default_free(table);
1484 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1486 struct rte_swx_table_state *ts;
1492 /* Operate the changes on the current ts_next before it becomes the new
1495 for (i = 0; i < ctl->info.n_tables; i++) {
1496 status = table_rollfwd0(ctl, i, 0);
1501 for (i = 0; i < ctl->info.n_tables; i++)
1502 table_rollfwd1(ctl, i);
1504 /* Swap the table state for the data plane. The current ts and ts_next
1505 * become the new ts_next and ts, respectively.
1507 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1510 ctl->ts = ctl->ts_next;
1513 /* Operate the changes on the current ts_next, which is the previous ts.
1515 for (i = 0; i < ctl->info.n_tables; i++) {
1516 table_rollfwd0(ctl, i, 1);
1517 table_rollfwd1(ctl, i);
1518 table_rollfwd2(ctl, i);
1524 for (i = 0; i < ctl->info.n_tables; i++) {
1525 table_rollback(ctl, i);
1527 table_abort(ctl, i);
1534 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1541 for (i = 0; i < ctl->info.n_tables; i++)
1542 table_abort(ctl, i);
1546 token_is_comment(const char *token)
1548 if ((token[0] == '#') ||
1549 (token[0] == ';') ||
1550 ((token[0] == '/') && (token[1] == '/')))
1551 return 1; /* TRUE. */
1553 return 0; /* FALSE. */
1556 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1558 struct rte_swx_table_entry *
1559 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1560 const char *table_name,
1562 int *is_blank_or_comment)
1564 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
1565 struct table *table;
1566 struct action *action;
1567 struct rte_swx_table_entry *entry = NULL;
1568 char *s0 = NULL, *s;
1569 uint32_t n_tokens = 0, arg_offset = 0, i;
1570 int blank_or_comment = 0;
1572 /* Check input arguments. */
1576 if (!table_name || !table_name[0])
1579 table = table_find(ctl, table_name);
1583 if (!string || !string[0])
1586 /* Memory allocation. */
1587 s0 = strdup(string);
1591 entry = table_entry_alloc(table);
1595 /* Parse the string into tokens. */
1599 token = strtok_r(s, " \f\n\r\t\v", &s);
1600 if (!token || token_is_comment(token))
1603 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1606 token_array[n_tokens] = token;
1611 blank_or_comment = 1;
1615 tokens = token_array;
1620 if (n_tokens && strcmp(tokens[0], "match"))
1623 if (n_tokens < 1 + table->info.n_match_fields)
1626 for (i = 0; i < table->info.n_match_fields; i++) {
1627 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1628 char *mf_val = tokens[1 + i], *mf_mask = NULL;
1629 uint64_t val, mask = UINT64_MAX;
1630 uint32_t offset = (mf->offset - table->mf[0].offset) / 8;
1635 mf_mask = strchr(mf_val, '/');
1641 mask = strtoull(mf_mask, &mf_mask, 0);
1645 /* Endianness conversion. */
1647 mask = field_hton(mask, mf->n_bits);
1650 /* Copy to entry. */
1651 if (entry->key_mask)
1652 memcpy(&entry->key_mask[offset],
1660 val = strtoull(mf_val, &mf_val, 0);
1664 /* Endianness conversion. */
1666 val = field_hton(val, mf->n_bits);
1668 /* Copy to entry. */
1669 memcpy(&entry->key[offset],
1674 tokens += 1 + table->info.n_match_fields;
1675 n_tokens -= 1 + table->info.n_match_fields;
1680 if (n_tokens && !strcmp(tokens[0], "priority")) {
1681 char *priority = tokens[1];
1688 val = strtoul(priority, &priority, 0);
1692 /* Copy to entry. */
1693 entry->key_priority = val;
1703 if (n_tokens && strcmp(tokens[0], "action"))
1709 action = action_find(ctl, tokens[1]);
1713 if (n_tokens < 2 + action->info.n_args * 2)
1717 entry->action_id = action - ctl->actions;
1720 for (i = 0; i < action->info.n_args; i++) {
1721 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1722 char *arg_name, *arg_val;
1726 arg_name = tokens[2 + i * 2];
1727 arg_val = tokens[2 + i * 2 + 1];
1729 if (strcmp(arg_name, arg->name) ||
1730 (strlen(arg_val) < 4) ||
1731 ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1732 (arg_val[1] != '(') ||
1733 (arg_val[strlen(arg_val) - 1] != ')'))
1736 if (arg_val[0] == 'N')
1739 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1740 arg_val += 2; /* Remove the "H(" or "N(". */
1742 val = strtoull(arg_val, &arg_val, 0);
1746 /* Endianness conversion. */
1748 val = field_hton(val, arg->n_bits);
1750 /* Copy to entry. */
1751 memcpy(&entry->action_data[arg_offset],
1755 arg_offset += arg->n_bits / 8;
1758 tokens += 2 + action->info.n_args * 2;
1759 n_tokens -= 2 + action->info.n_args * 2;
1769 table_entry_free(entry);
1771 if (is_blank_or_comment)
1772 *is_blank_or_comment = blank_or_comment;
1777 table_entry_printf(FILE *f,
1778 struct rte_swx_ctl_pipeline *ctl,
1779 struct table *table,
1780 struct rte_swx_table_entry *entry)
1782 struct action *action = &ctl->actions[entry->action_id];
1785 fprintf(f, "match ");
1786 for (i = 0; i < table->params.key_size; i++)
1787 fprintf(f, "%02x", entry->key[i]);
1789 if (entry->key_mask) {
1791 for (i = 0; i < table->params.key_size; i++)
1792 fprintf(f, "%02x", entry->key_mask[i]);
1795 fprintf(f, " priority %u", entry->key_priority);
1797 fprintf(f, " action %s ", action->info.name);
1798 for (i = 0; i < action->data_size; i++)
1799 fprintf(f, "%02x", entry->action_data[i]);
1805 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1806 struct rte_swx_ctl_pipeline *ctl,
1807 const char *table_name)
1809 struct table *table;
1810 struct rte_swx_table_entry *entry;
1811 uint32_t n_entries = 0, i;
1813 if (!f || !ctl || !table_name || !table_name[0])
1816 table = table_find(ctl, table_name);
1821 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1823 table->params.key_size,
1824 table->params.key_offset);
1826 for (i = 0; i < table->params.key_size; i++)
1827 fprintf(f, "%02x", table->params.key_mask0[i]);
1829 fprintf(f, "], action data size %u bytes\n",
1830 table->params.action_data_size);
1832 /* Table entries. */
1833 TAILQ_FOREACH(entry, &table->entries, node) {
1834 table_entry_printf(f, ctl, table, entry);
1838 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1839 table_entry_printf(f, ctl, table, entry);
1843 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1844 table_entry_printf(f, ctl, table, entry);
1848 fprintf(f, "# Table %s currently has %u entries.\n",