[dpdk-dev,v2,1/2] app/testpmd: enabled vxlan and nvgre encap/decap support for rte_flow

Message ID 1526058841-31650-2-git-send-email-mohammad.abdul.awal@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Mohammad Abdul Awal May 11, 2018, 5:14 p.m. UTC
  We have enabled testpmd application with ability to create a flow with
vxlan/nvgre tunnel types and with encapsulation/decapsulation
functionalities.

Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
---
 app/test-pmd/cmdline_flow.c | 937 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 937 insertions(+)
  

Comments

Iremonger, Bernard May 14, 2018, 11:14 a.m. UTC | #1
Hi Awal,

> -----Original Message-----
> From: Awal, Mohammad Abdul
> Sent: Friday, May 11, 2018 6:14 PM
> To: dev@dpdk.org; Iremonger, Bernard <bernard.iremonger@intel.com>;
> adrien.mazarguil@6wind.com
> Subject: [PATCH v2 1/2] app/testpmd: enabled vxlan and nvgre encap/decap
> support for rte_flow
> 
> We have enabled testpmd application with ability to create a flow with
> vxlan/nvgre tunnel types and with encapsulation/decapsulation functionalities.
> 
> Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
> ---
>  app/test-pmd/cmdline_flow.c | 937
> ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 937 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index
> 5754e78..5ffc127 100644
> --- a/app/test-pmd/cmdline_flow.c
> +++ b/app/test-pmd/cmdline_flow.c
> @@ -237,6 +237,48 @@ 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_VLAN_TCI,
> +	ACTION_VXLAN_ENCAP_VLAN_TCI_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,
> +	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_VLAN_TCI,
> +	ACTION_NVGRE_ENCAP_VLAN_TCI_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,
> +	ACTION_NVGRE_DECAP,
>  };
> 
>  /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -256,6
> +298,30 @@ 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_vlan vlan;
> +	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_vlan vlan;
> +	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 +449,13 @@ struct token {
>  		.size = (s), \
>  	})
> 
> +#define ARGS_ENTRY_ARB_HTON(o, s) \
> +	(&(const struct arg){ \
> +		.hton = 1, \
> +		.offset = (o), \
> +		.size = (s), \
> +	})
> +

The ARGS_ENTRY_ARB_HTON macro does not seem to be used in the code.
Should it be removed?

