From: Rory Sexton Date: Mon, 13 Jan 2020 11:50:41 +0000 (+0000) Subject: net/i40e: support flow director for L2TPv3 over IP X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=c5f8365bc85d;p=dpdk.git net/i40e: support flow director for L2TPv3 over IP Adding FDIR support for L2TPv3 over IP header matching and adding a new customized pctype for l2tpv3 over IP. Signed-off-by: Rory Sexton Signed-off-by: Dariusz Jagus Acked-by: Beilei Xing --- diff --git a/doc/guides/rel_notes/release_20_02.rst b/doc/guides/rel_notes/release_20_02.rst index 3d483c62cd..9931716f43 100644 --- a/doc/guides/rel_notes/release_20_02.rst +++ b/doc/guides/rel_notes/release_20_02.rst @@ -71,6 +71,11 @@ New Features * Added support for Rx interrupt. +* **Updated i40e driver to support L2TPv3 over IP flows.** + + Updated the i40e PMD to support L2TPv3 over IP profiles which can be + programmed by the dynamic device personalization (DDP) process. + * **Updated Mellanox mlx5 driver.** Updated Mellanox mlx5 driver with new features and improvements, including: diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 3c60856b32..fb01d6187d 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -12350,6 +12350,14 @@ i40e_update_customized_pctype(struct rte_eth_dev *dev, uint8_t *pkg, new_pctype = i40e_find_customized_pctype(pf, I40E_CUSTOMIZED_GTPU); + else if (!strcmp(name, "IPV4_L2TPV3")) + new_pctype = + i40e_find_customized_pctype(pf, + I40E_CUSTOMIZED_IPV4_L2TPV3); + else if (!strcmp(name, "IPV6_L2TPV3")) + new_pctype = + i40e_find_customized_pctype(pf, + I40E_CUSTOMIZED_IPV6_L2TPV3); if (new_pctype) { if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) { new_pctype->pctype = pctype_value; @@ -12543,7 +12551,8 @@ i40e_update_customized_ptype(struct rte_eth_dev *dev, uint8_t *pkg, RTE_PTYPE_TUNNEL_GRENAT; in_tunnel = true; } else if (!strncasecmp(name, "L2TPV2CTL", 9) || - !strncasecmp(name, "L2TPV2", 6)) { + !strncasecmp(name, "L2TPV2", 6) || + !strncasecmp(name, "L2TPV3", 6)) { ptype_mapping[i].sw_ptype |= RTE_PTYPE_TUNNEL_L2TP; in_tunnel = true; diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 295ad593b9..bba2b83b4f 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -508,24 +508,38 @@ struct i40e_raw_flow { uint32_t length; }; +/* A structure used to define the input for L2TPv3 over IPv4 flow */ +struct i40e_ipv4_l2tpv3oip_flow { + struct rte_eth_ipv4_flow ip4; + uint32_t session_id; /* Session ID in big endian. */ +}; + +/* A structure used to define the input for L2TPv3 over IPv6 flow */ +struct i40e_ipv6_l2tpv3oip_flow { + struct rte_eth_ipv6_flow ip6; + uint32_t session_id; /* Session ID in big endian. */ +}; + /* * A union contains the inputs for all types of flow * items in flows need to be in big endian */ union i40e_fdir_flow { - struct rte_eth_l2_flow l2_flow; - struct rte_eth_udpv4_flow udp4_flow; - struct rte_eth_tcpv4_flow tcp4_flow; - struct rte_eth_sctpv4_flow sctp4_flow; - struct rte_eth_ipv4_flow ip4_flow; - struct rte_eth_udpv6_flow udp6_flow; - struct rte_eth_tcpv6_flow tcp6_flow; - struct rte_eth_sctpv6_flow sctp6_flow; - struct rte_eth_ipv6_flow ipv6_flow; - struct i40e_gtp_flow gtp_flow; - struct i40e_gtp_ipv4_flow gtp_ipv4_flow; - struct i40e_gtp_ipv6_flow gtp_ipv6_flow; - struct i40e_raw_flow raw_flow; + struct rte_eth_l2_flow l2_flow; + struct rte_eth_udpv4_flow udp4_flow; + struct rte_eth_tcpv4_flow tcp4_flow; + struct rte_eth_sctpv4_flow sctp4_flow; + struct rte_eth_ipv4_flow ip4_flow; + struct rte_eth_udpv6_flow udp6_flow; + struct rte_eth_tcpv6_flow tcp6_flow; + struct rte_eth_sctpv6_flow sctp6_flow; + struct rte_eth_ipv6_flow ipv6_flow; + struct i40e_gtp_flow gtp_flow; + struct i40e_gtp_ipv4_flow gtp_ipv4_flow; + struct i40e_gtp_ipv6_flow gtp_ipv6_flow; + struct i40e_raw_flow raw_flow; + struct i40e_ipv4_l2tpv3oip_flow ip4_l2tpv3oip_flow; + struct i40e_ipv6_l2tpv3oip_flow ip6_l2tpv3oip_flow; }; enum i40e_fdir_ip_type { @@ -542,6 +556,7 @@ struct i40e_fdir_flow_ext { uint16_t dst_id; /* VF ID, available when is_vf is 1*/ bool inner_ip; /* If there is inner ip */ enum i40e_fdir_ip_type iip_type; /* ip type for inner ip */ + enum i40e_fdir_ip_type oip_type; /* ip type for outer ip */ bool customized_pctype; /* If customized pctype is used */ bool pkt_template; /* If raw packet template is used */ }; @@ -897,6 +912,8 @@ enum i40e_new_pctype { I40E_CUSTOMIZED_GTPU_IPV4, I40E_CUSTOMIZED_GTPU_IPV6, I40E_CUSTOMIZED_GTPU, + I40E_CUSTOMIZED_IPV4_L2TPV3, + I40E_CUSTOMIZED_IPV6_L2TPV3, I40E_CUSTOMIZED_MAX, }; diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index dee007daae..2fc099517b 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -33,6 +33,10 @@ #define IPV6_ADDR_LEN 16 #endif +#ifndef IPPROTO_L2TP +#define IPPROTO_L2TP 115 +#endif + #define I40E_FDIR_PKT_LEN 512 #define I40E_FDIR_IP_DEFAULT_LEN 420 #define I40E_FDIR_IP_DEFAULT_TTL 0x40 @@ -1026,7 +1030,12 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, pctype == I40E_FILTER_PCTYPE_NONF_IPV4_SCTP || pctype == I40E_FILTER_PCTYPE_NONF_IPV4_OTHER || pctype == I40E_FILTER_PCTYPE_FRAG_IPV4 || - is_customized_pctype) { + ((is_customized_pctype) && + ((cus_pctype->index == I40E_CUSTOMIZED_GTPC) || + (cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV4) || + (cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV6) || + (cus_pctype->index == I40E_CUSTOMIZED_GTPU) || + (cus_pctype->index == I40E_CUSTOMIZED_IPV4_L2TPV3)))) { ip = (struct rte_ipv4_hdr *)raw_pkt; *ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); @@ -1054,12 +1063,16 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV6 || cus_pctype->index == I40E_CUSTOMIZED_GTPU) ip->next_proto_id = IPPROTO_UDP; + else if (cus_pctype->index == I40E_CUSTOMIZED_IPV4_L2TPV3) + ip->next_proto_id = IPPROTO_L2TP; len += sizeof(struct rte_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 || pctype == I40E_FILTER_PCTYPE_NONF_IPV6_OTHER || - pctype == I40E_FILTER_PCTYPE_FRAG_IPV6) { + pctype == I40E_FILTER_PCTYPE_FRAG_IPV6 || + ((is_customized_pctype) && + (cus_pctype->index == I40E_CUSTOMIZED_IPV6_L2TPV3))) { ip6 = (struct rte_ipv6_hdr *)raw_pkt; *ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6); @@ -1069,9 +1082,12 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf, 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]; + if (!is_customized_pctype) + ip6->proto = fdir_input->flow.ipv6_flow.proto ? + fdir_input->flow.ipv6_flow.proto : + next_proto[fdir_input->pctype]; + else if (cus_pctype->index == I40E_CUSTOMIZED_IPV6_L2TPV3) + ip6->proto = IPPROTO_L2TP; ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ? fdir_input->flow.ipv6_flow.hop_limits : I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; @@ -1115,6 +1131,7 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, struct rte_flow_item_gtp *gtp; struct rte_ipv4_hdr *gtp_ipv4; struct rte_ipv6_hdr *gtp_ipv6; + struct rte_flow_item_l2tpv3oip *l2tpv3oip; uint8_t size, dst = 0; uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/ int len; @@ -1285,6 +1302,19 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, } else payload = (unsigned char *)gtp + sizeof(struct rte_flow_item_gtp); + } else if (cus_pctype->index == I40E_CUSTOMIZED_IPV4_L2TPV3 || + cus_pctype->index == I40E_CUSTOMIZED_IPV6_L2TPV3) { + l2tpv3oip = (struct rte_flow_item_l2tpv3oip *)(raw_pkt + + len); + + if (cus_pctype->index == I40E_CUSTOMIZED_IPV4_L2TPV3) + l2tpv3oip->session_id = + fdir_input->flow.ip4_l2tpv3oip_flow.session_id; + else + l2tpv3oip->session_id = + fdir_input->flow.ip6_l2tpv3oip_flow.session_id; + payload = (unsigned char *)l2tpv3oip + + sizeof(struct rte_flow_item_l2tpv3oip); } } else { PMD_DRV_LOG(ERR, "unknown pctype %u.", diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index 61021037c8..949ecc8d17 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -1615,6 +1615,20 @@ static enum rte_flow_item_type pattern_qinq_1[] = { RTE_FLOW_ITEM_TYPE_END, }; +static enum rte_flow_item_type pattern_fdir_ipv4_l2tpv3oip[] = { + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_L2TPV3OIP, + RTE_FLOW_ITEM_TYPE_END, +}; + +static enum rte_flow_item_type pattern_fdir_ipv6_l2tpv3oip[] = { + RTE_FLOW_ITEM_TYPE_ETH, + RTE_FLOW_ITEM_TYPE_IPV6, + RTE_FLOW_ITEM_TYPE_L2TPV3OIP, + RTE_FLOW_ITEM_TYPE_END, +}; + static struct i40e_valid_pattern i40e_supported_patterns[] = { /* Ethertype */ { pattern_ethertype, i40e_flow_parse_ethertype_filter }, @@ -1795,6 +1809,9 @@ static struct i40e_valid_pattern i40e_supported_patterns[] = { { pattern_fdir_ipv6_gtpu, i40e_flow_parse_gtp_filter }, /* QINQ */ { pattern_qinq_1, i40e_flow_parse_qinq_filter }, + /* L2TPv3 over IP */ + { pattern_fdir_ipv4_l2tpv3oip, i40e_flow_parse_fdir_filter }, + { pattern_fdir_ipv6_l2tpv3oip, i40e_flow_parse_fdir_filter }, }; #define NEXT_ITEM_OF_ACTION(act, actions, index) \ @@ -2420,6 +2437,15 @@ i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf, cus_pctype = i40e_find_customized_pctype(pf, I40E_CUSTOMIZED_GTPU_IPV6); break; + case RTE_FLOW_ITEM_TYPE_L2TPV3OIP: + if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4) + cus_pctype = i40e_find_customized_pctype(pf, + I40E_CUSTOMIZED_IPV4_L2TPV3); + else if (filter->input.flow_ext.oip_type == + I40E_FDIR_IPTYPE_IPV6) + cus_pctype = i40e_find_customized_pctype(pf, + I40E_CUSTOMIZED_IPV6_L2TPV3); + break; default: PMD_DRV_LOG(ERR, "Unsupported item type"); break; @@ -2461,6 +2487,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, const struct rte_flow_item_gtp *gtp_spec, *gtp_mask; const struct rte_flow_item_raw *raw_spec, *raw_mask; const struct rte_flow_item_vf *vf_spec; + const struct rte_flow_item_l2tpv3oip *l2tpv3oip_spec, *l2tpv3oip_mask; uint8_t pctype = 0; uint64_t input_set = I40E_INSET_NONE; @@ -3012,6 +3039,36 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, return -rte_errno; } break; + case RTE_FLOW_ITEM_TYPE_L2TPV3OIP: + l2tpv3oip_spec = item->spec; + l2tpv3oip_mask = item->mask; + + if (!l2tpv3oip_spec || !l2tpv3oip_mask) + break; + + if (l2tpv3oip_mask->session_id != UINT32_MAX) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid L2TPv3 mask"); + return -rte_errno; + } + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { + filter->input.flow.ip4_l2tpv3oip_flow.session_id = + l2tpv3oip_spec->session_id; + filter->input.flow_ext.oip_type = + I40E_FDIR_IPTYPE_IPV4; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { + filter->input.flow.ip6_l2tpv3oip_flow.session_id = + l2tpv3oip_spec->session_id; + filter->input.flow_ext.oip_type = + I40E_FDIR_IPTYPE_IPV6; + } + + filter->input.flow_ext.customized_pctype = true; + cus_proto = item_type; + break; default: break; }