X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest-pmd%2Fcmdline_flow.c;h=0618611ab1d58df01114471779bffcbdd97d2cb0;hb=3127f99274b679124658afdbfc49210730c50617;hp=3d1dd059537fe814e998415f39421be20b9450b8;hpb=1848b117cca159cc4e5f287876491e86e3413f21;p=dpdk.git diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 3d1dd05953..0618611ab1 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include #include "testpmd.h" @@ -114,6 +118,7 @@ enum index { SHARED_ACTION_CREATE_ID, SHARED_ACTION_INGRESS, SHARED_ACTION_EGRESS, + SHARED_ACTION_TRANSFER, SHARED_ACTION_SPEC, /* Shared action destroy arguments */ @@ -218,6 +223,7 @@ enum index { ITEM_GENEVE, ITEM_GENEVE_VNI, ITEM_GENEVE_PROTO, + ITEM_GENEVE_OPTLEN, ITEM_VXLAN_GPE, ITEM_VXLAN_GPE_VNI, ITEM_ARP_ETH_IPV4, @@ -278,6 +284,11 @@ enum index { ITEM_ECPRI_MSG_IQ_DATA_PCID, ITEM_ECPRI_MSG_RTC_CTRL_RTCID, ITEM_ECPRI_MSG_DLY_MSR_MSRID, + ITEM_GENEVE_OPT, + ITEM_GENEVE_OPT_CLASS, + ITEM_GENEVE_OPT_TYPE, + ITEM_GENEVE_OPT_LENGTH, + ITEM_GENEVE_OPT_DATA, /* Validate/create actions. */ ACTIONS, @@ -403,11 +414,27 @@ enum index { ACTION_SAMPLE_INDEX_VALUE, ACTION_SHARED, SHARED_ACTION_ID2PTR, + ACTION_MODIFY_FIELD, + ACTION_MODIFY_FIELD_OP, + ACTION_MODIFY_FIELD_OP_VALUE, + ACTION_MODIFY_FIELD_DST_TYPE, + ACTION_MODIFY_FIELD_DST_TYPE_VALUE, + ACTION_MODIFY_FIELD_DST_LEVEL, + ACTION_MODIFY_FIELD_DST_OFFSET, + ACTION_MODIFY_FIELD_SRC_TYPE, + ACTION_MODIFY_FIELD_SRC_TYPE_VALUE, + ACTION_MODIFY_FIELD_SRC_LEVEL, + ACTION_MODIFY_FIELD_SRC_OFFSET, + ACTION_MODIFY_FIELD_SRC_VALUE, + ACTION_MODIFY_FIELD_WIDTH, }; /** Maximum size for pattern in struct rte_flow_item_raw. */ #define ITEM_RAW_PATTERN_SIZE 40 +/** Maximum size for GENEVE option data pattern in bytes. */ +#define ITEM_GENEVE_OPT_DATA_SIZE 124 + /** Storage size for struct rte_flow_item_raw including pattern. */ #define ITEM_RAW_SIZE \ (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE) @@ -423,7 +450,7 @@ struct action_rss_data { }; /** Maximum data size in struct rte_flow_action_raw_encap. */ -#define ACTION_RAW_ENCAP_MAX_DATA 128 +#define ACTION_RAW_ENCAP_MAX_DATA 512 #define RAW_ENCAP_CONFS_MAX_NUM 8 /** Storage for struct rte_flow_action_raw_encap. */ @@ -555,6 +582,23 @@ struct rte_flow_action_queue sample_queue[RAW_SAMPLE_CONFS_MAX_NUM]; struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM]; struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM]; struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM]; +struct action_rss_data sample_rss_data[RAW_SAMPLE_CONFS_MAX_NUM]; + +static const char *const modify_field_ops[] = { + "set", "add", "sub", NULL +}; + +static const char *const modify_field_ids[] = { + "start", "mac_dst", "mac_src", + "vlan_type", "vlan_id", "mac_type", + "ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst", + "ipv6_hoplimit", "ipv6_src", "ipv6_dst", + "tcp_port_src", "tcp_port_dst", + "tcp_seq_num", "tcp_ack_num", "tcp_flags", + "udp_port_src", "udp_port_dst", + "vxlan_vni", "geneve_vni", "gtp_teid", + "tag", "mark", "meta", "pointer", "value", NULL +}; /** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16 @@ -653,6 +697,16 @@ struct token { .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ }) +/** Static initializer for ARGS() to target a field with limits. */ +#define ARGS_ENTRY_BOUNDED(s, f, i, a) \ + (&(const struct arg){ \ + .bounded = 1, \ + .min = (i), \ + .max = (a), \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) + /** Static initializer for ARGS() to target an arbitrary bit-mask. */ #define ARGS_ENTRY_MASK(s, f, m) \ (&(const struct arg){ \ @@ -782,6 +836,7 @@ static const enum index next_sa_create_attr[] = { SHARED_ACTION_CREATE_ID, SHARED_ACTION_INGRESS, SHARED_ACTION_EGRESS, + SHARED_ACTION_TRANSFER, SHARED_ACTION_SPEC, ZERO, }; @@ -806,26 +861,6 @@ static const enum index next_vc_attr[] = { ZERO, }; -static const enum index tunnel_create_attr[] = { - TUNNEL_CREATE, - TUNNEL_CREATE_TYPE, - END, - ZERO, -}; - -static const enum index tunnel_destroy_attr[] = { - TUNNEL_DESTROY, - TUNNEL_DESTROY_ID, - END, - ZERO, -}; - -static const enum index tunnel_list_attr[] = { - TUNNEL_LIST, - END, - ZERO, -}; - static const enum index next_destroy_attr[] = { DESTROY_RULE, END, @@ -917,6 +952,7 @@ static const enum index next_item[] = { ITEM_AH, ITEM_PFCP, ITEM_ECPRI, + ITEM_GENEVE_OPT, END_SET, ZERO, }; @@ -1096,6 +1132,7 @@ static const enum index item_gtp[] = { static const enum index item_geneve[] = { ITEM_GENEVE_VNI, ITEM_GENEVE_PROTO, + ITEM_GENEVE_OPTLEN, ITEM_NEXT, ZERO, }; @@ -1258,6 +1295,15 @@ static const enum index item_ecpri_common_type[] = { ZERO, }; +static const enum index item_geneve_opt[] = { + ITEM_GENEVE_OPT_CLASS, + ITEM_GENEVE_OPT_TYPE, + ITEM_GENEVE_OPT_LENGTH, + ITEM_GENEVE_OPT_DATA, + ITEM_NEXT, + ZERO, +}; + static const enum index next_action[] = { ACTION_END, ACTION_VOID, @@ -1320,6 +1366,7 @@ static const enum index next_action[] = { ACTION_AGE, ACTION_SAMPLE, ACTION_SHARED, + ACTION_MODIFY_FIELD, ZERO, }; @@ -1562,6 +1609,7 @@ static const enum index action_sample[] = { static const enum index next_action_sample[] = { ACTION_QUEUE, + ACTION_RSS, ACTION_MARK, ACTION_COUNT, ACTION_PORT_ID, @@ -1570,6 +1618,21 @@ static const enum index next_action_sample[] = { ZERO, }; +static const enum index action_modify_field_dst[] = { + ACTION_MODIFY_FIELD_DST_LEVEL, + ACTION_MODIFY_FIELD_DST_OFFSET, + ACTION_MODIFY_FIELD_SRC_TYPE, + ZERO, +}; + +static const enum index action_modify_field_src[] = { + ACTION_MODIFY_FIELD_SRC_LEVEL, + ACTION_MODIFY_FIELD_SRC_OFFSET, + ACTION_MODIFY_FIELD_SRC_VALUE, + ACTION_MODIFY_FIELD_WIDTH, + ZERO, +}; + static int parse_set_raw_encap_decap(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1652,6 +1715,14 @@ static int parse_vc_action_sample_index(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, unsigned int size); +static int +parse_vc_modify_field_op(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); +static int +parse_vc_modify_field_id(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); static int parse_destroy(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1736,6 +1807,10 @@ 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_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); /** Token definitions. */ static const struct token token_list[] = { @@ -2003,35 +2078,37 @@ static const struct token token_list[] = { [TUNNEL_CREATE] = { .name = "create", .help = "create new tunnel object", - .next = NEXT(tunnel_create_attr, NEXT_ENTRY(PORT_ID)), + .next = NEXT(NEXT_ENTRY(TUNNEL_CREATE_TYPE), + NEXT_ENTRY(PORT_ID)), .args = ARGS(ARGS_ENTRY(struct buffer, port)), .call = parse_tunnel, }, [TUNNEL_CREATE_TYPE] = { .name = "type", .help = "create new tunnel", - .next = NEXT(tunnel_create_attr, NEXT_ENTRY(FILE_PATH)), + .next = NEXT(NEXT_ENTRY(FILE_PATH)), .args = ARGS(ARGS_ENTRY(struct tunnel_ops, type)), .call = parse_tunnel, }, [TUNNEL_DESTROY] = { .name = "destroy", .help = "destroy tunel", - .next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(PORT_ID)), + .next = NEXT(NEXT_ENTRY(TUNNEL_DESTROY_ID), + NEXT_ENTRY(PORT_ID)), .args = ARGS(ARGS_ENTRY(struct buffer, port)), .call = parse_tunnel, }, [TUNNEL_DESTROY_ID] = { .name = "id", .help = "tunnel identifier to testroy", - .next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(UNSIGNED)), + .next = NEXT(NEXT_ENTRY(UNSIGNED)), .args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)), .call = parse_tunnel, }, [TUNNEL_LIST] = { .name = "list", .help = "list existing tunnels", - .next = NEXT(tunnel_list_attr, NEXT_ENTRY(PORT_ID)), + .next = NEXT(NEXT_ENTRY(PORT_ID)), .args = ARGS(ARGS_ENTRY(struct buffer, port)), .call = parse_tunnel, }, @@ -2791,6 +2868,14 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, protocol)), }, + [ITEM_GENEVE_OPTLEN] = { + .name = "optlen", + .help = "GENEVE options length in dwords", + .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_geneve, + ver_opt_len_o_c_rsvd0, + "\x3f\x00")), + }, [ITEM_VXLAN_GPE] = { .name = "vxlan-gpe", .help = "match VXLAN-GPE header", @@ -3204,7 +3289,9 @@ static const struct token token_list[] = { [ITEM_ECPRI_MSG_IQ_DATA_PCID] = { .name = "pc_id", .help = "Physical Channel ID", - .next = NEXT(item_ecpri, NEXT_ENTRY(UNSIGNED), item_param), + .next = NEXT(NEXT_ENTRY(ITEM_ECPRI_MSG_IQ_DATA_PCID, + ITEM_ECPRI_COMMON, ITEM_NEXT), + NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ecpri, hdr.type0.pc_id)), }, @@ -3218,7 +3305,9 @@ static const struct token token_list[] = { [ITEM_ECPRI_MSG_RTC_CTRL_RTCID] = { .name = "rtc_id", .help = "Real-Time Control Data ID", - .next = NEXT(item_ecpri, NEXT_ENTRY(UNSIGNED), item_param), + .next = NEXT(NEXT_ENTRY(ITEM_ECPRI_MSG_RTC_CTRL_RTCID, + ITEM_ECPRI_COMMON, ITEM_NEXT), + NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ecpri, hdr.type2.rtc_id)), }, @@ -3232,10 +3321,53 @@ static const struct token token_list[] = { [ITEM_ECPRI_MSG_DLY_MSR_MSRID] = { .name = "msr_id", .help = "Measurement ID", - .next = NEXT(item_ecpri, NEXT_ENTRY(UNSIGNED), item_param), + .next = NEXT(NEXT_ENTRY(ITEM_ECPRI_MSG_DLY_MSR_MSRID, + ITEM_ECPRI_COMMON, ITEM_NEXT), + NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ecpri, hdr.type5.msr_id)), }, + [ITEM_GENEVE_OPT] = { + .name = "geneve-opt", + .help = "GENEVE header option", + .priv = PRIV_ITEM(GENEVE_OPT, + sizeof(struct rte_flow_item_geneve_opt) + + ITEM_GENEVE_OPT_DATA_SIZE), + .next = NEXT(item_geneve_opt), + .call = parse_vc, + }, + [ITEM_GENEVE_OPT_CLASS] = { + .name = "class", + .help = "GENEVE option class", + .next = NEXT(item_geneve_opt, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve_opt, + option_class)), + }, + [ITEM_GENEVE_OPT_TYPE] = { + .name = "type", + .help = "GENEVE option type", + .next = NEXT(item_geneve_opt, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_geneve_opt, + option_type)), + }, + [ITEM_GENEVE_OPT_LENGTH] = { + .name = "length", + .help = "GENEVE option data length (in 32b words)", + .next = NEXT(item_geneve_opt, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_BOUNDED( + struct rte_flow_item_geneve_opt, option_len, + 0, 31)), + }, + [ITEM_GENEVE_OPT_DATA] = { + .name = "data", + .help = "GENEVE option data pattern", + .next = NEXT(item_geneve_opt, NEXT_ENTRY(HEX), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_geneve_opt, data), + ARGS_ENTRY_ARB(0, 0), + ARGS_ENTRY_ARB + (sizeof(struct rte_flow_item_geneve_opt), + ITEM_GENEVE_OPT_DATA_SIZE)), + }, /* Validate/create actions. */ [ACTIONS] = { .name = "actions", @@ -4043,6 +4175,103 @@ static const struct token token_list[] = { .call = parse_vc_action_raw_decap_index, .comp = comp_set_raw_index, }, + [ACTION_MODIFY_FIELD] = { + .name = "modify_field", + .help = "modify destination field with data from source field", + .priv = PRIV_ACTION(MODIFY_FIELD, + sizeof(struct rte_flow_action_modify_field)), + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)), + .call = parse_vc, + }, + [ACTION_MODIFY_FIELD_OP] = { + .name = "op", + .help = "operation type", + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE), + NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_OP_VALUE] = { + .name = "{operation}", + .help = "operation type value", + .call = parse_vc_modify_field_op, + .comp = comp_set_modify_field_op, + }, + [ACTION_MODIFY_FIELD_DST_TYPE] = { + .name = "dst_type", + .help = "destination field type", + .next = NEXT(action_modify_field_dst, + NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = { + .name = "{dst_type}", + .help = "destination field type value", + .call = parse_vc_modify_field_id, + .comp = comp_set_modify_field_id, + }, + [ACTION_MODIFY_FIELD_DST_LEVEL] = { + .name = "dst_level", + .help = "destination field level", + .next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + dst.level)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_DST_OFFSET] = { + .name = "dst_offset", + .help = "destination field bit offset", + .next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + dst.offset)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_TYPE] = { + .name = "src_type", + .help = "source field type", + .next = NEXT(action_modify_field_src, + NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = { + .name = "{src_type}", + .help = "source field type value", + .call = parse_vc_modify_field_id, + .comp = comp_set_modify_field_id, + }, + [ACTION_MODIFY_FIELD_SRC_LEVEL] = { + .name = "src_level", + .help = "source field level", + .next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.level)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_OFFSET] = { + .name = "src_offset", + .help = "source field bit offset", + .next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.offset)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_VALUE] = { + .name = "src_value", + .help = "source immediate value", + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH), + NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.value)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_WIDTH] = { + .name = "width", + .help = "number of bits to copy", + .next = NEXT(NEXT_ENTRY(ACTION_NEXT), + NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + width)), + .call = parse_vc_conf, + }, /* Top level command. */ [SET] = { .name = "set", @@ -4280,6 +4509,12 @@ static const struct token token_list[] = { .next = NEXT(next_sa_create_attr), .call = parse_sa, }, + [SHARED_ACTION_TRANSFER] = { + .name = "transfer", + .help = "affect rule to transfer", + .next = NEXT(next_sa_create_attr), + .call = parse_sa, + }, [SHARED_ACTION_SPEC] = { .name = "action", .help = "specify action to share", @@ -4515,6 +4750,9 @@ parse_sa(struct context *ctx, const struct token *token, case SHARED_ACTION_INGRESS: out->args.vc.attr.ingress = 1; return len; + case SHARED_ACTION_TRANSFER: + out->args.vc.attr.transfer = 1; + return len; default: return -1; } @@ -5957,6 +6195,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token, return len; } +/** Parse operation for modify_field command. */ +static int +parse_vc_modify_field_op(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct rte_flow_action_modify_field *action_modify_field; + unsigned int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE) + return -1; + for (i = 0; modify_field_ops[i]; ++i) + if (!strcmp_partial(modify_field_ops[i], str, len)) + break; + if (!modify_field_ops[i]) + return -1; + if (!ctx->object) + return len; + action_modify_field = ctx->object; + action_modify_field->operation = (enum rte_flow_modify_op)i; + return len; +} + +/** Parse id for modify_field command. */ +static int +parse_vc_modify_field_id(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct rte_flow_action_modify_field *action_modify_field; + unsigned int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE && + ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE) + return -1; + for (i = 0; modify_field_ids[i]; ++i) + if (!strcmp_partial(modify_field_ids[i], str, len)) + break; + if (!modify_field_ids[i]) + return -1; + if (!ctx->object) + return len; + action_modify_field = ctx->object; + if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE) + action_modify_field->dst.field = (enum rte_flow_field_id)i; + else + action_modify_field->src.field = (enum rte_flow_field_id)i; + return len; +} + /** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token, @@ -6479,11 +6773,14 @@ parse_hex(struct context *ctx, const struct token *token, ret = snprintf(tmp, sizeof(tmp), "%u", hexlen); if (ret < 0) goto error; - push_args(ctx, arg_len); - ret = parse_int(ctx, token, tmp, ret, NULL, 0); - if (ret < 0) { - pop_args(ctx); - goto error; + /* Save length if requested. */ + if (arg_len->size) { + push_args(ctx, arg_len); + ret = parse_int(ctx, token, tmp, ret, NULL, 0); + if (ret < 0) { + pop_args(ctx); + goto error; + } } buf = (uint8_t *)ctx->object + arg_data->offset; /* Output buffer is not necessarily NUL-terminated. */ @@ -7026,6 +7323,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token, return nb; } +/** Complete operation for modify_field command. */ +static int +comp_set_modify_field_op(struct context *ctx, const struct token *token, + unsigned int ent, char *buf, unsigned int size) +{ + uint16_t idx = 0; + + RTE_SET_USED(ctx); + RTE_SET_USED(token); + for (idx = 0; modify_field_ops[idx]; ++idx) + ; + if (!buf) + return idx + 1; + if (ent < idx) + return strlcpy(buf, modify_field_ops[ent], size); + return -1; +} + +/** Complete field id for modify_field command. */ +static int +comp_set_modify_field_id(struct context *ctx, const struct token *token, + unsigned int ent, char *buf, unsigned int size) +{ + uint16_t idx = 0; + + RTE_SET_USED(ctx); + RTE_SET_USED(token); + for (idx = 0; modify_field_ids[idx]; ++idx) + ; + if (!buf) + return idx + 1; + if (ent < idx) + return strlcpy(buf, modify_field_ids[ent], size); + return -1; +} + /** Internal context. */ static struct context cmd_flow_context; @@ -7267,6 +7600,7 @@ cmd_flow_parsed(const struct buffer *in) &((const struct rte_flow_shared_action_conf) { .ingress = in->args.vc.attr.ingress, .egress = in->args.vc.attr.egress, + .transfer = in->args.vc.attr.transfer, }), in->args.vc.actions); break; @@ -7355,42 +7689,42 @@ cmdline_parse_inst_t cmd_flow = { static void update_fields(uint8_t *buf, struct rte_flow_item *item, uint16_t next_proto) { - struct rte_flow_item_ipv4 *ipv4; - struct rte_flow_item_eth *eth; - struct rte_flow_item_ipv6 *ipv6; - struct rte_flow_item_vxlan *vxlan; - struct rte_flow_item_vxlan_gpe *gpe; + struct rte_ipv4_hdr *ipv4; + struct rte_ether_hdr *eth; + struct rte_ipv6_hdr *ipv6; + struct rte_vxlan_hdr *vxlan; + struct rte_vxlan_gpe_hdr *gpe; struct rte_flow_item_nvgre *nvgre; uint32_t ipv6_vtc_flow; switch (item->type) { case RTE_FLOW_ITEM_TYPE_ETH: - eth = (struct rte_flow_item_eth *)buf; + eth = (struct rte_ether_hdr *)buf; if (next_proto) - eth->type = rte_cpu_to_be_16(next_proto); + eth->ether_type = rte_cpu_to_be_16(next_proto); break; case RTE_FLOW_ITEM_TYPE_IPV4: - ipv4 = (struct rte_flow_item_ipv4 *)buf; - ipv4->hdr.version_ihl = 0x45; - if (next_proto && ipv4->hdr.next_proto_id == 0) - ipv4->hdr.next_proto_id = (uint8_t)next_proto; + ipv4 = (struct rte_ipv4_hdr *)buf; + ipv4->version_ihl = 0x45; + if (next_proto && ipv4->next_proto_id == 0) + ipv4->next_proto_id = (uint8_t)next_proto; break; case RTE_FLOW_ITEM_TYPE_IPV6: - ipv6 = (struct rte_flow_item_ipv6 *)buf; - if (next_proto && ipv6->hdr.proto == 0) - ipv6->hdr.proto = (uint8_t)next_proto; - ipv6_vtc_flow = rte_be_to_cpu_32(ipv6->hdr.vtc_flow); + ipv6 = (struct rte_ipv6_hdr *)buf; + if (next_proto && ipv6->proto == 0) + ipv6->proto = (uint8_t)next_proto; + ipv6_vtc_flow = rte_be_to_cpu_32(ipv6->vtc_flow); ipv6_vtc_flow &= 0x0FFFFFFF; /*< reset version bits. */ ipv6_vtc_flow |= 0x60000000; /*< set ipv6 version. */ - ipv6->hdr.vtc_flow = rte_cpu_to_be_32(ipv6_vtc_flow); + ipv6->vtc_flow = rte_cpu_to_be_32(ipv6_vtc_flow); break; case RTE_FLOW_ITEM_TYPE_VXLAN: - vxlan = (struct rte_flow_item_vxlan *)buf; - vxlan->flags = 0x08; + vxlan = (struct rte_vxlan_hdr *)buf; + vxlan->vx_flags = 0x08; break; case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: - gpe = (struct rte_flow_item_vxlan_gpe *)buf; - gpe->flags = 0x0C; + gpe = (struct rte_vxlan_gpe_hdr *)buf; + gpe->vx_flags = 0x0C; break; case RTE_FLOW_ITEM_TYPE_NVGRE: nvgre = (struct rte_flow_item_nvgre *)buf; @@ -7482,6 +7816,9 @@ flow_item_default_mask(const struct rte_flow_item *item) case RTE_FLOW_ITEM_TYPE_GENEVE: mask = &rte_flow_item_geneve_mask; break; + case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: + mask = &rte_flow_item_geneve_opt_mask; + break; case RTE_FLOW_ITEM_TYPE_PPPOE_PROTO_ID: mask = &rte_flow_item_pppoe_proto_id_mask; break; @@ -7511,6 +7848,7 @@ cmd_set_raw_parsed_sample(const struct buffer *in) uint32_t i = 0; struct rte_flow_action *action = NULL; struct rte_flow_action *data = NULL; + const struct rte_flow_action_rss *rss = NULL; size_t size = 0; uint16_t idx = in->port; /* We borrow port field as index */ uint32_t max_size = sizeof(struct rte_flow_action) * @@ -7542,6 +7880,29 @@ cmd_set_raw_parsed_sample(const struct buffer *in) (const void *)action->conf, size); action->conf = &sample_queue[idx]; break; + case RTE_FLOW_ACTION_TYPE_RSS: + size = sizeof(struct rte_flow_action_rss); + rss = action->conf; + rte_memcpy(&sample_rss_data[idx].conf, + (const void *)rss, size); + if (rss->key_len) { + sample_rss_data[idx].conf.key = + sample_rss_data[idx].key; + rte_memcpy((void *)((uintptr_t) + sample_rss_data[idx].conf.key), + (const void *)rss->key, + sizeof(uint8_t) * rss->key_len); + } + if (rss->queue_num) { + sample_rss_data[idx].conf.queue = + sample_rss_data[idx].queue; + rte_memcpy((void *)((uintptr_t) + sample_rss_data[idx].conf.queue), + (const void *)rss->queue, + sizeof(uint16_t) * rss->queue_num); + } + action->conf = &sample_rss_data[idx].conf; + break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: size = sizeof(struct rte_flow_action_raw_encap); rte_memcpy(&sample_encap[idx], @@ -7577,6 +7938,7 @@ cmd_set_raw_parsed(const struct buffer *in) uint16_t upper_layer = 0; uint16_t proto = 0; uint16_t idx = in->port; /* We borrow port field as index */ + int gtp_psc = -1; /* GTP PSC option index. */ if (in->command == SET_SAMPLE_ACTIONS) return cmd_set_raw_parsed_sample(in); @@ -7594,41 +7956,44 @@ cmd_set_raw_parsed(const struct buffer *in) /* process hdr from upper layer to low layer (L3/L4 -> L2). */ data_tail = data + ACTION_RAW_ENCAP_MAX_DATA; for (i = n - 1 ; i >= 0; --i) { + const struct rte_flow_item_gtp *gtp; + const struct rte_flow_item_geneve_opt *opt; + item = in->args.vc.pattern + i; if (item->spec == NULL) item->spec = flow_item_default_mask(item); switch (item->type) { case RTE_FLOW_ITEM_TYPE_ETH: - size = sizeof(struct rte_flow_item_eth); + size = sizeof(struct rte_ether_hdr); break; case RTE_FLOW_ITEM_TYPE_VLAN: - size = sizeof(struct rte_flow_item_vlan); + size = sizeof(struct rte_vlan_hdr); proto = RTE_ETHER_TYPE_VLAN; break; case RTE_FLOW_ITEM_TYPE_IPV4: - size = sizeof(struct rte_flow_item_ipv4); + size = sizeof(struct rte_ipv4_hdr); proto = RTE_ETHER_TYPE_IPV4; break; case RTE_FLOW_ITEM_TYPE_IPV6: - size = sizeof(struct rte_flow_item_ipv6); + size = sizeof(struct rte_ipv6_hdr); proto = RTE_ETHER_TYPE_IPV6; break; case RTE_FLOW_ITEM_TYPE_UDP: - size = sizeof(struct rte_flow_item_udp); + size = sizeof(struct rte_udp_hdr); proto = 0x11; break; case RTE_FLOW_ITEM_TYPE_TCP: - size = sizeof(struct rte_flow_item_tcp); + size = sizeof(struct rte_tcp_hdr); proto = 0x06; break; case RTE_FLOW_ITEM_TYPE_VXLAN: - size = sizeof(struct rte_flow_item_vxlan); + size = sizeof(struct rte_vxlan_hdr); break; case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: - size = sizeof(struct rte_flow_item_vxlan_gpe); + size = sizeof(struct rte_vxlan_gpe_hdr); break; case RTE_FLOW_ITEM_TYPE_GRE: - size = sizeof(struct rte_flow_item_gre); + size = sizeof(struct rte_gre_hdr); proto = 0x2F; break; case RTE_FLOW_ITEM_TYPE_GRE_KEY: @@ -7636,7 +8001,7 @@ cmd_set_raw_parsed(const struct buffer *in) proto = 0x0; break; case RTE_FLOW_ITEM_TYPE_MPLS: - size = sizeof(struct rte_flow_item_mpls); + size = sizeof(struct rte_mpls_hdr); proto = 0x0; break; case RTE_FLOW_ITEM_TYPE_NVGRE: @@ -7644,14 +8009,26 @@ cmd_set_raw_parsed(const struct buffer *in) proto = 0x2F; break; case RTE_FLOW_ITEM_TYPE_GENEVE: - size = sizeof(struct rte_flow_item_geneve); + size = sizeof(struct rte_geneve_hdr); + break; + case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: + opt = (const struct rte_flow_item_geneve_opt *) + item->spec; + size = offsetof(struct rte_flow_item_geneve_opt, data); + if (opt->option_len && opt->data) { + *total_size += opt->option_len * + sizeof(uint32_t); + rte_memcpy(data_tail - (*total_size), + opt->data, + opt->option_len * sizeof(uint32_t)); + } break; case RTE_FLOW_ITEM_TYPE_L2TPV3OIP: - size = sizeof(struct rte_flow_item_l2tpv3oip); + size = sizeof(rte_be32_t); proto = 0x73; break; case RTE_FLOW_ITEM_TYPE_ESP: - size = sizeof(struct rte_flow_item_esp); + size = sizeof(struct rte_esp_hdr); proto = 0x32; break; case RTE_FLOW_ITEM_TYPE_AH: @@ -7659,16 +8036,68 @@ cmd_set_raw_parsed(const struct buffer *in) proto = 0x33; break; case RTE_FLOW_ITEM_TYPE_GTP: - size = sizeof(struct rte_flow_item_gtp); + if (gtp_psc < 0) { + size = sizeof(struct rte_gtp_hdr); + break; + } + if (gtp_psc != i + 1) { + printf("Error - GTP PSC does not follow GTP\n"); + goto error; + } + gtp = item->spec; + if ((gtp->v_pt_rsv_flags & 0x07) != 0x04) { + /* Only E flag should be set. */ + printf("Error - GTP unsupported flags\n"); + goto error; + } else { + struct rte_gtp_hdr_ext_word ext_word = { + .next_ext = 0x85 + }; + + /* We have to add GTP header extra word. */ + *total_size += sizeof(ext_word); + rte_memcpy(data_tail - (*total_size), + &ext_word, sizeof(ext_word)); + } + size = sizeof(struct rte_gtp_hdr); + break; + case RTE_FLOW_ITEM_TYPE_GTP_PSC: + if (gtp_psc >= 0) { + printf("Error - Multiple GTP PSC items\n"); + goto error; + } else { + const struct rte_flow_item_gtp_psc + *opt = item->spec; + struct { + uint8_t len; + uint8_t pdu_type; + uint8_t qfi; + uint8_t next; + } psc; + + if (opt->pdu_type & 0x0F) { + /* Support the minimal option only. */ + printf("Error - GTP PSC option with " + "extra fields not supported\n"); + goto error; + } + psc.len = sizeof(psc); + psc.pdu_type = opt->pdu_type; + psc.qfi = opt->qfi; + psc.next = 0; + *total_size += sizeof(psc); + rte_memcpy(data_tail - (*total_size), + &psc, sizeof(psc)); + gtp_psc = i; + size = 0; + } break; case RTE_FLOW_ITEM_TYPE_PFCP: size = sizeof(struct rte_flow_item_pfcp); break; default: printf("Error - Not supported item\n"); - *total_size = 0; - memset(data, 0x00, ACTION_RAW_ENCAP_MAX_DATA); - return; + goto error; } *total_size += size; rte_memcpy(data_tail - (*total_size), item->spec, size); @@ -7681,6 +8110,11 @@ cmd_set_raw_parsed(const struct buffer *in) printf("total data size is %zu\n", (*total_size)); RTE_ASSERT((*total_size) <= ACTION_RAW_ENCAP_MAX_DATA); memmove(data, (data_tail - (*total_size)), *total_size); + return; + +error: + *total_size = 0; + memset(data, 0x00, ACTION_RAW_ENCAP_MAX_DATA); } /** Populate help strings for current token (cmdline API). */ @@ -7816,7 +8250,7 @@ cmdline_parse_token_string_t cmd_show_set_raw_cmd_what = cmd_what, "raw_encap#raw_decap"); cmdline_parse_token_num_t cmd_show_set_raw_cmd_index = TOKEN_NUM_INITIALIZER(struct cmd_show_set_raw_result, - cmd_index, UINT16); + cmd_index, RTE_UINT16); cmdline_parse_token_string_t cmd_show_set_raw_cmd_all = TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result, cmd_all, "all");