From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id 4A6891C088 for ; Fri, 11 May 2018 12:45:42 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 May 2018 03:45:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,388,1520924400"; d="scan'208";a="45157288" Received: from awalabdu-mobl.ger.corp.intel.com (HELO [163.33.228.102]) ([163.33.228.102]) by fmsmga002.fm.intel.com with ESMTP; 11 May 2018 03:45:40 -0700 To: "Iremonger, Bernard" , "dev@dpdk.org" , Adrien Mazarguil References: <1525884992-24390-1-git-send-email-mohammad.abdul.awal@intel.com> <8CEF83825BEC744B83065625E567D7C24E0C9955@IRSMSX108.ger.corp.intel.com> From: Mohammad Abdul Awal Message-ID: <208904aa-ab66-aa1d-3e36-2b7cc18397ac@intel.com> Date: Fri, 11 May 2018 11:45:39 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <8CEF83825BEC744B83065625E567D7C24E0C9955@IRSMSX108.ger.corp.intel.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US Subject: Re: [dpdk-dev] [PATCH] app/testpmd: enabled vxlan and nvgre encap/decap support for rte_flow X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 May 2018 10:45:43 -0000 Hi Bernard, On 10/05/2018 13:47, Iremonger, Bernard wrote: > Hi Awal, > >> -----Original Message----- >> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Mohammad Abdul >> Awal >> Sent: Wednesday, May 9, 2018 5:57 PM >> To: dev@dpdk.org >> Cc: Awal, Mohammad Abdul >> 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 >> --- >> 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. >