Add command lines to generate IPv6 routing extension push and remove patterns and follow the raw_encap/decap style.
Add the new actions to the action template parsing. Generating the action patterns 1. IPv6 routing extension push set ipv6_ext_push 1 ipv6_ext type is 43 / ipv6_routing_ext ext_type is 4 ext_next_hdr is 17 ext_seg_left is 2 / end_set 2. IPv6 routing extension remove set ipv6_ext_remove 1 ipv6_ext type is 43 / end_set Specifying the action in the template 1. actions_template_id 1 template ipv6_ext_push index 1 2. actions_template_id 1 template ipv6_ext_remove index 1 Signed-off-by: Rongwei Liu <rongw...@nvidia.com> --- app/test-pmd/cmdline_flow.c | 443 +++++++++++++++++++++++++++++++++++- 1 file changed, 442 insertions(+), 1 deletion(-) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 88e6594c12..45555ea1bd 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -78,6 +78,9 @@ enum index { SET_RAW_INDEX, SET_SAMPLE_ACTIONS, SET_SAMPLE_INDEX, + SET_IPV6_EXT_REMOVE, + SET_IPV6_EXT_PUSH, + SET_IPV6_EXT_INDEX, /* Top-level command. */ FLOW, @@ -536,6 +539,8 @@ enum index { ITEM_IB_BTH_PKEY, ITEM_IB_BTH_DST_QPN, ITEM_IB_BTH_PSN, + ITEM_IPV6_PUSH_REMOVE_EXT, + ITEM_IPV6_PUSH_REMOVE_EXT_TYPE, /* Validate/create actions. */ ACTIONS, @@ -721,6 +726,12 @@ enum index { ACTION_SET_TCP_TP_DST, ACTION_SET_TCP_TP_DST_TP_DST, ACTION_IPSEC, + ACTION_IPV6_EXT_REMOVE, + ACTION_IPV6_EXT_REMOVE_INDEX, + ACTION_IPV6_EXT_REMOVE_INDEX_VALUE, + ACTION_IPV6_EXT_PUSH, + ACTION_IPV6_EXT_PUSH_INDEX, + ACTION_IPV6_EXT_PUSH_INDEX_VALUE, }; /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -787,6 +798,42 @@ struct action_raw_decap_data { uint16_t idx; }; +/** Maximum data size in struct rte_flow_action_ipv6_ext_push. */ +#define ACTION_IPV6_EXT_PUSH_MAX_DATA 512 +#define IPV6_EXT_PUSH_CONFS_MAX_NUM 8 + +/** Storage for struct rte_flow_action_ipv6_ext_push. */ +struct ipv6_ext_push_conf { + uint8_t data[ACTION_IPV6_EXT_PUSH_MAX_DATA]; + size_t size; + uint8_t type; +}; + +struct ipv6_ext_push_conf ipv6_ext_push_confs[IPV6_EXT_PUSH_CONFS_MAX_NUM]; + +/** Storage for struct rte_flow_action_ipv6_ext_push including external data. */ +struct action_ipv6_ext_push_data { + struct rte_flow_action_ipv6_ext_push conf; + uint8_t data[ACTION_IPV6_EXT_PUSH_MAX_DATA]; + uint8_t type; + uint16_t idx; +}; + +/** Storage for struct rte_flow_action_ipv6_ext_remove. */ +struct ipv6_ext_remove_conf { + struct rte_flow_action_ipv6_ext_remove conf; + uint8_t type; +}; + +struct ipv6_ext_remove_conf ipv6_ext_remove_confs[IPV6_EXT_PUSH_CONFS_MAX_NUM]; + +/** Storage for struct rte_flow_action_ipv6_ext_remove including external data. */ +struct action_ipv6_ext_remove_data { + struct rte_flow_action_ipv6_ext_remove conf; + uint8_t type; + uint16_t idx; +}; + struct vxlan_encap_conf vxlan_encap_conf = { .select_ipv4 = 1, .select_vlan = 0, @@ -2118,6 +2165,8 @@ static const enum index next_action[] = { ACTION_SET_TCP_TP_SRC, ACTION_SET_TCP_TP_DST, ACTION_IPSEC, + ACTION_IPV6_EXT_REMOVE, + ACTION_IPV6_EXT_PUSH, ZERO, }; @@ -2326,6 +2375,18 @@ static const enum index action_raw_decap[] = { ZERO, }; +static const enum index action_ipv6_ext_remove[] = { + ACTION_IPV6_EXT_REMOVE_INDEX, + ACTION_NEXT, + ZERO, +}; + +static const enum index action_ipv6_ext_push[] = { + ACTION_IPV6_EXT_PUSH_INDEX, + ACTION_NEXT, + ZERO, +}; + static const enum index action_set_tag[] = { ACTION_SET_TAG_DATA, ACTION_SET_TAG_INDEX, @@ -2390,6 +2451,22 @@ static const enum index next_action_sample[] = { ZERO, }; +static const enum index item_ipv6_push_ext[] = { + ITEM_IPV6_PUSH_REMOVE_EXT, + ZERO, +}; + +static const enum index item_ipv6_push_ext_type[] = { + ITEM_IPV6_PUSH_REMOVE_EXT_TYPE, + ZERO, +}; + +static const enum index item_ipv6_push_ext_header[] = { + ITEM_IPV6_ROUTING_EXT, + ITEM_NEXT, + ZERO, +}; + static const enum index action_modify_field_dst[] = { ACTION_MODIFY_FIELD_DST_LEVEL, ACTION_MODIFY_FIELD_DST_SUB_LEVEL, @@ -2497,6 +2574,9 @@ static int parse_set_raw_encap_decap(struct context *, const struct token *, static int parse_set_sample_action(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_set_ipv6_ext_action(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_set_init(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -2574,6 +2654,22 @@ static int parse_vc_action_raw_encap_index(struct context *, static int parse_vc_action_raw_decap_index(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_vc_action_ipv6_ext_remove(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); +static int parse_vc_action_ipv6_ext_remove_index(struct context *ctx, + const struct token *token, + const char *str, unsigned int len, + void *buf, + unsigned int size); +static int parse_vc_action_ipv6_ext_push(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); +static int parse_vc_action_ipv6_ext_push_index(struct context *ctx, + const struct token *token, + const char *str, unsigned int len, + void *buf, + unsigned int size); static int parse_vc_action_set_meta(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, @@ -2789,6 +2885,8 @@ static int comp_set_raw_index(struct context *, const struct token *, unsigned int, char *, unsigned int); static int comp_set_sample_index(struct context *, const struct token *, unsigned int, char *, unsigned int); +static int comp_set_ipv6_ext_index(struct context *ctx, const struct token *token, + unsigned int ent, char *buf, unsigned int size); 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 *, @@ -6765,6 +6863,48 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_IPV6_EXT_REMOVE] = { + .name = "ipv6_ext_remove", + .help = "IPv6 extension type, defined by set ipv6_ext_remove", + .priv = PRIV_ACTION(IPV6_EXT_REMOVE, + sizeof(struct action_ipv6_ext_remove_data)), + .next = NEXT(action_ipv6_ext_remove), + .call = parse_vc_action_ipv6_ext_remove, + }, + [ACTION_IPV6_EXT_REMOVE_INDEX] = { + .name = "index", + .help = "the index of ipv6_ext_remove", + .next = NEXT(NEXT_ENTRY(ACTION_IPV6_EXT_REMOVE_INDEX_VALUE)), + }, + [ACTION_IPV6_EXT_REMOVE_INDEX_VALUE] = { + .name = "{index}", + .type = "UNSIGNED", + .help = "unsigned integer value", + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc_action_ipv6_ext_remove_index, + .comp = comp_set_ipv6_ext_index, + }, + [ACTION_IPV6_EXT_PUSH] = { + .name = "ipv6_ext_push", + .help = "IPv6 extension data, defined by set ipv6_ext_push", + .priv = PRIV_ACTION(IPV6_EXT_PUSH, + sizeof(struct action_ipv6_ext_push_data)), + .next = NEXT(action_ipv6_ext_push), + .call = parse_vc_action_ipv6_ext_push, + }, + [ACTION_IPV6_EXT_PUSH_INDEX] = { + .name = "index", + .help = "the index of ipv6_ext_push", + .next = NEXT(NEXT_ENTRY(ACTION_IPV6_EXT_PUSH_INDEX_VALUE)), + }, + [ACTION_IPV6_EXT_PUSH_INDEX_VALUE] = { + .name = "{index}", + .type = "UNSIGNED", + .help = "unsigned integer value", + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc_action_ipv6_ext_push_index, + .comp = comp_set_ipv6_ext_index, + }, /* Top level command. */ [SET] = { .name = "set", @@ -6774,7 +6914,9 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY (SET_RAW_ENCAP, SET_RAW_DECAP, - SET_SAMPLE_ACTIONS)), + SET_SAMPLE_ACTIONS, + SET_IPV6_EXT_REMOVE, + SET_IPV6_EXT_PUSH)), .call = parse_set_init, }, /* Sub-level commands. */ @@ -6822,6 +6964,49 @@ static const struct token token_list[] = { 0, RAW_SAMPLE_CONFS_MAX_NUM - 1)), .call = parse_set_sample_action, }, + [SET_IPV6_EXT_PUSH] = { + .name = "ipv6_ext_push", + .help = "set IPv6 extension header", + .next = NEXT(NEXT_ENTRY(SET_IPV6_EXT_INDEX)), + .args = ARGS(ARGS_ENTRY_ARB_BOUNDED + (offsetof(struct buffer, port), + sizeof(((struct buffer *)0)->port), + 0, IPV6_EXT_PUSH_CONFS_MAX_NUM - 1)), + .call = parse_set_ipv6_ext_action, + }, + [SET_IPV6_EXT_REMOVE] = { + .name = "ipv6_ext_remove", + .help = "set IPv6 extension header", + .next = NEXT(NEXT_ENTRY(SET_IPV6_EXT_INDEX)), + .args = ARGS(ARGS_ENTRY_ARB_BOUNDED + (offsetof(struct buffer, port), + sizeof(((struct buffer *)0)->port), + 0, IPV6_EXT_PUSH_CONFS_MAX_NUM - 1)), + .call = parse_set_ipv6_ext_action, + }, + [SET_IPV6_EXT_INDEX] = { + .name = "{index}", + .type = "UNSIGNED", + .help = "index of ipv6 extension push/remove actions", + .next = NEXT(item_ipv6_push_ext), + .call = parse_port, + }, + [ITEM_IPV6_PUSH_REMOVE_EXT] = { + .name = "ipv6_ext", + .help = "set IPv6 extension header", + .priv = PRIV_ITEM(IPV6_EXT, + sizeof(struct rte_flow_item_ipv6_ext)), + .next = NEXT(item_ipv6_push_ext_type), + .call = parse_vc, + }, + [ITEM_IPV6_PUSH_REMOVE_EXT_TYPE] = { + .name = "type", + .help = "set IPv6 extension type", + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext, + next_hdr)), + .next = NEXT(item_ipv6_push_ext_header, NEXT_ENTRY(COMMON_UNSIGNED), + item_param), + }, [ACTION_SET_TAG] = { .name = "set_tag", .help = "set tag", @@ -9401,6 +9586,140 @@ parse_vc_action_raw_decap(struct context *ctx, const struct token *token, return ret; } +static int +parse_vc_action_ipv6_ext_remove(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_ipv6_ext_remove_data *ipv6_ext_remove_data = NULL; + int ret; + + ret = parse_vc(ctx, token, str, len, buf, size); + if (ret < 0) + return ret; + /* Nothing else to do if there is no buffer. */ + if (!out) + return ret; + if (!out->args.vc.actions_n) + return -1; + action = &out->args.vc.actions[out->args.vc.actions_n - 1]; + /* Point to selected object. */ + ctx->object = out->args.vc.data; + ctx->objmask = NULL; + /* Copy the headers to the buffer. */ + ipv6_ext_remove_data = ctx->object; + ipv6_ext_remove_data->conf.type = ipv6_ext_remove_confs[0].type; + action->conf = &ipv6_ext_remove_data->conf; + return ret; +} + +static int +parse_vc_action_ipv6_ext_remove_index(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct action_ipv6_ext_remove_data *action_ipv6_ext_remove_data; + struct rte_flow_action *action; + const struct arg *arg; + struct buffer *out = buf; + int ret; + uint16_t idx; + + RTE_SET_USED(token); + RTE_SET_USED(buf); + RTE_SET_USED(size); + arg = ARGS_ENTRY_ARB_BOUNDED + (offsetof(struct action_ipv6_ext_remove_data, idx), + sizeof(((struct action_ipv6_ext_remove_data *)0)->idx), + 0, IPV6_EXT_PUSH_CONFS_MAX_NUM - 1); + if (push_args(ctx, arg)) + return -1; + ret = parse_int(ctx, token, str, len, NULL, 0); + if (ret < 0) { + pop_args(ctx); + return -1; + } + if (!ctx->object) + return len; + action = &out->args.vc.actions[out->args.vc.actions_n - 1]; + action_ipv6_ext_remove_data = ctx->object; + idx = action_ipv6_ext_remove_data->idx; + action_ipv6_ext_remove_data->conf.type = ipv6_ext_remove_confs[idx].type; + action->conf = &action_ipv6_ext_remove_data->conf; + return len; +} + +static int +parse_vc_action_ipv6_ext_push(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_ipv6_ext_push_data *ipv6_ext_push_data = NULL; + int ret; + + ret = parse_vc(ctx, token, str, len, buf, size); + if (ret < 0) + return ret; + /* Nothing else to do if there is no buffer. */ + if (!out) + return ret; + if (!out->args.vc.actions_n) + return -1; + action = &out->args.vc.actions[out->args.vc.actions_n - 1]; + /* Point to selected object. */ + ctx->object = out->args.vc.data; + ctx->objmask = NULL; + /* Copy the headers to the buffer. */ + ipv6_ext_push_data = ctx->object; + ipv6_ext_push_data->conf.type = ipv6_ext_push_confs[0].type; + ipv6_ext_push_data->conf.data = ipv6_ext_push_confs[0].data; + ipv6_ext_push_data->conf.size = ipv6_ext_push_confs[0].size; + action->conf = &ipv6_ext_push_data->conf; + return ret; +} + +static int +parse_vc_action_ipv6_ext_push_index(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct action_ipv6_ext_push_data *action_ipv6_ext_push_data; + struct rte_flow_action *action; + const struct arg *arg; + struct buffer *out = buf; + int ret; + uint16_t idx; + + RTE_SET_USED(token); + RTE_SET_USED(buf); + RTE_SET_USED(size); + arg = ARGS_ENTRY_ARB_BOUNDED + (offsetof(struct action_ipv6_ext_push_data, idx), + sizeof(((struct action_ipv6_ext_push_data *)0)->idx), + 0, IPV6_EXT_PUSH_CONFS_MAX_NUM - 1); + if (push_args(ctx, arg)) + return -1; + ret = parse_int(ctx, token, str, len, NULL, 0); + if (ret < 0) { + pop_args(ctx); + return -1; + } + if (!ctx->object) + return len; + action = &out->args.vc.actions[out->args.vc.actions_n - 1]; + action_ipv6_ext_push_data = ctx->object; + idx = action_ipv6_ext_push_data->idx; + action_ipv6_ext_push_data->conf.type = ipv6_ext_push_confs[idx].type; + action_ipv6_ext_push_data->conf.size = ipv6_ext_push_confs[idx].size; + action_ipv6_ext_push_data->conf.data = ipv6_ext_push_confs[idx].data; + action->conf = &action_ipv6_ext_push_data->conf; + return len; +} + static int parse_vc_action_set_meta(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, @@ -11366,6 +11685,35 @@ parse_set_sample_action(struct context *ctx, const struct token *token, return len; } +/** Parse set command, initialize output buffer for subsequent tokens. */ +static int +parse_set_ipv6_ext_action(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; + /* Make sure buffer is large enough. */ + if (size < sizeof(*out)) + return -1; + ctx->objdata = 0; + ctx->objmask = NULL; + ctx->object = out; + if (!out->command) + return -1; + out->command = ctx->curr; + /* For ipv6_ext_push/remove we need is pattern */ + out->args.vc.pattern = (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), + sizeof(double)); + return len; +} + /** * Parse set raw_encap/raw_decap command, * initialize output buffer for subsequent tokens. @@ -11793,6 +12141,24 @@ comp_set_raw_index(struct context *ctx, const struct token *token, return nb; } +/** Complete index number for set raw_ipv6_ext_push/ipv6_ext_remove commands. */ +static int +comp_set_ipv6_ext_index(struct context *ctx, const struct token *token, + unsigned int ent, char *buf, unsigned int size) +{ + uint16_t idx = 0; + uint16_t nb = 0; + + RTE_SET_USED(ctx); + RTE_SET_USED(token); + for (idx = 0; idx < IPV6_EXT_PUSH_CONFS_MAX_NUM; ++idx) { + if (buf && idx == ent) + return snprintf(buf, size, "%u", idx); + ++nb; + } + return nb; +} + /** Complete index number for set raw_encap/raw_decap commands. */ static int comp_set_sample_index(struct context *ctx, const struct token *token, @@ -12697,6 +13063,78 @@ flow_item_default_mask(const struct rte_flow_item *item) return mask; } +/** Dispatch parsed buffer to function calls. */ +static void +cmd_set_ipv6_ext_parsed(const struct buffer *in) +{ + uint32_t n = in->args.vc.pattern_n; + int i = 0; + struct rte_flow_item *item = NULL; + size_t size = 0; + uint8_t *data = NULL; + uint8_t *type = NULL; + size_t *total_size = NULL; + uint16_t idx = in->port; /* We borrow port field as index */ + struct rte_flow_item_ipv6_routing_ext *ext; + const struct rte_flow_item_ipv6_ext *ipv6_ext; + + RTE_ASSERT(in->command == SET_IPV6_EXT_PUSH || + in->command == SET_IPV6_EXT_REMOVE); + + if (in->command == SET_IPV6_EXT_REMOVE) { + if (n != 1 || in->args.vc.pattern->type != + RTE_FLOW_ITEM_TYPE_IPV6_EXT) { + fprintf(stderr, "Error - Not supported item\n"); + return; + } + type = (uint8_t *)&ipv6_ext_remove_confs[idx].type; + item = in->args.vc.pattern; + ipv6_ext = item->spec; + *type = ipv6_ext->next_hdr; + return; + } + + total_size = &ipv6_ext_push_confs[idx].size; + data = (uint8_t *)&ipv6_ext_push_confs[idx].data; + type = (uint8_t *)&ipv6_ext_push_confs[idx].type; + + *total_size = 0; + memset(data, 0x00, ACTION_RAW_ENCAP_MAX_DATA); + for (i = n - 1 ; i >= 0; --i) { + item = in->args.vc.pattern + i; + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV6_EXT: + ipv6_ext = item->spec; + *type = ipv6_ext->next_hdr; + break; + case RTE_FLOW_ITEM_TYPE_IPV6_ROUTING_EXT: + ext = (struct rte_flow_item_ipv6_routing_ext *)(uintptr_t)item->spec; + if (!ext->hdr.hdr_len) { + size = sizeof(struct rte_ipv6_routing_ext) + + (ext->hdr.segments_left << 4); + ext->hdr.hdr_len = ext->hdr.segments_left << 1; + /* Indicate no TLV once SRH. */ + if (ext->hdr.type == RTE_IPV6_SRCRT_TYPE_4) + ext->hdr.last_entry = ext->hdr.segments_left - 1; + } else { + size = sizeof(struct rte_ipv6_routing_ext) + + (ext->hdr.hdr_len << 3); + } + *total_size += size; + memcpy(data, ext, size); + break; + default: + fprintf(stderr, "Error - Not supported item\n"); + goto error; + } + } + RTE_ASSERT((*total_size) <= ACTION_IPV6_EXT_PUSH_MAX_DATA); + return; +error: + *total_size = 0; + memset(data, 0x00, ACTION_IPV6_EXT_PUSH_MAX_DATA); +} + /** Dispatch parsed buffer to function calls. */ static void cmd_set_raw_parsed_sample(const struct buffer *in) @@ -12830,6 +13268,9 @@ cmd_set_raw_parsed(const struct buffer *in) if (in->command == SET_SAMPLE_ACTIONS) return cmd_set_raw_parsed_sample(in); + else if (in->command == SET_IPV6_EXT_PUSH || + in->command == SET_IPV6_EXT_REMOVE) + return cmd_set_ipv6_ext_parsed(in); RTE_ASSERT(in->command == SET_RAW_ENCAP || in->command == SET_RAW_DECAP); if (in->command == SET_RAW_ENCAP) { -- 2.27.0