From 4149825bbdb996837a3a73c1467ff93a228358a8 Mon Sep 17 00:00:00 2001 From: Beilei Xing Date: Thu, 5 Oct 2017 16:14:54 +0800 Subject: [PATCH] net/i40e: finish integration FDIR with generic flow API rte_eth_fdir_* structures are still used in FDIR functions. This patch adds i40e private FDIR related structures and functions to finish integration FDIR with generic flow API. Signed-off-by: Beilei Xing --- drivers/net/i40e/i40e_ethdev.h | 83 +++++- drivers/net/i40e/i40e_fdir.c | 487 +++++++++++++++++++++++++++++++-- drivers/net/i40e/i40e_flow.c | 77 +++--- 3 files changed, 584 insertions(+), 63 deletions(-) diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 9688ea8793..ef4c503519 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -460,6 +460,80 @@ struct i40e_vmdq_info { #define I40E_FLEX_WORD_MASK(off) (0x80 >> (off)) #define I40E_FDIR_IPv6_TC_OFFSET 20 +/* + * 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; +}; + +/* A structure used to contain extend input of flow */ +struct i40e_fdir_flow_ext { + uint16_t vlan_tci; + uint8_t flexbytes[RTE_ETH_FDIR_MAX_FLEXLEN]; + /* It is filled by the flexible payload to match. */ + uint8_t is_vf; /* 1 for VF, 0 for port dev */ + uint16_t dst_id; /* VF ID, available when is_vf is 1*/ +}; + +/* A structure used to define the input for a flow director filter entry */ +struct i40e_fdir_input { + enum i40e_filter_pctype pctype; + union i40e_fdir_flow flow; + /* Flow fields to match, dependent on flow_type */ + struct i40e_fdir_flow_ext flow_ext; + /* Additional fields to match */ +}; + +/* Behavior will be taken if FDIR match */ +enum i40e_fdir_behavior { + I40E_FDIR_ACCEPT = 0, + I40E_FDIR_REJECT, + I40E_FDIR_PASSTHRU, +}; + +/* Flow director report status + * It defines what will be reported if FDIR entry is matched. + */ +enum i40e_fdir_status { + I40E_FDIR_NO_REPORT_STATUS = 0, /* Report nothing. */ + I40E_FDIR_REPORT_ID, /* Only report FD ID. */ + I40E_FDIR_REPORT_ID_FLEX_4, /* Report FD ID and 4 flex bytes. */ + I40E_FDIR_REPORT_FLEX_8, /* Report 8 flex bytes. */ +}; + +/* A structure used to define an action when match FDIR packet filter. */ +struct i40e_fdir_action { + uint16_t rx_queue; /* Queue assigned to if FDIR match. */ + enum i40e_fdir_behavior behavior; /* Behavior will be taken */ + enum i40e_fdir_status report_status; /* Status report option */ + /* If report_status is I40E_FDIR_REPORT_ID_FLEX_4 or + * I40E_FDIR_REPORT_FLEX_8, flex_off specifies where the reported + * flex bytes start from in flexible payload. + */ + uint8_t flex_off; +}; + +/* A structure used to define the flow director filter entry by filter_ctrl API + * It supports RTE_ETH_FILTER_FDIR with RTE_ETH_FILTER_ADD and + * RTE_ETH_FILTER_DELETE operations. + */ +struct i40e_fdir_filter_conf { + uint32_t soft_id; + /* ID, an unique value is required when deal with FDIR entry */ + struct i40e_fdir_input input; /* Input set */ + struct i40e_fdir_action action; /* Action taken when match */ +}; + /* * Structure to store flex pit for flow diretor. */ @@ -484,7 +558,7 @@ struct i40e_fdir_flex_mask { struct i40e_fdir_filter { TAILQ_ENTRY(i40e_fdir_filter) rules; - struct rte_eth_fdir_filter fdir; + struct i40e_fdir_filter_conf fdir; }; TAILQ_HEAD(i40e_fdir_filter_list, i40e_fdir_filter); @@ -913,7 +987,7 @@ extern const struct rte_flow_ops i40e_flow_ops; union i40e_filter_t { struct rte_eth_ethertype_filter ethertype_filter; - struct rte_eth_fdir_filter fdir_filter; + struct i40e_fdir_filter_conf fdir_filter; struct rte_eth_tunnel_filter_conf tunnel_filter; struct i40e_tunnel_filter_conf consistent_tunnel_filter; }; @@ -990,7 +1064,7 @@ i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule, int i40e_sw_ethertype_filter_del(struct i40e_pf *pf, struct i40e_ethertype_filter_input *input); int i40e_sw_fdir_filter_del(struct i40e_pf *pf, - struct rte_eth_fdir_input *input); + struct i40e_fdir_input *input); struct i40e_tunnel_filter * i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule, const struct i40e_tunnel_filter_input *input); @@ -1003,6 +1077,9 @@ int i40e_ethertype_filter_set(struct i40e_pf *pf, int i40e_add_del_fdir_filter(struct rte_eth_dev *dev, const struct rte_eth_fdir_filter *filter, bool add); +int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, + const struct i40e_fdir_filter_conf *filter, + bool add); int i40e_dev_tunnel_filter_set(struct i40e_pf *pf, struct rte_eth_tunnel_filter_conf *tunnel_filter, uint8_t add); diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index 268ada0d50..7b16584bc4 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -100,13 +100,18 @@ static int i40e_fdir_filter_programming(struct i40e_pf *pf, enum i40e_filter_pctype pctype, const struct rte_eth_fdir_filter *filter, bool add); -static int i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input, +static int i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input, struct i40e_fdir_filter *filter); static struct i40e_fdir_filter * i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info, - const struct rte_eth_fdir_input *input); + const struct i40e_fdir_input *input); static int i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter); +static int +i40e_flow_fdir_filter_programming(struct i40e_pf *pf, + enum i40e_filter_pctype pctype, + const struct i40e_fdir_filter_conf *filter, + bool add); static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) @@ -933,6 +938,263 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, return 0; } +static inline int +i40e_flow_fdir_fill_eth_ip_head(const struct i40e_fdir_input *fdir_input, + unsigned char *raw_pkt, + bool vlan) +{ + static uint8_t vlan_frame[] = {0x81, 0, 0, 0}; + uint16_t *ether_type; + uint8_t len = 2 * sizeof(struct ether_addr); + struct ipv4_hdr *ip; + struct ipv6_hdr *ip6; + static const uint8_t next_proto[] = { + [I40E_FILTER_PCTYPE_FRAG_IPV4] = IPPROTO_IP, + [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = IPPROTO_TCP, + [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = IPPROTO_UDP, + [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = IPPROTO_SCTP, + [I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] = IPPROTO_IP, + [I40E_FILTER_PCTYPE_FRAG_IPV6] = IPPROTO_NONE, + [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] = IPPROTO_TCP, + [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] = IPPROTO_UDP, + [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] = IPPROTO_SCTP, + [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] = IPPROTO_NONE, + }; + + raw_pkt += 2 * sizeof(struct ether_addr); + if (vlan && fdir_input->flow_ext.vlan_tci) { + rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame)); + rte_memcpy(raw_pkt + sizeof(uint16_t), + &fdir_input->flow_ext.vlan_tci, + sizeof(uint16_t)); + raw_pkt += sizeof(vlan_frame); + len += sizeof(vlan_frame); + } + ether_type = (uint16_t *)raw_pkt; + raw_pkt += sizeof(uint16_t); + len += sizeof(uint16_t); + + switch (fdir_input->pctype) { + case I40E_FILTER_PCTYPE_L2_PAYLOAD: + *ether_type = fdir_input->flow.l2_flow.ether_type; + break; + case I40E_FILTER_PCTYPE_NONF_IPV4_TCP: + case I40E_FILTER_PCTYPE_NONF_IPV4_UDP: + case I40E_FILTER_PCTYPE_NONF_IPV4_SCTP: + case I40E_FILTER_PCTYPE_NONF_IPV4_OTHER: + case I40E_FILTER_PCTYPE_FRAG_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->next_proto_id = fdir_input->flow.ip4_flow.proto ? + fdir_input->flow.ip4_flow.proto : + next_proto[fdir_input->pctype]; + 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 + * to the expected received packets. + */ + ip->src_addr = fdir_input->flow.ip4_flow.dst_ip; + ip->dst_addr = fdir_input->flow.ip4_flow.src_ip; + len += sizeof(struct ipv4_hdr); + break; + case I40E_FILTER_PCTYPE_NONF_IPV6_TCP: + case I40E_FILTER_PCTYPE_NONF_IPV6_UDP: + case I40E_FILTER_PCTYPE_NONF_IPV6_SCTP: + case I40E_FILTER_PCTYPE_NONF_IPV6_OTHER: + case I40E_FILTER_PCTYPE_FRAG_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 | + (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; + /** + * 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); + break; + default: + PMD_DRV_LOG(ERR, "unknown pctype %u.", + fdir_input->pctype); + return -1; + } + return len; +} + +/** + * i40e_flow_fdir_construct_pkt - construct packet based on fields in input + * @pf: board private structure + * @fdir_input: input set of the flow director entry + * @raw_pkt: a packet to be constructed + */ +static int +i40e_flow_fdir_construct_pkt(struct i40e_pf *pf, + const struct i40e_fdir_input *fdir_input, + unsigned char *raw_pkt) +{ + unsigned char *payload, *ptr; + struct udp_hdr *udp; + struct tcp_hdr *tcp; + struct sctp_hdr *sctp; + uint8_t size, dst = 0; + uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/ + int len; + + /* fill the ethernet and IP head */ + len = i40e_flow_fdir_fill_eth_ip_head(fdir_input, raw_pkt, + !!fdir_input->flow_ext.vlan_tci); + if (len < 0) + return -EINVAL; + + /* fill the L4 head */ + switch (fdir_input->pctype) { + case I40E_FILTER_PCTYPE_NONF_IPV4_UDP: + udp = (struct udp_hdr *)(raw_pkt + len); + payload = (unsigned char *)udp + sizeof(struct udp_hdr); + /** + * The source and destination fields in the transmitted packet + * 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); + break; + + case I40E_FILTER_PCTYPE_NONF_IPV4_TCP: + tcp = (struct tcp_hdr *)(raw_pkt + len); + payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); + /** + * The source and destination fields in the transmitted packet + * need to be presented in a reversed order with respect + * to the expected received packets. + */ + tcp->src_port = fdir_input->flow.tcp4_flow.dst_port; + tcp->dst_port = fdir_input->flow.tcp4_flow.src_port; + tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; + break; + + case I40E_FILTER_PCTYPE_NONF_IPV4_SCTP: + sctp = (struct sctp_hdr *)(raw_pkt + len); + payload = (unsigned char *)sctp + sizeof(struct sctp_hdr); + /** + * The source and destination fields in the transmitted packet + * need to be presented in a reversed order with respect + * to the expected received packets. + */ + sctp->src_port = fdir_input->flow.sctp4_flow.dst_port; + sctp->dst_port = fdir_input->flow.sctp4_flow.src_port; + sctp->tag = fdir_input->flow.sctp4_flow.verify_tag; + break; + + case I40E_FILTER_PCTYPE_NONF_IPV4_OTHER: + case I40E_FILTER_PCTYPE_FRAG_IPV4: + payload = raw_pkt + len; + set_idx = I40E_FLXPLD_L3_IDX; + break; + + case I40E_FILTER_PCTYPE_NONF_IPV6_UDP: + udp = (struct udp_hdr *)(raw_pkt + len); + payload = (unsigned char *)udp + sizeof(struct udp_hdr); + /** + * The source and destination fields in the transmitted packet + * 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); + break; + + case I40E_FILTER_PCTYPE_NONF_IPV6_TCP: + tcp = (struct tcp_hdr *)(raw_pkt + len); + payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); + /** + * The source and destination fields in the transmitted packet + * need to be presented in a reversed order with respect + * to the expected received packets. + */ + tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; + tcp->src_port = fdir_input->flow.udp6_flow.dst_port; + tcp->dst_port = fdir_input->flow.udp6_flow.src_port; + break; + + case I40E_FILTER_PCTYPE_NONF_IPV6_SCTP: + sctp = (struct sctp_hdr *)(raw_pkt + len); + payload = (unsigned char *)sctp + sizeof(struct sctp_hdr); + /** + * The source and destination fields in the transmitted packet + * need to be presented in a reversed order with respect + * to the expected received packets. + */ + sctp->src_port = fdir_input->flow.sctp6_flow.dst_port; + sctp->dst_port = fdir_input->flow.sctp6_flow.src_port; + sctp->tag = fdir_input->flow.sctp6_flow.verify_tag; + break; + + case I40E_FILTER_PCTYPE_NONF_IPV6_OTHER: + case I40E_FILTER_PCTYPE_FRAG_IPV6: + payload = raw_pkt + len; + set_idx = I40E_FLXPLD_L3_IDX; + break; + case I40E_FILTER_PCTYPE_L2_PAYLOAD: + payload = raw_pkt + len; + /** + * ARP packet is a special case on which the payload + * starts after the whole ARP header + */ + if (fdir_input->flow.l2_flow.ether_type == + rte_cpu_to_be_16(ETHER_TYPE_ARP)) + payload += sizeof(struct arp_hdr); + set_idx = I40E_FLXPLD_L2_IDX; + break; + default: + PMD_DRV_LOG(ERR, "unknown pctype %u.", fdir_input->pctype); + return -EINVAL; + } + + /* fill the flexbytes to payload */ + for (i = 0; i < I40E_MAX_FLXPLD_FIED; i++) { + pit_idx = set_idx * I40E_MAX_FLXPLD_FIED + i; + size = pf->fdir.flex_set[pit_idx].size; + if (size == 0) + continue; + dst = pf->fdir.flex_set[pit_idx].dst_offset * sizeof(uint16_t); + ptr = payload + + pf->fdir.flex_set[pit_idx].src_offset * sizeof(uint16_t); + (void)rte_memcpy(ptr, + &fdir_input->flow_ext.flexbytes[dst], + size * sizeof(uint16_t)); + } + + return 0; +} + /* Construct the tx flags */ static inline uint64_t i40e_build_ctob(uint32_t td_cmd, @@ -1006,17 +1268,17 @@ i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq) } static int -i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input, +i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input, struct i40e_fdir_filter *filter) { - rte_memcpy(&filter->fdir, input, sizeof(struct rte_eth_fdir_filter)); + rte_memcpy(&filter->fdir, input, sizeof(struct i40e_fdir_filter_conf)); return 0; } /* Check if there exists the flow director filter */ static struct i40e_fdir_filter * i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info, - const struct rte_eth_fdir_input *input) + const struct i40e_fdir_input *input) { int ret; @@ -1051,7 +1313,7 @@ i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter) /* Delete a flow director filter from the SW list */ int -i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input) +i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct i40e_fdir_input *input) { struct i40e_fdir_info *fdir_info = &pf->fdir; struct i40e_fdir_filter *filter; @@ -1081,16 +1343,13 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input) */ int i40e_add_del_fdir_filter(struct rte_eth_dev *dev, - const struct rte_eth_fdir_filter *filter, - bool add) + const struct rte_eth_fdir_filter *filter, + bool add) { struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; enum i40e_filter_pctype pctype; - struct i40e_fdir_info *fdir_info = &pf->fdir; - struct i40e_fdir_filter *fdir_filter, *node; - struct i40e_fdir_filter check_filter; /* Check if the filter exists */ int ret = 0; if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) { @@ -1114,6 +1373,65 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, return -EINVAL; } + memset(pkt, 0, I40E_FDIR_PKT_LEN); + + ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt); + if (ret < 0) { + PMD_DRV_LOG(ERR, "construct packet for fdir fails."); + return ret; + } + + if (hw->mac.type == I40E_MAC_X722) { + /* get translated pctype value in fd pctype register */ + pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl( + hw, I40E_GLQF_FD_PCTYPES((int)pctype)); + } + + ret = i40e_fdir_filter_programming(pf, pctype, filter, add); + if (ret < 0) { + PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).", + pctype); + return ret; + } + + return ret; +} + +/** + * i40e_flow_add_del_fdir_filter - add or remove a flow director filter. + * @pf: board private structure + * @filter: fdir filter entry + * @add: 0 - delete, 1 - add + */ +int +i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, + const struct i40e_fdir_filter_conf *filter, + bool add) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + enum i40e_filter_pctype pctype; + struct i40e_fdir_info *fdir_info = &pf->fdir; + struct i40e_fdir_filter *fdir_filter, *node; + struct i40e_fdir_filter check_filter; /* Check if the filter exists */ + int ret = 0; + + if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) { + PMD_DRV_LOG(ERR, "FDIR is not enabled, please check the mode in fdir_conf."); + return -ENOTSUP; + } + + if (filter->action.rx_queue >= pf->dev_data->nb_rx_queues) { + PMD_DRV_LOG(ERR, "Invalid queue ID"); + return -EINVAL; + } + if (filter->input.flow_ext.is_vf && + filter->input.flow_ext.dst_id >= pf->vf_num) { + PMD_DRV_LOG(ERR, "Invalid VF ID"); + return -EINVAL; + } + /* Check if there is the filter in SW list */ memset(&check_filter, 0, sizeof(check_filter)); i40e_fdir_filter_convert(filter, &check_filter); @@ -1132,7 +1450,7 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, memset(pkt, 0, I40E_FDIR_PKT_LEN); - ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt); + ret = i40e_flow_fdir_construct_pkt(pf, &filter->input, pkt); if (ret < 0) { PMD_DRV_LOG(ERR, "construct packet for fdir fails."); return ret; @@ -1141,9 +1459,12 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, if (hw->mac.type == I40E_MAC_X722) { /* get translated pctype value in fd pctype register */ pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl( - hw, I40E_GLQF_FD_PCTYPES((int)pctype)); - } - ret = i40e_fdir_filter_programming(pf, pctype, filter, add); + hw, I40E_GLQF_FD_PCTYPES( + (int)filter->input.pctype)); + } else + pctype = filter->input.pctype; + + ret = i40e_flow_fdir_filter_programming(pf, pctype, filter, add); if (ret < 0) { PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).", pctype); @@ -1297,6 +1618,140 @@ i40e_fdir_filter_programming(struct i40e_pf *pf, return -ETIMEDOUT; } +/* + * i40e_flow_fdir_filter_programming - Program a flow director filter rule. + * Is done by Flow Director Programming Descriptor followed by packet + * structure that contains the filter fields need to match. + * @pf: board private structure + * @pctype: pctype + * @filter: fdir filter entry + * @add: 0 - delete, 1 - add + */ +static int +i40e_flow_fdir_filter_programming(struct i40e_pf *pf, + enum i40e_filter_pctype pctype, + const struct i40e_fdir_filter_conf *filter, + bool add) +{ + struct i40e_tx_queue *txq = pf->fdir.txq; + struct i40e_rx_queue *rxq = pf->fdir.rxq; + const struct i40e_fdir_action *fdir_action = &filter->action; + volatile struct i40e_tx_desc *txdp; + volatile struct i40e_filter_program_desc *fdirdp; + uint32_t td_cmd; + uint16_t vsi_id, i; + uint8_t dest; + + PMD_DRV_LOG(INFO, "filling filter programming descriptor."); + fdirdp = (volatile struct i40e_filter_program_desc *) + (&txq->tx_ring[txq->tx_tail]); + + fdirdp->qindex_flex_ptype_vsi = + rte_cpu_to_le_32((fdir_action->rx_queue << + I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & + I40E_TXD_FLTR_QW0_QINDEX_MASK); + + fdirdp->qindex_flex_ptype_vsi |= + rte_cpu_to_le_32((fdir_action->flex_off << + I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) & + I40E_TXD_FLTR_QW0_FLEXOFF_MASK); + + fdirdp->qindex_flex_ptype_vsi |= + rte_cpu_to_le_32((pctype << + I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) & + I40E_TXD_FLTR_QW0_PCTYPE_MASK); + + if (filter->input.flow_ext.is_vf) + vsi_id = pf->vfs[filter->input.flow_ext.dst_id].vsi->vsi_id; + else + /* Use LAN VSI Id by default */ + vsi_id = pf->main_vsi->vsi_id; + fdirdp->qindex_flex_ptype_vsi |= + rte_cpu_to_le_32(((uint32_t)vsi_id << + I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & + I40E_TXD_FLTR_QW0_DEST_VSI_MASK); + + fdirdp->dtype_cmd_cntindex = + rte_cpu_to_le_32(I40E_TX_DESC_DTYPE_FILTER_PROG); + + if (add) + fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32( + I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << + I40E_TXD_FLTR_QW1_PCMD_SHIFT); + else + fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32( + I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << + I40E_TXD_FLTR_QW1_PCMD_SHIFT); + + if (fdir_action->behavior == I40E_FDIR_REJECT) + dest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET; + else if (fdir_action->behavior == I40E_FDIR_ACCEPT) + dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; + else if (fdir_action->behavior == I40E_FDIR_PASSTHRU) + dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER; + else { + PMD_DRV_LOG(ERR, "Failed to program FDIR filter: unsupported fdir behavior."); + return -EINVAL; + } + + fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32((dest << + I40E_TXD_FLTR_QW1_DEST_SHIFT) & + I40E_TXD_FLTR_QW1_DEST_MASK); + + fdirdp->dtype_cmd_cntindex |= + rte_cpu_to_le_32((fdir_action->report_status << + I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) & + I40E_TXD_FLTR_QW1_FD_STATUS_MASK); + + fdirdp->dtype_cmd_cntindex |= + rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK); + fdirdp->dtype_cmd_cntindex |= + rte_cpu_to_le_32( + ((uint32_t)pf->fdir.match_counter_index << + I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & + I40E_TXD_FLTR_QW1_CNTINDEX_MASK); + + fdirdp->fd_id = rte_cpu_to_le_32(filter->soft_id); + + PMD_DRV_LOG(INFO, "filling transmit descriptor."); + txdp = &txq->tx_ring[txq->tx_tail + 1]; + txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr); + td_cmd = I40E_TX_DESC_CMD_EOP | + I40E_TX_DESC_CMD_RS | + I40E_TX_DESC_CMD_DUMMY; + + txdp->cmd_type_offset_bsz = + i40e_build_ctob(td_cmd, 0, I40E_FDIR_PKT_LEN, 0); + + txq->tx_tail += 2; /* set 2 descriptors above, fdirdp and txdp */ + if (txq->tx_tail >= txq->nb_tx_desc) + txq->tx_tail = 0; + /* Update the tx tail register */ + rte_wmb(); + I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail); + for (i = 0; i < I40E_FDIR_MAX_WAIT_US; i++) { + if ((txdp->cmd_type_offset_bsz & + rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) == + rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) + break; + rte_delay_us(1); + } + if (i >= I40E_FDIR_MAX_WAIT_US) { + PMD_DRV_LOG(ERR, + "Failed to program FDIR filter: time out to get DD on tx queue."); + return -ETIMEDOUT; + } + /* totally delay 10 ms to check programming status*/ + rte_delay_us(I40E_FDIR_MAX_WAIT_US); + if (i40e_check_fdir_programming_status(rxq) < 0) { + PMD_DRV_LOG(ERR, + "Failed to program FDIR filter: programming status reported."); + return -ETIMEDOUT; + } + + return 0; +} + /* * i40e_fdir_flush - clear all filters of Flow Director table * @pf: board private structure @@ -1572,7 +2027,7 @@ i40e_fdir_filter_restore(struct i40e_pf *pf) uint32_t best_cnt; /**< Number of filters in best effort spaces. */ TAILQ_FOREACH(f, fdir_list, rules) - i40e_add_del_fdir_filter(dev, &f->fdir, TRUE); + i40e_flow_add_del_fdir_filter(dev, &f->fdir, TRUE); fdstat = I40E_READ_REG(hw, I40E_PFQF_FDSTAT); guarant_cnt = diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index 5d8afc608e..73af7fda52 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -84,11 +84,11 @@ static int i40e_flow_parse_ethertype_action(struct rte_eth_dev *dev, static int i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - struct rte_eth_fdir_filter *filter); + struct i40e_fdir_filter_conf *filter); static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - struct rte_eth_fdir_filter *filter); + struct i40e_fdir_filter_conf *filter); static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, @@ -2315,7 +2315,7 @@ static int i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - struct rte_eth_fdir_filter *filter) + 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; @@ -2329,8 +2329,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, const struct rte_flow_item_raw *raw_spec, *raw_mask; const struct rte_flow_item_vf *vf_spec; - uint32_t flow_type = RTE_ETH_FLOW_UNKNOWN; - enum i40e_filter_pctype pctype; + enum i40e_filter_pctype pctype = 0; uint64_t input_set = I40E_INSET_NONE; uint16_t frag_off; enum rte_flow_item_type item_type; @@ -2402,7 +2401,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, } } - flow_type = RTE_ETH_FLOW_L2_PAYLOAD; + pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD; layer_idx = I40E_FLXPLD_L2_IDX; break; @@ -2420,7 +2419,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, } } - flow_type = RTE_ETH_FLOW_L2_PAYLOAD; + pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD; layer_idx = I40E_FLXPLD_L2_IDX; break; @@ -2457,13 +2456,13 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, input_set |= I40E_INSET_IPV4_PROTO; /* Get filter info */ - flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER; + pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; /* 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) - flow_type = RTE_ETH_FLOW_FRAG_IPV4; + pctype = I40E_FILTER_PCTYPE_FRAG_IPV4; /* Get the filter info */ filter->input.flow.ip4_flow.proto = @@ -2535,11 +2534,10 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, /* Check if it is fragment. */ if (ipv6_spec->hdr.proto == I40E_IPV6_FRAG_HEADER) - flow_type = - RTE_ETH_FLOW_FRAG_IPV6; + pctype = I40E_FILTER_PCTYPE_FRAG_IPV6; else - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV6_OTHER; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV6_OTHER; } layer_idx = I40E_FLXPLD_L3_IDX; @@ -2572,11 +2570,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, /* Get filter info */ if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV4_TCP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV4_TCP; else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV6_TCP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV6_TCP; if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { filter->input.flow.tcp4_flow.src_port = @@ -2616,11 +2614,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, /* Get filter info */ if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV4_UDP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV4_UDP; else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV6_UDP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV6_UDP; if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { filter->input.flow.udp4_flow.src_port = @@ -2663,11 +2661,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, /* Get filter info */ if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV4_SCTP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV4_SCTP; else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) - flow_type = - RTE_ETH_FLOW_NONFRAG_IPV6_SCTP; + pctype = + I40E_FILTER_PCTYPE_NONF_IPV6_SCTP; if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { filter->input.flow.sctp4_flow.src_port = @@ -2776,15 +2774,6 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, } } - pctype = i40e_flowtype_to_pctype(pf->adapter, flow_type); - if (pctype == I40E_FILTER_PCTYPE_INVALID || - pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, item, - "Unsupported flow type"); - return -rte_errno; - } - ret = i40e_flow_set_fdir_inset(pf, pctype, input_set); if (ret == -1) { rte_flow_error_set(error, EINVAL, @@ -2798,7 +2787,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev, return -rte_errno; } - filter->input.flow_type = flow_type; + filter->input.pctype = pctype; /* Store flex mask to SW */ ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask); @@ -2833,7 +2822,7 @@ static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - struct rte_eth_fdir_filter *filter) + struct i40e_fdir_filter_conf *filter) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); const struct rte_flow_action *act; @@ -2856,13 +2845,13 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, "Invalid queue ID for FDIR."); return -rte_errno; } - filter->action.behavior = RTE_ETH_FDIR_ACCEPT; + filter->action.behavior = I40E_FDIR_ACCEPT; break; case RTE_FLOW_ACTION_TYPE_DROP: - filter->action.behavior = RTE_ETH_FDIR_REJECT; + filter->action.behavior = I40E_FDIR_REJECT; break; case RTE_FLOW_ACTION_TYPE_PASSTHRU: - filter->action.behavior = RTE_ETH_FDIR_PASSTHRU; + filter->action.behavior = I40E_FDIR_PASSTHRU; break; default: rte_flow_error_set(error, EINVAL, @@ -2877,11 +2866,11 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev, switch (act->type) { case RTE_FLOW_ACTION_TYPE_MARK: mark_spec = (const struct rte_flow_action_mark *)act->conf; - filter->action.report_status = RTE_ETH_FDIR_REPORT_ID; + filter->action.report_status = I40E_FDIR_REPORT_ID; filter->soft_id = mark_spec->id; break; case RTE_FLOW_ACTION_TYPE_FLAG: - filter->action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS; + filter->action.report_status = I40E_FDIR_NO_REPORT_STATUS; break; case RTE_FLOW_ACTION_TYPE_END: return 0; @@ -2912,7 +2901,7 @@ i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev, struct rte_flow_error *error, union i40e_filter_t *filter) { - struct rte_eth_fdir_filter *fdir_filter = + struct i40e_fdir_filter_conf *fdir_filter = &filter->fdir_filter; int ret; @@ -3878,7 +3867,7 @@ i40e_flow_create(struct rte_eth_dev *dev, i40e_ethertype_filter_list); break; case RTE_ETH_FILTER_FDIR: - ret = i40e_add_del_fdir_filter(dev, + ret = i40e_flow_add_del_fdir_filter(dev, &cons_filter.fdir_filter, 1); if (ret) goto free_flow; @@ -3928,7 +3917,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, (struct i40e_tunnel_filter *)flow->rule); break; case RTE_ETH_FILTER_FDIR: - ret = i40e_add_del_fdir_filter(dev, + ret = i40e_flow_add_del_fdir_filter(dev, &((struct i40e_fdir_filter *)flow->rule)->fdir, 0); break; default: