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 struct rte_swx_table_entry_list entries;
46 struct rte_swx_table_entry_list pending_add;
47 struct rte_swx_table_entry_list pending_modify0;
48 struct rte_swx_table_entry_list pending_modify1;
49 struct rte_swx_table_entry_list pending_delete;
50 struct rte_swx_table_entry *pending_default;
58 struct rte_swx_ctl_pipeline {
59 struct rte_swx_ctl_pipeline_info info;
60 struct rte_swx_pipeline *p;
61 struct action *actions;
63 struct rte_swx_table_state *ts;
64 struct rte_swx_table_state *ts_next;
68 static struct action *
69 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
73 for (i = 0; i < ctl->info.n_actions; i++) {
74 struct action *a = &ctl->actions[i];
76 if (!strcmp(action_name, a->info.name))
84 action_free(struct rte_swx_ctl_pipeline *ctl)
91 for (i = 0; i < ctl->info.n_actions; i++) {
92 struct action *action = &ctl->actions[i];
101 static struct table *
102 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
106 for (i = 0; i < ctl->info.n_tables; i++) {
107 struct table *table = &ctl->tables[i];
109 if (!strcmp(table_name, table->info.name))
117 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
119 struct table *table = &ctl->tables[table_id];
120 uint8_t *key_mask = NULL;
121 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
122 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
124 if (table->info.n_match_fields) {
125 struct rte_swx_ctl_table_match_field_info *first, *last;
128 first = &table->mf[0];
129 last = &table->mf[table->info.n_match_fields - 1];
132 for (i = 0; i < table->info.n_match_fields; i++) {
133 struct rte_swx_ctl_table_match_field_info *f;
136 if (f->match_type != RTE_SWX_TABLE_MATCH_EXACT)
140 if (i == table->info.n_match_fields)
141 match_type = RTE_SWX_TABLE_MATCH_EXACT;
142 else if ((i == table->info.n_match_fields - 1) &&
143 (last->match_type == RTE_SWX_TABLE_MATCH_LPM))
144 match_type = RTE_SWX_TABLE_MATCH_LPM;
147 key_offset = first->offset / 8;
150 key_size = (last->offset + last->n_bits - first->offset) / 8;
153 key_mask = calloc(1, key_size);
154 CHECK(key_mask, ENOMEM);
156 for (i = 0; i < table->info.n_match_fields; i++) {
157 struct rte_swx_ctl_table_match_field_info *f;
162 start = (f->offset - first->offset) / 8;
163 size = f->n_bits / 8;
165 memset(&key_mask[start], 0xFF, size);
169 /* action_data_size. */
170 for (i = 0; i < table->info.n_actions; i++) {
171 uint32_t action_id = table->actions[i].action_id;
172 struct action *a = &ctl->actions[action_id];
174 if (a->data_size > action_data_size)
175 action_data_size = a->data_size;
179 table->params.match_type = match_type;
180 table->params.key_size = key_size;
181 table->params.key_offset = key_offset;
182 table->params.key_mask0 = key_mask;
183 table->params.action_data_size = action_data_size;
184 table->params.n_keys_max = table->info.size;
190 table_entry_free(struct rte_swx_table_entry *entry)
196 free(entry->key_mask);
197 free(entry->action_data);
201 static struct rte_swx_table_entry *
202 table_entry_alloc(struct table *table)
204 struct rte_swx_table_entry *entry;
206 entry = calloc(1, sizeof(struct rte_swx_table_entry));
211 if (!table->is_stub) {
212 entry->key = calloc(1, table->params.key_size);
216 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
217 entry->key_mask = calloc(1, table->params.key_size);
218 if (!entry->key_mask)
224 if (table->params.action_data_size) {
225 entry->action_data = calloc(1, table->params.action_data_size);
226 if (!entry->action_data)
233 table_entry_free(entry);
238 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
240 uint8_t *key_mask0 = table->params.key_mask0;
241 uint32_t key_size = table->params.key_size, i;
243 if (!entry->key_mask)
246 for (i = 0; i < key_size; i++) {
247 uint8_t km0 = key_mask0[i];
248 uint8_t km = entry->key_mask[i];
250 if ((km & km0) != km0)
258 table_entry_check(struct rte_swx_ctl_pipeline *ctl,
260 struct rte_swx_table_entry *entry,
264 struct table *table = &ctl->tables[table_id];
267 CHECK(entry, EINVAL);
270 if (table->is_stub) {
272 CHECK(!entry->key, EINVAL);
275 CHECK(!entry->key_mask, EINVAL);
278 CHECK(entry->key, EINVAL);
281 switch (table->params.match_type) {
282 case RTE_SWX_TABLE_MATCH_WILDCARD:
285 case RTE_SWX_TABLE_MATCH_LPM:
286 /* TBD Check that key mask is prefix. */
289 case RTE_SWX_TABLE_MATCH_EXACT:
290 status = table_entry_key_check_em(table, entry);
306 for (i = 0; i < table->info.n_actions; i++)
307 if (entry->action_id == table->actions[i].action_id)
310 CHECK(i < table->info.n_actions, EINVAL);
313 a = &ctl->actions[entry->action_id];
314 CHECK((a->data_size && entry->action_data) ||
315 (!a->data_size && !entry->action_data), EINVAL);
321 static struct rte_swx_table_entry *
322 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
324 struct rte_swx_table_entry *entry,
328 struct table *table = &ctl->tables[table_id];
329 struct rte_swx_table_entry *new_entry = NULL;
334 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
338 if (key_duplicate && !table->is_stub) {
343 new_entry->key = malloc(table->params.key_size);
347 memcpy(new_entry->key, entry->key, table->params.key_size);
350 new_entry->key_signature = entry->key_signature;
353 if (entry->key_mask) {
354 new_entry->key_mask = malloc(table->params.key_size);
355 if (!new_entry->key_mask)
358 memcpy(new_entry->key_mask,
360 table->params.key_size);
364 if (data_duplicate) {
369 for (i = 0; i < table->info.n_actions; i++)
370 if (entry->action_id == table->actions[i].action_id)
373 if (i >= table->info.n_actions)
376 new_entry->action_id = entry->action_id;
379 a = &ctl->actions[entry->action_id];
380 if (a->data_size && !entry->action_data)
383 /* The table layer provisions a constant action data size per
384 * entry, which should be the largest data size for all the
385 * actions enabled for the current table, and attempts to copy
386 * this many bytes each time a table entry is added, even if the
387 * specific action requires less data or even no data at all,
388 * hence we always have to allocate the max.
390 new_entry->action_data = calloc(1, table->params.action_data_size);
391 if (!new_entry->action_data)
395 memcpy(new_entry->action_data,
403 table_entry_free(new_entry);
408 table_entry_keycmp(struct table *table,
409 struct rte_swx_table_entry *e0,
410 struct rte_swx_table_entry *e1)
412 uint32_t key_size = table->params.key_size;
415 for (i = 0; i < key_size; i++) {
416 uint8_t *key_mask0 = table->params.key_mask0;
417 uint8_t km0, km[2], k[2];
419 km0 = key_mask0 ? key_mask0[i] : 0xFF;
421 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
422 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
427 /* Mask comparison. */
428 if ((km[0] & km0) != (km[1] & km0))
429 return 1; /* Not equal. */
431 /* Value comparison. */
432 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
433 return 1; /* Not equal. */
436 return 0; /* Equal. */
439 static struct rte_swx_table_entry *
440 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
442 struct rte_swx_table_entry *e;
444 TAILQ_FOREACH(e, &table->entries, node)
445 if (!table_entry_keycmp(table, entry, e))
446 return e; /* Found. */
448 return NULL; /* Not found. */
452 table_entries_free(struct table *table)
455 struct rte_swx_table_entry *entry;
457 entry = TAILQ_FIRST(&table->entries);
461 TAILQ_REMOVE(&table->entries, entry, node);
462 table_entry_free(entry);
466 static struct rte_swx_table_entry *
467 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
469 struct rte_swx_table_entry *e;
471 TAILQ_FOREACH(e, &table->pending_add, node)
472 if (!table_entry_keycmp(table, entry, e))
473 return e; /* Found. */
475 return NULL; /* Not found. */
479 table_pending_add_admit(struct table *table)
481 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
485 table_pending_add_free(struct table *table)
488 struct rte_swx_table_entry *entry;
490 entry = TAILQ_FIRST(&table->pending_add);
494 TAILQ_REMOVE(&table->pending_add, entry, node);
495 table_entry_free(entry);
499 static struct rte_swx_table_entry *
500 table_pending_modify0_find(struct table *table,
501 struct rte_swx_table_entry *entry)
503 struct rte_swx_table_entry *e;
505 TAILQ_FOREACH(e, &table->pending_modify0, node)
506 if (!table_entry_keycmp(table, entry, e))
507 return e; /* Found. */
509 return NULL; /* Not found. */
513 table_pending_modify0_admit(struct table *table)
515 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
519 table_pending_modify0_free(struct table *table)
522 struct rte_swx_table_entry *entry;
524 entry = TAILQ_FIRST(&table->pending_modify0);
528 TAILQ_REMOVE(&table->pending_modify0, entry, node);
529 table_entry_free(entry);
533 static struct rte_swx_table_entry *
534 table_pending_modify1_find(struct table *table,
535 struct rte_swx_table_entry *entry)
537 struct rte_swx_table_entry *e;
539 TAILQ_FOREACH(e, &table->pending_modify1, node)
540 if (!table_entry_keycmp(table, entry, e))
541 return e; /* Found. */
543 return NULL; /* Not found. */
547 table_pending_modify1_admit(struct table *table)
549 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
553 table_pending_modify1_free(struct table *table)
556 struct rte_swx_table_entry *entry;
558 entry = TAILQ_FIRST(&table->pending_modify1);
562 TAILQ_REMOVE(&table->pending_modify1, entry, node);
563 table_entry_free(entry);
567 static struct rte_swx_table_entry *
568 table_pending_delete_find(struct table *table,
569 struct rte_swx_table_entry *entry)
571 struct rte_swx_table_entry *e;
573 TAILQ_FOREACH(e, &table->pending_delete, node)
574 if (!table_entry_keycmp(table, entry, e))
575 return e; /* Found. */
577 return NULL; /* Not found. */
581 table_pending_delete_admit(struct table *table)
583 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
587 table_pending_delete_free(struct table *table)
590 struct rte_swx_table_entry *entry;
592 entry = TAILQ_FIRST(&table->pending_delete);
596 TAILQ_REMOVE(&table->pending_delete, entry, node);
597 table_entry_free(entry);
602 table_pending_default_free(struct table *table)
604 if (!table->pending_default)
607 free(table->pending_default->action_data);
608 free(table->pending_default);
609 table->pending_default = NULL;
613 table_free(struct rte_swx_ctl_pipeline *ctl)
620 for (i = 0; i < ctl->info.n_tables; i++) {
621 struct table *table = &ctl->tables[i];
624 free(table->actions);
625 free(table->params.key_mask0);
627 table_entries_free(table);
628 table_pending_add_free(table);
629 table_pending_modify0_free(table);
630 table_pending_modify1_free(table);
631 table_pending_delete_free(table);
632 table_pending_default_free(table);
640 table_state_free(struct rte_swx_ctl_pipeline *ctl)
647 /* For each table, free its table state. */
648 for (i = 0; i < ctl->info.n_tables; i++) {
649 struct table *table = &ctl->tables[i];
650 struct rte_swx_table_state *ts = &ctl->ts_next[i];
652 /* Default action data. */
653 free(ts->default_action_data);
656 if (!table->is_stub && table->ops.free && ts->obj)
657 table->ops.free(ts->obj);
665 table_state_create(struct rte_swx_ctl_pipeline *ctl)
670 ctl->ts_next = calloc(ctl->info.n_tables,
671 sizeof(struct rte_swx_table_state));
677 for (i = 0; i < ctl->info.n_tables; i++) {
678 struct table *table = &ctl->tables[i];
679 struct rte_swx_table_state *ts = &ctl->ts[i];
680 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
683 if (!table->is_stub) {
684 ts_next->obj = table->ops.create(&table->params,
694 /* Default action data: duplicate from current table state. */
695 ts_next->default_action_data =
696 malloc(table->params.action_data_size);
697 if (!ts_next->default_action_data) {
702 memcpy(ts_next->default_action_data,
703 ts->default_action_data,
704 table->params.action_data_size);
706 ts_next->default_action_id = ts->default_action_id;
712 table_state_free(ctl);
717 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
724 table_state_free(ctl);
731 struct rte_swx_ctl_pipeline *
732 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
734 struct rte_swx_ctl_pipeline *ctl = NULL;
741 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
746 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
751 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
759 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
763 for (i = 0; i < ctl->info.n_actions; i++) {
764 struct action *a = &ctl->actions[i];
768 status = rte_swx_ctl_action_info_get(p, i, &a->info);
773 a->args = calloc(a->info.n_args,
774 sizeof(struct rte_swx_ctl_action_arg_info));
778 for (j = 0; j < a->info.n_args; j++) {
779 status = rte_swx_ctl_action_arg_info_get(p,
788 for (j = 0; j < a->info.n_args; j++) {
789 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
791 a->data_size += info->n_bits;
794 a->data_size = (a->data_size + 7) / 8;
798 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
802 for (i = 0; i < ctl->info.n_tables; i++) {
803 struct table *t = &ctl->tables[i];
805 TAILQ_INIT(&t->entries);
806 TAILQ_INIT(&t->pending_add);
807 TAILQ_INIT(&t->pending_modify0);
808 TAILQ_INIT(&t->pending_modify1);
809 TAILQ_INIT(&t->pending_delete);
812 for (i = 0; i < ctl->info.n_tables; i++) {
813 struct table *t = &ctl->tables[i];
817 status = rte_swx_ctl_table_info_get(p, i, &t->info);
822 t->mf = calloc(t->info.n_match_fields,
823 sizeof(struct rte_swx_ctl_table_match_field_info));
827 for (j = 0; j < t->info.n_match_fields; j++) {
828 status = rte_swx_ctl_table_match_field_info_get(p,
837 t->actions = calloc(t->info.n_actions,
838 sizeof(struct rte_swx_ctl_table_action_info));
842 for (j = 0; j < t->info.n_actions; j++) {
843 status = rte_swx_ctl_table_action_info_get(p,
848 t->actions[j].action_id >= ctl->info.n_actions)
853 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
857 if ((t->is_stub && t->info.n_match_fields) ||
858 (!t->is_stub && !t->info.n_match_fields))
862 status = table_params_get(ctl, i);
868 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
873 status = table_state_create(ctl);
880 rte_swx_ctl_pipeline_free(ctl);
885 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
886 const char *table_name,
887 struct rte_swx_table_entry *entry)
890 struct rte_swx_table_entry *new_entry, *existing_entry;
894 CHECK(table_name && table_name[0], EINVAL);
896 table = table_find(ctl, table_name);
897 CHECK(table, EINVAL);
898 table_id = table - ctl->tables;
900 CHECK(entry, EINVAL);
901 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
903 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
904 CHECK(new_entry, ENOMEM);
906 /* The new entry is found in the table->entries list:
907 * - Add the new entry to the table->pending_modify1 list;
908 * - Move the existing entry from the table->entries list to the
909 * table->pending_modify0 list.
911 existing_entry = table_entries_find(table, entry);
912 if (existing_entry) {
913 TAILQ_INSERT_TAIL(&table->pending_modify1,
917 TAILQ_REMOVE(&table->entries,
921 TAILQ_INSERT_TAIL(&table->pending_modify0,
928 /* The new entry is found in the table->pending_add list:
929 * - Replace the entry in the table->pending_add list with the new entry
930 * (and free the replaced entry).
932 existing_entry = table_pending_add_find(table, entry);
933 if (existing_entry) {
934 TAILQ_INSERT_AFTER(&table->pending_add,
939 TAILQ_REMOVE(&table->pending_add,
943 table_entry_free(existing_entry);
948 /* The new entry is found in the table->pending_modify1 list:
949 * - Replace the entry in the table->pending_modify1 list with the new
950 * entry (and free the replaced entry).
952 existing_entry = table_pending_modify1_find(table, entry);
953 if (existing_entry) {
954 TAILQ_INSERT_AFTER(&table->pending_modify1,
959 TAILQ_REMOVE(&table->pending_modify1,
963 table_entry_free(existing_entry);
968 /* The new entry is found in the table->pending_delete list:
969 * - Add the new entry to the table->pending_modify1 list;
970 * - Move the existing entry from the table->pending_delete list to the
971 * table->pending_modify0 list.
973 existing_entry = table_pending_delete_find(table, entry);
974 if (existing_entry) {
975 TAILQ_INSERT_TAIL(&table->pending_modify1,
979 TAILQ_REMOVE(&table->pending_delete,
983 TAILQ_INSERT_TAIL(&table->pending_modify0,
990 /* The new entry is not found in any of the above lists:
991 * - Add the new entry to the table->pending_add list.
993 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
999 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
1000 const char *table_name,
1001 struct rte_swx_table_entry *entry)
1003 struct table *table;
1004 struct rte_swx_table_entry *existing_entry;
1009 CHECK(table_name && table_name[0], EINVAL);
1010 table = table_find(ctl, table_name);
1011 CHECK(table, EINVAL);
1012 table_id = table - ctl->tables;
1014 CHECK(entry, EINVAL);
1015 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1017 /* The entry is found in the table->entries list:
1018 * - Move the existing entry from the table->entries list to to the
1019 * table->pending_delete list.
1021 existing_entry = table_entries_find(table, entry);
1022 if (existing_entry) {
1023 TAILQ_REMOVE(&table->entries,
1027 TAILQ_INSERT_TAIL(&table->pending_delete,
1034 /* The entry is found in the table->pending_add list:
1035 * - Remove the entry from the table->pending_add list and free it.
1037 existing_entry = table_pending_add_find(table, entry);
1038 if (existing_entry) {
1039 TAILQ_REMOVE(&table->pending_add,
1043 table_entry_free(existing_entry);
1046 /* The entry is found in the table->pending_modify1 list:
1047 * - Free the entry in the table->pending_modify1 list;
1048 * - Move the existing entry from the table->pending_modify0 list to the
1049 * table->pending_delete list.
1051 existing_entry = table_pending_modify1_find(table, entry);
1052 if (existing_entry) {
1053 struct rte_swx_table_entry *real_existing_entry;
1055 TAILQ_REMOVE(&table->pending_modify1,
1059 table_entry_free(existing_entry);
1061 real_existing_entry = table_pending_modify0_find(table, entry);
1062 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1064 TAILQ_REMOVE(&table->pending_modify0,
1065 real_existing_entry,
1068 TAILQ_INSERT_TAIL(&table->pending_delete,
1069 real_existing_entry,
1075 /* The entry is found in the table->pending_delete list:
1076 * - Do nothing: the existing entry is already in the
1077 * table->pending_delete list, i.e. already marked for delete, so
1078 * simply keep it there as it is.
1081 /* The entry is not found in any of the above lists:
1082 * - Do nothing: no existing entry to delete.
1089 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1090 const char *table_name,
1091 struct rte_swx_table_entry *entry)
1093 struct table *table;
1094 struct rte_swx_table_entry *new_entry;
1099 CHECK(table_name && table_name[0], EINVAL);
1100 table = table_find(ctl, table_name);
1101 CHECK(table, EINVAL);
1102 table_id = table - ctl->tables;
1103 CHECK(!table->info.default_action_is_const, EINVAL);
1105 CHECK(entry, EINVAL);
1106 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
1108 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1109 CHECK(new_entry, ENOMEM);
1111 table_pending_default_free(table);
1113 table->pending_default = new_entry;
1118 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1120 struct table *table = &ctl->tables[table_id];
1121 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1122 struct rte_swx_table_entry *entry;
1124 /* Reset counters. */
1126 table->n_modify = 0;
1127 table->n_delete = 0;
1129 /* Add pending rules. */
1130 TAILQ_FOREACH(entry, &table->pending_add, node) {
1133 status = table->ops.add(ts_next->obj, entry);
1140 /* Modify pending rules. */
1141 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1144 status = table->ops.add(ts_next->obj, entry);
1151 /* Delete pending rules. */
1152 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1155 status = table->ops.del(ts_next->obj, entry);
1166 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1168 struct table *table = &ctl->tables[table_id];
1169 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1171 uint8_t *action_data;
1174 /* Copy the pending default entry. */
1175 if (!table->pending_default)
1178 action_id = table->pending_default->action_id;
1179 action_data = table->pending_default->action_data;
1180 a = &ctl->actions[action_id];
1182 memcpy(ts_next->default_action_data,
1186 ts_next->default_action_id = action_id;
1190 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1192 struct table *table = &ctl->tables[table_id];
1194 /* Move all the pending add entries to the table, as they are now part
1197 table_pending_add_admit(table);
1199 /* Move all the pending modify1 entries to table, are they are now part
1200 * of the table. Free up all the pending modify0 entries, as they are no
1201 * longer part of the table.
1203 table_pending_modify1_admit(table);
1204 table_pending_modify0_free(table);
1206 /* Free up all the pending delete entries, as they are no longer part of
1209 table_pending_delete_free(table);
1211 /* Free up the pending default entry, as it is now part of the table. */
1212 table_pending_default_free(table);
1216 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1218 struct table *table = &ctl->tables[table_id];
1219 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1220 struct rte_swx_table_entry *entry;
1222 /* Add back all the entries that were just deleted. */
1223 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1224 if (!table->n_delete)
1227 table->ops.add(ts_next->obj, entry);
1231 /* Add back the old copy for all the entries that were just
1234 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1235 if (!table->n_modify)
1238 table->ops.add(ts_next->obj, entry);
1242 /* Delete all the entries that were just added. */
1243 TAILQ_FOREACH(entry, &table->pending_add, node) {
1247 table->ops.del(ts_next->obj, entry);
1253 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1255 struct table *table = &ctl->tables[table_id];
1257 /* Free up all the pending add entries, as none of them is part of the
1260 table_pending_add_free(table);
1262 /* Free up all the pending modify1 entries, as none of them made it to
1263 * the table. Add back all the pending modify0 entries, as none of them
1264 * was deleted from the table.
1266 table_pending_modify1_free(table);
1267 table_pending_modify0_admit(table);
1269 /* Add back all the pending delete entries, as none of them was deleted
1272 table_pending_delete_admit(table);
1274 /* Free up the pending default entry, as it is no longer going to be
1275 * added to the table.
1277 table_pending_default_free(table);
1281 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1283 struct rte_swx_table_state *ts;
1289 /* Operate the changes on the current ts_next before it becomes the new
1292 for (i = 0; i < ctl->info.n_tables; i++) {
1293 status = table_rollfwd0(ctl, i);
1298 for (i = 0; i < ctl->info.n_tables; i++)
1299 table_rollfwd1(ctl, i);
1301 /* Swap the table state for the data plane. The current ts and ts_next
1302 * become the new ts_next and ts, respectively.
1304 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1307 ctl->ts = ctl->ts_next;
1310 /* Operate the changes on the current ts_next, which is the previous ts.
1312 for (i = 0; i < ctl->info.n_tables; i++) {
1313 table_rollfwd0(ctl, i);
1314 table_rollfwd1(ctl, i);
1315 table_rollfwd2(ctl, i);
1321 for (i = 0; i < ctl->info.n_tables; i++) {
1322 table_rollback(ctl, i);
1324 table_abort(ctl, i);
1331 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1338 for (i = 0; i < ctl->info.n_tables; i++)
1339 table_abort(ctl, i);
1342 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1344 struct rte_swx_table_entry *
1345 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1346 const char *table_name,
1349 char *tokens[RTE_SWX_CTL_ENTRY_TOKENS_MAX];
1350 struct table *table;
1351 struct action *action;
1352 struct rte_swx_table_entry *entry = NULL;
1353 char *s0 = NULL, *s;
1354 uint32_t n_tokens = 0, arg_offset = 0, i;
1356 /* Check input arguments. */
1360 if (!table_name || !table_name[0])
1363 table = table_find(ctl, table_name);
1367 if (!string || !string[0])
1370 /* Memory allocation. */
1371 s0 = strdup(string);
1375 entry = table_entry_alloc(table);
1379 /* Parse the string into tokens. */
1383 token = strtok_r(s, " \f\n\r\t\v", &s);
1387 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1390 tokens[n_tokens] = token;
1394 if ((n_tokens < 3 + table->info.n_match_fields) ||
1395 strcmp(tokens[0], "match") ||
1396 strcmp(tokens[1 + table->info.n_match_fields], "action"))
1399 action = action_find(ctl, tokens[2 + table->info.n_match_fields]);
1403 if (n_tokens != 3 + table->info.n_match_fields +
1404 action->info.n_args * 2)
1410 for (i = 0; i < table->info.n_match_fields; i++) {
1411 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1412 char *mf_val = tokens[1 + i];
1415 val = strtoull(mf_val, &mf_val, 0);
1419 /* Endianness conversion. */
1421 val = field_hton(val, mf->n_bits);
1423 /* Copy key and key_mask to entry. */
1424 memcpy(&entry->key[(mf->offset - table->mf[0].offset) / 8],
1428 /* TBD Set entry->key_mask for wildcard and LPM tables. */
1435 entry->action_id = action - ctl->actions;
1438 for (i = 0; i < action->info.n_args; i++) {
1439 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1440 char *arg_name, *arg_val;
1444 arg_name = tokens[3 + table->info.n_match_fields + i * 2];
1445 arg_val = tokens[3 + table->info.n_match_fields + i * 2 + 1];
1447 if (strcmp(arg_name, arg->name) ||
1448 (strlen(arg_val) < 4) ||
1449 ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1450 (arg_val[1] != '(') ||
1451 (arg_val[strlen(arg_val) - 1] != ')'))
1454 if (arg_val[0] == 'N')
1457 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1458 arg_val += 2; /* Remove the "H(" or "N(". */
1460 val = strtoull(arg_val, &arg_val, 0);
1464 /* Endianness conversion. */
1466 val = field_hton(val, arg->n_bits);
1468 /* Copy to entry. */
1469 memcpy(&entry->action_data[arg_offset],
1473 arg_offset += arg->n_bits / 8;
1480 table_entry_free(entry);
1486 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1487 struct rte_swx_ctl_pipeline *ctl,
1488 const char *table_name)
1490 struct table *table;
1491 struct rte_swx_table_entry *entry;
1492 uint32_t n_entries = 0, i;
1494 if (!f || !ctl || !table_name || !table_name[0])
1497 table = table_find(ctl, table_name);
1502 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1504 table->params.key_size,
1505 table->params.key_offset);
1507 for (i = 0; i < table->params.key_size; i++)
1508 fprintf(f, "%02x", table->params.key_mask0[i]);
1510 fprintf(f, "], action data size %u bytes\n",
1511 table->params.action_data_size);
1513 /* Table entries. */
1514 TAILQ_FOREACH(entry, &table->entries, node) {
1515 struct action *action = &ctl->actions[entry->action_id];
1517 fprintf(f, "match ");
1518 for (i = 0; i < table->params.key_size; i++)
1519 fprintf(f, "%02x", entry->key[i]);
1521 fprintf(f, " action %s ", action->info.name);
1522 for (i = 0; i < action->data_size; i++)
1523 fprintf(f, "%02x", entry->action_data[i]);
1529 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1530 struct action *action = &ctl->actions[entry->action_id];
1532 fprintf(f, "match ");
1533 for (i = 0; i < table->params.key_size; i++)
1534 fprintf(f, "%02x", entry->key[i]);
1536 fprintf(f, " action %s ", action->info.name);
1537 for (i = 0; i < action->data_size; i++)
1538 fprintf(f, "%02x", entry->action_data[i]);
1544 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1545 struct action *action = &ctl->actions[entry->action_id];
1547 fprintf(f, "match ");
1548 for (i = 0; i < table->params.key_size; i++)
1549 fprintf(f, "%02x", entry->key[i]);
1551 fprintf(f, " action %s ", action->info.name);
1552 for (i = 0; i < action->data_size; i++)
1553 fprintf(f, "%02x", entry->action_data[i]);
1559 fprintf(f, "# Table %s currently has %u entries.\n",