Parsing command line for rte_flow_action_prog. Syntax:
"prog name <name> [arguments <arg_name_0> <arg_value_0> \ <arg_name_1> <arg_value1> ... end]" Use parse_string0 to parse name string. Use parse_hex to parse hex string. Use struct action_prog_data to store parsed result. Example: Action with 2 arguments: "prog name action0 arguments field0 03FF field1 55AA end" Action without argument: "prog name action1" Signed-off-by: Qi Zhang <qi.z.zh...@intel.com> --- v6: - fix typo. v5: - complete testpmd document. v4: - be more generous on the max size of name and value. v3: - refine struct action_prog_data - enlarge the max size v2: - fix title - minor coding style refine. app/test-pmd/cmdline_flow.c | 232 ++++++++++++++++++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 17 ++ 2 files changed, 249 insertions(+) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 70eef3e34d..d9152f9485 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -721,6 +721,13 @@ enum index { ACTION_IPV6_EXT_PUSH, ACTION_IPV6_EXT_PUSH_INDEX, ACTION_IPV6_EXT_PUSH_INDEX_VALUE, + ACTION_PROG, + ACTION_PROG_NAME, + ACTION_PROG_NAME_STRING, + ACTION_PROG_ARGUMENTS, + ACTION_PROG_ARG_NAME, + ACTION_PROG_ARG_VALUE, + ACTION_PROG_ARG_END, }; /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -751,6 +758,23 @@ struct action_rss_data { uint16_t queue[ACTION_RSS_QUEUE_NUM]; }; +#define ACTION_PROG_NAME_SIZE_MAX 256 +#define ACTION_PROG_ARG_NUM_MAX 16 +#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64 + +/** Storage for struct rte_flow_action_prog including external data. */ +struct action_prog_data { + struct rte_flow_action_prog conf; + struct { + char name[ACTION_PROG_NAME_SIZE_MAX]; + struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX]; + struct { + char names[ACTION_PROG_NAME_SIZE_MAX]; + uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX]; + } arg_data[ACTION_PROG_ARG_NUM_MAX]; + } data; +}; + /** Maximum data size in struct rte_flow_action_raw_encap. */ #define ACTION_RAW_ENCAP_MAX_DATA 512 #define RAW_ENCAP_CONFS_MAX_NUM 8 @@ -2178,6 +2202,7 @@ static const enum index next_action[] = { ACTION_QUOTA_QU, ACTION_IPV6_EXT_REMOVE, ACTION_IPV6_EXT_PUSH, + ACTION_PROG, ZERO, }; @@ -2519,6 +2544,13 @@ static const enum index action_represented_port[] = { ZERO, }; +static const enum index action_prog[] = { + ACTION_PROG_NAME, + ACTION_PROG_ARGUMENTS, + ACTION_NEXT, + ZERO, +}; + static int parse_set_raw_encap_decap(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -2795,6 +2827,18 @@ static int parse_qu_mode_name(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, unsigned int size); +static int +parse_vc_action_prog(struct context *, const struct token *, + const char *, unsigned int, void *, + unsigned int); +static int +parse_vc_action_prog_arg_name(struct context *, const struct token *, + const char *, unsigned int, void *, + unsigned int); +static int +parse_vc_action_prog_arg_value(struct context *, const struct token *, + const char *, unsigned int, void *, + unsigned int); static int comp_none(struct context *, const struct token *, unsigned int, char *, unsigned int); static int comp_boolean(struct context *, const struct token *, @@ -7543,6 +7587,48 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue, tx_queue)), }, + [ACTION_PROG] = { + .name = "prog", + .help = "match a programmable action", + .priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)), + .next = NEXT(action_prog), + .call = parse_vc_action_prog, + }, + [ACTION_PROG_NAME] = { + .name = "name", + .help = "programble action name", + .next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)), + .args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)), + }, + [ACTION_PROG_NAME_STRING] = { + .name = "{string}", + .type = "STRING", + .help = "programmable action name string", + .call = parse_string0, + }, + [ACTION_PROG_ARGUMENTS] = { + .name = "arguments", + .help = "programmable action name", + .next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)), + .call = parse_vc_conf, + }, + [ACTION_PROG_ARG_NAME] = { + .name = "{string}", + .help = "programmable action argument name", + .next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)), + .call = parse_vc_action_prog_arg_name, + }, + [ACTION_PROG_ARG_VALUE] = { + .name = "{hex}", + .help = "programmable action argument value", + .next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)), + .call = parse_vc_action_prog_arg_value, + }, + [ACTION_PROG_ARG_END] = { + .name = "end", + .help = "end of the programmable action arguments", + }, + }; /** Remove and return last entry from argument stack. */ @@ -11700,6 +11786,152 @@ parse_qu_mode_name(struct context *ctx, const struct token *token, (uint32_t *)&out->args.ia.qu_mode); } +/** Parse prog action. */ +static int +parse_vc_action_prog(struct context *ctx, const struct token *token, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + struct buffer *out = buf; + struct rte_flow_action *action; + struct action_prog_data *action_prog_data; + uint16_t i; + int ret; + + ret = parse_vc(ctx, token, str, len, buf, size); + if (ret < 0) + return ret; + + if (!out) + return ret; + + if (!out->args.vc.actions_n) + return -1; + + action = &out->args.vc.actions[out->args.vc.actions_n - 1]; + ctx->object = out->args.vc.data; + action_prog_data = ctx->object; + *action_prog_data = (struct action_prog_data) { + .conf = (struct rte_flow_action_prog) { + .args_num = 0, + .name = action_prog_data->data.name, + .args = action_prog_data->data.args, + }, + }; + + for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i) + action_prog_data->data.args[i].name = action_prog_data->data.arg_data[i].names; + action->conf = &action_prog_data->conf; + + return ret; +} + +static int +parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + struct action_prog_data *action_prog_data; + struct buffer *out = buf; + const struct arg *arg; + uint32_t i; + int ret; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_PROG_ARG_NAME) + return -1; + + if (!out) + return len; + + action_prog_data = (void *)out->args.vc.data; + i = action_prog_data->conf.args_num; + + if (i >= ACTION_PROG_ARG_NUM_MAX) + return -1; + + arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, + data.arg_data[i].names), + ACTION_PROG_NAME_SIZE_MAX); + + if (push_args(ctx, arg)) + return -1; + + ret = parse_string0(ctx, token, str, len, NULL, 0); + if (ret < 0) { + pop_args(ctx); + return -1; + } + + return len; +} + +static int +parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + struct action_prog_data *action_prog_data; + const struct arg *arg_addr; + const struct arg *arg_size; + const struct arg *arg_data; + struct buffer *out = buf; + uint32_t i; + int ret; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_PROG_ARG_VALUE) + return -1; + + if (!out) + return len; + + action_prog_data = (void *)out->args.vc.data; + i = action_prog_data->conf.args_num; + + arg_addr = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, + data.args[i].value), + sizeof(action_prog_data->data.args[i].value)); + + arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, + data.args[i].size), + sizeof(action_prog_data->data.args[i].size)); + + arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, + data.arg_data[i].value), + ACTION_PROG_ARG_VALUE_SIZE_MAX); + + if (push_args(ctx, arg_addr)) + return -1; + + if (push_args(ctx, arg_size)) { + pop_args(ctx); + return -1; + } + + if (push_args(ctx, arg_data)) { + pop_args(ctx); + pop_args(ctx); + return -1; + } + + ret = parse_hex(ctx, token, str, len, NULL, 0); + if (ret < 0) { + pop_args(ctx); + pop_args(ctx); + pop_args(ctx); + return -1; + } + + action_prog_data->conf.args_num++; + + return len; +} + /** No completion. */ static int comp_none(struct context *ctx, const struct token *token, diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 67968ecb7f..84be67625a 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -4108,6 +4108,14 @@ This section lists supported actions and their attributes, if any. - ``mtr_init_color {value}``: initial color value (green/yellow/red) - ``mtr_state {unsigned}``: meter state (disabled/enabled) +- ``prog``: Set a Programmable Action that aligns with the current device + configuration, typically intended for use with a P4 programmable device. + + - ``name {string}``: The name of a Programmable Action schema + - ``arguments [{string} {hex string} [...]] end``: It is optional, the names + and values of each argument for the Programmable Action in a list, the + name is represented as {string} and value is represented as {hex string} + Destroying flow rules ~~~~~~~~~~~~~~~~~~~~~ @@ -5262,6 +5270,15 @@ A RAW rule can be created as following using ``pattern_hex`` key and mask. pattern_hex mask 0000000000000000000000000000000000000000000000000000ffffffff / end actions queue index 4 / end +Sample Programmable Action rule + +A rule use Programmable Action to perform a customized tunnel header encap for specific IP packets. + +:: + + testpmd> flow create 0 ingress pattern eth / ipv4 src is 1.2.3.4 / end actions prog name cust_tun_encap + arguments tunn_id 55AA meta0 2E meta1 9000 end / end + BPF Functions -------------- -- 2.31.1