X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fnet%2Fice%2Fice_fdir_filter.c;h=fa87074556fa1ba8adbefcad6129126800a2f290;hb=a57fdc78b68dd8e09de02596945f4dd3399f1814;hp=e3b633e232197e2ca5267e1fd6861ba9974b7460;hpb=01af3d0a416130e91c159147f590f9d07da4e767;p=dpdk.git diff --git a/drivers/net/ice/ice_fdir_filter.c b/drivers/net/ice/ice_fdir_filter.c index e3b633e232..fa87074556 100644 --- a/drivers/net/ice/ice_fdir_filter.c +++ b/drivers/net/ice/ice_fdir_filter.c @@ -1,3 +1,7 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + #include #include #include @@ -64,6 +68,9 @@ ICE_INSET_TUN_SCTP_SRC_PORT | ICE_INSET_TUN_SCTP_DST_PORT) #define ICE_FDIR_INSET_GTPU_IPV4 (\ + ICE_INSET_GTPU_TEID) + +#define ICE_FDIR_INSET_GTPU_EH_IPV4 (\ ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) static struct ice_pattern_match_item ice_fdir_pattern_os[] = { @@ -119,6 +126,8 @@ static struct ice_pattern_match_item ice_fdir_pattern_comms[] = { {pattern_eth_ipv4_udp_vxlan_eth_ipv4_sctp, ICE_FDIR_INSET_VXLAN_IPV4_SCTP, ICE_INSET_NONE}, {pattern_eth_ipv4_gtpu_ipv4, ICE_FDIR_INSET_GTPU_IPV4, ICE_INSET_NONE}, + {pattern_eth_ipv4_gtpu_eh_ipv4, + ICE_FDIR_INSET_GTPU_EH_IPV4, ICE_INSET_NONE}, }; static struct ice_flow_parser ice_fdir_parser_os; @@ -167,9 +176,14 @@ ice_fdir_prof_alloc(struct ice_hw *hw) fail_mem: for (fltr_ptype = ICE_FLTR_PTYPE_NONF_NONE + 1; fltr_ptype < ptype; - fltr_ptype++) + fltr_ptype++) { rte_free(hw->fdir_prof[fltr_ptype]); + hw->fdir_prof[fltr_ptype] = NULL; + } + rte_free(hw->fdir_prof); + hw->fdir_prof = NULL; + return -ENOMEM; } @@ -249,8 +263,10 @@ ice_fdir_counter_release(struct ice_pf *pf) &fdir_info->counter; uint8_t i; - for (i = 0; i < container->index_free; i++) + for (i = 0; i < container->index_free; i++) { rte_free(container->pools[i]); + container->pools[i] = NULL; + } TAILQ_INIT(&container->pool_list); container->index_free = 0; @@ -400,6 +416,9 @@ ice_fdir_release_filter_list(struct ice_pf *pf) rte_free(fdir_info->hash_map); if (fdir_info->hash_table) rte_hash_free(fdir_info->hash_table); + + fdir_info->hash_map = NULL; + fdir_info->hash_table = NULL; } /* @@ -477,6 +496,11 @@ ice_fdir_setup(struct ice_pf *pf) goto fail_mem; } + /* Enable FDIR MSIX interrupt */ + vsi->nb_used_qps = 1; + ice_vsi_queues_bind_intr(vsi); + ice_vsi_enable_queues_intr(vsi); + /* reserve memory for the fdir programming packet */ snprintf(z_name, sizeof(z_name), "ICE_%s_%d", ICE_FDIR_MZ_NAME, @@ -526,10 +550,13 @@ ice_fdir_prof_free(struct ice_hw *hw) for (ptype = ICE_FLTR_PTYPE_NONF_NONE + 1; ptype < ICE_FLTR_PTYPE_MAX; - ptype++) + ptype++) { rte_free(hw->fdir_prof[ptype]); + hw->fdir_prof[ptype] = NULL; + } rte_free(hw->fdir_prof); + hw->fdir_prof = NULL; } /* Remove a profile for some filter type */ @@ -598,6 +625,8 @@ ice_fdir_teardown(struct ice_pf *pf) if (!vsi) return; + ice_vsi_disable_queues_intr(vsi); + err = ice_fdir_tx_queue_stop(eth_dev, pf->fdir.txq->queue_id); if (err) PMD_DRV_LOG(ERR, "Failed to stop TX queue."); @@ -629,6 +658,156 @@ ice_fdir_teardown(struct ice_pf *pf) } } +static int +ice_fdir_cur_prof_conflict(struct ice_pf *pf, + enum ice_fltr_ptype ptype, + struct ice_flow_seg_info *seg, + bool is_tunnel) +{ + struct ice_hw *hw = ICE_PF_TO_HW(pf); + struct ice_flow_seg_info *ori_seg; + struct ice_fd_hw_prof *hw_prof; + + hw_prof = hw->fdir_prof[ptype]; + ori_seg = hw_prof->fdir_seg[is_tunnel]; + + /* profile does not exist */ + if (!ori_seg) + return 0; + + /* if no input set conflict, return -EEXIST */ + if ((!is_tunnel && !memcmp(ori_seg, seg, sizeof(*seg))) || + (is_tunnel && !memcmp(&ori_seg[1], &seg[1], sizeof(*seg)))) { + PMD_DRV_LOG(DEBUG, "Profile already exists for flow type %d.", + ptype); + return -EEXIST; + } + + /* a rule with input set conflict already exist, so give up */ + if (pf->fdir_fltr_cnt[ptype][is_tunnel]) { + PMD_DRV_LOG(DEBUG, "Failed to create profile for flow type %d due to conflict with existing rule.", + ptype); + return -EINVAL; + } + + /* it's safe to delete an empty profile */ + ice_fdir_prof_rm(pf, ptype, is_tunnel); + return 0; +} + +static bool +ice_fdir_prof_resolve_conflict(struct ice_pf *pf, + enum ice_fltr_ptype ptype, + bool is_tunnel) +{ + struct ice_hw *hw = ICE_PF_TO_HW(pf); + struct ice_fd_hw_prof *hw_prof; + struct ice_flow_seg_info *seg; + + hw_prof = hw->fdir_prof[ptype]; + seg = hw_prof->fdir_seg[is_tunnel]; + + /* profile does not exist */ + if (!seg) + return true; + + /* profile exists and rule exists, fail to resolve the conflict */ + if (pf->fdir_fltr_cnt[ptype][is_tunnel] != 0) + return false; + + /* it's safe to delete an empty profile */ + ice_fdir_prof_rm(pf, ptype, is_tunnel); + + return true; +} + +static int +ice_fdir_cross_prof_conflict(struct ice_pf *pf, + enum ice_fltr_ptype ptype, + bool is_tunnel) +{ + enum ice_fltr_ptype cflct_ptype; + + switch (ptype) { + /* IPv4 */ + case ICE_FLTR_PTYPE_NONF_IPV4_UDP: + case ICE_FLTR_PTYPE_NONF_IPV4_TCP: + case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_TCP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_SCTP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + /* IPv4 GTPU */ + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP: + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP: + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + /* IPv6 */ + case ICE_FLTR_PTYPE_NONF_IPV6_UDP: + case ICE_FLTR_PTYPE_NONF_IPV6_TCP: + case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV6_UDP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV6_TCP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV6_SCTP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + default: + break; + } + return 0; +err: + PMD_DRV_LOG(DEBUG, "Failed to create profile for flow type %d due to conflict with existing rule of flow type %d.", + ptype, cflct_ptype); + return -EINVAL; +} + static int ice_fdir_hw_tbl_conf(struct ice_pf *pf, struct ice_vsi *vsi, struct ice_vsi *ctrl_vsi, @@ -638,7 +817,6 @@ ice_fdir_hw_tbl_conf(struct ice_pf *pf, struct ice_vsi *vsi, { struct ice_hw *hw = ICE_PF_TO_HW(pf); enum ice_flow_dir dir = ICE_FLOW_RX; - struct ice_flow_seg_info *ori_seg; struct ice_fd_hw_prof *hw_prof; struct ice_flow_prof *prof; uint64_t entry_1 = 0; @@ -647,22 +825,15 @@ ice_fdir_hw_tbl_conf(struct ice_pf *pf, struct ice_vsi *vsi, int ret; uint64_t prof_id; - hw_prof = hw->fdir_prof[ptype]; - ori_seg = hw_prof->fdir_seg[is_tunnel]; - if (ori_seg) { - if (!is_tunnel) { - if (!memcmp(ori_seg, seg, sizeof(*seg))) - return -EAGAIN; - } else { - if (!memcmp(&ori_seg[1], &seg[1], sizeof(*seg))) - return -EAGAIN; - } - - if (pf->fdir_fltr_cnt[ptype][is_tunnel]) - return -EINVAL; + /* check if have input set conflict on current profile. */ + ret = ice_fdir_cur_prof_conflict(pf, ptype, seg, is_tunnel); + if (ret) + return ret; - ice_fdir_prof_rm(pf, ptype, is_tunnel); - } + /* check if the profile is conflict with other profile. */ + ret = ice_fdir_cross_prof_conflict(pf, ptype, is_tunnel); + if (ret) + return ret; prof_id = ptype + is_tunnel * ICE_FLTR_PTYPE_MAX; ret = ice_flow_add_prof(hw, ICE_BLK_FD, dir, prof_id, seg, @@ -686,6 +857,7 @@ ice_fdir_hw_tbl_conf(struct ice_pf *pf, struct ice_vsi *vsi, goto err_add_entry; } + hw_prof = hw->fdir_prof[ptype]; pf->hw_prof_cnt[ptype][is_tunnel] = 0; hw_prof->cnt = 0; hw_prof->fdir_seg[is_tunnel] = seg; @@ -813,6 +985,7 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP: case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | + ICE_FLOW_SEG_HDR_GTPU_IP | ICE_FLOW_SEG_HDR_IPV4); break; default: @@ -849,7 +1022,7 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, rte_free(seg); if (is_tunnel) rte_free(seg_tun); - return (ret == -EAGAIN) ? 0 : ret; + return (ret == -EEXIST) ? 0 : ret; } else { return ret; } @@ -1542,6 +1715,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, tcp_spec = item->spec; tcp_mask = item->mask; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP; + if (tcp_spec && tcp_mask) { /* Check TCP mask and update input set */ if (tcp_mask->hdr.sent_seq || @@ -1573,15 +1751,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, tcp_spec->hdr.src_port; filter->input.ip.v4.src_port = tcp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV4_TCP; } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { filter->input.ip.v6.dst_port = tcp_spec->hdr.src_port; filter->input.ip.v6.src_port = tcp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV6_TCP; } } break; @@ -1589,6 +1763,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, udp_spec = item->spec; udp_mask = item->mask; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP; + if (udp_spec && udp_mask) { /* Check UDP mask and update input set*/ if (udp_mask->hdr.dgram_len || @@ -1615,15 +1794,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, udp_spec->hdr.src_port; filter->input.ip.v4.src_port = udp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV4_UDP; } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { filter->input.ip.v6.src_port = udp_spec->hdr.dst_port; filter->input.ip.v6.dst_port = udp_spec->hdr.src_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV6_UDP; } } break; @@ -1631,6 +1806,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, sctp_spec = item->spec; sctp_mask = item->mask; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_SCTP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_SCTP; + if (sctp_spec && sctp_mask) { /* Check SCTP mask and update input set */ if (sctp_mask->hdr.cksum) { @@ -1656,15 +1836,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, sctp_spec->hdr.src_port; filter->input.ip.v4.src_port = sctp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV4_SCTP; } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { filter->input.ip.v6.dst_port = sctp_spec->hdr.src_port; filter->input.ip.v6.src_port = sctp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV6_SCTP; } } break; @@ -1706,6 +1882,8 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, filter->input.gtpu_data.teid = gtp_spec->teid; } + + tunnel_type = ICE_FDIR_TUNNEL_TYPE_GTPU; break; case RTE_FLOW_ITEM_TYPE_GTP_PSC: gtp_psc_spec = item->spec; @@ -1718,8 +1896,6 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, filter->input.gtpu_data.qfi = gtp_psc_spec->qfi; } - - tunnel_type = ICE_FDIR_TUNNEL_TYPE_GTPU; break; default: rte_flow_error_set(error, EINVAL,