app/testpmd: add flow template management

Add testpmd support for the rte_flow_pattern_template and
rte_flow_actions_template APIs. Provide the command line interface
for the template creation/destruction. Usage example:
  testpmd> flow pattern_template 0 create pattern_template_id 2
           template eth dst is 00:16:3e:31:15:c3 / end
  testpmd> flow actions_template 0 create actions_template_id 4
           template drop / end mask drop / end
  testpmd> flow actions_template 0 destroy actions_template 4
  testpmd> flow pattern_template 0 destroy pattern_template 2

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
This commit is contained in:
Alexander Kozyrev 2022-02-23 05:02:35 +02:00 committed by Ferruh Yigit
parent 9ad3a41ab2
commit 04cc665fab
4 changed files with 782 additions and 2 deletions

View File

@ -56,6 +56,8 @@ enum index {
COMMON_POLICY_ID,
COMMON_FLEX_HANDLE,
COMMON_FLEX_TOKEN,
COMMON_PATTERN_TEMPLATE_ID,
COMMON_ACTIONS_TEMPLATE_ID,
/* TOP-level command. */
ADD,
@ -74,6 +76,8 @@ enum index {
/* Sub-level commands. */
INFO,
CONFIGURE,
PATTERN_TEMPLATE,
ACTIONS_TEMPLATE,
INDIRECT_ACTION,
VALIDATE,
CREATE,
@ -92,6 +96,28 @@ enum index {
FLEX_ITEM_CREATE,
FLEX_ITEM_DESTROY,
/* Pattern template arguments. */
PATTERN_TEMPLATE_CREATE,
PATTERN_TEMPLATE_DESTROY,
PATTERN_TEMPLATE_CREATE_ID,
PATTERN_TEMPLATE_DESTROY_ID,
PATTERN_TEMPLATE_RELAXED_MATCHING,
PATTERN_TEMPLATE_INGRESS,
PATTERN_TEMPLATE_EGRESS,
PATTERN_TEMPLATE_TRANSFER,
PATTERN_TEMPLATE_SPEC,
/* Actions template arguments. */
ACTIONS_TEMPLATE_CREATE,
ACTIONS_TEMPLATE_DESTROY,
ACTIONS_TEMPLATE_CREATE_ID,
ACTIONS_TEMPLATE_DESTROY_ID,
ACTIONS_TEMPLATE_INGRESS,
ACTIONS_TEMPLATE_EGRESS,
ACTIONS_TEMPLATE_TRANSFER,
ACTIONS_TEMPLATE_SPEC,
ACTIONS_TEMPLATE_MASK,
/* Tunnel arguments. */
TUNNEL_CREATE,
TUNNEL_CREATE_TYPE,
@ -882,6 +908,10 @@ struct buffer {
uint32_t nb_queue;
struct rte_flow_queue_attr queue_attr;
} configure; /**< Configuration arguments. */
struct {
uint32_t *template_id;
uint32_t template_id_n;
} templ_destroy; /**< Template destroy arguments. */
struct {
uint32_t *action_id;
uint32_t action_id_n;
@ -890,10 +920,13 @@ struct buffer {
uint32_t action_id;
} ia; /* Indirect action query arguments */
struct {
uint32_t pat_templ_id;
uint32_t act_templ_id;
struct rte_flow_attr attr;
struct tunnel_ops tunnel_ops;
struct rte_flow_item *pattern;
struct rte_flow_action *actions;
struct rte_flow_action *masks;
uint32_t pattern_n;
uint32_t actions_n;
uint8_t *data;
@ -973,6 +1006,49 @@ static const enum index next_config_attr[] = {
ZERO,
};
static const enum index next_pt_subcmd[] = {
PATTERN_TEMPLATE_CREATE,
PATTERN_TEMPLATE_DESTROY,
ZERO,
};
static const enum index next_pt_attr[] = {
PATTERN_TEMPLATE_CREATE_ID,
PATTERN_TEMPLATE_RELAXED_MATCHING,
PATTERN_TEMPLATE_INGRESS,
PATTERN_TEMPLATE_EGRESS,
PATTERN_TEMPLATE_TRANSFER,
PATTERN_TEMPLATE_SPEC,
ZERO,
};
static const enum index next_pt_destroy_attr[] = {
PATTERN_TEMPLATE_DESTROY_ID,
END,
ZERO,
};
static const enum index next_at_subcmd[] = {
ACTIONS_TEMPLATE_CREATE,
ACTIONS_TEMPLATE_DESTROY,
ZERO,
};
static const enum index next_at_attr[] = {
ACTIONS_TEMPLATE_CREATE_ID,
ACTIONS_TEMPLATE_INGRESS,
ACTIONS_TEMPLATE_EGRESS,
ACTIONS_TEMPLATE_TRANSFER,
ACTIONS_TEMPLATE_SPEC,
ZERO,
};
static const enum index next_at_destroy_attr[] = {
ACTIONS_TEMPLATE_DESTROY_ID,
END,
ZERO,
};
static const enum index next_ia_create_attr[] = {
INDIRECT_ACTION_CREATE_ID,
INDIRECT_ACTION_INGRESS,
@ -2072,6 +2148,12 @@ static int parse_isolate(struct context *, const struct token *,
static int parse_configure(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
static int parse_template(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
static int parse_template_destroy(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
static int parse_tunnel(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@ -2141,6 +2223,10 @@ static int comp_set_modify_field_op(struct context *, const struct token *,
unsigned int, char *, unsigned int);
static int comp_set_modify_field_id(struct context *, const struct token *,
unsigned int, char *, unsigned int);
static int comp_pattern_template_id(struct context *, const struct token *,
unsigned int, char *, unsigned int);
static int comp_actions_template_id(struct context *, const struct token *,
unsigned int, char *, unsigned int);
/** Token definitions. */
static const struct token token_list[] = {
@ -2291,6 +2377,20 @@ static const struct token token_list[] = {
.call = parse_flex_handle,
.comp = comp_none,
},
[COMMON_PATTERN_TEMPLATE_ID] = {
.name = "{pattern_template_id}",
.type = "PATTERN_TEMPLATE_ID",
.help = "pattern template id",
.call = parse_int,
.comp = comp_pattern_template_id,
},
[COMMON_ACTIONS_TEMPLATE_ID] = {
.name = "{actions_template_id}",
.type = "ACTIONS_TEMPLATE_ID",
.help = "actions template id",
.call = parse_int,
.comp = comp_actions_template_id,
},
/* Top-level command. */
[FLOW] = {
.name = "flow",
@ -2299,6 +2399,8 @@ static const struct token token_list[] = {
.next = NEXT(NEXT_ENTRY
(INFO,
CONFIGURE,
PATTERN_TEMPLATE,
ACTIONS_TEMPLATE,
INDIRECT_ACTION,
VALIDATE,
CREATE,
@ -2373,6 +2475,148 @@ static const struct token token_list[] = {
args.configure.port_attr.nb_meters)),
},
/* Top-level command. */
[PATTERN_TEMPLATE] = {
.name = "pattern_template",
.type = "{command} {port_id} [{arg} [...]]",
.help = "manage pattern templates",
.next = NEXT(next_pt_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_template,
},
/* Sub-level commands. */
[PATTERN_TEMPLATE_CREATE] = {
.name = "create",
.help = "create pattern template",
.next = NEXT(next_pt_attr),
.call = parse_template,
},
[PATTERN_TEMPLATE_DESTROY] = {
.name = "destroy",
.help = "destroy pattern template",
.next = NEXT(NEXT_ENTRY(PATTERN_TEMPLATE_DESTROY_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_template_destroy,
},
/* Pattern template arguments. */
[PATTERN_TEMPLATE_CREATE_ID] = {
.name = "pattern_template_id",
.help = "specify a pattern template id to create",
.next = NEXT(next_pt_attr,
NEXT_ENTRY(COMMON_PATTERN_TEMPLATE_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, args.vc.pat_templ_id)),
},
[PATTERN_TEMPLATE_DESTROY_ID] = {
.name = "pattern_template",
.help = "specify a pattern template id to destroy",
.next = NEXT(next_pt_destroy_attr,
NEXT_ENTRY(COMMON_PATTERN_TEMPLATE_ID)),
.args = ARGS(ARGS_ENTRY_PTR(struct buffer,
args.templ_destroy.template_id)),
.call = parse_template_destroy,
},
[PATTERN_TEMPLATE_RELAXED_MATCHING] = {
.name = "relaxed",
.help = "is matching relaxed",
.next = NEXT(next_pt_attr,
NEXT_ENTRY(COMMON_BOOLEAN)),
.args = ARGS(ARGS_ENTRY_BF(struct buffer,
args.vc.attr.reserved, 1)),
},
[PATTERN_TEMPLATE_INGRESS] = {
.name = "ingress",
.help = "attribute pattern to ingress",
.next = NEXT(next_pt_attr),
.call = parse_template,
},
[PATTERN_TEMPLATE_EGRESS] = {
.name = "egress",
.help = "attribute pattern to egress",
.next = NEXT(next_pt_attr),
.call = parse_template,
},
[PATTERN_TEMPLATE_TRANSFER] = {
.name = "transfer",
.help = "attribute pattern to transfer",
.next = NEXT(next_pt_attr),
.call = parse_template,
},
[PATTERN_TEMPLATE_SPEC] = {
.name = "template",
.help = "specify item to create pattern template",
.next = NEXT(next_item),
},
/* Top-level command. */
[ACTIONS_TEMPLATE] = {
.name = "actions_template",
.type = "{command} {port_id} [{arg} [...]]",
.help = "manage actions templates",
.next = NEXT(next_at_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_template,
},
/* Sub-level commands. */
[ACTIONS_TEMPLATE_CREATE] = {
.name = "create",
.help = "create actions template",
.next = NEXT(next_at_attr),
.call = parse_template,
},
[ACTIONS_TEMPLATE_DESTROY] = {
.name = "destroy",
.help = "destroy actions template",
.next = NEXT(NEXT_ENTRY(ACTIONS_TEMPLATE_DESTROY_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_template_destroy,
},
/* Actions template arguments. */
[ACTIONS_TEMPLATE_CREATE_ID] = {
.name = "actions_template_id",
.help = "specify an actions template id to create",
.next = NEXT(NEXT_ENTRY(ACTIONS_TEMPLATE_MASK),
NEXT_ENTRY(ACTIONS_TEMPLATE_SPEC),
NEXT_ENTRY(COMMON_ACTIONS_TEMPLATE_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, args.vc.act_templ_id)),
},
[ACTIONS_TEMPLATE_DESTROY_ID] = {
.name = "actions_template",
.help = "specify an actions template id to destroy",
.next = NEXT(next_at_destroy_attr,
NEXT_ENTRY(COMMON_ACTIONS_TEMPLATE_ID)),
.args = ARGS(ARGS_ENTRY_PTR(struct buffer,
args.templ_destroy.template_id)),
.call = parse_template_destroy,
},
[ACTIONS_TEMPLATE_INGRESS] = {
.name = "ingress",
.help = "attribute actions to ingress",
.next = NEXT(next_at_attr),
.call = parse_template,
},
[ACTIONS_TEMPLATE_EGRESS] = {
.name = "egress",
.help = "attribute actions to egress",
.next = NEXT(next_at_attr),
.call = parse_template,
},
[ACTIONS_TEMPLATE_TRANSFER] = {
.name = "transfer",
.help = "attribute actions to transfer",
.next = NEXT(next_at_attr),
.call = parse_template,
},
[ACTIONS_TEMPLATE_SPEC] = {
.name = "template",
.help = "specify action to create actions template",
.next = NEXT(next_action),
.call = parse_template,
},
[ACTIONS_TEMPLATE_MASK] = {
.name = "mask",
.help = "specify action mask to create actions template",
.next = NEXT(next_action),
.call = parse_template,
},
/* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
.type = "{command} {port_id} [{arg} [...]]",
@ -2695,7 +2939,7 @@ static const struct token token_list[] = {
.name = "end",
.help = "end list of pattern items",
.priv = PRIV_ITEM(END, 0),
.next = NEXT(NEXT_ENTRY(ACTIONS)),
.next = NEXT(NEXT_ENTRY(ACTIONS, END)),
.call = parse_vc,
},
[ITEM_VOID] = {
@ -5975,7 +6219,9 @@ parse_vc(struct context *ctx, const struct token *token,
if (!out)
return len;
if (!out->command) {
if (ctx->curr != VALIDATE && ctx->curr != CREATE)
if (ctx->curr != VALIDATE && ctx->curr != CREATE &&
ctx->curr != PATTERN_TEMPLATE_CREATE &&
ctx->curr != ACTIONS_TEMPLATE_CREATE)
return -1;
if (sizeof(*out) > size)
return -1;
@ -7851,6 +8097,132 @@ parse_configure(struct context *ctx, const struct token *token,
return len;
}
/** Parse tokens for template create command. */
static int
parse_template(struct context *ctx, const struct token *token,
const char *str, unsigned int len,
void *buf, unsigned int size)
{
struct buffer *out = buf;
/* Token name must match. */
if (parse_default(ctx, token, str, len, NULL, 0) < 0)
return -1;
/* Nothing else to do if there is no buffer. */
if (!out)
return len;
if (!out->command) {
if (ctx->curr != PATTERN_TEMPLATE &&
ctx->curr != ACTIONS_TEMPLATE)
return -1;
if (sizeof(*out) > size)
return -1;
out->command = ctx->curr;
ctx->objdata = 0;
ctx->object = out;
ctx->objmask = NULL;
out->args.vc.data = (uint8_t *)out + size;
return len;
}
switch (ctx->curr) {
case PATTERN_TEMPLATE_CREATE:
out->args.vc.pattern =
(void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
sizeof(double));
out->args.vc.pat_templ_id = UINT32_MAX;
out->command = ctx->curr;
ctx->objdata = 0;
ctx->object = out;
ctx->objmask = NULL;
return len;
case PATTERN_TEMPLATE_EGRESS:
out->args.vc.attr.egress = 1;
return len;
case PATTERN_TEMPLATE_INGRESS:
out->args.vc.attr.ingress = 1;
return len;
case PATTERN_TEMPLATE_TRANSFER:
out->args.vc.attr.transfer = 1;
return len;
case ACTIONS_TEMPLATE_CREATE:
out->args.vc.act_templ_id = UINT32_MAX;
out->command = ctx->curr;
ctx->objdata = 0;
ctx->object = out;
ctx->objmask = NULL;
return len;
case ACTIONS_TEMPLATE_SPEC:
out->args.vc.actions =
(void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
sizeof(double));
ctx->object = out->args.vc.actions;
ctx->objmask = NULL;
return len;
case ACTIONS_TEMPLATE_MASK:
out->args.vc.masks =
(void *)RTE_ALIGN_CEIL((uintptr_t)
(out->args.vc.actions +
out->args.vc.actions_n),
sizeof(double));
ctx->object = out->args.vc.masks;
ctx->objmask = NULL;
return len;
case ACTIONS_TEMPLATE_EGRESS:
out->args.vc.attr.egress = 1;
return len;
case ACTIONS_TEMPLATE_INGRESS:
out->args.vc.attr.ingress = 1;
return len;
case ACTIONS_TEMPLATE_TRANSFER:
out->args.vc.attr.transfer = 1;
return len;
default:
return -1;
}
}
/** Parse tokens for template destroy command. */
static int
parse_template_destroy(struct context *ctx, const struct token *token,
const char *str, unsigned int len,
void *buf, unsigned int size)
{
struct buffer *out = buf;
uint32_t *template_id;
/* Token name must match. */
if (parse_default(ctx, token, str, len, NULL, 0) < 0)
return -1;
/* Nothing else to do if there is no buffer. */
if (!out)
return len;
if (!out->command ||
out->command == PATTERN_TEMPLATE ||
out->command == ACTIONS_TEMPLATE) {
if (ctx->curr != PATTERN_TEMPLATE_DESTROY &&
ctx->curr != ACTIONS_TEMPLATE_DESTROY)
return -1;
if (sizeof(*out) > size)
return -1;
out->command = ctx->curr;
ctx->objdata = 0;
ctx->object = out;
ctx->objmask = NULL;
out->args.templ_destroy.template_id =
(void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
sizeof(double));
return len;
}
template_id = out->args.templ_destroy.template_id
+ out->args.templ_destroy.template_id_n++;
if ((uint8_t *)template_id > (uint8_t *)out + size)
return -1;
ctx->objdata = 0;
ctx->object = template_id;
ctx->objmask = NULL;
return len;
}
static int
parse_flex(struct context *ctx, const struct token *token,
const char *str, unsigned int len,
@ -8820,6 +9192,54 @@ comp_set_modify_field_id(struct context *ctx, const struct token *token,
return -1;
}
/** Complete available pattern template IDs. */
static int
comp_pattern_template_id(struct context *ctx, const struct token *token,
unsigned int ent, char *buf, unsigned int size)
{
unsigned int i = 0;
struct rte_port *port;
struct port_template *pt;
(void)token;
if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
ctx->port == (portid_t)RTE_PORT_ALL)
return -1;
port = &ports[ctx->port];
for (pt = port->pattern_templ_list; pt != NULL; pt = pt->next) {
if (buf && i == ent)
return snprintf(buf, size, "%u", pt->id);
++i;
}
if (buf)
return -1;
return i;
}
/** Complete available actions template IDs. */
static int
comp_actions_template_id(struct context *ctx, const struct token *token,
unsigned int ent, char *buf, unsigned int size)
{
unsigned int i = 0;
struct rte_port *port;
struct port_template *pt;
(void)token;
if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
ctx->port == (portid_t)RTE_PORT_ALL)
return -1;
port = &ports[ctx->port];
for (pt = port->actions_templ_list; pt != NULL; pt = pt->next) {
if (buf && i == ent)
return snprintf(buf, size, "%u", pt->id);
++i;
}
if (buf)
return -1;
return i;
}
/** Internal context. */
static struct context cmd_flow_context;
@ -9088,6 +9508,38 @@ cmd_flow_parsed(const struct buffer *in)
in->args.configure.nb_queue,
&in->args.configure.queue_attr);
break;
case PATTERN_TEMPLATE_CREATE:
port_flow_pattern_template_create(in->port,
in->args.vc.pat_templ_id,
&((const struct rte_flow_pattern_template_attr) {
.relaxed_matching = in->args.vc.attr.reserved,
.ingress = in->args.vc.attr.ingress,
.egress = in->args.vc.attr.egress,
.transfer = in->args.vc.attr.transfer,
}),
in->args.vc.pattern);
break;
case PATTERN_TEMPLATE_DESTROY:
port_flow_pattern_template_destroy(in->port,
in->args.templ_destroy.template_id_n,
in->args.templ_destroy.template_id);
break;
case ACTIONS_TEMPLATE_CREATE:
port_flow_actions_template_create(in->port,
in->args.vc.act_templ_id,
&((const struct rte_flow_actions_template_attr) {
.ingress = in->args.vc.attr.ingress,
.egress = in->args.vc.attr.egress,
.transfer = in->args.vc.attr.transfer,
}),
in->args.vc.actions,
in->args.vc.masks);
break;
case ACTIONS_TEMPLATE_DESTROY:
port_flow_actions_template_destroy(in->port,
in->args.templ_destroy.template_id_n,
in->args.templ_destroy.template_id);
break;
case INDIRECT_ACTION_CREATE:
port_action_handle_create(
in->port, in->args.vc.attr.group,

View File

@ -1610,6 +1610,49 @@ action_alloc(portid_t port_id, uint32_t id,
return 0;
}
static int
template_alloc(uint32_t id, struct port_template **template,
struct port_template **list)
{
struct port_template *lst = *list;
struct port_template **ppt;
struct port_template *pt = NULL;
*template = NULL;
if (id == UINT32_MAX) {
/* taking first available ID */
if (lst) {
if (lst->id == UINT32_MAX - 1) {
printf("Highest template ID is already"
" assigned, delete it first\n");
return -ENOMEM;
}
id = lst->id + 1;
} else {
id = 0;
}
}
pt = calloc(1, sizeof(*pt));
if (!pt) {
printf("Allocation of port template failed\n");
return -ENOMEM;
}
ppt = list;
while (*ppt && (*ppt)->id > id)
ppt = &(*ppt)->next;
if (*ppt && (*ppt)->id == id) {
printf("Template #%u is already assigned,"
" delete it first\n", id);
free(pt);
return -EINVAL;
}
pt->next = *ppt;
pt->id = id;
*ppt = pt;
*template = pt;
return 0;
}
/** Get info about flow management resources. */
int
port_flow_get_info(portid_t port_id)
@ -2086,6 +2129,166 @@ age_action_get(const struct rte_flow_action *actions)
return NULL;
}
/** Create pattern template */
int
port_flow_pattern_template_create(portid_t port_id, uint32_t id,
const struct rte_flow_pattern_template_attr *attr,
const struct rte_flow_item *pattern)
{
struct rte_port *port;
struct port_template *pit;
int ret;
struct rte_flow_error error;
if (port_id_is_invalid(port_id, ENABLED_WARN) ||
port_id == (portid_t)RTE_PORT_ALL)
return -EINVAL;
port = &ports[port_id];
ret = template_alloc(id, &pit, &port->pattern_templ_list);
if (ret)
return ret;
/* Poisoning to make sure PMDs update it in case of error. */
memset(&error, 0x22, sizeof(error));
pit->template.pattern_template = rte_flow_pattern_template_create(port_id,
attr, pattern, &error);
if (!pit->template.pattern_template) {
uint32_t destroy_id = pit->id;
port_flow_pattern_template_destroy(port_id, 1, &destroy_id);
return port_flow_complain(&error);
}
printf("Pattern template #%u created\n", pit->id);
return 0;
}
/** Destroy pattern template */
int
port_flow_pattern_template_destroy(portid_t port_id, uint32_t n,
const uint32_t *template)
{
struct rte_port *port;
struct port_template **tmp;
uint32_t c = 0;
int ret = 0;
if (port_id_is_invalid(port_id, ENABLED_WARN) ||
port_id == (portid_t)RTE_PORT_ALL)
return -EINVAL;
port = &ports[port_id];
tmp = &port->pattern_templ_list;
while (*tmp) {
uint32_t i;
for (i = 0; i != n; ++i) {
struct rte_flow_error error;
struct port_template *pit = *tmp;
if (template[i] != pit->id)
continue;
/*
* Poisoning to make sure PMDs update it in case
* of error.
*/
memset(&error, 0x33, sizeof(error));
if (pit->template.pattern_template &&
rte_flow_pattern_template_destroy(port_id,
pit->template.pattern_template,
&error)) {
ret = port_flow_complain(&error);
continue;
}
*tmp = pit->next;
printf("Pattern template #%u destroyed\n", pit->id);
free(pit);
break;
}
if (i == n)
tmp = &(*tmp)->next;
++c;
}
return ret;
}
/** Create actions template */
int
port_flow_actions_template_create(portid_t port_id, uint32_t id,
const struct rte_flow_actions_template_attr *attr,
const struct rte_flow_action *actions,
const struct rte_flow_action *masks)
{
struct rte_port *port;
struct port_template *pat;
int ret;
struct rte_flow_error error;
if (port_id_is_invalid(port_id, ENABLED_WARN) ||
port_id == (portid_t)RTE_PORT_ALL)
return -EINVAL;
port = &ports[port_id];
ret = template_alloc(id, &pat, &port->actions_templ_list);
if (ret)
return ret;
/* Poisoning to make sure PMDs update it in case of error. */
memset(&error, 0x22, sizeof(error));
pat->template.actions_template = rte_flow_actions_template_create(port_id,
attr, actions, masks, &error);
if (!pat->template.actions_template) {
uint32_t destroy_id = pat->id;
port_flow_actions_template_destroy(port_id, 1, &destroy_id);
return port_flow_complain(&error);
}
printf("Actions template #%u created\n", pat->id);
return 0;
}
/** Destroy actions template */
int
port_flow_actions_template_destroy(portid_t port_id, uint32_t n,
const uint32_t *template)
{
struct rte_port *port;
struct port_template **tmp;
uint32_t c = 0;
int ret = 0;
if (port_id_is_invalid(port_id, ENABLED_WARN) ||
port_id == (portid_t)RTE_PORT_ALL)
return -EINVAL;
port = &ports[port_id];
tmp = &port->actions_templ_list;
while (*tmp) {
uint32_t i;
for (i = 0; i != n; ++i) {
struct rte_flow_error error;
struct port_template *pat = *tmp;
if (template[i] != pat->id)
continue;
/*
* Poisoning to make sure PMDs update it in case
* of error.
*/
memset(&error, 0x33, sizeof(error));
if (pat->template.actions_template &&
rte_flow_actions_template_destroy(port_id,
pat->template.actions_template, &error)) {
ret = port_flow_complain(&error);
continue;
}
*tmp = pat->next;
printf("Actions template #%u destroyed\n", pat->id);
free(pat);
break;
}
if (i == n)
tmp = &(*tmp)->next;
++c;
}
return ret;
}
/** Create flow rule. */
int
port_flow_create(portid_t port_id,

View File

@ -166,6 +166,17 @@ enum age_action_context_type {
ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION,
};
/** Descriptor for a template. */
struct port_template {
struct port_template *next; /**< Next template in list. */
struct port_template *tmp; /**< Temporary linking. */
uint32_t id; /**< Template ID. */
union {
struct rte_flow_pattern_template *pattern_template;
struct rte_flow_actions_template *actions_template;
} template; /**< PMD opaque template object */
};
/** Descriptor for a single flow. */
struct port_flow {
struct port_flow *next; /**< Next flow in list. */
@ -246,6 +257,8 @@ struct rte_port {
queueid_t queue_nb; /**< nb. of queues for flow rules */
uint32_t queue_sz; /**< size of a queue for flow rules */
uint8_t slave_flag; /**< bonding slave port */
struct port_template *pattern_templ_list; /**< Pattern templates. */
struct port_template *actions_templ_list; /**< Actions templates. */
struct port_flow *flow_list; /**< Associated flows. */
struct port_indirect_action *actions_list;
/**< Associated indirect actions. */
@ -892,6 +905,17 @@ int port_flow_configure(portid_t port_id,
const struct rte_flow_port_attr *port_attr,
uint16_t nb_queue,
const struct rte_flow_queue_attr *queue_attr);
int port_flow_pattern_template_create(portid_t port_id, uint32_t id,
const struct rte_flow_pattern_template_attr *attr,
const struct rte_flow_item *pattern);
int port_flow_pattern_template_destroy(portid_t port_id, uint32_t n,
const uint32_t *template);
int port_flow_actions_template_create(portid_t port_id, uint32_t id,
const struct rte_flow_actions_template_attr *attr,
const struct rte_flow_action *actions,
const struct rte_flow_action *masks);
int port_flow_actions_template_destroy(portid_t port_id, uint32_t n,
const uint32_t *template);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
const struct rte_flow_item *pattern,

View File

@ -3344,6 +3344,26 @@ following sections.
[aging_counters_number {number}]
[meters_number {number}]
- Create a pattern template::
flow pattern_template {port_id} create [pattern_template_id {id}]
[relaxed {boolean}] [ingress] [egress] [transfer]
template {item} [/ {item} [...]] / end
- Destroy a pattern template::
flow pattern_template {port_id} destroy pattern_template {id} [...]
- Create an actions template::
flow actions_template {port_id} create [actions_template_id {id}]
[ingress] [egress] [transfer]
template {action} [/ {action} [...]] / end
mask {action} [/ {action} [...]] / end
- Destroy an actions template::
flow actions_template {port_id} destroy actions_template {id} [...]
- Check whether a flow rule can be created::
flow validate {port_id}
@ -3448,6 +3468,87 @@ Otherwise it will show an error message of the form::
Caught error type [...] ([...]): [...]
Creating pattern templates
~~~~~~~~~~~~~~~~~~~~~~~~~~
``flow pattern_template create`` creates the specified pattern template.
It is bound to ``rte_flow_pattern_template_create()``::
flow pattern_template {port_id} create [pattern_template_id {id}]
[relaxed {boolean}] [ingress] [egress] [transfer]
template {item} [/ {item} [...]] / end
If successful, it will show::
Pattern template #[...] created
Otherwise it will show an error message of the form::
Caught error type [...] ([...]): [...]
This command uses the same pattern items as ``flow create``,
their format is described in `Creating flow rules`_.
Destroying pattern templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``flow pattern_template destroy`` destroys one or more pattern templates
from their template ID (as returned by ``flow pattern_template create``),
this command calls ``rte_flow_pattern_template_destroy()`` as many
times as necessary::
flow pattern_template {port_id} destroy pattern_template {id} [...]
If successful, it will show::
Pattern template #[...] destroyed
It does not report anything for pattern template IDs that do not exist.
The usual error message is shown when a pattern template cannot be destroyed::
Caught error type [...] ([...]): [...]
Creating actions templates
~~~~~~~~~~~~~~~~~~~~~~~~~~
``flow actions_template create`` creates the specified actions template.
It is bound to ``rte_flow_actions_template_create()``::
flow actions_template {port_id} create [actions_template_id {id}]
[ingress] [egress] [transfer]
template {action} [/ {action} [...]] / end
mask {action} [/ {action} [...]] / end
If successful, it will show::
Actions template #[...] created
Otherwise it will show an error message of the form::
Caught error type [...] ([...]): [...]
This command uses the same actions as ``flow create``,
their format is described in `Creating flow rules`_.
Destroying actions templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``flow actions_template destroy`` destroys one or more actions templates
from their template ID (as returned by ``flow actions_template create``),
this command calls ``rte_flow_actions_template_destroy()`` as many
times as necessary::
flow actions_template {port_id} destroy actions_template {id} [...]
If successful, it will show::
Actions template #[...] destroyed
It does not report anything for actions template IDs that do not exist.
The usual error message is shown when an actions template cannot be destroyed::
Caught error type [...] ([...]): [...]
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~