From patchwork Mon Nov 19 15:31:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kar, Subarna" X-Patchwork-Id: 48192 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 9ADF72C52; Tue, 20 Nov 2018 00:56:56 +0100 (CET) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id C46DA2B92 for ; Tue, 20 Nov 2018 00:56:54 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Nov 2018 15:56:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,254,1539673200"; d="scan'208";a="92449162" Received: from subarna-x10drh-16.jf.intel.com ([134.134.170.148]) by orsmga006.jf.intel.com with ESMTP; 19 Nov 2018 15:56:52 -0800 From: subarna.kar@intel.com To: dev@dpdk.org Cc: qi.z.zhang@intel.com, jingjing.wu@intel.com, Subarna Kar Date: Mon, 19 Nov 2018 07:31:46 -0800 Message-Id: <1542641506-33956-1-git-send-email-subarna.kar@intel.com> X-Mailer: git-send-email 2.7.4 Subject: [dpdk-dev] [dpdk_org] net/i40e: Match on outer and inner headers for tunneled packets 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: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Subarna Kar This patch is to allow i40e to match on outer and inner headers for tunneled packets (MPLSoGRE, MPLSoUDP, VXLAN) and perform actions like RSS, MARK Signed-off-by: Subarna Kar --- drivers/net/i40e/i40e_ethdev.c | 12 +- drivers/net/i40e/i40e_ethdev.h | 109 +++++- drivers/net/i40e/i40e_fdir.c | 415 ++++++++++++++++++++-- drivers/net/i40e/i40e_flow.c | 772 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 1259 insertions(+), 49 deletions(-) diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 85a6a86..27da052 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -8919,7 +8919,9 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype, I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER | I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST | I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL | - I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT, + I40E_INSET_IPV4_PROTO | I40E_INSET_TUNNEL_ID | + I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT | + I40E_INSET_TUNNEL_IPV4_DST | I40E_INSET_TUNNEL_DST_PORT | I40E_INSET_TUNNEL_IPV6_DST , [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] = I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER | I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST | @@ -8959,8 +8961,10 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype, [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] = I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER | I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST | - I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT | - I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT, + I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_NEXT_HDR | + I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT| + I40E_INSET_TUNNEL_ID | I40E_INSET_TUNNEL_DST_PORT | + I40E_INSET_TUNNEL_IPV4_DST | I40E_INSET_TUNNEL_IPV6_DST, [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] = I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER | I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST | @@ -12209,7 +12213,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg, uint32_t buff_size; uint32_t i; int ret; - if (op != RTE_PMD_I40E_PKG_OP_WR_ADD && op != RTE_PMD_I40E_PKG_OP_WR_DEL) { PMD_DRV_LOG(ERR, "Unsupported operation."); @@ -12228,7 +12231,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg, PMD_DRV_LOG(INFO, "No new protocol added"); return; } - buff_size = proto_num * sizeof(struct rte_pmd_i40e_proto_info); proto = rte_zmalloc("new_proto", buff_size, 0); if (!proto) { diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 3fffe5a..982d6ce 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -466,6 +466,92 @@ struct i40e_vmdq_info { #define I40E_FLEX_WORD_MASK(off) (0x80 >> (off)) #define I40E_FDIR_IPv6_TC_OFFSET 20 +/* A structure used to define input for MPLSoUDP flow */ +struct i40e_mplsoudpv4_udpv4_flow { + struct rte_eth_udpv4_flow outer_udp; //outer IPv4 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_mplsoudpv4_udpv6_flow { + struct rte_eth_udpv4_flow outer_udp; //outer IPv4 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + +struct i40e_mplsoudpv6_udpv4_flow { + struct rte_eth_udpv6_flow outer6_udp; //outer IPv6 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_mplsoudpv6_udpv6_flow { + struct rte_eth_udpv6_flow outer6_udp; //outer IPv6 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + +/* A structure used to define input for VXLAN flow */ +struct i40e_vxlanv4_udpv4_flow { + struct rte_eth_udpv4_flow outer_udp; //outer IPv4 + struct rte_flow_item_vxlan vxlan; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_vxlanv4_udpv6_flow { + struct rte_eth_udpv4_flow outer_udp; //outer IPv4 + struct rte_flow_item_vxlan vxlan; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + +struct i40e_vxlanv6_udpv4_flow { + struct rte_eth_udpv6_flow outer6_udp; //outer IPv6 + struct rte_flow_item_vxlan vxlan; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_vxlanv6_udpv6_flow { + struct rte_eth_udpv6_flow outer6_udp; //outer IPv6 + struct rte_flow_item_vxlan vxlan; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + +/* A structure used to define input for MPLSoGRE flow */ + +struct i40e_gre_flow { + struct rte_eth_ipv4_flow ip; + struct rte_flow_item_gre gre; +}; + +struct i40e_mplsogrev4_udpv4_flow { + struct i40e_gre_flow outer_gre; //outer IPv4 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_mplsogrev4_udpv6_flow { + struct i40e_gre_flow outer_gre; //outer IPv4 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + +struct i40e_gre_ipv6_flow { + struct rte_eth_ipv6_flow ip; + struct rte_flow_item_gre gre; +}; + +struct i40e_mplsogrev6_udpv4_flow { + struct i40e_gre_ipv6_flow outer6_gre; //outer IPv6 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv4_flow inner_udp; //inner IPv4 +}; + +struct i40e_mplsogrev6_udpv6_flow { + struct i40e_gre_ipv6_flow outer6_gre; //outer IPv6 + struct rte_flow_item_mpls mpls; + struct rte_eth_udpv6_flow inner6_udp; //inner IPv6 +}; + /* A structure used to define the input for GTP flow */ struct i40e_gtp_flow { struct rte_eth_udpv4_flow udp; /* IPv4 UDP fields to match. */ @@ -510,6 +596,19 @@ union i40e_fdir_flow { struct i40e_gtp_ipv4_flow gtp_ipv4_flow; struct i40e_gtp_ipv6_flow gtp_ipv6_flow; struct i40e_raw_flow raw_flow; + //this is for tunneled pkts to match on outer and inner + struct i40e_mplsoudpv4_udpv4_flow mplsudp4_flow; + struct i40e_mplsoudpv4_udpv6_flow mplsudp6_flow; + struct i40e_mplsoudpv6_udpv4_flow mpls6udp4_flow; + struct i40e_mplsoudpv6_udpv6_flow mpls6udp6_flow; + struct i40e_mplsogrev4_udpv4_flow mplsgre4_flow; + struct i40e_mplsogrev4_udpv6_flow mplsgre6_flow; + struct i40e_mplsogrev6_udpv4_flow mpls6gre4_flow; + struct i40e_mplsogrev6_udpv6_flow mpls6gre6_flow; + struct i40e_vxlanv4_udpv4_flow vxlanudp4_flow; + struct i40e_vxlanv4_udpv6_flow vxlanudp6_flow; + struct i40e_vxlanv6_udpv4_flow vxlan6udp4_flow; + struct i40e_vxlanv6_udpv6_flow vxlan6udp6_flow; }; enum i40e_fdir_ip_type { @@ -517,6 +616,12 @@ enum i40e_fdir_ip_type { I40E_FDIR_IPTYPE_IPV6, }; +enum i40e_fdir_tunnel_type { + MPLSOUDP, + MPLSOGRE, + VXLAN, +}; + /* A structure used to contain extend input of flow */ struct i40e_fdir_flow_ext { uint16_t vlan_tci; @@ -528,6 +633,8 @@ struct i40e_fdir_flow_ext { enum i40e_fdir_ip_type iip_type; /* ip type for inner ip */ bool customized_pctype; /* If customized pctype is used */ bool pkt_template; /* If raw packet template is used */ + bool tunnel; /*if its tunnel pkts, then allow inner headers. */ + enum i40e_fdir_tunnel_type tunnel_val; }; /* A structure used to define the input for a flow director filter entry */ @@ -748,8 +855,8 @@ enum i40e_tunnel_type { I40E_TUNNEL_TYPE_NVGRE, I40E_TUNNEL_TYPE_IP_IN_GRE, I40E_L2_TUNNEL_TYPE_E_TAG, - I40E_TUNNEL_TYPE_MPLSoUDP, I40E_TUNNEL_TYPE_MPLSoGRE, + I40E_TUNNEL_TYPE_MPLSoUDP, I40E_TUNNEL_TYPE_QINQ, I40E_TUNNEL_TYPE_GTPC, I40E_TUNNEL_TYPE_GTPU, diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index d41601a..016c2fa 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -35,6 +35,7 @@ #define I40E_FDIR_PKT_LEN 512 #define I40E_FDIR_IP_DEFAULT_LEN 420 +#define I40E_FDIR_IP_DEFAULT_LEN_INNER 370 #define I40E_FDIR_IP_DEFAULT_TTL 0x40 #define I40E_FDIR_IP_DEFAULT_VERSION_IHL 0x45 #define I40E_FDIR_TCP_DEFAULT_DATAOFF 0x50 @@ -43,6 +44,7 @@ #define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS 0xFF #define I40E_FDIR_IPv6_PAYLOAD_LEN 380 #define I40E_FDIR_UDP_DEFAULT_LEN 400 +#define I40E_FDIR_UDP_DEFAULT_LEN_INNER 350 #define I40E_FDIR_GTP_DEFAULT_LEN 384 #define I40E_FDIR_INNER_IP_DEFAULT_LEN 384 #define I40E_FDIR_INNER_IPV6_DEFAULT_LEN 344 @@ -53,7 +55,7 @@ #define I40E_FDIR_GTP_VER_FLAG_0X32 0x32 #define I40E_FDIR_GTP_MSG_TYPE_0X01 0x01 #define I40E_FDIR_GTP_MSG_TYPE_0XFF 0xFF - +#define VXLAN_DEFAULT_FLAG 0x08 /* Wait time for fdir filter programming */ #define I40E_FDIR_MAX_WAIT_US 10000 @@ -951,15 +953,141 @@ i40e_flow_fdir_find_customized_pctype(struct i40e_pf *pf, uint8_t pctype) } static inline int +i40e_flow_fdir_fill_outer_header(const struct i40e_fdir_input *fdir_input, + unsigned char *raw_pkt) +{ + struct ipv4_hdr *ip; + struct ipv6_hdr *ip6; + struct udp_hdr *udp; + struct rte_flow_item_gre *gre; + struct rte_flow_item_mpls *mpls; + struct rte_flow_item_vxlan *vxlan; + uint16_t *ether_type; + uint8_t len = 2 * sizeof(struct ether_addr); + raw_pkt += 2 * sizeof(struct ether_addr); + ether_type = (uint16_t *)raw_pkt; + raw_pkt += sizeof(uint16_t); + len += sizeof(uint16_t); + + + //we don't need ETH, so direct skip to IP + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + ip = (struct ipv4_hdr *)raw_pkt; + *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + ip->version_ihl = + I40E_FDIR_IP_DEFAULT_VERSION_IHL; + /* set len to by default */ + ip->total_length = + rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); + ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + ip->type_of_service = fdir_input->flow.ip4_flow.tos; + ip->src_addr = fdir_input->flow.ip4_flow.src_ip; + ip->dst_addr = fdir_input->flow.ip4_flow.dst_ip; + if(fdir_input->flow_ext.tunnel_val == MPLSOGRE) + ip->next_proto_id = IPPROTO_GRE; + else + ip->next_proto_id = IPPROTO_UDP; + len += sizeof(struct ipv4_hdr); + raw_pkt += sizeof(struct ipv4_hdr); + } + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6) { + + ip6 = (struct ipv6_hdr *)raw_pkt; + *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->payload_len = + rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->hop_limits = + I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; + ip6->proto = fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.proto; + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.src_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.dst_ip, IPV6_ADDR_LEN); + len += sizeof(struct ipv6_hdr); + raw_pkt += sizeof(struct ipv6_hdr); + } + if (fdir_input->flow_ext.tunnel_val == MPLSOGRE) { + + gre = (struct rte_flow_item_gre *)raw_pkt; + gre->protocol = + fdir_input->flow.mplsgre4_flow.outer_gre.gre.protocol; + len += sizeof(struct rte_flow_item_gre); + raw_pkt += sizeof(struct rte_flow_item_gre); + } else { //now put UDP info for VXLAN and MPLSoUDP + + udp = (struct udp_hdr *)raw_pkt; + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4){ + udp->src_port = + fdir_input->flow.mplsudp4_flow.outer_udp.src_port; + udp->dst_port = + fdir_input->flow.mplsudp4_flow.outer_udp.dst_port; + } else { + + udp->src_port = fdir_input->flow.mpls6udp4_flow.outer6_udp.src_port; + udp->dst_port = fdir_input->flow.mpls6udp4_flow.outer6_udp.dst_port; + } + udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); + len += sizeof(struct udp_hdr); + raw_pkt += sizeof(struct udp_hdr); + } + if (fdir_input->flow_ext.tunnel_val == VXLAN) { + + vxlan = (struct rte_flow_item_vxlan *)raw_pkt; + if(fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + vxlan->vni[0] = + fdir_input->flow.vxlanudp4_flow.vxlan.vni[0]; + vxlan->vni[1] = + fdir_input->flow.vxlanudp4_flow.vxlan.vni[1]; + vxlan->vni[2] = + fdir_input->flow.vxlanudp4_flow.vxlan.vni[2]; + } else { + + vxlan->vni[0] = + fdir_input->flow.vxlan6udp4_flow.vxlan.vni[0]; + vxlan->vni[1] = + fdir_input->flow.vxlan6udp4_flow.vxlan.vni[1]; + vxlan->vni[2] = + fdir_input->flow.vxlan6udp4_flow.vxlan.vni[2]; + } + vxlan->flags = VXLAN_DEFAULT_FLAG; + len += sizeof(struct rte_flow_item_vxlan); + } else { + //now put MPLS info for MPLSoUDP and MPLSoGRE + mpls = (struct rte_flow_item_mpls *)raw_pkt; + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + mpls->label_tc_s[0] = + fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[0]; + mpls->label_tc_s[1] = + fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[1]; + mpls->label_tc_s[2] = + fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[2]; + } else { + + mpls->label_tc_s[0] = + fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[0]; + mpls->label_tc_s[1] = + fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[1]; + mpls->label_tc_s[2] = + fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[2]; + } + len += sizeof(struct rte_flow_item_mpls); + } + return len; +} + +static inline int i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, const struct i40e_fdir_input *fdir_input, unsigned char *raw_pkt, - bool vlan) + bool vlan, int outer_len) { struct i40e_customized_pctype *cus_pctype = NULL; static uint8_t vlan_frame[] = {0x81, 0, 0, 0}; uint16_t *ether_type; - uint8_t len = 2 * sizeof(struct ether_addr); + uint8_t len = 2 * sizeof(struct ether_addr) + outer_len; struct ipv4_hdr *ip; struct ipv6_hdr *ip6; uint8_t pctype = fdir_input->pctype; @@ -977,7 +1105,7 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] = IPPROTO_NONE, }; - raw_pkt += 2 * sizeof(struct ether_addr); + raw_pkt += 2 * sizeof(struct ether_addr) + outer_len; if (vlan && fdir_input->flow_ext.vlan_tci) { rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame)); rte_memcpy(raw_pkt + sizeof(uint16_t), @@ -1011,12 +1139,89 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL; - /* set len to by default */ - ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); - ip->time_to_live = fdir_input->flow.ip4_flow.ttl ? - fdir_input->flow.ip4_flow.ttl : - I40E_FDIR_IP_DEFAULT_TTL; - ip->type_of_service = fdir_input->flow.ip4_flow.tos; + + if(outer_len) { //we have a tunneled pkt + + if (fdir_input->flow_ext.tunnel_val != VXLAN) { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4){ + + ip->time_to_live = + fdir_input->flow.mplsudp4_flow.inner_udp.ip.ttl ? + fdir_input->flow.mplsudp4_flow.inner_udp.ip.ttl : + I40E_FDIR_IP_DEFAULT_TTL; + ip->total_length = + rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER); + ip->type_of_service = + fdir_input->flow.mplsudp4_flow.inner_udp.ip.tos; + ip->src_addr = + fdir_input->flow.mplsudp4_flow.inner_udp.ip.dst_ip; + ip->dst_addr = + fdir_input->flow.mplsudp4_flow.inner_udp.ip.src_ip; + ip->next_proto_id = + fdir_input->flow.mplsudp4_flow.inner_udp.ip.proto; + } else { + + ip->time_to_live = + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.ttl ? + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.ttl : + I40E_FDIR_IP_DEFAULT_TTL; + ip->total_length = + rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER); + ip->type_of_service = + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.tos; + ip->src_addr = + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.dst_ip; + ip->dst_addr = + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.src_ip; + ip->next_proto_id = + fdir_input->flow.mpls6udp4_flow.inner_udp.ip.proto; + } + + } else { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + ip->time_to_live = + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.ttl ? + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.ttl : + I40E_FDIR_IP_DEFAULT_TTL; + ip->total_length = + rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER); + ip->type_of_service = + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.tos; + ip->src_addr = + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.dst_ip; + ip->dst_addr = + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.src_ip; + ip->next_proto_id = + fdir_input->flow.vxlanudp4_flow.inner_udp.ip.proto; + } else { + + ip->time_to_live = + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.ttl ? + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.ttl : + I40E_FDIR_IP_DEFAULT_TTL; + ip->total_length = + rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER); + ip->type_of_service = + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.tos; + ip->src_addr = + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.dst_ip; + ip->dst_addr = + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.src_ip; + ip->next_proto_id = + fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.proto; + } + } + len += sizeof(struct ipv4_hdr); + } else { + + /* set len to by default */ + ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); + ip->time_to_live = fdir_input->flow.ip4_flow.ttl ? + fdir_input->flow.ip4_flow.ttl :I40E_FDIR_IP_DEFAULT_TTL; + ip->type_of_service = fdir_input->flow.ip4_flow.tos; /** * The source and destination fields in the transmitted packet * need to be presented in a reversed order with respect @@ -1033,8 +1238,10 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV4 || cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV6 || cus_pctype->index == I40E_CUSTOMIZED_GTPU) + ip->next_proto_id = IPPROTO_UDP; - len += sizeof(struct ipv4_hdr); + len += sizeof(struct ipv4_hdr); + } } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_TCP || pctype == I40E_FILTER_PCTYPE_NONF_IPV6_UDP || pctype == I40E_FILTER_PCTYPE_NONF_IPV6_SCTP || @@ -1043,30 +1250,76 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, ip6 = (struct ipv6_hdr *)raw_pkt; *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); - ip6->vtc_flow = - rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW | + + if (outer_len) { + + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; + if (fdir_input->flow_ext.tunnel_val != VXLAN) { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + ip6->proto = + fdir_input->flow.mplsudp6_flow.inner6_udp.ip.proto; + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.mplsudp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.mplsudp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN); + } else { + + ip6->proto = + fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.proto; + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN); + } + } else { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4){ + ip6->proto = + fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.proto; + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN); + } else { + + ip6->proto = + fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.proto; + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN); + } + } + len += sizeof(struct ipv6_hdr); + } + else { + ip6->vtc_flow = + rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW | (fdir_input->flow.ipv6_flow.tc << I40E_FDIR_IPv6_TC_OFFSET)); - ip6->payload_len = - rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); - ip6->proto = fdir_input->flow.ipv6_flow.proto ? - fdir_input->flow.ipv6_flow.proto : - next_proto[fdir_input->pctype]; - ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ? - fdir_input->flow.ipv6_flow.hop_limits : - I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; + ip6->payload_len = + rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->proto = fdir_input->flow.ipv6_flow.proto ? + fdir_input->flow.ipv6_flow.proto : + next_proto[fdir_input->pctype]; + ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ? + fdir_input->flow.ipv6_flow.hop_limits : + I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; /** * The source and destination fields in the transmitted packet * need to be presented in a reversed order with respect * to the expected received packets. */ - rte_memcpy(&ip6->src_addr, - &fdir_input->flow.ipv6_flow.dst_ip, - IPV6_ADDR_LEN); - rte_memcpy(&ip6->dst_addr, - &fdir_input->flow.ipv6_flow.src_ip, - IPV6_ADDR_LEN); - len += sizeof(struct ipv6_hdr); + rte_memcpy(&ip6->src_addr, + &fdir_input->flow.ipv6_flow.dst_ip, IPV6_ADDR_LEN); + rte_memcpy(&ip6->dst_addr, + &fdir_input->flow.ipv6_flow.src_ip, IPV6_ADDR_LEN); + len += sizeof(struct ipv6_hdr); + } } else { PMD_DRV_LOG(ERR, "unknown pctype %u.", fdir_input->pctype); @@ -1097,7 +1350,7 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, struct ipv6_hdr *gtp_ipv6; uint8_t size, dst = 0; uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/ - int len; + int len, outer_len = 0; uint8_t pctype = fdir_input->pctype; struct i40e_customized_pctype *cus_pctype; @@ -1108,9 +1361,17 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, return 0; } + //add outer header info to raw pkt, if tunnel flow + //subarna + if (fdir_input->flow_ext.tunnel) { + + outer_len = i40e_flow_fdir_fill_outer_header(fdir_input, raw_pkt); + } + /* fill the ethernet and IP head */ len = i40e_flow_fdir_fill_eth_ip_head(pf, fdir_input, raw_pkt, - !!fdir_input->flow_ext.vlan_tci); + !!fdir_input->flow_ext.vlan_tci, + outer_len); if (len < 0) return -EINVAL; @@ -1123,9 +1384,49 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, * need to be presented in a reversed order with respect * to the expected received packets. */ - udp->src_port = fdir_input->flow.udp4_flow.dst_port; - udp->dst_port = fdir_input->flow.udp4_flow.src_port; - udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); + if (fdir_input->flow_ext.tunnel_val != VXLAN) { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + udp->src_port = + fdir_input->flow.mplsudp4_flow.inner_udp.dst_port; + udp->dst_port = + fdir_input->flow.mplsudp4_flow.inner_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } else { + + udp->src_port = + fdir_input->flow.mpls6udp4_flow.inner_udp.dst_port; + udp->dst_port = + fdir_input->flow.mpls6udp4_flow.inner_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } + } + else if (fdir_input->flow_ext.tunnel_val == VXLAN) { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + udp->src_port = + fdir_input->flow.vxlanudp4_flow.inner_udp.dst_port; + udp->dst_port = + fdir_input->flow.vxlanudp4_flow.inner_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } else { + udp->src_port = + fdir_input->flow.vxlan6udp4_flow.inner_udp.dst_port; + udp->dst_port = + fdir_input->flow.vxlan6udp4_flow.inner_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } + } else{ + udp->src_port = fdir_input->flow.udp4_flow.dst_port; + udp->dst_port = fdir_input->flow.udp4_flow.src_port; + udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); + } } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV4_TCP) { tcp = (struct tcp_hdr *)(raw_pkt + len); payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); @@ -1160,9 +1461,48 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, * need to be presented in a reversed order with respect * to the expected received packets. */ - udp->src_port = fdir_input->flow.udp6_flow.dst_port; - udp->dst_port = fdir_input->flow.udp6_flow.src_port; - udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + if (fdir_input->flow_ext.tunnel_val != VXLAN){ + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + udp->src_port = + fdir_input->flow.mplsudp6_flow.inner6_udp.dst_port; + udp->dst_port = + fdir_input->flow.mplsudp6_flow.inner6_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + }else { + + udp->src_port = + fdir_input->flow.mpls6udp6_flow.inner6_udp.dst_port; + udp->dst_port = + fdir_input->flow.mpls6udp6_flow.inner6_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } + }else if (fdir_input->flow_ext.tunnel_val == VXLAN) { + + if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + udp->src_port = + fdir_input->flow.vxlanudp6_flow.inner6_udp.dst_port; + udp->dst_port = + fdir_input->flow.vxlanudp6_flow.inner6_udp.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + }else{ + udp->src_port = + fdir_input->flow.vxlan6udp6_flow.inner6_udp.dst_port; + udp->dst_port = + fdir_input->flow.vxlan6udp6_flow.inner6_udp.src_port; + udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER); + } + }else { + udp->src_port = fdir_input->flow.udp6_flow.dst_port; + udp->dst_port = fdir_input->flow.udp6_flow.src_port; + udp->dgram_len = + rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + } } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_TCP) { tcp = (struct tcp_hdr *)(raw_pkt + len); payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); @@ -1265,6 +1605,7 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, payload = (unsigned char *)gtp + sizeof(struct rte_flow_item_gtp); } + } else { PMD_DRV_LOG(ERR, "unknown pctype %u.", fdir_input->pctype); @@ -1564,7 +1905,7 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, pctype = filter->input.pctype; } - /* Check if there is the filter in SW list */ + /* Check if there is the filter in SW list */ memset(&check_filter, 0, sizeof(check_filter)); i40e_fdir_filter_convert(filter, &check_filter); node = i40e_sw_fdir_filter_lookup(fdir_info, &check_filter.fdir.input); diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index c67b264..6fd96b4 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -80,6 +80,12 @@ static int i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev, const struct rte_flow_action actions[], struct rte_flow_error *error, union i40e_filter_t *filter); +static int i40e_flow_parse_fdir_tunnel_filter(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], + struct rte_flow_error *error, + union i40e_filter_t *filter); static int i40e_flow_parse_vxlan_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_item pattern[], @@ -136,6 +142,8 @@ const struct rte_flow_ops i40e_flow_ops = { union i40e_filter_t cons_filter; enum rte_filter_type cons_filter_type = RTE_ETH_FILTER_NONE; +#define TUNNEL_FDIR_FUNCTION i40e_flow_parse_fdir_tunnel_filter + /* Pattern matched ethertype filter */ static enum rte_flow_item_type pattern_ethertype[] = { RTE_FLOW_ITEM_TYPE_ETH, @@ -1543,6 +1551,50 @@ static enum rte_flow_item_type pattern_vxlan_4[] = { RTE_FLOW_ITEM_TYPE_END, }; +static enum rte_flow_item_type pattern_vxlan_5[] = { //IPv4+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_vxlan_6[] = { //IPv4+IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_vxlan_7[] = { //IPv6+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_vxlan_8[] = { //IPv6+IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + static enum rte_flow_item_type pattern_nvgre_1[] = { RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4, @@ -1609,6 +1661,96 @@ static enum rte_flow_item_type pattern_mpls_4[] = { RTE_FLOW_ITEM_TYPE_END, }; +//adding only for IPv4. adding MPLS flow match for inner packet + +static enum rte_flow_item_type pattern_mpls_5[] = { //IPv4+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_6[] = { //IPv4 +IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_7[] = { //IPv6+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_8[] = { //IPv6+IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_9[] = { //IPv4+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_GRE, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_10[] = { //IPv4+IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_GRE, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_11[] = { //IPv6+IPv4 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_GRE, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_mpls_12[] = { //IPv6+IPv6 + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_GRE, + RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_END, +}; + static enum rte_flow_item_type pattern_qinq_1[] = { RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_VLAN, @@ -1779,6 +1921,11 @@ static struct i40e_valid_pattern i40e_supported_patterns[] = { { pattern_vxlan_2, i40e_flow_parse_vxlan_filter }, { pattern_vxlan_3, i40e_flow_parse_vxlan_filter }, { pattern_vxlan_4, i40e_flow_parse_vxlan_filter }, + /*VXLAN with inner header */ + { pattern_vxlan_5, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_vxlan_6, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_vxlan_7, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_vxlan_8, i40e_flow_parse_fdir_tunnel_filter }, /* NVGRE */ { pattern_nvgre_1, i40e_flow_parse_nvgre_filter }, { pattern_nvgre_2, i40e_flow_parse_nvgre_filter }, @@ -1789,6 +1936,15 @@ static struct i40e_valid_pattern i40e_supported_patterns[] = { { pattern_mpls_2, i40e_flow_parse_mpls_filter }, { pattern_mpls_3, i40e_flow_parse_mpls_filter }, { pattern_mpls_4, i40e_flow_parse_mpls_filter }, + /* MPLS patterns with inner header */ + { pattern_mpls_5, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_6, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_7, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_8, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_9, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_10, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_11, i40e_flow_parse_fdir_tunnel_filter }, + { pattern_mpls_12, i40e_flow_parse_fdir_tunnel_filter }, /* GTP-C & GTP-U */ { pattern_fdir_ipv4_gtpc, i40e_flow_parse_gtp_filter }, { pattern_fdir_ipv4_gtpu, i40e_flow_parse_gtp_filter }, @@ -2408,6 +2564,549 @@ i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf, return I40E_FILTER_PCTYPE_INVALID; } + +static int +i40e_flow_parse_fdir_tunnel_pattern(struct rte_eth_dev *dev, + const struct rte_flow_item *pattern, + struct rte_flow_error *error, + struct i40e_fdir_filter_conf *filter) +{ + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + const struct rte_flow_item *item = pattern; + const struct rte_flow_item_eth *eth_spec, *eth_mask; + const struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_mask; + const struct rte_flow_item_mpls *mpls_spec, *mpls_mask; + const struct rte_flow_item_vxlan *vxlan_spec, *vxlan_mask; + const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask; + const struct rte_flow_item_udp *udp_spec, *udp_mask; + const struct rte_flow_item_gre *gre_spec, *gre_mask; + uint8_t pctype = 0; + uint64_t input_set = I40E_INSET_NONE; + enum rte_flow_item_type item_type; + enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END; + uint16_t frag_off; + bool outer_ip = true; + bool outer_udp = true; + int ret; + uint8_t ipv6_addr_mask[16] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + uint8_t label_mask[3] = {0xFF, 0xFF, 0xF0}; + uint8_t vni_mask[] = {0xFF, 0xFF, 0xFF}; + + filter->input.flow_ext.customized_pctype = false; + for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (item->last) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support range"); + return -rte_errno; + } + item_type = item->type; + switch (item_type) { + case RTE_FLOW_ITEM_TYPE_ETH: + eth_spec = item->spec; + eth_mask = item->mask; + + if (eth_spec && eth_mask) { + if (!is_zero_ether_addr(ð_mask->src) || + !is_zero_ether_addr(ð_mask->dst)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid MAC_addr mask."); + return -rte_errno; + } + } + pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD; + break; + + case RTE_FLOW_ITEM_TYPE_IPV4: + l3 = RTE_FLOW_ITEM_TYPE_IPV4; + ipv4_spec = item->spec; + ipv4_mask = item->mask; + + if (ipv4_spec && ipv4_mask && outer_ip) { + /* Check IPv4 mask and update input set */ + //for outer, we can take only dst IP + + if (ipv4_mask->hdr.version_ihl || + ipv4_mask->hdr.total_length || + ipv4_mask->hdr.packet_id || + ipv4_mask->hdr.fragment_offset || + ipv4_mask -> hdr.src_addr || + ipv4_mask -> hdr.type_of_service || + ipv4_mask->hdr.time_to_live || ipv4_mask->hdr.next_proto_id || + ipv4_mask->hdr.hdr_checksum) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid IPv4 mask."); + return -rte_errno; + } + + if (ipv4_mask->hdr.dst_addr == UINT32_MAX) + input_set |= I40E_INSET_TUNNEL_IPV4_DST; + + filter->input.flow.mplsudp4_flow.outer_udp.ip.dst_ip = + ipv4_spec->hdr.dst_addr; + filter->input.flow_ext.iip_type = I40E_FDIR_IPTYPE_IPV4; + } else if (!ipv4_spec && !ipv4_mask && !outer_ip) { //no spec and mask for Inner IP + + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid inner IPv4 mask."); + return -rte_errno; + + } else if ((ipv4_spec || ipv4_mask) && !outer_ip) { //spec and mask for inner IP, set pctype and input_set + + pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; + + if (ipv4_mask->hdr.version_ihl || + ipv4_mask->hdr.total_length || + ipv4_mask->hdr.packet_id || + ipv4_mask->hdr.fragment_offset || + ipv4_mask -> hdr.type_of_service || + ipv4_mask->hdr.time_to_live || + ipv4_mask->hdr.hdr_checksum) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid IPv4 mask."); + return -rte_errno; + } + + if(ipv4_mask->hdr.src_addr == UINT32_MAX) + input_set |= I40E_INSET_IPV4_SRC; + if(ipv4_mask->hdr.dst_addr == UINT32_MAX) + input_set |= I40E_INSET_IPV4_DST; + if (ipv4_mask->hdr.next_proto_id == UINT8_MAX) + input_set |= I40E_INSET_IPV4_PROTO; + + /* Check if it is fragment. */ + frag_off = ipv4_spec->hdr.fragment_offset; + frag_off = rte_be_to_cpu_16(frag_off); + if (frag_off & IPV4_HDR_OFFSET_MASK || + frag_off & IPV4_HDR_MF_FLAG) + pctype = I40E_FILTER_PCTYPE_FRAG_IPV4; + + if(filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4 && + filter->input.flow_ext.tunnel_val != VXLAN) { + //MPLS with outerIPv4 + filter->input.flow.mplsudp4_flow.inner_udp.ip.dst_ip = + ipv4_spec->hdr.dst_addr; + filter->input.flow.mplsudp4_flow.inner_udp.ip.src_ip = + ipv4_spec->hdr.src_addr; + filter->input.flow.mplsudp4_flow.inner_udp.ip.proto = + ipv4_spec->hdr.next_proto_id; + } else if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6 && + filter->input.flow_ext.tunnel_val != VXLAN) { + // MPLS with outer IPv6 + filter->input.flow.mpls6udp4_flow.inner_udp.ip.dst_ip = + ipv4_spec->hdr.dst_addr; + filter->input.flow.mpls6udp4_flow.inner_udp.ip.src_ip = + ipv4_spec->hdr.src_addr; + filter->input.flow.mpls6udp4_flow.inner_udp.ip.proto = + ipv4_spec->hdr.next_proto_id; + } else if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4 && + filter->input.flow_ext.tunnel_val == VXLAN) { + //VXLAN with outer IPv4 + filter->input.flow.vxlanudp4_flow.inner_udp.ip.dst_ip = + ipv4_spec->hdr.dst_addr; + filter->input.flow.vxlanudp4_flow.inner_udp.ip.src_ip = + ipv4_spec->hdr.src_addr; + filter->input.flow.vxlanudp4_flow.inner_udp.ip.proto = + ipv4_spec->hdr.next_proto_id; + } else { + // VXLAN with outer IPv6 + filter->input.flow.vxlan6udp4_flow.inner_udp.ip.dst_ip = + ipv4_spec->hdr.dst_addr; + filter->input.flow.vxlan6udp4_flow.inner_udp.ip.src_ip = + ipv4_spec->hdr.src_addr; + filter->input.flow.vxlan6udp4_flow.inner_udp.ip.proto = + ipv4_spec->hdr.next_proto_id; + } + } + + if (outer_ip) + outer_ip = false; + break; + + case RTE_FLOW_ITEM_TYPE_IPV6: + l3 = RTE_FLOW_ITEM_TYPE_IPV6; + ipv6_spec = item->spec; + ipv6_mask = item->mask; + + if (ipv6_spec && ipv6_mask && outer_ip) { + /* Check IPv6 mask and update input set, we take only dst IP */ + if (ipv6_mask->hdr.payload_len) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid IPv6 mask"); + return -rte_errno; + } + + if (!memcmp(ipv6_mask->hdr.dst_addr, + ipv6_addr_mask, + RTE_DIM(ipv6_mask->hdr.dst_addr))) + input_set |= I40E_INSET_TUNNEL_IPV6_DST; + + /* Get filter info */ + + filter->input.flow.mpls6udp4_flow.outer6_udp.ip.proto = + ipv6_spec->hdr.proto; + rte_memcpy(filter->input.flow.mpls6udp4_flow.outer6_udp.ip.dst_ip, + ipv6_spec->hdr.dst_addr, 16); + filter->input.flow_ext.iip_type = + I40E_FDIR_IPTYPE_IPV6; + + } else if (!ipv6_spec && !ipv6_mask && !outer_ip) { //no spec,mask for inner IPv6 + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid inner IPv6 mask."); + return -rte_errno; + } else if ((ipv6_spec || ipv6_mask) && !outer_ip) { //spec,mask mentioned for inner IPv6 + pctype = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER; + if (ipv6_mask->hdr.payload_len) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid IPv6 mask"); + return -rte_errno; + } + + if (!memcmp(ipv6_mask->hdr.src_addr, + ipv6_addr_mask, + RTE_DIM(ipv6_mask->hdr.src_addr))) + input_set |= I40E_INSET_IPV6_SRC; + if (!memcmp(ipv6_mask->hdr.dst_addr, + ipv6_addr_mask, + RTE_DIM(ipv6_mask->hdr.dst_addr))) + input_set |= I40E_INSET_IPV6_DST; + + if ((ipv6_mask->hdr.vtc_flow & + rte_cpu_to_be_32(I40E_IPV6_TC_MASK)) + == rte_cpu_to_be_32(I40E_IPV6_TC_MASK)) + input_set |= I40E_INSET_IPV6_TC; + if (ipv6_mask->hdr.proto == UINT8_MAX) + input_set |= I40E_INSET_IPV6_NEXT_HDR; + if (ipv6_mask->hdr.hop_limits == UINT8_MAX) + input_set |= I40E_INSET_IPV6_HOP_LIMIT; + + /* Get filter info */ + if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4 && + filter->input.flow_ext.tunnel_val != VXLAN) { + + filter->input.flow.mplsudp6_flow.inner6_udp.ip.proto = + ipv6_spec->hdr.proto; + rte_memcpy(filter->input.flow.mplsudp6_flow.inner6_udp.ip.src_ip, + ipv6_spec->hdr.src_addr, 16); + rte_memcpy(filter->input.flow.mplsudp6_flow.inner6_udp.ip.dst_ip, + ipv6_spec->hdr.dst_addr, 16); + + } else if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6 && + filter->input.flow_ext.tunnel_val != VXLAN) { + + filter->input.flow.mpls6udp6_flow.inner6_udp.ip.proto = + ipv6_spec->hdr.proto; + rte_memcpy(filter->input.flow.mpls6udp6_flow.inner6_udp.ip.src_ip, + ipv6_spec->hdr.src_addr, 16); + rte_memcpy(filter->input.flow.mpls6udp6_flow.inner6_udp.ip.dst_ip, + ipv6_spec->hdr.dst_addr, 16); + + } else if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4 && + filter->input.flow_ext.tunnel_val == VXLAN) { + + filter->input.flow.vxlanudp6_flow.inner6_udp.ip.proto = + ipv6_spec->hdr.proto; + rte_memcpy(filter->input.flow.vxlanudp6_flow.inner6_udp.ip.src_ip, + ipv6_spec->hdr.src_addr, 16); + rte_memcpy(filter->input.flow.vxlanudp6_flow.inner6_udp.ip.dst_ip, + ipv6_spec->hdr.dst_addr, 16); + + } else { + + filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.proto = + ipv6_spec->hdr.proto; + rte_memcpy(filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.src_ip, + ipv6_spec->hdr.src_addr, 16); + rte_memcpy(filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.dst_ip, + ipv6_spec->hdr.dst_addr, 16); + + } + + /* Check if it is fragment. */ + if (ipv6_spec->hdr.proto == I40E_IPV6_FRAG_HEADER) + pctype = I40E_FILTER_PCTYPE_FRAG_IPV6; + } + + if (outer_ip) + outer_ip = false; + break; + + case RTE_FLOW_ITEM_TYPE_GRE: + gre_spec = item->spec; + gre_mask = item->mask; + if (gre_spec && gre_mask) { + + if (gre_mask->c_rsvd0_ver) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid GRE mask"); + return -rte_errno; + } + + if (gre_mask->protocol == UINT16_MAX) + input_set |= I40E_INSET_TUNNEL_DST_PORT; //the location for gre protocol is same as outer DST port in field vector + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { //outer IPv4 + filter->input.flow.mplsgre4_flow.outer_gre.gre.protocol = gre_spec->protocol; + } else { + filter->input.flow.mpls6gre4_flow.outer6_gre.gre.protocol = gre_spec->protocol; + } + } else { + + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid GRE mask"); + return -rte_errno; + } + outer_udp = false; + filter->input.flow_ext.tunnel_val = MPLSOGRE; + break; + + case RTE_FLOW_ITEM_TYPE_UDP: + udp_spec = item->spec; + udp_mask = item->mask; + + if (udp_spec && udp_mask && outer_udp) { + /* Check UDP mask and update input set */ + //for outer, we can take only dst port + + if (udp_mask->hdr.dgram_len || udp_mask->hdr.src_port || + udp_mask->hdr.dgram_cksum) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid UDP mask"); + return -rte_errno; + } + if (udp_mask->hdr.dst_port == UINT16_MAX) + input_set |= I40E_INSET_TUNNEL_DST_PORT; + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { //outer UDP for outer IPv4 + filter->input.flow.mplsudp4_flow.outer_udp.dst_port = + udp_spec->hdr.dst_port; + } else + filter->input.flow.mpls6udp4_flow.outer6_udp.dst_port = + udp_spec->hdr.dst_port; + + } else if (!udp_spec && !udp_mask && !outer_udp) { //no spec and mask for Inner UDP + + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid inner IPv4 mask."); + return -rte_errno; + + } else if ((udp_spec || udp_mask) && !outer_udp) { + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + pctype =I40E_FILTER_PCTYPE_NONF_IPV4_UDP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP; + /* Check UDP mask and update input set */ + //for inner, we can take dst port and src port + + if (udp_mask->hdr.dgram_len || + udp_mask->hdr.dgram_cksum) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid UDP mask"); + return -rte_errno; + } + if (udp_mask->hdr.src_port == UINT16_MAX) + input_set |= I40E_INSET_SRC_PORT; + if (udp_mask->hdr.dst_port == UINT16_MAX) + input_set |= I40E_INSET_DST_PORT; + if(filter->input.flow_ext.tunnel_val != VXLAN){ + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { //both ipv4 + + filter->input.flow.mplsudp4_flow.inner_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.mplsudp4_flow.inner_udp.src_port = + udp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6) { //inner ipv4 and outer ipv6 + + filter->input.flow.mpls6udp4_flow.inner_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.mpls6udp4_flow.inner_udp.src_port = + udp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { //outer ipv4 and inner ipv6 + + filter->input.flow.mplsudp6_flow.inner6_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.mplsudp6_flow.inner6_udp.src_port = + udp_spec->hdr.src_port; + } else { //both IPv6 + filter->input.flow.mpls6udp6_flow.inner6_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.mpls6udp6_flow.inner6_udp.src_port = + udp_spec->hdr.src_port; + } + } else { + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { //both ipv4 + filter->input.flow.vxlanudp4_flow.inner_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.vxlanudp4_flow.inner_udp.src_port = + udp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6) { //inner ipv4 and outer ipv6 + + filter->input.flow.vxlan6udp4_flow.inner_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.vxlan6udp4_flow.inner_udp.src_port = + udp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6 && + filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { //outer ipv4 and inner ipv6 + + filter->input.flow.vxlanudp6_flow.inner6_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.vxlanudp6_flow.inner6_udp.src_port = + udp_spec->hdr.src_port; + } else { //both IPv6 + filter->input.flow.vxlan6udp6_flow.inner6_udp.dst_port = + udp_spec->hdr.dst_port; + filter->input.flow.vxlan6udp6_flow.inner6_udp.src_port = + udp_spec->hdr.src_port; + } + } + } + if (outer_udp) + outer_udp = false; + break; + case RTE_FLOW_ITEM_TYPE_MPLS: + mpls_spec = item->spec; + mpls_mask = item->mask; + if (mpls_spec && mpls_mask) + { + if (memcmp(mpls_mask->label_tc_s, label_mask, 3)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid MPLS label mask"); + return -rte_errno; + } else { + input_set |= I40E_INSET_TUNNEL_ID; + } + if (filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) { + + filter->input.flow.mplsudp4_flow.mpls.label_tc_s[0] = + mpls_spec->label_tc_s[0]; + filter->input.flow.mplsudp4_flow.mpls.label_tc_s[1] = + mpls_spec->label_tc_s[1]; + filter->input.flow.mplsudp4_flow.mpls.label_tc_s[2] = + mpls_spec->label_tc_s[2]; + + } else { + + filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[0] = + mpls_spec->label_tc_s[0]; + filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[1] = + mpls_spec->label_tc_s[1]; + filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[2] = + mpls_spec->label_tc_s[2]; + } + } + + filter->input.flow_ext.tunnel = true; + if(filter->input.flow_ext.tunnel_val != MPLSOGRE) //it has not been set by GRE header before, then it must be MPLSoUDP + filter->input.flow_ext.tunnel_val = MPLSOUDP; + break; + case RTE_FLOW_ITEM_TYPE_VXLAN: + vxlan_spec = item->spec; + vxlan_mask = item->mask; + /* Check if VXLAN item is used to describe protocol. + * If yes, both spec and mask should be NULL. + * If no, both spec and mask shouldn't be NULL. + */ + if ((!vxlan_spec && !vxlan_mask)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid VXLAN item"); + return -rte_errno; + } + + /* Check if VNI is masked. */ + if (vxlan_spec && vxlan_mask) { + if (memcmp(vxlan_mask->vni, vni_mask, 3)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid VXLAN mask"); + return -rte_errno; + } + else { + input_set |= I40E_INSET_TUNNEL_ID; + } + + if(filter->input.flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4){ + filter->input.flow.vxlanudp4_flow.vxlan.vni[0] = + vxlan_spec->vni[0]; + filter->input.flow.vxlanudp4_flow.vxlan.vni[1] = + vxlan_spec->vni[1]; + filter->input.flow.vxlanudp4_flow.vxlan.vni[2] = + vxlan_spec->vni[2]; + } else { + filter->input.flow.vxlan6udp4_flow.vxlan.vni[0] = + vxlan_spec->vni[0]; + filter->input.flow.vxlan6udp4_flow.vxlan.vni[1] = + vxlan_spec->vni[1]; + filter->input.flow.vxlan6udp4_flow.vxlan.vni[2] = + vxlan_spec->vni[2]; + } + } + filter->input.flow_ext.tunnel = true; + filter->input.flow_ext.tunnel_val = VXLAN; + break; + default: + break; + } + } + + /* If customized pctype is not used, set fdir configuration.*/ + if (!filter->input.flow_ext.customized_pctype) { + ret = i40e_flow_set_fdir_inset(pf, pctype, input_set); + if (ret == -1) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "Conflict with the first rule's input set."); + return -rte_errno; + } else if (ret == -EINVAL) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "Invalid pattern mask."); + return -rte_errno; + } + } + filter->input.pctype = pctype; //PCTYPE gets set as per inner packet type + return 0; +} + /* 1. Last in item should be NULL as range is not supported. * 2. Supported patterns: refer to array i40e_supported_patterns. * 3. Default supported flow type and input set: refer to array @@ -3011,7 +3710,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, "Invalid pattern mask."); return -rte_errno; } - + filter->input.flow_ext.tunnel=false; /* Store flex mask to SW */ ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask); if (ret == -1) { @@ -3079,6 +3778,9 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_PASSTHRU: filter->action.behavior = I40E_FDIR_PASSTHRU; break; + case RTE_FLOW_ACTION_TYPE_RSS: + filter->action.behavior = I40E_FDIR_PASSTHRU; + break; default: rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, @@ -3120,6 +3822,59 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, } static int +i40e_flow_parse_fdir_tunnel_filter(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], + struct rte_flow_error *error, + union i40e_filter_t *filter) +{ + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + struct i40e_fdir_filter_conf *fdir_filter = + &filter->fdir_filter; + int ret; + + ret = i40e_flow_parse_fdir_tunnel_pattern(dev,pattern, error, + fdir_filter); + if (ret) + return ret; + + ret = i40e_flow_parse_fdir_action(dev, actions, error, fdir_filter); + if (ret) + return ret; + + ret = i40e_flow_parse_attr(attr, error); + if (ret) + return ret; + + cons_filter_type = RTE_ETH_FILTER_FDIR; + + if (dev->data->dev_conf.fdir_conf.mode != + RTE_FDIR_MODE_PERFECT) { + ret = i40e_fdir_setup(pf); + if(ret != I40E_SUCCESS) { + + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Failed to setup fdir"); + return -rte_errno; + } + ret = i40e_fdir_configure(dev); + if(ret < 0) { + + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Failed to configure fdir"); + goto err; + } + dev->data->dev_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + } + return 0; + +err: + i40e_fdir_teardown(pf); + return -rte_errno; +} + +static int i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_item pattern[], @@ -4542,6 +5297,7 @@ i40e_flow_validate(struct rte_eth_dev *dev, uint32_t item_num = 0; /* non-void item number of pattern*/ uint32_t i = 0; bool flag = false; + bool rss = false; int ret = I40E_NOT_SUPPORTED; if (!pattern) { @@ -4570,9 +5326,8 @@ i40e_flow_validate(struct rte_eth_dev *dev, while ((actions + i)->type == RTE_FLOW_ACTION_TYPE_VOID) i++; - if ((actions + i)->type == RTE_FLOW_ACTION_TYPE_RSS) { - ret = i40e_parse_rss_filter(dev, attr, pattern, - actions, &cons_filter, error); + if ((actions + i)->type == RTE_FLOW_ACTION_TYPE_RSS) { + rss = true; return ret; } @@ -4605,9 +5360,14 @@ i40e_flow_validate(struct rte_eth_dev *dev, rte_free(items); return -rte_errno; } - if (parse_filter) + if (parse_filter){ + if(parse_filter != TUNNEL_FDIR_FUNCTION && rss == true){ + ret = i40e_parse_rss_filter(dev, attr, pattern, + actions, &cons_filter, error); + return ret; + } else ret = parse_filter(dev, attr, items, actions, - error, &cons_filter); + error, &cons_filter); } flag = true; } while ((ret < 0) && (i < RTE_DIM(i40e_supported_patterns)));