X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fice%2Fice_fdir_filter.c;h=68af2f2e25204dde319696dec246d70c36920007;hb=dc36bd5dfdeb;hp=80da6ee244e151742c7b5dd17534113a84b4ada5;hpb=efc16c6214152b9cc89906f004718ccf6603c1ce;p=dpdk.git diff --git a/drivers/net/ice/ice_fdir_filter.c b/drivers/net/ice/ice_fdir_filter.c index 80da6ee244..68af2f2e25 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 @@ -32,6 +36,7 @@ ICE_INSET_SCTP_SRC_PORT | ICE_INSET_SCTP_DST_PORT) #define ICE_FDIR_INSET_ETH_IPV6 (\ + ICE_INSET_DMAC | \ ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | ICE_INSET_IPV6_TC | \ ICE_INSET_IPV6_HOP_LIMIT | ICE_INSET_IPV6_NEXT_HDR) @@ -63,16 +68,10 @@ ICE_INSET_TUN_SCTP_SRC_PORT | ICE_INSET_TUN_SCTP_DST_PORT) #define ICE_FDIR_INSET_GTPU_IPV4 (\ - ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) + ICE_INSET_GTPU_TEID) -#define ICE_FDIR_INSET_GTPU_IPV4_TCP (\ - ICE_FDIR_INSET_GTPU_IPV4) - -#define ICE_FDIR_INSET_GTPU_IPV4_UDP (\ - ICE_FDIR_INSET_GTPU_IPV4) - -#define ICE_FDIR_INSET_GTPU_IPV4_UDP (\ - ICE_FDIR_INSET_GTPU_IPV4) +#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[] = { {pattern_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE}, @@ -127,10 +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_ipv4_tcp, - ICE_FDIR_INSET_GTPU_IPV4, ICE_INSET_NONE}, - {pattern_eth_ipv4_gtpu_ipv4_udp, - 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; @@ -139,6 +136,12 @@ static struct ice_flow_parser ice_fdir_parser_comms; static const struct rte_memzone * ice_memzone_reserve(const char *name, uint32_t len, int socket_id) { + const struct rte_memzone *mz; + + mz = rte_memzone_lookup(name); + if (mz) + return mz; + return rte_memzone_reserve_aligned(name, len, socket_id, RTE_MEMZONE_IOVA_CONTIG, ICE_RING_BASE_ALIGN); @@ -158,7 +161,7 @@ ice_fdir_prof_alloc(struct ice_hw *hw) if (!hw->fdir_prof) return -ENOMEM; } - for (ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + for (ptype = ICE_FLTR_PTYPE_NONF_NONE + 1; ptype < ICE_FLTR_PTYPE_MAX; ptype++) { if (!hw->fdir_prof[ptype]) { @@ -171,11 +174,16 @@ ice_fdir_prof_alloc(struct ice_hw *hw) return 0; fail_mem: - for (fltr_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + 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; } @@ -255,8 +263,13 @@ 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; return 0; } @@ -365,6 +378,7 @@ ice_fdir_init_filter_list(struct ice_pf *pf) .hash_func = rte_hash_crc, .hash_func_init_val = 0, .socket_id = rte_socket_id(), + .extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE, }; /* Initialize hash */ @@ -402,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; } /* @@ -479,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, @@ -492,19 +514,23 @@ ice_fdir_setup(struct ice_pf *pf) } pf->fdir.prg_pkt = mz->addr; pf->fdir.dma_addr = mz->iova; + pf->fdir.mz = mz; err = ice_fdir_prof_alloc(hw); if (err) { PMD_DRV_LOG(ERR, "Cannot allocate memory for " "flow director profile."); err = -ENOMEM; - goto fail_mem; + goto fail_prof; } PMD_DRV_LOG(INFO, "FDIR setup successfully, with programming queue %u.", vsi->base_queue); return ICE_SUCCESS; +fail_prof: + rte_memzone_free(pf->fdir.mz); + pf->fdir.mz = NULL; fail_mem: ice_rx_queue_release(pf->fdir.rxq); pf->fdir.rxq = NULL; @@ -522,12 +548,15 @@ ice_fdir_prof_free(struct ice_hw *hw) { enum ice_fltr_ptype ptype; - for (ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + 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 */ @@ -572,7 +601,7 @@ ice_fdir_prof_rm_all(struct ice_pf *pf) { enum ice_fltr_ptype ptype; - for (ptype = ICE_FLTR_PTYPE_NONF_NONE; + for (ptype = ICE_FLTR_PTYPE_NONF_NONE + 1; ptype < ICE_FLTR_PTYPE_MAX; ptype++) { ice_fdir_prof_rm(pf, ptype, false); @@ -596,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."); @@ -618,6 +649,163 @@ ice_fdir_teardown(struct ice_pf *pf) ice_fdir_prof_free(hw); ice_release_vsi(vsi); pf->fdir.fdir_vsi = NULL; + + if (pf->fdir.mz) { + err = rte_memzone_free(pf->fdir.mz); + pf->fdir.mz = NULL; + if (err) + PMD_DRV_LOG(ERR, "Failed to free FDIR memezone."); + } +} + +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 @@ -629,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; @@ -638,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, &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, @@ -677,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; @@ -804,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: @@ -840,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; } @@ -874,8 +1056,10 @@ ice_fdir_init(struct ice_adapter *ad) if (ad->active_pkg_type == ICE_PKG_TYPE_COMMS) parser = &ice_fdir_parser_comms; - else + else if (ad->active_pkg_type == ICE_PKG_TYPE_OS_DEFAULT) parser = &ice_fdir_parser_os; + else + return -EINVAL; return ice_register_parser(parser, ad); } @@ -1320,6 +1504,7 @@ ice_fdir_parse_action(struct ice_adapter *ad, mark_spec = actions->conf; filter->input.fltr_id = mark_spec->id; + filter->input.fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_ONE; break; case RTE_FLOW_ACTION_TYPE_COUNT: counter_num++; @@ -1531,6 +1716,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 || @@ -1562,15 +1752,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; @@ -1578,6 +1764,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 || @@ -1604,15 +1795,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.src_port; - filter->input.ip.v6.dst_port = udp_spec->hdr.dst_port; - flow_type = - ICE_FLTR_PTYPE_NONF_IPV6_UDP; + filter->input.ip.v6.dst_port = + udp_spec->hdr.src_port; } } break; @@ -1620,6 +1807,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) { @@ -1645,15 +1837,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; @@ -1695,6 +1883,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; @@ -1707,8 +1897,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, @@ -1751,23 +1939,25 @@ ice_fdir_parse(struct ice_adapter *ad, ret = ice_fdir_parse_pattern(ad, pattern, error, filter); if (ret) - return ret; + goto error; input_set = filter->input_set; if (!input_set || input_set & ~item->input_set_mask) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_SPEC, pattern, "Invalid input set"); - return -rte_errno; + ret = -rte_errno; + goto error; } ret = ice_fdir_parse_action(ad, actions, error, filter); if (ret) - return ret; + goto error; *meta = filter; - - return 0; +error: + rte_free(item); + return ret; } static struct ice_flow_parser ice_fdir_parser_os = {