[dpdk-dev] [PATCH] app/testpmd: enabled vxlan and nvgre encap/decap support for rte_flow

Mohammad Abdul Awal mohammad.abdul.awal at intel.com
Fri May 11 12:45:39 CEST 2018


Hi Bernard,


On 10/05/2018 13:47, Iremonger, Bernard wrote:
> Hi Awal,
>
>> -----Original Message-----
>> From: dev [mailto:dev-bounces at dpdk.org] On Behalf Of Mohammad Abdul
>> Awal
>> Sent: Wednesday, May 9, 2018 5:57 PM
>> To: dev at dpdk.org
>> Cc: Awal, Mohammad Abdul <mohammad.abdul.awal at intel.com>
>> Subject: [dpdk-dev] [PATCH] app/testpmd: enabled vxlan and nvgre encap/decap
>> support for rte_flow
> The commit message should not be empty, it should contain a description of the changes
I will add some message here.
>
>> Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal at intel.com>
>> ---
>>   app/test-pmd/cmdline_flow.c | 872
>> ++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 872 insertions(+)
>>
>> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index
>> 5754e78..7d80f2a 100644
>> --- a/app/test-pmd/cmdline_flow.c
>> +++ b/app/test-pmd/cmdline_flow.c
>> @@ -237,6 +237,44 @@ enum index {
>>   	ACTION_OF_POP_MPLS_ETHERTYPE,
>>   	ACTION_OF_PUSH_MPLS,
>>   	ACTION_OF_PUSH_MPLS_ETHERTYPE,
>> +	ACTION_VXLAN_ENCAP,
>> +	ACTION_VXLAN_ENCAP_ETH_DST,
>> +	ACTION_VXLAN_ENCAP_ETH_DST_VALUE,
>> +	ACTION_VXLAN_ENCAP_ETH_SRC,
>> +	ACTION_VXLAN_ENCAP_ETH_SRC_VALUE,
>> +	ACTION_VXLAN_ENCAP_ETH_TYPE,
>> +	ACTION_VXLAN_ENCAP_ETH_TYPE_VALUE,
>> +	ACTION_VXLAN_ENCAP_IPV4_DST,
>> +	ACTION_VXLAN_ENCAP_IPV4_DST_VALUE,
>> +	ACTION_VXLAN_ENCAP_IPV4_SRC,
>> +	ACTION_VXLAN_ENCAP_IPV4_SRC_VALUE,
>> +	ACTION_VXLAN_ENCAP_IPV4_PROTO,
>> +	ACTION_VXLAN_ENCAP_IPV4_PROTO_VALUE,
>> +	ACTION_VXLAN_ENCAP_UDP_SRC,
>> +	ACTION_VXLAN_ENCAP_UDP_SRC_VALUE,
>> +	ACTION_VXLAN_ENCAP_UDP_DST,
>> +	ACTION_VXLAN_ENCAP_UDP_DST_VALUE,
>> +	ACTION_VXLAN_ENCAP_VXLAN_VNI,
>> +	ACTION_VXLAN_ENCAP_VXLAN_VNI_VALUE,
>> +	ACTION_VXLAN_ENCAP_END,
> Is ACTION_VXLAN_ENCAP_END necessary, could ACTION_END be used instead?
Actually, ACTION_VXLAN_ENCAP_END is different than ACTION_END.
ACTION_END creates the RTE_FLOW_ACTION_TYPE_END.
On the other hand, ACTION_VXLAN_ENCAP_END created RTE_FLOW_ITEM_TYPE_END 
at the end pf patterns in the encap definition which is pattern of items 
end by item_end.
So, to treat the two situations separately we need 
ACTION_VXLAN_ENCAP_END, unless there is a clever way present.

>
>> +	ACTION_VXLAN_DECAP,
>> +	ACTION_NVGRE_ENCAP,
>> +	ACTION_NVGRE_ENCAP_ETH_DST,
>> +	ACTION_NVGRE_ENCAP_ETH_DST_VALUE,
>> +	ACTION_NVGRE_ENCAP_ETH_SRC,
>> +	ACTION_NVGRE_ENCAP_ETH_SRC_VALUE,
>> +	ACTION_NVGRE_ENCAP_ETH_TYPE,
>> +	ACTION_NVGRE_ENCAP_ETH_TYPE_VALUE,
>> +	ACTION_NVGRE_ENCAP_IPV4_DST,
>> +	ACTION_NVGRE_ENCAP_IPV4_DST_VALUE,
>> +	ACTION_NVGRE_ENCAP_IPV4_SRC,
>> +	ACTION_NVGRE_ENCAP_IPV4_SRC_VALUE,
>> +	ACTION_NVGRE_ENCAP_IPV4_PROTO,
>> +	ACTION_NVGRE_ENCAP_IPV4_PROTO_VALUE,
>> +	ACTION_NVGRE_ENCAP_NVGRE_VSNI,
>> +	ACTION_NVGRE_ENCAP_NVGRE_VSNI_VALUE,
>> +	ACTION_NVGRE_ENCAP_END,
> Is ACTION_NVGRE_ENCAP_END necessary, could ACTION_END be used instead?
Please see my related comment above.
>
>> +	ACTION_NVGRE_DECAP,
>>   };
>>
>>   /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -256,6
>> +294,28 @@ struct action_rss_data {
>>   	uint16_t queue[ACTION_RSS_QUEUE_NUM];
>>   };
>>
>> +#define ACTION_VXLAN_ENCAP_MAX_PATTERN 5 #define
>> +ACTION_NVGRE_ENCAP_MAX_PATTERN 4
>> +
>> +struct action_vxlan_encap_data {
>> +	struct rte_flow_action_vxlan_encap conf;
>> +	struct rte_flow_item pattern[ACTION_VXLAN_ENCAP_MAX_PATTERN];
>> +	struct rte_flow_item_eth eth;
>> +	struct rte_flow_item_ipv4 ipv4;
>> +	struct rte_flow_item_udp udp;
>> +	struct rte_flow_item_vxlan vxlan;
>> +	uint32_t hdr_flags;
>> +};
>> +
>> +struct action_nvgre_encap_data {
>> +	struct rte_flow_action_nvgre_encap conf;
>> +	struct rte_flow_item pattern[ACTION_NVGRE_ENCAP_MAX_PATTERN];
>> +	struct rte_flow_item_eth eth;
>> +	struct rte_flow_item_ipv4 ipv4;
>> +	struct rte_flow_item_nvgre nvgre;
>> +	uint32_t hdr_flags;
>> +};
>> +
>>   /** Maximum number of subsequent tokens and arguments on the stack. */
>> #define CTX_STACK_SIZE 16
>>
>> @@ -383,6 +443,13 @@ struct token {
>>   		.size = (s), \
>>   	})
>>
>> +#define ARGS_ENTRY_ARB_HTON(o, s) \
>> +	(&(const struct arg){ \
>> +		.hton = 1, \
>> +		.offset = (o), \
>> +		.size = (s), \
>> +	})
>> +
>>   /** Same as ARGS_ENTRY_ARB() with bounded values. */  #define
>> ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
>>   	(&(const struct arg){ \
>> @@ -773,6 +840,10 @@ static const enum index next_action[] = {
>>   	ACTION_OF_SET_VLAN_PCP,
>>   	ACTION_OF_POP_MPLS,
>>   	ACTION_OF_PUSH_MPLS,
>> +	ACTION_VXLAN_ENCAP,
>> +	ACTION_VXLAN_DECAP,
>> +	ACTION_NVGRE_ENCAP,
>> +	ACTION_NVGRE_DECAP,
>>   	ZERO,
>>   };
>>
>> @@ -874,6 +945,44 @@ static const enum index action_jump[] = {
>>   	ZERO,
>>   };
>>
>> +static const enum index action_vxlan_encap[] = {
>> +	ACTION_VXLAN_ENCAP_ETH_DST,
>> +	ACTION_VXLAN_ENCAP_ETH_SRC,
>> +	ACTION_VXLAN_ENCAP_ETH_TYPE,
>> +	ACTION_VXLAN_ENCAP_IPV4_DST,
>> +	ACTION_VXLAN_ENCAP_IPV4_SRC,
>> +	ACTION_VXLAN_ENCAP_IPV4_PROTO,
>> +	ACTION_VXLAN_ENCAP_UDP_DST,
>> +	ACTION_VXLAN_ENCAP_UDP_SRC,
>> +	ACTION_VXLAN_ENCAP_VXLAN_VNI,
>> +	ACTION_VXLAN_ENCAP_END,
>> +	ACTION_NEXT,
>> +	ZERO,
>> +};
>> +
>> +static const enum index action_vxlan_decap[] = {
>> +	ACTION_NEXT,
>> +	ZERO,
>> +};
>> +
>> +static const enum index action_nvgre_encap[] = {
>> +	ACTION_NVGRE_ENCAP_ETH_DST,
>> +	ACTION_NVGRE_ENCAP_ETH_SRC,
>> +	ACTION_NVGRE_ENCAP_ETH_TYPE,
>> +	ACTION_NVGRE_ENCAP_IPV4_DST,
>> +	ACTION_NVGRE_ENCAP_IPV4_SRC,
>> +	ACTION_NVGRE_ENCAP_IPV4_PROTO,
>> +	ACTION_NVGRE_ENCAP_NVGRE_VSNI,
>> +	ACTION_NVGRE_ENCAP_END,
>> +	ACTION_NEXT,
>> +	ZERO,
>> +};
>> +
>> +static const enum index action_nvgre_decap[] = {
>> +	ACTION_NEXT,
>> +	ZERO,
>> +};
>> +
>>   static int parse_init(struct context *, const struct token *,
>>   		      const char *, unsigned int,
>>   		      void *, unsigned int);
>> @@ -896,6 +1005,42 @@ static int parse_vc_action_rss_type(struct context *,
>> const struct token *,  static int parse_vc_action_rss_queue(struct context *,
>> const struct token *,
>>   				     const char *, unsigned int, void *,
>>   				     unsigned int);
>> +static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
>> +				       const char *, unsigned int, void *,
>> +				       unsigned int);
>> +static int parse_vc_action_vxlan_decap(struct context *, const struct token *,
>> +				       const char *, unsigned int, void *,
>> +				       unsigned int);
>> +static int parse_vc_action_vxlan_encap_fields(struct context *,
>> +					      const struct token *,
>> +					      const char *, unsigned int,
>> +					      void *, unsigned int);
>> +static int parse_vc_action_vxlan_encap_fields_value(struct context *,
>> +						    const struct token *,
>> +						    const char *, unsigned int,
>> +						    void *, unsigned int);
>> +static int parse_vc_action_vxlan_encap_end(struct context *,
>> +					   const struct token *,
>> +					   const char *, unsigned int,
>> +					   void *, unsigned int);
>> +static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
>> +				       const char *, unsigned int, void *,
>> +				       unsigned int);
>> +static int parse_vc_action_nvgre_decap(struct context *, const struct token *,
>> +				       const char *, unsigned int, void *,
>> +				       unsigned int);
>> +static int parse_vc_action_nvgre_encap_fields(struct context *,
>> +					      const struct token *,
>> +					      const char *, unsigned int,
>> +					      void *, unsigned int);
>> +static int parse_vc_action_nvgre_encap_fields_value(struct context *,
>> +						    const struct token *,
>> +						    const char *, unsigned int,
>> +						    void *, unsigned int);
>> +static int parse_vc_action_nvgre_encap_end(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);
>> @@ -2362,6 +2507,256 @@ static const struct token token_list[] = {
>>   			      ethertype)),
>>   		.call = parse_vc_conf,
>>   	},
>> +	[ACTION_VXLAN_ENCAP] = {
>> +		.name = "vxlan_encap",
>> +		.help = "encap flow with vxlan tunnel definition",
>> +		.priv = PRIV_ACTION(VXLAN_ENCAP,
>> +				    sizeof(struct action_vxlan_encap_data)),
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> 	NEXT_ENTRY(ACTION_VXLAN_ENCAP_ETH_DST,
>> +					ACTION_VXLAN_ENCAP_ETH_SRC,
>> +					ACTION_VXLAN_ENCAP_ETH_TYPE,
>> +					ACTION_VXLAN_ENCAP_IPV4_DST,
>> +					ACTION_VXLAN_ENCAP_IPV4_SRC,
>> +					ACTION_VXLAN_ENCAP_IPV4_PROTO,
>> +					ACTION_VXLAN_ENCAP_UDP_DST,
>> +					ACTION_VXLAN_ENCAP_UDP_SRC,
>> +					ACTION_VXLAN_ENCAP_VXLAN_VNI,
>> +					ACTION_VXLAN_ENCAP_END)),
>> +		.call = parse_vc_action_vxlan_encap,
>> +	},
>> +	[ACTION_VXLAN_DECAP] = {
>> +		.name = "vxlan_decap",
>> +		.help = "decap flow with vxlan tunnel definition",
>> +		.priv = PRIV_ACTION(VXLAN_DECAP, 0),
>> +		.next = NEXT(action_vxlan_decap),
>> +		.call = parse_vc_action_vxlan_decap,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_DST] = {
>> +		.name = "eth_dst",
>> +		.help = "destination MAC for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_ETH_DST_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_DST_VALUE] = {
>> +		.name = "eth_dst_value",
>> +		.help = "destination MAC for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_SRC] = {
>> +		.name = "eth_src",
>> +		.help = "source MAC for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_ETH_SRC_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_SRC_VALUE] = {
>> +		.name = "eth_src_value",
>> +		.help = "source MAC for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_TYPE] = {
>> +		.name = "eth_type",
>> +		.help = "eth type for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_ETH_TYPE_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_ETH_TYPE_VALUE] = {
>> +		.name = "eth_type_value",
>> +		.help = "eth type for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_DST] = {
>> +		.name = "ipv4_dst",
>> +		.help = "destination ipv4 IP for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_IPV4_DST_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_DST_VALUE] = {
>> +		.name = "ipv4_dst_value",
>> +		.help = "destination ipv4 IP for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_SRC] = {
>> +		.name = "ipv4_src",
>> +		.help = "source ipv4 IP for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_IPV4_SRC_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_SRC_VALUE] = {
>> +		.name = "ipv4_src_value",
>> +		.help = "source ipv4 IP for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_PROTO] = {
>> +		.name = "ipv4_proto",
>> +		.help = "ipv4 proto for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_IPV4_PROTO_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_IPV4_PROTO_VALUE] = {
>> +		.name = "ipv4_proto_value",
>> +		.help = "ipv4 proto for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_UDP_DST] = {
>> +		.name = "udp_dst",
>> +		.help = "udp destination port for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_UDP_DST_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_UDP_DST_VALUE] = {
>> +		.name = "udp_dst_value",
>> +		.help = "udp destination port for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_UDP_SRC] = {
>> +		.name = "udp_src",
>> +		.help = "udp source port for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_UDP_SRC_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_UDP_SRC_VALUE] = {
>> +		.name = "udp_src_value",
>> +		.help = "udp source port for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_VXLAN_VNI] = {
>> +		.name = "vxlan_vni",
>> +		.help = "vxlan vni for vxlan tunnel",
>> +		.next = NEXT(action_vxlan_encap,
>> +
>> NEXT_ENTRY(ACTION_VXLAN_ENCAP_VXLAN_VNI_VALUE)),
>> +		.call = parse_vc_action_vxlan_encap_fields,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_VXLAN_VNI_VALUE] = {
>> +		.name = "vxlan_vni_value",
>> +		.help = "vxlan vni for vxlan tunnel",
>> +		.call = parse_vc_action_vxlan_encap_fields_value,
>> +	},
>> +	[ACTION_VXLAN_ENCAP_END] = {
>> +		.name = "end",
>> +		.help = "end of the pattern for vxlan encap",
>> +		.call = parse_vc_action_vxlan_encap_end,
> "end" only is being parsed, could ACTION_END be used instead?
Please see my related comment above.
>
>> +	},
>> +	[ACTION_NVGRE_ENCAP] = {
>> +		.name = "nvgre_encap",
>> +		.help = "encap flow with nvgre tunnel definition",
>> +		.priv = PRIV_ACTION(NVGRE_ENCAP,
>> +				    sizeof(struct action_nvgre_encap_data)),
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> 	NEXT_ENTRY(ACTION_NVGRE_ENCAP_ETH_DST,
>> +					ACTION_NVGRE_ENCAP_ETH_SRC,
>> +					ACTION_NVGRE_ENCAP_ETH_TYPE,
>> +					ACTION_NVGRE_ENCAP_IPV4_DST,
>> +					ACTION_NVGRE_ENCAP_IPV4_SRC,
>> +					ACTION_NVGRE_ENCAP_IPV4_PROTO,
>> +					ACTION_NVGRE_ENCAP_NVGRE_VSNI,
>> +					ACTION_NVGRE_ENCAP_END)),
>> +		.call = parse_vc_action_nvgre_encap,
>> +	},
>> +	[ACTION_NVGRE_DECAP] = {
>> +		.name = "nvgre_decap",
>> +		.help = "decap flow with nvgre tunnel definition",
>> +		.priv = PRIV_ACTION(NVGRE_DECAP, 0),
>> +		.next = NEXT(action_nvgre_decap),
>> +		.call = parse_vc_action_nvgre_decap,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_DST] = {
>> +		.name = "eth_dst",
>> +		.help = "destination MAC for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_ETH_DST_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_DST_VALUE] = {
>> +		.name = "eth_dst_value",
>> +		.help = "destination MAC for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_SRC] = {
>> +		.name = "eth_src",
>> +		.help = "source MAC for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_ETH_SRC_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_SRC_VALUE] = {
>> +		.name = "eth_src_value",
>> +		.help = "source MAC for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_TYPE] = {
>> +		.name = "eth_type",
>> +		.help = "eth type for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_ETH_TYPE_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_ETH_TYPE_VALUE] = {
>> +		.name = "eth_type_value",
>> +		.help = "eth type for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_DST] = {
>> +		.name = "ipv4_dst",
>> +		.help = "destination ipv4 IP for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_IPV4_DST_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_DST_VALUE] = {
>> +		.name = "ipv4_dst_value",
>> +		.help = "destination ipv4 IP for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_SRC] = {
>> +		.name = "ipv4_src",
>> +		.help = "source ipv4 IP for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_IPV4_SRC_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_SRC_VALUE] = {
>> +		.name = "ipv4_src_value",
>> +		.help = "source ipv4 IP for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_PROTO] = {
>> +		.name = "ipv4_proto",
>> +		.help = "ipv4 proto for nvgre tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_IPV4_PROTO_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_IPV4_PROTO_VALUE] = {
>> +		.name = "ipv4_proto_value",
>> +		.help = "ipv4 proto for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_NVGRE_VSNI] = {
>> +		.name = "nvgre_vsni",
>> +		.help = "nvgre vsni for NVGRE tunnel",
>> +		.next = NEXT(action_nvgre_encap,
>> +
>> NEXT_ENTRY(ACTION_NVGRE_ENCAP_NVGRE_VSNI_VALUE)),
>> +		.call = parse_vc_action_nvgre_encap_fields,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_NVGRE_VSNI_VALUE] = {
>> +		.name = "nvgre_vsni_value",
>> +		.help = "nvgre vsni for nvgre tunnel",
>> +		.call = parse_vc_action_nvgre_encap_fields_value,
>> +	},
>> +	[ACTION_NVGRE_ENCAP_END] = {
>> +		.name = "end",
>> +		.help = "end of the pattern for nvgre encap",
>> +		.call = parse_vc_action_nvgre_encap_end,
> "end" only is being parsed, could ACTION_END be used instead?
Please see my related comment above.
>
>> +	},
>>   };
>>
>>   /** Remove and return last entry from argument stack. */ @@ -2924,6
>> +3319,482 @@ parse_vc_action_rss_queue(struct context *ctx, const struct
>> token *token,
>>   	return len;
>>   }
>>
>> +/** Parse VXLAN_ENCAP action. */
>> +static int
>> +parse_vc_action_vxlan_encap(struct context *ctx, const struct token *token,
>> +			    const char *str, unsigned int len,
>> +			    void *buf, unsigned int size)
>> +{
>> +	struct buffer *out = buf;
>> +	struct rte_flow_action *action;
>> +	struct action_vxlan_encap_data *data;
>> +	int ret;
>> +
>> +	ret = parse_vc(ctx, token, str, len, buf, size);
>> +	if (ret < 0)
>> +		return ret;
>> +	/* Nothing else to do if there is no buffer. */
>> +	if (!out)
>> +		return ret;
>> +	if (!out->args.vc.actions_n)
>> +		return -1;
>> +	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
>> +	/* Point to selected object. */
>> +	ctx->object = out->args.vc.data;
>> +	ctx->objmask = NULL;
>> +	/* Set up default configuration. */
>> +	data = ctx->object;
>> +	data->conf.definition = data->pattern;
>> +	action->conf = &data->conf;
>> +
>> +	return ret;
>> +}
>> +
>> +/** Parse VXLAN_DECAP action. */
>> +static int
>> +parse_vc_action_vxlan_decap(struct context *ctx, const struct token *token,
>> +			    const char *str, unsigned int len,
>> +			    void *buf, unsigned int size)
>> +{
>> +	struct buffer *out = buf;
>> +	int ret;
>> +
>> +	ret = parse_vc(ctx, token, str, len, buf, size);
>> +	if (ret < 0)
>> +		return ret;
>> +	/* Nothing else to do if there is no buffer. */
>> +	if (!out)
>> +		return ret;
>> +	if (!out->args.vc.actions_n)
>> +		return -1;
>> +	/* Point to selected object. */
>> +	ctx->object = out->args.vc.data;
>> +	ctx->objmask = NULL;
>> +	return ret;
>> +}
>> +
>> +static uint32_t get_proto_index_using_flag(uint32_t flag) {
>> +	uint32_t c = 0, i = 0;
>> +	uint32_t supported_ptypes[] = {
>> +					RTE_PTYPE_L2_ETHER,
>> +					RTE_PTYPE_L2_ETHER_VLAN,
>> +					RTE_PTYPE_L3_IPV4,
>> +					RTE_PTYPE_L4_UDP,
>> +					RTE_PTYPE_TUNNEL_VXLAN,
>> +					RTE_PTYPE_TUNNEL_NVGRE
>> +				       };
>> +
>> +	for (i = 0; i != RTE_DIM(supported_ptypes); i++) {
>> +		if (supported_ptypes[i] & flag)
>> +			c++;
>> +	}
>> +	c = (c > 0) ? (c - 1) : 0;
>> +
>> +	return c;
>> +}
>> +
>> +/** Parse VXLAN_ENCAP action pattern fields. */ static int
>> +parse_vc_action_vxlan_encap_fields(struct context *ctx,
>> +				   const struct token *token,
>> +				   const char *str, unsigned int len,
>> +				   void *buf, unsigned int size)
>> +{
>> +	struct action_vxlan_encap_data *data;
>> +	uint32_t p_index;
>> +
>> +	(void)buf;
>> +	(void)size;
>> +	/* Token name must match. */
>> +	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
>> +		return -1;
>> +	if (!ctx->object)
>> +		return len;
>> +	switch (ctx->curr) {
>> +	case ACTION_VXLAN_ENCAP_ETH_DST:
>> +	case ACTION_VXLAN_ENCAP_ETH_SRC:
>> +	case ACTION_VXLAN_ENCAP_ETH_TYPE:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_L2_ETHER;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->eth;
>> +		data->pattern[p_index].mask = &rte_flow_item_eth_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_ETH;
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_IPV4_DST:
>> +	case ACTION_VXLAN_ENCAP_IPV4_SRC:
>> +	case ACTION_VXLAN_ENCAP_IPV4_PROTO:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_L3_IPV4;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->ipv4;
>> +		data->pattern[p_index].mask = &rte_flow_item_ipv4_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_IPV4;
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_UDP_DST:
>> +	case ACTION_VXLAN_ENCAP_UDP_SRC:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_L4_UDP;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->udp;
>> +		data->pattern[p_index].mask = &rte_flow_item_udp_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_UDP;
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_VXLAN_VNI:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_TUNNEL_VXLAN;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->vxlan;
>> +		data->pattern[p_index].mask = &rte_flow_item_vxlan_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_VXLAN;
>> +		break;
>> +	default:
>> +		return -1;
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +/** Parse VXLAN_ENCAP action pattern fields value. */ static int
>> +parse_vc_action_vxlan_encap_fields_value(struct context *ctx,
>> +					 const struct token *token,
>> +					 const char *str, unsigned int len,
>> +					 void *buf, unsigned int size)
>> +{
>> +	struct action_vxlan_encap_data *data;
>> +	struct ether_addr mac;
>> +	char str2[len + 1];
>> +	struct in_addr ip4;
>> +	uint16_t val1;
>> +	uint32_t val2;
>> +	int ret;
>> +
>> +	(void)token;
>> +	(void)buf;
>> +	if (!ctx->object)
>> +		return len;
>> +	data = ctx->object;
>> +	switch (ctx->curr) {
>> +	case ACTION_VXLAN_ENCAP_ETH_DST_VALUE:
>> +		ret = cmdline_parse_etheraddr(NULL, str, &mac, size);
>> +		if (ret < 0 || (unsigned int)ret != len)
>> +			return -1;
>> +		memcpy(&data->eth.dst, &mac, sizeof(mac));
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_ETH_SRC_VALUE:
>> +		ret = cmdline_parse_etheraddr(NULL, str, &mac, size);
>> +		if (ret < 0 || (unsigned int)ret != len)
>> +			return -1;
>> +		memcpy(&data->eth.src, &mac, sizeof(mac));
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_ETH_TYPE_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->eth.type = htons(val1);
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_IPV4_DST_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		ret = inet_pton(AF_INET, str2, &ip4);
>> +		if (ret != 1)
>> +			return -1;
>> +		memcpy(&data->ipv4.hdr.dst_addr, &ip4, sizeof(ip4));
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_IPV4_SRC_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		ret = inet_pton(AF_INET, str2, &ip4);
>> +		if (ret != 1)
>> +			return -1;
>> +		memcpy(&data->ipv4.hdr.src_addr, &ip4, sizeof(ip4));
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_IPV4_PROTO_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->ipv4.hdr.next_proto_id = val1;
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_UDP_DST_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->udp.hdr.dst_port = htons(val1);
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_UDP_SRC_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->udp.hdr.src_port = htons(val1);
>> +		break;
>> +	case ACTION_VXLAN_ENCAP_VXLAN_VNI_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val2 = strtoul(str2, NULL, 0);
>> +		if (val2 == 0)
>> +			return -1;
>> +		data->vxlan.vni[0] = (uint8_t)((val2 >> 16) & 0xff);
>> +		data->vxlan.vni[1] = (uint8_t)((val2 >> 8) & 0xff);
>> +		data->vxlan.vni[2] = (uint8_t)(val2 & 0xff);
>> +		break;
>> +	default:
>> +		return -1;
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +/** Parse VXLAN_ENCAP action pattern end. */ static int
>> +parse_vc_action_vxlan_encap_end(struct context *ctx,
>> +				const struct token *token,
>> +				const char *str, unsigned int len,
>> +				void *buf, unsigned int size)
>> +{
> This function should not be necessary if ACTION_END be used instead?
Please see my related comment above.
>
>> +	struct action_vxlan_encap_data *data;
>> +	uint32_t p_index;
>> +
>> +	(void)buf;
>> +	(void)size;
>> +	/* Token name must match. */
>> +	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
>> +		return -1;
>> +	if (ctx->curr != ACTION_VXLAN_ENCAP_END)
>> +		return -1;
>> +	if (!ctx->object)
>> +		return len;
>> +	data = ctx->object;
>> +	p_index = get_proto_index_using_flag(data->hdr_flags);
>> +	data->pattern[p_index + 1].type = RTE_FLOW_ITEM_TYPE_END;
>> +
>> +	return len;
>> +}
>> +
>> +/** Parse NVGRE_ENCAP action. */
>> +static int
>> +parse_vc_action_nvgre_encap(struct context *ctx, const struct token *token,
>> +			    const char *str, unsigned int len,
>> +			    void *buf, unsigned int size)
>> +{
>> +	struct buffer *out = buf;
>> +	struct rte_flow_action *action;
>> +	struct action_nvgre_encap_data *data;
>> +	int ret;
>> +
>> +	ret = parse_vc(ctx, token, str, len, buf, size);
>> +	if (ret < 0)
>> +		return ret;
>> +	/* Nothing else to do if there is no buffer. */
>> +	if (!out)
>> +		return ret;
>> +	if (!out->args.vc.actions_n)
>> +		return -1;
>> +	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
>> +	/* Point to selected object. */
>> +	ctx->object = out->args.vc.data;
>> +	ctx->objmask = NULL;
>> +	/* Set up default configuration. */
>> +	data = ctx->object;
>> +	data->conf.definition = data->pattern;
>> +	action->conf = &data->conf;
>> +
>> +	return ret;
>> +}
>> +
>> +/** Parse NVGRE_DECAP action. */
>> +static int
>> +parse_vc_action_nvgre_decap(struct context *ctx, const struct token *token,
>> +			    const char *str, unsigned int len,
>> +			    void *buf, unsigned int size)
>> +{
>> +	struct buffer *out = buf;
>> +	int ret;
>> +
>> +	ret = parse_vc(ctx, token, str, len, buf, size);
>> +	if (ret < 0)
>> +		return ret;
>> +	/* Nothing else to do if there is no buffer. */
>> +	if (!out)
>> +		return ret;
>> +	if (!out->args.vc.actions_n)
>> +		return -1;
>> +	/* Point to selected object. */
>> +	ctx->object = out->args.vc.data;
>> +	ctx->objmask = NULL;
>> +	return ret;
>> +}
>> +
>> +/** Parse NVGRE_ENCAP action pattern fields. */ static int
>> +parse_vc_action_nvgre_encap_fields(struct context *ctx,
>> +				   const struct token *token,
>> +				   const char *str, unsigned int len,
>> +				   void *buf, unsigned int size)
>> +{
>> +	struct action_nvgre_encap_data *data;
>> +	uint32_t p_index;
>> +
>> +	(void)buf;
>> +	(void)size;
>> +	/* Token name must match. */
>> +	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
>> +		return -1;
>> +	if (!ctx->object)
>> +		return len;
>> +	switch (ctx->curr) {
>> +	case ACTION_NVGRE_ENCAP_ETH_DST:
>> +	case ACTION_NVGRE_ENCAP_ETH_SRC:
>> +	case ACTION_NVGRE_ENCAP_ETH_TYPE:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_L2_ETHER;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->eth;
>> +		data->pattern[p_index].mask = &rte_flow_item_eth_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_ETH;
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_IPV4_DST:
>> +	case ACTION_NVGRE_ENCAP_IPV4_SRC:
>> +	case ACTION_NVGRE_ENCAP_IPV4_PROTO:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_L3_IPV4;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->ipv4;
>> +		data->pattern[p_index].mask = &rte_flow_item_ipv4_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_IPV4;
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_NVGRE_VSNI:
>> +		data = ctx->object;
>> +		data->hdr_flags |= RTE_PTYPE_TUNNEL_NVGRE;
>> +		p_index = get_proto_index_using_flag(data->hdr_flags);
>> +		data->pattern[p_index].spec = &data->nvgre;
>> +		data->pattern[p_index].mask = &rte_flow_item_nvgre_mask;
>> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_NVGRE;
>> +		break;
>> +	default:
>> +		return -1;
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +/** Parse NVGRE_ENCAP action pattern fields value. */ static int
>> +parse_vc_action_nvgre_encap_fields_value(struct context *ctx,
>> +					 const struct token *token,
>> +					 const char *str, unsigned int len,
>> +					 void *buf, unsigned int size)
>> +{
>> +	struct action_nvgre_encap_data *data;
>> +	struct ether_addr mac;
>> +	char str2[len + 1];
>> +	struct in_addr ip4;
>> +	uint16_t val1;
>> +	uint32_t val2;
>> +	int ret;
>> +
>> +	(void)token;
>> +	(void)buf;
>> +	if (!ctx->object)
>> +		return len;
>> +	data = ctx->object;
>> +	switch (ctx->curr) {
>> +	case ACTION_NVGRE_ENCAP_ETH_DST_VALUE:
>> +		ret = cmdline_parse_etheraddr(NULL, str, &mac, size);
>> +		if (ret < 0 || (unsigned int)ret != len)
>> +			return -1;
>> +		memcpy(&data->eth.dst, &mac, sizeof(mac));
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_ETH_SRC_VALUE:
>> +		ret = cmdline_parse_etheraddr(NULL, str, &mac, size);
>> +		if (ret < 0 || (unsigned int)ret != len)
>> +			return -1;
>> +		memcpy(&data->eth.src, &mac, sizeof(mac));
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_ETH_TYPE_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->eth.type = htons(val1);
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_IPV4_DST_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		ret = inet_pton(AF_INET, str2, &ip4);
>> +		if (ret != 1)
>> +			return -1;
>> +		memcpy(&data->ipv4.hdr.dst_addr, &ip4, sizeof(ip4));
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_IPV4_SRC_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		ret = inet_pton(AF_INET, str2, &ip4);
>> +		if (ret != 1)
>> +			return -1;
>> +		memcpy(&data->ipv4.hdr.src_addr, &ip4, sizeof(ip4));
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_IPV4_PROTO_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val1 = strtoul(str2, NULL, 0);
>> +		if (val1 == 0)
>> +			return -1;
>> +		data->ipv4.hdr.next_proto_id = val1;
>> +		break;
>> +	case ACTION_NVGRE_ENCAP_NVGRE_VSNI_VALUE:
>> +		memcpy(str2, str, len);
>> +		str2[len] = '\0';
>> +		val2 = strtoul(str2, NULL, 0);
>> +		if (val2 == 0)
>> +			return -1;
>> +		data->nvgre.tni[0] = (uint8_t)((val2 >> 16) & 0xff);
>> +		data->nvgre.tni[1] = (uint8_t)((val2 >> 8) & 0xff);
>> +		data->nvgre.tni[2] = (uint8_t)(val2 & 0xff);
>> +		break;
>> +	default:
>> +		return -1;
>> +	}
>> +
>> +	return len;
>> +}
>> +
>> +/** Parse NVGRE_ENCAP action pattern end. */ static int
>> +parse_vc_action_nvgre_encap_end(struct context *ctx,
>> +				const struct token *token,
>> +				const char *str, unsigned int len,
>> +				void *buf, unsigned int size)
>> +{
> This function should not be necessary if ACTION_END be used instead?
Please see my related comment above.
>
>> +	struct action_nvgre_encap_data *data;
>> +	uint32_t p_index;
>> +
>> +	(void)buf;
>> +	(void)size;
>> +	/* Token name must match. */
>> +	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
>> +		return -1;
>> +	if (ctx->curr != ACTION_NVGRE_ENCAP_END)
>> +		return -1;
>> +	if (!ctx->object)
>> +		return len;
>> +	data = ctx->object;
>> +	p_index = get_proto_index_using_flag(data->hdr_flags);
>> +	data->pattern[p_index + 1].type = RTE_FLOW_ITEM_TYPE_END;
>> +
>> +	return len;
>> +}
>> +
>>   /** Parse tokens for destroy command. */  static int  parse_destroy(struct
>> context *ctx, const struct token *token, @@ -2961,6 +3832,7 @@
>> parse_destroy(struct context *ctx, const struct token *token,
>>   	return len;
>>   }
>>
>> +
> Extra blank line should be removed.
Removed.
>
>>   /** Parse tokens for flush command. */
>>   static int
>>   parse_flush(struct context *ctx, const struct token *token,
>> --
>> 2.7.4
> In the Testpmd  Application/User Guide, there is section 4.12. Flow rules management.
> dpdk/build/doc/html/guides/testpmd_app_ug/index.html
>
> As the encap and decap flows are fairly complex, It might be worth adding sections on Sample Encap flow rules and Sample Decap flow rules.
I will add some documentation in the flow guide.

Regards,
Awal.

>
> Regards,
>
> Bernard.
>



More information about the dev mailing list