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_check(struct rte_swx_ctl_pipeline *ctl,
240 struct rte_swx_table_entry *entry,
244 struct table *table = &ctl->tables[table_id];
246 CHECK(entry, EINVAL);
249 if (table->is_stub) {
251 CHECK(!entry->key, EINVAL);
254 CHECK(!entry->key_mask, EINVAL);
257 CHECK(entry->key, EINVAL);
260 switch (table->params.match_type) {
261 case RTE_SWX_TABLE_MATCH_WILDCARD:
264 case RTE_SWX_TABLE_MATCH_LPM:
265 /* TBD Check that key mask is prefix. */
268 case RTE_SWX_TABLE_MATCH_EXACT:
269 CHECK(!entry->key_mask, EINVAL);
283 for (i = 0; i < table->info.n_actions; i++)
284 if (entry->action_id == table->actions[i].action_id)
287 CHECK(i < table->info.n_actions, EINVAL);
290 a = &ctl->actions[entry->action_id];
291 CHECK((a->data_size && entry->action_data) ||
292 (!a->data_size && !entry->action_data), EINVAL);
298 static struct rte_swx_table_entry *
299 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
301 struct rte_swx_table_entry *entry,
305 struct table *table = &ctl->tables[table_id];
306 struct rte_swx_table_entry *new_entry = NULL;
311 new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
315 if (key_duplicate && !table->is_stub) {
320 new_entry->key = malloc(table->params.key_size);
324 memcpy(new_entry->key, entry->key, table->params.key_size);
327 new_entry->key_signature = entry->key_signature;
330 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
331 if (!entry->key_mask)
334 new_entry->key_mask = malloc(table->params.key_size);
335 if (!new_entry->key_mask)
338 memcpy(new_entry->key_mask,
340 table->params.key_size);
344 if (data_duplicate) {
349 for (i = 0; i < table->info.n_actions; i++)
350 if (entry->action_id == table->actions[i].action_id)
353 if (i >= table->info.n_actions)
356 new_entry->action_id = entry->action_id;
359 a = &ctl->actions[entry->action_id];
361 if (!entry->action_data)
364 new_entry->action_data = malloc(a->data_size);
365 if (!new_entry->action_data)
368 memcpy(new_entry->action_data,
377 table_entry_free(new_entry);
382 entry_keycmp_em(struct rte_swx_table_entry *e0,
383 struct rte_swx_table_entry *e1,
386 if (e0->key_signature != e1->key_signature)
387 return 1; /* Not equal. */
389 if (memcmp(e0->key, e1->key, key_size))
390 return 1; /* Not equal. */
392 return 0; /* Equal */
396 entry_keycmp_wm(struct rte_swx_table_entry *e0 __rte_unused,
397 struct rte_swx_table_entry *e1 __rte_unused,
398 uint32_t key_size __rte_unused)
402 return 1; /* Not equal */
406 entry_keycmp_lpm(struct rte_swx_table_entry *e0 __rte_unused,
407 struct rte_swx_table_entry *e1 __rte_unused,
408 uint32_t key_size __rte_unused)
412 return 1; /* Not equal */
416 table_entry_keycmp(struct table *table,
417 struct rte_swx_table_entry *e0,
418 struct rte_swx_table_entry *e1)
420 switch (table->params.match_type) {
421 case RTE_SWX_TABLE_MATCH_EXACT:
422 return entry_keycmp_em(e0, e1, table->params.key_size);
424 case RTE_SWX_TABLE_MATCH_WILDCARD:
425 return entry_keycmp_wm(e0, e1, table->params.key_size);
427 case RTE_SWX_TABLE_MATCH_LPM:
428 return entry_keycmp_lpm(e0, e1, table->params.key_size);
431 return 1; /* Not equal. */
435 static struct rte_swx_table_entry *
436 table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
438 struct rte_swx_table_entry *e;
440 TAILQ_FOREACH(e, &table->entries, node)
441 if (!table_entry_keycmp(table, entry, e))
442 return e; /* Found. */
444 return NULL; /* Not found. */
448 table_entries_free(struct table *table)
451 struct rte_swx_table_entry *entry;
453 entry = TAILQ_FIRST(&table->entries);
457 TAILQ_REMOVE(&table->entries, entry, node);
458 table_entry_free(entry);
462 static struct rte_swx_table_entry *
463 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
465 struct rte_swx_table_entry *e;
467 TAILQ_FOREACH(e, &table->pending_add, node)
468 if (!table_entry_keycmp(table, entry, e))
469 return e; /* Found. */
471 return NULL; /* Not found. */
475 table_pending_add_admit(struct table *table)
477 TAILQ_CONCAT(&table->entries, &table->pending_add, node);
481 table_pending_add_free(struct table *table)
484 struct rte_swx_table_entry *entry;
486 entry = TAILQ_FIRST(&table->pending_add);
490 TAILQ_REMOVE(&table->pending_add, entry, node);
491 table_entry_free(entry);
495 static struct rte_swx_table_entry *
496 table_pending_modify0_find(struct table *table,
497 struct rte_swx_table_entry *entry)
499 struct rte_swx_table_entry *e;
501 TAILQ_FOREACH(e, &table->pending_modify0, node)
502 if (!table_entry_keycmp(table, entry, e))
503 return e; /* Found. */
505 return NULL; /* Not found. */
509 table_pending_modify0_admit(struct table *table)
511 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
515 table_pending_modify0_free(struct table *table)
518 struct rte_swx_table_entry *entry;
520 entry = TAILQ_FIRST(&table->pending_modify0);
524 TAILQ_REMOVE(&table->pending_modify0, entry, node);
525 table_entry_free(entry);
529 static struct rte_swx_table_entry *
530 table_pending_modify1_find(struct table *table,
531 struct rte_swx_table_entry *entry)
533 struct rte_swx_table_entry *e;
535 TAILQ_FOREACH(e, &table->pending_modify1, node)
536 if (!table_entry_keycmp(table, entry, e))
537 return e; /* Found. */
539 return NULL; /* Not found. */
543 table_pending_modify1_admit(struct table *table)
545 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
549 table_pending_modify1_free(struct table *table)
552 struct rte_swx_table_entry *entry;
554 entry = TAILQ_FIRST(&table->pending_modify1);
558 TAILQ_REMOVE(&table->pending_modify1, entry, node);
559 table_entry_free(entry);
563 static struct rte_swx_table_entry *
564 table_pending_delete_find(struct table *table,
565 struct rte_swx_table_entry *entry)
567 struct rte_swx_table_entry *e;
569 TAILQ_FOREACH(e, &table->pending_delete, node)
570 if (!table_entry_keycmp(table, entry, e))
571 return e; /* Found. */
573 return NULL; /* Not found. */
577 table_pending_delete_admit(struct table *table)
579 TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
583 table_pending_delete_free(struct table *table)
586 struct rte_swx_table_entry *entry;
588 entry = TAILQ_FIRST(&table->pending_delete);
592 TAILQ_REMOVE(&table->pending_delete, entry, node);
593 table_entry_free(entry);
598 table_pending_default_free(struct table *table)
600 if (!table->pending_default)
603 free(table->pending_default->action_data);
604 free(table->pending_default);
605 table->pending_default = NULL;
609 table_free(struct rte_swx_ctl_pipeline *ctl)
616 for (i = 0; i < ctl->info.n_tables; i++) {
617 struct table *table = &ctl->tables[i];
620 free(table->actions);
621 free(table->params.key_mask0);
623 table_entries_free(table);
624 table_pending_add_free(table);
625 table_pending_modify0_free(table);
626 table_pending_modify1_free(table);
627 table_pending_delete_free(table);
628 table_pending_default_free(table);
636 table_state_free(struct rte_swx_ctl_pipeline *ctl)
643 /* For each table, free its table state. */
644 for (i = 0; i < ctl->info.n_tables; i++) {
645 struct table *table = &ctl->tables[i];
646 struct rte_swx_table_state *ts = &ctl->ts_next[i];
648 /* Default action data. */
649 free(ts->default_action_data);
652 if (!table->is_stub && table->ops.free && ts->obj)
653 table->ops.free(ts->obj);
661 table_state_create(struct rte_swx_ctl_pipeline *ctl)
666 ctl->ts_next = calloc(ctl->info.n_tables,
667 sizeof(struct rte_swx_table_state));
673 for (i = 0; i < ctl->info.n_tables; i++) {
674 struct table *table = &ctl->tables[i];
675 struct rte_swx_table_state *ts = &ctl->ts[i];
676 struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
679 if (!table->is_stub) {
680 ts_next->obj = table->ops.create(&table->params,
690 /* Default action data: duplicate from current table state. */
691 ts_next->default_action_data =
692 malloc(table->params.action_data_size);
693 if (!ts_next->default_action_data) {
698 memcpy(ts_next->default_action_data,
699 ts->default_action_data,
700 table->params.action_data_size);
702 ts_next->default_action_id = ts->default_action_id;
708 table_state_free(ctl);
713 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
720 table_state_free(ctl);
727 struct rte_swx_ctl_pipeline *
728 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
730 struct rte_swx_ctl_pipeline *ctl = NULL;
737 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
742 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
747 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
755 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
759 for (i = 0; i < ctl->info.n_actions; i++) {
760 struct action *a = &ctl->actions[i];
764 status = rte_swx_ctl_action_info_get(p, i, &a->info);
769 a->args = calloc(a->info.n_args,
770 sizeof(struct rte_swx_ctl_action_arg_info));
774 for (j = 0; j < a->info.n_args; j++) {
775 status = rte_swx_ctl_action_arg_info_get(p,
784 for (j = 0; j < a->info.n_args; j++) {
785 struct rte_swx_ctl_action_arg_info *info = &a->args[j];
787 a->data_size += info->n_bits;
790 a->data_size = (a->data_size + 7) / 8;
794 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
798 for (i = 0; i < ctl->info.n_tables; i++) {
799 struct table *t = &ctl->tables[i];
801 TAILQ_INIT(&t->entries);
802 TAILQ_INIT(&t->pending_add);
803 TAILQ_INIT(&t->pending_modify0);
804 TAILQ_INIT(&t->pending_modify1);
805 TAILQ_INIT(&t->pending_delete);
808 for (i = 0; i < ctl->info.n_tables; i++) {
809 struct table *t = &ctl->tables[i];
813 status = rte_swx_ctl_table_info_get(p, i, &t->info);
818 t->mf = calloc(t->info.n_match_fields,
819 sizeof(struct rte_swx_ctl_table_match_field_info));
823 for (j = 0; j < t->info.n_match_fields; j++) {
824 status = rte_swx_ctl_table_match_field_info_get(p,
833 t->actions = calloc(t->info.n_actions,
834 sizeof(struct rte_swx_ctl_table_action_info));
838 for (j = 0; j < t->info.n_actions; j++) {
839 status = rte_swx_ctl_table_action_info_get(p,
844 t->actions[j].action_id >= ctl->info.n_actions)
849 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
853 if ((t->is_stub && t->info.n_match_fields) ||
854 (!t->is_stub && !t->info.n_match_fields))
858 status = table_params_get(ctl, i);
864 status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
869 status = table_state_create(ctl);
876 rte_swx_ctl_pipeline_free(ctl);
881 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
882 const char *table_name,
883 struct rte_swx_table_entry *entry)
886 struct rte_swx_table_entry *new_entry, *existing_entry;
890 CHECK(table_name && table_name[0], EINVAL);
892 table = table_find(ctl, table_name);
893 CHECK(table, EINVAL);
894 table_id = table - ctl->tables;
896 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
897 CHECK(new_entry, ENOMEM);
899 /* The new entry is found in the table->entries list:
900 * - Add the new entry to the table->pending_modify1 list;
901 * - Move the existing entry from the table->entries list to the
902 * table->pending_modify0 list.
904 existing_entry = table_entries_find(table, entry);
905 if (existing_entry) {
906 TAILQ_INSERT_TAIL(&table->pending_modify1,
910 TAILQ_REMOVE(&table->entries,
914 TAILQ_INSERT_TAIL(&table->pending_modify0,
921 /* The new entry is found in the table->pending_add list:
922 * - Replace the entry in the table->pending_add list with the new entry
923 * (and free the replaced entry).
925 existing_entry = table_pending_add_find(table, entry);
926 if (existing_entry) {
927 TAILQ_INSERT_AFTER(&table->pending_add,
932 TAILQ_REMOVE(&table->pending_add,
936 table_entry_free(existing_entry);
941 /* The new entry is found in the table->pending_modify1 list:
942 * - Replace the entry in the table->pending_modify1 list with the new
943 * entry (and free the replaced entry).
945 existing_entry = table_pending_modify1_find(table, entry);
946 if (existing_entry) {
947 TAILQ_INSERT_AFTER(&table->pending_modify1,
952 TAILQ_REMOVE(&table->pending_modify1,
956 table_entry_free(existing_entry);
961 /* The new entry is found in the table->pending_delete list:
962 * - Add the new entry to the table->pending_modify1 list;
963 * - Move the existing entry from the table->pending_delete list to the
964 * table->pending_modify0 list.
966 existing_entry = table_pending_delete_find(table, entry);
967 if (existing_entry) {
968 TAILQ_INSERT_TAIL(&table->pending_modify1,
972 TAILQ_REMOVE(&table->pending_delete,
976 TAILQ_INSERT_TAIL(&table->pending_modify0,
983 /* The new entry is not found in any of the above lists:
984 * - Add the new entry to the table->pending_add list.
986 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
992 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
993 const char *table_name,
994 struct rte_swx_table_entry *entry)
997 struct rte_swx_table_entry *existing_entry;
1002 CHECK(table_name && table_name[0], EINVAL);
1003 table = table_find(ctl, table_name);
1004 CHECK(table, EINVAL);
1005 table_id = table - ctl->tables;
1007 CHECK(entry, EINVAL);
1008 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
1010 /* The entry is found in the table->entries list:
1011 * - Move the existing entry from the table->entries list to to the
1012 * table->pending_delete list.
1014 existing_entry = table_entries_find(table, entry);
1015 if (existing_entry) {
1016 TAILQ_REMOVE(&table->entries,
1020 TAILQ_INSERT_TAIL(&table->pending_delete,
1027 /* The entry is found in the table->pending_add list:
1028 * - Remove the entry from the table->pending_add list and free it.
1030 existing_entry = table_pending_add_find(table, entry);
1031 if (existing_entry) {
1032 TAILQ_REMOVE(&table->pending_add,
1036 table_entry_free(existing_entry);
1039 /* The entry is found in the table->pending_modify1 list:
1040 * - Free the entry in the table->pending_modify1 list;
1041 * - Move the existing entry from the table->pending_modify0 list to the
1042 * table->pending_delete list.
1044 existing_entry = table_pending_modify1_find(table, entry);
1045 if (existing_entry) {
1046 struct rte_swx_table_entry *real_existing_entry;
1048 TAILQ_REMOVE(&table->pending_modify1,
1052 table_entry_free(existing_entry);
1054 real_existing_entry = table_pending_modify0_find(table, entry);
1055 CHECK(real_existing_entry, EINVAL); /* Coverity. */
1057 TAILQ_REMOVE(&table->pending_modify0,
1058 real_existing_entry,
1061 TAILQ_INSERT_TAIL(&table->pending_delete,
1062 real_existing_entry,
1068 /* The entry is found in the table->pending_delete list:
1069 * - Do nothing: the existing entry is already in the
1070 * table->pending_delete list, i.e. already marked for delete, so
1071 * simply keep it there as it is.
1074 /* The entry is not found in any of the above lists:
1075 * - Do nothing: no existing entry to delete.
1082 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
1083 const char *table_name,
1084 struct rte_swx_table_entry *entry)
1086 struct table *table;
1087 struct rte_swx_table_entry *new_entry;
1092 CHECK(table_name && table_name[0], EINVAL);
1093 table = table_find(ctl, table_name);
1094 CHECK(table, EINVAL);
1095 table_id = table - ctl->tables;
1096 CHECK(!table->info.default_action_is_const, EINVAL);
1098 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
1099 CHECK(new_entry, ENOMEM);
1101 table_pending_default_free(table);
1103 table->pending_default = new_entry;
1108 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1110 struct table *table = &ctl->tables[table_id];
1111 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1112 struct rte_swx_table_entry *entry;
1114 /* Reset counters. */
1116 table->n_modify = 0;
1117 table->n_delete = 0;
1119 /* Add pending rules. */
1120 TAILQ_FOREACH(entry, &table->pending_add, node) {
1123 status = table->ops.add(ts_next->obj, entry);
1130 /* Modify pending rules. */
1131 TAILQ_FOREACH(entry, &table->pending_modify1, node) {
1134 status = table->ops.add(ts_next->obj, entry);
1141 /* Delete pending rules. */
1142 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1145 status = table->ops.del(ts_next->obj, entry);
1156 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1158 struct table *table = &ctl->tables[table_id];
1159 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1161 uint8_t *action_data;
1164 /* Copy the pending default entry. */
1165 if (!table->pending_default)
1168 action_id = table->pending_default->action_id;
1169 action_data = table->pending_default->action_data;
1170 a = &ctl->actions[action_id];
1172 memcpy(ts_next->default_action_data,
1176 ts_next->default_action_id = action_id;
1180 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1182 struct table *table = &ctl->tables[table_id];
1184 /* Move all the pending add entries to the table, as they are now part
1187 table_pending_add_admit(table);
1189 /* Move all the pending modify1 entries to table, are they are now part
1190 * of the table. Free up all the pending modify0 entries, as they are no
1191 * longer part of the table.
1193 table_pending_modify1_admit(table);
1194 table_pending_modify0_free(table);
1196 /* Free up all the pending delete entries, as they are no longer part of
1199 table_pending_delete_free(table);
1201 /* Free up the pending default entry, as it is now part of the table. */
1202 table_pending_default_free(table);
1206 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1208 struct table *table = &ctl->tables[table_id];
1209 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
1210 struct rte_swx_table_entry *entry;
1212 /* Add back all the entries that were just deleted. */
1213 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1214 if (!table->n_delete)
1217 table->ops.add(ts_next->obj, entry);
1221 /* Add back the old copy for all the entries that were just
1224 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1225 if (!table->n_modify)
1228 table->ops.add(ts_next->obj, entry);
1232 /* Delete all the entries that were just added. */
1233 TAILQ_FOREACH(entry, &table->pending_add, node) {
1237 table->ops.del(ts_next->obj, entry);
1243 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
1245 struct table *table = &ctl->tables[table_id];
1247 /* Free up all the pending add entries, as none of them is part of the
1250 table_pending_add_free(table);
1252 /* Free up all the pending modify1 entries, as none of them made it to
1253 * the table. Add back all the pending modify0 entries, as none of them
1254 * was deleted from the table.
1256 table_pending_modify1_free(table);
1257 table_pending_modify0_admit(table);
1259 /* Add back all the pending delete entries, as none of them was deleted
1262 table_pending_delete_admit(table);
1264 /* Free up the pending default entry, as it is no longer going to be
1265 * added to the table.
1267 table_pending_default_free(table);
1271 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
1273 struct rte_swx_table_state *ts;
1279 /* Operate the changes on the current ts_next before it becomes the new
1282 for (i = 0; i < ctl->info.n_tables; i++) {
1283 status = table_rollfwd0(ctl, i);
1288 for (i = 0; i < ctl->info.n_tables; i++)
1289 table_rollfwd1(ctl, i);
1291 /* Swap the table state for the data plane. The current ts and ts_next
1292 * become the new ts_next and ts, respectively.
1294 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
1297 ctl->ts = ctl->ts_next;
1300 /* Operate the changes on the current ts_next, which is the previous ts.
1302 for (i = 0; i < ctl->info.n_tables; i++) {
1303 table_rollfwd0(ctl, i);
1304 table_rollfwd1(ctl, i);
1305 table_rollfwd2(ctl, i);
1311 for (i = 0; i < ctl->info.n_tables; i++) {
1312 table_rollback(ctl, i);
1314 table_abort(ctl, i);
1321 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
1328 for (i = 0; i < ctl->info.n_tables; i++)
1329 table_abort(ctl, i);
1332 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
1334 struct rte_swx_table_entry *
1335 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
1336 const char *table_name,
1339 char *tokens[RTE_SWX_CTL_ENTRY_TOKENS_MAX];
1340 struct table *table;
1341 struct action *action;
1342 struct rte_swx_table_entry *entry = NULL;
1343 char *s0 = NULL, *s;
1344 uint32_t n_tokens = 0, arg_offset = 0, i;
1346 /* Check input arguments. */
1350 if (!table_name || !table_name[0])
1353 table = table_find(ctl, table_name);
1357 if (!string || !string[0])
1360 /* Memory allocation. */
1361 s0 = strdup(string);
1365 entry = table_entry_alloc(table);
1369 /* Parse the string into tokens. */
1373 token = strtok_r(s, " \f\n\r\t\v", &s);
1377 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
1380 tokens[n_tokens] = token;
1384 if ((n_tokens < 3 + table->info.n_match_fields) ||
1385 strcmp(tokens[0], "match") ||
1386 strcmp(tokens[1 + table->info.n_match_fields], "action"))
1389 action = action_find(ctl, tokens[2 + table->info.n_match_fields]);
1393 if (n_tokens != 3 + table->info.n_match_fields +
1394 action->info.n_args * 2)
1400 for (i = 0; i < table->info.n_match_fields; i++) {
1401 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
1402 char *mf_val = tokens[1 + i];
1405 val = strtoull(mf_val, &mf_val, 0);
1409 /* Endianness conversion. */
1411 val = field_hton(val, mf->n_bits);
1413 /* Copy key and key_mask to entry. */
1414 memcpy(&entry->key[(mf->offset - table->mf[0].offset) / 8],
1418 /* TBD Set entry->key_mask for wildcard and LPM tables. */
1425 entry->action_id = action - ctl->actions;
1428 for (i = 0; i < action->info.n_args; i++) {
1429 struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
1430 char *arg_name, *arg_val;
1434 arg_name = tokens[3 + table->info.n_match_fields + i * 2];
1435 arg_val = tokens[3 + table->info.n_match_fields + i * 2 + 1];
1437 if (strcmp(arg_name, arg->name) ||
1438 (strlen(arg_val) < 4) ||
1439 ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
1440 (arg_val[1] != '(') ||
1441 (arg_val[strlen(arg_val) - 1] != ')'))
1444 if (arg_val[0] == 'N')
1447 arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
1448 arg_val += 2; /* Remove the "H(" or "N(". */
1450 val = strtoull(arg_val, &arg_val, 0);
1454 /* Endianness conversion. */
1456 val = field_hton(val, arg->n_bits);
1458 /* Copy to entry. */
1459 memcpy(&entry->action_data[arg_offset],
1463 arg_offset += arg->n_bits / 8;
1469 table_entry_free(entry);
1475 rte_swx_ctl_pipeline_table_fprintf(FILE *f,
1476 struct rte_swx_ctl_pipeline *ctl,
1477 const char *table_name)
1479 struct table *table;
1480 struct rte_swx_table_entry *entry;
1481 uint32_t n_entries = 0, i;
1483 if (!f || !ctl || !table_name || !table_name[0])
1486 table = table_find(ctl, table_name);
1491 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
1493 table->params.key_size,
1494 table->params.key_offset);
1496 for (i = 0; i < table->params.key_size; i++)
1497 fprintf(f, "%02x", table->params.key_mask0[i]);
1499 fprintf(f, "], action data size %u bytes\n",
1500 table->params.action_data_size);
1502 /* Table entries. */
1503 TAILQ_FOREACH(entry, &table->entries, node) {
1504 struct action *action = &ctl->actions[entry->action_id];
1506 fprintf(f, "match ");
1507 for (i = 0; i < table->params.key_size; i++)
1508 fprintf(f, "%02x", entry->key[i]);
1510 fprintf(f, " action %s ", action->info.name);
1511 for (i = 0; i < action->data_size; i++)
1512 fprintf(f, "%02x", entry->action_data[i]);
1518 TAILQ_FOREACH(entry, &table->pending_modify0, node) {
1519 struct action *action = &ctl->actions[entry->action_id];
1521 fprintf(f, "match ");
1522 for (i = 0; i < table->params.key_size; i++)
1523 fprintf(f, "%02x", entry->key[i]);
1525 fprintf(f, " action %s ", action->info.name);
1526 for (i = 0; i < action->data_size; i++)
1527 fprintf(f, "%02x", entry->action_data[i]);
1533 TAILQ_FOREACH(entry, &table->pending_delete, node) {
1534 struct action *action = &ctl->actions[entry->action_id];
1536 fprintf(f, "match ");
1537 for (i = 0; i < table->params.key_size; i++)
1538 fprintf(f, "%02x", entry->key[i]);
1540 fprintf(f, " action %s ", action->info.name);
1541 for (i = 0; i < action->data_size; i++)
1542 fprintf(f, "%02x", entry->action_data[i]);
1548 fprintf(f, "# Table %s currently has %u entries.\n",