pipeline: support learner tables
Add pipeline level support for learner tables. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
parent
0c06fa3bfa
commit
4f59d37261
@ -123,12 +123,26 @@ struct selector {
|
||||
struct rte_swx_table_selector_params params;
|
||||
};
|
||||
|
||||
struct learner {
|
||||
struct rte_swx_ctl_learner_info info;
|
||||
struct rte_swx_ctl_table_match_field_info *mf;
|
||||
struct rte_swx_ctl_table_action_info *actions;
|
||||
uint32_t action_data_size;
|
||||
|
||||
/* The pending default action: this is NOT the current default action;
|
||||
* this will be the new default action after the next commit, if the
|
||||
* next commit operation is successful.
|
||||
*/
|
||||
struct rte_swx_table_entry *pending_default;
|
||||
};
|
||||
|
||||
struct rte_swx_ctl_pipeline {
|
||||
struct rte_swx_ctl_pipeline_info info;
|
||||
struct rte_swx_pipeline *p;
|
||||
struct action *actions;
|
||||
struct table *tables;
|
||||
struct selector *selectors;
|
||||
struct learner *learners;
|
||||
struct rte_swx_table_state *ts;
|
||||
struct rte_swx_table_state *ts_next;
|
||||
int numa_node;
|
||||
@ -924,6 +938,70 @@ selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
learner_pending_default_free(struct learner *l)
|
||||
{
|
||||
if (!l->pending_default)
|
||||
return;
|
||||
|
||||
free(l->pending_default->action_data);
|
||||
free(l->pending_default);
|
||||
l->pending_default = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
learner_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!ctl->learners)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
struct learner *l = &ctl->learners[i];
|
||||
|
||||
free(l->mf);
|
||||
free(l->actions);
|
||||
|
||||
learner_pending_default_free(l);
|
||||
}
|
||||
|
||||
free(ctl->learners);
|
||||
ctl->learners = NULL;
|
||||
}
|
||||
|
||||
static struct learner *
|
||||
learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
struct learner *l = &ctl->learners[i];
|
||||
|
||||
if (!strcmp(learner_name, l->info.name))
|
||||
return l;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l)
|
||||
{
|
||||
uint32_t action_data_size = 0, i;
|
||||
|
||||
for (i = 0; i < l->info.n_actions; i++) {
|
||||
uint32_t action_id = l->actions[i].action_id;
|
||||
struct action *a = &ctl->actions[action_id];
|
||||
|
||||
if (a->data_size > action_data_size)
|
||||
action_data_size = a->data_size;
|
||||
}
|
||||
|
||||
return action_data_size;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
{
|
||||
@ -954,6 +1032,14 @@ table_state_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
rte_swx_table_selector_free(ts->obj);
|
||||
}
|
||||
|
||||
/* For each learner table, free its table state. */
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
struct rte_swx_table_state *ts = &ctl->ts_next[i];
|
||||
|
||||
/* Default action data. */
|
||||
free(ts->default_action_data);
|
||||
}
|
||||
|
||||
free(ctl->ts_next);
|
||||
ctl->ts_next = NULL;
|
||||
}
|
||||
@ -1020,6 +1106,29 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
|
||||
}
|
||||
}
|
||||
|
||||
/* Learner tables. */
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
struct learner *l = &ctl->learners[i];
|
||||
struct rte_swx_table_state *ts = &ctl->ts[i];
|
||||
struct rte_swx_table_state *ts_next = &ctl->ts_next[i];
|
||||
|
||||
/* Table object: duplicate from the current table state. */
|
||||
ts_next->obj = ts->obj;
|
||||
|
||||
/* Default action data: duplicate from the current table state. */
|
||||
ts_next->default_action_data = malloc(l->action_data_size);
|
||||
if (!ts_next->default_action_data) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(ts_next->default_action_data,
|
||||
ts->default_action_data,
|
||||
l->action_data_size);
|
||||
|
||||
ts_next->default_action_id = ts->default_action_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@ -1037,6 +1146,8 @@ rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
|
||||
table_state_free(ctl);
|
||||
|
||||
learner_free(ctl);
|
||||
|
||||
selector_free(ctl);
|
||||
|
||||
table_free(ctl);
|
||||
@ -1251,6 +1362,54 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* learner tables. */
|
||||
ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner));
|
||||
if (!ctl->learners)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
struct learner *l = &ctl->learners[i];
|
||||
uint32_t j;
|
||||
|
||||
/* info. */
|
||||
status = rte_swx_ctl_learner_info_get(p, i, &l->info);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
/* mf. */
|
||||
l->mf = calloc(l->info.n_match_fields,
|
||||
sizeof(struct rte_swx_ctl_table_match_field_info));
|
||||
if (!l->mf)
|
||||
goto error;
|
||||
|
||||
for (j = 0; j < l->info.n_match_fields; j++) {
|
||||
status = rte_swx_ctl_learner_match_field_info_get(p,
|
||||
i,
|
||||
j,
|
||||
&l->mf[j]);
|
||||
if (status)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* actions. */
|
||||
l->actions = calloc(l->info.n_actions,
|
||||
sizeof(struct rte_swx_ctl_table_action_info));
|
||||
if (!l->actions)
|
||||
goto error;
|
||||
|
||||
for (j = 0; j < l->info.n_actions; j++) {
|
||||
status = rte_swx_ctl_learner_action_info_get(p,
|
||||
i,
|
||||
j,
|
||||
&l->actions[j]);
|
||||
if (status || l->actions[j].action_id >= ctl->info.n_actions)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* action_data_size. */
|
||||
l->action_data_size = learner_action_data_size_get(ctl, l);
|
||||
}
|
||||
|
||||
/* ts. */
|
||||
status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
|
||||
if (status)
|
||||
@ -1685,9 +1844,8 @@ table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
|
||||
action_data = table->pending_default->action_data;
|
||||
a = &ctl->actions[action_id];
|
||||
|
||||
memcpy(ts_next->default_action_data,
|
||||
action_data,
|
||||
a->data_size);
|
||||
if (a->data_size)
|
||||
memcpy(ts_next->default_action_data, action_data, a->data_size);
|
||||
|
||||
ts_next->default_action_id = action_id;
|
||||
}
|
||||
@ -2099,6 +2257,178 @@ selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
|
||||
}
|
||||
|
||||
static struct rte_swx_table_entry *
|
||||
learner_default_entry_alloc(struct learner *l)
|
||||
{
|
||||
struct rte_swx_table_entry *entry;
|
||||
|
||||
entry = calloc(1, sizeof(struct rte_swx_table_entry));
|
||||
if (!entry)
|
||||
goto error;
|
||||
|
||||
/* action_data. */
|
||||
if (l->action_data_size) {
|
||||
entry->action_data = calloc(1, l->action_data_size);
|
||||
if (!entry->action_data)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
||||
error:
|
||||
table_entry_free(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl,
|
||||
uint32_t learner_id,
|
||||
struct rte_swx_table_entry *entry)
|
||||
{
|
||||
struct learner *l = &ctl->learners[learner_id];
|
||||
struct action *a;
|
||||
uint32_t i;
|
||||
|
||||
CHECK(entry, EINVAL);
|
||||
|
||||
/* action_id. */
|
||||
for (i = 0; i < l->info.n_actions; i++)
|
||||
if (entry->action_id == l->actions[i].action_id)
|
||||
break;
|
||||
|
||||
CHECK(i < l->info.n_actions, EINVAL);
|
||||
|
||||
/* action_data. */
|
||||
a = &ctl->actions[entry->action_id];
|
||||
CHECK(!(a->data_size && !entry->action_data), EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct learner *l = &ctl->learners[learner_id];
|
||||
struct rte_swx_table_entry *new_entry = NULL;
|
||||
struct action *a;
|
||||
uint32_t i;
|
||||
|
||||
if (!entry)
|
||||
goto error;
|
||||
|
||||
new_entry = calloc(1, sizeof(struct rte_swx_table_entry));
|
||||
if (!new_entry)
|
||||
goto error;
|
||||
|
||||
/* action_id. */
|
||||
for (i = 0; i < l->info.n_actions; i++)
|
||||
if (entry->action_id == l->actions[i].action_id)
|
||||
break;
|
||||
|
||||
if (i >= l->info.n_actions)
|
||||
goto error;
|
||||
|
||||
new_entry->action_id = entry->action_id;
|
||||
|
||||
/* action_data. */
|
||||
a = &ctl->actions[entry->action_id];
|
||||
if (a->data_size && !entry->action_data)
|
||||
goto error;
|
||||
|
||||
/* The table layer provisions a constant action data size per
|
||||
* entry, which should be the largest data size for all the
|
||||
* actions enabled for the current table, and attempts to copy
|
||||
* this many bytes each time a table entry is added, even if the
|
||||
* specific action requires less data or even no data at all,
|
||||
* hence we always have to allocate the max.
|
||||
*/
|
||||
new_entry->action_data = calloc(1, l->action_data_size);
|
||||
if (!new_entry->action_data)
|
||||
goto error;
|
||||
|
||||
if (a->data_size)
|
||||
memcpy(new_entry->action_data, entry->action_data, a->data_size);
|
||||
|
||||
return new_entry;
|
||||
|
||||
error:
|
||||
table_entry_free(new_entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct learner *l;
|
||||
struct rte_swx_table_entry *new_entry;
|
||||
uint32_t learner_id;
|
||||
|
||||
CHECK(ctl, EINVAL);
|
||||
|
||||
CHECK(learner_name && learner_name[0], EINVAL);
|
||||
l = learner_find(ctl, learner_name);
|
||||
CHECK(l, EINVAL);
|
||||
learner_id = l - ctl->learners;
|
||||
CHECK(!l->info.default_action_is_const, EINVAL);
|
||||
|
||||
CHECK(entry, EINVAL);
|
||||
CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
|
||||
|
||||
new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
|
||||
CHECK(new_entry, ENOMEM);
|
||||
|
||||
learner_pending_default_free(l);
|
||||
|
||||
l->pending_default = new_entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
|
||||
{
|
||||
struct learner *l = &ctl->learners[learner_id];
|
||||
struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables +
|
||||
ctl->info.n_selectors + learner_id];
|
||||
struct action *a;
|
||||
uint8_t *action_data;
|
||||
uint64_t action_id;
|
||||
|
||||
/* Copy the pending default entry. */
|
||||
if (!l->pending_default)
|
||||
return;
|
||||
|
||||
action_id = l->pending_default->action_id;
|
||||
action_data = l->pending_default->action_data;
|
||||
a = &ctl->actions[action_id];
|
||||
|
||||
if (a->data_size)
|
||||
memcpy(ts_next->default_action_data, action_data, a->data_size);
|
||||
|
||||
ts_next->default_action_id = action_id;
|
||||
}
|
||||
|
||||
static void
|
||||
learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
|
||||
{
|
||||
struct learner *l = &ctl->learners[learner_id];
|
||||
|
||||
/* Free up the pending default entry, as it is now part of the table. */
|
||||
learner_pending_default_free(l);
|
||||
}
|
||||
|
||||
static void
|
||||
learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id)
|
||||
{
|
||||
struct learner *l = &ctl->learners[learner_id];
|
||||
|
||||
/* Free up the pending default entry, as it is no longer going to be added to the table. */
|
||||
learner_pending_default_free(l);
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
{
|
||||
@ -2110,6 +2440,7 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
|
||||
/* Operate the changes on the current ts_next before it becomes the new ts. First, operate
|
||||
* all the changes that can fail; if no failure, then operate the changes that cannot fail.
|
||||
* We must be able to fully revert all the changes that can fail as if they never happened.
|
||||
*/
|
||||
for (i = 0; i < ctl->info.n_tables; i++) {
|
||||
status = table_rollfwd0(ctl, i, 0);
|
||||
@ -2123,9 +2454,15 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
/* Second, operate all the changes that cannot fail. Since nothing can fail from this point
|
||||
* onwards, the transaction is guaranteed to be successful.
|
||||
*/
|
||||
for (i = 0; i < ctl->info.n_tables; i++)
|
||||
table_rollfwd1(ctl, i);
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++)
|
||||
learner_rollfwd(ctl, i);
|
||||
|
||||
/* Swap the table state for the data plane. The current ts and ts_next
|
||||
* become the new ts_next and ts, respectively.
|
||||
*/
|
||||
@ -2151,6 +2488,11 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
selector_rollfwd_finalize(ctl, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++) {
|
||||
learner_rollfwd(ctl, i);
|
||||
learner_rollfwd_finalize(ctl, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
@ -2166,6 +2508,10 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
selector_abort(ctl, i);
|
||||
}
|
||||
|
||||
if (abort_on_fail)
|
||||
for (i = 0; i < ctl->info.n_learners; i++)
|
||||
learner_abort(ctl, i);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -2182,6 +2528,9 @@ rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++)
|
||||
selector_abort(ctl, i);
|
||||
|
||||
for (i = 0; i < ctl->info.n_learners; i++)
|
||||
learner_abort(ctl, i);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2460,6 +2809,130 @@ rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens;
|
||||
struct learner *l;
|
||||
struct action *action;
|
||||
struct rte_swx_table_entry *entry = NULL;
|
||||
char *s0 = NULL, *s;
|
||||
uint32_t n_tokens = 0, arg_offset = 0, i;
|
||||
int blank_or_comment = 0;
|
||||
|
||||
/* Check input arguments. */
|
||||
if (!ctl)
|
||||
goto error;
|
||||
|
||||
if (!learner_name || !learner_name[0])
|
||||
goto error;
|
||||
|
||||
l = learner_find(ctl, learner_name);
|
||||
if (!l)
|
||||
goto error;
|
||||
|
||||
if (!string || !string[0])
|
||||
goto error;
|
||||
|
||||
/* Memory allocation. */
|
||||
s0 = strdup(string);
|
||||
if (!s0)
|
||||
goto error;
|
||||
|
||||
entry = learner_default_entry_alloc(l);
|
||||
if (!entry)
|
||||
goto error;
|
||||
|
||||
/* Parse the string into tokens. */
|
||||
for (s = s0; ; ) {
|
||||
char *token;
|
||||
|
||||
token = strtok_r(s, " \f\n\r\t\v", &s);
|
||||
if (!token || token_is_comment(token))
|
||||
break;
|
||||
|
||||
if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX)
|
||||
goto error;
|
||||
|
||||
token_array[n_tokens] = token;
|
||||
n_tokens++;
|
||||
}
|
||||
|
||||
if (!n_tokens) {
|
||||
blank_or_comment = 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
tokens = token_array;
|
||||
|
||||
/*
|
||||
* Action.
|
||||
*/
|
||||
if (!(n_tokens && !strcmp(tokens[0], "action")))
|
||||
goto other;
|
||||
|
||||
if (n_tokens < 2)
|
||||
goto error;
|
||||
|
||||
action = action_find(ctl, tokens[1]);
|
||||
if (!action)
|
||||
goto error;
|
||||
|
||||
if (n_tokens < 2 + action->info.n_args * 2)
|
||||
goto error;
|
||||
|
||||
/* action_id. */
|
||||
entry->action_id = action - ctl->actions;
|
||||
|
||||
/* action_data. */
|
||||
for (i = 0; i < action->info.n_args; i++) {
|
||||
struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
|
||||
char *arg_name, *arg_val;
|
||||
uint64_t val;
|
||||
|
||||
arg_name = tokens[2 + i * 2];
|
||||
arg_val = tokens[2 + i * 2 + 1];
|
||||
|
||||
if (strcmp(arg_name, arg->name))
|
||||
goto error;
|
||||
|
||||
val = strtoull(arg_val, &arg_val, 0);
|
||||
if (arg_val[0])
|
||||
goto error;
|
||||
|
||||
/* Endianness conversion. */
|
||||
if (arg->is_network_byte_order)
|
||||
val = field_hton(val, arg->n_bits);
|
||||
|
||||
/* Copy to entry. */
|
||||
memcpy(&entry->action_data[arg_offset],
|
||||
(uint8_t *)&val,
|
||||
arg->n_bits / 8);
|
||||
|
||||
arg_offset += arg->n_bits / 8;
|
||||
}
|
||||
|
||||
tokens += 2 + action->info.n_args * 2;
|
||||
n_tokens -= 2 + action->info.n_args * 2;
|
||||
|
||||
other:
|
||||
if (n_tokens)
|
||||
goto error;
|
||||
|
||||
free(s0);
|
||||
return entry;
|
||||
|
||||
error:
|
||||
table_entry_free(entry);
|
||||
free(s0);
|
||||
if (is_blank_or_comment)
|
||||
*is_blank_or_comment = blank_or_comment;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
table_entry_printf(FILE *f,
|
||||
struct rte_swx_ctl_pipeline *ctl,
|
||||
|
@ -52,6 +52,9 @@ struct rte_swx_ctl_pipeline_info {
|
||||
/** Number of selector tables. */
|
||||
uint32_t n_selectors;
|
||||
|
||||
/** Number of learner tables. */
|
||||
uint32_t n_learners;
|
||||
|
||||
/** Number of register arrays. */
|
||||
uint32_t n_regarrays;
|
||||
|
||||
@ -512,6 +515,142 @@ rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p,
|
||||
const char *selector_name,
|
||||
struct rte_swx_pipeline_selector_stats *stats);
|
||||
|
||||
/*
|
||||
* Learner Table Query API.
|
||||
*/
|
||||
|
||||
/** Learner table info. */
|
||||
struct rte_swx_ctl_learner_info {
|
||||
/** Learner table name. */
|
||||
char name[RTE_SWX_CTL_NAME_SIZE];
|
||||
|
||||
/** Number of match fields. */
|
||||
uint32_t n_match_fields;
|
||||
|
||||
/** Number of actions. */
|
||||
uint32_t n_actions;
|
||||
|
||||
/** Non-zero (true) when the default action is constant, therefore it
|
||||
* cannot be changed; zero (false) when the default action not constant,
|
||||
* therefore it can be changed.
|
||||
*/
|
||||
int default_action_is_const;
|
||||
|
||||
/** Learner table size parameter. */
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Learner table info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] learner_id
|
||||
* Learner table ID (0 .. *n_learners* - 1).
|
||||
* @param[out] learner
|
||||
* Learner table info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t learner_id,
|
||||
struct rte_swx_ctl_learner_info *learner);
|
||||
|
||||
/**
|
||||
* Learner table match field info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] learner_id
|
||||
* Learner table ID (0 .. *n_learners* - 1).
|
||||
* @param[in] match_field_id
|
||||
* Match field ID (0 .. *n_match_fields* - 1).
|
||||
* @param[out] match_field
|
||||
* Learner table match field info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t learner_id,
|
||||
uint32_t match_field_id,
|
||||
struct rte_swx_ctl_table_match_field_info *match_field);
|
||||
|
||||
/**
|
||||
* Learner table action info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] learner_id
|
||||
* Learner table ID (0 .. *n_learners* - 1).
|
||||
* @param[in] learner_action_id
|
||||
* Action index within the set of learner table actions (0 .. learner table n_actions - 1). Not
|
||||
* to be confused with the pipeline-leve action ID (0 .. pipeline n_actions - 1), which is
|
||||
* precisely what this function returns as part of the *learner_action*.
|
||||
* @param[out] learner_action
|
||||
* Learner action info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t learner_id,
|
||||
uint32_t learner_action_id,
|
||||
struct rte_swx_ctl_table_action_info *learner_action);
|
||||
|
||||
/** Learner table statistics. */
|
||||
struct rte_swx_learner_stats {
|
||||
/** Number of packets with lookup hit. */
|
||||
uint64_t n_pkts_hit;
|
||||
|
||||
/** Number of packets with lookup miss. */
|
||||
uint64_t n_pkts_miss;
|
||||
|
||||
/** Number of packets with successful learning. */
|
||||
uint64_t n_pkts_learn_ok;
|
||||
|
||||
/** Number of packets with learning error. */
|
||||
uint64_t n_pkts_learn_err;
|
||||
|
||||
/** Number of packets with forget event. */
|
||||
uint64_t n_pkts_forget;
|
||||
|
||||
/** Number of packets (with either lookup hit or miss) per pipeline action. Array of
|
||||
* pipeline *n_actions* elements indedex by the pipeline-level *action_id*, therefore this
|
||||
* array has the same size for all the tables within the same pipeline.
|
||||
*/
|
||||
uint64_t *n_pkts_action;
|
||||
};
|
||||
|
||||
/**
|
||||
* Learner table statistics counters read
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] learner_name
|
||||
* Learner table name.
|
||||
* @param[out] stats
|
||||
* Learner table stats. Must point to a pre-allocated structure. The *n_pkts_action* field also
|
||||
* needs to be pre-allocated as array of pipeline *n_actions* elements. The pipeline actions that
|
||||
* are not valid for the current learner table have their associated *n_pkts_action* element
|
||||
* always set to zero.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p,
|
||||
const char *learner_name,
|
||||
struct rte_swx_learner_stats *stats);
|
||||
|
||||
/*
|
||||
* Table Update API.
|
||||
*/
|
||||
@ -761,6 +900,27 @@ rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *c
|
||||
uint32_t group_id,
|
||||
uint32_t member_id);
|
||||
|
||||
/**
|
||||
* Pipeline learner table default entry add
|
||||
*
|
||||
* Schedule learner table default entry update as part of the next commit operation.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] learner_name
|
||||
* Learner table name.
|
||||
* @param[in] entry
|
||||
* The new table default entry. The *key* and *key_mask* entry fields are ignored.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
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);
|
||||
|
||||
/**
|
||||
* Pipeline commit
|
||||
*
|
||||
@ -819,6 +979,32 @@ rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *string,
|
||||
int *is_blank_or_comment);
|
||||
|
||||
/**
|
||||
* Pipeline learner table default entry read
|
||||
*
|
||||
* Read learner table default entry from string.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] learner_name
|
||||
* Learner table name.
|
||||
* @param[in] string
|
||||
* String containing the learner table default entry.
|
||||
* @param[out] is_blank_or_comment
|
||||
* On error, this argument provides an indication of whether *string* contains
|
||||
* an invalid table entry (set to zero) or a blank or comment line that should
|
||||
* typically be ignored (set to a non-zero value).
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
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);
|
||||
|
||||
/**
|
||||
* Pipeline table print to file
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -676,6 +676,83 @@ rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p,
|
||||
const char *name,
|
||||
struct rte_swx_pipeline_selector_params *params);
|
||||
|
||||
/** Pipeline learner table parameters. */
|
||||
struct rte_swx_pipeline_learner_params {
|
||||
/** The set of match fields for the current table.
|
||||
* Restriction: All the match fields of the current table need to be
|
||||
* part of the same struct, i.e. either all the match fields are part of
|
||||
* the same header or all the match fields are part of the meta-data.
|
||||
*/
|
||||
const char **field_names;
|
||||
|
||||
/** The number of match fields for the current table. Must be non-zero.
|
||||
*/
|
||||
uint32_t n_fields;
|
||||
|
||||
/** The set of actions for the current table. */
|
||||
const char **action_names;
|
||||
|
||||
/** The number of actions for the current table. Must be at least one.
|
||||
*/
|
||||
uint32_t n_actions;
|
||||
|
||||
/** This table type allows adding the latest lookup key (typically done
|
||||
* only in the case of lookup miss) to the table with a given action.
|
||||
* The action arguments are picked up from the packet meta-data: for
|
||||
* each action, a set of successive meta-data fields (with the name of
|
||||
* the first such field provided here) is 1:1 mapped to the action
|
||||
* arguments. These meta-data fields must be set with the actual values
|
||||
* of the action arguments before the key add operation.
|
||||
*/
|
||||
const char **action_field_names;
|
||||
|
||||
/** The default table action that gets executed on lookup miss. Must be
|
||||
* one of the table actions included in the *action_names*.
|
||||
*/
|
||||
const char *default_action_name;
|
||||
|
||||
/** Default action data. The size of this array is the action data size
|
||||
* of the default action. Must be NULL if the default action data size
|
||||
* is zero.
|
||||
*/
|
||||
uint8_t *default_action_data;
|
||||
|
||||
/** If non-zero (true), then the default action of the current table
|
||||
* cannot be changed. If zero (false), then the default action can be
|
||||
* changed in the future with another action from the *action_names*
|
||||
* list.
|
||||
*/
|
||||
int default_action_is_const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pipeline learner table configure
|
||||
*
|
||||
* @param[out] p
|
||||
* Pipeline handle.
|
||||
* @param[in] name
|
||||
* Learner table name.
|
||||
* @param[in] params
|
||||
* Learner table parameters.
|
||||
* @param[in] size
|
||||
* The maximum number of table entries. Must be non-zero.
|
||||
* @param[in] timeout
|
||||
* Table entry timeout in seconds. Must be non-zero.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument;
|
||||
* -ENOMEM: Not enough space/cannot allocate memory;
|
||||
* -EEXIST: Learner table with this name already exists;
|
||||
* -ENODEV: Learner table creation error.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p,
|
||||
const char *name,
|
||||
struct rte_swx_pipeline_learner_params *params,
|
||||
uint32_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Pipeline register array configure
|
||||
*
|
||||
|
@ -20,7 +20,10 @@
|
||||
#define TABLE_ACTIONS_BLOCK 4
|
||||
#define SELECTOR_BLOCK 5
|
||||
#define SELECTOR_SELECTOR_BLOCK 6
|
||||
#define APPLY_BLOCK 7
|
||||
#define LEARNER_BLOCK 7
|
||||
#define LEARNER_KEY_BLOCK 8
|
||||
#define LEARNER_ACTIONS_BLOCK 9
|
||||
#define APPLY_BLOCK 10
|
||||
|
||||
/*
|
||||
* extobj.
|
||||
@ -1281,6 +1284,420 @@ selector_block_parse(struct selector_spec *s,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* learner.
|
||||
*
|
||||
* learner {
|
||||
* key {
|
||||
* MATCH_FIELD_NAME
|
||||
* ...
|
||||
* }
|
||||
* actions {
|
||||
* ACTION_NAME args METADATA_FIELD_NAME
|
||||
* ...
|
||||
* }
|
||||
* default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
|
||||
* size SIZE
|
||||
* timeout TIMEOUT_IN_SECONDS
|
||||
* }
|
||||
*/
|
||||
struct learner_spec {
|
||||
char *name;
|
||||
struct rte_swx_pipeline_learner_params params;
|
||||
uint32_t size;
|
||||
uint32_t timeout;
|
||||
};
|
||||
|
||||
static void
|
||||
learner_spec_free(struct learner_spec *s)
|
||||
{
|
||||
uintptr_t default_action_name;
|
||||
uint32_t i;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
free(s->name);
|
||||
s->name = NULL;
|
||||
|
||||
for (i = 0; i < s->params.n_fields; i++) {
|
||||
uintptr_t name = (uintptr_t)s->params.field_names[i];
|
||||
|
||||
free((void *)name);
|
||||
}
|
||||
|
||||
free(s->params.field_names);
|
||||
s->params.field_names = NULL;
|
||||
|
||||
s->params.n_fields = 0;
|
||||
|
||||
for (i = 0; i < s->params.n_actions; i++) {
|
||||
uintptr_t name = (uintptr_t)s->params.action_names[i];
|
||||
|
||||
free((void *)name);
|
||||
}
|
||||
|
||||
free(s->params.action_names);
|
||||
s->params.action_names = NULL;
|
||||
|
||||
for (i = 0; i < s->params.n_actions; i++) {
|
||||
uintptr_t name = (uintptr_t)s->params.action_field_names[i];
|
||||
|
||||
free((void *)name);
|
||||
}
|
||||
|
||||
free(s->params.action_field_names);
|
||||
s->params.action_field_names = NULL;
|
||||
|
||||
s->params.n_actions = 0;
|
||||
|
||||
default_action_name = (uintptr_t)s->params.default_action_name;
|
||||
free((void *)default_action_name);
|
||||
s->params.default_action_name = NULL;
|
||||
|
||||
free(s->params.default_action_data);
|
||||
s->params.default_action_data = NULL;
|
||||
|
||||
s->params.default_action_is_const = 0;
|
||||
|
||||
s->size = 0;
|
||||
|
||||
s->timeout = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_key_statement_parse(uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
/* Check format. */
|
||||
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid key statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* block_mask. */
|
||||
*block_mask |= 1 << LEARNER_KEY_BLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_key_block_parse(struct learner_spec *s,
|
||||
uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
const char **new_field_names = NULL;
|
||||
char *field_name = NULL;
|
||||
|
||||
/* Handle end of block. */
|
||||
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
||||
*block_mask &= ~(1 << LEARNER_KEY_BLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check input arguments. */
|
||||
if (n_tokens != 1) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid match field statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
field_name = strdup(tokens[0]);
|
||||
new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
|
||||
if (!field_name || !new_field_names) {
|
||||
free(field_name);
|
||||
free(new_field_names);
|
||||
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s->params.field_names = new_field_names;
|
||||
s->params.field_names[s->params.n_fields] = field_name;
|
||||
s->params.n_fields++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_actions_statement_parse(uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
/* Check format. */
|
||||
if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid actions statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* block_mask. */
|
||||
*block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_actions_block_parse(struct learner_spec *s,
|
||||
uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
const char **new_action_names = NULL;
|
||||
const char **new_action_field_names = NULL;
|
||||
char *action_name = NULL, *action_field_name = NULL;
|
||||
int has_args = 1;
|
||||
|
||||
/* Handle end of block. */
|
||||
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
||||
*block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check input arguments. */
|
||||
if ((n_tokens != 3) || strcmp(tokens[1], "args")) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid action name statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[2], "none"))
|
||||
has_args = 0;
|
||||
|
||||
action_name = strdup(tokens[0]);
|
||||
|
||||
if (has_args)
|
||||
action_field_name = strdup(tokens[2]);
|
||||
|
||||
new_action_names = realloc(s->params.action_names,
|
||||
(s->params.n_actions + 1) * sizeof(char *));
|
||||
|
||||
new_action_field_names = realloc(s->params.action_field_names,
|
||||
(s->params.n_actions + 1) * sizeof(char *));
|
||||
|
||||
if (!action_name ||
|
||||
(has_args && !action_field_name) ||
|
||||
!new_action_names ||
|
||||
!new_action_field_names) {
|
||||
free(action_name);
|
||||
free(action_field_name);
|
||||
free(new_action_names);
|
||||
free(new_action_field_names);
|
||||
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s->params.action_names = new_action_names;
|
||||
s->params.action_names[s->params.n_actions] = action_name;
|
||||
s->params.action_field_names = new_action_field_names;
|
||||
s->params.action_field_names[s->params.n_actions] = action_field_name;
|
||||
s->params.n_actions++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_statement_parse(struct learner_spec *s,
|
||||
uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
/* Check format. */
|
||||
if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid learner statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* spec. */
|
||||
s->name = strdup(tokens[1]);
|
||||
if (!s->name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* block_mask. */
|
||||
*block_mask |= 1 << LEARNER_BLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
learner_block_parse(struct learner_spec *s,
|
||||
uint32_t *block_mask,
|
||||
char **tokens,
|
||||
uint32_t n_tokens,
|
||||
uint32_t n_lines,
|
||||
uint32_t *err_line,
|
||||
const char **err_msg)
|
||||
{
|
||||
if (*block_mask & (1 << LEARNER_KEY_BLOCK))
|
||||
return learner_key_block_parse(s,
|
||||
block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
|
||||
if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
|
||||
return learner_actions_block_parse(s,
|
||||
block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
|
||||
/* Handle end of block. */
|
||||
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
||||
*block_mask &= ~(1 << LEARNER_BLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "key"))
|
||||
return learner_key_statement_parse(block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
|
||||
if (!strcmp(tokens[0], "actions"))
|
||||
return learner_actions_statement_parse(block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
|
||||
if (!strcmp(tokens[0], "default_action")) {
|
||||
if (((n_tokens != 4) && (n_tokens != 5)) ||
|
||||
strcmp(tokens[2], "args") ||
|
||||
strcmp(tokens[3], "none") ||
|
||||
((n_tokens == 5) && strcmp(tokens[4], "const"))) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid default_action statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s->params.default_action_name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Duplicate default_action stmt.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->params.default_action_name = strdup(tokens[1]);
|
||||
if (!s->params.default_action_name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (n_tokens == 5)
|
||||
s->params.default_action_is_const = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "size")) {
|
||||
char *p = tokens[1];
|
||||
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid size statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->size = strtoul(p, &p, 0);
|
||||
if (p[0]) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid size argument.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "timeout")) {
|
||||
char *p = tokens[1];
|
||||
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid timeout statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->timeout = strtoul(p, &p, 0);
|
||||
if (p[0]) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid timeout argument.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Anything else. */
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* regarray.
|
||||
*
|
||||
@ -1545,6 +1962,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
struct action_spec action_spec = {0};
|
||||
struct table_spec table_spec = {0};
|
||||
struct selector_spec selector_spec = {0};
|
||||
struct learner_spec learner_spec = {0};
|
||||
struct regarray_spec regarray_spec = {0};
|
||||
struct metarray_spec metarray_spec = {0};
|
||||
struct apply_spec apply_spec = {0};
|
||||
@ -1761,6 +2179,40 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* learner block. */
|
||||
if (block_mask & (1 << LEARNER_BLOCK)) {
|
||||
status = learner_block_parse(&learner_spec,
|
||||
&block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
if (block_mask & (1 << LEARNER_BLOCK))
|
||||
continue;
|
||||
|
||||
/* End of block. */
|
||||
status = rte_swx_pipeline_learner_config(p,
|
||||
learner_spec.name,
|
||||
&learner_spec.params,
|
||||
learner_spec.size,
|
||||
learner_spec.timeout);
|
||||
if (status) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Learner table configuration error.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
learner_spec_free(&learner_spec);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply block. */
|
||||
if (block_mask & (1 << APPLY_BLOCK)) {
|
||||
status = apply_block_parse(&apply_spec,
|
||||
@ -1934,6 +2386,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* learner. */
|
||||
if (!strcmp(tokens[0], "learner")) {
|
||||
status = learner_statement_parse(&learner_spec,
|
||||
&block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* regarray. */
|
||||
if (!strcmp(tokens[0], "regarray")) {
|
||||
status = regarray_statement_parse(®array_spec,
|
||||
@ -2042,6 +2509,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
action_spec_free(&action_spec);
|
||||
table_spec_free(&table_spec);
|
||||
selector_spec_free(&selector_spec);
|
||||
learner_spec_free(&learner_spec);
|
||||
regarray_spec_free(®array_spec);
|
||||
metarray_spec_free(&metarray_spec);
|
||||
apply_spec_free(&apply_spec);
|
||||
|
@ -129,4 +129,13 @@ EXPERIMENTAL {
|
||||
rte_swx_ctl_selector_field_info_get;
|
||||
rte_swx_ctl_selector_group_id_field_info_get;
|
||||
rte_swx_ctl_selector_member_id_field_info_get;
|
||||
|
||||
#added in 21.11
|
||||
rte_swx_ctl_pipeline_learner_default_entry_add;
|
||||
rte_swx_ctl_pipeline_learner_default_entry_read;
|
||||
rte_swx_ctl_pipeline_learner_stats_read;
|
||||
rte_swx_ctl_learner_action_info_get;
|
||||
rte_swx_ctl_learner_info_get;
|
||||
rte_swx_ctl_learner_match_field_info_get;
|
||||
rte_swx_pipeline_learner_config;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user