>  /** Same as ARGS_ENTRY_ARB() with bounded values. */  #define
> ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
>  	(&(const struct arg){ \
> @@ -773,6 +846,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 +951,46 @@ 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_VLAN_TCI,
> +	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_VLAN_TCI,
> +	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 +1013,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 +2515,282 @@ 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_VLAN_TCI,
> +					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_VLAN_TCI] = {
> +		.name = "vlan_tci",
> +		.help = "vlan tci for vxlan tunnel",
> +		.next = NEXT(action_vxlan_encap,
> +
> NEXT_ENTRY(ACTION_VXLAN_ENCAP_VLAN_TCI_VALUE)),
> +		.call = parse_vc_action_vxlan_encap_fields,
> +	},
> +	[ACTION_VXLAN_ENCAP_VLAN_TCI_VALUE] = {
> +		.name = "vlan_tci_value",
> +		.help = "vlan tci 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,
> +	},
> +	[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_VLAN_TCI,
> +					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_VLAN_TCI] = {
> +		.name = "vlan_tci",
> +		.help = "vlan tci for nvgre tunnel",
> +		.next = NEXT(action_nvgre_encap,
> +
> NEXT_ENTRY(ACTION_NVGRE_ENCAP_VLAN_TCI_VALUE)),
> +		.call = parse_vc_action_nvgre_encap_fields,
> +	},
> +	[ACTION_NVGRE_ENCAP_VLAN_TCI_VALUE] = {
> +		.name = "vlan_tci_value",
> +		.help = "vlan tci 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,
> +	},
>  };
> 
>  /** Remove and return last entry from argument stack. */ @@ -2924,6
> +3353,514 @@ parse_vc_action_rss_queue(struct context *ctx, const struct
> token *token,
>  	return len;
>  }
> 
> +/** Parse VXLAN_ENCAP action. */
> +static int __rte_unused
> +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 __rte_unused
> +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_VLAN_TCI:
> +		data = ctx->object;
> +		data->hdr_flags |= RTE_PTYPE_L2_ETHER_VLAN;
> +		p_index = get_proto_index_using_flag(data->hdr_flags);
> +		data->pattern[p_index].spec = &data->vlan;
> +		data->pattern[p_index].mask = &rte_flow_item_vlan_mask;
> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_VLAN;
> +		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
> +__rte_unused 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_VLAN_TCI_VALUE:
> +		memcpy(str2, str, len);
> +		str2[len] = '\0';
> +		val1 = strtoul(str2, NULL, 0);
> +		if (val1 == 0)
> +			return -1;
> +		data->vlan.tci = 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 __rte_unused
> +parse_vc_action_vxlan_encap_end(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->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 __rte_unused
> +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 __rte_unused
> +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 __rte_unused
> +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_VLAN_TCI:
> +		data = ctx->object;
> +		data->hdr_flags |= RTE_PTYPE_L2_ETHER_VLAN;
> +		p_index = get_proto_index_using_flag(data->hdr_flags);
> +		data->pattern[p_index].spec = &data->vlan;
> +		data->pattern[p_index].mask = &rte_flow_item_vlan_mask;
> +		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_VLAN;
> +		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
> +__rte_unused 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_VLAN_TCI_VALUE:
> +		memcpy(str2, str, len);
> +		str2[len] = '\0';
> +		val1 = strtoul(str2, NULL, 0);
> +		if (val1 == 0)
> +			return -1;
> +		data->vlan.tci = 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 __rte_unused
> +parse_vc_action_nvgre_encap_end(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->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,
> --
> 2.7.4

Regards,

Bernard.
  

Patch

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 5754e78..5ffc127 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -237,6 +237,48 @@  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_VLAN_TCI,
+	ACTION_VXLAN_ENCAP_VLAN_TCI_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,
+	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_VLAN_TCI,
+	ACTION_NVGRE_ENCAP_VLAN_TCI_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,
+	ACTION_NVGRE_DECAP,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -256,6 +298,30 @@  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_vlan vlan;
+	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_vlan vlan;
+	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 +449,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 +846,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 +951,46 @@  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_VLAN_TCI,
+	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_VLAN_TCI,
+	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 +1013,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 +2515,282 @@  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_VLAN_TCI,
+					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_VLAN_TCI] = {
+		.name = "vlan_tci",
+		.help = "vlan tci for vxlan tunnel",
+		.next = NEXT(action_vxlan_encap,
+			     NEXT_ENTRY(ACTION_VXLAN_ENCAP_VLAN_TCI_VALUE)),
+		.call = parse_vc_action_vxlan_encap_fields,
+	},
+	[ACTION_VXLAN_ENCAP_VLAN_TCI_VALUE] = {
+		.name = "vlan_tci_value",
+		.help = "vlan tci 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,
+	},
+	[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_VLAN_TCI,
+					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_VLAN_TCI] = {
+		.name = "vlan_tci",
+		.help = "vlan tci for nvgre tunnel",
+		.next = NEXT(action_nvgre_encap,
+			     NEXT_ENTRY(ACTION_NVGRE_ENCAP_VLAN_TCI_VALUE)),
+		.call = parse_vc_action_nvgre_encap_fields,
+	},
+	[ACTION_NVGRE_ENCAP_VLAN_TCI_VALUE] = {
+		.name = "vlan_tci_value",
+		.help = "vlan tci 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,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -2924,6 +3353,514 @@  parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse VXLAN_ENCAP action. */
+static int __rte_unused
+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 __rte_unused
+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_VLAN_TCI:
+		data = ctx->object;
+		data->hdr_flags |= RTE_PTYPE_L2_ETHER_VLAN;
+		p_index = get_proto_index_using_flag(data->hdr_flags);
+		data->pattern[p_index].spec = &data->vlan;
+		data->pattern[p_index].mask = &rte_flow_item_vlan_mask;
+		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_VLAN;
+		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 __rte_unused
+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_VLAN_TCI_VALUE:
+		memcpy(str2, str, len);
+		str2[len] = '\0';
+		val1 = strtoul(str2, NULL, 0);
+		if (val1 == 0)
+			return -1;
+		data->vlan.tci = 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 __rte_unused
+parse_vc_action_vxlan_encap_end(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->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 __rte_unused
+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 __rte_unused
+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 __rte_unused
+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_VLAN_TCI:
+		data = ctx->object;
+		data->hdr_flags |= RTE_PTYPE_L2_ETHER_VLAN;
+		p_index = get_proto_index_using_flag(data->hdr_flags);
+		data->pattern[p_index].spec = &data->vlan;
+		data->pattern[p_index].mask = &rte_flow_item_vlan_mask;
+		data->pattern[p_index].type = RTE_FLOW_ITEM_TYPE_VLAN;
+		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 __rte_unused
+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_VLAN_TCI_VALUE:
+		memcpy(str2, str, len);
+		str2[len] = '\0';
+		val1 = strtoul(str2, NULL, 0);
+		if (val1 == 0)
+			return -1;
+		data->vlan.tci = 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 __rte_unused
+parse_vc_action_nvgre_encap_end(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->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,