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:
parent
9ad3a41ab2
commit
04cc665fab
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user