xref: /dpdk/lib/pipeline/rte_swx_ctl.c (revision 23f3dac43237d5de18f9544c6e3f932c70c39e27)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2020 Intel Corporation
399a2dd95SBruce Richardson  */
472b452c5SDmitry Kozlyuk #include <errno.h>
599a2dd95SBruce Richardson #include <stdlib.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson #include <stdio.h>
899a2dd95SBruce Richardson #include <sys/queue.h>
999a2dd95SBruce Richardson #include <unistd.h>
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #include <rte_common.h>
1299a2dd95SBruce Richardson #include <rte_byteorder.h>
13d69c90c8SCristian Dumitrescu #include <rte_tailq.h>
14d69c90c8SCristian Dumitrescu #include <rte_eal_memconfig.h>
1599a2dd95SBruce Richardson 
16cdaa937dSCristian Dumitrescu #include <rte_swx_table_selector.h>
17cdaa937dSCristian Dumitrescu 
1899a2dd95SBruce Richardson #include "rte_swx_ctl.h"
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson #define CHECK(condition, err_code)                                             \
2199a2dd95SBruce Richardson do {                                                                           \
2299a2dd95SBruce Richardson 	if (!(condition))                                                      \
2399a2dd95SBruce Richardson 		return -(err_code);                                            \
2499a2dd95SBruce Richardson } while (0)
2599a2dd95SBruce Richardson 
2699a2dd95SBruce Richardson #define ntoh64(x) rte_be_to_cpu_64(x)
2799a2dd95SBruce Richardson #define hton64(x) rte_cpu_to_be_64(x)
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
3099a2dd95SBruce Richardson #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
3199a2dd95SBruce Richardson #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
3299a2dd95SBruce Richardson #else
3399a2dd95SBruce Richardson #define field_ntoh(val, n_bits) (val)
3499a2dd95SBruce Richardson #define field_hton(val, n_bits) (val)
3599a2dd95SBruce Richardson #endif
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson struct action {
3899a2dd95SBruce Richardson 	struct rte_swx_ctl_action_info info;
3999a2dd95SBruce Richardson 	struct rte_swx_ctl_action_arg_info *args;
4099a2dd95SBruce Richardson 	uint32_t data_size;
4199a2dd95SBruce Richardson };
4299a2dd95SBruce Richardson 
4399a2dd95SBruce Richardson struct table {
4499a2dd95SBruce Richardson 	struct rte_swx_ctl_table_info info;
4599a2dd95SBruce Richardson 	struct rte_swx_ctl_table_match_field_info *mf;
4699a2dd95SBruce Richardson 
4799a2dd95SBruce Richardson 	/* Match field with the smallest offset. */
4899a2dd95SBruce Richardson 	struct rte_swx_ctl_table_match_field_info *mf_first;
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson 	/* Match field with the biggest offset. */
5199a2dd95SBruce Richardson 	struct rte_swx_ctl_table_match_field_info *mf_last;
5299a2dd95SBruce Richardson 
5399a2dd95SBruce Richardson 	struct rte_swx_ctl_table_action_info *actions;
5499a2dd95SBruce Richardson 	struct rte_swx_table_ops ops;
5599a2dd95SBruce Richardson 	struct rte_swx_table_params params;
5699a2dd95SBruce Richardson 
5799a2dd95SBruce Richardson 	/* Set of "stable" keys: these keys are currently part of the table;
5899a2dd95SBruce Richardson 	 * these keys will be preserved with no action data changes after the
5999a2dd95SBruce Richardson 	 * next commit.
6099a2dd95SBruce Richardson 	 */
6199a2dd95SBruce Richardson 	struct rte_swx_table_entry_list entries;
6299a2dd95SBruce Richardson 
6399a2dd95SBruce Richardson 	/* Set of new keys: these keys are currently NOT part of the table;
6499a2dd95SBruce Richardson 	 * these keys will be added to the table on the next commit, if
6599a2dd95SBruce Richardson 	 * the commit operation is successful.
6699a2dd95SBruce Richardson 	 */
6799a2dd95SBruce Richardson 	struct rte_swx_table_entry_list pending_add;
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	/* Set of keys to be modified: these keys are currently part of the
7099a2dd95SBruce Richardson 	 * table; these keys are still going to be part of the table after the
7199a2dd95SBruce Richardson 	 * next commit, but their action data will be modified if the commit
7299a2dd95SBruce Richardson 	 * operation is successful. The modify0 list contains the keys with the
7399a2dd95SBruce Richardson 	 * current action data, the modify1 list contains the keys with the
7499a2dd95SBruce Richardson 	 * modified action data.
7599a2dd95SBruce Richardson 	 */
7699a2dd95SBruce Richardson 	struct rte_swx_table_entry_list pending_modify0;
7799a2dd95SBruce Richardson 	struct rte_swx_table_entry_list pending_modify1;
7899a2dd95SBruce Richardson 
7999a2dd95SBruce Richardson 	/* Set of keys to be deleted: these keys are currently part of the
8099a2dd95SBruce Richardson 	 * table; these keys are to be deleted from the table on the next
8199a2dd95SBruce Richardson 	 * commit, if the commit operation is successful.
8299a2dd95SBruce Richardson 	 */
8399a2dd95SBruce Richardson 	struct rte_swx_table_entry_list pending_delete;
8499a2dd95SBruce Richardson 
8599a2dd95SBruce Richardson 	/* The pending default action: this is NOT the current default action;
8699a2dd95SBruce Richardson 	 * this will be the new default action after the next commit, if the
8799a2dd95SBruce Richardson 	 * next commit operation is successful.
8899a2dd95SBruce Richardson 	 */
8999a2dd95SBruce Richardson 	struct rte_swx_table_entry *pending_default;
9099a2dd95SBruce Richardson 
9199a2dd95SBruce Richardson 	int is_stub;
9299a2dd95SBruce Richardson 	uint32_t n_add;
9399a2dd95SBruce Richardson 	uint32_t n_modify;
9499a2dd95SBruce Richardson 	uint32_t n_delete;
9599a2dd95SBruce Richardson };
9699a2dd95SBruce Richardson 
97cdaa937dSCristian Dumitrescu struct selector {
98cdaa937dSCristian Dumitrescu 	/* Selector table info. */
99cdaa937dSCristian Dumitrescu 	struct rte_swx_ctl_selector_info info;
100cdaa937dSCristian Dumitrescu 
101cdaa937dSCristian Dumitrescu 	/* group_id field. */
102cdaa937dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info group_id_field;
103cdaa937dSCristian Dumitrescu 
104cdaa937dSCristian Dumitrescu 	/* selector fields. */
105cdaa937dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info *selector_fields;
106cdaa937dSCristian Dumitrescu 
107cdaa937dSCristian Dumitrescu 	/* member_id field. */
108cdaa937dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info member_id_field;
109cdaa937dSCristian Dumitrescu 
110cdaa937dSCristian Dumitrescu 	/* Current selector table. Array of info.n_groups_max elements.*/
111cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group **groups;
112cdaa937dSCristian Dumitrescu 
113cdaa937dSCristian Dumitrescu 	/* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
114cdaa937dSCristian Dumitrescu 	 */
115cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group **pending_groups;
116cdaa937dSCristian Dumitrescu 
117cdaa937dSCristian Dumitrescu 	/* Valid flag per group. Array of n_groups_max elements. */
118cdaa937dSCristian Dumitrescu 	int *groups_added;
119cdaa937dSCristian Dumitrescu 
120cdaa937dSCristian Dumitrescu 	/* Pending delete flag per group. Group deletion is subject to the next commit. Array of
121cdaa937dSCristian Dumitrescu 	 * info.n_groups_max elements.
122cdaa937dSCristian Dumitrescu 	 */
123cdaa937dSCristian Dumitrescu 	int *groups_pending_delete;
124cdaa937dSCristian Dumitrescu 
125cdaa937dSCristian Dumitrescu 	/* Params. */
126cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_params params;
127cdaa937dSCristian Dumitrescu };
128cdaa937dSCristian Dumitrescu 
1294f59d372SCristian Dumitrescu struct learner {
1304f59d372SCristian Dumitrescu 	struct rte_swx_ctl_learner_info info;
1314f59d372SCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info *mf;
1324f59d372SCristian Dumitrescu 	struct rte_swx_ctl_table_action_info *actions;
1334f59d372SCristian Dumitrescu 	uint32_t action_data_size;
1344f59d372SCristian Dumitrescu 
1354f59d372SCristian Dumitrescu 	/* The pending default action: this is NOT the current default action;
1364f59d372SCristian Dumitrescu 	 * this will be the new default action after the next commit, if the
1374f59d372SCristian Dumitrescu 	 * next commit operation is successful.
1384f59d372SCristian Dumitrescu 	 */
1394f59d372SCristian Dumitrescu 	struct rte_swx_table_entry *pending_default;
1404f59d372SCristian Dumitrescu };
1414f59d372SCristian Dumitrescu 
14299a2dd95SBruce Richardson struct rte_swx_ctl_pipeline {
14399a2dd95SBruce Richardson 	struct rte_swx_ctl_pipeline_info info;
14499a2dd95SBruce Richardson 	struct rte_swx_pipeline *p;
14599a2dd95SBruce Richardson 	struct action *actions;
14699a2dd95SBruce Richardson 	struct table *tables;
147cdaa937dSCristian Dumitrescu 	struct selector *selectors;
1484f59d372SCristian Dumitrescu 	struct learner *learners;
14999a2dd95SBruce Richardson 	struct rte_swx_table_state *ts;
15099a2dd95SBruce Richardson 	struct rte_swx_table_state *ts_next;
15199a2dd95SBruce Richardson 	int numa_node;
15299a2dd95SBruce Richardson };
15399a2dd95SBruce Richardson 
15499a2dd95SBruce Richardson static struct action *
action_find(struct rte_swx_ctl_pipeline * ctl,const char * action_name)15599a2dd95SBruce Richardson action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name)
15699a2dd95SBruce Richardson {
15799a2dd95SBruce Richardson 	uint32_t i;
15899a2dd95SBruce Richardson 
15999a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_actions; i++) {
16099a2dd95SBruce Richardson 		struct action *a = &ctl->actions[i];
16199a2dd95SBruce Richardson 
16299a2dd95SBruce Richardson 		if (!strcmp(action_name, a->info.name))
16399a2dd95SBruce Richardson 			return a;
16499a2dd95SBruce Richardson 	}
16599a2dd95SBruce Richardson 
16699a2dd95SBruce Richardson 	return NULL;
16799a2dd95SBruce Richardson }
16899a2dd95SBruce Richardson 
16999a2dd95SBruce Richardson static void
action_free(struct rte_swx_ctl_pipeline * ctl)17099a2dd95SBruce Richardson action_free(struct rte_swx_ctl_pipeline *ctl)
17199a2dd95SBruce Richardson {
17299a2dd95SBruce Richardson 	uint32_t i;
17399a2dd95SBruce Richardson 
17499a2dd95SBruce Richardson 	if (!ctl->actions)
17599a2dd95SBruce Richardson 		return;
17699a2dd95SBruce Richardson 
17799a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_actions; i++) {
17899a2dd95SBruce Richardson 		struct action *action = &ctl->actions[i];
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 		free(action->args);
18199a2dd95SBruce Richardson 	}
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 	free(ctl->actions);
18499a2dd95SBruce Richardson 	ctl->actions = NULL;
18599a2dd95SBruce Richardson }
18699a2dd95SBruce Richardson 
18799a2dd95SBruce Richardson static struct table *
table_find(struct rte_swx_ctl_pipeline * ctl,const char * table_name)18899a2dd95SBruce Richardson table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name)
18999a2dd95SBruce Richardson {
19099a2dd95SBruce Richardson 	uint32_t i;
19199a2dd95SBruce Richardson 
19299a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
19399a2dd95SBruce Richardson 		struct table *table = &ctl->tables[i];
19499a2dd95SBruce Richardson 
19599a2dd95SBruce Richardson 		if (!strcmp(table_name, table->info.name))
19699a2dd95SBruce Richardson 			return table;
19799a2dd95SBruce Richardson 	}
19899a2dd95SBruce Richardson 
19999a2dd95SBruce Richardson 	return NULL;
20099a2dd95SBruce Richardson }
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson static int
table_params_get(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)20399a2dd95SBruce Richardson table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
20499a2dd95SBruce Richardson {
20599a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
20699a2dd95SBruce Richardson 	struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
20799a2dd95SBruce Richardson 	uint8_t *key_mask = NULL;
20899a2dd95SBruce Richardson 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
20999a2dd95SBruce Richardson 	uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i;
21099a2dd95SBruce Richardson 
21199a2dd95SBruce Richardson 	if (table->info.n_match_fields) {
21299a2dd95SBruce Richardson 		uint32_t n_match_fields_em = 0, i;
21399a2dd95SBruce Richardson 
21499a2dd95SBruce Richardson 		/* Find first (smallest offset) and last (biggest offset) match fields. */
21599a2dd95SBruce Richardson 		first = &table->mf[0];
21699a2dd95SBruce Richardson 		last = &table->mf[0];
21799a2dd95SBruce Richardson 
21899a2dd95SBruce Richardson 		for (i = 1; i < table->info.n_match_fields; i++) {
21999a2dd95SBruce Richardson 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
22099a2dd95SBruce Richardson 
22199a2dd95SBruce Richardson 			if (f->offset < first->offset)
22299a2dd95SBruce Richardson 				first = f;
22399a2dd95SBruce Richardson 
22499a2dd95SBruce Richardson 			if (f->offset > last->offset)
22599a2dd95SBruce Richardson 				last = f;
22699a2dd95SBruce Richardson 		}
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson 		/* match_type. */
22999a2dd95SBruce Richardson 		for (i = 0; i < table->info.n_match_fields; i++) {
23099a2dd95SBruce Richardson 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson 			if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
23399a2dd95SBruce Richardson 				n_match_fields_em++;
23499a2dd95SBruce Richardson 		}
23599a2dd95SBruce Richardson 
23699a2dd95SBruce Richardson 		if (n_match_fields_em == table->info.n_match_fields)
23799a2dd95SBruce Richardson 			match_type = RTE_SWX_TABLE_MATCH_EXACT;
23899a2dd95SBruce Richardson 
23999a2dd95SBruce Richardson 		/* key_offset. */
24099a2dd95SBruce Richardson 		key_offset = first->offset / 8;
24199a2dd95SBruce Richardson 
24299a2dd95SBruce Richardson 		/* key_size. */
24399a2dd95SBruce Richardson 		key_size = (last->offset + last->n_bits - first->offset) / 8;
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 		/* key_mask. */
24699a2dd95SBruce Richardson 		key_mask = calloc(1, key_size);
24799a2dd95SBruce Richardson 		CHECK(key_mask, ENOMEM);
24899a2dd95SBruce Richardson 
24999a2dd95SBruce Richardson 		for (i = 0; i < table->info.n_match_fields; i++) {
25099a2dd95SBruce Richardson 			struct rte_swx_ctl_table_match_field_info *f = &table->mf[i];
25199a2dd95SBruce Richardson 			uint32_t start;
25299a2dd95SBruce Richardson 			size_t size;
25399a2dd95SBruce Richardson 
25499a2dd95SBruce Richardson 			start = (f->offset - first->offset) / 8;
25599a2dd95SBruce Richardson 			size = f->n_bits / 8;
25699a2dd95SBruce Richardson 
25799a2dd95SBruce Richardson 			memset(&key_mask[start], 0xFF, size);
25899a2dd95SBruce Richardson 		}
25999a2dd95SBruce Richardson 	}
26099a2dd95SBruce Richardson 
26199a2dd95SBruce Richardson 	/* action_data_size. */
26299a2dd95SBruce Richardson 	for (i = 0; i < table->info.n_actions; i++) {
26399a2dd95SBruce Richardson 		uint32_t action_id = table->actions[i].action_id;
26499a2dd95SBruce Richardson 		struct action *a = &ctl->actions[action_id];
26599a2dd95SBruce Richardson 
26699a2dd95SBruce Richardson 		if (a->data_size > action_data_size)
26799a2dd95SBruce Richardson 			action_data_size = a->data_size;
26899a2dd95SBruce Richardson 	}
26999a2dd95SBruce Richardson 
27099a2dd95SBruce Richardson 	/* Fill in. */
27199a2dd95SBruce Richardson 	table->params.match_type = match_type;
27299a2dd95SBruce Richardson 	table->params.key_size = key_size;
27399a2dd95SBruce Richardson 	table->params.key_offset = key_offset;
27499a2dd95SBruce Richardson 	table->params.key_mask0 = key_mask;
27599a2dd95SBruce Richardson 	table->params.action_data_size = action_data_size;
2769560a329SCristian Dumitrescu 	table->params.hash_func = table->info.hash_func;
27799a2dd95SBruce Richardson 	table->params.n_keys_max = table->info.size;
27899a2dd95SBruce Richardson 
27999a2dd95SBruce Richardson 	table->mf_first = first;
28099a2dd95SBruce Richardson 	table->mf_last = last;
28199a2dd95SBruce Richardson 
28299a2dd95SBruce Richardson 	return 0;
28399a2dd95SBruce Richardson }
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson static void
table_entry_free(struct rte_swx_table_entry * entry)28699a2dd95SBruce Richardson table_entry_free(struct rte_swx_table_entry *entry)
28799a2dd95SBruce Richardson {
28899a2dd95SBruce Richardson 	if (!entry)
28999a2dd95SBruce Richardson 		return;
29099a2dd95SBruce Richardson 
29199a2dd95SBruce Richardson 	free(entry->key);
29299a2dd95SBruce Richardson 	free(entry->key_mask);
29399a2dd95SBruce Richardson 	free(entry->action_data);
29499a2dd95SBruce Richardson 	free(entry);
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson 
29799a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_entry_alloc(struct table * table)29899a2dd95SBruce Richardson table_entry_alloc(struct table *table)
29999a2dd95SBruce Richardson {
30099a2dd95SBruce Richardson 	struct rte_swx_table_entry *entry;
30199a2dd95SBruce Richardson 
30299a2dd95SBruce Richardson 	entry = calloc(1, sizeof(struct rte_swx_table_entry));
30399a2dd95SBruce Richardson 	if (!entry)
30499a2dd95SBruce Richardson 		goto error;
30599a2dd95SBruce Richardson 
30699a2dd95SBruce Richardson 	/* key, key_mask. */
30799a2dd95SBruce Richardson 	if (!table->is_stub) {
30899a2dd95SBruce Richardson 		entry->key = calloc(1, table->params.key_size);
30999a2dd95SBruce Richardson 		if (!entry->key)
31099a2dd95SBruce Richardson 			goto error;
31199a2dd95SBruce Richardson 
31299a2dd95SBruce Richardson 		if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) {
31399a2dd95SBruce Richardson 			entry->key_mask = calloc(1, table->params.key_size);
31499a2dd95SBruce Richardson 			if (!entry->key_mask)
31599a2dd95SBruce Richardson 				goto error;
31699a2dd95SBruce Richardson 		}
31799a2dd95SBruce Richardson 	}
31899a2dd95SBruce Richardson 
31999a2dd95SBruce Richardson 	/* action_data. */
32099a2dd95SBruce Richardson 	if (table->params.action_data_size) {
32199a2dd95SBruce Richardson 		entry->action_data = calloc(1, table->params.action_data_size);
32299a2dd95SBruce Richardson 		if (!entry->action_data)
32399a2dd95SBruce Richardson 			goto error;
32499a2dd95SBruce Richardson 	}
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson 	return entry;
32799a2dd95SBruce Richardson 
32899a2dd95SBruce Richardson error:
32999a2dd95SBruce Richardson 	table_entry_free(entry);
33099a2dd95SBruce Richardson 	return NULL;
33199a2dd95SBruce Richardson }
33299a2dd95SBruce Richardson 
33399a2dd95SBruce Richardson static int
table_entry_key_check_em(struct table * table,struct rte_swx_table_entry * entry)33499a2dd95SBruce Richardson table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry)
33599a2dd95SBruce Richardson {
33699a2dd95SBruce Richardson 	uint8_t *key_mask0 = table->params.key_mask0;
33799a2dd95SBruce Richardson 	uint32_t key_size = table->params.key_size, i;
33899a2dd95SBruce Richardson 
33999a2dd95SBruce Richardson 	if (!entry->key_mask)
34099a2dd95SBruce Richardson 		return 0;
34199a2dd95SBruce Richardson 
34299a2dd95SBruce Richardson 	for (i = 0; i < key_size; i++) {
34399a2dd95SBruce Richardson 		uint8_t km0 = key_mask0[i];
34499a2dd95SBruce Richardson 		uint8_t km = entry->key_mask[i];
34599a2dd95SBruce Richardson 
34699a2dd95SBruce Richardson 		if ((km & km0) != km0)
34799a2dd95SBruce Richardson 			return -EINVAL;
34899a2dd95SBruce Richardson 	}
34999a2dd95SBruce Richardson 
35099a2dd95SBruce Richardson 	return 0;
35199a2dd95SBruce Richardson }
35299a2dd95SBruce Richardson 
35399a2dd95SBruce Richardson static int
table_entry_check(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_check,int data_check)35499a2dd95SBruce Richardson table_entry_check(struct rte_swx_ctl_pipeline *ctl,
35599a2dd95SBruce Richardson 		  uint32_t table_id,
35699a2dd95SBruce Richardson 		  struct rte_swx_table_entry *entry,
35799a2dd95SBruce Richardson 		  int key_check,
35899a2dd95SBruce Richardson 		  int data_check)
35999a2dd95SBruce Richardson {
36099a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
36199a2dd95SBruce Richardson 	int status;
36299a2dd95SBruce Richardson 
36399a2dd95SBruce Richardson 	CHECK(entry, EINVAL);
36499a2dd95SBruce Richardson 
365a3ac0a48SCristian Dumitrescu 	if (key_check && !table->is_stub) {
36699a2dd95SBruce Richardson 		/* key. */
36799a2dd95SBruce Richardson 		CHECK(entry->key, EINVAL);
36899a2dd95SBruce Richardson 
36999a2dd95SBruce Richardson 		/* key_mask. */
370a3ac0a48SCristian Dumitrescu 		if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) {
37199a2dd95SBruce Richardson 			status = table_entry_key_check_em(table, entry);
37299a2dd95SBruce Richardson 			if (status)
37399a2dd95SBruce Richardson 				return status;
37499a2dd95SBruce Richardson 		}
37599a2dd95SBruce Richardson 	}
37699a2dd95SBruce Richardson 
37799a2dd95SBruce Richardson 	if (data_check) {
37899a2dd95SBruce Richardson 		struct action *a;
3798f8f6c14SCristian Dumitrescu 		struct rte_swx_ctl_table_action_info *tai;
38099a2dd95SBruce Richardson 		uint32_t i;
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson 		/* action_id. */
3838f8f6c14SCristian Dumitrescu 		for (i = 0; i < table->info.n_actions; i++) {
3848f8f6c14SCristian Dumitrescu 			tai = &table->actions[i];
3858f8f6c14SCristian Dumitrescu 
3868f8f6c14SCristian Dumitrescu 			if (entry->action_id == tai->action_id)
38799a2dd95SBruce Richardson 				break;
3888f8f6c14SCristian Dumitrescu 		}
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson 		CHECK(i < table->info.n_actions, EINVAL);
39199a2dd95SBruce Richardson 
39299a2dd95SBruce Richardson 		/* action_data. */
39399a2dd95SBruce Richardson 		a = &ctl->actions[entry->action_id];
39499a2dd95SBruce Richardson 		CHECK(!(a->data_size && !entry->action_data), EINVAL);
3958f8f6c14SCristian Dumitrescu 
3968f8f6c14SCristian Dumitrescu 		/* When both key_check and data_check are true, we are interested in both the entry
3978f8f6c14SCristian Dumitrescu 		 * key and data, which means the operation is _regular_ table entry add.
3988f8f6c14SCristian Dumitrescu 		 */
3998f8f6c14SCristian Dumitrescu 		if (key_check && !tai->action_is_for_table_entries)
4008f8f6c14SCristian Dumitrescu 			return -EINVAL;
4018f8f6c14SCristian Dumitrescu 
4028f8f6c14SCristian Dumitrescu 		/* When key_check is false while data_check is true, we are only interested in the
4038f8f6c14SCristian Dumitrescu 		 * entry data, which means the operation is _default_ table entry add.
4048f8f6c14SCristian Dumitrescu 		 */
4058f8f6c14SCristian Dumitrescu 		if (!key_check && !tai->action_is_for_default_entry)
4068f8f6c14SCristian Dumitrescu 			return -EINVAL;
40799a2dd95SBruce Richardson 	}
40899a2dd95SBruce Richardson 
40999a2dd95SBruce Richardson 	return 0;
41099a2dd95SBruce Richardson }
41199a2dd95SBruce Richardson 
41299a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_entry_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry * entry,int key_duplicate,int data_duplicate)41399a2dd95SBruce Richardson table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
41499a2dd95SBruce Richardson 		      uint32_t table_id,
41599a2dd95SBruce Richardson 		      struct rte_swx_table_entry *entry,
41699a2dd95SBruce Richardson 		      int key_duplicate,
41799a2dd95SBruce Richardson 		      int data_duplicate)
41899a2dd95SBruce Richardson {
41999a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
42099a2dd95SBruce Richardson 	struct rte_swx_table_entry *new_entry = NULL;
42199a2dd95SBruce Richardson 
42299a2dd95SBruce Richardson 	if (!entry)
42399a2dd95SBruce Richardson 		goto error;
42499a2dd95SBruce Richardson 
42599a2dd95SBruce Richardson 	new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
42699a2dd95SBruce Richardson 	if (!new_entry)
42799a2dd95SBruce Richardson 		goto error;
42899a2dd95SBruce Richardson 
42999a2dd95SBruce Richardson 	if (key_duplicate && !table->is_stub) {
43099a2dd95SBruce Richardson 		/* key. */
43199a2dd95SBruce Richardson 		if (!entry->key)
43299a2dd95SBruce Richardson 			goto error;
43399a2dd95SBruce Richardson 
43499a2dd95SBruce Richardson 		new_entry->key = malloc(table->params.key_size);
43599a2dd95SBruce Richardson 		if (!new_entry->key)
43699a2dd95SBruce Richardson 			goto error;
43799a2dd95SBruce Richardson 
43899a2dd95SBruce Richardson 		memcpy(new_entry->key, entry->key, table->params.key_size);
43999a2dd95SBruce Richardson 
44099a2dd95SBruce Richardson 		/* key_signature. */
44199a2dd95SBruce Richardson 		new_entry->key_signature = entry->key_signature;
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson 		/* key_mask. */
44499a2dd95SBruce Richardson 		if (entry->key_mask) {
44599a2dd95SBruce Richardson 			new_entry->key_mask = malloc(table->params.key_size);
44699a2dd95SBruce Richardson 			if (!new_entry->key_mask)
44799a2dd95SBruce Richardson 				goto error;
44899a2dd95SBruce Richardson 
44999a2dd95SBruce Richardson 			memcpy(new_entry->key_mask,
45099a2dd95SBruce Richardson 			       entry->key_mask,
45199a2dd95SBruce Richardson 			       table->params.key_size);
45299a2dd95SBruce Richardson 		}
45399a2dd95SBruce Richardson 
45499a2dd95SBruce Richardson 		/* key_priority. */
45599a2dd95SBruce Richardson 		new_entry->key_priority = entry->key_priority;
45699a2dd95SBruce Richardson 	}
45799a2dd95SBruce Richardson 
45899a2dd95SBruce Richardson 	if (data_duplicate) {
45999a2dd95SBruce Richardson 		struct action *a;
46099a2dd95SBruce Richardson 		uint32_t i;
46199a2dd95SBruce Richardson 
46299a2dd95SBruce Richardson 		/* action_id. */
46399a2dd95SBruce Richardson 		for (i = 0; i < table->info.n_actions; i++)
46499a2dd95SBruce Richardson 			if (entry->action_id == table->actions[i].action_id)
46599a2dd95SBruce Richardson 				break;
46699a2dd95SBruce Richardson 
46799a2dd95SBruce Richardson 		if (i >= table->info.n_actions)
46899a2dd95SBruce Richardson 			goto error;
46999a2dd95SBruce Richardson 
47099a2dd95SBruce Richardson 		new_entry->action_id = entry->action_id;
47199a2dd95SBruce Richardson 
47299a2dd95SBruce Richardson 		/* action_data. */
47399a2dd95SBruce Richardson 		a = &ctl->actions[entry->action_id];
47499a2dd95SBruce Richardson 		if (a->data_size && !entry->action_data)
47599a2dd95SBruce Richardson 			goto error;
47699a2dd95SBruce Richardson 
47799a2dd95SBruce Richardson 		/* The table layer provisions a constant action data size per
47899a2dd95SBruce Richardson 		 * entry, which should be the largest data size for all the
47999a2dd95SBruce Richardson 		 * actions enabled for the current table, and attempts to copy
48099a2dd95SBruce Richardson 		 * this many bytes each time a table entry is added, even if the
48199a2dd95SBruce Richardson 		 * specific action requires less data or even no data at all,
48299a2dd95SBruce Richardson 		 * hence we always have to allocate the max.
48399a2dd95SBruce Richardson 		 */
48499a2dd95SBruce Richardson 		new_entry->action_data = calloc(1, table->params.action_data_size);
48599a2dd95SBruce Richardson 		if (!new_entry->action_data)
48699a2dd95SBruce Richardson 			goto error;
48799a2dd95SBruce Richardson 
48899a2dd95SBruce Richardson 		if (a->data_size)
48999a2dd95SBruce Richardson 			memcpy(new_entry->action_data,
49099a2dd95SBruce Richardson 			       entry->action_data,
49199a2dd95SBruce Richardson 			       a->data_size);
49299a2dd95SBruce Richardson 	}
49399a2dd95SBruce Richardson 
49499a2dd95SBruce Richardson 	return new_entry;
49599a2dd95SBruce Richardson 
49699a2dd95SBruce Richardson error:
49799a2dd95SBruce Richardson 	table_entry_free(new_entry);
49899a2dd95SBruce Richardson 	return NULL;
49999a2dd95SBruce Richardson }
50099a2dd95SBruce Richardson 
50199a2dd95SBruce Richardson static int
table_entry_keycmp(struct table * table,struct rte_swx_table_entry * e0,struct rte_swx_table_entry * e1)50299a2dd95SBruce Richardson table_entry_keycmp(struct table *table,
50399a2dd95SBruce Richardson 		   struct rte_swx_table_entry *e0,
50499a2dd95SBruce Richardson 		   struct rte_swx_table_entry *e1)
50599a2dd95SBruce Richardson {
50699a2dd95SBruce Richardson 	uint32_t key_size = table->params.key_size;
50799a2dd95SBruce Richardson 	uint32_t i;
50899a2dd95SBruce Richardson 
50999a2dd95SBruce Richardson 	for (i = 0; i < key_size; i++) {
51099a2dd95SBruce Richardson 		uint8_t *key_mask0 = table->params.key_mask0;
51199a2dd95SBruce Richardson 		uint8_t km0, km[2], k[2];
51299a2dd95SBruce Richardson 
51399a2dd95SBruce Richardson 		km0 = key_mask0 ? key_mask0[i] : 0xFF;
51499a2dd95SBruce Richardson 
51599a2dd95SBruce Richardson 		km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF;
51699a2dd95SBruce Richardson 		km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF;
51799a2dd95SBruce Richardson 
51899a2dd95SBruce Richardson 		k[0] = e0->key[i];
51999a2dd95SBruce Richardson 		k[1] = e1->key[i];
52099a2dd95SBruce Richardson 
52199a2dd95SBruce Richardson 		/* Mask comparison. */
52299a2dd95SBruce Richardson 		if ((km[0] & km0) != (km[1] & km0))
52399a2dd95SBruce Richardson 			return 1; /* Not equal. */
52499a2dd95SBruce Richardson 
52599a2dd95SBruce Richardson 		/* Value comparison. */
52699a2dd95SBruce Richardson 		if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0))
52799a2dd95SBruce Richardson 			return 1; /* Not equal. */
52899a2dd95SBruce Richardson 	}
52999a2dd95SBruce Richardson 
53099a2dd95SBruce Richardson 	return 0; /* Equal. */
53199a2dd95SBruce Richardson }
53299a2dd95SBruce Richardson 
53399a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_entries_find(struct table * table,struct rte_swx_table_entry * entry)53499a2dd95SBruce Richardson table_entries_find(struct table *table, struct rte_swx_table_entry *entry)
53599a2dd95SBruce Richardson {
53699a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
53799a2dd95SBruce Richardson 
53899a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->entries, node)
53999a2dd95SBruce Richardson 		if (!table_entry_keycmp(table, entry, e))
54099a2dd95SBruce Richardson 			return e; /* Found. */
54199a2dd95SBruce Richardson 
54299a2dd95SBruce Richardson 	return NULL; /* Not found. */
54399a2dd95SBruce Richardson }
54499a2dd95SBruce Richardson 
54599a2dd95SBruce Richardson static void
table_entries_free(struct table * table)54699a2dd95SBruce Richardson table_entries_free(struct table *table)
54799a2dd95SBruce Richardson {
54899a2dd95SBruce Richardson 	for ( ; ; ) {
54999a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
55099a2dd95SBruce Richardson 
55199a2dd95SBruce Richardson 		entry = TAILQ_FIRST(&table->entries);
55299a2dd95SBruce Richardson 		if (!entry)
55399a2dd95SBruce Richardson 			break;
55499a2dd95SBruce Richardson 
55599a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->entries, entry, node);
55699a2dd95SBruce Richardson 		table_entry_free(entry);
55799a2dd95SBruce Richardson 	}
55899a2dd95SBruce Richardson }
55999a2dd95SBruce Richardson 
56099a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_pending_add_find(struct table * table,struct rte_swx_table_entry * entry)56199a2dd95SBruce Richardson table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry)
56299a2dd95SBruce Richardson {
56399a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
56499a2dd95SBruce Richardson 
56599a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_add, node)
56699a2dd95SBruce Richardson 		if (!table_entry_keycmp(table, entry, e))
56799a2dd95SBruce Richardson 			return e; /* Found. */
56899a2dd95SBruce Richardson 
56999a2dd95SBruce Richardson 	return NULL; /* Not found. */
57099a2dd95SBruce Richardson }
57199a2dd95SBruce Richardson 
57299a2dd95SBruce Richardson static void
table_pending_add_admit(struct table * table)57399a2dd95SBruce Richardson table_pending_add_admit(struct table *table)
57499a2dd95SBruce Richardson {
57599a2dd95SBruce Richardson 	TAILQ_CONCAT(&table->entries, &table->pending_add, node);
57699a2dd95SBruce Richardson }
57799a2dd95SBruce Richardson 
57899a2dd95SBruce Richardson static void
table_pending_add_free(struct table * table)57999a2dd95SBruce Richardson table_pending_add_free(struct table *table)
58099a2dd95SBruce Richardson {
58199a2dd95SBruce Richardson 	for ( ; ; ) {
58299a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
58399a2dd95SBruce Richardson 
58499a2dd95SBruce Richardson 		entry = TAILQ_FIRST(&table->pending_add);
58599a2dd95SBruce Richardson 		if (!entry)
58699a2dd95SBruce Richardson 			break;
58799a2dd95SBruce Richardson 
58899a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_add, entry, node);
58999a2dd95SBruce Richardson 		table_entry_free(entry);
59099a2dd95SBruce Richardson 	}
59199a2dd95SBruce Richardson }
59299a2dd95SBruce Richardson 
59399a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_pending_modify0_find(struct table * table,struct rte_swx_table_entry * entry)59499a2dd95SBruce Richardson table_pending_modify0_find(struct table *table,
59599a2dd95SBruce Richardson 			   struct rte_swx_table_entry *entry)
59699a2dd95SBruce Richardson {
59799a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
59899a2dd95SBruce Richardson 
59999a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_modify0, node)
60099a2dd95SBruce Richardson 		if (!table_entry_keycmp(table, entry, e))
60199a2dd95SBruce Richardson 			return e; /* Found. */
60299a2dd95SBruce Richardson 
60399a2dd95SBruce Richardson 	return NULL; /* Not found. */
60499a2dd95SBruce Richardson }
60599a2dd95SBruce Richardson 
60699a2dd95SBruce Richardson static void
table_pending_modify0_admit(struct table * table)60799a2dd95SBruce Richardson table_pending_modify0_admit(struct table *table)
60899a2dd95SBruce Richardson {
60999a2dd95SBruce Richardson 	TAILQ_CONCAT(&table->entries, &table->pending_modify0, node);
61099a2dd95SBruce Richardson }
61199a2dd95SBruce Richardson 
61299a2dd95SBruce Richardson static void
table_pending_modify0_free(struct table * table)61399a2dd95SBruce Richardson table_pending_modify0_free(struct table *table)
61499a2dd95SBruce Richardson {
61599a2dd95SBruce Richardson 	for ( ; ; ) {
61699a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
61799a2dd95SBruce Richardson 
61899a2dd95SBruce Richardson 		entry = TAILQ_FIRST(&table->pending_modify0);
61999a2dd95SBruce Richardson 		if (!entry)
62099a2dd95SBruce Richardson 			break;
62199a2dd95SBruce Richardson 
62299a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_modify0, entry, node);
62399a2dd95SBruce Richardson 		table_entry_free(entry);
62499a2dd95SBruce Richardson 	}
62599a2dd95SBruce Richardson }
62699a2dd95SBruce Richardson 
62799a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_pending_modify1_find(struct table * table,struct rte_swx_table_entry * entry)62899a2dd95SBruce Richardson table_pending_modify1_find(struct table *table,
62999a2dd95SBruce Richardson 			   struct rte_swx_table_entry *entry)
63099a2dd95SBruce Richardson {
63199a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
63299a2dd95SBruce Richardson 
63399a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_modify1, node)
63499a2dd95SBruce Richardson 		if (!table_entry_keycmp(table, entry, e))
63599a2dd95SBruce Richardson 			return e; /* Found. */
63699a2dd95SBruce Richardson 
63799a2dd95SBruce Richardson 	return NULL; /* Not found. */
63899a2dd95SBruce Richardson }
63999a2dd95SBruce Richardson 
64099a2dd95SBruce Richardson static void
table_pending_modify1_admit(struct table * table)64199a2dd95SBruce Richardson table_pending_modify1_admit(struct table *table)
64299a2dd95SBruce Richardson {
64399a2dd95SBruce Richardson 	TAILQ_CONCAT(&table->entries, &table->pending_modify1, node);
64499a2dd95SBruce Richardson }
64599a2dd95SBruce Richardson 
64699a2dd95SBruce Richardson static void
table_pending_modify1_free(struct table * table)64799a2dd95SBruce Richardson table_pending_modify1_free(struct table *table)
64899a2dd95SBruce Richardson {
64999a2dd95SBruce Richardson 	for ( ; ; ) {
65099a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
65199a2dd95SBruce Richardson 
65299a2dd95SBruce Richardson 		entry = TAILQ_FIRST(&table->pending_modify1);
65399a2dd95SBruce Richardson 		if (!entry)
65499a2dd95SBruce Richardson 			break;
65599a2dd95SBruce Richardson 
65699a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_modify1, entry, node);
65799a2dd95SBruce Richardson 		table_entry_free(entry);
65899a2dd95SBruce Richardson 	}
65999a2dd95SBruce Richardson }
66099a2dd95SBruce Richardson 
66199a2dd95SBruce Richardson static struct rte_swx_table_entry *
table_pending_delete_find(struct table * table,struct rte_swx_table_entry * entry)66299a2dd95SBruce Richardson table_pending_delete_find(struct table *table,
66399a2dd95SBruce Richardson 			  struct rte_swx_table_entry *entry)
66499a2dd95SBruce Richardson {
66599a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
66699a2dd95SBruce Richardson 
66799a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_delete, node)
66899a2dd95SBruce Richardson 		if (!table_entry_keycmp(table, entry, e))
66999a2dd95SBruce Richardson 			return e; /* Found. */
67099a2dd95SBruce Richardson 
67199a2dd95SBruce Richardson 	return NULL; /* Not found. */
67299a2dd95SBruce Richardson }
67399a2dd95SBruce Richardson 
67499a2dd95SBruce Richardson static void
table_pending_delete_admit(struct table * table)67599a2dd95SBruce Richardson table_pending_delete_admit(struct table *table)
67699a2dd95SBruce Richardson {
67799a2dd95SBruce Richardson 	TAILQ_CONCAT(&table->entries, &table->pending_delete, node);
67899a2dd95SBruce Richardson }
67999a2dd95SBruce Richardson 
68099a2dd95SBruce Richardson static void
table_pending_delete_free(struct table * table)68199a2dd95SBruce Richardson table_pending_delete_free(struct table *table)
68299a2dd95SBruce Richardson {
68399a2dd95SBruce Richardson 	for ( ; ; ) {
68499a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
68599a2dd95SBruce Richardson 
68699a2dd95SBruce Richardson 		entry = TAILQ_FIRST(&table->pending_delete);
68799a2dd95SBruce Richardson 		if (!entry)
68899a2dd95SBruce Richardson 			break;
68999a2dd95SBruce Richardson 
69099a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_delete, entry, node);
69199a2dd95SBruce Richardson 		table_entry_free(entry);
69299a2dd95SBruce Richardson 	}
69399a2dd95SBruce Richardson }
69499a2dd95SBruce Richardson 
69599a2dd95SBruce Richardson static void
table_pending_default_free(struct table * table)69699a2dd95SBruce Richardson table_pending_default_free(struct table *table)
69799a2dd95SBruce Richardson {
69899a2dd95SBruce Richardson 	if (!table->pending_default)
69999a2dd95SBruce Richardson 		return;
70099a2dd95SBruce Richardson 
70199a2dd95SBruce Richardson 	free(table->pending_default->action_data);
70299a2dd95SBruce Richardson 	free(table->pending_default);
70399a2dd95SBruce Richardson 	table->pending_default = NULL;
70499a2dd95SBruce Richardson }
70599a2dd95SBruce Richardson 
70699a2dd95SBruce Richardson static int
table_is_update_pending(struct table * table,int consider_pending_default)70799a2dd95SBruce Richardson table_is_update_pending(struct table *table, int consider_pending_default)
70899a2dd95SBruce Richardson {
70999a2dd95SBruce Richardson 	struct rte_swx_table_entry *e;
71099a2dd95SBruce Richardson 	uint32_t n = 0;
71199a2dd95SBruce Richardson 
71299a2dd95SBruce Richardson 	/* Pending add. */
71399a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_add, node)
71499a2dd95SBruce Richardson 		n++;
71599a2dd95SBruce Richardson 
71699a2dd95SBruce Richardson 	/* Pending modify. */
71799a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_modify1, node)
71899a2dd95SBruce Richardson 		n++;
71999a2dd95SBruce Richardson 
72099a2dd95SBruce Richardson 	/* Pending delete. */
72199a2dd95SBruce Richardson 	TAILQ_FOREACH(e, &table->pending_delete, node)
72299a2dd95SBruce Richardson 		n++;
72399a2dd95SBruce Richardson 
72499a2dd95SBruce Richardson 	/* Pending default. */
72599a2dd95SBruce Richardson 	if (consider_pending_default && table->pending_default)
72699a2dd95SBruce Richardson 		n++;
72799a2dd95SBruce Richardson 
72899a2dd95SBruce Richardson 	return n;
72999a2dd95SBruce Richardson }
73099a2dd95SBruce Richardson 
73199a2dd95SBruce Richardson static void
table_free(struct rte_swx_ctl_pipeline * ctl)73299a2dd95SBruce Richardson table_free(struct rte_swx_ctl_pipeline *ctl)
73399a2dd95SBruce Richardson {
73499a2dd95SBruce Richardson 	uint32_t i;
73599a2dd95SBruce Richardson 
73699a2dd95SBruce Richardson 	if (!ctl->tables)
73799a2dd95SBruce Richardson 		return;
73899a2dd95SBruce Richardson 
73999a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
74099a2dd95SBruce Richardson 		struct table *table = &ctl->tables[i];
74199a2dd95SBruce Richardson 
74299a2dd95SBruce Richardson 		free(table->mf);
74399a2dd95SBruce Richardson 		free(table->actions);
74499a2dd95SBruce Richardson 		free(table->params.key_mask0);
74599a2dd95SBruce Richardson 
74699a2dd95SBruce Richardson 		table_entries_free(table);
74799a2dd95SBruce Richardson 		table_pending_add_free(table);
74899a2dd95SBruce Richardson 		table_pending_modify0_free(table);
74999a2dd95SBruce Richardson 		table_pending_modify1_free(table);
75099a2dd95SBruce Richardson 		table_pending_delete_free(table);
75199a2dd95SBruce Richardson 		table_pending_default_free(table);
75299a2dd95SBruce Richardson 	}
75399a2dd95SBruce Richardson 
75499a2dd95SBruce Richardson 	free(ctl->tables);
75599a2dd95SBruce Richardson 	ctl->tables = NULL;
75699a2dd95SBruce Richardson }
75799a2dd95SBruce Richardson 
75899a2dd95SBruce Richardson static void
selector_group_members_free(struct selector * s,uint32_t group_id)759cdaa937dSCristian Dumitrescu selector_group_members_free(struct selector *s, uint32_t group_id)
760cdaa937dSCristian Dumitrescu {
761cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *group = s->groups[group_id];
762cdaa937dSCristian Dumitrescu 
763cdaa937dSCristian Dumitrescu 	if (!group)
764cdaa937dSCristian Dumitrescu 		return;
765cdaa937dSCristian Dumitrescu 
766cdaa937dSCristian Dumitrescu 	for ( ; ; ) {
767cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_member *m;
768cdaa937dSCristian Dumitrescu 
769cdaa937dSCristian Dumitrescu 		m = TAILQ_FIRST(&group->members);
770cdaa937dSCristian Dumitrescu 		if (!m)
771cdaa937dSCristian Dumitrescu 			break;
772cdaa937dSCristian Dumitrescu 
773cdaa937dSCristian Dumitrescu 		TAILQ_REMOVE(&group->members, m, node);
774cdaa937dSCristian Dumitrescu 		free(m);
775cdaa937dSCristian Dumitrescu 	}
776cdaa937dSCristian Dumitrescu 
777cdaa937dSCristian Dumitrescu 	free(group);
778cdaa937dSCristian Dumitrescu 	s->groups[group_id] = NULL;
779cdaa937dSCristian Dumitrescu }
780cdaa937dSCristian Dumitrescu 
781cdaa937dSCristian Dumitrescu static void
selector_pending_group_members_free(struct selector * s,uint32_t group_id)782cdaa937dSCristian Dumitrescu selector_pending_group_members_free(struct selector *s, uint32_t group_id)
783cdaa937dSCristian Dumitrescu {
784cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
785cdaa937dSCristian Dumitrescu 
786cdaa937dSCristian Dumitrescu 	if (!group)
787cdaa937dSCristian Dumitrescu 		return;
788cdaa937dSCristian Dumitrescu 
789cdaa937dSCristian Dumitrescu 	for ( ; ; ) {
790cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_member *m;
791cdaa937dSCristian Dumitrescu 
792cdaa937dSCristian Dumitrescu 		m = TAILQ_FIRST(&group->members);
793cdaa937dSCristian Dumitrescu 		if (!m)
794cdaa937dSCristian Dumitrescu 			break;
795cdaa937dSCristian Dumitrescu 
796cdaa937dSCristian Dumitrescu 		TAILQ_REMOVE(&group->members, m, node);
797cdaa937dSCristian Dumitrescu 		free(m);
798cdaa937dSCristian Dumitrescu 	}
799cdaa937dSCristian Dumitrescu 
800cdaa937dSCristian Dumitrescu 	free(group);
801cdaa937dSCristian Dumitrescu 	s->pending_groups[group_id] = NULL;
802cdaa937dSCristian Dumitrescu }
803cdaa937dSCristian Dumitrescu 
804cdaa937dSCristian Dumitrescu static int
selector_group_duplicate_to_pending(struct selector * s,uint32_t group_id)805cdaa937dSCristian Dumitrescu selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
806cdaa937dSCristian Dumitrescu {
807cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *g, *gp;
808cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_member *m;
809cdaa937dSCristian Dumitrescu 
810cdaa937dSCristian Dumitrescu 	selector_pending_group_members_free(s, group_id);
811cdaa937dSCristian Dumitrescu 
812cdaa937dSCristian Dumitrescu 	g = s->groups[group_id];
813cdaa937dSCristian Dumitrescu 	gp = s->pending_groups[group_id];
814cdaa937dSCristian Dumitrescu 
815cdaa937dSCristian Dumitrescu 	if (!gp) {
816cdaa937dSCristian Dumitrescu 		gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
817cdaa937dSCristian Dumitrescu 		if (!gp)
818cdaa937dSCristian Dumitrescu 			goto error;
819cdaa937dSCristian Dumitrescu 
820cdaa937dSCristian Dumitrescu 		TAILQ_INIT(&gp->members);
821cdaa937dSCristian Dumitrescu 
822cdaa937dSCristian Dumitrescu 		s->pending_groups[group_id] = gp;
823cdaa937dSCristian Dumitrescu 	}
824cdaa937dSCristian Dumitrescu 
825cdaa937dSCristian Dumitrescu 	if (!g)
826cdaa937dSCristian Dumitrescu 		return 0;
827cdaa937dSCristian Dumitrescu 
828cdaa937dSCristian Dumitrescu 	TAILQ_FOREACH(m, &g->members, node) {
829cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_member *mp;
830cdaa937dSCristian Dumitrescu 
831cdaa937dSCristian Dumitrescu 		mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
832cdaa937dSCristian Dumitrescu 		if (!mp)
833cdaa937dSCristian Dumitrescu 			goto error;
834cdaa937dSCristian Dumitrescu 
835cdaa937dSCristian Dumitrescu 		memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
836cdaa937dSCristian Dumitrescu 
837cdaa937dSCristian Dumitrescu 		TAILQ_INSERT_TAIL(&gp->members, mp, node);
838cdaa937dSCristian Dumitrescu 	}
839cdaa937dSCristian Dumitrescu 
840cdaa937dSCristian Dumitrescu 	return 0;
841cdaa937dSCristian Dumitrescu 
842cdaa937dSCristian Dumitrescu error:
843cdaa937dSCristian Dumitrescu 	selector_pending_group_members_free(s, group_id);
844cdaa937dSCristian Dumitrescu 	return -ENOMEM;
845cdaa937dSCristian Dumitrescu }
846cdaa937dSCristian Dumitrescu 
847cdaa937dSCristian Dumitrescu static void
selector_free(struct rte_swx_ctl_pipeline * ctl)848cdaa937dSCristian Dumitrescu selector_free(struct rte_swx_ctl_pipeline *ctl)
849cdaa937dSCristian Dumitrescu {
850cdaa937dSCristian Dumitrescu 	uint32_t i;
851cdaa937dSCristian Dumitrescu 
85240d42de5SCristian Dumitrescu 	if (!ctl->selectors)
853cdaa937dSCristian Dumitrescu 		return;
854cdaa937dSCristian Dumitrescu 
855cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
856cdaa937dSCristian Dumitrescu 		struct selector *s = &ctl->selectors[i];
857cdaa937dSCristian Dumitrescu 		uint32_t i;
858cdaa937dSCristian Dumitrescu 
859cdaa937dSCristian Dumitrescu 		/* selector_fields. */
860cdaa937dSCristian Dumitrescu 		free(s->selector_fields);
861cdaa937dSCristian Dumitrescu 
862cdaa937dSCristian Dumitrescu 		/* groups. */
863cdaa937dSCristian Dumitrescu 		if (s->groups)
864cdaa937dSCristian Dumitrescu 			for (i = 0; i < s->info.n_groups_max; i++)
865cdaa937dSCristian Dumitrescu 				selector_group_members_free(s, i);
866cdaa937dSCristian Dumitrescu 
867cdaa937dSCristian Dumitrescu 		free(s->groups);
868cdaa937dSCristian Dumitrescu 
869cdaa937dSCristian Dumitrescu 		/* pending_groups. */
870cdaa937dSCristian Dumitrescu 		if (s->pending_groups)
871cdaa937dSCristian Dumitrescu 			for (i = 0; i < s->info.n_groups_max; i++)
872cdaa937dSCristian Dumitrescu 				selector_pending_group_members_free(s, i);
873cdaa937dSCristian Dumitrescu 
874cdaa937dSCristian Dumitrescu 		free(s->pending_groups);
875cdaa937dSCristian Dumitrescu 
876cdaa937dSCristian Dumitrescu 		/* groups_added. */
877cdaa937dSCristian Dumitrescu 		free(s->groups_added);
878cdaa937dSCristian Dumitrescu 
879cdaa937dSCristian Dumitrescu 		/* groups_pending_delete. */
880cdaa937dSCristian Dumitrescu 		free(s->groups_pending_delete);
881cdaa937dSCristian Dumitrescu 
882cdaa937dSCristian Dumitrescu 		/* params. */
883cdaa937dSCristian Dumitrescu 		free(s->params.selector_mask);
884cdaa937dSCristian Dumitrescu 	}
885cdaa937dSCristian Dumitrescu 
886cdaa937dSCristian Dumitrescu 	free(ctl->selectors);
887cdaa937dSCristian Dumitrescu 	ctl->selectors = NULL;
888cdaa937dSCristian Dumitrescu }
889cdaa937dSCristian Dumitrescu 
890cdaa937dSCristian Dumitrescu static struct selector *
selector_find(struct rte_swx_ctl_pipeline * ctl,const char * selector_name)891cdaa937dSCristian Dumitrescu selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
892cdaa937dSCristian Dumitrescu {
893cdaa937dSCristian Dumitrescu 	uint32_t i;
894cdaa937dSCristian Dumitrescu 
895cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
896cdaa937dSCristian Dumitrescu 		struct selector *s = &ctl->selectors[i];
897cdaa937dSCristian Dumitrescu 
898cdaa937dSCristian Dumitrescu 		if (!strcmp(selector_name, s->info.name))
899cdaa937dSCristian Dumitrescu 			return s;
900cdaa937dSCristian Dumitrescu 	}
901cdaa937dSCristian Dumitrescu 
902cdaa937dSCristian Dumitrescu 	return NULL;
903cdaa937dSCristian Dumitrescu }
904cdaa937dSCristian Dumitrescu 
905cdaa937dSCristian Dumitrescu static int
selector_params_get(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)906cdaa937dSCristian Dumitrescu selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
907cdaa937dSCristian Dumitrescu {
908cdaa937dSCristian Dumitrescu 	struct selector *s = &ctl->selectors[selector_id];
909cdaa937dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
910cdaa937dSCristian Dumitrescu 	uint8_t *selector_mask = NULL;
911cdaa937dSCristian Dumitrescu 	uint32_t selector_size = 0, selector_offset = 0, i;
912cdaa937dSCristian Dumitrescu 
913cdaa937dSCristian Dumitrescu 	/* Find first (smallest offset) and last (biggest offset) match fields. */
914cdaa937dSCristian Dumitrescu 	first = &s->selector_fields[0];
915cdaa937dSCristian Dumitrescu 	last = &s->selector_fields[0];
916cdaa937dSCristian Dumitrescu 
917cdaa937dSCristian Dumitrescu 	for (i = 1; i < s->info.n_selector_fields; i++) {
918cdaa937dSCristian Dumitrescu 		struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
919cdaa937dSCristian Dumitrescu 
920cdaa937dSCristian Dumitrescu 		if (f->offset < first->offset)
921cdaa937dSCristian Dumitrescu 			first = f;
922cdaa937dSCristian Dumitrescu 
923cdaa937dSCristian Dumitrescu 		if (f->offset > last->offset)
924cdaa937dSCristian Dumitrescu 			last = f;
925cdaa937dSCristian Dumitrescu 	}
926cdaa937dSCristian Dumitrescu 
927cdaa937dSCristian Dumitrescu 	/* selector_offset. */
928cdaa937dSCristian Dumitrescu 	selector_offset = first->offset / 8;
929cdaa937dSCristian Dumitrescu 
930cdaa937dSCristian Dumitrescu 	/* selector_size. */
931cdaa937dSCristian Dumitrescu 	selector_size = (last->offset + last->n_bits - first->offset) / 8;
932cdaa937dSCristian Dumitrescu 
933cdaa937dSCristian Dumitrescu 	/* selector_mask. */
934cdaa937dSCristian Dumitrescu 	selector_mask = calloc(1, selector_size);
935cdaa937dSCristian Dumitrescu 	if (!selector_mask)
936cdaa937dSCristian Dumitrescu 		return -ENOMEM;
937cdaa937dSCristian Dumitrescu 
938cdaa937dSCristian Dumitrescu 	for (i = 0; i < s->info.n_selector_fields; i++) {
939cdaa937dSCristian Dumitrescu 		struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
940cdaa937dSCristian Dumitrescu 		uint32_t start;
941cdaa937dSCristian Dumitrescu 		size_t size;
942cdaa937dSCristian Dumitrescu 
943cdaa937dSCristian Dumitrescu 		start = (f->offset - first->offset) / 8;
944cdaa937dSCristian Dumitrescu 		size = f->n_bits / 8;
945cdaa937dSCristian Dumitrescu 
946cdaa937dSCristian Dumitrescu 		memset(&selector_mask[start], 0xFF, size);
947cdaa937dSCristian Dumitrescu 	}
948cdaa937dSCristian Dumitrescu 
949cdaa937dSCristian Dumitrescu 	/* Fill in. */
950cdaa937dSCristian Dumitrescu 	s->params.group_id_offset = s->group_id_field.offset / 8;
951cdaa937dSCristian Dumitrescu 	s->params.selector_size = selector_size;
952cdaa937dSCristian Dumitrescu 	s->params.selector_offset = selector_offset;
953cdaa937dSCristian Dumitrescu 	s->params.selector_mask = selector_mask;
954cdaa937dSCristian Dumitrescu 	s->params.member_id_offset = s->member_id_field.offset / 8;
955cdaa937dSCristian Dumitrescu 	s->params.n_groups_max = s->info.n_groups_max;
956cdaa937dSCristian Dumitrescu 	s->params.n_members_per_group_max = s->info.n_members_per_group_max;
957cdaa937dSCristian Dumitrescu 
958cdaa937dSCristian Dumitrescu 	return 0;
959cdaa937dSCristian Dumitrescu }
960cdaa937dSCristian Dumitrescu 
961cdaa937dSCristian Dumitrescu static void
learner_pending_default_free(struct learner * l)9624f59d372SCristian Dumitrescu learner_pending_default_free(struct learner *l)
9634f59d372SCristian Dumitrescu {
9644f59d372SCristian Dumitrescu 	if (!l->pending_default)
9654f59d372SCristian Dumitrescu 		return;
9664f59d372SCristian Dumitrescu 
9674f59d372SCristian Dumitrescu 	free(l->pending_default->action_data);
9684f59d372SCristian Dumitrescu 	free(l->pending_default);
9694f59d372SCristian Dumitrescu 	l->pending_default = NULL;
9704f59d372SCristian Dumitrescu }
9714f59d372SCristian Dumitrescu 
9724f59d372SCristian Dumitrescu 
9734f59d372SCristian Dumitrescu static void
learner_free(struct rte_swx_ctl_pipeline * ctl)9744f59d372SCristian Dumitrescu learner_free(struct rte_swx_ctl_pipeline *ctl)
9754f59d372SCristian Dumitrescu {
9764f59d372SCristian Dumitrescu 	uint32_t i;
9774f59d372SCristian Dumitrescu 
9784f59d372SCristian Dumitrescu 	if (!ctl->learners)
9794f59d372SCristian Dumitrescu 		return;
9804f59d372SCristian Dumitrescu 
9814f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
9824f59d372SCristian Dumitrescu 		struct learner *l = &ctl->learners[i];
9834f59d372SCristian Dumitrescu 
9844f59d372SCristian Dumitrescu 		free(l->mf);
9854f59d372SCristian Dumitrescu 		free(l->actions);
9864f59d372SCristian Dumitrescu 
9874f59d372SCristian Dumitrescu 		learner_pending_default_free(l);
9884f59d372SCristian Dumitrescu 	}
9894f59d372SCristian Dumitrescu 
9904f59d372SCristian Dumitrescu 	free(ctl->learners);
9914f59d372SCristian Dumitrescu 	ctl->learners = NULL;
9924f59d372SCristian Dumitrescu }
9934f59d372SCristian Dumitrescu 
9944f59d372SCristian Dumitrescu static struct learner *
learner_find(struct rte_swx_ctl_pipeline * ctl,const char * learner_name)9954f59d372SCristian Dumitrescu learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
9964f59d372SCristian Dumitrescu {
9974f59d372SCristian Dumitrescu 	uint32_t i;
9984f59d372SCristian Dumitrescu 
9994f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
10004f59d372SCristian Dumitrescu 		struct learner *l = &ctl->learners[i];
10014f59d372SCristian Dumitrescu 
10024f59d372SCristian Dumitrescu 		if (!strcmp(learner_name, l->info.name))
10034f59d372SCristian Dumitrescu 			return l;
10044f59d372SCristian Dumitrescu 	}
10054f59d372SCristian Dumitrescu 
10064f59d372SCristian Dumitrescu 	return NULL;
10074f59d372SCristian Dumitrescu }
10084f59d372SCristian Dumitrescu 
10094f59d372SCristian Dumitrescu static uint32_t
learner_action_data_size_get(struct rte_swx_ctl_pipeline * ctl,struct learner * l)10104f59d372SCristian Dumitrescu learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
10114f59d372SCristian Dumitrescu {
10124f59d372SCristian Dumitrescu 	uint32_t action_data_size = 0, i;
10134f59d372SCristian Dumitrescu 
10144f59d372SCristian Dumitrescu 	for (i = 0; i < l->info.n_actions; i++) {
10154f59d372SCristian Dumitrescu 		uint32_t action_id = l->actions[i].action_id;
10164f59d372SCristian Dumitrescu 		struct action *a = &ctl->actions[action_id];
10174f59d372SCristian Dumitrescu 
10184f59d372SCristian Dumitrescu 		if (a->data_size > action_data_size)
10194f59d372SCristian Dumitrescu 			action_data_size = a->data_size;
10204f59d372SCristian Dumitrescu 	}
10214f59d372SCristian Dumitrescu 
10224f59d372SCristian Dumitrescu 	return action_data_size;
10234f59d372SCristian Dumitrescu }
10244f59d372SCristian Dumitrescu 
10254f59d372SCristian Dumitrescu static void
table_state_free(struct rte_swx_ctl_pipeline * ctl)102699a2dd95SBruce Richardson table_state_free(struct rte_swx_ctl_pipeline *ctl)
102799a2dd95SBruce Richardson {
1028eb3e2c11SCristian Dumitrescu 	uint32_t table_base_index, selector_base_index, learner_base_index, i;
102999a2dd95SBruce Richardson 
103099a2dd95SBruce Richardson 	if (!ctl->ts_next)
103199a2dd95SBruce Richardson 		return;
103299a2dd95SBruce Richardson 
103399a2dd95SBruce Richardson 	/* For each table, free its table state. */
1034eb3e2c11SCristian Dumitrescu 	table_base_index = 0;
103599a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
103699a2dd95SBruce Richardson 		struct table *table = &ctl->tables[i];
1037eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i];
103899a2dd95SBruce Richardson 
103999a2dd95SBruce Richardson 		/* Default action data. */
104099a2dd95SBruce Richardson 		free(ts->default_action_data);
104199a2dd95SBruce Richardson 
104299a2dd95SBruce Richardson 		/* Table object. */
104399a2dd95SBruce Richardson 		if (!table->is_stub && table->ops.free && ts->obj)
104499a2dd95SBruce Richardson 			table->ops.free(ts->obj);
104599a2dd95SBruce Richardson 	}
104699a2dd95SBruce Richardson 
1047cdaa937dSCristian Dumitrescu 	/* For each selector table, free its table state. */
1048eb3e2c11SCristian Dumitrescu 	selector_base_index = ctl->info.n_tables;
1049cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
1050eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i];
1051cdaa937dSCristian Dumitrescu 
1052cdaa937dSCristian Dumitrescu 		/* Table object. */
1053cdaa937dSCristian Dumitrescu 		rte_swx_table_selector_free(ts->obj);
1054cdaa937dSCristian Dumitrescu 	}
1055cdaa937dSCristian Dumitrescu 
10564f59d372SCristian Dumitrescu 	/* For each learner table, free its table state. */
1057eb3e2c11SCristian Dumitrescu 	learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
10584f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
1059eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i];
10604f59d372SCristian Dumitrescu 
10614f59d372SCristian Dumitrescu 		/* Default action data. */
10624f59d372SCristian Dumitrescu 		free(ts->default_action_data);
10634f59d372SCristian Dumitrescu 	}
10644f59d372SCristian Dumitrescu 
106599a2dd95SBruce Richardson 	free(ctl->ts_next);
106699a2dd95SBruce Richardson 	ctl->ts_next = NULL;
106799a2dd95SBruce Richardson }
106899a2dd95SBruce Richardson 
106999a2dd95SBruce Richardson static int
table_state_create(struct rte_swx_ctl_pipeline * ctl)107099a2dd95SBruce Richardson table_state_create(struct rte_swx_ctl_pipeline *ctl)
107199a2dd95SBruce Richardson {
1072eb3e2c11SCristian Dumitrescu 	uint32_t table_base_index, selector_base_index, learner_base_index, i;
107399a2dd95SBruce Richardson 	int status = 0;
107499a2dd95SBruce Richardson 
1075eb3e2c11SCristian Dumitrescu 	ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners,
107699a2dd95SBruce Richardson 			      sizeof(struct rte_swx_table_state));
107799a2dd95SBruce Richardson 	if (!ctl->ts_next) {
107899a2dd95SBruce Richardson 		status = -ENOMEM;
107999a2dd95SBruce Richardson 		goto error;
108099a2dd95SBruce Richardson 	}
108199a2dd95SBruce Richardson 
1082cdaa937dSCristian Dumitrescu 	/* Tables. */
1083eb3e2c11SCristian Dumitrescu 	table_base_index = 0;
108499a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
108599a2dd95SBruce Richardson 		struct table *table = &ctl->tables[i];
1086eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i];
1087eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i];
108899a2dd95SBruce Richardson 
108999a2dd95SBruce Richardson 		/* Table object. */
109099a2dd95SBruce Richardson 		if (!table->is_stub && table->ops.add) {
109199a2dd95SBruce Richardson 			ts_next->obj = table->ops.create(&table->params,
109299a2dd95SBruce Richardson 							 &table->entries,
109399a2dd95SBruce Richardson 							 table->info.args,
109499a2dd95SBruce Richardson 							 ctl->numa_node);
109599a2dd95SBruce Richardson 			if (!ts_next->obj) {
109699a2dd95SBruce Richardson 				status = -ENODEV;
109799a2dd95SBruce Richardson 				goto error;
109899a2dd95SBruce Richardson 			}
109999a2dd95SBruce Richardson 		}
110099a2dd95SBruce Richardson 
110199a2dd95SBruce Richardson 		if (!table->is_stub && !table->ops.add)
110299a2dd95SBruce Richardson 			ts_next->obj = ts->obj;
110399a2dd95SBruce Richardson 
110499a2dd95SBruce Richardson 		/* Default action data: duplicate from current table state. */
110599a2dd95SBruce Richardson 		ts_next->default_action_data =
110699a2dd95SBruce Richardson 			malloc(table->params.action_data_size);
110799a2dd95SBruce Richardson 		if (!ts_next->default_action_data) {
110899a2dd95SBruce Richardson 			status = -ENOMEM;
110999a2dd95SBruce Richardson 			goto error;
111099a2dd95SBruce Richardson 		}
111199a2dd95SBruce Richardson 
111299a2dd95SBruce Richardson 		memcpy(ts_next->default_action_data,
111399a2dd95SBruce Richardson 		       ts->default_action_data,
111499a2dd95SBruce Richardson 		       table->params.action_data_size);
111599a2dd95SBruce Richardson 
111699a2dd95SBruce Richardson 		ts_next->default_action_id = ts->default_action_id;
111799a2dd95SBruce Richardson 	}
111899a2dd95SBruce Richardson 
1119cdaa937dSCristian Dumitrescu 	/* Selector tables. */
1120eb3e2c11SCristian Dumitrescu 	selector_base_index = ctl->info.n_tables;
1121cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
1122cdaa937dSCristian Dumitrescu 		struct selector *s = &ctl->selectors[i];
1123eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i];
1124cdaa937dSCristian Dumitrescu 
1125cdaa937dSCristian Dumitrescu 		/* Table object. */
1126cdaa937dSCristian Dumitrescu 		ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
1127cdaa937dSCristian Dumitrescu 		if (!ts_next->obj) {
1128cdaa937dSCristian Dumitrescu 			status = -ENODEV;
1129cdaa937dSCristian Dumitrescu 			goto error;
1130cdaa937dSCristian Dumitrescu 		}
1131cdaa937dSCristian Dumitrescu 	}
1132cdaa937dSCristian Dumitrescu 
11334f59d372SCristian Dumitrescu 	/* Learner tables. */
1134eb3e2c11SCristian Dumitrescu 	learner_base_index = ctl->info.n_tables + ctl->info.n_selectors;
11354f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
11364f59d372SCristian Dumitrescu 		struct learner *l = &ctl->learners[i];
1137eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i];
1138eb3e2c11SCristian Dumitrescu 		struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i];
11394f59d372SCristian Dumitrescu 
11404f59d372SCristian Dumitrescu 		/* Table object: duplicate from the current table state. */
11414f59d372SCristian Dumitrescu 		ts_next->obj = ts->obj;
11424f59d372SCristian Dumitrescu 
11434f59d372SCristian Dumitrescu 		/* Default action data: duplicate from the current table state. */
11444f59d372SCristian Dumitrescu 		ts_next->default_action_data = malloc(l->action_data_size);
11454f59d372SCristian Dumitrescu 		if (!ts_next->default_action_data) {
11464f59d372SCristian Dumitrescu 			status = -ENOMEM;
11474f59d372SCristian Dumitrescu 			goto error;
11484f59d372SCristian Dumitrescu 		}
11494f59d372SCristian Dumitrescu 
11504f59d372SCristian Dumitrescu 		memcpy(ts_next->default_action_data,
11514f59d372SCristian Dumitrescu 		       ts->default_action_data,
11524f59d372SCristian Dumitrescu 		       l->action_data_size);
11534f59d372SCristian Dumitrescu 
11544f59d372SCristian Dumitrescu 		ts_next->default_action_id = ts->default_action_id;
11554f59d372SCristian Dumitrescu 	}
11564f59d372SCristian Dumitrescu 
115799a2dd95SBruce Richardson 	return 0;
115899a2dd95SBruce Richardson 
115999a2dd95SBruce Richardson error:
116099a2dd95SBruce Richardson 	table_state_free(ctl);
116199a2dd95SBruce Richardson 	return status;
116299a2dd95SBruce Richardson }
116399a2dd95SBruce Richardson 
1164d69c90c8SCristian Dumitrescu /* Global list of pipeline instances. */
1165d69c90c8SCristian Dumitrescu TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
1166d69c90c8SCristian Dumitrescu 
1167d69c90c8SCristian Dumitrescu static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
1168d69c90c8SCristian Dumitrescu 	.name = "RTE_SWX_CTL_PIPELINE",
1169d69c90c8SCristian Dumitrescu };
1170d69c90c8SCristian Dumitrescu 
EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)1171d69c90c8SCristian Dumitrescu EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
1172d69c90c8SCristian Dumitrescu 
1173d69c90c8SCristian Dumitrescu struct rte_swx_ctl_pipeline *
1174d69c90c8SCristian Dumitrescu rte_swx_ctl_pipeline_find(const char *name)
1175d69c90c8SCristian Dumitrescu {
1176d69c90c8SCristian Dumitrescu 	struct rte_swx_ctl_pipeline_list *ctl_list;
1177d69c90c8SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
1178d69c90c8SCristian Dumitrescu 
1179d69c90c8SCristian Dumitrescu 	if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
1180d69c90c8SCristian Dumitrescu 		return NULL;
1181d69c90c8SCristian Dumitrescu 
1182d69c90c8SCristian Dumitrescu 	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1183d69c90c8SCristian Dumitrescu 
1184d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_read_lock();
1185d69c90c8SCristian Dumitrescu 
1186d69c90c8SCristian Dumitrescu 	TAILQ_FOREACH(te, ctl_list, next) {
1187d69c90c8SCristian Dumitrescu 		struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
1188d69c90c8SCristian Dumitrescu 
1189d69c90c8SCristian Dumitrescu 		if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
1190d69c90c8SCristian Dumitrescu 			rte_mcfg_tailq_read_unlock();
1191d69c90c8SCristian Dumitrescu 			return ctl;
1192d69c90c8SCristian Dumitrescu 		}
1193d69c90c8SCristian Dumitrescu 	}
1194d69c90c8SCristian Dumitrescu 
1195d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_read_unlock();
1196d69c90c8SCristian Dumitrescu 	return NULL;
1197d69c90c8SCristian Dumitrescu }
1198d69c90c8SCristian Dumitrescu 
1199d69c90c8SCristian Dumitrescu static int
ctl_register(struct rte_swx_ctl_pipeline * ctl)1200d69c90c8SCristian Dumitrescu ctl_register(struct rte_swx_ctl_pipeline *ctl)
1201d69c90c8SCristian Dumitrescu {
1202d69c90c8SCristian Dumitrescu 	struct rte_swx_ctl_pipeline_list *ctl_list;
1203d69c90c8SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
1204d69c90c8SCristian Dumitrescu 
1205d69c90c8SCristian Dumitrescu 	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1206d69c90c8SCristian Dumitrescu 
1207d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_write_lock();
1208d69c90c8SCristian Dumitrescu 
1209d69c90c8SCristian Dumitrescu 	TAILQ_FOREACH(te, ctl_list, next) {
1210d69c90c8SCristian Dumitrescu 		struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
1211d69c90c8SCristian Dumitrescu 
1212d69c90c8SCristian Dumitrescu 		if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
1213d69c90c8SCristian Dumitrescu 			rte_mcfg_tailq_write_unlock();
1214d69c90c8SCristian Dumitrescu 			return -EEXIST;
1215d69c90c8SCristian Dumitrescu 		}
1216d69c90c8SCristian Dumitrescu 	}
1217d69c90c8SCristian Dumitrescu 
1218d69c90c8SCristian Dumitrescu 	te = calloc(1, sizeof(struct rte_tailq_entry));
1219d69c90c8SCristian Dumitrescu 	if (!te) {
1220d69c90c8SCristian Dumitrescu 		rte_mcfg_tailq_write_unlock();
1221d69c90c8SCristian Dumitrescu 		return -ENOMEM;
1222d69c90c8SCristian Dumitrescu 	}
1223d69c90c8SCristian Dumitrescu 
1224d69c90c8SCristian Dumitrescu 	te->data = (void *)ctl;
1225d69c90c8SCristian Dumitrescu 	TAILQ_INSERT_TAIL(ctl_list, te, next);
1226d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_write_unlock();
1227d69c90c8SCristian Dumitrescu 	return 0;
1228d69c90c8SCristian Dumitrescu }
1229d69c90c8SCristian Dumitrescu 
1230d69c90c8SCristian Dumitrescu static void
ctl_unregister(struct rte_swx_ctl_pipeline * ctl)1231d69c90c8SCristian Dumitrescu ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
1232d69c90c8SCristian Dumitrescu {
1233d69c90c8SCristian Dumitrescu 	struct rte_swx_ctl_pipeline_list *ctl_list;
1234d69c90c8SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
1235d69c90c8SCristian Dumitrescu 
1236d69c90c8SCristian Dumitrescu 	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
1237d69c90c8SCristian Dumitrescu 
1238d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_write_lock();
1239d69c90c8SCristian Dumitrescu 
1240d69c90c8SCristian Dumitrescu 	TAILQ_FOREACH(te, ctl_list, next) {
1241d69c90c8SCristian Dumitrescu 		if (te->data == (void *)ctl) {
1242d69c90c8SCristian Dumitrescu 			TAILQ_REMOVE(ctl_list, te, next);
1243d69c90c8SCristian Dumitrescu 			rte_mcfg_tailq_write_unlock();
1244d69c90c8SCristian Dumitrescu 			free(te);
1245d69c90c8SCristian Dumitrescu 			return;
1246d69c90c8SCristian Dumitrescu 		}
1247d69c90c8SCristian Dumitrescu 	}
1248d69c90c8SCristian Dumitrescu 
1249d69c90c8SCristian Dumitrescu 	rte_mcfg_tailq_write_unlock();
1250d69c90c8SCristian Dumitrescu }
1251d69c90c8SCristian Dumitrescu 
125299a2dd95SBruce Richardson void
rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline * ctl)125399a2dd95SBruce Richardson rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
125499a2dd95SBruce Richardson {
125599a2dd95SBruce Richardson 	if (!ctl)
125699a2dd95SBruce Richardson 		return;
125799a2dd95SBruce Richardson 
1258d69c90c8SCristian Dumitrescu 	if (ctl->info.name[0])
1259d69c90c8SCristian Dumitrescu 		ctl_unregister(ctl);
1260d69c90c8SCristian Dumitrescu 
126199a2dd95SBruce Richardson 	action_free(ctl);
126299a2dd95SBruce Richardson 
126399a2dd95SBruce Richardson 	table_state_free(ctl);
126499a2dd95SBruce Richardson 
12654f59d372SCristian Dumitrescu 	learner_free(ctl);
12664f59d372SCristian Dumitrescu 
1267cdaa937dSCristian Dumitrescu 	selector_free(ctl);
1268cdaa937dSCristian Dumitrescu 
126999a2dd95SBruce Richardson 	table_free(ctl);
127099a2dd95SBruce Richardson 
127199a2dd95SBruce Richardson 	free(ctl);
127299a2dd95SBruce Richardson }
127399a2dd95SBruce Richardson 
127499a2dd95SBruce Richardson struct rte_swx_ctl_pipeline *
rte_swx_ctl_pipeline_create(struct rte_swx_pipeline * p)127599a2dd95SBruce Richardson rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
127699a2dd95SBruce Richardson {
127799a2dd95SBruce Richardson 	struct rte_swx_ctl_pipeline *ctl = NULL;
127899a2dd95SBruce Richardson 	uint32_t i;
127999a2dd95SBruce Richardson 	int status;
128099a2dd95SBruce Richardson 
128199a2dd95SBruce Richardson 	if (!p)
128299a2dd95SBruce Richardson 		goto error;
128399a2dd95SBruce Richardson 
128499a2dd95SBruce Richardson 	ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline));
128599a2dd95SBruce Richardson 	if (!ctl)
128699a2dd95SBruce Richardson 		goto error;
128799a2dd95SBruce Richardson 
128899a2dd95SBruce Richardson 	/* info. */
128999a2dd95SBruce Richardson 	status = rte_swx_ctl_pipeline_info_get(p, &ctl->info);
129099a2dd95SBruce Richardson 	if (status)
129199a2dd95SBruce Richardson 		goto error;
129299a2dd95SBruce Richardson 
129399a2dd95SBruce Richardson 	/* numa_node. */
129499a2dd95SBruce Richardson 	status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node);
129599a2dd95SBruce Richardson 	if (status)
129699a2dd95SBruce Richardson 		goto error;
129799a2dd95SBruce Richardson 
129899a2dd95SBruce Richardson 	/* p. */
129999a2dd95SBruce Richardson 	ctl->p = p;
130099a2dd95SBruce Richardson 
130199a2dd95SBruce Richardson 	/* actions. */
130299a2dd95SBruce Richardson 	ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action));
130399a2dd95SBruce Richardson 	if (!ctl->actions)
130499a2dd95SBruce Richardson 		goto error;
130599a2dd95SBruce Richardson 
130699a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_actions; i++) {
130799a2dd95SBruce Richardson 		struct action *a = &ctl->actions[i];
130899a2dd95SBruce Richardson 		uint32_t j;
130999a2dd95SBruce Richardson 
131099a2dd95SBruce Richardson 		/* info. */
131199a2dd95SBruce Richardson 		status = rte_swx_ctl_action_info_get(p, i, &a->info);
131299a2dd95SBruce Richardson 		if (status)
131399a2dd95SBruce Richardson 			goto error;
131499a2dd95SBruce Richardson 
131599a2dd95SBruce Richardson 		/* args. */
131699a2dd95SBruce Richardson 		a->args = calloc(a->info.n_args,
131799a2dd95SBruce Richardson 				 sizeof(struct rte_swx_ctl_action_arg_info));
131899a2dd95SBruce Richardson 		if (!a->args)
131999a2dd95SBruce Richardson 			goto error;
132099a2dd95SBruce Richardson 
132199a2dd95SBruce Richardson 		for (j = 0; j < a->info.n_args; j++) {
132299a2dd95SBruce Richardson 			status = rte_swx_ctl_action_arg_info_get(p,
132399a2dd95SBruce Richardson 								 i,
132499a2dd95SBruce Richardson 								 j,
132599a2dd95SBruce Richardson 								 &a->args[j]);
132699a2dd95SBruce Richardson 			if (status)
132799a2dd95SBruce Richardson 				goto error;
132899a2dd95SBruce Richardson 		}
132999a2dd95SBruce Richardson 
133099a2dd95SBruce Richardson 		/* data_size. */
133199a2dd95SBruce Richardson 		for (j = 0; j < a->info.n_args; j++) {
133299a2dd95SBruce Richardson 			struct rte_swx_ctl_action_arg_info *info = &a->args[j];
133399a2dd95SBruce Richardson 
133499a2dd95SBruce Richardson 			a->data_size += info->n_bits;
133599a2dd95SBruce Richardson 		}
133699a2dd95SBruce Richardson 
133799a2dd95SBruce Richardson 		a->data_size = (a->data_size + 7) / 8;
133899a2dd95SBruce Richardson 	}
133999a2dd95SBruce Richardson 
134099a2dd95SBruce Richardson 	/* tables. */
134199a2dd95SBruce Richardson 	ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table));
134299a2dd95SBruce Richardson 	if (!ctl->tables)
134399a2dd95SBruce Richardson 		goto error;
134499a2dd95SBruce Richardson 
134599a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
134699a2dd95SBruce Richardson 		struct table *t = &ctl->tables[i];
134799a2dd95SBruce Richardson 
134899a2dd95SBruce Richardson 		TAILQ_INIT(&t->entries);
134999a2dd95SBruce Richardson 		TAILQ_INIT(&t->pending_add);
135099a2dd95SBruce Richardson 		TAILQ_INIT(&t->pending_modify0);
135199a2dd95SBruce Richardson 		TAILQ_INIT(&t->pending_modify1);
135299a2dd95SBruce Richardson 		TAILQ_INIT(&t->pending_delete);
135399a2dd95SBruce Richardson 	}
135499a2dd95SBruce Richardson 
135599a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
135699a2dd95SBruce Richardson 		struct table *t = &ctl->tables[i];
135799a2dd95SBruce Richardson 		uint32_t j;
135899a2dd95SBruce Richardson 
135999a2dd95SBruce Richardson 		/* info. */
136099a2dd95SBruce Richardson 		status = rte_swx_ctl_table_info_get(p, i, &t->info);
136199a2dd95SBruce Richardson 		if (status)
136299a2dd95SBruce Richardson 			goto error;
136399a2dd95SBruce Richardson 
136499a2dd95SBruce Richardson 		/* mf. */
136599a2dd95SBruce Richardson 		t->mf = calloc(t->info.n_match_fields,
136699a2dd95SBruce Richardson 			sizeof(struct rte_swx_ctl_table_match_field_info));
136799a2dd95SBruce Richardson 		if (!t->mf)
136899a2dd95SBruce Richardson 			goto error;
136999a2dd95SBruce Richardson 
137099a2dd95SBruce Richardson 		for (j = 0; j < t->info.n_match_fields; j++) {
137199a2dd95SBruce Richardson 			status = rte_swx_ctl_table_match_field_info_get(p,
137299a2dd95SBruce Richardson 				i,
137399a2dd95SBruce Richardson 				j,
137499a2dd95SBruce Richardson 				&t->mf[j]);
137599a2dd95SBruce Richardson 			if (status)
137699a2dd95SBruce Richardson 				goto error;
137799a2dd95SBruce Richardson 		}
137899a2dd95SBruce Richardson 
137999a2dd95SBruce Richardson 		/* actions. */
138099a2dd95SBruce Richardson 		t->actions = calloc(t->info.n_actions,
138199a2dd95SBruce Richardson 			sizeof(struct rte_swx_ctl_table_action_info));
138299a2dd95SBruce Richardson 		if (!t->actions)
138399a2dd95SBruce Richardson 			goto error;
138499a2dd95SBruce Richardson 
138599a2dd95SBruce Richardson 		for (j = 0; j < t->info.n_actions; j++) {
138699a2dd95SBruce Richardson 			status = rte_swx_ctl_table_action_info_get(p,
138799a2dd95SBruce Richardson 				i,
138899a2dd95SBruce Richardson 				j,
138999a2dd95SBruce Richardson 				&t->actions[j]);
139099a2dd95SBruce Richardson 			if (status ||
139199a2dd95SBruce Richardson 			    t->actions[j].action_id >= ctl->info.n_actions)
139299a2dd95SBruce Richardson 				goto error;
139399a2dd95SBruce Richardson 		}
139499a2dd95SBruce Richardson 
139599a2dd95SBruce Richardson 		/* ops, is_stub. */
139699a2dd95SBruce Richardson 		status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub);
139799a2dd95SBruce Richardson 		if (status)
139899a2dd95SBruce Richardson 			goto error;
139999a2dd95SBruce Richardson 
140099a2dd95SBruce Richardson 		if ((t->is_stub && t->info.n_match_fields) ||
140199a2dd95SBruce Richardson 		    (!t->is_stub && !t->info.n_match_fields))
140299a2dd95SBruce Richardson 			goto error;
140399a2dd95SBruce Richardson 
140499a2dd95SBruce Richardson 		/* params. */
140599a2dd95SBruce Richardson 		status = table_params_get(ctl, i);
140699a2dd95SBruce Richardson 		if (status)
140799a2dd95SBruce Richardson 			goto error;
140899a2dd95SBruce Richardson 	}
140999a2dd95SBruce Richardson 
1410cdaa937dSCristian Dumitrescu 	/* selector tables. */
1411cdaa937dSCristian Dumitrescu 	ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
1412cdaa937dSCristian Dumitrescu 	if (!ctl->selectors)
1413cdaa937dSCristian Dumitrescu 		goto error;
1414cdaa937dSCristian Dumitrescu 
1415cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
1416cdaa937dSCristian Dumitrescu 		struct selector *s = &ctl->selectors[i];
1417cdaa937dSCristian Dumitrescu 		uint32_t j;
1418cdaa937dSCristian Dumitrescu 
1419cdaa937dSCristian Dumitrescu 		/* info. */
1420cdaa937dSCristian Dumitrescu 		status = rte_swx_ctl_selector_info_get(p, i, &s->info);
1421cdaa937dSCristian Dumitrescu 		if (status)
1422cdaa937dSCristian Dumitrescu 			goto error;
1423cdaa937dSCristian Dumitrescu 
1424cdaa937dSCristian Dumitrescu 		/* group_id field. */
1425cdaa937dSCristian Dumitrescu 		status = rte_swx_ctl_selector_group_id_field_info_get(p,
1426cdaa937dSCristian Dumitrescu 			i,
1427cdaa937dSCristian Dumitrescu 			&s->group_id_field);
1428cdaa937dSCristian Dumitrescu 		if (status)
1429cdaa937dSCristian Dumitrescu 			goto error;
1430cdaa937dSCristian Dumitrescu 
1431cdaa937dSCristian Dumitrescu 		/* selector fields. */
1432cdaa937dSCristian Dumitrescu 		s->selector_fields = calloc(s->info.n_selector_fields,
1433cdaa937dSCristian Dumitrescu 			sizeof(struct rte_swx_ctl_table_match_field_info));
1434cdaa937dSCristian Dumitrescu 		if (!s->selector_fields)
1435cdaa937dSCristian Dumitrescu 			goto error;
1436cdaa937dSCristian Dumitrescu 
1437cdaa937dSCristian Dumitrescu 		for (j = 0; j < s->info.n_selector_fields; j++) {
1438cdaa937dSCristian Dumitrescu 			status = rte_swx_ctl_selector_field_info_get(p,
1439cdaa937dSCristian Dumitrescu 				i,
1440cdaa937dSCristian Dumitrescu 				j,
1441cdaa937dSCristian Dumitrescu 				&s->selector_fields[j]);
1442cdaa937dSCristian Dumitrescu 			if (status)
1443cdaa937dSCristian Dumitrescu 				goto error;
1444cdaa937dSCristian Dumitrescu 		}
1445cdaa937dSCristian Dumitrescu 
1446cdaa937dSCristian Dumitrescu 		/* member_id field. */
1447cdaa937dSCristian Dumitrescu 		status = rte_swx_ctl_selector_member_id_field_info_get(p,
1448cdaa937dSCristian Dumitrescu 			i,
1449cdaa937dSCristian Dumitrescu 			&s->member_id_field);
1450cdaa937dSCristian Dumitrescu 		if (status)
1451cdaa937dSCristian Dumitrescu 			goto error;
1452cdaa937dSCristian Dumitrescu 
1453cdaa937dSCristian Dumitrescu 		/* groups. */
1454cdaa937dSCristian Dumitrescu 		s->groups = calloc(s->info.n_groups_max,
1455cdaa937dSCristian Dumitrescu 			sizeof(struct rte_swx_table_selector_group *));
1456cdaa937dSCristian Dumitrescu 		if (!s->groups)
1457cdaa937dSCristian Dumitrescu 			goto error;
1458cdaa937dSCristian Dumitrescu 
1459cdaa937dSCristian Dumitrescu 		/* pending_groups. */
1460cdaa937dSCristian Dumitrescu 		s->pending_groups = calloc(s->info.n_groups_max,
1461cdaa937dSCristian Dumitrescu 			sizeof(struct rte_swx_table_selector_group *));
1462cdaa937dSCristian Dumitrescu 		if (!s->pending_groups)
1463cdaa937dSCristian Dumitrescu 			goto error;
1464cdaa937dSCristian Dumitrescu 
1465cdaa937dSCristian Dumitrescu 		/* groups_added. */
1466cdaa937dSCristian Dumitrescu 		s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
1467cdaa937dSCristian Dumitrescu 		if (!s->groups_added)
1468cdaa937dSCristian Dumitrescu 			goto error;
1469cdaa937dSCristian Dumitrescu 
1470cdaa937dSCristian Dumitrescu 		/* groups_pending_delete. */
1471cdaa937dSCristian Dumitrescu 		s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
1472cdaa937dSCristian Dumitrescu 		if (!s->groups_pending_delete)
1473cdaa937dSCristian Dumitrescu 			goto error;
1474cdaa937dSCristian Dumitrescu 
1475cdaa937dSCristian Dumitrescu 		/* params. */
1476cdaa937dSCristian Dumitrescu 		status = selector_params_get(ctl, i);
1477cdaa937dSCristian Dumitrescu 		if (status)
1478cdaa937dSCristian Dumitrescu 			goto error;
1479cdaa937dSCristian Dumitrescu 	}
1480cdaa937dSCristian Dumitrescu 
14814f59d372SCristian Dumitrescu 	/* learner tables. */
14824f59d372SCristian Dumitrescu 	ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
14834f59d372SCristian Dumitrescu 	if (!ctl->learners)
14844f59d372SCristian Dumitrescu 		goto error;
14854f59d372SCristian Dumitrescu 
14864f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
14874f59d372SCristian Dumitrescu 		struct learner *l = &ctl->learners[i];
14884f59d372SCristian Dumitrescu 		uint32_t j;
14894f59d372SCristian Dumitrescu 
14904f59d372SCristian Dumitrescu 		/* info. */
14914f59d372SCristian Dumitrescu 		status = rte_swx_ctl_learner_info_get(p, i, &l->info);
14924f59d372SCristian Dumitrescu 		if (status)
14934f59d372SCristian Dumitrescu 			goto error;
14944f59d372SCristian Dumitrescu 
14954f59d372SCristian Dumitrescu 		/* mf. */
14964f59d372SCristian Dumitrescu 		l->mf = calloc(l->info.n_match_fields,
14974f59d372SCristian Dumitrescu 			       sizeof(struct rte_swx_ctl_table_match_field_info));
14984f59d372SCristian Dumitrescu 		if (!l->mf)
14994f59d372SCristian Dumitrescu 			goto error;
15004f59d372SCristian Dumitrescu 
15014f59d372SCristian Dumitrescu 		for (j = 0; j < l->info.n_match_fields; j++) {
15024f59d372SCristian Dumitrescu 			status = rte_swx_ctl_learner_match_field_info_get(p,
15034f59d372SCristian Dumitrescu 				i,
15044f59d372SCristian Dumitrescu 				j,
15054f59d372SCristian Dumitrescu 				&l->mf[j]);
15064f59d372SCristian Dumitrescu 			if (status)
15074f59d372SCristian Dumitrescu 				goto error;
15084f59d372SCristian Dumitrescu 		}
15094f59d372SCristian Dumitrescu 
15104f59d372SCristian Dumitrescu 		/* actions. */
15114f59d372SCristian Dumitrescu 		l->actions = calloc(l->info.n_actions,
15124f59d372SCristian Dumitrescu 			sizeof(struct rte_swx_ctl_table_action_info));
15134f59d372SCristian Dumitrescu 		if (!l->actions)
15144f59d372SCristian Dumitrescu 			goto error;
15154f59d372SCristian Dumitrescu 
15164f59d372SCristian Dumitrescu 		for (j = 0; j < l->info.n_actions; j++) {
15174f59d372SCristian Dumitrescu 			status = rte_swx_ctl_learner_action_info_get(p,
15184f59d372SCristian Dumitrescu 				i,
15194f59d372SCristian Dumitrescu 				j,
15204f59d372SCristian Dumitrescu 				&l->actions[j]);
15214f59d372SCristian Dumitrescu 			if (status || l->actions[j].action_id >= ctl->info.n_actions)
15224f59d372SCristian Dumitrescu 				goto error;
15234f59d372SCristian Dumitrescu 		}
15244f59d372SCristian Dumitrescu 
15254f59d372SCristian Dumitrescu 		/* action_data_size. */
15264f59d372SCristian Dumitrescu 		l->action_data_size = learner_action_data_size_get(ctl, l);
15274f59d372SCristian Dumitrescu 	}
15284f59d372SCristian Dumitrescu 
152999a2dd95SBruce Richardson 	/* ts. */
153099a2dd95SBruce Richardson 	status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
153199a2dd95SBruce Richardson 	if (status)
153299a2dd95SBruce Richardson 		goto error;
153399a2dd95SBruce Richardson 
153499a2dd95SBruce Richardson 	/* ts_next. */
153599a2dd95SBruce Richardson 	status = table_state_create(ctl);
153699a2dd95SBruce Richardson 	if (status)
153799a2dd95SBruce Richardson 		goto error;
153899a2dd95SBruce Richardson 
1539d69c90c8SCristian Dumitrescu 	if (ctl->info.name[0]) {
1540d69c90c8SCristian Dumitrescu 		status = ctl_register(ctl);
1541d69c90c8SCristian Dumitrescu 		if (status)
1542d69c90c8SCristian Dumitrescu 			goto error;
1543d69c90c8SCristian Dumitrescu 	}
1544d69c90c8SCristian Dumitrescu 
154599a2dd95SBruce Richardson 	return ctl;
154699a2dd95SBruce Richardson 
154799a2dd95SBruce Richardson error:
154899a2dd95SBruce Richardson 	rte_swx_ctl_pipeline_free(ctl);
154999a2dd95SBruce Richardson 	return NULL;
155099a2dd95SBruce Richardson }
155199a2dd95SBruce Richardson 
155299a2dd95SBruce Richardson int
rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)155399a2dd95SBruce Richardson rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl,
155499a2dd95SBruce Richardson 				     const char *table_name,
155599a2dd95SBruce Richardson 				     struct rte_swx_table_entry *entry)
155699a2dd95SBruce Richardson {
155799a2dd95SBruce Richardson 	struct table *table;
155899a2dd95SBruce Richardson 	struct rte_swx_table_entry *new_entry, *existing_entry;
155999a2dd95SBruce Richardson 	uint32_t table_id;
156099a2dd95SBruce Richardson 
156199a2dd95SBruce Richardson 	CHECK(ctl, EINVAL);
156299a2dd95SBruce Richardson 	CHECK(table_name && table_name[0], EINVAL);
156399a2dd95SBruce Richardson 
156499a2dd95SBruce Richardson 	table = table_find(ctl, table_name);
156599a2dd95SBruce Richardson 	CHECK(table, EINVAL);
156699a2dd95SBruce Richardson 	table_id = table - ctl->tables;
156799a2dd95SBruce Richardson 
156899a2dd95SBruce Richardson 	CHECK(entry, EINVAL);
156999a2dd95SBruce Richardson 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
157099a2dd95SBruce Richardson 
157199a2dd95SBruce Richardson 	new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
157299a2dd95SBruce Richardson 	CHECK(new_entry, ENOMEM);
157399a2dd95SBruce Richardson 
157499a2dd95SBruce Richardson 	/* The new entry is found in the table->entries list:
157599a2dd95SBruce Richardson 	 * - Add the new entry to the table->pending_modify1 list;
157699a2dd95SBruce Richardson 	 * - Move the existing entry from the table->entries list to the
157799a2dd95SBruce Richardson 	 *   table->pending_modify0 list.
157899a2dd95SBruce Richardson 	 */
157999a2dd95SBruce Richardson 	existing_entry = table_entries_find(table, entry);
158099a2dd95SBruce Richardson 	if (existing_entry) {
158199a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_modify1,
158299a2dd95SBruce Richardson 				  new_entry,
158399a2dd95SBruce Richardson 				  node);
158499a2dd95SBruce Richardson 
158599a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->entries,
158699a2dd95SBruce Richardson 			     existing_entry,
158799a2dd95SBruce Richardson 			     node);
158899a2dd95SBruce Richardson 
158999a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_modify0,
159099a2dd95SBruce Richardson 				  existing_entry,
159199a2dd95SBruce Richardson 				  node);
159299a2dd95SBruce Richardson 
159399a2dd95SBruce Richardson 		return 0;
159499a2dd95SBruce Richardson 	}
159599a2dd95SBruce Richardson 
159699a2dd95SBruce Richardson 	/* The new entry is found in the table->pending_add list:
159799a2dd95SBruce Richardson 	 * - Replace the entry in the table->pending_add list with the new entry
159899a2dd95SBruce Richardson 	 *   (and free the replaced entry).
159999a2dd95SBruce Richardson 	 */
160099a2dd95SBruce Richardson 	existing_entry = table_pending_add_find(table, entry);
160199a2dd95SBruce Richardson 	if (existing_entry) {
160299a2dd95SBruce Richardson 		TAILQ_INSERT_AFTER(&table->pending_add,
160399a2dd95SBruce Richardson 				   existing_entry,
160499a2dd95SBruce Richardson 				   new_entry,
160599a2dd95SBruce Richardson 				   node);
160699a2dd95SBruce Richardson 
160799a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_add,
160899a2dd95SBruce Richardson 			     existing_entry,
160999a2dd95SBruce Richardson 			     node);
161099a2dd95SBruce Richardson 
161199a2dd95SBruce Richardson 		table_entry_free(existing_entry);
161299a2dd95SBruce Richardson 
161399a2dd95SBruce Richardson 		return 0;
161499a2dd95SBruce Richardson 	}
161599a2dd95SBruce Richardson 
161699a2dd95SBruce Richardson 	/* The new entry is found in the table->pending_modify1 list:
161799a2dd95SBruce Richardson 	 * - Replace the entry in the table->pending_modify1 list with the new
161899a2dd95SBruce Richardson 	 *   entry (and free the replaced entry).
161999a2dd95SBruce Richardson 	 */
162099a2dd95SBruce Richardson 	existing_entry = table_pending_modify1_find(table, entry);
162199a2dd95SBruce Richardson 	if (existing_entry) {
162299a2dd95SBruce Richardson 		TAILQ_INSERT_AFTER(&table->pending_modify1,
162399a2dd95SBruce Richardson 				   existing_entry,
162499a2dd95SBruce Richardson 				   new_entry,
162599a2dd95SBruce Richardson 				   node);
162699a2dd95SBruce Richardson 
162799a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_modify1,
162899a2dd95SBruce Richardson 			     existing_entry,
162999a2dd95SBruce Richardson 			     node);
163099a2dd95SBruce Richardson 
163199a2dd95SBruce Richardson 		table_entry_free(existing_entry);
163299a2dd95SBruce Richardson 
163399a2dd95SBruce Richardson 		return 0;
163499a2dd95SBruce Richardson 	}
163599a2dd95SBruce Richardson 
163699a2dd95SBruce Richardson 	/* The new entry is found in the table->pending_delete list:
163799a2dd95SBruce Richardson 	 * - Add the new entry to the table->pending_modify1 list;
163899a2dd95SBruce Richardson 	 * - Move the existing entry from the table->pending_delete list to the
163999a2dd95SBruce Richardson 	 *   table->pending_modify0 list.
164099a2dd95SBruce Richardson 	 */
164199a2dd95SBruce Richardson 	existing_entry = table_pending_delete_find(table, entry);
164299a2dd95SBruce Richardson 	if (existing_entry) {
164399a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_modify1,
164499a2dd95SBruce Richardson 				  new_entry,
164599a2dd95SBruce Richardson 				  node);
164699a2dd95SBruce Richardson 
164799a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_delete,
164899a2dd95SBruce Richardson 			     existing_entry,
164999a2dd95SBruce Richardson 			     node);
165099a2dd95SBruce Richardson 
165199a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_modify0,
165299a2dd95SBruce Richardson 				  existing_entry,
165399a2dd95SBruce Richardson 				  node);
165499a2dd95SBruce Richardson 
165599a2dd95SBruce Richardson 		return 0;
165699a2dd95SBruce Richardson 	}
165799a2dd95SBruce Richardson 
165899a2dd95SBruce Richardson 	/* The new entry is not found in any of the above lists:
165999a2dd95SBruce Richardson 	 * - Add the new entry to the table->pending_add list.
166099a2dd95SBruce Richardson 	 */
166199a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node);
166299a2dd95SBruce Richardson 
166399a2dd95SBruce Richardson 	return 0;
166499a2dd95SBruce Richardson }
166599a2dd95SBruce Richardson 
166699a2dd95SBruce Richardson int
rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)166799a2dd95SBruce Richardson rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
166899a2dd95SBruce Richardson 					const char *table_name,
166999a2dd95SBruce Richardson 					struct rte_swx_table_entry *entry)
167099a2dd95SBruce Richardson {
167199a2dd95SBruce Richardson 	struct table *table;
167299a2dd95SBruce Richardson 	struct rte_swx_table_entry *existing_entry;
167399a2dd95SBruce Richardson 	uint32_t table_id;
167499a2dd95SBruce Richardson 
167599a2dd95SBruce Richardson 	CHECK(ctl, EINVAL);
167699a2dd95SBruce Richardson 
167799a2dd95SBruce Richardson 	CHECK(table_name && table_name[0], EINVAL);
167899a2dd95SBruce Richardson 	table = table_find(ctl, table_name);
167999a2dd95SBruce Richardson 	CHECK(table, EINVAL);
168099a2dd95SBruce Richardson 	table_id = table - ctl->tables;
168199a2dd95SBruce Richardson 
168299a2dd95SBruce Richardson 	CHECK(entry, EINVAL);
168399a2dd95SBruce Richardson 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL);
168499a2dd95SBruce Richardson 
168599a2dd95SBruce Richardson 	/* The entry is found in the table->entries list:
1686*23f3dac4SStephen Hemminger 	 * - Move the existing entry from the table->entries list to the
168799a2dd95SBruce Richardson 	 *   table->pending_delete list.
168899a2dd95SBruce Richardson 	 */
168999a2dd95SBruce Richardson 	existing_entry = table_entries_find(table, entry);
169099a2dd95SBruce Richardson 	if (existing_entry) {
169199a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->entries,
169299a2dd95SBruce Richardson 			     existing_entry,
169399a2dd95SBruce Richardson 			     node);
169499a2dd95SBruce Richardson 
169599a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_delete,
169699a2dd95SBruce Richardson 				  existing_entry,
169799a2dd95SBruce Richardson 				  node);
169899a2dd95SBruce Richardson 
169999a2dd95SBruce Richardson 		return 0;
170099a2dd95SBruce Richardson 	}
170199a2dd95SBruce Richardson 
170299a2dd95SBruce Richardson 	/* The entry is found in the table->pending_add list:
170399a2dd95SBruce Richardson 	 * - Remove the entry from the table->pending_add list and free it.
170499a2dd95SBruce Richardson 	 */
170599a2dd95SBruce Richardson 	existing_entry = table_pending_add_find(table, entry);
170699a2dd95SBruce Richardson 	if (existing_entry) {
170799a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_add,
170899a2dd95SBruce Richardson 			     existing_entry,
170999a2dd95SBruce Richardson 			     node);
171099a2dd95SBruce Richardson 
171199a2dd95SBruce Richardson 		table_entry_free(existing_entry);
171299a2dd95SBruce Richardson 	}
171399a2dd95SBruce Richardson 
171499a2dd95SBruce Richardson 	/* The entry is found in the table->pending_modify1 list:
171599a2dd95SBruce Richardson 	 * - Free the entry in the table->pending_modify1 list;
171699a2dd95SBruce Richardson 	 * - Move the existing entry from the table->pending_modify0 list to the
171799a2dd95SBruce Richardson 	 *   table->pending_delete list.
171899a2dd95SBruce Richardson 	 */
171999a2dd95SBruce Richardson 	existing_entry = table_pending_modify1_find(table, entry);
172099a2dd95SBruce Richardson 	if (existing_entry) {
172199a2dd95SBruce Richardson 		struct rte_swx_table_entry *real_existing_entry;
172299a2dd95SBruce Richardson 
172399a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_modify1,
172499a2dd95SBruce Richardson 			     existing_entry,
172599a2dd95SBruce Richardson 			     node);
172699a2dd95SBruce Richardson 
172799a2dd95SBruce Richardson 		table_entry_free(existing_entry);
172899a2dd95SBruce Richardson 
172999a2dd95SBruce Richardson 		real_existing_entry = table_pending_modify0_find(table, entry);
173099a2dd95SBruce Richardson 		CHECK(real_existing_entry, EINVAL); /* Coverity. */
173199a2dd95SBruce Richardson 
173299a2dd95SBruce Richardson 		TAILQ_REMOVE(&table->pending_modify0,
173399a2dd95SBruce Richardson 			     real_existing_entry,
173499a2dd95SBruce Richardson 			     node);
173599a2dd95SBruce Richardson 
173699a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(&table->pending_delete,
173799a2dd95SBruce Richardson 				  real_existing_entry,
173899a2dd95SBruce Richardson 				  node);
173999a2dd95SBruce Richardson 
174099a2dd95SBruce Richardson 		return 0;
174199a2dd95SBruce Richardson 	}
174299a2dd95SBruce Richardson 
174399a2dd95SBruce Richardson 	/* The entry is found in the table->pending_delete list:
174499a2dd95SBruce Richardson 	 * - Do nothing: the existing entry is already in the
174599a2dd95SBruce Richardson 	 *   table->pending_delete list, i.e. already marked for delete, so
174699a2dd95SBruce Richardson 	 *   simply keep it there as it is.
174799a2dd95SBruce Richardson 	 */
174899a2dd95SBruce Richardson 
174999a2dd95SBruce Richardson 	/* The entry is not found in any of the above lists:
175099a2dd95SBruce Richardson 	 * - Do nothing: no existing entry to delete.
175199a2dd95SBruce Richardson 	 */
175299a2dd95SBruce Richardson 
175399a2dd95SBruce Richardson 	return 0;
175499a2dd95SBruce Richardson }
175599a2dd95SBruce Richardson 
175699a2dd95SBruce Richardson int
rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * table_name,struct rte_swx_table_entry * entry)175799a2dd95SBruce Richardson rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
175899a2dd95SBruce Richardson 					     const char *table_name,
175999a2dd95SBruce Richardson 					     struct rte_swx_table_entry *entry)
176099a2dd95SBruce Richardson {
176199a2dd95SBruce Richardson 	struct table *table;
176299a2dd95SBruce Richardson 	struct rte_swx_table_entry *new_entry;
176399a2dd95SBruce Richardson 	uint32_t table_id;
176499a2dd95SBruce Richardson 
176599a2dd95SBruce Richardson 	CHECK(ctl, EINVAL);
176699a2dd95SBruce Richardson 
176799a2dd95SBruce Richardson 	CHECK(table_name && table_name[0], EINVAL);
176899a2dd95SBruce Richardson 	table = table_find(ctl, table_name);
176999a2dd95SBruce Richardson 	CHECK(table, EINVAL);
177099a2dd95SBruce Richardson 	table_id = table - ctl->tables;
177199a2dd95SBruce Richardson 	CHECK(!table->info.default_action_is_const, EINVAL);
177299a2dd95SBruce Richardson 
177399a2dd95SBruce Richardson 	CHECK(entry, EINVAL);
177499a2dd95SBruce Richardson 	CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
177599a2dd95SBruce Richardson 
177699a2dd95SBruce Richardson 	new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
177799a2dd95SBruce Richardson 	CHECK(new_entry, ENOMEM);
177899a2dd95SBruce Richardson 
177999a2dd95SBruce Richardson 	table_pending_default_free(table);
178099a2dd95SBruce Richardson 
178199a2dd95SBruce Richardson 	table->pending_default = new_entry;
178299a2dd95SBruce Richardson 	return 0;
178399a2dd95SBruce Richardson }
178499a2dd95SBruce Richardson 
178599a2dd95SBruce Richardson 
178699a2dd95SBruce Richardson static void
table_entry_list_free(struct rte_swx_table_entry_list * list)178799a2dd95SBruce Richardson table_entry_list_free(struct rte_swx_table_entry_list *list)
178899a2dd95SBruce Richardson {
178999a2dd95SBruce Richardson 	for ( ; ; ) {
179099a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
179199a2dd95SBruce Richardson 
179299a2dd95SBruce Richardson 		entry = TAILQ_FIRST(list);
179399a2dd95SBruce Richardson 		if (!entry)
179499a2dd95SBruce Richardson 			break;
179599a2dd95SBruce Richardson 
179699a2dd95SBruce Richardson 		TAILQ_REMOVE(list, entry, node);
179799a2dd95SBruce Richardson 		table_entry_free(entry);
179899a2dd95SBruce Richardson 	}
179999a2dd95SBruce Richardson }
180099a2dd95SBruce Richardson 
180199a2dd95SBruce Richardson static int
table_entry_list_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,struct rte_swx_table_entry_list * dst,struct rte_swx_table_entry_list * src)180299a2dd95SBruce Richardson table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl,
180399a2dd95SBruce Richardson 			   uint32_t table_id,
180499a2dd95SBruce Richardson 			   struct rte_swx_table_entry_list *dst,
180599a2dd95SBruce Richardson 			   struct rte_swx_table_entry_list *src)
180699a2dd95SBruce Richardson {
180799a2dd95SBruce Richardson 	struct rte_swx_table_entry *src_entry;
180899a2dd95SBruce Richardson 
180999a2dd95SBruce Richardson 	TAILQ_FOREACH(src_entry, src, node) {
181099a2dd95SBruce Richardson 		struct rte_swx_table_entry *dst_entry;
181199a2dd95SBruce Richardson 
181299a2dd95SBruce Richardson 		dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1);
181399a2dd95SBruce Richardson 		if (!dst_entry)
181499a2dd95SBruce Richardson 			goto error;
181599a2dd95SBruce Richardson 
181699a2dd95SBruce Richardson 		TAILQ_INSERT_TAIL(dst, dst_entry, node);
181799a2dd95SBruce Richardson 	}
181899a2dd95SBruce Richardson 
181999a2dd95SBruce Richardson 	return 0;
182099a2dd95SBruce Richardson 
182199a2dd95SBruce Richardson error:
182299a2dd95SBruce Richardson 	table_entry_list_free(dst);
182399a2dd95SBruce Richardson 	return -ENOMEM;
182499a2dd95SBruce Richardson }
182599a2dd95SBruce Richardson 
182699a2dd95SBruce Richardson /* This commit stage contains all the operations that can fail; in case ANY of
182799a2dd95SBruce Richardson  * them fails for ANY table, ALL of them are rolled back for ALL the tables.
182899a2dd95SBruce Richardson  */
182999a2dd95SBruce Richardson static int
table_rollfwd0(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id,uint32_t after_swap)183099a2dd95SBruce Richardson table_rollfwd0(struct rte_swx_ctl_pipeline *ctl,
183199a2dd95SBruce Richardson 	       uint32_t table_id,
183299a2dd95SBruce Richardson 	       uint32_t after_swap)
183399a2dd95SBruce Richardson {
183499a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
183599a2dd95SBruce Richardson 	struct rte_swx_table_state *ts = &ctl->ts[table_id];
183699a2dd95SBruce Richardson 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
183799a2dd95SBruce Richardson 
183899a2dd95SBruce Richardson 	if (table->is_stub || !table_is_update_pending(table, 0))
183999a2dd95SBruce Richardson 		return 0;
184099a2dd95SBruce Richardson 
184199a2dd95SBruce Richardson 	/*
184299a2dd95SBruce Richardson 	 * Current table supports incremental update.
184399a2dd95SBruce Richardson 	 */
184499a2dd95SBruce Richardson 	if (table->ops.add) {
184599a2dd95SBruce Richardson 		/* Reset counters. */
184699a2dd95SBruce Richardson 		table->n_add = 0;
184799a2dd95SBruce Richardson 		table->n_modify = 0;
184899a2dd95SBruce Richardson 		table->n_delete = 0;
184999a2dd95SBruce Richardson 
185099a2dd95SBruce Richardson 		/* Add pending rules. */
185199a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
185299a2dd95SBruce Richardson 
185399a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_add, node) {
185499a2dd95SBruce Richardson 			int status;
185599a2dd95SBruce Richardson 
185699a2dd95SBruce Richardson 			status = table->ops.add(ts_next->obj, entry);
185799a2dd95SBruce Richardson 			if (status)
185899a2dd95SBruce Richardson 				return status;
185999a2dd95SBruce Richardson 
186099a2dd95SBruce Richardson 			table->n_add++;
186199a2dd95SBruce Richardson 		}
186299a2dd95SBruce Richardson 
186399a2dd95SBruce Richardson 		/* Modify pending rules. */
186499a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_modify1, node) {
186599a2dd95SBruce Richardson 			int status;
186699a2dd95SBruce Richardson 
186799a2dd95SBruce Richardson 			status = table->ops.add(ts_next->obj, entry);
186899a2dd95SBruce Richardson 			if (status)
186999a2dd95SBruce Richardson 				return status;
187099a2dd95SBruce Richardson 
187199a2dd95SBruce Richardson 			table->n_modify++;
187299a2dd95SBruce Richardson 		}
187399a2dd95SBruce Richardson 
187499a2dd95SBruce Richardson 		/* Delete pending rules. */
187599a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
187699a2dd95SBruce Richardson 			int status;
187799a2dd95SBruce Richardson 
187899a2dd95SBruce Richardson 			status = table->ops.del(ts_next->obj, entry);
187999a2dd95SBruce Richardson 			if (status)
188099a2dd95SBruce Richardson 				return status;
188199a2dd95SBruce Richardson 
188299a2dd95SBruce Richardson 			table->n_delete++;
188399a2dd95SBruce Richardson 		}
188499a2dd95SBruce Richardson 
188599a2dd95SBruce Richardson 		return 0;
188699a2dd95SBruce Richardson 	}
188799a2dd95SBruce Richardson 
188899a2dd95SBruce Richardson 	/*
188999a2dd95SBruce Richardson 	 * Current table does NOT support incremental update.
189099a2dd95SBruce Richardson 	 */
189199a2dd95SBruce Richardson 	if (!after_swap) {
189299a2dd95SBruce Richardson 		struct rte_swx_table_entry_list list;
189399a2dd95SBruce Richardson 		int status;
189499a2dd95SBruce Richardson 
189599a2dd95SBruce Richardson 		/* Create updated list of entries included. */
189699a2dd95SBruce Richardson 		TAILQ_INIT(&list);
189799a2dd95SBruce Richardson 
189899a2dd95SBruce Richardson 		status = table_entry_list_duplicate(ctl,
189999a2dd95SBruce Richardson 						    table_id,
190099a2dd95SBruce Richardson 						    &list,
190199a2dd95SBruce Richardson 						    &table->entries);
190299a2dd95SBruce Richardson 		if (status)
190399a2dd95SBruce Richardson 			goto error;
190499a2dd95SBruce Richardson 
190599a2dd95SBruce Richardson 		status = table_entry_list_duplicate(ctl,
190699a2dd95SBruce Richardson 						    table_id,
190799a2dd95SBruce Richardson 						    &list,
190899a2dd95SBruce Richardson 						    &table->pending_add);
190999a2dd95SBruce Richardson 		if (status)
191099a2dd95SBruce Richardson 			goto error;
191199a2dd95SBruce Richardson 
191299a2dd95SBruce Richardson 		status = table_entry_list_duplicate(ctl,
191399a2dd95SBruce Richardson 						    table_id,
191499a2dd95SBruce Richardson 						    &list,
191599a2dd95SBruce Richardson 						    &table->pending_modify1);
191699a2dd95SBruce Richardson 		if (status)
191799a2dd95SBruce Richardson 			goto error;
191899a2dd95SBruce Richardson 
191999a2dd95SBruce Richardson 		/* Create new table object with the updates included. */
192099a2dd95SBruce Richardson 		ts_next->obj = table->ops.create(&table->params,
192199a2dd95SBruce Richardson 						 &list,
192299a2dd95SBruce Richardson 						 table->info.args,
192399a2dd95SBruce Richardson 						 ctl->numa_node);
192499a2dd95SBruce Richardson 		if (!ts_next->obj) {
192599a2dd95SBruce Richardson 			status = -ENODEV;
192699a2dd95SBruce Richardson 			goto error;
192799a2dd95SBruce Richardson 		}
192899a2dd95SBruce Richardson 
192999a2dd95SBruce Richardson 		table_entry_list_free(&list);
193099a2dd95SBruce Richardson 
193199a2dd95SBruce Richardson 		return 0;
193299a2dd95SBruce Richardson 
193399a2dd95SBruce Richardson error:
193499a2dd95SBruce Richardson 		table_entry_list_free(&list);
193599a2dd95SBruce Richardson 		return status;
193699a2dd95SBruce Richardson 	}
193799a2dd95SBruce Richardson 
193899a2dd95SBruce Richardson 	/* Free the old table object. */
193999a2dd95SBruce Richardson 	if (ts_next->obj && table->ops.free)
194099a2dd95SBruce Richardson 		table->ops.free(ts_next->obj);
194199a2dd95SBruce Richardson 
194299a2dd95SBruce Richardson 	/* Copy over the new table object. */
194399a2dd95SBruce Richardson 	ts_next->obj = ts->obj;
194499a2dd95SBruce Richardson 
194599a2dd95SBruce Richardson 	return 0;
194699a2dd95SBruce Richardson }
194799a2dd95SBruce Richardson 
194899a2dd95SBruce Richardson /* This commit stage contains all the operations that cannot fail. They are
194999a2dd95SBruce Richardson  * executed only if the previous stage was successful for ALL the tables. Hence,
195099a2dd95SBruce Richardson  * none of these operations has to be rolled back for ANY table.
195199a2dd95SBruce Richardson  */
195299a2dd95SBruce Richardson static void
table_rollfwd1(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)195399a2dd95SBruce Richardson table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
195499a2dd95SBruce Richardson {
195599a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
195699a2dd95SBruce Richardson 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
195799a2dd95SBruce Richardson 	struct action *a;
195899a2dd95SBruce Richardson 	uint8_t *action_data;
195999a2dd95SBruce Richardson 	uint64_t action_id;
196099a2dd95SBruce Richardson 
196199a2dd95SBruce Richardson 	/* Copy the pending default entry. */
196299a2dd95SBruce Richardson 	if (!table->pending_default)
196399a2dd95SBruce Richardson 		return;
196499a2dd95SBruce Richardson 
196599a2dd95SBruce Richardson 	action_id = table->pending_default->action_id;
196699a2dd95SBruce Richardson 	action_data = table->pending_default->action_data;
196799a2dd95SBruce Richardson 	a = &ctl->actions[action_id];
196899a2dd95SBruce Richardson 
19694f59d372SCristian Dumitrescu 	if (a->data_size)
19704f59d372SCristian Dumitrescu 		memcpy(ts_next->default_action_data, action_data, a->data_size);
197199a2dd95SBruce Richardson 
197299a2dd95SBruce Richardson 	ts_next->default_action_id = action_id;
197399a2dd95SBruce Richardson }
197499a2dd95SBruce Richardson 
197599a2dd95SBruce Richardson /* This last commit stage is simply finalizing a successful commit operation.
197699a2dd95SBruce Richardson  * This stage is only executed if all the previous stages were successful. This
197799a2dd95SBruce Richardson  * stage cannot fail.
197899a2dd95SBruce Richardson  */
197999a2dd95SBruce Richardson static void
table_rollfwd2(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)198099a2dd95SBruce Richardson table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
198199a2dd95SBruce Richardson {
198299a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
198399a2dd95SBruce Richardson 
198499a2dd95SBruce Richardson 	/* Move all the pending add entries to the table, as they are now part
198599a2dd95SBruce Richardson 	 * of the table.
198699a2dd95SBruce Richardson 	 */
198799a2dd95SBruce Richardson 	table_pending_add_admit(table);
198899a2dd95SBruce Richardson 
198999a2dd95SBruce Richardson 	/* Move all the pending modify1 entries to table, are they are now part
199099a2dd95SBruce Richardson 	 * of the table. Free up all the pending modify0 entries, as they are no
199199a2dd95SBruce Richardson 	 * longer part of the table.
199299a2dd95SBruce Richardson 	 */
199399a2dd95SBruce Richardson 	table_pending_modify1_admit(table);
199499a2dd95SBruce Richardson 	table_pending_modify0_free(table);
199599a2dd95SBruce Richardson 
199699a2dd95SBruce Richardson 	/* Free up all the pending delete entries, as they are no longer part of
199799a2dd95SBruce Richardson 	 * the table.
199899a2dd95SBruce Richardson 	 */
199999a2dd95SBruce Richardson 	table_pending_delete_free(table);
200099a2dd95SBruce Richardson 
200199a2dd95SBruce Richardson 	/* Free up the pending default entry, as it is now part of the table. */
200299a2dd95SBruce Richardson 	table_pending_default_free(table);
200399a2dd95SBruce Richardson }
200499a2dd95SBruce Richardson 
200599a2dd95SBruce Richardson /* The rollback stage is only executed when the commit failed, i.e. ANY of the
200699a2dd95SBruce Richardson  * commit operations that can fail did fail for ANY table. It reverts ALL the
200799a2dd95SBruce Richardson  * tables to their state before the commit started, as if the commit never
200899a2dd95SBruce Richardson  * happened.
200999a2dd95SBruce Richardson  */
201099a2dd95SBruce Richardson static void
table_rollback(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)201199a2dd95SBruce Richardson table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
201299a2dd95SBruce Richardson {
201399a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
201499a2dd95SBruce Richardson 	struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id];
201599a2dd95SBruce Richardson 
201699a2dd95SBruce Richardson 	if (table->is_stub || !table_is_update_pending(table, 0))
201799a2dd95SBruce Richardson 		return;
201899a2dd95SBruce Richardson 
201999a2dd95SBruce Richardson 	if (table->ops.add) {
202099a2dd95SBruce Richardson 		struct rte_swx_table_entry *entry;
202199a2dd95SBruce Richardson 
202299a2dd95SBruce Richardson 		/* Add back all the entries that were just deleted. */
202399a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_delete, node) {
202499a2dd95SBruce Richardson 			if (!table->n_delete)
202599a2dd95SBruce Richardson 				break;
202699a2dd95SBruce Richardson 
202799a2dd95SBruce Richardson 			table->ops.add(ts_next->obj, entry);
202899a2dd95SBruce Richardson 			table->n_delete--;
202999a2dd95SBruce Richardson 		}
203099a2dd95SBruce Richardson 
203199a2dd95SBruce Richardson 		/* Add back the old copy for all the entries that were just
203299a2dd95SBruce Richardson 		 * modified.
203399a2dd95SBruce Richardson 		 */
203499a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_modify0, node) {
203599a2dd95SBruce Richardson 			if (!table->n_modify)
203699a2dd95SBruce Richardson 				break;
203799a2dd95SBruce Richardson 
203899a2dd95SBruce Richardson 			table->ops.add(ts_next->obj, entry);
203999a2dd95SBruce Richardson 			table->n_modify--;
204099a2dd95SBruce Richardson 		}
204199a2dd95SBruce Richardson 
204299a2dd95SBruce Richardson 		/* Delete all the entries that were just added. */
204399a2dd95SBruce Richardson 		TAILQ_FOREACH(entry, &table->pending_add, node) {
204499a2dd95SBruce Richardson 			if (!table->n_add)
204599a2dd95SBruce Richardson 				break;
204699a2dd95SBruce Richardson 
204799a2dd95SBruce Richardson 			table->ops.del(ts_next->obj, entry);
204899a2dd95SBruce Richardson 			table->n_add--;
204999a2dd95SBruce Richardson 		}
205099a2dd95SBruce Richardson 	} else {
205199a2dd95SBruce Richardson 		struct rte_swx_table_state *ts = &ctl->ts[table_id];
205299a2dd95SBruce Richardson 
205399a2dd95SBruce Richardson 		/* Free the new table object, as update was cancelled. */
205499a2dd95SBruce Richardson 		if (ts_next->obj && table->ops.free)
205599a2dd95SBruce Richardson 			table->ops.free(ts_next->obj);
205699a2dd95SBruce Richardson 
205799a2dd95SBruce Richardson 		/* Reinstate the old table object. */
205899a2dd95SBruce Richardson 		ts_next->obj = ts->obj;
205999a2dd95SBruce Richardson 	}
206099a2dd95SBruce Richardson }
206199a2dd95SBruce Richardson 
206299a2dd95SBruce Richardson /* This stage is conditionally executed (as instructed by the user) after a
206399a2dd95SBruce Richardson  * failed commit operation to remove ALL the pending work for ALL the tables.
206499a2dd95SBruce Richardson  */
206599a2dd95SBruce Richardson static void
table_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t table_id)206699a2dd95SBruce Richardson table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
206799a2dd95SBruce Richardson {
206899a2dd95SBruce Richardson 	struct table *table = &ctl->tables[table_id];
206999a2dd95SBruce Richardson 
207099a2dd95SBruce Richardson 	/* Free up all the pending add entries, as none of them is part of the
207199a2dd95SBruce Richardson 	 * table.
207299a2dd95SBruce Richardson 	 */
207399a2dd95SBruce Richardson 	table_pending_add_free(table);
207499a2dd95SBruce Richardson 
207599a2dd95SBruce Richardson 	/* Free up all the pending modify1 entries, as none of them made it to
207699a2dd95SBruce Richardson 	 * the table. Add back all the pending modify0 entries, as none of them
207799a2dd95SBruce Richardson 	 * was deleted from the table.
207899a2dd95SBruce Richardson 	 */
207999a2dd95SBruce Richardson 	table_pending_modify1_free(table);
208099a2dd95SBruce Richardson 	table_pending_modify0_admit(table);
208199a2dd95SBruce Richardson 
208299a2dd95SBruce Richardson 	/* Add back all the pending delete entries, as none of them was deleted
208399a2dd95SBruce Richardson 	 * from the table.
208499a2dd95SBruce Richardson 	 */
208599a2dd95SBruce Richardson 	table_pending_delete_admit(table);
208699a2dd95SBruce Richardson 
208799a2dd95SBruce Richardson 	/* Free up the pending default entry, as it is no longer going to be
208899a2dd95SBruce Richardson 	 * added to the table.
208999a2dd95SBruce Richardson 	 */
209099a2dd95SBruce Richardson 	table_pending_default_free(table);
209199a2dd95SBruce Richardson }
209299a2dd95SBruce Richardson 
209399a2dd95SBruce Richardson int
rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t * group_id)2094cdaa937dSCristian Dumitrescu rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
2095cdaa937dSCristian Dumitrescu 					const char *selector_name,
2096cdaa937dSCristian Dumitrescu 					uint32_t *group_id)
2097cdaa937dSCristian Dumitrescu {
2098cdaa937dSCristian Dumitrescu 	struct selector *s;
2099cdaa937dSCristian Dumitrescu 	uint32_t i;
2100cdaa937dSCristian Dumitrescu 
2101cdaa937dSCristian Dumitrescu 	/* Check input arguments. */
2102cdaa937dSCristian Dumitrescu 	if (!ctl || !selector_name || !selector_name[0] || !group_id)
2103cdaa937dSCristian Dumitrescu 		return -EINVAL;
2104cdaa937dSCristian Dumitrescu 
2105cdaa937dSCristian Dumitrescu 	s = selector_find(ctl, selector_name);
2106cdaa937dSCristian Dumitrescu 	if (!s)
2107cdaa937dSCristian Dumitrescu 		return -EINVAL;
2108cdaa937dSCristian Dumitrescu 
2109cdaa937dSCristian Dumitrescu 	/* Find an unused group. */
2110cdaa937dSCristian Dumitrescu 	for (i = 0; i < s->info.n_groups_max; i++)
2111cdaa937dSCristian Dumitrescu 		if (!s->groups_added[i]) {
2112cdaa937dSCristian Dumitrescu 			*group_id = i;
2113cdaa937dSCristian Dumitrescu 			s->groups_added[i] = 1;
2114cdaa937dSCristian Dumitrescu 			return 0;
2115cdaa937dSCristian Dumitrescu 		}
2116cdaa937dSCristian Dumitrescu 
2117cdaa937dSCristian Dumitrescu 	return -ENOSPC;
2118cdaa937dSCristian Dumitrescu }
2119cdaa937dSCristian Dumitrescu 
2120cdaa937dSCristian Dumitrescu int
rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id)2121cdaa937dSCristian Dumitrescu rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
2122cdaa937dSCristian Dumitrescu 					   const char *selector_name,
2123cdaa937dSCristian Dumitrescu 					   uint32_t group_id)
2124cdaa937dSCristian Dumitrescu {
2125cdaa937dSCristian Dumitrescu 	struct selector *s;
2126cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *group;
2127cdaa937dSCristian Dumitrescu 
2128cdaa937dSCristian Dumitrescu 	/* Check input arguments. */
2129cdaa937dSCristian Dumitrescu 	if (!ctl || !selector_name || !selector_name[0])
2130cdaa937dSCristian Dumitrescu 		return -EINVAL;
2131cdaa937dSCristian Dumitrescu 
2132cdaa937dSCristian Dumitrescu 	s = selector_find(ctl, selector_name);
2133cdaa937dSCristian Dumitrescu 	if (!s ||
2134cdaa937dSCristian Dumitrescu 	   (group_id >= s->info.n_groups_max) ||
2135cdaa937dSCristian Dumitrescu 	   !s->groups_added[group_id])
2136cdaa937dSCristian Dumitrescu 		return -EINVAL;
2137cdaa937dSCristian Dumitrescu 
2138cdaa937dSCristian Dumitrescu 	/* Check if this group is already scheduled for deletion. */
2139cdaa937dSCristian Dumitrescu 	if (s->groups_pending_delete[group_id])
2140cdaa937dSCristian Dumitrescu 		return 0;
2141cdaa937dSCristian Dumitrescu 
2142cdaa937dSCristian Dumitrescu 	/* Initialize the pending group, if needed. */
2143cdaa937dSCristian Dumitrescu 	if (!s->pending_groups[group_id]) {
2144cdaa937dSCristian Dumitrescu 		int status;
2145cdaa937dSCristian Dumitrescu 
2146cdaa937dSCristian Dumitrescu 		status = selector_group_duplicate_to_pending(s, group_id);
2147cdaa937dSCristian Dumitrescu 		if (status)
2148cdaa937dSCristian Dumitrescu 			return status;
2149cdaa937dSCristian Dumitrescu 	}
2150cdaa937dSCristian Dumitrescu 
2151cdaa937dSCristian Dumitrescu 	group = s->pending_groups[group_id];
2152cdaa937dSCristian Dumitrescu 
2153cdaa937dSCristian Dumitrescu 	/* Schedule removal of all the members from the current group. */
2154cdaa937dSCristian Dumitrescu 	for ( ; ; ) {
2155cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_member *m;
2156cdaa937dSCristian Dumitrescu 
2157cdaa937dSCristian Dumitrescu 		m = TAILQ_FIRST(&group->members);
2158cdaa937dSCristian Dumitrescu 		if (!m)
2159cdaa937dSCristian Dumitrescu 			break;
2160cdaa937dSCristian Dumitrescu 
2161cdaa937dSCristian Dumitrescu 		TAILQ_REMOVE(&group->members, m, node);
2162cdaa937dSCristian Dumitrescu 		free(m);
2163cdaa937dSCristian Dumitrescu 	}
2164cdaa937dSCristian Dumitrescu 
2165cdaa937dSCristian Dumitrescu 	/* Schedule the group for deletion. */
2166cdaa937dSCristian Dumitrescu 	s->groups_pending_delete[group_id] = 1;
2167cdaa937dSCristian Dumitrescu 
2168cdaa937dSCristian Dumitrescu 	return 0;
2169cdaa937dSCristian Dumitrescu }
2170cdaa937dSCristian Dumitrescu 
2171cdaa937dSCristian Dumitrescu int
rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id,uint32_t member_id,uint32_t member_weight)2172cdaa937dSCristian Dumitrescu rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl,
2173cdaa937dSCristian Dumitrescu 					       const char *selector_name,
2174cdaa937dSCristian Dumitrescu 					       uint32_t group_id,
2175cdaa937dSCristian Dumitrescu 					       uint32_t member_id,
2176cdaa937dSCristian Dumitrescu 					       uint32_t member_weight)
2177cdaa937dSCristian Dumitrescu {
2178cdaa937dSCristian Dumitrescu 	struct selector *s;
2179cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *group;
2180cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_member *m;
2181cdaa937dSCristian Dumitrescu 
2182cdaa937dSCristian Dumitrescu 	if (!member_weight)
2183cdaa937dSCristian Dumitrescu 		return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
2184cdaa937dSCristian Dumitrescu 									 selector_name,
2185cdaa937dSCristian Dumitrescu 									 group_id,
2186cdaa937dSCristian Dumitrescu 									 member_id);
2187cdaa937dSCristian Dumitrescu 
2188cdaa937dSCristian Dumitrescu 	/* Check input arguments. */
2189cdaa937dSCristian Dumitrescu 	if (!ctl || !selector_name || !selector_name[0])
2190cdaa937dSCristian Dumitrescu 		return -EINVAL;
2191cdaa937dSCristian Dumitrescu 
2192cdaa937dSCristian Dumitrescu 	s = selector_find(ctl, selector_name);
2193cdaa937dSCristian Dumitrescu 	if (!s ||
2194cdaa937dSCristian Dumitrescu 	   (group_id >= s->info.n_groups_max) ||
2195cdaa937dSCristian Dumitrescu 	   !s->groups_added[group_id] ||
2196cdaa937dSCristian Dumitrescu 	   s->groups_pending_delete[group_id])
2197cdaa937dSCristian Dumitrescu 		return -EINVAL;
2198cdaa937dSCristian Dumitrescu 
2199cdaa937dSCristian Dumitrescu 	/* Initialize the pending group, if needed. */
2200cdaa937dSCristian Dumitrescu 	if (!s->pending_groups[group_id]) {
2201cdaa937dSCristian Dumitrescu 		int status;
2202cdaa937dSCristian Dumitrescu 
2203cdaa937dSCristian Dumitrescu 		status = selector_group_duplicate_to_pending(s, group_id);
2204cdaa937dSCristian Dumitrescu 		if (status)
2205cdaa937dSCristian Dumitrescu 			return status;
2206cdaa937dSCristian Dumitrescu 	}
2207cdaa937dSCristian Dumitrescu 
2208cdaa937dSCristian Dumitrescu 	group = s->pending_groups[group_id];
2209cdaa937dSCristian Dumitrescu 
2210cdaa937dSCristian Dumitrescu 	/* If this member is already in this group, then simply update its weight and return. */
2211cdaa937dSCristian Dumitrescu 	TAILQ_FOREACH(m, &group->members, node)
2212cdaa937dSCristian Dumitrescu 		if (m->member_id == member_id) {
2213cdaa937dSCristian Dumitrescu 			m->member_weight = member_weight;
2214cdaa937dSCristian Dumitrescu 			return 0;
2215cdaa937dSCristian Dumitrescu 		}
2216cdaa937dSCristian Dumitrescu 
2217cdaa937dSCristian Dumitrescu 	/* Add new member to this group. */
2218cdaa937dSCristian Dumitrescu 	m = calloc(1, sizeof(struct rte_swx_table_selector_member));
2219cdaa937dSCristian Dumitrescu 	if (!m)
2220cdaa937dSCristian Dumitrescu 		return -ENOMEM;
2221cdaa937dSCristian Dumitrescu 
2222cdaa937dSCristian Dumitrescu 	m->member_id = member_id;
2223cdaa937dSCristian Dumitrescu 	m->member_weight = member_weight;
2224cdaa937dSCristian Dumitrescu 
2225cdaa937dSCristian Dumitrescu 	TAILQ_INSERT_TAIL(&group->members, m, node);
2226cdaa937dSCristian Dumitrescu 
2227cdaa937dSCristian Dumitrescu 	return 0;
2228cdaa937dSCristian Dumitrescu }
2229cdaa937dSCristian Dumitrescu 
2230cdaa937dSCristian Dumitrescu int
rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline * ctl,const char * selector_name,uint32_t group_id __rte_unused,uint32_t member_id __rte_unused)2231cdaa937dSCristian Dumitrescu rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
2232cdaa937dSCristian Dumitrescu 						  const char *selector_name,
2233cdaa937dSCristian Dumitrescu 						  uint32_t group_id __rte_unused,
2234cdaa937dSCristian Dumitrescu 						  uint32_t member_id __rte_unused)
2235cdaa937dSCristian Dumitrescu {
2236cdaa937dSCristian Dumitrescu 	struct selector *s;
2237cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_group *group;
2238cdaa937dSCristian Dumitrescu 	struct rte_swx_table_selector_member *m;
2239cdaa937dSCristian Dumitrescu 
2240cdaa937dSCristian Dumitrescu 	/* Check input arguments. */
2241cdaa937dSCristian Dumitrescu 	if (!ctl || !selector_name || !selector_name[0])
2242cdaa937dSCristian Dumitrescu 		return -EINVAL;
2243cdaa937dSCristian Dumitrescu 
2244cdaa937dSCristian Dumitrescu 	s = selector_find(ctl, selector_name);
2245cdaa937dSCristian Dumitrescu 	if (!s ||
2246cdaa937dSCristian Dumitrescu 	    (group_id >= s->info.n_groups_max) ||
2247cdaa937dSCristian Dumitrescu 	    !s->groups_added[group_id] ||
2248cdaa937dSCristian Dumitrescu 	    s->groups_pending_delete[group_id])
2249cdaa937dSCristian Dumitrescu 		return -EINVAL;
2250cdaa937dSCristian Dumitrescu 
2251cdaa937dSCristian Dumitrescu 	/* Initialize the pending group, if needed. */
2252cdaa937dSCristian Dumitrescu 	if (!s->pending_groups[group_id]) {
2253cdaa937dSCristian Dumitrescu 		int status;
2254cdaa937dSCristian Dumitrescu 
2255cdaa937dSCristian Dumitrescu 		status = selector_group_duplicate_to_pending(s, group_id);
2256cdaa937dSCristian Dumitrescu 		if (status)
2257cdaa937dSCristian Dumitrescu 			return status;
2258cdaa937dSCristian Dumitrescu 	}
2259cdaa937dSCristian Dumitrescu 
2260cdaa937dSCristian Dumitrescu 	group = s->pending_groups[group_id];
2261cdaa937dSCristian Dumitrescu 
2262cdaa937dSCristian Dumitrescu 	/* Look for this member in the group and remove it, if found. */
2263cdaa937dSCristian Dumitrescu 	TAILQ_FOREACH(m, &group->members, node)
2264cdaa937dSCristian Dumitrescu 		if (m->member_id == member_id) {
2265cdaa937dSCristian Dumitrescu 			TAILQ_REMOVE(&group->members, m, node);
2266cdaa937dSCristian Dumitrescu 			free(m);
2267cdaa937dSCristian Dumitrescu 			return 0;
2268cdaa937dSCristian Dumitrescu 		}
2269cdaa937dSCristian Dumitrescu 
2270cdaa937dSCristian Dumitrescu 	return 0;
2271cdaa937dSCristian Dumitrescu }
2272cdaa937dSCristian Dumitrescu 
2273cdaa937dSCristian Dumitrescu static int
selector_rollfwd(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2274cdaa937dSCristian Dumitrescu selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2275cdaa937dSCristian Dumitrescu {
2276cdaa937dSCristian Dumitrescu 	struct selector *s = &ctl->selectors[selector_id];
2277cdaa937dSCristian Dumitrescu 	struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2278cdaa937dSCristian Dumitrescu 	uint32_t group_id;
2279cdaa937dSCristian Dumitrescu 
2280cdaa937dSCristian Dumitrescu 	/* Push pending group member changes (s->pending_groups[group_id]) to the selector table
2281cdaa937dSCristian Dumitrescu 	 * mirror copy (ts_next->obj).
2282cdaa937dSCristian Dumitrescu 	 */
2283cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2284cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
2285cdaa937dSCristian Dumitrescu 		int status;
2286cdaa937dSCristian Dumitrescu 
2287cdaa937dSCristian Dumitrescu 		/* Skip this group if no change needed. */
2288cdaa937dSCristian Dumitrescu 		if (!group)
2289cdaa937dSCristian Dumitrescu 			continue;
2290cdaa937dSCristian Dumitrescu 
2291cdaa937dSCristian Dumitrescu 		/* Apply the pending changes for the current group. */
2292cdaa937dSCristian Dumitrescu 		status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
2293cdaa937dSCristian Dumitrescu 		if (status)
2294cdaa937dSCristian Dumitrescu 			return status;
2295cdaa937dSCristian Dumitrescu 	}
2296cdaa937dSCristian Dumitrescu 
2297cdaa937dSCristian Dumitrescu 	return 0;
2298cdaa937dSCristian Dumitrescu }
2299cdaa937dSCristian Dumitrescu 
2300cdaa937dSCristian Dumitrescu static void
selector_rollfwd_finalize(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2301cdaa937dSCristian Dumitrescu selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2302cdaa937dSCristian Dumitrescu {
2303cdaa937dSCristian Dumitrescu 	struct selector *s = &ctl->selectors[selector_id];
2304cdaa937dSCristian Dumitrescu 	uint32_t group_id;
2305cdaa937dSCristian Dumitrescu 
2306cdaa937dSCristian Dumitrescu 	/* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
2307cdaa937dSCristian Dumitrescu 	 * records (s->groups[group_id).
2308cdaa937dSCristian Dumitrescu 	 */
2309cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2310cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_group *g = s->groups[group_id];
2311cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2312cdaa937dSCristian Dumitrescu 
2313cdaa937dSCristian Dumitrescu 		/* Skip this group if no change needed. */
2314cdaa937dSCristian Dumitrescu 		if (!gp)
2315cdaa937dSCristian Dumitrescu 			continue;
2316cdaa937dSCristian Dumitrescu 
2317cdaa937dSCristian Dumitrescu 		/* Transition the pending changes to stable. */
2318cdaa937dSCristian Dumitrescu 		s->groups[group_id] = gp;
2319cdaa937dSCristian Dumitrescu 		s->pending_groups[group_id] = NULL;
2320cdaa937dSCristian Dumitrescu 
2321cdaa937dSCristian Dumitrescu 		/* Free the old group member list. */
2322cdaa937dSCristian Dumitrescu 		if (!g)
2323cdaa937dSCristian Dumitrescu 			continue;
2324cdaa937dSCristian Dumitrescu 
2325cdaa937dSCristian Dumitrescu 		for ( ; ; ) {
2326cdaa937dSCristian Dumitrescu 			struct rte_swx_table_selector_member *m;
2327cdaa937dSCristian Dumitrescu 
2328cdaa937dSCristian Dumitrescu 			m = TAILQ_FIRST(&g->members);
2329cdaa937dSCristian Dumitrescu 			if (!m)
2330cdaa937dSCristian Dumitrescu 				break;
2331cdaa937dSCristian Dumitrescu 
2332cdaa937dSCristian Dumitrescu 			TAILQ_REMOVE(&g->members, m, node);
2333cdaa937dSCristian Dumitrescu 			free(m);
2334cdaa937dSCristian Dumitrescu 		}
2335cdaa937dSCristian Dumitrescu 
2336cdaa937dSCristian Dumitrescu 		free(g);
2337cdaa937dSCristian Dumitrescu 	}
2338cdaa937dSCristian Dumitrescu 
2339cdaa937dSCristian Dumitrescu 	/* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
2340cdaa937dSCristian Dumitrescu 	 * s->groups_added[group_id].
2341cdaa937dSCristian Dumitrescu 	 */
2342cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2343cdaa937dSCristian Dumitrescu 		if (s->groups_pending_delete[group_id]) {
2344cdaa937dSCristian Dumitrescu 			s->groups_added[group_id] = 0;
2345cdaa937dSCristian Dumitrescu 			s->groups_pending_delete[group_id] = 0;
2346cdaa937dSCristian Dumitrescu 		}
2347cdaa937dSCristian Dumitrescu }
2348cdaa937dSCristian Dumitrescu 
2349cdaa937dSCristian Dumitrescu static void
selector_rollback(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2350cdaa937dSCristian Dumitrescu selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2351cdaa937dSCristian Dumitrescu {
2352cdaa937dSCristian Dumitrescu 	struct selector *s = &ctl->selectors[selector_id];
2353cdaa937dSCristian Dumitrescu 	struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
2354cdaa937dSCristian Dumitrescu 	struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
2355cdaa937dSCristian Dumitrescu 	uint32_t group_id;
2356cdaa937dSCristian Dumitrescu 
2357cdaa937dSCristian Dumitrescu 	/* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
2358cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
2359cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
2360cdaa937dSCristian Dumitrescu 
2361cdaa937dSCristian Dumitrescu 		if (gp) {
2362cdaa937dSCristian Dumitrescu 			ts_next->obj = ts->obj;
2363cdaa937dSCristian Dumitrescu 			break;
2364cdaa937dSCristian Dumitrescu 		}
2365cdaa937dSCristian Dumitrescu 	}
2366cdaa937dSCristian Dumitrescu }
2367cdaa937dSCristian Dumitrescu 
2368cdaa937dSCristian Dumitrescu static void
selector_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t selector_id)2369cdaa937dSCristian Dumitrescu selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
2370cdaa937dSCristian Dumitrescu {
2371cdaa937dSCristian Dumitrescu 	struct selector *s = &ctl->selectors[selector_id];
2372cdaa937dSCristian Dumitrescu 	uint32_t group_id;
2373cdaa937dSCristian Dumitrescu 
2374cdaa937dSCristian Dumitrescu 	/* Discard any pending group member changes (s->pending_groups[group_id]). */
2375cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
2376cdaa937dSCristian Dumitrescu 		selector_pending_group_members_free(s, group_id);
2377cdaa937dSCristian Dumitrescu 
2378cdaa937dSCristian Dumitrescu 	/* Discard any pending group deletions. */
2379cdaa937dSCristian Dumitrescu 	memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
2380cdaa937dSCristian Dumitrescu }
2381cdaa937dSCristian Dumitrescu 
23824f59d372SCristian Dumitrescu static struct rte_swx_table_entry *
learner_default_entry_alloc(struct learner * l)23834f59d372SCristian Dumitrescu learner_default_entry_alloc(struct learner *l)
23844f59d372SCristian Dumitrescu {
23854f59d372SCristian Dumitrescu 	struct rte_swx_table_entry *entry;
23864f59d372SCristian Dumitrescu 
23874f59d372SCristian Dumitrescu 	entry = calloc(1, sizeof(struct rte_swx_table_entry));
23884f59d372SCristian Dumitrescu 	if (!entry)
23894f59d372SCristian Dumitrescu 		goto error;
23904f59d372SCristian Dumitrescu 
23914f59d372SCristian Dumitrescu 	/* action_data. */
23924f59d372SCristian Dumitrescu 	if (l->action_data_size) {
23934f59d372SCristian Dumitrescu 		entry->action_data = calloc(1, l->action_data_size);
23944f59d372SCristian Dumitrescu 		if (!entry->action_data)
23954f59d372SCristian Dumitrescu 			goto error;
23964f59d372SCristian Dumitrescu 	}
23974f59d372SCristian Dumitrescu 
23984f59d372SCristian Dumitrescu 	return entry;
23994f59d372SCristian Dumitrescu 
24004f59d372SCristian Dumitrescu error:
24014f59d372SCristian Dumitrescu 	table_entry_free(entry);
24024f59d372SCristian Dumitrescu 	return NULL;
24034f59d372SCristian Dumitrescu }
24044f59d372SCristian Dumitrescu 
24054f59d372SCristian Dumitrescu static int
learner_default_entry_check(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id,struct rte_swx_table_entry * entry)24064f59d372SCristian Dumitrescu learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
24074f59d372SCristian Dumitrescu 			    uint32_t learner_id,
24084f59d372SCristian Dumitrescu 			    struct rte_swx_table_entry *entry)
24094f59d372SCristian Dumitrescu {
24104f59d372SCristian Dumitrescu 	struct learner *l = &ctl->learners[learner_id];
24114f59d372SCristian Dumitrescu 	struct action *a;
24124f59d372SCristian Dumitrescu 	uint32_t i;
24134f59d372SCristian Dumitrescu 
24144f59d372SCristian Dumitrescu 	CHECK(entry, EINVAL);
24154f59d372SCristian Dumitrescu 
24164f59d372SCristian Dumitrescu 	/* action_id. */
24174f59d372SCristian Dumitrescu 	for (i = 0; i < l->info.n_actions; i++)
24184f59d372SCristian Dumitrescu 		if (entry->action_id == l->actions[i].action_id)
24194f59d372SCristian Dumitrescu 			break;
24204f59d372SCristian Dumitrescu 
24214f59d372SCristian Dumitrescu 	CHECK(i < l->info.n_actions, EINVAL);
24224f59d372SCristian Dumitrescu 
24234f59d372SCristian Dumitrescu 	/* action_data. */
24244f59d372SCristian Dumitrescu 	a = &ctl->actions[entry->action_id];
24254f59d372SCristian Dumitrescu 	CHECK(!(a->data_size && !entry->action_data), EINVAL);
24264f59d372SCristian Dumitrescu 
24274f59d372SCristian Dumitrescu 	return 0;
24284f59d372SCristian Dumitrescu }
24294f59d372SCristian Dumitrescu 
24304f59d372SCristian Dumitrescu static struct rte_swx_table_entry *
learner_default_entry_duplicate(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id,struct rte_swx_table_entry * entry)24314f59d372SCristian Dumitrescu learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl,
24324f59d372SCristian Dumitrescu 				uint32_t learner_id,
24334f59d372SCristian Dumitrescu 				struct rte_swx_table_entry *entry)
24344f59d372SCristian Dumitrescu {
24354f59d372SCristian Dumitrescu 	struct learner *l = &ctl->learners[learner_id];
24364f59d372SCristian Dumitrescu 	struct rte_swx_table_entry *new_entry = NULL;
24374f59d372SCristian Dumitrescu 	struct action *a;
24384f59d372SCristian Dumitrescu 	uint32_t i;
24394f59d372SCristian Dumitrescu 
24404f59d372SCristian Dumitrescu 	if (!entry)
24414f59d372SCristian Dumitrescu 		goto error;
24424f59d372SCristian Dumitrescu 
24434f59d372SCristian Dumitrescu 	new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
24444f59d372SCristian Dumitrescu 	if (!new_entry)
24454f59d372SCristian Dumitrescu 		goto error;
24464f59d372SCristian Dumitrescu 
24474f59d372SCristian Dumitrescu 	/* action_id. */
24484f59d372SCristian Dumitrescu 	for (i = 0; i < l->info.n_actions; i++)
24494f59d372SCristian Dumitrescu 		if (entry->action_id == l->actions[i].action_id)
24504f59d372SCristian Dumitrescu 			break;
24514f59d372SCristian Dumitrescu 
24524f59d372SCristian Dumitrescu 	if (i >= l->info.n_actions)
24534f59d372SCristian Dumitrescu 		goto error;
24544f59d372SCristian Dumitrescu 
24554f59d372SCristian Dumitrescu 	new_entry->action_id = entry->action_id;
24564f59d372SCristian Dumitrescu 
24574f59d372SCristian Dumitrescu 	/* action_data. */
24584f59d372SCristian Dumitrescu 	a = &ctl->actions[entry->action_id];
24594f59d372SCristian Dumitrescu 	if (a->data_size && !entry->action_data)
24604f59d372SCristian Dumitrescu 		goto error;
24614f59d372SCristian Dumitrescu 
24624f59d372SCristian Dumitrescu 	/* The table layer provisions a constant action data size per
24634f59d372SCristian Dumitrescu 	 * entry, which should be the largest data size for all the
24644f59d372SCristian Dumitrescu 	 * actions enabled for the current table, and attempts to copy
24654f59d372SCristian Dumitrescu 	 * this many bytes each time a table entry is added, even if the
24664f59d372SCristian Dumitrescu 	 * specific action requires less data or even no data at all,
24674f59d372SCristian Dumitrescu 	 * hence we always have to allocate the max.
24684f59d372SCristian Dumitrescu 	 */
24694f59d372SCristian Dumitrescu 	new_entry->action_data = calloc(1, l->action_data_size);
24704f59d372SCristian Dumitrescu 	if (!new_entry->action_data)
24714f59d372SCristian Dumitrescu 		goto error;
24724f59d372SCristian Dumitrescu 
24734f59d372SCristian Dumitrescu 	if (a->data_size)
24744f59d372SCristian Dumitrescu 		memcpy(new_entry->action_data, entry->action_data, a->data_size);
24754f59d372SCristian Dumitrescu 
24764f59d372SCristian Dumitrescu 	return new_entry;
24774f59d372SCristian Dumitrescu 
24784f59d372SCristian Dumitrescu error:
24794f59d372SCristian Dumitrescu 	table_entry_free(new_entry);
24804f59d372SCristian Dumitrescu 	return NULL;
24814f59d372SCristian Dumitrescu }
24824f59d372SCristian Dumitrescu 
24834f59d372SCristian Dumitrescu int
rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline * ctl,const char * learner_name,struct rte_swx_table_entry * entry)24844f59d372SCristian Dumitrescu rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl,
24854f59d372SCristian Dumitrescu 					       const char *learner_name,
24864f59d372SCristian Dumitrescu 					       struct rte_swx_table_entry *entry)
24874f59d372SCristian Dumitrescu {
24884f59d372SCristian Dumitrescu 	struct learner *l;
24894f59d372SCristian Dumitrescu 	struct rte_swx_table_entry *new_entry;
24904f59d372SCristian Dumitrescu 	uint32_t learner_id;
24914f59d372SCristian Dumitrescu 
24924f59d372SCristian Dumitrescu 	CHECK(ctl, EINVAL);
24934f59d372SCristian Dumitrescu 
24944f59d372SCristian Dumitrescu 	CHECK(learner_name && learner_name[0], EINVAL);
24954f59d372SCristian Dumitrescu 	l = learner_find(ctl, learner_name);
24964f59d372SCristian Dumitrescu 	CHECK(l, EINVAL);
24974f59d372SCristian Dumitrescu 	learner_id = l - ctl->learners;
24984f59d372SCristian Dumitrescu 	CHECK(!l->info.default_action_is_const, EINVAL);
24994f59d372SCristian Dumitrescu 
25004f59d372SCristian Dumitrescu 	CHECK(entry, EINVAL);
25014f59d372SCristian Dumitrescu 	CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
25024f59d372SCristian Dumitrescu 
2503cd79e020SYogesh Jangra 	CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
2504cd79e020SYogesh Jangra 
25054f59d372SCristian Dumitrescu 	new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
25064f59d372SCristian Dumitrescu 	CHECK(new_entry, ENOMEM);
25074f59d372SCristian Dumitrescu 
25084f59d372SCristian Dumitrescu 	learner_pending_default_free(l);
25094f59d372SCristian Dumitrescu 
25104f59d372SCristian Dumitrescu 	l->pending_default = new_entry;
25114f59d372SCristian Dumitrescu 	return 0;
25124f59d372SCristian Dumitrescu }
25134f59d372SCristian Dumitrescu 
25144f59d372SCristian Dumitrescu static void
learner_rollfwd(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)25154f59d372SCristian Dumitrescu learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
25164f59d372SCristian Dumitrescu {
25174f59d372SCristian Dumitrescu 	struct learner *l = &ctl->learners[learner_id];
25184f59d372SCristian Dumitrescu 	struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
25194f59d372SCristian Dumitrescu 		ctl->info.n_selectors + learner_id];
25204f59d372SCristian Dumitrescu 	struct action *a;
25214f59d372SCristian Dumitrescu 	uint8_t *action_data;
25224f59d372SCristian Dumitrescu 	uint64_t action_id;
25234f59d372SCristian Dumitrescu 
25244f59d372SCristian Dumitrescu 	/* Copy the pending default entry. */
25254f59d372SCristian Dumitrescu 	if (!l->pending_default)
25264f59d372SCristian Dumitrescu 		return;
25274f59d372SCristian Dumitrescu 
25284f59d372SCristian Dumitrescu 	action_id = l->pending_default->action_id;
25294f59d372SCristian Dumitrescu 	action_data = l->pending_default->action_data;
25304f59d372SCristian Dumitrescu 	a = &ctl->actions[action_id];
25314f59d372SCristian Dumitrescu 
25324f59d372SCristian Dumitrescu 	if (a->data_size)
25334f59d372SCristian Dumitrescu 		memcpy(ts_next->default_action_data, action_data, a->data_size);
25344f59d372SCristian Dumitrescu 
25354f59d372SCristian Dumitrescu 	ts_next->default_action_id = action_id;
25364f59d372SCristian Dumitrescu }
25374f59d372SCristian Dumitrescu 
25384f59d372SCristian Dumitrescu static void
learner_rollfwd_finalize(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)25394f59d372SCristian Dumitrescu learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
25404f59d372SCristian Dumitrescu {
25414f59d372SCristian Dumitrescu 	struct learner *l = &ctl->learners[learner_id];
25424f59d372SCristian Dumitrescu 
25434f59d372SCristian Dumitrescu 	/* Free up the pending default entry, as it is now part of the table. */
25444f59d372SCristian Dumitrescu 	learner_pending_default_free(l);
25454f59d372SCristian Dumitrescu }
25464f59d372SCristian Dumitrescu 
25474f59d372SCristian Dumitrescu static void
learner_abort(struct rte_swx_ctl_pipeline * ctl,uint32_t learner_id)25484f59d372SCristian Dumitrescu learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
25494f59d372SCristian Dumitrescu {
25504f59d372SCristian Dumitrescu 	struct learner *l = &ctl->learners[learner_id];
25514f59d372SCristian Dumitrescu 
25524f59d372SCristian Dumitrescu 	/* Free up the pending default entry, as it is no longer going to be added to the table. */
25534f59d372SCristian Dumitrescu 	learner_pending_default_free(l);
25544f59d372SCristian Dumitrescu }
25554f59d372SCristian Dumitrescu 
2556cdaa937dSCristian Dumitrescu int
rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline * ctl,int abort_on_fail)255799a2dd95SBruce Richardson rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
255899a2dd95SBruce Richardson {
255999a2dd95SBruce Richardson 	struct rte_swx_table_state *ts;
256099a2dd95SBruce Richardson 	int status = 0;
256199a2dd95SBruce Richardson 	uint32_t i;
256299a2dd95SBruce Richardson 
256399a2dd95SBruce Richardson 	CHECK(ctl, EINVAL);
256499a2dd95SBruce Richardson 
2565cdaa937dSCristian Dumitrescu 	/* Operate the changes on the current ts_next before it becomes the new ts. First, operate
2566cdaa937dSCristian Dumitrescu 	 * all the changes that can fail; if no failure, then operate the changes that cannot fail.
25674f59d372SCristian Dumitrescu 	 * We must be able to fully revert all the changes that can fail as if they never happened.
256899a2dd95SBruce Richardson 	 */
256999a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
257099a2dd95SBruce Richardson 		status = table_rollfwd0(ctl, i, 0);
257199a2dd95SBruce Richardson 		if (status)
257299a2dd95SBruce Richardson 			goto rollback;
257399a2dd95SBruce Richardson 	}
257499a2dd95SBruce Richardson 
2575cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
2576cdaa937dSCristian Dumitrescu 		status = selector_rollfwd(ctl, i);
2577cdaa937dSCristian Dumitrescu 		if (status)
2578cdaa937dSCristian Dumitrescu 			goto rollback;
2579cdaa937dSCristian Dumitrescu 	}
2580cdaa937dSCristian Dumitrescu 
25814f59d372SCristian Dumitrescu 	/* Second, operate all the changes that cannot fail. Since nothing can fail from this point
25824f59d372SCristian Dumitrescu 	 * onwards, the transaction is guaranteed to be successful.
25834f59d372SCristian Dumitrescu 	 */
258499a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++)
258599a2dd95SBruce Richardson 		table_rollfwd1(ctl, i);
258699a2dd95SBruce Richardson 
25874f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++)
25884f59d372SCristian Dumitrescu 		learner_rollfwd(ctl, i);
25894f59d372SCristian Dumitrescu 
259099a2dd95SBruce Richardson 	/* Swap the table state for the data plane. The current ts and ts_next
259199a2dd95SBruce Richardson 	 * become the new ts_next and ts, respectively.
259299a2dd95SBruce Richardson 	 */
259399a2dd95SBruce Richardson 	rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next);
259499a2dd95SBruce Richardson 	usleep(100);
259599a2dd95SBruce Richardson 	ts = ctl->ts;
259699a2dd95SBruce Richardson 	ctl->ts = ctl->ts_next;
259799a2dd95SBruce Richardson 	ctl->ts_next = ts;
259899a2dd95SBruce Richardson 
2599cdaa937dSCristian Dumitrescu 	/* Operate the changes on the current ts_next, which is the previous ts, in order to get
2600cdaa937dSCristian Dumitrescu 	 * the current ts_next in sync with the current ts. Since the changes that can fail did
2601cdaa937dSCristian Dumitrescu 	 * not fail on the previous ts_next, it is guaranteed that they will not fail on the
2602cdaa937dSCristian Dumitrescu 	 * current ts_next, hence no error checking is needed.
260399a2dd95SBruce Richardson 	 */
260499a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
260599a2dd95SBruce Richardson 		table_rollfwd0(ctl, i, 1);
260699a2dd95SBruce Richardson 		table_rollfwd1(ctl, i);
260799a2dd95SBruce Richardson 		table_rollfwd2(ctl, i);
260899a2dd95SBruce Richardson 	}
260999a2dd95SBruce Richardson 
2610cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
2611cdaa937dSCristian Dumitrescu 		selector_rollfwd(ctl, i);
2612cdaa937dSCristian Dumitrescu 		selector_rollfwd_finalize(ctl, i);
2613cdaa937dSCristian Dumitrescu 	}
2614cdaa937dSCristian Dumitrescu 
26154f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++) {
26164f59d372SCristian Dumitrescu 		learner_rollfwd(ctl, i);
26174f59d372SCristian Dumitrescu 		learner_rollfwd_finalize(ctl, i);
26184f59d372SCristian Dumitrescu 	}
26194f59d372SCristian Dumitrescu 
262099a2dd95SBruce Richardson 	return 0;
262199a2dd95SBruce Richardson 
262299a2dd95SBruce Richardson rollback:
262399a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++) {
262499a2dd95SBruce Richardson 		table_rollback(ctl, i);
262599a2dd95SBruce Richardson 		if (abort_on_fail)
262699a2dd95SBruce Richardson 			table_abort(ctl, i);
262799a2dd95SBruce Richardson 	}
262899a2dd95SBruce Richardson 
2629cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++) {
2630cdaa937dSCristian Dumitrescu 		selector_rollback(ctl, i);
2631cdaa937dSCristian Dumitrescu 		if (abort_on_fail)
2632cdaa937dSCristian Dumitrescu 			selector_abort(ctl, i);
2633cdaa937dSCristian Dumitrescu 	}
2634cdaa937dSCristian Dumitrescu 
26354f59d372SCristian Dumitrescu 	if (abort_on_fail)
26364f59d372SCristian Dumitrescu 		for (i = 0; i < ctl->info.n_learners; i++)
26374f59d372SCristian Dumitrescu 			learner_abort(ctl, i);
26384f59d372SCristian Dumitrescu 
263999a2dd95SBruce Richardson 	return status;
264099a2dd95SBruce Richardson }
264199a2dd95SBruce Richardson 
264299a2dd95SBruce Richardson void
rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline * ctl)264399a2dd95SBruce Richardson rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
264499a2dd95SBruce Richardson {
264599a2dd95SBruce Richardson 	uint32_t i;
264699a2dd95SBruce Richardson 
264799a2dd95SBruce Richardson 	if (!ctl)
264899a2dd95SBruce Richardson 		return;
264999a2dd95SBruce Richardson 
265099a2dd95SBruce Richardson 	for (i = 0; i < ctl->info.n_tables; i++)
265199a2dd95SBruce Richardson 		table_abort(ctl, i);
2652cdaa937dSCristian Dumitrescu 
2653cdaa937dSCristian Dumitrescu 	for (i = 0; i < ctl->info.n_selectors; i++)
2654cdaa937dSCristian Dumitrescu 		selector_abort(ctl, i);
26554f59d372SCristian Dumitrescu 
26564f59d372SCristian Dumitrescu 	for (i = 0; i < ctl->info.n_learners; i++)
26574f59d372SCristian Dumitrescu 		learner_abort(ctl, i);
265899a2dd95SBruce Richardson }
265999a2dd95SBruce Richardson 
266099a2dd95SBruce Richardson static int
mask_to_prefix(uint64_t mask,uint32_t mask_length,uint32_t * prefix_length)2661a3ac0a48SCristian Dumitrescu mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length)
2662a3ac0a48SCristian Dumitrescu {
2663a3ac0a48SCristian Dumitrescu 	uint32_t n_trailing_zeros = 0, n_ones = 0, i;
2664a3ac0a48SCristian Dumitrescu 
2665a3ac0a48SCristian Dumitrescu 	if (!mask) {
2666a3ac0a48SCristian Dumitrescu 		*prefix_length = 0;
2667a3ac0a48SCristian Dumitrescu 		return 0;
2668a3ac0a48SCristian Dumitrescu 	}
2669a3ac0a48SCristian Dumitrescu 
2670a3ac0a48SCristian Dumitrescu 	/* Count trailing zero bits. */
2671a3ac0a48SCristian Dumitrescu 	for (i = 0; i < 64; i++) {
2672a3ac0a48SCristian Dumitrescu 		if (mask & (1LLU << i))
2673a3ac0a48SCristian Dumitrescu 			break;
2674a3ac0a48SCristian Dumitrescu 
2675a3ac0a48SCristian Dumitrescu 		n_trailing_zeros++;
2676a3ac0a48SCristian Dumitrescu 	}
2677a3ac0a48SCristian Dumitrescu 
2678a3ac0a48SCristian Dumitrescu 	/* Count the one bits that follow. */
2679a3ac0a48SCristian Dumitrescu 	for ( ; i < 64; i++) {
2680a3ac0a48SCristian Dumitrescu 		if (!(mask & (1LLU << i)))
2681a3ac0a48SCristian Dumitrescu 			break;
2682a3ac0a48SCristian Dumitrescu 
2683a3ac0a48SCristian Dumitrescu 		n_ones++;
2684a3ac0a48SCristian Dumitrescu 	}
2685a3ac0a48SCristian Dumitrescu 
2686a3ac0a48SCristian Dumitrescu 	/* Check that no more one bits are present */
2687a3ac0a48SCristian Dumitrescu 	for ( ; i < 64; i++)
2688a3ac0a48SCristian Dumitrescu 		if (mask & (1LLU << i))
2689a3ac0a48SCristian Dumitrescu 			return -EINVAL;
2690a3ac0a48SCristian Dumitrescu 
2691a3ac0a48SCristian Dumitrescu 	/* Check that the input mask is a prefix or the right length. */
2692a3ac0a48SCristian Dumitrescu 	if (n_ones + n_trailing_zeros != mask_length)
2693a3ac0a48SCristian Dumitrescu 		return -EINVAL;
2694a3ac0a48SCristian Dumitrescu 
2695a3ac0a48SCristian Dumitrescu 	*prefix_length = n_ones;
2696a3ac0a48SCristian Dumitrescu 	return 0;
2697a3ac0a48SCristian Dumitrescu }
2698a3ac0a48SCristian Dumitrescu 
2699a3ac0a48SCristian Dumitrescu static int
large_mask_to_prefix(uint8_t * mask,uint32_t n_mask_bytes,uint32_t * prefix_length)2700103b303dSCristian Dumitrescu large_mask_to_prefix(uint8_t *mask, uint32_t n_mask_bytes, uint32_t *prefix_length)
2701103b303dSCristian Dumitrescu {
2702103b303dSCristian Dumitrescu 	uint32_t pl, i;
2703103b303dSCristian Dumitrescu 
2704103b303dSCristian Dumitrescu 	/* Check input arguments. */
2705103b303dSCristian Dumitrescu 	if (!mask || !n_mask_bytes || !prefix_length)
2706103b303dSCristian Dumitrescu 		return -EINVAL;
2707103b303dSCristian Dumitrescu 
2708103b303dSCristian Dumitrescu 	/* Count leading bits of one. */
2709103b303dSCristian Dumitrescu 	for (i = 0; i < n_mask_bytes * 8; i++) {
2710103b303dSCristian Dumitrescu 		uint32_t byte_id = i / 8;
2711103b303dSCristian Dumitrescu 		uint32_t bit_id = i & 7;
2712103b303dSCristian Dumitrescu 
2713103b303dSCristian Dumitrescu 		uint32_t byte = mask[byte_id];
2714103b303dSCristian Dumitrescu 		uint32_t bit = byte & (1 << (7 - bit_id));
2715103b303dSCristian Dumitrescu 
2716103b303dSCristian Dumitrescu 		if (!bit)
2717103b303dSCristian Dumitrescu 			break;
2718103b303dSCristian Dumitrescu 	}
2719103b303dSCristian Dumitrescu 
2720103b303dSCristian Dumitrescu 	/* Save the potential prefix length. */
2721103b303dSCristian Dumitrescu 	pl = i;
2722103b303dSCristian Dumitrescu 
2723103b303dSCristian Dumitrescu 	/* Check that all remaining bits are zeros. */
2724103b303dSCristian Dumitrescu 	for ( ; i < n_mask_bytes * 8; i++) {
2725103b303dSCristian Dumitrescu 		uint32_t byte_id = i / 8;
2726103b303dSCristian Dumitrescu 		uint32_t bit_id = i & 7;
2727103b303dSCristian Dumitrescu 
2728103b303dSCristian Dumitrescu 		uint32_t byte = mask[byte_id];
2729103b303dSCristian Dumitrescu 		uint32_t bit = byte & (1 << (7 - bit_id));
2730103b303dSCristian Dumitrescu 
2731103b303dSCristian Dumitrescu 		if (bit)
2732103b303dSCristian Dumitrescu 			break;
2733103b303dSCristian Dumitrescu 	}
2734103b303dSCristian Dumitrescu 
2735103b303dSCristian Dumitrescu 	if (i < n_mask_bytes * 8)
2736103b303dSCristian Dumitrescu 		return -EINVAL;
2737103b303dSCristian Dumitrescu 
2738103b303dSCristian Dumitrescu 	*prefix_length = pl;
2739103b303dSCristian Dumitrescu 	return 0;
2740103b303dSCristian Dumitrescu }
2741103b303dSCristian Dumitrescu 
2742103b303dSCristian Dumitrescu static int
char_to_hex(char c,uint8_t * val)2743103b303dSCristian Dumitrescu char_to_hex(char c, uint8_t *val)
2744103b303dSCristian Dumitrescu {
2745103b303dSCristian Dumitrescu 	if (c >= '0' && c <= '9') {
2746103b303dSCristian Dumitrescu 		*val = c - '0';
2747103b303dSCristian Dumitrescu 		return 0;
2748103b303dSCristian Dumitrescu 	}
2749103b303dSCristian Dumitrescu 
2750103b303dSCristian Dumitrescu 	if (c >= 'A' && c <= 'F') {
2751103b303dSCristian Dumitrescu 		*val = c - 'A' + 10;
2752103b303dSCristian Dumitrescu 		return 0;
2753103b303dSCristian Dumitrescu 	}
2754103b303dSCristian Dumitrescu 
2755103b303dSCristian Dumitrescu 	if (c >= 'a' && c <= 'f') {
2756103b303dSCristian Dumitrescu 		*val = c - 'a' + 10;
2757103b303dSCristian Dumitrescu 		return 0;
2758103b303dSCristian Dumitrescu 	}
2759103b303dSCristian Dumitrescu 
2760103b303dSCristian Dumitrescu 	return -EINVAL;
2761103b303dSCristian Dumitrescu }
2762103b303dSCristian Dumitrescu 
2763103b303dSCristian Dumitrescu static int
hex_string_parse(char * src,uint8_t * dst,uint32_t n_dst_bytes)2764103b303dSCristian Dumitrescu hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
2765103b303dSCristian Dumitrescu {
2766103b303dSCristian Dumitrescu 	uint32_t i;
2767103b303dSCristian Dumitrescu 
2768103b303dSCristian Dumitrescu 	/* Check input arguments. */
2769103b303dSCristian Dumitrescu 	if (!src || !src[0] || !dst || !n_dst_bytes)
2770103b303dSCristian Dumitrescu 		return -EINVAL;
2771103b303dSCristian Dumitrescu 
2772103b303dSCristian Dumitrescu 	/* Skip any leading "0x" or "0X" in the src string. */
2773103b303dSCristian Dumitrescu 	if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
2774103b303dSCristian Dumitrescu 		src += 2;
2775103b303dSCristian Dumitrescu 
2776103b303dSCristian Dumitrescu 	/* Convert each group of two hex characters in the src string to one byte in dst array. */
2777103b303dSCristian Dumitrescu 	for (i = 0; i < n_dst_bytes; i++) {
2778103b303dSCristian Dumitrescu 		uint8_t a, b;
2779103b303dSCristian Dumitrescu 		int status;
2780103b303dSCristian Dumitrescu 
2781103b303dSCristian Dumitrescu 		status = char_to_hex(*src, &a);
2782103b303dSCristian Dumitrescu 		if (status)
2783103b303dSCristian Dumitrescu 			return status;
2784103b303dSCristian Dumitrescu 		src++;
2785103b303dSCristian Dumitrescu 
2786103b303dSCristian Dumitrescu 		status = char_to_hex(*src, &b);
2787103b303dSCristian Dumitrescu 		if (status)
2788103b303dSCristian Dumitrescu 			return status;
2789103b303dSCristian Dumitrescu 		src++;
2790103b303dSCristian Dumitrescu 
2791103b303dSCristian Dumitrescu 		dst[i] = a * 16 + b;
2792103b303dSCristian Dumitrescu 	}
2793103b303dSCristian Dumitrescu 
2794103b303dSCristian Dumitrescu 	/* Check for the end of the src string. */
2795103b303dSCristian Dumitrescu 	if (*src)
2796103b303dSCristian Dumitrescu 		return -EINVAL;
2797103b303dSCristian Dumitrescu 
2798103b303dSCristian Dumitrescu 	return 0;
2799103b303dSCristian Dumitrescu }
2800103b303dSCristian Dumitrescu 
2801103b303dSCristian Dumitrescu static int
table_entry_match_field_read(struct table * table,struct rte_swx_table_entry * entry,uint32_t mf_id,char * mf_val,char * mf_mask,int * lpm,uint32_t * lpm_prefix_length_max,uint32_t * lpm_prefix_length)2802103b303dSCristian Dumitrescu table_entry_match_field_read(struct table *table,
2803103b303dSCristian Dumitrescu 			     struct rte_swx_table_entry *entry,
2804103b303dSCristian Dumitrescu 			     uint32_t mf_id,
2805103b303dSCristian Dumitrescu 			     char *mf_val,
2806103b303dSCristian Dumitrescu 			     char *mf_mask,
2807103b303dSCristian Dumitrescu 			     int *lpm,
2808103b303dSCristian Dumitrescu 			     uint32_t *lpm_prefix_length_max,
2809103b303dSCristian Dumitrescu 			     uint32_t *lpm_prefix_length)
2810103b303dSCristian Dumitrescu {
2811103b303dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2812103b303dSCristian Dumitrescu 	uint64_t val, mask = UINT64_MAX;
2813103b303dSCristian Dumitrescu 	uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2814103b303dSCristian Dumitrescu 
2815103b303dSCristian Dumitrescu 	/*
2816103b303dSCristian Dumitrescu 	 * Mask.
2817103b303dSCristian Dumitrescu 	 */
2818103b303dSCristian Dumitrescu 	if (mf_mask) {
2819103b303dSCristian Dumitrescu 		/* Parse. */
2820103b303dSCristian Dumitrescu 		mask = strtoull(mf_mask, &mf_mask, 0);
2821103b303dSCristian Dumitrescu 		if (mf_mask[0])
2822103b303dSCristian Dumitrescu 			return -EINVAL;
2823103b303dSCristian Dumitrescu 
2824103b303dSCristian Dumitrescu 		/* LPM. */
2825103b303dSCristian Dumitrescu 		if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2826103b303dSCristian Dumitrescu 			int status;
2827103b303dSCristian Dumitrescu 
2828103b303dSCristian Dumitrescu 			*lpm = 1;
2829103b303dSCristian Dumitrescu 
2830103b303dSCristian Dumitrescu 			*lpm_prefix_length_max = mf->n_bits;
2831103b303dSCristian Dumitrescu 
2832103b303dSCristian Dumitrescu 			status = mask_to_prefix(mask, mf->n_bits, lpm_prefix_length);
2833103b303dSCristian Dumitrescu 			if (status)
2834103b303dSCristian Dumitrescu 				return status;
2835103b303dSCristian Dumitrescu 		}
2836103b303dSCristian Dumitrescu 
2837103b303dSCristian Dumitrescu 		/* Endianness conversion. */
2838103b303dSCristian Dumitrescu 		if (mf->is_header)
2839103b303dSCristian Dumitrescu 			mask = field_hton(mask, mf->n_bits);
2840103b303dSCristian Dumitrescu 	}
2841103b303dSCristian Dumitrescu 
2842103b303dSCristian Dumitrescu 	/* Copy to entry. */
2843103b303dSCristian Dumitrescu 	if (entry->key_mask)
2844103b303dSCristian Dumitrescu 		memcpy(&entry->key_mask[offset], (uint8_t *)&mask, mf->n_bits / 8);
2845103b303dSCristian Dumitrescu 
2846103b303dSCristian Dumitrescu 	/*
2847103b303dSCristian Dumitrescu 	 * Value.
2848103b303dSCristian Dumitrescu 	 */
2849103b303dSCristian Dumitrescu 	/* Parse. */
2850103b303dSCristian Dumitrescu 	val = strtoull(mf_val, &mf_val, 0);
2851103b303dSCristian Dumitrescu 	if (mf_val[0])
2852103b303dSCristian Dumitrescu 		return -EINVAL;
2853103b303dSCristian Dumitrescu 
2854103b303dSCristian Dumitrescu 	/* Endianness conversion. */
2855103b303dSCristian Dumitrescu 	if (mf->is_header)
2856103b303dSCristian Dumitrescu 		val = field_hton(val, mf->n_bits);
2857103b303dSCristian Dumitrescu 
2858103b303dSCristian Dumitrescu 	/* Copy to entry. */
2859103b303dSCristian Dumitrescu 	memcpy(&entry->key[offset], (uint8_t *)&val, mf->n_bits / 8);
2860103b303dSCristian Dumitrescu 
2861103b303dSCristian Dumitrescu 	return 0;
2862103b303dSCristian Dumitrescu }
2863103b303dSCristian Dumitrescu 
2864103b303dSCristian Dumitrescu static int
table_entry_action_argument_read(struct action * action,struct rte_swx_table_entry * entry,uint32_t arg_id,uint32_t arg_offset,char * arg_val)2865103b303dSCristian Dumitrescu table_entry_action_argument_read(struct action *action,
2866103b303dSCristian Dumitrescu 				 struct rte_swx_table_entry *entry,
2867103b303dSCristian Dumitrescu 				 uint32_t arg_id,
2868103b303dSCristian Dumitrescu 				 uint32_t arg_offset,
2869103b303dSCristian Dumitrescu 				 char *arg_val)
2870103b303dSCristian Dumitrescu {
2871103b303dSCristian Dumitrescu 	struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2872103b303dSCristian Dumitrescu 	uint64_t val;
2873103b303dSCristian Dumitrescu 
2874103b303dSCristian Dumitrescu 	val = strtoull(arg_val, &arg_val, 0);
2875103b303dSCristian Dumitrescu 	if (arg_val[0])
2876103b303dSCristian Dumitrescu 		return -EINVAL;
2877103b303dSCristian Dumitrescu 
2878103b303dSCristian Dumitrescu 	/* Endianness conversion. */
2879103b303dSCristian Dumitrescu 	if (arg->is_network_byte_order)
2880103b303dSCristian Dumitrescu 		val = field_hton(val, arg->n_bits);
2881103b303dSCristian Dumitrescu 
2882103b303dSCristian Dumitrescu 	/* Copy to entry. */
2883103b303dSCristian Dumitrescu 	memcpy(&entry->action_data[arg_offset],
2884103b303dSCristian Dumitrescu 	       (uint8_t *)&val,
2885103b303dSCristian Dumitrescu 	       arg->n_bits / 8);
2886103b303dSCristian Dumitrescu 
2887103b303dSCristian Dumitrescu 	return 0;
2888103b303dSCristian Dumitrescu }
2889103b303dSCristian Dumitrescu 
2890103b303dSCristian Dumitrescu static int
table_entry_large_match_field_read(struct table * table,struct rte_swx_table_entry * entry,uint32_t mf_id,char * mf_val,char * mf_mask,int * lpm,uint32_t * lpm_prefix_length_max,uint32_t * lpm_prefix_length)2891103b303dSCristian Dumitrescu table_entry_large_match_field_read(struct table *table,
2892103b303dSCristian Dumitrescu 				   struct rte_swx_table_entry *entry,
2893103b303dSCristian Dumitrescu 				   uint32_t mf_id,
2894103b303dSCristian Dumitrescu 				   char *mf_val,
2895103b303dSCristian Dumitrescu 				   char *mf_mask,
2896103b303dSCristian Dumitrescu 				   int *lpm,
2897103b303dSCristian Dumitrescu 				   uint32_t *lpm_prefix_length_max,
2898103b303dSCristian Dumitrescu 				   uint32_t *lpm_prefix_length)
2899103b303dSCristian Dumitrescu {
2900103b303dSCristian Dumitrescu 	struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id];
2901103b303dSCristian Dumitrescu 	uint32_t offset = (mf->offset - table->mf_first->offset) / 8;
2902103b303dSCristian Dumitrescu 	int status;
2903103b303dSCristian Dumitrescu 
2904103b303dSCristian Dumitrescu 	/*
2905103b303dSCristian Dumitrescu 	 * Mask.
2906103b303dSCristian Dumitrescu 	 */
2907103b303dSCristian Dumitrescu 	if (!entry->key_mask)
2908103b303dSCristian Dumitrescu 		goto value;
2909103b303dSCristian Dumitrescu 
2910103b303dSCristian Dumitrescu 	if (!mf_mask) {
2911103b303dSCristian Dumitrescu 		/* Set mask to all-ones. */
2912103b303dSCristian Dumitrescu 		memset(&entry->key_mask[offset], 0xFF, mf->n_bits / 8);
2913103b303dSCristian Dumitrescu 		goto value;
2914103b303dSCristian Dumitrescu 	}
2915103b303dSCristian Dumitrescu 
2916103b303dSCristian Dumitrescu 	/* Parse. */
2917103b303dSCristian Dumitrescu 	status = hex_string_parse(mf_mask, &entry->key_mask[offset], mf->n_bits / 8);
2918103b303dSCristian Dumitrescu 	if (status)
2919103b303dSCristian Dumitrescu 		return -EINVAL;
2920103b303dSCristian Dumitrescu 
2921103b303dSCristian Dumitrescu 	/* LPM. */
2922103b303dSCristian Dumitrescu 	if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) {
2923103b303dSCristian Dumitrescu 		*lpm = 1;
2924103b303dSCristian Dumitrescu 
2925103b303dSCristian Dumitrescu 		*lpm_prefix_length_max = mf->n_bits;
2926103b303dSCristian Dumitrescu 
2927103b303dSCristian Dumitrescu 		status = large_mask_to_prefix(&entry->key_mask[offset],
2928103b303dSCristian Dumitrescu 					      mf->n_bits / 8,
2929103b303dSCristian Dumitrescu 					      lpm_prefix_length);
2930103b303dSCristian Dumitrescu 		if (status)
2931103b303dSCristian Dumitrescu 			return status;
2932103b303dSCristian Dumitrescu 	}
2933103b303dSCristian Dumitrescu 
2934103b303dSCristian Dumitrescu 	/*
2935103b303dSCristian Dumitrescu 	 * Value.
2936103b303dSCristian Dumitrescu 	 */
2937103b303dSCristian Dumitrescu value:
2938103b303dSCristian Dumitrescu 	/* Parse. */
2939103b303dSCristian Dumitrescu 	status = hex_string_parse(mf_val, &entry->key[offset], mf->n_bits / 8);
2940103b303dSCristian Dumitrescu 	if (status)
2941103b303dSCristian Dumitrescu 		return -EINVAL;
2942103b303dSCristian Dumitrescu 
2943103b303dSCristian Dumitrescu 	return 0;
2944103b303dSCristian Dumitrescu }
2945103b303dSCristian Dumitrescu 
2946103b303dSCristian Dumitrescu static int
table_entry_large_action_argument_read(struct action * action,struct rte_swx_table_entry * entry,uint32_t arg_id,uint32_t arg_offset,char * arg_val)2947103b303dSCristian Dumitrescu table_entry_large_action_argument_read(struct action *action,
2948103b303dSCristian Dumitrescu 				       struct rte_swx_table_entry *entry,
2949103b303dSCristian Dumitrescu 				       uint32_t arg_id,
2950103b303dSCristian Dumitrescu 				       uint32_t arg_offset,
2951103b303dSCristian Dumitrescu 				       char *arg_val)
2952103b303dSCristian Dumitrescu {
2953103b303dSCristian Dumitrescu 	struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id];
2954103b303dSCristian Dumitrescu 	int status;
2955103b303dSCristian Dumitrescu 
2956103b303dSCristian Dumitrescu 	status = hex_string_parse(arg_val, &entry->action_data[arg_offset], arg->n_bits / 8);
2957103b303dSCristian Dumitrescu 	if (status)
2958103b303dSCristian Dumitrescu 		return -EINVAL;
2959103b303dSCristian Dumitrescu 
2960103b303dSCristian Dumitrescu 	return 0;
2961103b303dSCristian Dumitrescu }
2962103b303dSCristian Dumitrescu 
2963103b303dSCristian Dumitrescu static int
token_is_comment(const char * token)296499a2dd95SBruce Richardson token_is_comment(const char *token)
296599a2dd95SBruce Richardson {
296699a2dd95SBruce Richardson 	if ((token[0] == '#') ||
296799a2dd95SBruce Richardson 	    (token[0] == ';') ||
296899a2dd95SBruce Richardson 	    ((token[0] == '/') && (token[1] == '/')))
296999a2dd95SBruce Richardson 		return 1; /* TRUE. */
297099a2dd95SBruce Richardson 
297199a2dd95SBruce Richardson 	return 0; /* FALSE. */
297299a2dd95SBruce Richardson }
297399a2dd95SBruce Richardson 
297499a2dd95SBruce Richardson #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256
297599a2dd95SBruce Richardson 
297699a2dd95SBruce Richardson struct rte_swx_table_entry *
rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline * ctl,const char * table_name,const char * string,int * is_blank_or_comment)297799a2dd95SBruce Richardson rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
297899a2dd95SBruce Richardson 				      const char *table_name,
297999a2dd95SBruce Richardson 				      const char *string,
298099a2dd95SBruce Richardson 				      int *is_blank_or_comment)
298199a2dd95SBruce Richardson {
298299a2dd95SBruce Richardson 	char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
298399a2dd95SBruce Richardson 	struct table *table;
298499a2dd95SBruce Richardson 	struct action *action;
298599a2dd95SBruce Richardson 	struct rte_swx_table_entry *entry = NULL;
298699a2dd95SBruce Richardson 	char *s0 = NULL, *s;
2987a3ac0a48SCristian Dumitrescu 	uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i;
2988a3ac0a48SCristian Dumitrescu 	int lpm = 0, blank_or_comment = 0;
298999a2dd95SBruce Richardson 
299099a2dd95SBruce Richardson 	/* Check input arguments. */
299199a2dd95SBruce Richardson 	if (!ctl)
299299a2dd95SBruce Richardson 		goto error;
299399a2dd95SBruce Richardson 
299499a2dd95SBruce Richardson 	if (!table_name || !table_name[0])
299599a2dd95SBruce Richardson 		goto error;
299699a2dd95SBruce Richardson 
299799a2dd95SBruce Richardson 	table = table_find(ctl, table_name);
299899a2dd95SBruce Richardson 	if (!table)
299999a2dd95SBruce Richardson 		goto error;
300099a2dd95SBruce Richardson 
300199a2dd95SBruce Richardson 	if (!string || !string[0])
300299a2dd95SBruce Richardson 		goto error;
300399a2dd95SBruce Richardson 
300499a2dd95SBruce Richardson 	/* Memory allocation. */
300599a2dd95SBruce Richardson 	s0 = strdup(string);
300699a2dd95SBruce Richardson 	if (!s0)
300799a2dd95SBruce Richardson 		goto error;
300899a2dd95SBruce Richardson 
300999a2dd95SBruce Richardson 	entry = table_entry_alloc(table);
301099a2dd95SBruce Richardson 	if (!entry)
301199a2dd95SBruce Richardson 		goto error;
301299a2dd95SBruce Richardson 
301399a2dd95SBruce Richardson 	/* Parse the string into tokens. */
301499a2dd95SBruce Richardson 	for (s = s0; ; ) {
301599a2dd95SBruce Richardson 		char *token;
301699a2dd95SBruce Richardson 
301799a2dd95SBruce Richardson 		token = strtok_r(s, " \f\n\r\t\v", &s);
301899a2dd95SBruce Richardson 		if (!token || token_is_comment(token))
301999a2dd95SBruce Richardson 			break;
302099a2dd95SBruce Richardson 
302199a2dd95SBruce Richardson 		if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
302299a2dd95SBruce Richardson 			goto error;
302399a2dd95SBruce Richardson 
302499a2dd95SBruce Richardson 		token_array[n_tokens] = token;
302599a2dd95SBruce Richardson 		n_tokens++;
302699a2dd95SBruce Richardson 	}
302799a2dd95SBruce Richardson 
302899a2dd95SBruce Richardson 	if (!n_tokens) {
302999a2dd95SBruce Richardson 		blank_or_comment = 1;
303099a2dd95SBruce Richardson 		goto error;
303199a2dd95SBruce Richardson 	}
303299a2dd95SBruce Richardson 
303399a2dd95SBruce Richardson 	tokens = token_array;
303499a2dd95SBruce Richardson 
303599a2dd95SBruce Richardson 	/*
303699a2dd95SBruce Richardson 	 * Match.
303799a2dd95SBruce Richardson 	 */
3038a57d92d7SCristian Dumitrescu 	if (!(n_tokens && !strcmp(tokens[0], "match")))
303999a2dd95SBruce Richardson 		goto action;
304099a2dd95SBruce Richardson 
304199a2dd95SBruce Richardson 	if (n_tokens < 1 + table->info.n_match_fields)
304299a2dd95SBruce Richardson 		goto error;
304399a2dd95SBruce Richardson 
304499a2dd95SBruce Richardson 	for (i = 0; i < table->info.n_match_fields; i++) {
304599a2dd95SBruce Richardson 		struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i];
304699a2dd95SBruce Richardson 		char *mf_val = tokens[1 + i], *mf_mask = NULL;
3047103b303dSCristian Dumitrescu 		int status;
304899a2dd95SBruce Richardson 
304999a2dd95SBruce Richardson 		mf_mask = strchr(mf_val, '/');
305099a2dd95SBruce Richardson 		if (mf_mask) {
305199a2dd95SBruce Richardson 			*mf_mask = 0;
305299a2dd95SBruce Richardson 			mf_mask++;
3053103b303dSCristian Dumitrescu 		}
305499a2dd95SBruce Richardson 
3055103b303dSCristian Dumitrescu 		if (mf->n_bits <= 64)
3056103b303dSCristian Dumitrescu 			status = table_entry_match_field_read(table,
3057103b303dSCristian Dumitrescu 							      entry,
3058103b303dSCristian Dumitrescu 							      i,
3059103b303dSCristian Dumitrescu 							      mf_val,
3060103b303dSCristian Dumitrescu 							      mf_mask,
3061103b303dSCristian Dumitrescu 							      &lpm,
3062103b303dSCristian Dumitrescu 							      &lpm_prefix_length_max,
3063103b303dSCristian Dumitrescu 							      &lpm_prefix_length);
3064103b303dSCristian Dumitrescu 		else
3065103b303dSCristian Dumitrescu 			status = table_entry_large_match_field_read(table,
3066103b303dSCristian Dumitrescu 								    entry,
3067103b303dSCristian Dumitrescu 								    i,
3068103b303dSCristian Dumitrescu 								    mf_val,
3069103b303dSCristian Dumitrescu 								    mf_mask,
3070103b303dSCristian Dumitrescu 								    &lpm,
3071103b303dSCristian Dumitrescu 								    &lpm_prefix_length_max,
3072103b303dSCristian Dumitrescu 								    &lpm_prefix_length);
3073a3ac0a48SCristian Dumitrescu 		if (status)
3074a3ac0a48SCristian Dumitrescu 			goto error;
3075a3ac0a48SCristian Dumitrescu 
307699a2dd95SBruce Richardson 	}
307799a2dd95SBruce Richardson 
307899a2dd95SBruce Richardson 	tokens += 1 + table->info.n_match_fields;
307999a2dd95SBruce Richardson 	n_tokens -= 1 + table->info.n_match_fields;
308099a2dd95SBruce Richardson 
308199a2dd95SBruce Richardson 	/*
308299a2dd95SBruce Richardson 	 * Match priority.
308399a2dd95SBruce Richardson 	 */
308499a2dd95SBruce Richardson 	if (n_tokens && !strcmp(tokens[0], "priority")) {
308599a2dd95SBruce Richardson 		char *priority = tokens[1];
308699a2dd95SBruce Richardson 		uint32_t val;
308799a2dd95SBruce Richardson 
308899a2dd95SBruce Richardson 		if (n_tokens < 2)
308999a2dd95SBruce Richardson 			goto error;
309099a2dd95SBruce Richardson 
309199a2dd95SBruce Richardson 		/* Parse. */
309299a2dd95SBruce Richardson 		val = strtoul(priority, &priority, 0);
309399a2dd95SBruce Richardson 		if (priority[0])
309499a2dd95SBruce Richardson 			goto error;
309599a2dd95SBruce Richardson 
309699a2dd95SBruce Richardson 		/* Copy to entry. */
309799a2dd95SBruce Richardson 		entry->key_priority = val;
309899a2dd95SBruce Richardson 
309999a2dd95SBruce Richardson 		tokens += 2;
310099a2dd95SBruce Richardson 		n_tokens -= 2;
310199a2dd95SBruce Richardson 	}
310299a2dd95SBruce Richardson 
3103a3ac0a48SCristian Dumitrescu 	/* LPM. */
3104a3ac0a48SCristian Dumitrescu 	if (lpm)
3105a3ac0a48SCristian Dumitrescu 		entry->key_priority = lpm_prefix_length_max - lpm_prefix_length;
3106a3ac0a48SCristian Dumitrescu 
310799a2dd95SBruce Richardson 	/*
310899a2dd95SBruce Richardson 	 * Action.
310999a2dd95SBruce Richardson 	 */
311099a2dd95SBruce Richardson action:
3111a57d92d7SCristian Dumitrescu 	if (!(n_tokens && !strcmp(tokens[0], "action")))
311299a2dd95SBruce Richardson 		goto other;
311399a2dd95SBruce Richardson 
311499a2dd95SBruce Richardson 	if (n_tokens < 2)
311599a2dd95SBruce Richardson 		goto error;
311699a2dd95SBruce Richardson 
311799a2dd95SBruce Richardson 	action = action_find(ctl, tokens[1]);
311899a2dd95SBruce Richardson 	if (!action)
311999a2dd95SBruce Richardson 		goto error;
312099a2dd95SBruce Richardson 
312199a2dd95SBruce Richardson 	if (n_tokens < 2 + action->info.n_args * 2)
312299a2dd95SBruce Richardson 		goto error;
312399a2dd95SBruce Richardson 
312499a2dd95SBruce Richardson 	/* action_id. */
312599a2dd95SBruce Richardson 	entry->action_id = action - ctl->actions;
312699a2dd95SBruce Richardson 
312799a2dd95SBruce Richardson 	/* action_data. */
312899a2dd95SBruce Richardson 	for (i = 0; i < action->info.n_args; i++) {
312999a2dd95SBruce Richardson 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
313099a2dd95SBruce Richardson 		char *arg_name, *arg_val;
3131103b303dSCristian Dumitrescu 		int status;
313299a2dd95SBruce Richardson 
313399a2dd95SBruce Richardson 		arg_name = tokens[2 + i * 2];
313499a2dd95SBruce Richardson 		arg_val = tokens[2 + i * 2 + 1];
313599a2dd95SBruce Richardson 
313699a2dd95SBruce Richardson 		if (strcmp(arg_name, arg->name))
313799a2dd95SBruce Richardson 			goto error;
313899a2dd95SBruce Richardson 
3139103b303dSCristian Dumitrescu 		if (arg->n_bits <= 64)
3140103b303dSCristian Dumitrescu 			status = table_entry_action_argument_read(action,
3141103b303dSCristian Dumitrescu 								  entry,
3142103b303dSCristian Dumitrescu 								  i,
3143103b303dSCristian Dumitrescu 								  arg_offset,
3144103b303dSCristian Dumitrescu 								  arg_val);
3145103b303dSCristian Dumitrescu 		else
3146103b303dSCristian Dumitrescu 			status = table_entry_large_action_argument_read(action,
3147103b303dSCristian Dumitrescu 									entry,
3148103b303dSCristian Dumitrescu 									i,
3149103b303dSCristian Dumitrescu 									arg_offset,
3150103b303dSCristian Dumitrescu 									arg_val);
3151103b303dSCristian Dumitrescu 		if (status)
315299a2dd95SBruce Richardson 			goto error;
315399a2dd95SBruce Richardson 
315499a2dd95SBruce Richardson 		arg_offset += arg->n_bits / 8;
315599a2dd95SBruce Richardson 	}
315699a2dd95SBruce Richardson 
315799a2dd95SBruce Richardson 	tokens += 2 + action->info.n_args * 2;
315899a2dd95SBruce Richardson 	n_tokens -= 2 + action->info.n_args * 2;
315999a2dd95SBruce Richardson 
316099a2dd95SBruce Richardson other:
316199a2dd95SBruce Richardson 	if (n_tokens)
316299a2dd95SBruce Richardson 		goto error;
316399a2dd95SBruce Richardson 
316499a2dd95SBruce Richardson 	free(s0);
316599a2dd95SBruce Richardson 	return entry;
316699a2dd95SBruce Richardson 
316799a2dd95SBruce Richardson error:
316899a2dd95SBruce Richardson 	table_entry_free(entry);
316999a2dd95SBruce Richardson 	free(s0);
317099a2dd95SBruce Richardson 	if (is_blank_or_comment)
317199a2dd95SBruce Richardson 		*is_blank_or_comment = blank_or_comment;
317299a2dd95SBruce Richardson 	return NULL;
317399a2dd95SBruce Richardson }
317499a2dd95SBruce Richardson 
31754f59d372SCristian Dumitrescu struct rte_swx_table_entry *
rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline * ctl,const char * learner_name,const char * string,int * is_blank_or_comment)31764f59d372SCristian Dumitrescu rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl,
31774f59d372SCristian Dumitrescu 						const char *learner_name,
31784f59d372SCristian Dumitrescu 						const char *string,
31794f59d372SCristian Dumitrescu 						int *is_blank_or_comment)
31804f59d372SCristian Dumitrescu {
31814f59d372SCristian Dumitrescu 	char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
31824f59d372SCristian Dumitrescu 	struct learner *l;
31834f59d372SCristian Dumitrescu 	struct action *action;
31844f59d372SCristian Dumitrescu 	struct rte_swx_table_entry *entry = NULL;
31854f59d372SCristian Dumitrescu 	char *s0 = NULL, *s;
31864f59d372SCristian Dumitrescu 	uint32_t n_tokens = 0, arg_offset = 0, i;
31874f59d372SCristian Dumitrescu 	int blank_or_comment = 0;
31884f59d372SCristian Dumitrescu 
31894f59d372SCristian Dumitrescu 	/* Check input arguments. */
31904f59d372SCristian Dumitrescu 	if (!ctl)
31914f59d372SCristian Dumitrescu 		goto error;
31924f59d372SCristian Dumitrescu 
31934f59d372SCristian Dumitrescu 	if (!learner_name || !learner_name[0])
31944f59d372SCristian Dumitrescu 		goto error;
31954f59d372SCristian Dumitrescu 
31964f59d372SCristian Dumitrescu 	l = learner_find(ctl, learner_name);
31974f59d372SCristian Dumitrescu 	if (!l)
31984f59d372SCristian Dumitrescu 		goto error;
31994f59d372SCristian Dumitrescu 
32004f59d372SCristian Dumitrescu 	if (!string || !string[0])
32014f59d372SCristian Dumitrescu 		goto error;
32024f59d372SCristian Dumitrescu 
32034f59d372SCristian Dumitrescu 	/* Memory allocation. */
32044f59d372SCristian Dumitrescu 	s0 = strdup(string);
32054f59d372SCristian Dumitrescu 	if (!s0)
32064f59d372SCristian Dumitrescu 		goto error;
32074f59d372SCristian Dumitrescu 
32084f59d372SCristian Dumitrescu 	entry = learner_default_entry_alloc(l);
32094f59d372SCristian Dumitrescu 	if (!entry)
32104f59d372SCristian Dumitrescu 		goto error;
32114f59d372SCristian Dumitrescu 
32124f59d372SCristian Dumitrescu 	/* Parse the string into tokens. */
32134f59d372SCristian Dumitrescu 	for (s = s0; ; ) {
32144f59d372SCristian Dumitrescu 		char *token;
32154f59d372SCristian Dumitrescu 
32164f59d372SCristian Dumitrescu 		token = strtok_r(s, " \f\n\r\t\v", &s);
32174f59d372SCristian Dumitrescu 		if (!token || token_is_comment(token))
32184f59d372SCristian Dumitrescu 			break;
32194f59d372SCristian Dumitrescu 
32204f59d372SCristian Dumitrescu 		if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
32214f59d372SCristian Dumitrescu 			goto error;
32224f59d372SCristian Dumitrescu 
32234f59d372SCristian Dumitrescu 		token_array[n_tokens] = token;
32244f59d372SCristian Dumitrescu 		n_tokens++;
32254f59d372SCristian Dumitrescu 	}
32264f59d372SCristian Dumitrescu 
32274f59d372SCristian Dumitrescu 	if (!n_tokens) {
32284f59d372SCristian Dumitrescu 		blank_or_comment = 1;
32294f59d372SCristian Dumitrescu 		goto error;
32304f59d372SCristian Dumitrescu 	}
32314f59d372SCristian Dumitrescu 
32324f59d372SCristian Dumitrescu 	tokens = token_array;
32334f59d372SCristian Dumitrescu 
32344f59d372SCristian Dumitrescu 	/*
32354f59d372SCristian Dumitrescu 	 * Action.
32364f59d372SCristian Dumitrescu 	 */
32374f59d372SCristian Dumitrescu 	if (!(n_tokens && !strcmp(tokens[0], "action")))
32384f59d372SCristian Dumitrescu 		goto other;
32394f59d372SCristian Dumitrescu 
32404f59d372SCristian Dumitrescu 	if (n_tokens < 2)
32414f59d372SCristian Dumitrescu 		goto error;
32424f59d372SCristian Dumitrescu 
32434f59d372SCristian Dumitrescu 	action = action_find(ctl, tokens[1]);
32444f59d372SCristian Dumitrescu 	if (!action)
32454f59d372SCristian Dumitrescu 		goto error;
32464f59d372SCristian Dumitrescu 
32474f59d372SCristian Dumitrescu 	if (n_tokens < 2 + action->info.n_args * 2)
32484f59d372SCristian Dumitrescu 		goto error;
32494f59d372SCristian Dumitrescu 
32504f59d372SCristian Dumitrescu 	/* action_id. */
32514f59d372SCristian Dumitrescu 	entry->action_id = action - ctl->actions;
32524f59d372SCristian Dumitrescu 
32534f59d372SCristian Dumitrescu 	/* action_data. */
32544f59d372SCristian Dumitrescu 	for (i = 0; i < action->info.n_args; i++) {
32554f59d372SCristian Dumitrescu 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
32564f59d372SCristian Dumitrescu 		char *arg_name, *arg_val;
32574f59d372SCristian Dumitrescu 		uint64_t val;
32584f59d372SCristian Dumitrescu 
32594f59d372SCristian Dumitrescu 		arg_name = tokens[2 + i * 2];
32604f59d372SCristian Dumitrescu 		arg_val = tokens[2 + i * 2 + 1];
32614f59d372SCristian Dumitrescu 
32624f59d372SCristian Dumitrescu 		if (strcmp(arg_name, arg->name))
32634f59d372SCristian Dumitrescu 			goto error;
32644f59d372SCristian Dumitrescu 
32654f59d372SCristian Dumitrescu 		val = strtoull(arg_val, &arg_val, 0);
32664f59d372SCristian Dumitrescu 		if (arg_val[0])
32674f59d372SCristian Dumitrescu 			goto error;
32684f59d372SCristian Dumitrescu 
32694f59d372SCristian Dumitrescu 		/* Endianness conversion. */
32704f59d372SCristian Dumitrescu 		if (arg->is_network_byte_order)
32714f59d372SCristian Dumitrescu 			val = field_hton(val, arg->n_bits);
32724f59d372SCristian Dumitrescu 
32734f59d372SCristian Dumitrescu 		/* Copy to entry. */
32744f59d372SCristian Dumitrescu 		memcpy(&entry->action_data[arg_offset],
32754f59d372SCristian Dumitrescu 		       (uint8_t *)&val,
32764f59d372SCristian Dumitrescu 		       arg->n_bits / 8);
32774f59d372SCristian Dumitrescu 
32784f59d372SCristian Dumitrescu 		arg_offset += arg->n_bits / 8;
32794f59d372SCristian Dumitrescu 	}
32804f59d372SCristian Dumitrescu 
32814f59d372SCristian Dumitrescu 	tokens += 2 + action->info.n_args * 2;
32824f59d372SCristian Dumitrescu 	n_tokens -= 2 + action->info.n_args * 2;
32834f59d372SCristian Dumitrescu 
32844f59d372SCristian Dumitrescu other:
32854f59d372SCristian Dumitrescu 	if (n_tokens)
32864f59d372SCristian Dumitrescu 		goto error;
32874f59d372SCristian Dumitrescu 
32884f59d372SCristian Dumitrescu 	free(s0);
32894f59d372SCristian Dumitrescu 	return entry;
32904f59d372SCristian Dumitrescu 
32914f59d372SCristian Dumitrescu error:
32924f59d372SCristian Dumitrescu 	table_entry_free(entry);
32934f59d372SCristian Dumitrescu 	free(s0);
32944f59d372SCristian Dumitrescu 	if (is_blank_or_comment)
32954f59d372SCristian Dumitrescu 		*is_blank_or_comment = blank_or_comment;
32964f59d372SCristian Dumitrescu 	return NULL;
32974f59d372SCristian Dumitrescu }
32984f59d372SCristian Dumitrescu 
329999a2dd95SBruce Richardson static void
table_entry_printf(FILE * f,struct rte_swx_ctl_pipeline * ctl,struct table * table,struct rte_swx_table_entry * entry)330099a2dd95SBruce Richardson table_entry_printf(FILE *f,
330199a2dd95SBruce Richardson 		   struct rte_swx_ctl_pipeline *ctl,
330299a2dd95SBruce Richardson 		   struct table *table,
330399a2dd95SBruce Richardson 		   struct rte_swx_table_entry *entry)
330499a2dd95SBruce Richardson {
330599a2dd95SBruce Richardson 	struct action *action = &ctl->actions[entry->action_id];
330699a2dd95SBruce Richardson 	uint32_t i;
330799a2dd95SBruce Richardson 
330899a2dd95SBruce Richardson 	fprintf(f, "match ");
330999a2dd95SBruce Richardson 	for (i = 0; i < table->params.key_size; i++)
331099a2dd95SBruce Richardson 		fprintf(f, "%02x", entry->key[i]);
331199a2dd95SBruce Richardson 
331299a2dd95SBruce Richardson 	if (entry->key_mask) {
331399a2dd95SBruce Richardson 		fprintf(f, "/");
331499a2dd95SBruce Richardson 		for (i = 0; i < table->params.key_size; i++)
331599a2dd95SBruce Richardson 			fprintf(f, "%02x", entry->key_mask[i]);
331699a2dd95SBruce Richardson 	}
331799a2dd95SBruce Richardson 
331899a2dd95SBruce Richardson 	fprintf(f, " priority %u", entry->key_priority);
331999a2dd95SBruce Richardson 
332099a2dd95SBruce Richardson 	fprintf(f, " action %s ", action->info.name);
332199a2dd95SBruce Richardson 	for (i = 0; i < action->data_size; i++)
332299a2dd95SBruce Richardson 		fprintf(f, "%02x", entry->action_data[i]);
332399a2dd95SBruce Richardson 
332499a2dd95SBruce Richardson 	fprintf(f, "\n");
332599a2dd95SBruce Richardson }
332699a2dd95SBruce Richardson 
332799a2dd95SBruce Richardson int
rte_swx_ctl_pipeline_table_fprintf(FILE * f,struct rte_swx_ctl_pipeline * ctl,const char * table_name)332899a2dd95SBruce Richardson rte_swx_ctl_pipeline_table_fprintf(FILE *f,
332999a2dd95SBruce Richardson 				   struct rte_swx_ctl_pipeline *ctl,
333099a2dd95SBruce Richardson 				   const char *table_name)
333199a2dd95SBruce Richardson {
333299a2dd95SBruce Richardson 	struct table *table;
333399a2dd95SBruce Richardson 	struct rte_swx_table_entry *entry;
333499a2dd95SBruce Richardson 	uint32_t n_entries = 0, i;
333599a2dd95SBruce Richardson 
333699a2dd95SBruce Richardson 	if (!f || !ctl || !table_name || !table_name[0])
333799a2dd95SBruce Richardson 		return -EINVAL;
333899a2dd95SBruce Richardson 
333999a2dd95SBruce Richardson 	table = table_find(ctl, table_name);
334099a2dd95SBruce Richardson 	if (!table)
334199a2dd95SBruce Richardson 		return -EINVAL;
334299a2dd95SBruce Richardson 
334399a2dd95SBruce Richardson 	/* Table. */
334499a2dd95SBruce Richardson 	fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [",
334599a2dd95SBruce Richardson 		table->info.name,
334699a2dd95SBruce Richardson 		table->params.key_size,
334799a2dd95SBruce Richardson 		table->params.key_offset);
334899a2dd95SBruce Richardson 
334999a2dd95SBruce Richardson 	for (i = 0; i < table->params.key_size; i++)
335099a2dd95SBruce Richardson 		fprintf(f, "%02x", table->params.key_mask0[i]);
335199a2dd95SBruce Richardson 
335299a2dd95SBruce Richardson 	fprintf(f, "], action data size %u bytes\n",
335399a2dd95SBruce Richardson 		table->params.action_data_size);
335499a2dd95SBruce Richardson 
335599a2dd95SBruce Richardson 	/* Table entries. */
335699a2dd95SBruce Richardson 	TAILQ_FOREACH(entry, &table->entries, node) {
335799a2dd95SBruce Richardson 		table_entry_printf(f, ctl, table, entry);
335899a2dd95SBruce Richardson 		n_entries++;
335999a2dd95SBruce Richardson 	}
336099a2dd95SBruce Richardson 
336199a2dd95SBruce Richardson 	TAILQ_FOREACH(entry, &table->pending_modify0, node) {
336299a2dd95SBruce Richardson 		table_entry_printf(f, ctl, table, entry);
336399a2dd95SBruce Richardson 		n_entries++;
336499a2dd95SBruce Richardson 	}
336599a2dd95SBruce Richardson 
336699a2dd95SBruce Richardson 	TAILQ_FOREACH(entry, &table->pending_delete, node) {
336799a2dd95SBruce Richardson 		table_entry_printf(f, ctl, table, entry);
336899a2dd95SBruce Richardson 		n_entries++;
336999a2dd95SBruce Richardson 	}
337099a2dd95SBruce Richardson 
337199a2dd95SBruce Richardson 	fprintf(f, "# Table %s currently has %u entries.\n",
337299a2dd95SBruce Richardson 		table_name,
337399a2dd95SBruce Richardson 		n_entries);
337499a2dd95SBruce Richardson 	return 0;
337599a2dd95SBruce Richardson }
3376cdaa937dSCristian Dumitrescu 
3377cdaa937dSCristian Dumitrescu int
rte_swx_ctl_pipeline_selector_fprintf(FILE * f,struct rte_swx_ctl_pipeline * ctl,const char * selector_name)3378cdaa937dSCristian Dumitrescu rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
3379cdaa937dSCristian Dumitrescu 				      struct rte_swx_ctl_pipeline *ctl,
3380cdaa937dSCristian Dumitrescu 				      const char *selector_name)
3381cdaa937dSCristian Dumitrescu {
3382cdaa937dSCristian Dumitrescu 	struct selector *s;
3383cdaa937dSCristian Dumitrescu 	uint32_t group_id;
3384cdaa937dSCristian Dumitrescu 
3385cdaa937dSCristian Dumitrescu 	if (!f || !ctl || !selector_name || !selector_name[0])
3386cdaa937dSCristian Dumitrescu 		return -EINVAL;
3387cdaa937dSCristian Dumitrescu 
3388cdaa937dSCristian Dumitrescu 	s = selector_find(ctl, selector_name);
3389cdaa937dSCristian Dumitrescu 	if (!s)
3390cdaa937dSCristian Dumitrescu 		return -EINVAL;
3391cdaa937dSCristian Dumitrescu 
3392cdaa937dSCristian Dumitrescu 	/* Selector. */
3393cdaa937dSCristian Dumitrescu 	fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
3394cdaa937dSCristian Dumitrescu 		s->info.name,
3395cdaa937dSCristian Dumitrescu 		s->info.n_groups_max,
3396cdaa937dSCristian Dumitrescu 		s->info.n_members_per_group_max);
3397cdaa937dSCristian Dumitrescu 
3398cdaa937dSCristian Dumitrescu 	/* Groups. */
3399cdaa937dSCristian Dumitrescu 	for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
3400cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_group *group = s->groups[group_id];
3401cdaa937dSCristian Dumitrescu 		struct rte_swx_table_selector_member *m;
3402cdaa937dSCristian Dumitrescu 		uint32_t n_members = 0;
3403cdaa937dSCristian Dumitrescu 
3404cdaa937dSCristian Dumitrescu 		fprintf(f, "Group %u = [", group_id);
3405cdaa937dSCristian Dumitrescu 
3406cdaa937dSCristian Dumitrescu 		/* Non-empty group. */
3407cdaa937dSCristian Dumitrescu 		if (group)
3408cdaa937dSCristian Dumitrescu 			TAILQ_FOREACH(m, &group->members, node) {
3409cdaa937dSCristian Dumitrescu 				fprintf(f, "%u:%u ", m->member_id, m->member_weight);
3410cdaa937dSCristian Dumitrescu 				n_members++;
3411cdaa937dSCristian Dumitrescu 			}
3412cdaa937dSCristian Dumitrescu 
3413cdaa937dSCristian Dumitrescu 		/* Empty group. */
3414cdaa937dSCristian Dumitrescu 		if (!n_members)
3415cdaa937dSCristian Dumitrescu 			fprintf(f, "0:1 ");
3416cdaa937dSCristian Dumitrescu 
3417cdaa937dSCristian Dumitrescu 		fprintf(f, "]\n");
3418cdaa937dSCristian Dumitrescu 	}
3419cdaa937dSCristian Dumitrescu 
3420cdaa937dSCristian Dumitrescu 	return 0;
3421cdaa937dSCristian Dumitrescu }
3422