Generic flow director/filtering/classification API
PATCH v5 15/26 app/testpmd: add rte_flow item spec prefix length
In reply to Adrien MazarguilGenerating bit-masks from prefix lengths is often more convenient than providing them entirely (e.g. to define IPv4 and IPv6 subnets).
This commit adds the "prefix" operator that assigns generated bit-masks to any pattern item specification field.
--- app/test-pmd/cmdline_flow.c | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
app/test-pmd/cmdline_flow.c +80 -0
@@ -56,6 +56,7 @@ enum index {/* Common tokens. */ INTEGER ,UNSIGNED , +PREFIX ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -93,6 +94,7 @@ enum index {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -278,6 +280,7 @@ static const enum index item_param[] = {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX , ZERO, };
@@ -321,6 +324,9 @@ static int parse_list(struct context *, const struct token *,static int parse_int (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_prefix (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -361,6 +367,13 @@ static const struct token token_list[] = { .call = parse_int, .comp = comp_none, }, + [PREFIX] = { + .name = "{prefix}", + .type = "PREFIX", + .help = "prefix length for bit-mask", + .call = parse_prefix, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -528,6 +541,11 @@ static const struct token token_list[] = { .help = "specify bit-mask with relevant bits set to one", .call = parse_vc_spec, }, + [ITEM_PARAM_PREFIX] = { + .name = "prefix", + .help = "generate bit-mask from a prefix length", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +623,62 @@ push_args(struct context *ctx, const struct arg *arg)return 0 ; } +/** +* Parse a prefix length and generate a bit-mask. +* +* Last argument (ctx->args) is retrieved to determine mask size, storage +* location and whether the result must use network byte ordering. +*/ +static int +parse_prefix (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +static const uint8_t conv[] ="\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff" ; +char *end; +uintmax_t u; +unsigned int bytes; +unsigned int extra; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u =strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; + bytes = u /8 ; + extra = u %8 ; + size = arg->size; +if (bytes > size || bytes + !!extra > size) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { +memset ((uint8_t *)buf + size - bytes,0xff , bytes); +memset (buf,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[size - bytes -1 ] = conv[extra]; + } else +#endif + { +memset (buf,0xff , bytes); +memset ((uint8_t *)buf + bytes,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[bytes] = conv[extra]; + } +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -776,6 +850,12 @@ parse_vc_spec(struct context *ctx, const struct token *token,case ITEM_PARAM_LAST : index =1 ;break ; +case ITEM_PARAM_PREFIX : +/* Modify next token to expect a prefix. */ +if (ctx->next_num <2 ) +return -1 ; + ctx->next[ctx->next_num -2 ] =NEXT_ENTRY (PREFIX ); +/* Fall through. */ case ITEM_PARAM_MASK : index =2 ;break ;
Signature · 1 line
2.1.4
PATCH v5 16/26 app/testpmd: add rte_flow bit-field support
In reply to Adrien MazarguilSeveral rte_flow structures expose bit-fields that cannot be set in a generic fashion at byte level. Add bit-mask support to handle them.
--- app/test-pmd/cmdline_flow.c | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
app/test-pmd/cmdline_flow.c +70 -0
@@ -136,6 +136,7 @@ struct arg { uint32_t sign:1; /**< Value is signed. */uint32_t offset;/**< Relative offset from ctx->object. */ uint32_t size;/**< Field size. */ +const uint8_t *mask;/**< Bit-mask to use instead of offset/size. */ };/** Parser token definition. */
@@ -195,6 +196,13 @@ struct token { .size = sizeof(((s *)0)->f), \ }) +/** Static initializer for ARGS() to target a bit-field. */ +#define ARGS_ENTRY_BF (s, f, b) \ + (&(const struct arg){ \ + .size = sizeof(s), \ + .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ + }) +/** Static initializer for ARGS() to target a pointer. */ #define ARGS_ENTRY_PTR (s, f) \ (&(const struct arg){ \
@@ -623,6 +631,45 @@ push_args(struct context *ctx, const struct arg *arg)return 0 ; } +/** Spread value into buffer according to bit-mask. */ +static size_t +arg_entry_bf_fill (void *dst,uintmax_t val,const struct arg *arg) +{ +uint32_t i = arg->size; +uint32_t end =0 ; +int sub =1 ; +int add =0 ; +size_t len =0 ; + +if (!arg->mask) +return 0 ; +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { + i =0 ; + end = arg->size; + sub =0 ; + add =1 ; + } +#endif +while (i != end) { +unsigned int shift =0 ; +uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub); + +for (shift =0 ; arg->mask[i] >> shift; ++shift) { +if (!(arg->mask[i] & (1 << shift))) +continue ; + ++len; +if (!dst) +continue ; + *buf &= ~(1 << shift); + *buf |= (val &1 ) << shift; + val >>=1 ; + } + i += add; + } +return len; +} +/** * Parse a prefix length and generate a bit-mask. *
@@ -649,6 +696,23 @@ parse_prefix(struct context *ctx, const struct token *token, u =strtoumax (str, &end,0 );if (errno || (size_t )(end - str) != len) goto error; +if (arg->mask) { +uintmax_t v =0 ; + + extra =arg_entry_bf_fill (NULL ,0 , arg); +if (u > extra) + goto error; +if (!ctx->object) +return len; + extra -= u; +while (u--) + (v <<=1 , v |=1 ); + v <<= extra; +if (!arg_entry_bf_fill (ctx->object, v, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } bytes = u /8 ; extra = u %8 ; size = arg->size;
@@ -1072,6 +1136,12 @@ parse_int(struct context *ctx, const struct token *token, goto error;if (!ctx->object)return len; +if (arg->mask) { +if (!arg_entry_bf_fill (ctx->object, u, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; objmask:
Signature · 1 line
2.1.4
PATCH v5 17/26 app/testpmd: add item any to flow command
In reply to Adrien MazarguilThis pattern item matches any protocol in place of the current layer and has two properties:
- min: minimum number of layers covered (0 or more).
- max: maximum number of layers covered (0 means infinity).
--- app/test-pmd/cmdline_flow.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
app/test-pmd/cmdline_flow.c +22 -1
@@ -99,6 +99,8 @@ enum index {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , +ITEM_ANY_NUM ,/* Validate/create actions. */ ACTIONS,
@@ -282,7 +284,6 @@ static const enum index next_list_attr[] = { ZERO, }; -__rte_unused static const enum index item_param[] = {ITEM_PARAM_IS ,ITEM_PARAM_SPEC ,
@@ -296,6 +297,13 @@ static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , + ZERO, +}; + +static const enum index item_any[] = { +ITEM_ANY_NUM , +ITEM_NEXT ,ZERO , };
@@ -580,6 +588,19 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), .call = parse_vc, }, + [ITEM_ANY] = { + .name = "any", + .help = "match any protocol for the current layer", + .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)), + .next = NEXT(item_any), + .call = parse_vc, + }, + [ITEM_ANY_NUM] = { + .name = "num", + .help = "number of layers covered", + .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v5 18/26 app/testpmd: add various items to flow command
In reply to Adrien Mazarguil- PF: match packets addressed to the physical function.
- VF: match packets addressed to a virtual function ID.
- PORT: device-specific physical port index to use.
--- app/test-pmd/cmdline_flow.c | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
app/test-pmd/cmdline_flow.c +53 -0
@@ -101,6 +101,11 @@ enum index {ITEM_INVERT ,ITEM_ANY ,ITEM_ANY_NUM , +ITEM_PF , +ITEM_VF , +ITEM_VF_ID , +ITEM_PORT , +ITEM_PORT_INDEX ,/* Validate/create actions. */ ACTIONS,
@@ -298,6 +303,9 @@ static const enum index next_item[] = {ITEM_VOID ,ITEM_INVERT ,ITEM_ANY , +ITEM_PF , +ITEM_VF , +ITEM_PORT , ZERO, };
@@ -307,6 +315,18 @@ static const enum index item_any[] = { ZERO, }; +static const enum index item_vf[] = { +ITEM_VF_ID , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_port[] = { +ITEM_PORT_INDEX , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -601,6 +621,39 @@ static const struct token token_list[] = { .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), }, + [ITEM_PF] = { + .name = "pf", + .help = "match packets addressed to the physical function", + .priv = PRIV_ITEM(PF, 0), + .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), + .call = parse_vc, + }, + [ITEM_VF] = { + .name = "vf", + .help = "match packets addressed to a virtual function ID", + .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)), + .next = NEXT(item_vf), + .call = parse_vc, + }, + [ITEM_VF_ID] = { + .name = "id", + .help = "destination VF ID", + .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), + }, + [ITEM_PORT] = { + .name = "port", + .help = "device-specific physical port index to use", + .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)), + .next = NEXT(item_port), + .call = parse_vc, + }, + [ITEM_PORT_INDEX] = { + .name = "index", + .help = "physical port index", + .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v5 19/26 app/testpmd: add item raw to flow command
In reply to Adrien MazarguilMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.
--- app/test-pmd/cmdline_flow.c | 208 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+)
app/test-pmd/cmdline_flow.c +208 -0
@@ -57,6 +57,8 @@ enum index {INTEGER ,UNSIGNED ,PREFIX , +BOOLEAN , +STRING ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -106,6 +108,12 @@ enum index {ITEM_VF_ID ,ITEM_PORT ,ITEM_PORT_INDEX , +ITEM_RAW , +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN ,/* Validate/create actions. */ ACTIONS,
@@ -115,6 +123,13 @@ enum index { ACTION_PASSTHRU, }; +/** Size of pattern[] field in struct rte_flow_item_raw. */ +#define ITEM_RAW_PATTERN_SIZE 36 + +/** Storage size for struct rte_flow_item_raw including pattern. */ +#define ITEM_RAW_SIZE \ + (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -216,6 +231,13 @@ struct token { .size = sizeof(*((s *)0)->f), \ }) +/** Static initializer for ARGS() with arbitrary size. */ +#define ARGS_ENTRY_USZ (s, f, sz) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = (sz), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -306,6 +328,7 @@ static const enum index next_item[] = {ITEM_PF ,ITEM_VF ,ITEM_PORT , +ITEM_RAW , ZERO, };
@@ -327,6 +350,16 @@ static const enum index item_port[] = { ZERO, }; +static const enum index item_raw[] = { +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -363,11 +396,19 @@ static int parse_int(struct context *, const struct token *,static int parse_prefix (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_boolean (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_string (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (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 *, +unsigned int ,char *,unsigned int );static int comp_action (struct context *,const struct token *,unsigned int ,char *,unsigned int ); static int comp_port(struct context *, const struct token *,
@@ -410,6 +451,20 @@ static const struct token token_list[] = { .call = parse_prefix, .comp = comp_none, }, + [BOOLEAN] = { + .name = "{boolean}", + .type = "BOOLEAN", + .help = "any boolean value", + .call = parse_boolean, + .comp = comp_boolean, + }, + [STRING] = { + .name = "{string}", + .type = "STRING", + .help = "fixed string", + .call = parse_string, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -654,6 +709,52 @@ static const struct token token_list[] = { .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), }, + [ITEM_RAW] = { + .name = "raw", + .help = "match an arbitrary byte string", + .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), + .next = NEXT(item_raw), + .call = parse_vc, + }, + [ITEM_RAW_RELATIVE] = { + .name = "relative", + .help = "look for pattern after the previous item", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + relative, 1)), + }, + [ITEM_RAW_SEARCH] = { + .name = "search", + .help = "search pattern from offset (see also limit)", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + search, 1)), + }, + [ITEM_RAW_OFFSET] = { + .name = "offset", + .help = "absolute or relative offset for pattern", + .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)), + }, + [ITEM_RAW_LIMIT] = { + .name = "limit", + .help = "search area limit for start of pattern", + .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), + }, + [ITEM_RAW_PATTERN] = { + .name = "pattern", + .help = "byte string to look for", + .next =NEXT (item_raw, +NEXT_ENTRY (STRING ), +NEXT_ENTRY (ITEM_PARAM_IS , +ITEM_PARAM_SPEC , + ITEM_PARAM_MASK)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length), + ARGS_ENTRY_USZ(struct rte_flow_item_raw, + pattern, + ITEM_RAW_PATTERN_SIZE)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1246,6 +1347,96 @@ parse_int(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a string. +* +* Two arguments (ctx->args) are retrieved from the stack to store data and +* its length (in that order). +*/ +static int +parse_string (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg_data =pop_args (ctx); +const struct arg *arg_len =pop_args (ctx); +char tmp[16 ];/* Ought to be enough. */ +int ret; + +/* Arguments are expected. */ +if (!arg_data) +return -1 ; +if (!arg_len) { +push_args (ctx, arg_data); +return -1 ; + } + size = arg_data->size; +/* Bit-mask fill is not supported. */ +if (arg_data->mask || size < len) + goto error; +if (!ctx->object) +return len; +/* Let parse_int() fill length information first. */ + ret =snprintf (tmp,sizeof (tmp),"%u" , len); +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; + } + buf = (uint8_t *)ctx->object + arg_data->offset; +/* Output buffer is not necessarily NUL-terminated. */ +memcpy (buf, str, len); +memset ((uint8_t *)buf + len,0x55 , size - len); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg_data->offset,0xff , len); +return len; +error: +push_args (ctx, arg_len); +push_args (ctx, arg_data); +return -1 ; +} + +/** Boolean values (even indices stand for false). */ +static const char *const boolean_name[] = { +"0" ,"1" , +"false" ,"true" , +"no" ,"yes" , +"N" ,"Y" , +NULL , +}; + +/** +* Parse a boolean value. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_boolean (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +unsigned int i; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; +for (i =0 ; boolean_name[i]; ++i) +if (!strncmp (str, boolean_name[i], len)) +break ; +/* Process token as integer. */ +if (boolean_name[i]) + str = i &1 ?"1" :"0" ; +push_args (ctx, arg); + ret =parse_int (ctx, token, str,strlen (str), buf, size); +return ret >0 ? (int )len : ret; +} +/** Parse port and update context. */ static int parse_port(struct context *ctx, const struct token *token,
@@ -1284,6 +1475,23 @@ comp_none(struct context *ctx, const struct token *token,return 0 ; } +/** Complete boolean values. */ +static int +comp_boolean (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; boolean_name[i]; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , boolean_name[i]); +if (buf) +return -1 ; +return i; +} +/** Complete action names. */ static int comp_action(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
Re: [PATCH v5 19/26] app/testpmd: add item raw to flow command
Hi, Adrien
Quoted 50 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Wednesday, December 21, 2016 10:52 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v5 19/26] app/testpmd: add item raw to flow commandMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>--- app/test-pmd/cmdline_flow.c | 208 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+)app/test-pmd/cmdline_flow.c +8
-0@@ -57,6 +57,8 @@ enum index {INTEGER ,UNSIGNED ,PREFIX , +BOOLEAN , +STRING ,RULE_ID ,PORT_ID , GROUP_ID,@@ -106,6 +108,12 @@ enum index {ITEM_VF_ID ,ITEM_PORT ,ITEM_PORT_INDEX , +ITEM_RAW , +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN ,/* Validate/create actions. */ ACTIONS,
app/test-pmd/cmdline_flow.c enum index { · line 132
Quoted 10 lines
app/test-pmd/cmdline_flow.c +6
-0@@ -115,6 +123,13 @@ enum index { ACTION_PASSTHRU, }; +/** Size of pattern[] field in struct rte_flow_item_raw. */ #define +ITEM_RAW_PATTERN_SIZE 36 + +/** Storage size for struct rte_flow_item_raw including pattern. */ +#define ITEM_RAW_SIZE \ + (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
#define ITEM_RAW_PATTERN_SIZE 36
The size of NIC i350 flex byte filter can accommodate the max length size of 128 byte, and the reason to Define it as 36 is ?If it is the max length of pattern, maybe 128 is more appropriate? Maybe I have not understand your purpose.
Thank you.
Quoted 270 lines
app/test-pmd/cmdline_flow.c +8
-0+/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16@@ -216,6 +231,13 @@ struct token { .size = sizeof(*((s *)0)->f), \ }) +/** Static initializer for ARGS() with arbitrary size. */ #define +ARGS_ENTRY_USZ (s, f, sz) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = (sz), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer { enum index command; /**< Flow command. */ @@ -306,6 +328,7@@ static const enum index next_item[] = {
app/test-pmd/cmdline_flow.c +19
-0ITEM_PF ,ITEM_VF ,ITEM_PORT , +ITEM_RAW , ZERO, };@@ -327,6 +350,16 @@ static const enum index item_port[] = { ZERO, }; +static const enum index item_raw[] = { +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,@@ -363,11 +396,19 @@ static int parse_int(struct context *, const struct token *, static int parse_prefix(struct context *, const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_boolean (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_string (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (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 *, +unsigned int ,char *,unsigned int );static int comp_action (struct context *,const struct token *, unsigned int, char *, unsigned int); static intcomp_port(struct context *, const struct token *, @@ -410,6 +451,20 @@ static const struct token token_list[] = {
app/test-pmd/cmdline_flow.c +32
-0.call = parse_prefix, .comp = comp_none, }, + [BOOLEAN] = { + .name = "{boolean}", + .type = "BOOLEAN", + .help = "any boolean value", + .call = parse_boolean, + .comp = comp_boolean, + }, + [STRING] = { + .name = "{string}", + .type = "STRING", + .help = "fixed string", + .call = parse_string, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",@@ -654,6 +709,52 @@ static const struct token token_list[] = { .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), }, + [ITEM_RAW] = { + .name = "raw", + .help = "match an arbitrary byte string", + .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), + .next = NEXT(item_raw), + .call = parse_vc, + }, + [ITEM_RAW_RELATIVE] = { + .name = "relative", + .help = "look for pattern after the previous item", + .next =NEXT (item_raw,NEXT_ENTRY (BOOLEAN ), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + relative, 1)), + }, + [ITEM_RAW_SEARCH] = { + .name = "search", + .help = "search pattern from offset (see also limit)", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN),
item_param),app/test-pmd/cmdline_flow.c +7
-0+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + search, 1)), + }, + [ITEM_RAW_OFFSET] = { + .name = "offset", + .help = "absolute or relative offset for pattern", + .next = NEXT(item_raw, NEXT_ENTRY(INTEGER),
item_param),app/test-pmd/cmdline_flow.c +1
-0+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw,offset)),
app/test-pmd/cmdline_flow.c +5
-0+ }, + [ITEM_RAW_LIMIT ] = { + .name ="limit" , + .help ="search area limit for start of pattern" , + .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED),
item_param),app/test-pmd/cmdline_flow.c +11
-0+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), + }, + [ITEM_RAW_PATTERN] = { + .name = "pattern", + .help = "byte string to look for", + .next =NEXT (item_raw, +NEXT_ENTRY (STRING ), +NEXT_ENTRY (ITEM_PARAM_IS , +ITEM_PARAM_SPEC , + ITEM_PARAM_MASK)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw,length),
app/test-pmd/cmdline_flow.c +112
-1+ ARGS_ENTRY_USZ(struct rte_flow_item_raw, + pattern, + ITEM_RAW_PATTERN_SIZE)), + },/* Validate/create actions. */ [ACTIONS ] = { .name ="actions" ,@@ -1246,6 +1347,96 @@ parse_int(struct context *ctx, const struct token *token, return -1 ; } +/** +* Parse a string. +* +* Two arguments (ctx->args) are retrieved from the stack to store data +and +* its length (in that order). +*/ +static int +parse_string (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg_data =pop_args (ctx); +const struct arg *arg_len =pop_args (ctx); +char tmp[16 ];/* Ought to be enough. */ +int ret; + +/* Arguments are expected. */ +if (!arg_data) +return -1 ; +if (!arg_len) { +push_args (ctx, arg_data); +return -1 ; + } + size = arg_data->size; +/* Bit-mask fill is not supported. */ +if (arg_data->mask || size < len) + goto error; +if (!ctx->object) +return len; +/* Let parse_int() fill length information first. */ + ret =snprintf (tmp,sizeof (tmp),"%u" , len); +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; + } + buf = (uint8_t *)ctx->object + arg_data->offset; +/* Output buffer is not necessarily NUL-terminated. */ +memcpy (buf, str, len); +memset ((uint8_t *)buf + len,0x55 , size - len); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg_data->offset,0xff , len); +return len; +error: +push_args (ctx, arg_len); +push_args (ctx, arg_data); +return -1 ; +} + +/** Boolean values (even indices stand for false). */ static const char +*const boolean_name[] = { +"0" ,"1" , +"false" ,"true" , +"no" ,"yes" , +"N" ,"Y" , +NULL , +}; + +/** +* Parse a boolean value. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_boolean (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +unsigned int i; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; +for (i =0 ; boolean_name[i]; ++i) +if (!strncmp (str, boolean_name[i], len)) +break ; +/* Process token as integer. */ +if (boolean_name[i]) + str = i &1 ?"1" :"0" ; +push_args (ctx, arg); + ret =parse_int (ctx, token, str,strlen (str), buf, size); +return ret >0 ? (int )len : ret; +} +/** Parse port and update context. */ static int parse_port(struct context *ctx, const struct token *token, @@ -1284,6 +1475,23 @@ comp_none(struct context *ctx, const struct token *token, return 0; } +/** Complete boolean values. */ +static int +comp_boolean (struct context *ctx,const struct token *token, + unsigned int ent, char *buf, unsigned int size) { + unsigned int i; + + (void)ctx; + (void)token; + for (i = 0; boolean_name[i]; ++i) + if (buf && i == ent) + return snprintf(buf, size, "%s", boolean_name[i]); +if (buf) +return -1 ; +return i; +} +/** Complete action names. */ static int comp_action(struct context *ctx, const struct token *token, --2.1.4
Re: [PATCH v5 19/26] app/testpmd: add item raw to flow command
Hi Wei,
Quoted 20 lines · Wei
Hi, Adrien
Quoted 18 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Wednesday, December 21, 2016 10:52 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v5 19/26] app/testpmd: add item raw to flow commandMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>
[...]
Quoted 7 lines
#define
ITEM_RAW_PATTERN_SIZE36The size of NIC i350 flex byte filter can accommodate the max length size of 128 byte, and the reason to Define it as 36 is ?If it is the max length of pattern, maybe 128 is more appropriate? Maybe I have not understand your purpose.
Thank you.
It's more or less an arbitrary compromise due to various limitations.
Once parsed, the result of an entire command is stored in a fixed buffer of size CMDLINE_PARSE_RESULT_BUFSIZE (8192). Each parsed token ends up somewhere in that buffer.
Each flow item always consumes sizeof(struct rte_flow_item) + sizeof(struct rte_flow_item_xxx) * 3 (spec, last and mask) + alignment constraints.
For the raw item, this makes at least:
(sizeof(rte_flow_item) +
(sizeof(rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE) * 3)
/* (32 + (12 + 36) * 3) => 176 bytes */
Because space is always consumed regardless of the size of the byte string to match for implementation reasons, there is a chance to fill the buffer too quickly with a larger ITEM_RAW_PATTERN_SIZE.
Also, this does not prevent users from specifying larger raw patterns (even larger than 128) by combining them, e.g.:
flow create 0
pattern eth / raw relative is 1 pattern is foobar /
raw relative is 1 pattern is barbaz / end
actions queue index 42 / end
Such a pattern ends up matching a single "foobarbarbaz" string.
To summarize, it is only due to testpmd limitations. Even without PMD support for combination, the current ability to provide 36 bytes of raw data to match per specified item is plenty to validate basic functionality. We'll improve testpmd eventually.
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v5 19/26] app/testpmd: add item raw to flow command
Hi, Adrien Mazarguil
Quoted 70 lines
-----Original Message-----
From: Adrien Mazarguil [mailto:[email protected]]
Sent: Friday, May 12, 2017 5:13 PM
To: Zhao1, Wei <[email protected]>
Cc: [email protected]; Xing, Beilei <[email protected]>; Lu, Wenzhuo <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v5 19/26] app/testpmd: add item raw to flow commandHi Wei,
Quoted 21 lines · Wei
Hi, Adrien
Quoted 19 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Wednesday, December 21, 2016 10:52 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v5 19/26] app/testpmd: add item raw to flow commandMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>[...]
Quoted 4 lines
#define
ITEM_RAW_PATTERN_SIZE36The size of NIC i350 flex byte filter can accommodate the max length size of 128 byte, and the reason to Define it as 36 is ?If it is the max length
of pattern, maybe 128 is more appropriate?
Quoted 3 lines
Maybe I have not understand your purpose.
Thank you.
It's more or less an arbitrary compromise due to various limitations.
Once parsed, the result of an entire command is stored in a fixed buffer of size
CMDLINE_PARSE_RESULT_BUFSIZE(8192). Each parsed token ends up somewhere in that buffer.Each flow item always consumes
sizeof(struct rte_flow_item)+sizeof(struct rte_flow_item_xxx)* 3 (spec, last and mask) + alignment constraints.For the raw item, this makes at least:
(
sizeof(rte_flow_item)+
(sizeof(rte_flow_item_raw)+ITEM_RAW_PATTERN_SIZE) * 3)
/* (32 + (12 + 36) * 3) => 176 bytes */Because space is always consumed regardless of the size of the byte string to match for implementation reasons, there is a chance to fill the buffer too quickly with a larger
ITEM_RAW_PATTERN_SIZE.Also, this does not prevent users from specifying larger raw patterns (even larger than 128) by combining them, e.g.:
flow create 0
pattern eth / raw relative is 1 pattern is foobar /
raw relative is 1 pattern is barbaz / end
actions queue index 42 / end
Quoted 7 lines
Such a pattern ends up matching a single "foobarbarbaz" string.
To summarize, it is only due to testpmd limitations. Even without PMD support for combination, the current ability to provide 36 bytes of raw data to match per specified item is plenty to validate basic functionality. We'll improve testpmd eventually.
Thank you for your detailed explanation.
Igb flex byte filter will support for that type combination for raw item. But this testpmd limitation will make trouble for users and tester.
Quoted 3 lines
--
Adrien Mazarguil
6WIND
PATCH v5 20/26 app/testpmd: add items eth/vlan to flow command
In reply to Adrien MazarguilThese pattern items match basic Ethernet headers (source, destination and type) and related 802.1Q/ad VLAN headers.
--- app/test-pmd/cmdline_flow.c | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
app/test-pmd/cmdline_flow.c +126 -0
@@ -43,6 +43,7 @@#include <rte_ethdev.h> #include <rte_byteorder.h> #include <cmdline_parse.h> +#include <cmdline_parse_etheraddr.h> #include <rte_flow.h> #include "testpmd.h"
@@ -59,6 +60,7 @@ enum index {PREFIX ,BOOLEAN ,STRING , +MAC_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -114,6 +116,13 @@ enum index {ITEM_RAW_OFFSET ,ITEM_RAW_LIMIT ,ITEM_RAW_PATTERN , +ITEM_ETH , +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_VLAN , +ITEM_VLAN_TPID , +ITEM_VLAN_TCI ,/* Validate/create actions. */ ACTIONS,
@@ -238,6 +247,14 @@ struct token { .size = (sz), \ }) +/** Same as ARGS_ENTRY() using network byte ordering. */ +#define ARGS_ENTRY_HTON (s, f) \ + (&(const struct arg){ \ + .hton = 1, \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -329,6 +346,8 @@ static const enum index next_item[] = {ITEM_VF ,ITEM_PORT ,ITEM_RAW , +ITEM_ETH , +ITEM_VLAN , ZERO, };
@@ -360,6 +379,21 @@ static const enum index item_raw[] = { ZERO, }; +static const enum index item_eth[] = { +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vlan[] = { +ITEM_VLAN_TPID , +ITEM_VLAN_TCI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -402,6 +436,9 @@ static int parse_boolean(struct context *, const struct token *,static int parse_string (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_mac_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -465,6 +502,13 @@ static const struct token token_list[] = { .call = parse_string, .comp = comp_none, }, + [MAC_ADDR] = { + .name = "{MAC address}", + .type = "MAC-48", + .help = "standard MAC address notation", + .call = parse_mac_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -755,6 +799,50 @@ static const struct token token_list[] = { pattern, ITEM_RAW_PATTERN_SIZE)), }, + [ITEM_ETH ] = { + .name ="eth" , + .help ="match Ethernet header" , + .priv =PRIV_ITEM (ETH ,sizeof (struct rte_flow_item_eth )), + .next =NEXT (item_eth), + .call = parse_vc, + }, + [ITEM_ETH_DST ] = { + .name ="dst" , + .help ="destination MAC" , + .next =NEXT (item_eth,NEXT_ENTRY (MAC_ADDR ), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, dst)), + }, + [ITEM_ETH_SRC ] = { + .name ="src" , + .help ="source MAC" , + .next =NEXT (item_eth,NEXT_ENTRY (MAC_ADDR ), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, src)), + }, + [ITEM_ETH_TYPE ] = { + .name ="type" , + .help ="EtherType" , + .next =NEXT (item_eth,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)), + }, + [ITEM_VLAN ] = { + .name ="vlan" , + .help ="match 802.1Q/ad VLAN tag" , + .priv =PRIV_ITEM (VLAN ,sizeof (struct rte_flow_item_vlan )), + .next =NEXT (item_vlan), + .call = parse_vc, + }, + [ITEM_VLAN_TPID ] = { + .name ="tpid" , + .help ="tag protocol identifier" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)), + }, + [ITEM_VLAN_TCI ] = { + .name ="tci" , + .help ="tag control information" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), + }, /* Validate/create actions. */ [ACTIONS ] = { .name ="actions" ,
@@ -1399,6 +1487,44 @@ parse_string(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a MAC address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_mac_addr (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +struct ether_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; + ret =cmdline_parse_etheraddr (NULL , str, &tmp, size); +if (ret <0 || (unsigned int )ret != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
PATCH v5 21/26 app/testpmd: add items ipv4/ipv6 to flow command
In reply to Adrien MazarguilAdd the ability to match basic fields from IPv4 and IPv6 headers (source and destination addresses only).
--- app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
app/test-pmd/cmdline_flow.c +177 -0
@@ -38,6 +38,7 @@#include <errno.h> #include <ctype.h> #include <string.h> +#include <arpa/inet.h> #include <rte_common.h> #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {BOOLEAN ,STRING ,MAC_ADDR , +IPV4_ADDR , +IPV6_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -123,6 +126,12 @@ enum index {ITEM_VLAN ,ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_IPV4 , +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_IPV6 , +ITEM_IPV6_SRC , +ITEM_IPV6_DST ,/* Validate/create actions. */ ACTIONS,
@@ -348,6 +357,8 @@ static const enum index next_item[] = {ITEM_RAW ,ITEM_ETH ,ITEM_VLAN , +ITEM_IPV4 , +ITEM_IPV6 , ZERO, };
@@ -394,6 +405,20 @@ static const enum index item_vlan[] = { ZERO, }; +static const enum index item_ipv4[] = { +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_ipv6[] = { +ITEM_IPV6_SRC , +ITEM_IPV6_DST , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -439,6 +464,12 @@ static int parse_string(struct context *, const struct token *,static int parse_mac_addr (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_ipv4_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_ipv6_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -509,6 +540,20 @@ static const struct token token_list[] = { .call = parse_mac_addr, .comp = comp_none, }, + [IPV4_ADDR] = { + .name = "{IPv4 address}", + .type = "IPV4 ADDRESS", + .help = "standard IPv4 address notation", + .call = parse_ipv4_addr, + .comp = comp_none, + }, + [IPV6_ADDR] = { + .name = "{IPv6 address}", + .type = "IPV6 ADDRESS", + .help = "standard IPv6 address notation", + .call = parse_ipv6_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -843,6 +888,48 @@ static const struct token token_list[] = { .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), }, + [ITEM_IPV4] = { + .name = "ipv4", + .help = "match IPv4 header", + .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + .next = NEXT(item_ipv4), + .call = parse_vc, + }, + [ITEM_IPV4_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.src_addr)), + }, + [ITEM_IPV4_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.dst_addr)), + }, + [ITEM_IPV6] = { + .name = "ipv6", + .help = "match IPv6 header", + .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + .next = NEXT(item_ipv6), + .call = parse_vc, + }, + [ITEM_IPV6_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.src_addr)), + }, + [ITEM_IPV6_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.dst_addr)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1525,6 +1612,96 @@ parse_mac_addr(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse an IPv4 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv4_addr (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +char str2[len +1 ]; +struct in_addr tmp; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET , str2, &tmp); +if (ret !=1 ) { +/* Attempt integer parsing. */ +push_args (ctx, arg); +return parse_int (ctx, token, str, len, buf, size); + } +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** +* Parse an IPv6 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv6_addr (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg =pop_args (ctx); +char str2[len +1 ]; +struct in6_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET6 , str2, &tmp); +if (ret !=1 ) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
PATCH v5 22/26 app/testpmd: add L4 items to flow command
In reply to Adrien MazarguilAdd the ability to match a few properties of common L4[.5] protocol headers:
- ICMP: type and code.
- UDP: source and destination ports.
- TCP: source and destination ports.
- SCTP: source and destination ports.
- VXLAN: network identifier.
--- app/test-pmd/cmdline_flow.c | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
app/test-pmd/cmdline_flow.c +163 -0
@@ -132,6 +132,20 @@ enum index {ITEM_IPV6 ,ITEM_IPV6_SRC ,ITEM_IPV6_DST , +ITEM_ICMP , +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_UDP , +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_TCP , +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_SCTP , +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_VXLAN , +ITEM_VXLAN_VNI ,/* Validate/create actions. */ ACTIONS,
@@ -359,6 +373,11 @@ static const enum index next_item[] = {ITEM_VLAN ,ITEM_IPV4 ,ITEM_IPV6 , +ITEM_ICMP , +ITEM_UDP , +ITEM_TCP , +ITEM_SCTP , +ITEM_VXLAN , ZERO, };
@@ -419,6 +438,40 @@ static const enum index item_ipv6[] = { ZERO, }; +static const enum index item_icmp[] = { +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_udp[] = { +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_tcp[] = { +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_sctp[] = { +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vxlan[] = { +ITEM_VXLAN_VNI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -930,6 +983,103 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, hdr.dst_addr)), }, + [ITEM_ICMP] = { + .name = "icmp", + .help = "match ICMP header", + .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + .next = NEXT(item_icmp), + .call = parse_vc, + }, + [ITEM_ICMP_TYPE] = { + .name = "type", + .help = "ICMP packet type", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_type)), + }, + [ITEM_ICMP_CODE] = { + .name = "code", + .help = "ICMP packet code", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_code)), + }, + [ITEM_UDP] = { + .name = "udp", + .help = "match UDP header", + .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + .next = NEXT(item_udp), + .call = parse_vc, + }, + [ITEM_UDP_SRC] = { + .name = "src", + .help = "UDP source port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.src_port)), + }, + [ITEM_UDP_DST] = { + .name = "dst", + .help = "UDP destination port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.dst_port)), + }, + [ITEM_TCP] = { + .name = "tcp", + .help = "match TCP header", + .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + .next = NEXT(item_tcp), + .call = parse_vc, + }, + [ITEM_TCP_SRC] = { + .name = "src", + .help = "TCP source port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.src_port)), + }, + [ITEM_TCP_DST] = { + .name = "dst", + .help = "TCP destination port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.dst_port)), + }, + [ITEM_SCTP] = { + .name = "sctp", + .help = "match SCTP header", + .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + .next = NEXT(item_sctp), + .call = parse_vc, + }, + [ITEM_SCTP_SRC] = { + .name = "src", + .help = "SCTP source port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.src_port)), + }, + [ITEM_SCTP_DST] = { + .name = "dst", + .help = "SCTP destination port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.dst_port)), + }, + [ITEM_VXLAN] = { + .name = "vxlan", + .help = "match VXLAN header", + .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), + .next = NEXT(item_vxlan), + .call = parse_vc, + }, + [ITEM_VXLAN_VNI] = { + .name = "vni", + .help = "VXLAN identifier", + .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1502,6 +1652,19 @@ parse_int(struct context *ctx, const struct token *token,case sizeof (uint16_t ): *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u;break ; +case sizeof (uint8_t [3 ]): +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { + ((uint8_t *)buf)[0 ] = u; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u >>16 ; +break ; + } +#endif + ((uint8_t *)buf)[0 ] = u >>16 ; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u; +break ;case sizeof (uint32_t ): *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u;break ;
Signature · 1 line
2.1.4
PATCH v5 23/26 app/testpmd: add various actions to flow command
In reply to Adrien Mazarguil- MARK: attach 32 bit value to packets.
- FLAG: flag packets.
- DROP: drop packets.
- COUNT: enable counters for a rule.
- PF: redirect packets to physical device function.
- VF: redirect packets to virtual device function.
--- app/test-pmd/cmdline_flow.c | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+)
app/test-pmd/cmdline_flow.c +121 -0
@@ -153,6 +153,15 @@ enum index {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_MARK_ID , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , +ACTION_VF_ORIGINAL , + ACTION_VF_ID, };/** Size of pattern[] field in struct rte_flow_item_raw. */
@@ -476,6 +485,25 @@ static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , + ZERO, +}; + +static const enum index action_mark[] = { +ACTION_MARK_ID , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_vf[] = { +ACTION_VF_ORIGINAL , +ACTION_VF_ID , +ACTION_NEXT ,ZERO , };
@@ -487,6 +515,8 @@ static int parse_vc(struct context *, const struct token *, void *, unsigned int);static int parse_vc_spec (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_conf (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -1112,6 +1142,70 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_MARK] = { + .name = "mark", + .help = "attach 32 bit value to packets", + .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)), + .next = NEXT(action_mark), + .call = parse_vc, + }, + [ACTION_MARK_ID] = { + .name = "id", + .help = "32 bit value to return with packets", + .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)), + .call = parse_vc_conf, + }, + [ACTION_FLAG] = { + .name = "flag", + .help = "flag packets", + .priv = PRIV_ACTION(FLAG, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_DROP] = { + .name = "drop", + .help = "drop packets (note: passthru has priority)", + .priv = PRIV_ACTION(DROP, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_COUNT] = { + .name = "count", + .help = "enable counters for this rule", + .priv = PRIV_ACTION(COUNT, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_PF] = { + .name = "pf", + .help = "redirect packets to physical device function", + .priv = PRIV_ACTION(PF, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_VF] = { + .name = "vf", + .help = "redirect packets to virtual device function", + .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)), + .next = NEXT(action_vf), + .call = parse_vc, + }, + [ACTION_VF_ORIGINAL] = { + .name = "original", + .help = "use original VF ID if possible", + .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf, + original, 1)), + .call = parse_vc_conf, + }, + [ACTION_VF_ID] = { + .name = "id", + .help = "VF ID to redirect packets to", + .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), + .call = parse_vc_conf, + }, };/** Remove and return last entry from argument stack. */
@@ -1446,6 +1540,33 @@ parse_vc_spec(struct context *ctx, const struct token *token,return len; } +/** Parse action configuration field. */ +static int +parse_vc_conf (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; + + (void )size; +/* 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->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 ; +/* Update configuration pointer. */ + action->conf = ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
PATCH v5 24/26 app/testpmd: add queue actions to flow command
In reply to Adrien Mazarguil- QUEUE: assign packets to a given queue index.
- DUP: duplicate packets to a given queue index.
- RSS: spread packets among several queues.
--- app/test-pmd/cmdline_flow.c | 152 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+)
app/test-pmd/cmdline_flow.c +152 -0
@@ -156,8 +156,15 @@ enum index {ACTION_MARK ,ACTION_MARK_ID ,ACTION_FLAG , +ACTION_QUEUE , +ACTION_QUEUE_INDEX ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_DUP_INDEX , +ACTION_RSS , +ACTION_RSS_QUEUES , +ACTION_RSS_QUEUE ,ACTION_PF ,ACTION_VF , ACTION_VF_ORIGINAL,
@@ -171,6 +178,14 @@ enum index {#define ITEM_RAW_SIZE \ (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Number of queue[] entries in struct rte_flow_action_rss. */ +#define ACTION_RSS_NUM 32 + +/** Storage size for struct rte_flow_action_rss including queues. */ +#define ACTION_RSS_SIZE \ + (offsetof(struct rte_flow_action_rss, queue) + \ + sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -487,8 +502,11 @@ static const enum index next_action[] = {ACTION_PASSTHRU ,ACTION_MARK ,ACTION_FLAG , +ACTION_QUEUE ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_RSS ,ACTION_PF ,ACTION_VF , ZERO,
@@ -500,6 +518,24 @@ static const enum index action_mark[] = { ZERO, }; +static const enum index action_queue[] = { +ACTION_QUEUE_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_dup[] = { +ACTION_DUP_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_rss[] = { +ACTION_RSS_QUEUES , +ACTION_NEXT , +ZERO , +}; +static const enum index action_vf[] = {ACTION_VF_ORIGINAL ,ACTION_VF_ID ,
@@ -517,6 +553,9 @@ static int parse_vc_spec(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int);static int parse_vc_conf (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_action_rss_queue (struct context *,const struct token *, +const char *,unsigned int ,void *, +unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -566,6 +605,8 @@ static int comp_port(struct context *, const struct token *, unsigned int, char *, unsigned int);static int comp_rule_id (struct context *,const struct token *,unsigned int ,char *,unsigned int ); +static int comp_vc_action_rss_queue (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -1163,6 +1204,21 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_QUEUE] = { + .name = "queue", + .help = "assign packets to a given queue index", + .priv =PRIV_ACTION (QUEUE , + sizeof(struct rte_flow_action_queue)), + .next = NEXT(action_queue), + .call = parse_vc, + }, + [ACTION_QUEUE_INDEX] = { + .name = "index", + .help = "queue index to use", + .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)), + .call = parse_vc_conf, + }, [ACTION_DROP] = { .name = "drop", .help = "drop packets (note: passthru has priority)",
@@ -1177,6 +1233,39 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_DUP] = { + .name = "dup", + .help = "duplicate packets to a given queue index", + .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + .next = NEXT(action_dup), + .call = parse_vc, + }, + [ACTION_DUP_INDEX] = { + .name = "index", + .help = "queue index to duplicate packets to", + .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)), + .call = parse_vc_conf, + }, + [ACTION_RSS] = { + .name = "rss", + .help = "spread packets among several queues", + .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE), + .next = NEXT(action_rss), + .call = parse_vc, + }, + [ACTION_RSS_QUEUES] = { + .name = "queues", + .help = "queue indices to use", + .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)), + .call = parse_vc_conf, + }, + [ACTION_RSS_QUEUE] = { + .name = "{queue}", + .help = "queue index", + .call = parse_vc_action_rss_queue, + .comp = comp_vc_action_rss_queue, + }, [ACTION_PF] = { .name = "pf", .help = "redirect packets to physical device function",
@@ -1567,6 +1656,51 @@ parse_vc_conf(struct context *ctx, const struct token *token,return len; } +/** +* Parse queue field for RSS action. +* +* Valid tokens are queue indices and the "end" token. +*/ +static int +parse_vc_action_rss_queue (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +static const enum index next[] =NEXT_ENTRY (ACTION_RSS_QUEUE ); +int ret; +int i; + + (void )token; + (void )buf; + (void )size; +if (ctx->curr !=ACTION_RSS_QUEUE ) +return -1 ; + i = ctx->objdata >>16 ; +if (!strncmp (str,"end" , len)) { + ctx->objdata &=0xffff ; +return len; + } +if (i >=ACTION_RSS_NUM ) +return -1 ; + if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i]))) +return -1 ; + ret =parse_int (ctx, token, str, len,NULL ,0 ); +if (ret <0 ) { +pop_args (ctx); +return -1 ; + } + ++i; + ctx->objdata = i <<16 | (ctx->objdata &0xffff ); +/* Repeat token. */ +if (ctx->next_num ==RTE_DIM (ctx->next)) +return -1 ; + ctx->next[ctx->next_num++] = next; +if (!ctx->object) +return len; + ((struct rte_flow_action_rss *)ctx->object)->num = i; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -2141,6 +2275,24 @@ comp_rule_id(struct context *ctx, const struct token *token,return i; } +/** Complete queue field for RSS action. */ +static int +comp_vc_action_rss_queue (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +static const char *const str[] = {"" ,"end" ,NULL }; +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; str[i] !=NULL ; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , str[i]); +if (buf) +return -1 ; +return i; +} +/** Internal context. */ static struct context cmd_flow_context;
Signature · 1 line
2.1.4
PATCH v5 25/26 doc: describe testpmd flow command
In reply to Adrien MazarguilDocument syntax, interaction with rte_flow and provide usage examples.
--- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++++++++++++++++++++ 1 file changed, 612 insertions(+)
doc/guides/testpmd_app_ug/testpmd_funcs.rst +612 -0
@@ -1631,6 +1631,9 @@ Filter Functions This section details the available filter functions that are available. +Note these functions interface the deprecated legacy filtering framework, +superseded by *rte_flow*. See `Flow rules management`_. + ethertype_filter ~~~~~~~~~~~~~~~~~~~~
@@ -2041,3 +2044,612 @@ Set different GRE key length for input set:: For example to set GRE key length for input set to 4 bytes on port 0:: testpmd> global_config 0 gre-key-len 4 + + +.. _testpmd_rte_flow: + +Flow rules management +--------------------- + +Control of the generic flow API (*rte_flow*) is fully exposed through the +``flow`` command (validation, creation, destruction and queries). + +Considering *rte_flow* overlaps with all `Filter Functions`_, using both +features simultaneously may cause undefined side-effects and is therefore +not recommended. + +``flow`` syntax +~~~~~~~~~~~~~~~ + +Because the ``flow`` command uses dynamic tokens to handle the large number +of possible flow rules combinations, its behavior differs slightly from +other commands, in particular: + +- Pressing *?* or the *<tab>* key displays contextual help for the current + token, not that of the entire command. + +- Optional and repeated parameters are supported (provided they are listed + in the contextual help). + +The first parameter stands for the operation mode. Possible operations and +their general syntax are described below. They are covered in detail in the +following sections. + +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} + +- Query an existing flow rule:: + + flow query {port_id} {rule_id} {action} + +- List existing flow rules sorted by priority, filtered by group + identifiers:: + + flow list {port_id} [group {group_id}] [...] + +Validating flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow validate`` reports whether a flow rule would be accepted by the +underlying device in its current state but stops short of creating it. It is +bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will show:: + + Flow rule validated + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +This command uses the same parameters as ``flow create``, their format is +described in `Creating flow rules`_. + +Check whether redirecting any Ethernet packet received on port 0 to RX queue +index 6 is supported:: + + testpmd> flow validate 0 ingress pattern eth / end + actions queue index 6 / end + Flow rule validated + testpmd> + +Port 0 does not support TCPv6 rules:: + + testpmd> flow validate 0 ingress pattern eth / ipv6 / tcp / end + actions drop / end + Caught error type 9 (specific pattern item): Invalid argument + testpmd> + +Creating flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow create`` validates and creates the specified flow rule. It is bound +to ``rte_flow_create()``:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will return a flow rule ID usable with other commands:: + + Flow rule #[...] created + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +Parameters describe in the following order: + +- Attributes (*group*, *priority*, *ingress*, *egress* tokens). +- A matching pattern, starting with the *pattern* token and terminated by an + *end* pattern item. +- Actions, starting with the *actions* token and terminated by an *end* + action. + +These translate directly to *rte_flow* objects provided as-is to the +underlying functions. + +The shortest valid definition only comprises mandatory tokens:: + + testpmd> flow create 0 pattern end actions end + +Note that PMDs may refuse rules that essentially do nothing such as this +one. + +**All unspecified object values are automatically initialized to 0.** + +Attributes +^^^^^^^^^^ + +These tokens affect flow rule attributes (``struct rte_flow_attr``) and are +specified before the ``pattern`` token. + +- ``group {group id}``: priority group. +- ``priority {level}``: priority level within group. +- ``ingress``: rule applies to ingress traffic. +- ``egress``: rule applies to egress traffic. + +Each instance of an attribute specified several times overrides the previous +value as shown below (group 4 is used):: + + testpmd> flow create 0 group 42 group 24 group 4 [...] + +Note that once enabled, ``ingress`` and ``egress`` cannot be disabled. + +While not specifying a direction is an error, some rules may allow both +simultaneously. + +Most rules affect RX therefore contain the ``ingress`` token:: + + testpmd> flow create 0 ingress pattern [...] + +Matching pattern +^^^^^^^^^^^^^^^^ + +A matching pattern starts after the ``pattern`` token. It is made of pattern +items and is terminated by a mandatory ``end`` item. + +Items are named after their type (*RTE_FLOW_ITEM_TYPE_* from ``enum +rte_flow_item_type``). + +The ``/`` token is used as a separator between pattern items as shown +below:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end [...] + +Note that protocol items like these must be stacked from lowest to highest +layer to make sense. For instance, the following rule is either invalid or +unlikely to match any packet:: + + testpmd> flow create 0 ingress pattern eth / udp / ipv4 / end [...] + +More information on these restrictions can be found in the *rte_flow* +documentation. + +Several items support additional specification structures, for example +``ipv4`` allows specifying source and destination addresses as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 src is 10.1.1.1 + dst is 10.2.0.0 / end [...] + +This rule matches all IPv4 traffic with the specified properties. + +In this example, ``src`` and ``dst`` are field names of the underlying +``struct rte_flow_item_ipv4`` object. All item properties can be specified +in a similar fashion. + +The ``is`` token means that the subsequent value must be matched exactly, +and assigns ``spec`` and ``mask`` fields in ``struct rte_flow_item`` +accordingly. Possible assignment tokens are: + +- ``is``: match value perfectly (with full bit-mask). +- ``spec``: match value according to configured bit-mask. +- ``last``: specify upper bound to establish a range. +- ``mask``: specify bit-mask with relevant bits set to one. +- ``prefix``: generate bit-mask from a prefix length. + +These yield identical results:: + + ipv4 src is 10.1.1.1 + +:: + + ipv4 src spec 10.1.1.1 src mask 255.255.255.255 + +:: + + ipv4 src spec 10.1.1.1 src prefix 32 + +:: + + ipv4 src is 10.1.1.1 src last 10.1.1.1 # range with a single value + +:: + + ipv4 src is 10.1.1.1 src last 0 # 0 disables range + +Inclusive ranges can be defined with ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 # 10.1.1.1 to 10.2.3.4 + +Note that ``mask`` affects both ``spec`` and ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 src mask 255.255.0.0 + # matches 10.1.0.0 to 10.2.255.255 + +Properties can be modified multiple times:: + + ipv4 src is 10.1.1.1 src is 10.1.2.3 src is 10.2.3.4 # matches 10.2.3.4 + +:: + + ipv4 src is 10.1.1.1 src prefix 24 src prefix 16 # matches 10.1.0.0/16 + +Pattern items +^^^^^^^^^^^^^ + +This section lists supported pattern items and their attributes, if any. + +- ``end``: end list of pattern items. + +- ``void``: no-op pattern item. + +- ``invert``: perform actions when pattern does not match. + +- ``any``: match any protocol for the current layer. + + - ``num {unsigned}``: number of layers covered. + +- ``pf``: match packets addressed to the physical function. + +- ``vf``: match packets addressed to a virtual function ID. + + - ``id {unsigned}``: destination VF ID. + +- ``port``: device-specific physical port index to use. + + - ``index {unsigned}``: physical port index. + +- ``raw``: match an arbitrary byte string. + + - ``relative {boolean}``: look for pattern after the previous item. + - ``search {boolean}``: search pattern from offset (see also limit). + - ``offset {integer}``: absolute or relative offset for pattern. + - ``limit {unsigned}``: search area limit for start of pattern. + - ``pattern {string}``: byte string to look for. + +- ``eth``: match Ethernet header. + + - ``dst {MAC-48}``: destination MAC. + - ``src {MAC-48}``: source MAC. + - ``type {unsigned}``: EtherType. + +- ``vlan``: match 802.1Q/ad VLAN tag. + + - ``tpid {unsigned}``: tag protocol identifier. + - ``tci {unsigned}``: tag control information. + +- ``ipv4``: match IPv4 header. + + - ``src {ipv4 address}``: source address. + - ``dst {ipv4 address}``: destination address. + +- ``ipv6``: match IPv6 header. + + - ``src {ipv6 address}``: source address. + - ``dst {ipv6 address}``: destination address. + +- ``icmp``: match ICMP header. + + - ``type {unsigned}``: ICMP packet type. + - ``code {unsigned}``: ICMP packet code. + +- ``udp``: match UDP header. + + - ``src {unsigned}``: UDP source port. + - ``dst {unsigned}``: UDP destination port. + +- ``tcp``: match TCP header. + + - ``src {unsigned}``: TCP source port. + - ``dst {unsigned}``: TCP destination port. + +- ``sctp``: match SCTP header. + + - ``src {unsigned}``: SCTP source port. + - ``dst {unsigned}``: SCTP destination port. + +- ``vxlan``: match VXLAN header. + + - ``vni {unsigned}``: VXLAN identifier. + +Actions list +^^^^^^^^^^^^ + +A list of actions starts after the ``actions`` token in the same fashion as +`Matching pattern`_; actions are separated by ``/`` tokens and the list is +terminated by a mandatory ``end`` action. + +Actions are named after their type (*RTE_FLOW_ACTION_TYPE_* from ``enum +rte_flow_action_type``). + +Dropping all incoming UDPv4 packets can be expressed as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions drop / end + +Several actions have configurable properties which must be specified when +there is no valid default value. For example, ``queue`` requires a target +queue index. + +This rule redirects incoming UDPv4 traffic to queue index 6:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue index 6 / end + +While this one could be rejected by PMDs (unspecified queue index):: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue / end + +As defined by *rte_flow*, the list is not ordered, all actions of a given +rule are performed simultaneously. These are equivalent:: + + queue index 6 / void / mark id 42 / end + +:: + + void / mark id 42 / queue index 6 / end + +All actions in a list should have different types, otherwise only the last +action of a given type is taken into account:: + + queue index 4 / queue index 5 / queue index 6 / end # will use queue 6 + +:: + + drop / drop / drop / end # drop is performed only once + +:: + + mark id 42 / queue index 3 / mark id 24 / end # mark will be 24 + +Considering they are performed simultaneously, opposite and overlapping +actions can sometimes be combined when the end result is unambiguous:: + + drop / queue index 6 / end # drop has no effect + +:: + + drop / dup index 6 / end # same as above + +:: + + queue index 6 / rss queues 6 7 8 / end # queue has no effect + +:: + + drop / passthru / end # drop has no effect + +Note that PMDs may still refuse such combinations. + +Actions +^^^^^^^ + +This section lists supported actions and their attributes, if any. + +- ``end``: end list of actions. + +- ``void``: no-op action. + +- ``passthru``: let subsequent rule process matched packets. + +- ``mark``: attach 32 bit value to packets. + + - ``id {unsigned}``: 32 bit value to return with packets. + +- ``flag``: flag packets. + +- ``queue``: assign packets to a given queue index. + + - ``index {unsigned}``: queue index to use. + +- ``drop``: drop packets (note: passthru has priority). + +- ``count``: enable counters for this rule. + +- ``dup``: duplicate packets to a given queue index. + + - ``index {unsigned}``: queue index to duplicate packets to. + +- ``rss``: spread packets among several queues. + + - ``queues [{unsigned} [...]] end``: queue indices to use. + +- ``pf``: redirect packets to physical device function. + +- ``vf``: redirect packets to virtual device function. + + - ``original {boolean}``: use original VF ID if possible. + - ``id {unsigned}``: VF ID to redirect packets to. + +Destroying flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow destroy`` destroys one or more rules from their rule ID (as returned +by ``flow create``), this command calls ``rte_flow_destroy()`` as many +times as necessary:: + + flow destroy {port_id} rule {rule_id} [...] + +If successful, it will show:: + + Flow rule #[...] destroyed + +It does not report anything for rule IDs that do not exist. The usual error +message is shown when a rule cannot be destroyed:: + + Caught error type [...] ([...]): [...] + +``flow flush`` destroys all rules on a device and does not take extra +arguments. It is bound to ``rte_flow_flush()``:: + + flow flush {port_id} + +Any errors are reported as above. + +Creating several rules and destroying them:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 0 rule 1 + Flow rule #1 destroyed + Flow rule #0 destroyed + testpmd> + +The same result can be achieved using ``flow flush``:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow flush 0 + testpmd> + +Non-existent rule IDs are ignored:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 42 rule 10 rule 2 + testpmd> + testpmd> flow destroy 0 rule 0 + Flow rule #0 destroyed + testpmd> + +Querying flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow query`` queries a specific action of a flow rule having that +ability. Such actions collect information that can be reported using this +command. It is bound to ``rte_flow_query()``:: + + flow query {port_id} {rule_id} {action} + +If successful, it will display either the retrieved data for known actions +or the following message:: + + Cannot display result for action type [...] ([...]) + +Otherwise, it will complain either that the rule does not exist or that some +error occurred:: + + Flow rule #[...] not found + +:: + + Caught error type [...] ([...]): [...] + +Currently only the ``count`` action is supported. This action reports the +number of packets that hit the flow rule and the total number of bytes. Its +output has the following format:: + + count: + hits_set: [...] # whether "hits" contains a valid value + bytes_set: [...] # whether "bytes" contains a valid value + hits: [...] # number of packets + bytes: [...] # number of bytes + +Querying counters for TCPv6 packets redirected to queue 6:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / tcp / end + actions queue index 6 / count / end + Flow rule #4 created + testpmd> flow query 0 4 count + count: + hits_set: 1 + bytes_set: 0 + hits: 386446 + bytes: 0 + testpmd> + +Listing flow rules +~~~~~~~~~~~~~~~~~~ + +``flow list`` lists existing flow rules sorted by priority and optionally +filtered by group identifiers:: + + flow list {port_id} [group {group_id}] [...] + +This command only fails with the following message if the device does not +exist:: + + Invalid port [...] + +Output consists of a header line followed by a short description of each +flow rule, one per line. There is no output at all when no flow rules are +configured on the device:: + + ID Group Prio Attr Rule + [...] [...] [...] [...] [...] + +``Attr`` column flags: + +- ``i`` for ``ingress``. +- ``e`` for ``egress``. + +Creating several flow rules and listing them:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 6 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #1 created + testpmd> flow create 0 priority 5 ingress pattern eth / ipv4 / udp / end + actions rss queues 6 7 8 end / end + Flow rule #2 created + testpmd> flow list 0 + ID Group Prio Attr Rule + 0 0 0 i- ETH IPV4 => QUEUE + 1 0 0 i- ETH IPV6 => QUEUE + 2 0 5 i- ETH IPV4 UDP => RSS + testpmd> + +Rules are sorted by priority (i.e. group ID first, then priority level):: + + testpmd> flow list 1 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 1 24 0 i- ETH IPV4 UDP => QUEUE + 4 24 10 i- ETH IPV4 TCP => DROP + 3 24 20 i- ETH IPV4 => DROP + 2 24 42 i- ETH IPV4 UDP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd> + +Output can be limited to specific groups:: + + testpmd> flow list 1 group 0 group 63 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd>
Signature · 1 line
2.1.4
PATCH v5 26/26 app/testpmd: add protocol fields to flow command
In reply to Adrien MazarguilThis commit exposes the following item fields through the flow command:
- VLAN priority code point, drop eligible indicator and VLAN identifier (all part of TCI).
- IPv4 type of service, time to live and protocol.
- IPv6 traffic class, flow label, next header and hop limit.
- SCTP tag and checksum.
--- app/test-pmd/cmdline_flow.c | 127 +++++++++++++++++++++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 12 +++ 2 files changed, 139 insertions(+)
app/test-pmd/cmdline_flow.c +127 -0
@@ -126,10 +126,20 @@ enum index {ITEM_VLAN ,ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_VLAN_PCP , +ITEM_VLAN_DEI , +ITEM_VLAN_VID ,ITEM_IPV4 , +ITEM_IPV4_TOS , +ITEM_IPV4_TTL , +ITEM_IPV4_PROTO ,ITEM_IPV4_SRC ,ITEM_IPV4_DST ,ITEM_IPV6 , +ITEM_IPV6_TC , +ITEM_IPV6_FLOW , +ITEM_IPV6_PROTO , +ITEM_IPV6_HOP ,ITEM_IPV6_SRC ,ITEM_IPV6_DST , ITEM_ICMP,
@@ -144,6 +154,8 @@ enum index {ITEM_SCTP ,ITEM_SCTP_SRC ,ITEM_SCTP_DST , +ITEM_SCTP_TAG , +ITEM_SCTP_CKSUM ,ITEM_VXLAN , ITEM_VXLAN_VNI,
@@ -281,6 +293,23 @@ struct token { .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ }) +/** Static initializer for ARGS() to target an arbitrary bit-mask. */ +#define ARGS_ENTRY_MASK (s, f, m) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + .mask = (const void *)(m), \ + }) + +/** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */ +#define ARGS_ENTRY_MASK_HTON (s, f, m) \ + (&(const struct arg){ \ + .hton = 1, \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + .mask = (const void *)(m), \ + }) +/** Static initializer for ARGS() to target a pointer. */ #define ARGS_ENTRY_PTR (s, f) \ (&(const struct arg){ \
@@ -444,11 +473,17 @@ static const enum index item_eth[] = {static const enum index item_vlan[] = {ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_VLAN_PCP , +ITEM_VLAN_DEI , +ITEM_VLAN_VID ,ITEM_NEXT ,ZERO , };static const enum index item_ipv4[] = { +ITEM_IPV4_TOS , +ITEM_IPV4_TTL , +ITEM_IPV4_PROTO ,ITEM_IPV4_SRC ,ITEM_IPV4_DST ,ITEM_NEXT ,
@@ -456,6 +491,10 @@ static const enum index item_ipv4[] = { };static const enum index item_ipv6[] = { +ITEM_IPV6_TC , +ITEM_IPV6_FLOW , +ITEM_IPV6_PROTO , +ITEM_IPV6_HOP ,ITEM_IPV6_SRC ,ITEM_IPV6_DST ,ITEM_NEXT ,
@@ -486,6 +525,8 @@ static const enum index item_tcp[] = {static const enum index item_sctp[] = {ITEM_SCTP_SRC ,ITEM_SCTP_DST , +ITEM_SCTP_TAG , +ITEM_SCTP_CKSUM ,ITEM_NEXT ,ZERO , };
@@ -1012,6 +1053,27 @@ static const struct token token_list[] = { .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), }, + [ITEM_VLAN_PCP] = { + .name = "pcp", + .help = "priority code point", + .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, + tci, "\xe0\x00")), + }, + [ITEM_VLAN_DEI] = { + .name = "dei", + .help = "drop eligible indicator", + .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, + tci, "\x10\x00")), + }, + [ITEM_VLAN_VID] = { + .name = "vid", + .help = "VLAN identifier", + .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, + tci, "\x0f\xff")), + }, [ITEM_IPV4] = { .name = "ipv4", .help = "match IPv4 header",
@@ -1019,6 +1081,27 @@ static const struct token token_list[] = { .next = NEXT(item_ipv4), .call = parse_vc, }, + [ITEM_IPV4_TOS] = { + .name = "tos", + .help = "type of service", + .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.type_of_service)), + }, + [ITEM_IPV4_TTL] = { + .name = "ttl", + .help = "time to live", + .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.time_to_live)), + }, + [ITEM_IPV4_PROTO] = { + .name = "proto", + .help = "next protocol ID", + .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.next_proto_id)), + }, [ITEM_IPV4_SRC] = { .name = "src", .help = "source address",
@@ -1040,6 +1123,36 @@ static const struct token token_list[] = { .next = NEXT(item_ipv6), .call = parse_vc, }, + [ITEM_IPV6_TC] = { + .name = "tc", + .help = "traffic class", + .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, + hdr.vtc_flow, + "\x0f\xf0\x00\x00")), + }, + [ITEM_IPV6_FLOW] = { + .name = "flow", + .help = "flow label", + .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, + hdr.vtc_flow, + "\x00\x0f\xff\xff")), + }, + [ITEM_IPV6_PROTO] = { + .name = "proto", + .help = "protocol (next header)", + .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.proto)), + }, + [ITEM_IPV6_HOP] = { + .name = "hop", + .help = "hop limit", + .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.hop_limits)), + }, [ITEM_IPV6_SRC] = { .name = "src", .help = "source address",
@@ -1138,6 +1251,20 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, hdr.dst_port)), }, + [ITEM_SCTP_TAG] = { + .name = "tag", + .help = "validation tag", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.tag)), + }, + [ITEM_SCTP_CKSUM] = { + .name = "cksum", + .help = "checksum", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.cksum)), + }, [ITEM_VXLAN] = { .name = "vxlan", .help = "match VXLAN header",
doc/guides/testpmd_app_ug/testpmd_funcs.rst +12 -0
@@ -2333,14 +2333,24 @@ This section lists supported pattern items and their attributes, if any. - ``tpid {unsigned}``: tag protocol identifier. - ``tci {unsigned}``: tag control information. + - ``pcp {unsigned}``: priority code point. + - ``dei {unsigned}``: drop eligible indicator. + - ``vid {unsigned}``: VLAN identifier. - ``ipv4``: match IPv4 header. + - ``tos {unsigned}``: type of service. + - ``ttl {unsigned}``: time to live. + - ``proto {unsigned}``: next protocol ID. - ``src {ipv4 address}``: source address. - ``dst {ipv4 address}``: destination address. - ``ipv6``: match IPv6 header. + - ``tc {unsigned}``: traffic class. + - ``flow {unsigned}``: flow label. + - ``proto {unsigned}``: protocol (next header). + - ``hop {unsigned}``: hop limit. - ``src {ipv6 address}``: source address. - ``dst {ipv6 address}``: destination address.
@@ -2363,6 +2373,8 @@ This section lists supported pattern items and their attributes, if any. - ``src {unsigned}``: SCTP source port. - ``dst {unsigned}``: SCTP destination port. + - ``tag {unsigned}``: validation tag. + - ``cksum {unsigned}``: checksum. - ``vxlan``: match VXLAN header.
Signature · 1 line
2.1.4
Thomas Monjalon
AppliedRe: [PATCH v5 00/26] Generic flow API (rte_flow)
In reply to Adrien MazarguilQuoted 19 lines
Adrien Mazarguil (26):
ethdev: introduce generic flow API
doc: addrte_flowprog guide
doc: announce deprecation of legacy filter types
cmdline: add support for dynamic tokens
cmdline: add alignment constraint app/testpmd: implement basic support forrte_flowapp/testpmd: add flow command app/testpmd: addrte_flowinteger support app/testpmd: add flow list command app/testpmd: add flow flush command app/testpmd: add flow destroy command app/testpmd: add flow validate/create commands app/testpmd: add flow query command app/testpmd: addrte_flowitem spec handler app/testpmd: addrte_flowitem spec prefix length app/testpmd: addrte_flowbit-field support app/testpmd: add item any to flow command app/testpmd: add various items to flow command
Quoted 8 lines
app/testpmd: add item raw to flow command app/testpmd: add items eth/vlan to flow command app/testpmd: add items ipv4/ipv6 to flow command app/testpmd: add L4 items to flow command app/testpmd: add various actions to flow command app/testpmd: add queue actions to flow command
doc: describe testpmd flow command app/testpmd: add protocol fields to flow command
Applied, thanks for the great work!
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
In reply to Adrien MazarguilQuoted 17 lines · Adrien Mazarguil
As previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "
rte_flow" from the prefix used for its public symbols. I personally favor the latter.While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
Quoted 6 lines
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
Hi Adrien,
thanks for this valuable work.
I would like to ask some high level questions on the proposal. I apologise in advance if any of these questions are based on a misunderstanding on my part.
* I am wondering about provisions for actions to modify packet data or metadata. I do see support for marking packets. Is the implication of this that the main focus is to provide a mechanism for classification with the assumption that any actions - other than drop and variants of output - would be performed elsewhere?
If so I would observe that this seems somewhat limiting in the case of hardware that can perform a richer set of actions. And seems particularly limiting on egress as there doesn't seem anywhere else that other actions could be performed after classification is performed by this API.
* I am curious to know what considerations have been given to supporting support for tunnelling (encapsulation and decapsulation of e.g. VXLAN),
tagging (pushing and popping e.g. VLANs), and labels (pushing or popping e.g. MPLS).
Such features seem would useful for application of this work in a variety of situations including overlay networks and VNFs.
* I am wondering if any thought has gone into supporting matching on the n-th instance of a field that may appear more than once: e.g. VLAN tag.
With the above questions in mind I am curious to know what use-cases the proposal is targeted at.
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
Quoted 18 lines · Simon Horman
Quoted 17 lines · Adrien Mazarguil
As previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "
rte_flow" from the prefix used for its public symbols. I personally favor the latter.While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
Quoted 6 lines
Quoted 6 lines
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
Hi Simon,
Quoted 8 lines
Hi Adrien,
thanks for this valuable work.
I would like to ask some high level questions on the proposal. I apologise in advance if any of these questions are based on a misunderstanding on my part.
Quoted 5 lines
* I am wondering about provisions for actions to modify packet data or metadata. I do see support for marking packets. Is the implication of this that the main focus is to provide a mechanism for classification with the assumption that any actions - other than drop and variants of output - would be performed elsewhere?
I'm not sure to understand what you mean by "elsewhere" here. Packet marking as currently defined is a purely ingress action, i.e. HW matches some packet and returns a user-defined tag in related meta-data that the PMD copies to the appropriate mbuf structure field before returning it to the application.
There is provision for egress rules and I wrote down a few ideas describing how they could be useful (as above), however they remain to be defined.
Quoted 4 lines
If so I would observe that this seems somewhat limiting in the case of hardware that can perform a richer set of actions. And seems particularly limiting on egress as there doesn't seem anywhere else that other actions could be performed after classification is performed by this API.
A single flow rule may contain any number of distinct actions. For egress, it means you could wrap matching packets in VLAN and VXLAN at once.
If you wanted to perform the same action twice on matching packets, you'd have to provide two rules with defined priorities and use a non-terminating action for the first one:
- Rule with priority 0: match UDP -> add VLAN 42, passthrough
- Rule with priority 1: match UDP -> add VLAN 64, terminating
This is how automatic QinQ would be defined for outgoing UDP packets.
Quoted 6 lines
* I am curious to know what considerations have been given to supporting support for tunnelling (encapsulation and decapsulation of e.g. VXLAN),
tagging (pushing and popping e.g. VLANs), and labels (pushing or popping e.g. MPLS).Such features seem would useful for application of this work in a variety of situations including overlay networks and VNFs.
This is also what I had in mind and we'd only have to define specific ingress/egress actions for these. Currently rte_flow only implements a basic set of existing features from the legacy filtering framework, but is meant to be extended.
Quoted 2 lines
* I am wondering if any thought has gone into supporting matching on the n-th instance of a field that may appear more than once: e.g. VLAN tag.
Sure, please see the latest documentation [1] and testpmd examples [2]. Pattern items being stacked in the same order as protocol layers, maching specific QinQ traffic and redirecting it to some queue could be expressed with something like:
testpmd> flow create 0 ingress pattern eth / vlan vid is 64 / vlan vid is 42 / end
actions queue 6 / end
Such a rule is translated as-is to rte_flow pattern items and action structures.
Quoted 2 lines
With the above questions in mind I am curious to know what use-cases the proposal is targeted at.
Well, it should be easier to answer if you have a specific use-case in mind you would like to support but that cannot be expressed with the API as defined in [1], in which case please share it with the community.
[1] http://dpdk.org/ml/archives/dev/2016-December/052954.html
[2] http://dpdk.org/ml/archives/dev/2016-December/052975.html
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
Quoted 19 lines · Adrien Mazarguil
Quoted 18 lines · Simon Horman
Quoted 17 lines · Adrien Mazarguil
As previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "
rte_flow" from the prefix used for its public symbols. I personally favor the latter.While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
Hi Adrien,
apologies for not replying for some time due to my winter vacation.
Quoted 16 lines
Hi Simon,
Quoted 8 lines
Hi Adrien,
thanks for this valuable work.
I would like to ask some high level questions on the proposal. I apologise in advance if any of these questions are based on a misunderstanding on my part.
Quoted 5 lines
* I am wondering about provisions for actions to modify packet data or metadata. I do see support for marking packets. Is the implication of this that the main focus is to provide a mechanism for classification with the assumption that any actions - other than drop and variants of output - would be performed elsewhere?
Quoted 4 lines
I'm not sure to understand what you mean by "elsewhere" here. Packet marking as currently defined is a purely ingress action, i.e. HW matches some packet and returns a user-defined tag in related meta-data that the PMD copies to the appropriate mbuf structure field before returning it to the application.
By elsewhere I meant in the application, sorry for being unclear.
Quoted 11 lines
There is provision for egress rules and I wrote down a few ideas describing how they could be useful (as above), however they remain to be defined.
Quoted 4 lines
If so I would observe that this seems somewhat limiting in the case of hardware that can perform a richer set of actions. And seems particularly limiting on egress as there doesn't seem anywhere else that other actions could be performed after classification is performed by this API.
A single flow rule may contain any number of distinct actions. For egress, it means you could wrap matching packets in VLAN and VXLAN at once.
Quoted 8 lines
If you wanted to perform the same action twice on matching packets, you'd have to provide two rules with defined priorities and use a non-terminating action for the first one:
- Rule with priority 0: match UDP -> add VLAN 42, passthrough
- Rule with priority 1: match UDP -> add VLAN 64, terminatingThis is how automatic QinQ would be defined for outgoing UDP packets.
Ok understood. I have two follow-up questions:
1. Is the "add VLAN" action included at this time, I was not able to find it
2. Was consideration given to allowing multiple actions in a single rule? I see there would be some advantage to that if classification is expensive.
Quoted 11 lines
Quoted 6 lines
* I am curious to know what considerations have been given to supporting support for tunnelling (encapsulation and decapsulation of e.g. VXLAN),
tagging (pushing and popping e.g. VLANs), and labels (pushing or popping e.g. MPLS).Such features seem would useful for application of this work in a variety of situations including overlay networks and VNFs.
This is also what I had in mind and we'd only have to define specific ingress/egress actions for these. Currently
rte_flowonly implements a basic set of existing features from the legacy filtering framework, but is meant to be extended.
Thanks. I think that answers most of my questions: what I see as missing in terms of actions can be added.
Quoted 8 lines
Quoted 2 lines
* I am wondering if any thought has gone into supporting matching on the n-th instance of a field that may appear more than once: e.g. VLAN tag.
Sure, please see the latest documentation [1] and testpmd examples [2]. Pattern items being stacked in the same order as protocol layers, maching specific QinQ traffic and redirecting it to some queue could be expressed with something like:
Quoted 5 lines
testpmd> flow create 0 ingress pattern eth / vlan vid is 64 / vlan vid is 42 / end
actions queue 6 / endSuch a rule is translated as-is to
rte_flowpattern items and action structures.
Thanks, I will look over that.
Quoted 6 lines
Quoted 2 lines
With the above questions in mind I am curious to know what use-cases the proposal is targeted at.
Well, it should be easier to answer if you have a specific use-case in mind you would like to support but that cannot be expressed with the API as defined in [1], in which case please share it with the community.
A use-case would be implementing OvS DPIF flow offload using this API.
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
Quoted 3 lines · Simon Horman
Quoted 2 lines · Adrien Mazarguil
Quoted 1 line · Simon Horman
On Fri, Dec 16, 2016 at 05:24:57PM +0100, Adrien Mazarguil wrote:
[...]
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
I would like to ask some high level questions on the proposal. I apologise in advance if any of these questions are based on a misunderstanding on my part.
* I am wondering about provisions for actions to modify packet data or metadata. I do see support for marking packets. Is the implication of this that the main focus is to provide a mechanism for classification with the assumption that any actions - other than drop and variants of output - would be performed elsewhere?
Quoted 6 lines
Quoted 4 lines
I'm not sure to understand what you mean by "elsewhere" here. Packet marking as currently defined is a purely ingress action, i.e. HW matches some packet and returns a user-defined tag in related meta-data that the PMD copies to the appropriate mbuf structure field before returning it to the application.
By elsewhere I meant in the application, sorry for being unclear.
OK, then a high level definition would be that PMDs perform all actions part of a flow rule, and applications are left to handle what they did not explicitly request to be offloaded.
Quoted 15 lines
Quoted 15 lines
There is provision for egress rules and I wrote down a few ideas describing how they could be useful (as above), however they remain to be defined.
Quoted 4 lines
If so I would observe that this seems somewhat limiting in the case of hardware that can perform a richer set of actions. And seems particularly limiting on egress as there doesn't seem anywhere else that other actions could be performed after classification is performed by this API.
A single flow rule may contain any number of distinct actions. For egress, it means you could wrap matching packets in VLAN and VXLAN at once.
If you wanted to perform the same action twice on matching packets, you'd have to provide two rules with defined priorities and use a non-terminating action for the first one:
Quoted 8 lines
Quoted 4 lines
- Rule with priority 0: match UDP -> add VLAN 42, passthrough
- Rule with priority 1: match UDP -> add VLAN 64, terminatingThis is how automatic QinQ would be defined for outgoing UDP packets.
Ok understood. I have two follow-up questions:
1. Is the "add VLAN" action included at this time, I was not able to find it
It has not been defined yet. All egress offload actions remain to be defined.
Quoted 3 lines
2. Was consideration given to allowing multiple actions in a single rule? I see there would be some advantage to that if classification is expensive.
Yes, it is supported as described in the documentation (now available on-line since the series has been applied [3]).
What is not supported however is requesting the same action to be performed multiple times in a single flow rule, because order is not guaranteed by design. Actions may all happen simultaneously.
This scenario can be handled with multiple rules using priorities as in my QinQ example above, or through a new action performing several things at once in a defined order (e.g. a single "QinQ" action).
Quoted 31 lines
Quoted 11 lines
Quoted 6 lines
* I am curious to know what considerations have been given to supporting support for tunnelling (encapsulation and decapsulation of e.g. VXLAN),
tagging (pushing and popping e.g. VLANs), and labels (pushing or popping e.g. MPLS).Such features seem would useful for application of this work in a variety of situations including overlay networks and VNFs.
This is also what I had in mind and we'd only have to define specific ingress/egress actions for these. Currently
rte_flowonly implements a basic set of existing features from the legacy filtering framework, but is meant to be extended.Thanks. I think that answers most of my questions: what I see as missing in terms of actions can be added.
Quoted 8 lines
Quoted 2 lines
* I am wondering if any thought has gone into supporting matching on the n-th instance of a field that may appear more than once: e.g. VLAN tag.
Sure, please see the latest documentation [1] and testpmd examples [2]. Pattern items being stacked in the same order as protocol layers, maching specific QinQ traffic and redirecting it to some queue could be expressed with something like:
Quoted 5 lines
testpmd> flow create 0 ingress pattern eth / vlan vid is 64 / vlan vid is 42 / end
actions queue 6 / endSuch a rule is translated as-is to
rte_flowpattern items and action structures.Thanks, I will look over that.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
With the above questions in mind I am curious to know what use-cases the proposal is targeted at.
Well, it should be easier to answer if you have a specific use-case in mind you would like to support but that cannot be expressed with the API as defined in [1], in which case please share it with the community.
A use-case would be implementing OvS DPIF flow offload using this API.
OK, OVS has been mentioned several times in this thread and my understanding is that rte_flow seems to accommodate most of its needs according to people familiar with it. Perhaps ML archives can answer the remaining questions you may have about combining rte_flow with OVS.
Quoted 2 lines
[3] http://dpdk.org/doc/guides/prog_guide/rte_flow.html
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
[...]
Quoted 10 lines
Quoted 5 lines
Quoted 3 lines
Well, it should be easier to answer if you have a specific use-case in mind you would like to support but that cannot be expressed with the API as defined in [1], in which case please share it with the community.
A use-case would be implementing OvS DPIF flow offload using this API.
OK, OVS has been mentioned several times in this thread and my understanding is that
rte_flowseems to accommodate most of its needs according to people familiar with it. Perhaps ML archives can answer the remaining questions you may have about combiningrte_flowwith OVS.
For what its worth. I reviewed this and believe it should be sufficient to support the OVS SR-IOV offload use case with action/classifier extensions but without any fundamental changes to the design. We built a prototype OVS offload on top of another API we dubbed Flow-API a year+ ago and there seems to be a 1:1 mapping between that older API and the one now in DPDK so I'm happy. And the missing things seem to fit nicely into extensions.
Also I believe the partial pre-classify use cases should be easily handled as well although I'm not as familiar with the bit-level details of that implementation.
At some point capability discovery will be useful but we certainly don't need those in first iteration and rte_flow doesn't preclude these type of extensions so that is good.
By the way thanks for doing this work Adrien, glad to see it being accepted and drivers picking it up.
Thanks,
John
Quoted 6 lines
Quoted 3 lines