pipeline: support selector table
Add pipeline-level support for selector tables. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
parent
f7598a62d1
commit
cdaa937d3e
@ -10,6 +10,8 @@
|
||||
#include <rte_common.h>
|
||||
#include <rte_byteorder.h>
|
||||
|
||||
#include <rte_swx_table_selector.h>
|
||||
|
||||
#include "rte_swx_ctl.h"
|
||||
|
||||
#define CHECK(condition, err_code) \
|
||||
@ -89,11 +91,44 @@ struct table {
|
||||
uint32_t n_delete;
|
||||
};
|
||||
|
||||
struct selector {
|
||||
/* Selector table info. */
|
||||
struct rte_swx_ctl_selector_info info;
|
||||
|
||||
/* group_id field. */
|
||||
struct rte_swx_ctl_table_match_field_info group_id_field;
|
||||
|
||||
/* selector fields. */
|
||||
struct rte_swx_ctl_table_match_field_info *selector_fields;
|
||||
|
||||
/* member_id field. */
|
||||
struct rte_swx_ctl_table_match_field_info member_id_field;
|
||||
|
||||
/* Current selector table. Array of info.n_groups_max elements.*/
|
||||
struct rte_swx_table_selector_group **groups;
|
||||
|
||||
/* Pending selector table subject to the next commit. Array of info.n_groups_max elements.
|
||||
*/
|
||||
struct rte_swx_table_selector_group **pending_groups;
|
||||
|
||||
/* Valid flag per group. Array of n_groups_max elements. */
|
||||
int *groups_added;
|
||||
|
||||
/* Pending delete flag per group. Group deletion is subject to the next commit. Array of
|
||||
* info.n_groups_max elements.
|
||||
*/
|
||||
int *groups_pending_delete;
|
||||
|
||||
/* Params. */
|
||||
struct rte_swx_table_selector_params params;
|
||||
};
|
||||
|
||||
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 rte_swx_table_state *ts;
|
||||
struct rte_swx_table_state *ts_next;
|
||||
int numa_node;
|
||||
@ -709,6 +744,209 @@ table_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
ctl->tables = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_group_members_free(struct selector *s, uint32_t group_id)
|
||||
{
|
||||
struct rte_swx_table_selector_group *group = s->groups[group_id];
|
||||
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
for ( ; ; ) {
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
m = TAILQ_FIRST(&group->members);
|
||||
if (!m)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&group->members, m, node);
|
||||
free(m);
|
||||
}
|
||||
|
||||
free(group);
|
||||
s->groups[group_id] = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_pending_group_members_free(struct selector *s, uint32_t group_id)
|
||||
{
|
||||
struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
|
||||
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
for ( ; ; ) {
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
m = TAILQ_FIRST(&group->members);
|
||||
if (!m)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&group->members, m, node);
|
||||
free(m);
|
||||
}
|
||||
|
||||
free(group);
|
||||
s->pending_groups[group_id] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id)
|
||||
{
|
||||
struct rte_swx_table_selector_group *g, *gp;
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
selector_pending_group_members_free(s, group_id);
|
||||
|
||||
g = s->groups[group_id];
|
||||
gp = s->pending_groups[group_id];
|
||||
|
||||
if (!gp) {
|
||||
gp = calloc(1, sizeof(struct rte_swx_table_selector_group));
|
||||
if (!gp)
|
||||
goto error;
|
||||
|
||||
TAILQ_INIT(&gp->members);
|
||||
|
||||
s->pending_groups[group_id] = gp;
|
||||
}
|
||||
|
||||
if (!g)
|
||||
return 0;
|
||||
|
||||
TAILQ_FOREACH(m, &g->members, node) {
|
||||
struct rte_swx_table_selector_member *mp;
|
||||
|
||||
mp = calloc(1, sizeof(struct rte_swx_table_selector_member));
|
||||
if (!mp)
|
||||
goto error;
|
||||
|
||||
memcpy(mp, m, sizeof(struct rte_swx_table_selector_member));
|
||||
|
||||
TAILQ_INSERT_TAIL(&gp->members, mp, node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
selector_pending_group_members_free(s, group_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (ctl->selectors)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
struct selector *s = &ctl->selectors[i];
|
||||
uint32_t i;
|
||||
|
||||
/* selector_fields. */
|
||||
free(s->selector_fields);
|
||||
|
||||
/* groups. */
|
||||
if (s->groups)
|
||||
for (i = 0; i < s->info.n_groups_max; i++)
|
||||
selector_group_members_free(s, i);
|
||||
|
||||
free(s->groups);
|
||||
|
||||
/* pending_groups. */
|
||||
if (s->pending_groups)
|
||||
for (i = 0; i < s->info.n_groups_max; i++)
|
||||
selector_pending_group_members_free(s, i);
|
||||
|
||||
free(s->pending_groups);
|
||||
|
||||
/* groups_added. */
|
||||
free(s->groups_added);
|
||||
|
||||
/* groups_pending_delete. */
|
||||
free(s->groups_pending_delete);
|
||||
|
||||
/* params. */
|
||||
free(s->params.selector_mask);
|
||||
}
|
||||
|
||||
free(ctl->selectors);
|
||||
ctl->selectors = NULL;
|
||||
}
|
||||
|
||||
static struct selector *
|
||||
selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
struct selector *s = &ctl->selectors[i];
|
||||
|
||||
if (!strcmp(selector_name, s->info.name))
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
{
|
||||
struct selector *s = &ctl->selectors[selector_id];
|
||||
struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL;
|
||||
uint8_t *selector_mask = NULL;
|
||||
uint32_t selector_size = 0, selector_offset = 0, i;
|
||||
|
||||
/* Find first (smallest offset) and last (biggest offset) match fields. */
|
||||
first = &s->selector_fields[0];
|
||||
last = &s->selector_fields[0];
|
||||
|
||||
for (i = 1; i < s->info.n_selector_fields; i++) {
|
||||
struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
|
||||
|
||||
if (f->offset < first->offset)
|
||||
first = f;
|
||||
|
||||
if (f->offset > last->offset)
|
||||
last = f;
|
||||
}
|
||||
|
||||
/* selector_offset. */
|
||||
selector_offset = first->offset / 8;
|
||||
|
||||
/* selector_size. */
|
||||
selector_size = (last->offset + last->n_bits - first->offset) / 8;
|
||||
|
||||
/* selector_mask. */
|
||||
selector_mask = calloc(1, selector_size);
|
||||
if (!selector_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < s->info.n_selector_fields; i++) {
|
||||
struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i];
|
||||
uint32_t start;
|
||||
size_t size;
|
||||
|
||||
start = (f->offset - first->offset) / 8;
|
||||
size = f->n_bits / 8;
|
||||
|
||||
memset(&selector_mask[start], 0xFF, size);
|
||||
}
|
||||
|
||||
/* Fill in. */
|
||||
s->params.group_id_offset = s->group_id_field.offset / 8;
|
||||
s->params.selector_size = selector_size;
|
||||
s->params.selector_offset = selector_offset;
|
||||
s->params.selector_mask = selector_mask;
|
||||
s->params.member_id_offset = s->member_id_field.offset / 8;
|
||||
s->params.n_groups_max = s->info.n_groups_max;
|
||||
s->params.n_members_per_group_max = s->info.n_members_per_group_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
{
|
||||
@ -730,6 +968,15 @@ table_state_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
table->ops.free(ts->obj);
|
||||
}
|
||||
|
||||
/* For each selector table, free its table state. */
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
struct rte_swx_table_state *ts = &ctl->ts_next[i];
|
||||
|
||||
/* Table object. */
|
||||
if (ts->obj)
|
||||
rte_swx_table_selector_free(ts->obj);
|
||||
}
|
||||
|
||||
free(ctl->ts_next);
|
||||
ctl->ts_next = NULL;
|
||||
}
|
||||
@ -740,13 +987,14 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
|
||||
int status = 0;
|
||||
uint32_t i;
|
||||
|
||||
ctl->ts_next = calloc(ctl->info.n_tables,
|
||||
ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors,
|
||||
sizeof(struct rte_swx_table_state));
|
||||
if (!ctl->ts_next) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Tables. */
|
||||
for (i = 0; i < ctl->info.n_tables; i++) {
|
||||
struct table *table = &ctl->tables[i];
|
||||
struct rte_swx_table_state *ts = &ctl->ts[i];
|
||||
@ -782,6 +1030,19 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
|
||||
ts_next->default_action_id = ts->default_action_id;
|
||||
}
|
||||
|
||||
/* Selector tables. */
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
struct selector *s = &ctl->selectors[i];
|
||||
struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + i];
|
||||
|
||||
/* Table object. */
|
||||
ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node);
|
||||
if (!ts_next->obj) {
|
||||
status = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@ -799,6 +1060,8 @@ rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
|
||||
|
||||
table_state_free(ctl);
|
||||
|
||||
selector_free(ctl);
|
||||
|
||||
table_free(ctl);
|
||||
|
||||
free(ctl);
|
||||
@ -940,6 +1203,77 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* selector tables. */
|
||||
ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector));
|
||||
if (!ctl->selectors)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
struct selector *s = &ctl->selectors[i];
|
||||
uint32_t j;
|
||||
|
||||
/* info. */
|
||||
status = rte_swx_ctl_selector_info_get(p, i, &s->info);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
/* group_id field. */
|
||||
status = rte_swx_ctl_selector_group_id_field_info_get(p,
|
||||
i,
|
||||
&s->group_id_field);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
/* selector fields. */
|
||||
s->selector_fields = calloc(s->info.n_selector_fields,
|
||||
sizeof(struct rte_swx_ctl_table_match_field_info));
|
||||
if (!s->selector_fields)
|
||||
goto error;
|
||||
|
||||
for (j = 0; j < s->info.n_selector_fields; j++) {
|
||||
status = rte_swx_ctl_selector_field_info_get(p,
|
||||
i,
|
||||
j,
|
||||
&s->selector_fields[j]);
|
||||
if (status)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* member_id field. */
|
||||
status = rte_swx_ctl_selector_member_id_field_info_get(p,
|
||||
i,
|
||||
&s->member_id_field);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
/* groups. */
|
||||
s->groups = calloc(s->info.n_groups_max,
|
||||
sizeof(struct rte_swx_table_selector_group *));
|
||||
if (!s->groups)
|
||||
goto error;
|
||||
|
||||
/* pending_groups. */
|
||||
s->pending_groups = calloc(s->info.n_groups_max,
|
||||
sizeof(struct rte_swx_table_selector_group *));
|
||||
if (!s->pending_groups)
|
||||
goto error;
|
||||
|
||||
/* groups_added. */
|
||||
s->groups_added = calloc(s->info.n_groups_max, sizeof(int));
|
||||
if (!s->groups_added)
|
||||
goto error;
|
||||
|
||||
/* groups_pending_delete. */
|
||||
s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int));
|
||||
if (!s->groups_pending_delete)
|
||||
goto error;
|
||||
|
||||
/* params. */
|
||||
status = selector_params_get(ctl, i);
|
||||
if (status)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* ts. */
|
||||
status = rte_swx_pipeline_table_state_get(p, &ctl->ts);
|
||||
if (status)
|
||||
@ -1499,6 +1833,295 @@ table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id)
|
||||
table_pending_default_free(table);
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name,
|
||||
uint32_t *group_id)
|
||||
{
|
||||
struct selector *s;
|
||||
uint32_t i;
|
||||
|
||||
/* Check input arguments. */
|
||||
if (!ctl || !selector_name || !selector_name[0] || !group_id)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(ctl, selector_name);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
/* Find an unused group. */
|
||||
for (i = 0; i < s->info.n_groups_max; i++)
|
||||
if (!s->groups_added[i]) {
|
||||
*group_id = i;
|
||||
s->groups_added[i] = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name,
|
||||
uint32_t group_id)
|
||||
{
|
||||
struct selector *s;
|
||||
struct rte_swx_table_selector_group *group;
|
||||
|
||||
/* Check input arguments. */
|
||||
if (!ctl || !selector_name || !selector_name[0])
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(ctl, selector_name);
|
||||
if (!s ||
|
||||
(group_id >= s->info.n_groups_max) ||
|
||||
!s->groups_added[group_id])
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if this group is already scheduled for deletion. */
|
||||
if (s->groups_pending_delete[group_id])
|
||||
return 0;
|
||||
|
||||
/* Initialize the pending group, if needed. */
|
||||
if (!s->pending_groups[group_id]) {
|
||||
int status;
|
||||
|
||||
status = selector_group_duplicate_to_pending(s, group_id);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
group = s->pending_groups[group_id];
|
||||
|
||||
/* Schedule removal of all the members from the current group. */
|
||||
for ( ; ; ) {
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
m = TAILQ_FIRST(&group->members);
|
||||
if (!m)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&group->members, m, node);
|
||||
free(m);
|
||||
}
|
||||
|
||||
/* Schedule the group for deletion. */
|
||||
s->groups_pending_delete[group_id] = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct selector *s;
|
||||
struct rte_swx_table_selector_group *group;
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
if (!member_weight)
|
||||
return rte_swx_ctl_pipeline_selector_group_member_delete(ctl,
|
||||
selector_name,
|
||||
group_id,
|
||||
member_id);
|
||||
|
||||
/* Check input arguments. */
|
||||
if (!ctl || !selector_name || !selector_name[0])
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(ctl, selector_name);
|
||||
if (!s ||
|
||||
(group_id >= s->info.n_groups_max) ||
|
||||
!s->groups_added[group_id] ||
|
||||
s->groups_pending_delete[group_id])
|
||||
return -EINVAL;
|
||||
|
||||
/* Initialize the pending group, if needed. */
|
||||
if (!s->pending_groups[group_id]) {
|
||||
int status;
|
||||
|
||||
status = selector_group_duplicate_to_pending(s, group_id);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
group = s->pending_groups[group_id];
|
||||
|
||||
/* If this member is already in this group, then simply update its weight and return. */
|
||||
TAILQ_FOREACH(m, &group->members, node)
|
||||
if (m->member_id == member_id) {
|
||||
m->member_weight = member_weight;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add new member to this group. */
|
||||
m = calloc(1, sizeof(struct rte_swx_table_selector_member));
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
m->member_id = member_id;
|
||||
m->member_weight = member_weight;
|
||||
|
||||
TAILQ_INSERT_TAIL(&group->members, m, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct selector *s;
|
||||
struct rte_swx_table_selector_group *group;
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
/* Check input arguments. */
|
||||
if (!ctl || !selector_name || !selector_name[0])
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(ctl, selector_name);
|
||||
if (!s ||
|
||||
(group_id >= s->info.n_groups_max) ||
|
||||
!s->groups_added[group_id] ||
|
||||
s->groups_pending_delete[group_id])
|
||||
return -EINVAL;
|
||||
|
||||
/* Initialize the pending group, if needed. */
|
||||
if (!s->pending_groups[group_id]) {
|
||||
int status;
|
||||
|
||||
status = selector_group_duplicate_to_pending(s, group_id);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
group = s->pending_groups[group_id];
|
||||
|
||||
/* Look for this member in the group and remove it, if found. */
|
||||
TAILQ_FOREACH(m, &group->members, node)
|
||||
if (m->member_id == member_id) {
|
||||
TAILQ_REMOVE(&group->members, m, node);
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
{
|
||||
struct selector *s = &ctl->selectors[selector_id];
|
||||
struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
|
||||
uint32_t group_id;
|
||||
|
||||
/* Push pending group member changes (s->pending_groups[group_id]) to the selector table
|
||||
* mirror copy (ts_next->obj).
|
||||
*/
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
|
||||
struct rte_swx_table_selector_group *group = s->pending_groups[group_id];
|
||||
int status;
|
||||
|
||||
/* Skip this group if no change needed. */
|
||||
if (!group)
|
||||
continue;
|
||||
|
||||
/* Apply the pending changes for the current group. */
|
||||
status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
{
|
||||
struct selector *s = &ctl->selectors[selector_id];
|
||||
uint32_t group_id;
|
||||
|
||||
/* Commit pending group member changes (s->pending_groups[group_id]) to the stable group
|
||||
* records (s->groups[group_id).
|
||||
*/
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
|
||||
struct rte_swx_table_selector_group *g = s->groups[group_id];
|
||||
struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
|
||||
|
||||
/* Skip this group if no change needed. */
|
||||
if (!gp)
|
||||
continue;
|
||||
|
||||
/* Transition the pending changes to stable. */
|
||||
s->groups[group_id] = gp;
|
||||
s->pending_groups[group_id] = NULL;
|
||||
|
||||
/* Free the old group member list. */
|
||||
if (!g)
|
||||
continue;
|
||||
|
||||
for ( ; ; ) {
|
||||
struct rte_swx_table_selector_member *m;
|
||||
|
||||
m = TAILQ_FIRST(&g->members);
|
||||
if (!m)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&g->members, m, node);
|
||||
free(m);
|
||||
}
|
||||
|
||||
free(g);
|
||||
}
|
||||
|
||||
/* Commit pending group validity changes (from s->groups_pending_delete[group_id] to
|
||||
* s->groups_added[group_id].
|
||||
*/
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
|
||||
if (s->groups_pending_delete[group_id]) {
|
||||
s->groups_added[group_id] = 0;
|
||||
s->groups_pending_delete[group_id] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
{
|
||||
struct selector *s = &ctl->selectors[selector_id];
|
||||
struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id];
|
||||
struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id];
|
||||
uint32_t group_id;
|
||||
|
||||
/* Discard any previous changes to the selector table mirror copy (ts_next->obj). */
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
|
||||
struct rte_swx_table_selector_group *gp = s->pending_groups[group_id];
|
||||
|
||||
if (gp) {
|
||||
ts_next->obj = ts->obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id)
|
||||
{
|
||||
struct selector *s = &ctl->selectors[selector_id];
|
||||
uint32_t group_id;
|
||||
|
||||
/* Discard any pending group member changes (s->pending_groups[group_id]). */
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++)
|
||||
selector_pending_group_members_free(s, group_id);
|
||||
|
||||
/* Discard any pending group deletions. */
|
||||
memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int));
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
{
|
||||
@ -1508,8 +2131,8 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
|
||||
CHECK(ctl, EINVAL);
|
||||
|
||||
/* Operate the changes on the current ts_next before it becomes the new
|
||||
* ts.
|
||||
/* 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.
|
||||
*/
|
||||
for (i = 0; i < ctl->info.n_tables; i++) {
|
||||
status = table_rollfwd0(ctl, i, 0);
|
||||
@ -1517,6 +2140,12 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
status = selector_rollfwd(ctl, i);
|
||||
if (status)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctl->info.n_tables; i++)
|
||||
table_rollfwd1(ctl, i);
|
||||
|
||||
@ -1529,7 +2158,10 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
ctl->ts = ctl->ts_next;
|
||||
ctl->ts_next = ts;
|
||||
|
||||
/* Operate the changes on the current ts_next, which is the previous ts.
|
||||
/* Operate the changes on the current ts_next, which is the previous ts, in order to get
|
||||
* the current ts_next in sync with the current ts. Since the changes that can fail did
|
||||
* not fail on the previous ts_next, it is guaranteed that they will not fail on the
|
||||
* current ts_next, hence no error checking is needed.
|
||||
*/
|
||||
for (i = 0; i < ctl->info.n_tables; i++) {
|
||||
table_rollfwd0(ctl, i, 1);
|
||||
@ -1537,6 +2169,11 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
table_rollfwd2(ctl, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
selector_rollfwd(ctl, i);
|
||||
selector_rollfwd_finalize(ctl, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
@ -1546,6 +2183,12 @@ rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail)
|
||||
table_abort(ctl, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++) {
|
||||
selector_rollback(ctl, i);
|
||||
if (abort_on_fail)
|
||||
selector_abort(ctl, i);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1559,6 +2202,9 @@ rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl)
|
||||
|
||||
for (i = 0; i < ctl->info.n_tables; i++)
|
||||
table_abort(ctl, i);
|
||||
|
||||
for (i = 0; i < ctl->info.n_selectors; i++)
|
||||
selector_abort(ctl, i);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1858,3 +2504,49 @@ rte_swx_ctl_pipeline_table_fprintf(FILE *f,
|
||||
n_entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
|
||||
struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name)
|
||||
{
|
||||
struct selector *s;
|
||||
uint32_t group_id;
|
||||
|
||||
if (!f || !ctl || !selector_name || !selector_name[0])
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(ctl, selector_name);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
/* Selector. */
|
||||
fprintf(f, "# Selector %s: max groups %u, max members per group %u\n",
|
||||
s->info.name,
|
||||
s->info.n_groups_max,
|
||||
s->info.n_members_per_group_max);
|
||||
|
||||
/* Groups. */
|
||||
for (group_id = 0; group_id < s->info.n_groups_max; group_id++) {
|
||||
struct rte_swx_table_selector_group *group = s->groups[group_id];
|
||||
struct rte_swx_table_selector_member *m;
|
||||
uint32_t n_members = 0;
|
||||
|
||||
fprintf(f, "Group %u = [", group_id);
|
||||
|
||||
/* Non-empty group. */
|
||||
if (group)
|
||||
TAILQ_FOREACH(m, &group->members, node) {
|
||||
fprintf(f, "%u:%u ", m->member_id, m->member_weight);
|
||||
n_members++;
|
||||
}
|
||||
|
||||
/* Empty group. */
|
||||
if (!n_members)
|
||||
fprintf(f, "0:1 ");
|
||||
|
||||
fprintf(f, "]\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ extern "C" {
|
||||
|
||||
#include "rte_swx_port.h"
|
||||
#include "rte_swx_table.h"
|
||||
#include "rte_swx_table_selector.h"
|
||||
|
||||
struct rte_swx_pipeline;
|
||||
|
||||
@ -48,6 +49,9 @@ struct rte_swx_ctl_pipeline_info {
|
||||
/** Number of tables. */
|
||||
uint32_t n_tables;
|
||||
|
||||
/** Number of selector tables. */
|
||||
uint32_t n_selectors;
|
||||
|
||||
/** Number of register arrays. */
|
||||
uint32_t n_regarrays;
|
||||
|
||||
@ -385,6 +389,129 @@ rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p,
|
||||
const char *table_name,
|
||||
struct rte_swx_table_stats *stats);
|
||||
|
||||
/*
|
||||
* Selector Table Query API.
|
||||
*/
|
||||
|
||||
/** Selector info. */
|
||||
struct rte_swx_ctl_selector_info {
|
||||
/** Selector table name. */
|
||||
char name[RTE_SWX_CTL_NAME_SIZE];
|
||||
|
||||
/** Number of selector fields. */
|
||||
uint32_t n_selector_fields;
|
||||
|
||||
/** Maximum number of groups. */
|
||||
uint32_t n_groups_max;
|
||||
|
||||
/** Maximum number of members per group. */
|
||||
uint32_t n_members_per_group_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Selector table info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] selector_id
|
||||
* Selector table ID (0 .. *n_selectors* - 1).
|
||||
* @param[out] selector
|
||||
* Selector table info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_selector_info *selector);
|
||||
|
||||
/**
|
||||
* Selector table "group ID" field info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] selector_id
|
||||
* Selector table ID (0 .. *n_selectors*).
|
||||
* @param[out] field
|
||||
* Selector table "group ID" field info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field);
|
||||
|
||||
/**
|
||||
* Sselector table selector field info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] selector_id
|
||||
* Selector table ID (0 .. *n_selectors*).
|
||||
* @param[in] selector_field_id
|
||||
* Selector table selector field ID (0 .. *n_selector_fields* - 1).
|
||||
* @param[out] field
|
||||
* Selector table selector field info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
uint32_t selector_field_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field);
|
||||
|
||||
/**
|
||||
* Selector table "member ID" field info get
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] selector_id
|
||||
* Selector table ID (0 .. *n_selectors*).
|
||||
* @param[out] field
|
||||
* Selector table "member ID" field info.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field);
|
||||
|
||||
/** Selector table statistics. */
|
||||
struct rte_swx_pipeline_selector_stats {
|
||||
/** Number of packets. */
|
||||
uint64_t n_pkts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Selector table statistics counters read
|
||||
*
|
||||
* @param[in] p
|
||||
* Pipeline handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @param[out] stats
|
||||
* Selector table stats. Must point to a pre-allocated structure.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p,
|
||||
const char *selector_name,
|
||||
struct rte_swx_pipeline_selector_stats *stats);
|
||||
|
||||
/*
|
||||
* Table Update API.
|
||||
*/
|
||||
@ -529,6 +656,111 @@ rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *table_name,
|
||||
struct rte_swx_table_entry *entry);
|
||||
|
||||
/**
|
||||
* Pipeline selector table group add
|
||||
*
|
||||
* Add a new group to a selector table. This operation is executed before this
|
||||
* function returns and its result is independent of the result of the next
|
||||
* commit operation.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @param[out] group_id
|
||||
* The ID of the new group. Only valid when the function call is successful.
|
||||
* This group is initially empty, i.e. it does not contain any members.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument;
|
||||
* -ENOSPC: All groups are currently in use, no group available.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name,
|
||||
uint32_t *group_id);
|
||||
|
||||
/**
|
||||
* Pipeline selector table group delete
|
||||
*
|
||||
* Schedule a group for deletion as part of the next commit operation. The group
|
||||
* to be deleted can be empty or non-empty.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @param[in] group_id
|
||||
* Group to be deleted from the selector table.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument;
|
||||
* -ENOMEM: Not enough memory.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name,
|
||||
uint32_t group_id);
|
||||
|
||||
/**
|
||||
* Pipeline selector table member add to group
|
||||
*
|
||||
* Schedule the operation to add a new member to an existing group as part of
|
||||
* the next commit operation. If this member is already in this group, the
|
||||
* member weight is updated to the new value. A weight of zero means this member
|
||||
* is to be deleted from the group.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @param[in] group_id
|
||||
* The group ID.
|
||||
* @param[in] member_id
|
||||
* The member to be added to the group.
|
||||
* @param[in] member_weight
|
||||
* Member weight.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument;
|
||||
* -ENOMEM: Not enough memory;
|
||||
* -ENOSPC: The group is full.
|
||||
*/
|
||||
__rte_experimental
|
||||
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);
|
||||
|
||||
/**
|
||||
* Pipeline selector table member delete from group
|
||||
*
|
||||
* Schedule the operation to delete a member from an existing group as part of
|
||||
* the next commit operation.
|
||||
*
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @param[in] group_id
|
||||
* The group ID. Must be valid.
|
||||
* @param[in] member_id
|
||||
* The member to be added to the group. Must be valid.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name,
|
||||
uint32_t group_id,
|
||||
uint32_t member_id);
|
||||
|
||||
/**
|
||||
* Pipeline commit
|
||||
*
|
||||
@ -608,6 +840,27 @@ rte_swx_ctl_pipeline_table_fprintf(FILE *f,
|
||||
struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *table_name);
|
||||
|
||||
/**
|
||||
* Pipeline selector print to file
|
||||
*
|
||||
* Print all the selector entries to file.
|
||||
*
|
||||
* @param[in] f
|
||||
* Output file.
|
||||
* @param[in] ctl
|
||||
* Pipeline control handle.
|
||||
* @param[in] selector_name
|
||||
* Selector table name.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_fprintf(FILE *f,
|
||||
struct rte_swx_ctl_pipeline *ctl,
|
||||
const char *selector_name);
|
||||
|
||||
/*
|
||||
* Register Array Query API.
|
||||
*/
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <rte_cycles.h>
|
||||
#include <rte_meter.h>
|
||||
|
||||
#include <rte_swx_table_selector.h>
|
||||
|
||||
#include "rte_swx_pipeline.h"
|
||||
#include "rte_swx_ctl.h"
|
||||
|
||||
@ -498,6 +500,7 @@ enum instruction_type {
|
||||
|
||||
/* table TABLE */
|
||||
INSTR_TABLE,
|
||||
INSTR_SELECTOR,
|
||||
|
||||
/* extern e.obj.func */
|
||||
INSTR_EXTERN_OBJ,
|
||||
@ -794,6 +797,38 @@ struct table_statistics {
|
||||
uint64_t *n_pkts_action;
|
||||
};
|
||||
|
||||
/*
|
||||
* Selector.
|
||||
*/
|
||||
struct selector {
|
||||
TAILQ_ENTRY(selector) node;
|
||||
char name[RTE_SWX_NAME_SIZE];
|
||||
|
||||
struct field *group_id_field;
|
||||
struct field **selector_fields;
|
||||
uint32_t n_selector_fields;
|
||||
struct header *selector_header;
|
||||
struct field *member_id_field;
|
||||
|
||||
uint32_t n_groups_max;
|
||||
uint32_t n_members_per_group_max;
|
||||
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(selector_tailq, selector);
|
||||
|
||||
struct selector_runtime {
|
||||
void *mailbox;
|
||||
uint8_t **group_id_buffer;
|
||||
uint8_t **selector_buffer;
|
||||
uint8_t **member_id_buffer;
|
||||
};
|
||||
|
||||
struct selector_statistics {
|
||||
uint64_t n_pkts;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register array.
|
||||
*/
|
||||
@ -873,6 +908,7 @@ struct thread {
|
||||
|
||||
/* Tables. */
|
||||
struct table_runtime *tables;
|
||||
struct selector_runtime *selectors;
|
||||
struct rte_swx_table_state *table_state;
|
||||
uint64_t action_id;
|
||||
int hit; /* 0 = Miss, 1 = Hit. */
|
||||
@ -1308,6 +1344,7 @@ struct rte_swx_pipeline {
|
||||
struct action_tailq actions;
|
||||
struct table_type_tailq table_types;
|
||||
struct table_tailq tables;
|
||||
struct selector_tailq selectors;
|
||||
struct regarray_tailq regarrays;
|
||||
struct meter_profile_tailq meter_profiles;
|
||||
struct metarray_tailq metarrays;
|
||||
@ -1317,6 +1354,7 @@ struct rte_swx_pipeline {
|
||||
struct instruction **action_instructions;
|
||||
struct rte_swx_table_state *table_state;
|
||||
struct table_statistics *table_stats;
|
||||
struct selector_statistics *selector_stats;
|
||||
struct regarray_runtime *regarray_runtime;
|
||||
struct metarray_runtime *metarray_runtime;
|
||||
struct instruction *instructions;
|
||||
@ -1329,6 +1367,7 @@ struct rte_swx_pipeline {
|
||||
uint32_t n_extern_funcs;
|
||||
uint32_t n_actions;
|
||||
uint32_t n_tables;
|
||||
uint32_t n_selectors;
|
||||
uint32_t n_regarrays;
|
||||
uint32_t n_metarrays;
|
||||
uint32_t n_headers;
|
||||
@ -3450,6 +3489,9 @@ instr_hdr_invalidate_exec(struct rte_swx_pipeline *p)
|
||||
static struct table *
|
||||
table_find(struct rte_swx_pipeline *p, const char *name);
|
||||
|
||||
static struct selector *
|
||||
selector_find(struct rte_swx_pipeline *p, const char *name);
|
||||
|
||||
static int
|
||||
instr_table_translate(struct rte_swx_pipeline *p,
|
||||
struct action *action,
|
||||
@ -3459,16 +3501,26 @@ instr_table_translate(struct rte_swx_pipeline *p,
|
||||
struct instruction_data *data __rte_unused)
|
||||
{
|
||||
struct table *t;
|
||||
struct selector *s;
|
||||
|
||||
CHECK(!action, EINVAL);
|
||||
CHECK(n_tokens == 2, EINVAL);
|
||||
|
||||
t = table_find(p, tokens[1]);
|
||||
CHECK(t, EINVAL);
|
||||
if (t) {
|
||||
instr->type = INSTR_TABLE;
|
||||
instr->table.table_id = t->id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
instr->type = INSTR_TABLE;
|
||||
instr->table.table_id = t->id;
|
||||
return 0;
|
||||
s = selector_find(p, tokens[1]);
|
||||
if (s) {
|
||||
instr->type = INSTR_SELECTOR;
|
||||
instr->table.table_id = s->id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHECK(0, EINVAL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -3522,6 +3574,45 @@ instr_table_exec(struct rte_swx_pipeline *p)
|
||||
thread_ip_action_call(p, t, action_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
instr_selector_exec(struct rte_swx_pipeline *p)
|
||||
{
|
||||
struct thread *t = &p->threads[p->thread_id];
|
||||
struct instruction *ip = t->ip;
|
||||
uint32_t selector_id = ip->table.table_id;
|
||||
struct rte_swx_table_state *ts = &t->table_state[p->n_tables + selector_id];
|
||||
struct selector_runtime *selector = &t->selectors[selector_id];
|
||||
struct selector_statistics *stats = &p->selector_stats[selector_id];
|
||||
uint64_t n_pkts = stats->n_pkts;
|
||||
int done;
|
||||
|
||||
/* Table. */
|
||||
done = rte_swx_table_selector_select(ts->obj,
|
||||
selector->mailbox,
|
||||
selector->group_id_buffer,
|
||||
selector->selector_buffer,
|
||||
selector->member_id_buffer);
|
||||
if (!done) {
|
||||
/* Thread. */
|
||||
TRACE("[Thread %2u] selector %u (not finalized)\n",
|
||||
p->thread_id,
|
||||
selector_id);
|
||||
|
||||
thread_yield(p);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TRACE("[Thread %2u] selector %u\n",
|
||||
p->thread_id,
|
||||
selector_id);
|
||||
|
||||
stats->n_pkts = n_pkts + 1;
|
||||
|
||||
/* Thread. */
|
||||
thread_ip_inc(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* extern.
|
||||
*/
|
||||
@ -8787,6 +8878,7 @@ static instr_exec_t instruction_table[] = {
|
||||
[INSTR_METER_IMI] = instr_meter_imi_exec,
|
||||
|
||||
[INSTR_TABLE] = instr_table_exec,
|
||||
[INSTR_SELECTOR] = instr_selector_exec,
|
||||
[INSTR_EXTERN_OBJ] = instr_extern_obj_exec,
|
||||
[INSTR_EXTERN_FUNC] = instr_extern_func_exec,
|
||||
|
||||
@ -9253,6 +9345,7 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
|
||||
|
||||
CHECK_NAME(name, EINVAL);
|
||||
CHECK(!table_find(p, name), EEXIST);
|
||||
CHECK(!selector_find(p, name), EEXIST);
|
||||
|
||||
CHECK(params, EINVAL);
|
||||
|
||||
@ -9455,82 +9548,6 @@ table_params_free(struct rte_swx_table_params *params)
|
||||
free(params);
|
||||
}
|
||||
|
||||
static int
|
||||
table_state_build(struct rte_swx_pipeline *p)
|
||||
{
|
||||
struct table *table;
|
||||
|
||||
p->table_state = calloc(p->n_tables,
|
||||
sizeof(struct rte_swx_table_state));
|
||||
CHECK(p->table_state, ENOMEM);
|
||||
|
||||
TAILQ_FOREACH(table, &p->tables, node) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[table->id];
|
||||
|
||||
if (table->type) {
|
||||
struct rte_swx_table_params *params;
|
||||
|
||||
/* ts->obj. */
|
||||
params = table_params_get(table);
|
||||
CHECK(params, ENOMEM);
|
||||
|
||||
ts->obj = table->type->ops.create(params,
|
||||
NULL,
|
||||
table->args,
|
||||
p->numa_node);
|
||||
|
||||
table_params_free(params);
|
||||
CHECK(ts->obj, ENODEV);
|
||||
}
|
||||
|
||||
/* ts->default_action_data. */
|
||||
if (table->action_data_size_max) {
|
||||
ts->default_action_data =
|
||||
malloc(table->action_data_size_max);
|
||||
CHECK(ts->default_action_data, ENOMEM);
|
||||
|
||||
memcpy(ts->default_action_data,
|
||||
table->default_action_data,
|
||||
table->action_data_size_max);
|
||||
}
|
||||
|
||||
/* ts->default_action_id. */
|
||||
ts->default_action_id = table->default_action->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_build_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!p->table_state)
|
||||
return;
|
||||
|
||||
for (i = 0; i < p->n_tables; i++) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[i];
|
||||
struct table *table = table_find_by_id(p, i);
|
||||
|
||||
/* ts->obj. */
|
||||
if (table->type && ts->obj)
|
||||
table->type->ops.free(ts->obj);
|
||||
|
||||
/* ts->default_action_data. */
|
||||
free(ts->default_action_data);
|
||||
}
|
||||
|
||||
free(p->table_state);
|
||||
p->table_state = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
table_state_build_free(p);
|
||||
}
|
||||
|
||||
static int
|
||||
table_stub_lkp(void *table __rte_unused,
|
||||
void *mailbox __rte_unused,
|
||||
@ -9658,6 +9675,458 @@ table_free(struct rte_swx_pipeline *p)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Selector.
|
||||
*/
|
||||
static struct selector *
|
||||
selector_find(struct rte_swx_pipeline *p, const char *name)
|
||||
{
|
||||
struct selector *s;
|
||||
|
||||
TAILQ_FOREACH(s, &p->selectors, node)
|
||||
if (strcmp(s->name, name) == 0)
|
||||
return s;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct selector *
|
||||
selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
|
||||
{
|
||||
struct selector *s = NULL;
|
||||
|
||||
TAILQ_FOREACH(s, &p->selectors, node)
|
||||
if (s->id == id)
|
||||
return s;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_fields_check(struct rte_swx_pipeline *p,
|
||||
struct rte_swx_pipeline_selector_params *params,
|
||||
struct header **header)
|
||||
{
|
||||
struct header *h0 = NULL;
|
||||
struct field *hf, *mf;
|
||||
uint32_t i;
|
||||
|
||||
/* Return if no selector fields. */
|
||||
if (!params->n_selector_fields || !params->selector_field_names)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check that all the selector fields either belong to the same header
|
||||
* or are all meta-data fields.
|
||||
*/
|
||||
hf = header_field_parse(p, params->selector_field_names[0], &h0);
|
||||
mf = metadata_field_parse(p, params->selector_field_names[0]);
|
||||
if (!hf && !mf)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 1; i < params->n_selector_fields; i++)
|
||||
if (h0) {
|
||||
struct header *h;
|
||||
|
||||
hf = header_field_parse(p, params->selector_field_names[i], &h);
|
||||
if (!hf || (h->id != h0->id))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
mf = metadata_field_parse(p, params->selector_field_names[i]);
|
||||
if (!mf)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check that there are no duplicated match fields. */
|
||||
for (i = 0; i < params->n_selector_fields; i++) {
|
||||
const char *field_name = params->selector_field_names[i];
|
||||
uint32_t j;
|
||||
|
||||
for (j = i + 1; j < params->n_selector_fields; j++)
|
||||
if (!strcmp(params->selector_field_names[j], field_name))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return. */
|
||||
if (header)
|
||||
*header = h0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p,
|
||||
const char *name,
|
||||
struct rte_swx_pipeline_selector_params *params)
|
||||
{
|
||||
struct selector *s;
|
||||
struct header *selector_header = NULL;
|
||||
struct field *group_id_field, *member_id_field;
|
||||
uint32_t i;
|
||||
int status = 0;
|
||||
|
||||
CHECK(p, EINVAL);
|
||||
|
||||
CHECK_NAME(name, EINVAL);
|
||||
CHECK(!table_find(p, name), EEXIST);
|
||||
CHECK(!selector_find(p, name), EEXIST);
|
||||
|
||||
CHECK(params, EINVAL);
|
||||
|
||||
CHECK_NAME(params->group_id_field_name, EINVAL);
|
||||
group_id_field = metadata_field_parse(p, params->group_id_field_name);
|
||||
CHECK(group_id_field, EINVAL);
|
||||
|
||||
for (i = 0; i < params->n_selector_fields; i++) {
|
||||
const char *field_name = params->selector_field_names[i];
|
||||
|
||||
CHECK_NAME(field_name, EINVAL);
|
||||
}
|
||||
status = selector_fields_check(p, params, &selector_header);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
CHECK_NAME(params->member_id_field_name, EINVAL);
|
||||
member_id_field = metadata_field_parse(p, params->member_id_field_name);
|
||||
CHECK(member_id_field, EINVAL);
|
||||
|
||||
CHECK(params->n_groups_max, EINVAL);
|
||||
|
||||
CHECK(params->n_members_per_group_max, EINVAL);
|
||||
|
||||
/* Memory allocation. */
|
||||
s = calloc(1, sizeof(struct selector));
|
||||
if (!s) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *));
|
||||
if (!s->selector_fields) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Node initialization. */
|
||||
strcpy(s->name, name);
|
||||
|
||||
s->group_id_field = group_id_field;
|
||||
|
||||
for (i = 0; i < params->n_selector_fields; i++) {
|
||||
const char *field_name = params->selector_field_names[i];
|
||||
|
||||
s->selector_fields[i] = selector_header ?
|
||||
header_field_parse(p, field_name, NULL) :
|
||||
metadata_field_parse(p, field_name);
|
||||
}
|
||||
|
||||
s->n_selector_fields = params->n_selector_fields;
|
||||
|
||||
s->selector_header = selector_header;
|
||||
|
||||
s->member_id_field = member_id_field;
|
||||
|
||||
s->n_groups_max = params->n_groups_max;
|
||||
|
||||
s->n_members_per_group_max = params->n_members_per_group_max;
|
||||
|
||||
s->id = p->n_selectors;
|
||||
|
||||
/* Node add to tailq. */
|
||||
TAILQ_INSERT_TAIL(&p->selectors, s, node);
|
||||
p->n_selectors++;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!s)
|
||||
return status;
|
||||
|
||||
free(s->selector_fields);
|
||||
|
||||
free(s);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_params_free(struct rte_swx_table_selector_params *params)
|
||||
{
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
free(params->selector_mask);
|
||||
|
||||
free(params);
|
||||
}
|
||||
|
||||
static struct rte_swx_table_selector_params *
|
||||
selector_table_params_get(struct selector *s)
|
||||
{
|
||||
struct rte_swx_table_selector_params *params = NULL;
|
||||
struct field *first, *last;
|
||||
uint32_t i;
|
||||
|
||||
/* Memory allocation. */
|
||||
params = calloc(1, sizeof(struct rte_swx_table_selector_params));
|
||||
if (!params)
|
||||
goto error;
|
||||
|
||||
/* Group ID. */
|
||||
params->group_id_offset = s->group_id_field->offset / 8;
|
||||
|
||||
/* Find first (smallest offset) and last (biggest offset) selector fields. */
|
||||
first = s->selector_fields[0];
|
||||
last = s->selector_fields[0];
|
||||
|
||||
for (i = 0; i < s->n_selector_fields; i++) {
|
||||
struct field *f = s->selector_fields[i];
|
||||
|
||||
if (f->offset < first->offset)
|
||||
first = f;
|
||||
|
||||
if (f->offset > last->offset)
|
||||
last = f;
|
||||
}
|
||||
|
||||
/* Selector offset and size. */
|
||||
params->selector_offset = first->offset / 8;
|
||||
params->selector_size = (last->offset + last->n_bits - first->offset) / 8;
|
||||
|
||||
/* Memory allocation. */
|
||||
params->selector_mask = calloc(1, params->selector_size);
|
||||
if (!params->selector_mask)
|
||||
goto error;
|
||||
|
||||
/* Selector mask. */
|
||||
for (i = 0; i < s->n_selector_fields; i++) {
|
||||
struct field *f = s->selector_fields[i];
|
||||
uint32_t start = (f->offset - first->offset) / 8;
|
||||
size_t size = f->n_bits / 8;
|
||||
|
||||
memset(¶ms->selector_mask[start], 0xFF, size);
|
||||
}
|
||||
|
||||
/* Member ID. */
|
||||
params->member_id_offset = s->member_id_field->offset / 8;
|
||||
|
||||
/* Maximum number of groups. */
|
||||
params->n_groups_max = s->n_groups_max;
|
||||
|
||||
/* Maximum number of members per group. */
|
||||
params->n_members_per_group_max = s->n_members_per_group_max;
|
||||
|
||||
return params;
|
||||
|
||||
error:
|
||||
selector_params_free(params);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_build_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
|
||||
struct thread *t = &p->threads[i];
|
||||
uint32_t j;
|
||||
|
||||
if (!t->selectors)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < p->n_selectors; j++) {
|
||||
struct selector_runtime *r = &t->selectors[j];
|
||||
|
||||
free(r->mailbox);
|
||||
}
|
||||
|
||||
free(t->selectors);
|
||||
t->selectors = NULL;
|
||||
}
|
||||
|
||||
free(p->selector_stats);
|
||||
p->selector_stats = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_build(struct rte_swx_pipeline *p)
|
||||
{
|
||||
uint32_t i;
|
||||
int status = 0;
|
||||
|
||||
/* Per pipeline: selector statistics. */
|
||||
p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics));
|
||||
if (!p->selector_stats) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Per thread: selector run-time. */
|
||||
for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
|
||||
struct thread *t = &p->threads[i];
|
||||
struct selector *s;
|
||||
|
||||
t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime));
|
||||
if (!t->selectors) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(s, &p->selectors, node) {
|
||||
struct selector_runtime *r = &t->selectors[s->id];
|
||||
uint64_t size;
|
||||
|
||||
/* r->mailbox. */
|
||||
size = rte_swx_table_selector_mailbox_size_get();
|
||||
if (size) {
|
||||
r->mailbox = calloc(1, size);
|
||||
if (!r->mailbox) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* r->group_id_buffer. */
|
||||
r->group_id_buffer = &t->structs[p->metadata_struct_id];
|
||||
|
||||
/* r->selector_buffer. */
|
||||
r->selector_buffer = s->selector_header ?
|
||||
&t->structs[s->selector_header->struct_id] :
|
||||
&t->structs[p->metadata_struct_id];
|
||||
|
||||
/* r->member_id_buffer. */
|
||||
r->member_id_buffer = &t->structs[p->metadata_struct_id];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
selector_build_free(p);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
selector_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
selector_build_free(p);
|
||||
|
||||
/* Selector tables. */
|
||||
for ( ; ; ) {
|
||||
struct selector *elem;
|
||||
|
||||
elem = TAILQ_FIRST(&p->selectors);
|
||||
if (!elem)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&p->selectors, elem, node);
|
||||
free(elem->selector_fields);
|
||||
free(elem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Table state.
|
||||
*/
|
||||
static int
|
||||
table_state_build(struct rte_swx_pipeline *p)
|
||||
{
|
||||
struct table *table;
|
||||
struct selector *s;
|
||||
|
||||
p->table_state = calloc(p->n_tables + p->n_selectors,
|
||||
sizeof(struct rte_swx_table_state));
|
||||
CHECK(p->table_state, ENOMEM);
|
||||
|
||||
TAILQ_FOREACH(table, &p->tables, node) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[table->id];
|
||||
|
||||
if (table->type) {
|
||||
struct rte_swx_table_params *params;
|
||||
|
||||
/* ts->obj. */
|
||||
params = table_params_get(table);
|
||||
CHECK(params, ENOMEM);
|
||||
|
||||
ts->obj = table->type->ops.create(params,
|
||||
NULL,
|
||||
table->args,
|
||||
p->numa_node);
|
||||
|
||||
table_params_free(params);
|
||||
CHECK(ts->obj, ENODEV);
|
||||
}
|
||||
|
||||
/* ts->default_action_data. */
|
||||
if (table->action_data_size_max) {
|
||||
ts->default_action_data =
|
||||
malloc(table->action_data_size_max);
|
||||
CHECK(ts->default_action_data, ENOMEM);
|
||||
|
||||
memcpy(ts->default_action_data,
|
||||
table->default_action_data,
|
||||
table->action_data_size_max);
|
||||
}
|
||||
|
||||
/* ts->default_action_id. */
|
||||
ts->default_action_id = table->default_action->id;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(s, &p->selectors, node) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id];
|
||||
struct rte_swx_table_selector_params *params;
|
||||
|
||||
/* ts->obj. */
|
||||
params = selector_table_params_get(s);
|
||||
CHECK(params, ENOMEM);
|
||||
|
||||
ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node);
|
||||
|
||||
selector_params_free(params);
|
||||
CHECK(ts->obj, ENODEV);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_build_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!p->table_state)
|
||||
return;
|
||||
|
||||
for (i = 0; i < p->n_tables; i++) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[i];
|
||||
struct table *table = table_find_by_id(p, i);
|
||||
|
||||
/* ts->obj. */
|
||||
if (table->type && ts->obj)
|
||||
table->type->ops.free(ts->obj);
|
||||
|
||||
/* ts->default_action_data. */
|
||||
free(ts->default_action_data);
|
||||
}
|
||||
|
||||
for (i = 0; i < p->n_selectors; i++) {
|
||||
struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i];
|
||||
|
||||
/* ts->obj. */
|
||||
if (ts->obj)
|
||||
rte_swx_table_selector_free(ts->obj);
|
||||
}
|
||||
|
||||
free(p->table_state);
|
||||
p->table_state = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
table_state_free(struct rte_swx_pipeline *p)
|
||||
{
|
||||
table_state_build_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register array.
|
||||
*/
|
||||
@ -9988,6 +10457,7 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
|
||||
TAILQ_INIT(&pipeline->actions);
|
||||
TAILQ_INIT(&pipeline->table_types);
|
||||
TAILQ_INIT(&pipeline->tables);
|
||||
TAILQ_INIT(&pipeline->selectors);
|
||||
TAILQ_INIT(&pipeline->regarrays);
|
||||
TAILQ_INIT(&pipeline->meter_profiles);
|
||||
TAILQ_INIT(&pipeline->metarrays);
|
||||
@ -10010,6 +10480,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
|
||||
metarray_free(p);
|
||||
regarray_free(p);
|
||||
table_state_free(p);
|
||||
selector_free(p);
|
||||
table_free(p);
|
||||
action_free(p);
|
||||
metadata_free(p);
|
||||
@ -10089,6 +10560,10 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
status = selector_build(p);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
status = table_state_build(p);
|
||||
if (status)
|
||||
goto error;
|
||||
@ -10108,6 +10583,7 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
|
||||
metarray_build_free(p);
|
||||
regarray_build_free(p);
|
||||
table_state_build_free(p);
|
||||
selector_build_free(p);
|
||||
table_build_free(p);
|
||||
action_build_free(p);
|
||||
metadata_build_free(p);
|
||||
@ -10167,6 +10643,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
|
||||
pipeline->n_ports_out = p->n_ports_out;
|
||||
pipeline->n_actions = n_actions;
|
||||
pipeline->n_tables = n_tables;
|
||||
pipeline->n_selectors = p->n_selectors;
|
||||
pipeline->n_regarrays = p->n_regarrays;
|
||||
pipeline->n_metarrays = p->n_metarrays;
|
||||
|
||||
@ -10320,6 +10797,98 @@ rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_selector_info *selector)
|
||||
{
|
||||
struct selector *s = NULL;
|
||||
|
||||
if (!p || !selector)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find_by_id(p, selector_id);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(selector->name, s->name);
|
||||
|
||||
selector->n_selector_fields = s->n_selector_fields;
|
||||
selector->n_groups_max = s->n_groups_max;
|
||||
selector->n_members_per_group_max = s->n_members_per_group_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field)
|
||||
{
|
||||
struct selector *s;
|
||||
|
||||
if (!p || (selector_id >= p->n_selectors) || !field)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find_by_id(p, selector_id);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
|
||||
field->is_header = 0;
|
||||
field->n_bits = s->group_id_field->n_bits;
|
||||
field->offset = s->group_id_field->offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
uint32_t selector_field_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field)
|
||||
{
|
||||
struct selector *s;
|
||||
struct field *f;
|
||||
|
||||
if (!p || (selector_id >= p->n_selectors) || !field)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find_by_id(p, selector_id);
|
||||
if (!s || (selector_field_id >= s->n_selector_fields))
|
||||
return -EINVAL;
|
||||
|
||||
f = s->selector_fields[selector_field_id];
|
||||
field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
|
||||
field->is_header = s->selector_header ? 1 : 0;
|
||||
field->n_bits = f->n_bits;
|
||||
field->offset = f->offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t selector_id,
|
||||
struct rte_swx_ctl_table_match_field_info *field)
|
||||
{
|
||||
struct selector *s;
|
||||
|
||||
if (!p || (selector_id >= p->n_selectors) || !field)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find_by_id(p, selector_id);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
|
||||
field->is_header = 0;
|
||||
field->n_bits = s->member_id_field->n_bits;
|
||||
field->offset = s->member_id_field->offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
|
||||
struct rte_swx_table_state **table_state)
|
||||
@ -10405,6 +10974,25 @@ rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p,
|
||||
const char *selector_name,
|
||||
struct rte_swx_pipeline_selector_stats *stats)
|
||||
{
|
||||
struct selector *s;
|
||||
|
||||
if (!p || !selector_name || !selector_name[0] || !stats)
|
||||
return -EINVAL;
|
||||
|
||||
s = selector_find(p, selector_name);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
stats->n_pkts = p->selector_stats[s->id].n_pkts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,
|
||||
uint32_t regarray_id,
|
||||
|
@ -612,6 +612,57 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
|
||||
const char *args,
|
||||
uint32_t size);
|
||||
|
||||
/** Pipeline selector table parameters. */
|
||||
struct rte_swx_pipeline_selector_params {
|
||||
/** The group ID field. Input into the selection operation.
|
||||
* Restriction: This field must be a meta-data field.
|
||||
*/
|
||||
const char *group_id_field_name;
|
||||
|
||||
/** The set of fields used to select (through a hashing scheme) the
|
||||
* member within the current group. Inputs into the seletion operation.
|
||||
* Restriction: All the selector fields must be part of the same struct,
|
||||
* i.e. part of the same header or part of the meta-data structure.
|
||||
*/
|
||||
const char **selector_field_names;
|
||||
|
||||
/** The number of selector fields. Must be non-zero. */
|
||||
uint32_t n_selector_fields;
|
||||
|
||||
/** The member ID field. Output from the selection operation.
|
||||
* Restriction: This field must be a meta-data field.
|
||||
*/
|
||||
const char *member_id_field_name;
|
||||
|
||||
/** Maximum number of groups. Must be non-zero. */
|
||||
uint32_t n_groups_max;
|
||||
|
||||
/** Maximum number of members per group. Must be non-zero. */
|
||||
uint32_t n_members_per_group_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pipeline selector table configure
|
||||
*
|
||||
* @param[out] p
|
||||
* Pipeline handle.
|
||||
* @param[in] name
|
||||
* Selector table name.
|
||||
* @param[in] params
|
||||
* Selector table parameters.
|
||||
* @return
|
||||
* 0 on success or the following error codes otherwise:
|
||||
* -EINVAL: Invalid argument;
|
||||
* -ENOMEM: Not enough space/cannot allocate memory;
|
||||
* -EEXIST: Selector table with this name already exists;
|
||||
* -ENODEV: Selector table creation error.
|
||||
*/
|
||||
__rte_experimental
|
||||
int
|
||||
rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p,
|
||||
const char *name,
|
||||
struct rte_swx_pipeline_selector_params *params);
|
||||
|
||||
/**
|
||||
* Pipeline register array configure
|
||||
*
|
||||
|
@ -18,7 +18,9 @@
|
||||
#define TABLE_BLOCK 2
|
||||
#define TABLE_KEY_BLOCK 3
|
||||
#define TABLE_ACTIONS_BLOCK 4
|
||||
#define APPLY_BLOCK 5
|
||||
#define SELECTOR_BLOCK 5
|
||||
#define SELECTOR_SELECTOR_BLOCK 6
|
||||
#define APPLY_BLOCK 7
|
||||
|
||||
/*
|
||||
* extobj.
|
||||
@ -940,6 +942,307 @@ table_block_parse(struct table_spec *s,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* selector.
|
||||
*
|
||||
* selector SELECTOR_NAME {
|
||||
* group_id FIELD_NAME
|
||||
* selector {
|
||||
* FIELD_NAME
|
||||
* ...
|
||||
* }
|
||||
* member_id FIELD_NAME
|
||||
* n_groups N_GROUPS
|
||||
* n_members_per_group N_MEMBERS_PER_GROUP
|
||||
* }
|
||||
*/
|
||||
struct selector_spec {
|
||||
char *name;
|
||||
struct rte_swx_pipeline_selector_params params;
|
||||
};
|
||||
|
||||
static void
|
||||
selector_spec_free(struct selector_spec *s)
|
||||
{
|
||||
uintptr_t field_name;
|
||||
uint32_t i;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
/* name. */
|
||||
free(s->name);
|
||||
s->name = NULL;
|
||||
|
||||
/* params->group_id_field_name. */
|
||||
field_name = (uintptr_t)s->params.group_id_field_name;
|
||||
free((void *)field_name);
|
||||
s->params.group_id_field_name = NULL;
|
||||
|
||||
/* params->selector_field_names. */
|
||||
for (i = 0; i < s->params.n_selector_fields; i++) {
|
||||
field_name = (uintptr_t)s->params.selector_field_names[i];
|
||||
|
||||
free((void *)field_name);
|
||||
}
|
||||
|
||||
free(s->params.selector_field_names);
|
||||
s->params.selector_field_names = NULL;
|
||||
|
||||
s->params.n_selector_fields = 0;
|
||||
|
||||
/* params->member_id_field_name. */
|
||||
field_name = (uintptr_t)s->params.member_id_field_name;
|
||||
free((void *)field_name);
|
||||
s->params.member_id_field_name = NULL;
|
||||
|
||||
/* params->n_groups_max. */
|
||||
s->params.n_groups_max = 0;
|
||||
|
||||
/* params->n_members_per_group_max. */
|
||||
s->params.n_members_per_group_max = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_statement_parse(struct selector_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 selector 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 << SELECTOR_BLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_selector_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 selector statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* block_mask. */
|
||||
*block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_selector_block_parse(struct selector_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_fields;
|
||||
char *name;
|
||||
|
||||
/* Handle end of block. */
|
||||
if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
|
||||
*block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check input arguments. */
|
||||
if (n_tokens != 1) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid selector field statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
name = strdup(tokens[0]);
|
||||
if (!name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new_fields = realloc(s->params.selector_field_names,
|
||||
(s->params.n_selector_fields + 1) * sizeof(char *));
|
||||
if (!new_fields) {
|
||||
free(name);
|
||||
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s->params.selector_field_names = new_fields;
|
||||
s->params.selector_field_names[s->params.n_selector_fields] = name;
|
||||
s->params.n_selector_fields++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
selector_block_parse(struct selector_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 << SELECTOR_SELECTOR_BLOCK))
|
||||
return selector_selector_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 << SELECTOR_BLOCK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "group_id")) {
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid group_id statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->params.group_id_field_name = strdup(tokens[1]);
|
||||
if (!s->params.group_id_field_name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "selector"))
|
||||
return selector_selector_statement_parse(block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
|
||||
if (!strcmp(tokens[0], "member_id")) {
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid member_id statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->params.member_id_field_name = strdup(tokens[1]);
|
||||
if (!s->params.member_id_field_name) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Memory allocation failed.";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "n_groups_max")) {
|
||||
char *p = tokens[1];
|
||||
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid n_groups statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->params.n_groups_max = strtoul(p, &p, 0);
|
||||
if (p[0]) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid n_groups argument.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(tokens[0], "n_members_per_group_max")) {
|
||||
char *p = tokens[1];
|
||||
|
||||
if (n_tokens != 2) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid n_members_per_group statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->params.n_members_per_group_max = strtoul(p, &p, 0);
|
||||
if (p[0]) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid n_members_per_group argument.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Anything else. */
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Invalid statement.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* regarray.
|
||||
*
|
||||
@ -1203,6 +1506,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
struct metadata_spec metadata_spec = {0};
|
||||
struct action_spec action_spec = {0};
|
||||
struct table_spec table_spec = {0};
|
||||
struct selector_spec selector_spec = {0};
|
||||
struct regarray_spec regarray_spec = {0};
|
||||
struct metarray_spec metarray_spec = {0};
|
||||
struct apply_spec apply_spec = {0};
|
||||
@ -1386,6 +1690,38 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* selector block. */
|
||||
if (block_mask & (1 << SELECTOR_BLOCK)) {
|
||||
status = selector_block_parse(&selector_spec,
|
||||
&block_mask,
|
||||
tokens,
|
||||
n_tokens,
|
||||
n_lines,
|
||||
err_line,
|
||||
err_msg);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
if (block_mask & (1 << SELECTOR_BLOCK))
|
||||
continue;
|
||||
|
||||
/* End of block. */
|
||||
status = rte_swx_pipeline_selector_config(p,
|
||||
selector_spec.name,
|
||||
&selector_spec.params);
|
||||
if (status) {
|
||||
if (err_line)
|
||||
*err_line = n_lines;
|
||||
if (err_msg)
|
||||
*err_msg = "Selector configuration error.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
selector_spec_free(&selector_spec);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply block. */
|
||||
if (block_mask & (1 << APPLY_BLOCK)) {
|
||||
status = apply_block_parse(&apply_spec,
|
||||
@ -1544,6 +1880,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* selector. */
|
||||
if (!strcmp(tokens[0], "selector")) {
|
||||
status = selector_statement_parse(&selector_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,
|
||||
@ -1651,6 +2002,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
||||
metadata_spec_free(&metadata_spec);
|
||||
action_spec_free(&action_spec);
|
||||
table_spec_free(&table_spec);
|
||||
selector_spec_free(&selector_spec);
|
||||
regarray_spec_free(®array_spec);
|
||||
metarray_spec_free(&metarray_spec);
|
||||
apply_spec_free(&apply_spec);
|
||||
|
@ -116,4 +116,17 @@ EXPERIMENTAL {
|
||||
rte_swx_ctl_regarray_info_get;
|
||||
rte_swx_pipeline_metarray_config;
|
||||
rte_swx_pipeline_regarray_config;
|
||||
|
||||
#added in 21.08
|
||||
rte_swx_pipeline_selector_config;
|
||||
rte_swx_ctl_pipeline_selector_fprintf;
|
||||
rte_swx_ctl_pipeline_selector_group_add;
|
||||
rte_swx_ctl_pipeline_selector_group_delete;
|
||||
rte_swx_ctl_pipeline_selector_group_member_add;
|
||||
rte_swx_ctl_pipeline_selector_group_member_delete;
|
||||
rte_swx_ctl_pipeline_selector_stats_read;
|
||||
rte_swx_ctl_selector_info_get;
|
||||
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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user