X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fice%2Fice_fdir_filter.c;h=0982478febf8696362b68a7aaa4419e9a78ca9b8;hb=531d2555c8a644030f1ee7d3c9edf1db9c35d6ef;hp=1b6101ec6b7a25b6125f3f35e60d52b85dc46e50;hpb=1a2fc1799f09212e79652b347529cd8d95e99523;p=dpdk.git diff --git a/drivers/net/ice/ice_fdir_filter.c b/drivers/net/ice/ice_fdir_filter.c index 1b6101ec6b..0982478feb 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 @@ -14,10 +18,13 @@ #define ICE_FDIR_MAX_QREGION_SIZE 128 +#define ICE_FDIR_INSET_ETH (\ + ICE_INSET_DMAC | ICE_INSET_SMAC | ICE_INSET_ETHERTYPE) + #define ICE_FDIR_INSET_ETH_IPV4 (\ - ICE_INSET_DMAC | \ + ICE_FDIR_INSET_ETH | \ ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | ICE_INSET_IPV4_TOS | \ - ICE_INSET_IPV4_TTL | ICE_INSET_IPV4_PROTO) + ICE_INSET_IPV4_TTL | ICE_INSET_IPV4_PROTO | ICE_INSET_IPV4_PKID) #define ICE_FDIR_INSET_ETH_IPV4_UDP (\ ICE_FDIR_INSET_ETH_IPV4 | \ @@ -32,8 +39,10 @@ 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) + ICE_INSET_IPV6_HOP_LIMIT | ICE_INSET_IPV6_NEXT_HDR | \ + ICE_INSET_IPV6_PKID) #define ICE_FDIR_INSET_ETH_IPV6_UDP (\ ICE_FDIR_INSET_ETH_IPV6 | \ @@ -47,22 +56,101 @@ ICE_FDIR_INSET_ETH_IPV6 | \ ICE_INSET_SCTP_SRC_PORT | ICE_INSET_SCTP_DST_PORT) -static struct ice_pattern_match_item ice_fdir_pattern[] = { - {pattern_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE}, - {pattern_eth_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv4_tcp, ICE_FDIR_INSET_ETH_IPV4_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv4_sctp, ICE_FDIR_INSET_ETH_IPV4_SCTP, ICE_INSET_NONE}, - {pattern_eth_ipv6, ICE_FDIR_INSET_ETH_IPV6, ICE_INSET_NONE}, - {pattern_eth_ipv6_udp, ICE_FDIR_INSET_ETH_IPV6_UDP, ICE_INSET_NONE}, - {pattern_eth_ipv6_tcp, ICE_FDIR_INSET_ETH_IPV6_TCP, ICE_INSET_NONE}, - {pattern_eth_ipv6_sctp, ICE_FDIR_INSET_ETH_IPV6_SCTP, ICE_INSET_NONE}, +#define ICE_FDIR_INSET_IPV4 (\ + ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | \ + ICE_INSET_IPV4_PKID) + +#define ICE_FDIR_INSET_IPV4_TCP (\ + ICE_FDIR_INSET_IPV4 | \ + ICE_INSET_TCP_SRC_PORT | ICE_INSET_TCP_DST_PORT) + +#define ICE_FDIR_INSET_IPV4_UDP (\ + ICE_FDIR_INSET_IPV4 | \ + ICE_INSET_UDP_SRC_PORT | ICE_INSET_UDP_DST_PORT) + +#define ICE_FDIR_INSET_IPV4_SCTP (\ + ICE_FDIR_INSET_IPV4 | \ + ICE_INSET_SCTP_SRC_PORT | ICE_INSET_SCTP_DST_PORT) + +#define ICE_FDIR_INSET_ETH_IPV4_VXLAN (\ + ICE_FDIR_INSET_ETH | ICE_FDIR_INSET_ETH_IPV4 | \ + ICE_INSET_VXLAN_VNI) + +#define ICE_FDIR_INSET_IPV4_GTPU (\ + ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | ICE_INSET_GTPU_TEID) + +#define ICE_FDIR_INSET_IPV4_GTPU_EH (\ + ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | \ + ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) + +#define ICE_FDIR_INSET_IPV6_GTPU (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | ICE_INSET_GTPU_TEID) + +#define ICE_FDIR_INSET_IPV6_GTPU_EH (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | \ + ICE_INSET_GTPU_TEID | ICE_INSET_GTPU_QFI) + +#define ICE_FDIR_INSET_IPV4_ESP (\ + ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | \ + ICE_INSET_ESP_SPI) + +#define ICE_FDIR_INSET_IPV6_ESP (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | \ + ICE_INSET_ESP_SPI) + +#define ICE_FDIR_INSET_IPV4_NATT_ESP (\ + ICE_INSET_IPV4_SRC | ICE_INSET_IPV4_DST | \ + ICE_INSET_NAT_T_ESP_SPI) + +#define ICE_FDIR_INSET_IPV6_NATT_ESP (\ + ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | \ + ICE_INSET_NAT_T_ESP_SPI) + +static struct ice_pattern_match_item ice_fdir_pattern_list[] = { + {pattern_raw, ICE_INSET_NONE, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_ethertype, ICE_FDIR_INSET_ETH, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_UDP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_tcp, ICE_FDIR_INSET_ETH_IPV4_TCP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_sctp, ICE_FDIR_INSET_ETH_IPV4_SCTP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6, ICE_FDIR_INSET_ETH_IPV6, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_frag_ext, ICE_FDIR_INSET_ETH_IPV6, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_udp, ICE_FDIR_INSET_ETH_IPV6_UDP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_tcp, ICE_FDIR_INSET_ETH_IPV6_TCP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_sctp, ICE_FDIR_INSET_ETH_IPV6_SCTP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_esp, ICE_FDIR_INSET_IPV4_ESP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_esp, ICE_FDIR_INSET_IPV4_NATT_ESP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_esp, ICE_FDIR_INSET_IPV6_ESP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv6_udp_esp, ICE_FDIR_INSET_IPV6_NATT_ESP, ICE_INSET_NONE, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_ipv4, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_IPV4, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_IPV4_UDP, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_ipv4_tcp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_IPV4_TCP, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_ipv4_sctp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_IPV4_SCTP, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_eth_ipv4, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_ETH_IPV4, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_eth_ipv4_udp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_ETH_IPV4_UDP, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_eth_ipv4_tcp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_ETH_IPV4_TCP, ICE_INSET_NONE}, + {pattern_eth_ipv4_udp_vxlan_eth_ipv4_sctp, ICE_FDIR_INSET_ETH_IPV4_VXLAN, ICE_FDIR_INSET_ETH_IPV4_SCTP, ICE_INSET_NONE}, + /* duplicated GTPU input set in 3rd column to align with shared code behavior. Ideally, only put GTPU field in 2nd column. */ + {pattern_eth_ipv4_gtpu, ICE_FDIR_INSET_IPV4_GTPU, ICE_FDIR_INSET_IPV4_GTPU, ICE_INSET_NONE}, + {pattern_eth_ipv4_gtpu_eh, ICE_FDIR_INSET_IPV4_GTPU_EH, ICE_FDIR_INSET_IPV4_GTPU_EH, ICE_INSET_NONE}, + {pattern_eth_ipv6_gtpu, ICE_FDIR_INSET_IPV6_GTPU, ICE_FDIR_INSET_IPV6_GTPU, ICE_INSET_NONE}, + {pattern_eth_ipv6_gtpu_eh, ICE_FDIR_INSET_IPV6_GTPU_EH, ICE_FDIR_INSET_IPV6_GTPU_EH, ICE_INSET_NONE}, }; static struct ice_flow_parser ice_fdir_parser; +static int +ice_fdir_is_tunnel_profile(enum ice_fdir_tunnel_type tunnel_type); + 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); @@ -82,7 +170,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]) { @@ -95,11 +183,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; } @@ -179,8 +272,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; } @@ -277,7 +375,7 @@ ice_fdir_counter_free(__rte_unused struct ice_pf *pf, static int ice_fdir_init_filter_list(struct ice_pf *pf) { - struct rte_eth_dev *dev = pf->adapter->eth_dev; + struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id]; struct ice_fdir_info *fdir_info = &pf->fdir; char fdir_hash_name[RTE_HASH_NAMESIZE]; int ret; @@ -289,6 +387,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 */ @@ -322,10 +421,11 @@ ice_fdir_release_filter_list(struct ice_pf *pf) { struct ice_fdir_info *fdir_info = &pf->fdir; - if (fdir_info->hash_map) - rte_free(fdir_info->hash_map); - if (fdir_info->hash_table) - rte_hash_free(fdir_info->hash_table); + rte_free(fdir_info->hash_map); + rte_hash_free(fdir_info->hash_table); + + fdir_info->hash_map = NULL; + fdir_info->hash_table = NULL; } /* @@ -335,7 +435,7 @@ ice_fdir_release_filter_list(struct ice_pf *pf) static int ice_fdir_setup(struct ice_pf *pf) { - struct rte_eth_dev *eth_dev = pf->adapter->eth_dev; + struct rte_eth_dev *eth_dev = &rte_eth_devices[pf->dev_data->port_id]; struct ice_hw *hw = ICE_PF_TO_HW(pf); const struct rte_memzone *mz = NULL; char z_name[RTE_MEMZONE_NAMESIZE]; @@ -403,6 +503,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, @@ -416,19 +521,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; @@ -446,12 +555,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 */ @@ -476,7 +588,7 @@ ice_fdir_prof_rm(struct ice_pf *pf, enum ice_fltr_ptype ptype, bool is_tunnel) hw_prof->vsi_h[i]); ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, ptype); - ice_flow_rem_entry(hw, + ice_flow_rem_entry(hw, ICE_BLK_FD, hw_prof->entry_h[i][is_tunnel]); hw_prof->entry_h[i][is_tunnel] = 0; } @@ -496,7 +608,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); @@ -511,7 +623,7 @@ ice_fdir_prof_rm_all(struct ice_pf *pf) static void ice_fdir_teardown(struct ice_pf *pf) { - struct rte_eth_dev *eth_dev = pf->adapter->eth_dev; + struct rte_eth_dev *eth_dev = &rte_eth_devices[pf->dev_data->port_id]; struct ice_hw *hw = ICE_PF_TO_HW(pf); struct ice_vsi *vsi; int err; @@ -520,6 +632,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."); @@ -542,6 +656,185 @@ 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_UDP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP; + 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; + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_UDP: + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_TCP: + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_SCTP: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_OTHER; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + break; + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_OTHER: + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_UDP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_TCP; + if (!ice_fdir_prof_resolve_conflict + (pf, cflct_ptype, is_tunnel)) + goto err; + cflct_ptype = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_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 @@ -553,7 +846,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; @@ -562,22 +854,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, @@ -601,6 +886,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; @@ -616,7 +902,7 @@ ice_fdir_hw_tbl_conf(struct ice_pf *pf, struct ice_vsi *vsi, err_add_entry: vsi_num = ice_get_hw_vsi_num(hw, vsi->idx); ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof_id); - ice_flow_rem_entry(hw, entry_1); + ice_flow_rem_entry(hw, ICE_BLK_FD, entry_1); err_add_prof: ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id); @@ -634,22 +920,38 @@ ice_fdir_input_set_parse(uint64_t inset, enum ice_flow_field *field) }; static const struct ice_inset_map ice_inset_map[] = { {ICE_INSET_DMAC, ICE_FLOW_FIELD_IDX_ETH_DA}, + {ICE_INSET_ETHERTYPE, ICE_FLOW_FIELD_IDX_ETH_TYPE}, {ICE_INSET_IPV4_SRC, ICE_FLOW_FIELD_IDX_IPV4_SA}, {ICE_INSET_IPV4_DST, ICE_FLOW_FIELD_IDX_IPV4_DA}, {ICE_INSET_IPV4_TOS, ICE_FLOW_FIELD_IDX_IPV4_DSCP}, {ICE_INSET_IPV4_TTL, ICE_FLOW_FIELD_IDX_IPV4_TTL}, {ICE_INSET_IPV4_PROTO, ICE_FLOW_FIELD_IDX_IPV4_PROT}, + {ICE_INSET_IPV4_PKID, ICE_FLOW_FIELD_IDX_IPV4_ID}, {ICE_INSET_IPV6_SRC, ICE_FLOW_FIELD_IDX_IPV6_SA}, {ICE_INSET_IPV6_DST, ICE_FLOW_FIELD_IDX_IPV6_DA}, {ICE_INSET_IPV6_TC, ICE_FLOW_FIELD_IDX_IPV6_DSCP}, {ICE_INSET_IPV6_NEXT_HDR, ICE_FLOW_FIELD_IDX_IPV6_PROT}, {ICE_INSET_IPV6_HOP_LIMIT, ICE_FLOW_FIELD_IDX_IPV6_TTL}, + {ICE_INSET_IPV6_PKID, ICE_FLOW_FIELD_IDX_IPV6_ID}, {ICE_INSET_TCP_SRC_PORT, ICE_FLOW_FIELD_IDX_TCP_SRC_PORT}, {ICE_INSET_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT}, {ICE_INSET_UDP_SRC_PORT, ICE_FLOW_FIELD_IDX_UDP_SRC_PORT}, {ICE_INSET_UDP_DST_PORT, ICE_FLOW_FIELD_IDX_UDP_DST_PORT}, {ICE_INSET_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT}, {ICE_INSET_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT}, + {ICE_INSET_IPV4_SRC, ICE_FLOW_FIELD_IDX_IPV4_SA}, + {ICE_INSET_IPV4_DST, ICE_FLOW_FIELD_IDX_IPV4_DA}, + {ICE_INSET_TCP_SRC_PORT, ICE_FLOW_FIELD_IDX_TCP_SRC_PORT}, + {ICE_INSET_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT}, + {ICE_INSET_UDP_SRC_PORT, ICE_FLOW_FIELD_IDX_UDP_SRC_PORT}, + {ICE_INSET_UDP_DST_PORT, ICE_FLOW_FIELD_IDX_UDP_DST_PORT}, + {ICE_INSET_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT}, + {ICE_INSET_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT}, + {ICE_INSET_GTPU_TEID, ICE_FLOW_FIELD_IDX_GTPU_IP_TEID}, + {ICE_INSET_GTPU_QFI, ICE_FLOW_FIELD_IDX_GTPU_EH_QFI}, + {ICE_INSET_VXLAN_VNI, ICE_FLOW_FIELD_IDX_VXLAN_VNI}, + {ICE_INSET_ESP_SPI, ICE_FLOW_FIELD_IDX_ESP_SPI}, + {ICE_INSET_NAT_T_ESP_SPI, ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI}, }; for (i = 0, j = 0; i < RTE_DIM(ice_inset_map); i++) { @@ -659,95 +961,168 @@ ice_fdir_input_set_parse(uint64_t inset, enum ice_flow_field *field) } } -static int -ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, - uint64_t input_set, bool is_tunnel) +static void +ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg) { - struct ice_flow_seg_info *seg; - struct ice_flow_seg_info *seg_tun = NULL; - enum ice_flow_field field[ICE_FLOW_FIELD_IDX_MAX]; - int i, ret; - - if (!input_set) - return -EINVAL; - - seg = (struct ice_flow_seg_info *) - ice_malloc(hw, sizeof(*seg)); - if (!seg) { - PMD_DRV_LOG(ERR, "No memory can be allocated"); - return -ENOMEM; - } - - for (i = 0; i < ICE_FLOW_FIELD_IDX_MAX; i++) - field[i] = ICE_FLOW_FIELD_IDX_MAX; - ice_fdir_input_set_parse(input_set, field); - switch (flow) { case ICE_FLTR_PTYPE_NONF_IPV4_UDP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | - ICE_FLOW_SEG_HDR_IPV4); + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV4_TCP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | - ICE_FLOW_SEG_HDR_IPV4); + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | - ICE_FLOW_SEG_HDR_IPV4); + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: - ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4); + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_FRAG_IPV4: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_FRAG); break; case ICE_FLTR_PTYPE_NONF_IPV6_UDP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | - ICE_FLOW_SEG_HDR_IPV6); + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV6_TCP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | - ICE_FLOW_SEG_HDR_IPV6); + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | - ICE_FLOW_SEG_HDR_IPV6); + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: - ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6); + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_FRAG_IPV6: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_FRAG); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_UDP: + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_TCP: + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_SCTP: + break; + case ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_OTHER: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_EH: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | + ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_GTPU: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_GTPU_EH: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | + ICE_FLOW_SEG_HDR_GTPU_IP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NON_IP_L2: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_ESP: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_ESP: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | + ICE_FLOW_SEG_HDR_IPV4 | + ICE_FLOW_SEG_HDR_IPV_OTHER); + break; + case ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP: + ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | + ICE_FLOW_SEG_HDR_IPV6 | + ICE_FLOW_SEG_HDR_IPV_OTHER); break; default: PMD_DRV_LOG(ERR, "not supported filter type."); break; } +} + +static int +ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow, + uint64_t inner_input_set, uint64_t outer_input_set, + enum ice_fdir_tunnel_type ttype) +{ + struct ice_flow_seg_info *seg; + struct ice_flow_seg_info *seg_tun = NULL; + enum ice_flow_field field[ICE_FLOW_FIELD_IDX_MAX]; + uint64_t input_set; + bool is_tunnel; + int k, i, ret = 0; + + if (!(inner_input_set | outer_input_set)) + return -EINVAL; - for (i = 0; field[i] != ICE_FLOW_FIELD_IDX_MAX; i++) { - ice_flow_set_fld(seg, field[i], - ICE_FLOW_FLD_OFF_INVAL, - ICE_FLOW_FLD_OFF_INVAL, - ICE_FLOW_FLD_OFF_INVAL, false); + seg_tun = (struct ice_flow_seg_info *) + ice_malloc(hw, sizeof(*seg_tun) * ICE_FD_HW_SEG_MAX); + if (!seg_tun) { + PMD_DRV_LOG(ERR, "No memory can be allocated"); + return -ENOMEM; } - if (!is_tunnel) { - ret = ice_fdir_hw_tbl_conf(pf, pf->main_vsi, pf->fdir.fdir_vsi, - seg, flow, false); - } else { - seg_tun = (struct ice_flow_seg_info *) - ice_malloc(hw, sizeof(*seg) * ICE_FD_HW_SEG_MAX); - if (!seg_tun) { - PMD_DRV_LOG(ERR, "No memory can be allocated"); - rte_free(seg); - return -ENOMEM; + /* use seg_tun[1] to record tunnel inner part */ + for (k = 0; k <= ICE_FD_HW_SEG_TUN; k++) { + seg = &seg_tun[k]; + input_set = (k == ICE_FD_HW_SEG_TUN) ? inner_input_set : outer_input_set; + if (input_set == 0) + continue; + + for (i = 0; i < ICE_FLOW_FIELD_IDX_MAX; i++) + field[i] = ICE_FLOW_FIELD_IDX_MAX; + + ice_fdir_input_set_parse(input_set, field); + + ice_fdir_input_set_hdrs(flow, seg); + + for (i = 0; field[i] != ICE_FLOW_FIELD_IDX_MAX; i++) { + ice_flow_set_fld(seg, field[i], + ICE_FLOW_FLD_OFF_INVAL, + ICE_FLOW_FLD_OFF_INVAL, + ICE_FLOW_FLD_OFF_INVAL, false); } - rte_memcpy(&seg_tun[1], seg, sizeof(*seg)); - ret = ice_fdir_hw_tbl_conf(pf, pf->main_vsi, pf->fdir.fdir_vsi, - seg_tun, flow, true); } + is_tunnel = ice_fdir_is_tunnel_profile(ttype); + + ret = ice_fdir_hw_tbl_conf(pf, pf->main_vsi, pf->fdir.fdir_vsi, + seg_tun, flow, is_tunnel); + if (!ret) { return ret; } else if (ret < 0) { - rte_free(seg); - if (is_tunnel) - rte_free(seg_tun); - return (ret == -EAGAIN) ? 0 : ret; + rte_free(seg_tun); + return (ret == -EEXIST) ? 0 : ret; } else { return ret; } @@ -772,25 +1147,64 @@ static int ice_fdir_init(struct ice_adapter *ad) { struct ice_pf *pf = &ad->pf; + struct ice_flow_parser *parser; int ret; + if (ad->hw.dcf_enabled) + return 0; + ret = ice_fdir_setup(pf); if (ret) return ret; - return ice_register_parser(&ice_fdir_parser, ad); + parser = &ice_fdir_parser; + + return ice_register_parser(parser, ad); } static void ice_fdir_uninit(struct ice_adapter *ad) { + struct ice_flow_parser *parser; struct ice_pf *pf = &ad->pf; - ice_unregister_parser(&ice_fdir_parser, ad); + if (ad->hw.dcf_enabled) + return; + + parser = &ice_fdir_parser; + + ice_unregister_parser(parser, ad); ice_fdir_teardown(pf); } +static int +ice_fdir_is_tunnel_profile(enum ice_fdir_tunnel_type tunnel_type) +{ + if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN) + return 1; + else + return 0; +} + +static int +ice_fdir_add_del_raw(struct ice_pf *pf, + struct ice_fdir_filter_conf *filter, + bool add) +{ + struct ice_hw *hw = ICE_PF_TO_HW(pf); + + unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + rte_memcpy(pkt, filter->pkt_buf, filter->pkt_len); + + struct ice_fltr_desc desc; + memset(&desc, 0, sizeof(desc)); + filter->input.comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW; + ice_fdir_get_prgm_desc(hw, &filter->input, &desc, add); + + return ice_fdir_programming(pf, &desc); +} + static int ice_fdir_add_del_filter(struct ice_pf *pf, struct ice_fdir_filter_conf *filter, @@ -799,15 +1213,19 @@ ice_fdir_add_del_filter(struct ice_pf *pf, struct ice_fltr_desc desc; struct ice_hw *hw = ICE_PF_TO_HW(pf); unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + bool is_tun; int ret; filter->input.dest_vsi = pf->main_vsi->idx; memset(&desc, 0, sizeof(desc)); + filter->input.comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW; ice_fdir_get_prgm_desc(hw, &filter->input, &desc, add); + is_tun = ice_fdir_is_tunnel_profile(filter->tunnel_type); + memset(pkt, 0, ICE_FDIR_PKT_LEN); - ret = ice_fdir_get_prgm_pkt(&filter->input, pkt, false); + ret = ice_fdir_get_gen_prgm_pkt(hw, &filter->input, pkt, false, is_tun); if (ret) { PMD_DRV_LOG(ERR, "Generate dummy packet failed"); return -EINVAL; @@ -828,6 +1246,11 @@ ice_fdir_extract_fltr_key(struct ice_fdir_fltr_pattern *key, rte_memcpy(&key->mask, &input->mask, sizeof(key->mask)); rte_memcpy(&key->ext_data, &input->ext_data, sizeof(key->ext_data)); rte_memcpy(&key->ext_mask, &input->ext_mask, sizeof(key->ext_mask)); + + rte_memcpy(&key->gtpu_data, &input->gtpu_data, sizeof(key->gtpu_data)); + rte_memcpy(&key->gtpu_mask, &input->gtpu_mask, sizeof(key->gtpu_mask)); + + key->tunnel_type = filter->tunnel_type; } /* Check if there exists the flow director filter */ @@ -895,7 +1318,70 @@ ice_fdir_create_filter(struct ice_adapter *ad, struct ice_fdir_info *fdir_info = &pf->fdir; struct ice_fdir_filter_conf *entry, *node; struct ice_fdir_fltr_pattern key; + bool is_tun; int ret; + int i; + + if (filter->parser_ena) { + struct ice_hw *hw = ICE_PF_TO_HW(pf); + + int id = ice_find_first_bit(filter->prof->ptypes, UINT16_MAX); + int ptg = hw->blk[ICE_BLK_FD].xlt1.t[id]; + u16 ctrl_vsi = pf->fdir.fdir_vsi->idx; + u16 main_vsi = pf->main_vsi->idx; + bool fv_found = false; + + struct ice_fdir_prof_info *pi = &ad->fdir_prof_info[ptg]; + if (pi->fdir_actived_cnt != 0) { + for (i = 0; i < ICE_MAX_FV_WORDS; i++) + if (pi->prof.fv[i].proto_id != + filter->prof->fv[i].proto_id || + pi->prof.fv[i].offset != + filter->prof->fv[i].offset || + pi->prof.fv[i].msk != + filter->prof->fv[i].msk) + break; + if (i == ICE_MAX_FV_WORDS) { + fv_found = true; + pi->fdir_actived_cnt++; + } + } + + if (!fv_found) { + ret = ice_flow_set_hw_prof(hw, main_vsi, ctrl_vsi, + filter->prof, ICE_BLK_FD); + if (ret) + goto error; + } + + ret = ice_fdir_add_del_raw(pf, filter, true); + if (ret) + goto error; + + if (!fv_found) { + for (i = 0; i < filter->prof->fv_num; i++) { + pi->prof.fv[i].proto_id = + filter->prof->fv[i].proto_id; + pi->prof.fv[i].offset = + filter->prof->fv[i].offset; + pi->prof.fv[i].msk = filter->prof->fv[i].msk; + } + pi->fdir_actived_cnt = 1; + } + + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 1); + + entry = rte_zmalloc("fdir_entry", sizeof(*entry), 0); + if (!entry) + goto error; + + rte_memcpy(entry, filter, sizeof(*filter)); + + flow->rule = entry; + + return 0; + } ice_fdir_extract_fltr_key(&key, filter); node = ice_fdir_entry_lookup(fdir_info, &key); @@ -914,8 +1400,11 @@ ice_fdir_create_filter(struct ice_adapter *ad, return -rte_errno; } + is_tun = ice_fdir_is_tunnel_profile(filter->tunnel_type); + ret = ice_fdir_input_set_conf(pf, filter->input.flow_type, - filter->input_set, false); + filter->input_set_i, filter->input_set_o, + filter->tunnel_type); if (ret) { rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, @@ -927,9 +1416,7 @@ ice_fdir_create_filter(struct ice_adapter *ad, if (filter->input.cnt_ena) { struct rte_flow_action_count *act_count = &filter->act_count; - filter->counter = ice_fdir_counter_alloc(pf, - act_count->shared, - act_count->id); + filter->counter = ice_fdir_counter_alloc(pf, 0, act_count->id); if (!filter->counter) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -947,6 +1434,9 @@ ice_fdir_create_filter(struct ice_adapter *ad, goto free_counter; } + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 1); + rte_memcpy(entry, filter, sizeof(*entry)); ret = ice_fdir_entry_insert(pf, entry, &key); if (ret) { @@ -957,7 +1447,7 @@ ice_fdir_create_filter(struct ice_adapter *ad, } flow->rule = entry; - ice_fdir_cnt_update(pf, filter->input.flow_type, false, true); + ice_fdir_cnt_update(pf, filter->input.flow_type, is_tun, true); return 0; @@ -970,6 +1460,11 @@ free_counter: free_entry: rte_free(entry); return -rte_errno; + +error: + rte_free(filter->prof); + rte_free(filter->pkt_buf); + return -rte_errno; } static int @@ -981,10 +1476,51 @@ ice_fdir_destroy_filter(struct ice_adapter *ad, struct ice_fdir_info *fdir_info = &pf->fdir; struct ice_fdir_filter_conf *filter, *entry; struct ice_fdir_fltr_pattern key; + bool is_tun; int ret; filter = (struct ice_fdir_filter_conf *)flow->rule; + if (filter->parser_ena) { + struct ice_hw *hw = ICE_PF_TO_HW(pf); + + int id = ice_find_first_bit(filter->prof->ptypes, UINT16_MAX); + int ptg = hw->blk[ICE_BLK_FD].xlt1.t[id]; + u16 ctrl_vsi = pf->fdir.fdir_vsi->idx; + u16 main_vsi = pf->main_vsi->idx; + enum ice_block blk = ICE_BLK_FD; + u16 vsi_num; + + ret = ice_fdir_add_del_raw(pf, filter, false); + if (ret) + return -rte_errno; + + struct ice_fdir_prof_info *pi = &ad->fdir_prof_info[ptg]; + if (pi->fdir_actived_cnt != 0) { + pi->fdir_actived_cnt--; + if (!pi->fdir_actived_cnt) { + vsi_num = ice_get_hw_vsi_num(hw, ctrl_vsi); + ice_rem_prof_id_flow(hw, blk, vsi_num, id); + + vsi_num = ice_get_hw_vsi_num(hw, main_vsi); + ice_rem_prof_id_flow(hw, blk, vsi_num, id); + } + } + + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 0); + + flow->rule = NULL; + + rte_free(filter->prof); + rte_free(filter->pkt_buf); + rte_free(filter); + + return 0; + } + + is_tun = ice_fdir_is_tunnel_profile(filter->tunnel_type); + if (filter->counter) { ice_fdir_counter_free(pf, filter->counter); filter->counter = NULL; @@ -1015,7 +1551,11 @@ ice_fdir_destroy_filter(struct ice_adapter *ad, return -rte_errno; } - ice_fdir_cnt_update(pf, filter->input.flow_type, false, false); + ice_fdir_cnt_update(pf, filter->input.flow_type, is_tun, false); + + if (filter->mark_flag == 1) + ice_fdir_rx_parsing_enable(ad, 0); + flow->rule = NULL; rte_free(filter); @@ -1176,8 +1716,7 @@ ice_fdir_parse_action(struct ice_adapter *ad, dest_num++; filter->input.dest_ctl = - ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX; - filter->input.q_index = 0; + ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER; break; case RTE_FLOW_ACTION_TYPE_RSS: dest_num++; @@ -1189,9 +1728,10 @@ ice_fdir_parse_action(struct ice_adapter *ad, break; case RTE_FLOW_ACTION_TYPE_MARK: mark_num++; - + filter->mark_flag = 1; 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++; @@ -1210,7 +1750,7 @@ ice_fdir_parse_action(struct ice_adapter *ad, } } - if (dest_num == 0 || dest_num >= 2) { + if (dest_num >= 2) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions, "Unsupported action combination"); @@ -1231,6 +1771,18 @@ ice_fdir_parse_action(struct ice_adapter *ad, return -rte_errno; } + if (dest_num + mark_num + counter_num == 0) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, actions, + "Empty action"); + return -rte_errno; + } + + /* set default action to PASSTHRU mode, in "mark/count only" case. */ + if (dest_num == 0) + filter->input.dest_ctl = + ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER; + return 0; } @@ -1243,285 +1795,640 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad, const struct rte_flow_item *item = pattern; enum rte_flow_item_type item_type; enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END; + enum rte_flow_item_type l4 = RTE_FLOW_ITEM_TYPE_END; + enum ice_fdir_tunnel_type tunnel_type = ICE_FDIR_TUNNEL_TYPE_NONE; + const struct rte_flow_item_raw *raw_spec, *raw_mask; 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_ipv4 *ipv4_spec, *ipv4_last, *ipv4_mask; const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask; + const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_spec, + *ipv6_frag_mask; const struct rte_flow_item_tcp *tcp_spec, *tcp_mask; const struct rte_flow_item_udp *udp_spec, *udp_mask; const struct rte_flow_item_sctp *sctp_spec, *sctp_mask; - uint64_t input_set = ICE_INSET_NONE; + const struct rte_flow_item_vxlan *vxlan_spec, *vxlan_mask; + const struct rte_flow_item_gtp *gtp_spec, *gtp_mask; + const struct rte_flow_item_gtp_psc *gtp_psc_spec, *gtp_psc_mask; + const struct rte_flow_item_esp *esp_spec, *esp_mask; + uint64_t input_set_i = ICE_INSET_NONE; /* only for tunnel inner */ + uint64_t input_set_o = ICE_INSET_NONE; /* non-tunnel and tunnel outer */ + uint64_t *input_set; uint8_t flow_type = ICE_FLTR_PTYPE_NONF_NONE; uint8_t ipv6_addr_mask[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint32_t vtc_flow_cpu; + uint16_t ether_type; + enum rte_flow_item_type next_type; + bool is_outer = true; + struct ice_fdir_extra *p_ext_data; + struct ice_fdir_v4 *p_v4 = NULL; + struct ice_fdir_v6 *p_v6 = NULL; + struct ice_parser_result rslt; + uint8_t item_num = 0; + for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (item->type == RTE_FLOW_ITEM_TYPE_VXLAN) + tunnel_type = ICE_FDIR_TUNNEL_TYPE_VXLAN; + /* To align with shared code behavior, save gtpu outer + * fields in inner struct. + */ + if (item->type == RTE_FLOW_ITEM_TYPE_GTPU || + item->type == RTE_FLOW_ITEM_TYPE_GTP_PSC) { + is_outer = false; + } + item_num++; + } + /* This loop parse flow pattern and distinguish Non-tunnel and tunnel + * flow. input_set_i is used for inner part. + */ for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { - if (item->last) { + item_type = item->type; + + if (item->last && !(item_type == RTE_FLOW_ITEM_TYPE_IPV4 || + item_type == + RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT)) { rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Not support range"); - return -rte_errno; + RTE_FLOW_ERROR_TYPE_ITEM, item, + "Not support range"); } - item_type = item->type; + + input_set = (tunnel_type && !is_outer) ? + &input_set_i : &input_set_o; switch (item_type) { + case RTE_FLOW_ITEM_TYPE_RAW: { + if (ad->psr == NULL) + return -rte_errno; + + raw_spec = item->spec; + raw_mask = item->mask; + + if (item_num != 1) + break; + + /* convert raw spec & mask from byte string to int */ + unsigned char *tmp_spec = + (uint8_t *)(uintptr_t)raw_spec->pattern; + unsigned char *tmp_mask = + (uint8_t *)(uintptr_t)raw_mask->pattern; + uint16_t tmp_val = 0; + uint8_t pkt_len = 0; + uint8_t tmp = 0; + int i, j; + + pkt_len = strlen((char *)(uintptr_t)raw_spec->pattern); + if (strlen((char *)(uintptr_t)raw_mask->pattern) != + pkt_len) + return -rte_errno; + + for (i = 0, j = 0; i < pkt_len; i += 2, j++) { + tmp = tmp_spec[i]; + if (tmp >= 'a' && tmp <= 'f') + tmp_val = tmp - 'a' + 10; + if (tmp >= 'A' && tmp <= 'F') + tmp_val = tmp - 'A' + 10; + if (tmp >= '0' && tmp <= '9') + tmp_val = tmp - '0'; + + tmp_val *= 16; + tmp = tmp_spec[i + 1]; + if (tmp >= 'a' && tmp <= 'f') + tmp_spec[j] = tmp_val + tmp - 'a' + 10; + if (tmp >= 'A' && tmp <= 'F') + tmp_spec[j] = tmp_val + tmp - 'A' + 10; + if (tmp >= '0' && tmp <= '9') + tmp_spec[j] = tmp_val + tmp - '0'; + + tmp = tmp_mask[i]; + if (tmp >= 'a' && tmp <= 'f') + tmp_val = tmp - 'a' + 10; + if (tmp >= 'A' && tmp <= 'F') + tmp_val = tmp - 'A' + 10; + if (tmp >= '0' && tmp <= '9') + tmp_val = tmp - '0'; + + tmp_val *= 16; + tmp = tmp_mask[i + 1]; + if (tmp >= 'a' && tmp <= 'f') + tmp_mask[j] = tmp_val + tmp - 'a' + 10; + if (tmp >= 'A' && tmp <= 'F') + tmp_mask[j] = tmp_val + tmp - 'A' + 10; + if (tmp >= '0' && tmp <= '9') + tmp_mask[j] = tmp_val + tmp - '0'; + } + + pkt_len /= 2; + + if (ice_parser_run(ad->psr, tmp_spec, pkt_len, &rslt)) + return -rte_errno; + + if (!tmp_mask) + return -rte_errno; + + filter->prof = (struct ice_parser_profile *) + ice_malloc(&ad->hw, sizeof(*filter->prof)); + if (!filter->prof) + return -ENOMEM; + + if (ice_parser_profile_init(&rslt, tmp_spec, tmp_mask, + pkt_len, ICE_BLK_FD, true, filter->prof)) + return -rte_errno; + + u8 *pkt_buf = (u8 *)ice_malloc(&ad->hw, pkt_len + 1); + if (!pkt_buf) + return -ENOMEM; + rte_memcpy(pkt_buf, tmp_spec, pkt_len); + filter->pkt_buf = pkt_buf; + + filter->pkt_len = pkt_len; + + filter->parser_ena = true; + + break; + } + case RTE_FLOW_ITEM_TYPE_ETH: + flow_type = ICE_FLTR_PTYPE_NON_IP_L2; eth_spec = item->spec; eth_mask = item->mask; - if (eth_spec && eth_mask) { - if (!rte_is_zero_ether_addr(ð_spec->src) || - !rte_is_zero_ether_addr(ð_mask->src)) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Src mac not support"); - return -rte_errno; - } + if (!(eth_spec && eth_mask)) + break; - if (!rte_is_broadcast_ether_addr(ð_mask->dst)) { + if (!rte_is_zero_ether_addr(ð_mask->dst)) + *input_set |= ICE_INSET_DMAC; + if (!rte_is_zero_ether_addr(ð_mask->src)) + *input_set |= ICE_INSET_SMAC; + + next_type = (item + 1)->type; + /* Ignore this field except for ICE_FLTR_PTYPE_NON_IP_L2 */ + if (eth_mask->type == RTE_BE16(0xffff) && + next_type == RTE_FLOW_ITEM_TYPE_END) { + *input_set |= ICE_INSET_ETHERTYPE; + ether_type = rte_be_to_cpu_16(eth_spec->type); + + if (ether_type == RTE_ETHER_TYPE_IPV4 || + ether_type == RTE_ETHER_TYPE_IPV6) { rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Invalid mac addr mask"); + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Unsupported ether_type."); return -rte_errno; } - - input_set |= ICE_INSET_DMAC; - rte_memcpy(&filter->input.ext_data.dst_mac, - ð_spec->dst, - RTE_ETHER_ADDR_LEN); } + + p_ext_data = (tunnel_type && is_outer) ? + &filter->input.ext_data_outer : + &filter->input.ext_data; + rte_memcpy(&p_ext_data->src_mac, + ð_spec->src, RTE_ETHER_ADDR_LEN); + rte_memcpy(&p_ext_data->dst_mac, + ð_spec->dst, RTE_ETHER_ADDR_LEN); + rte_memcpy(&p_ext_data->ether_type, + ð_spec->type, sizeof(eth_spec->type)); break; case RTE_FLOW_ITEM_TYPE_IPV4: + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; l3 = RTE_FLOW_ITEM_TYPE_IPV4; ipv4_spec = item->spec; + ipv4_last = item->last; ipv4_mask = item->mask; + p_v4 = (tunnel_type && is_outer) ? + &filter->input.ip_outer.v4 : + &filter->input.ip.v4; - if (ipv4_spec && ipv4_mask) { - /* Check IPv4 mask and update input set */ - if (ipv4_mask->hdr.version_ihl || - ipv4_mask->hdr.total_length || - ipv4_mask->hdr.packet_id || - ipv4_mask->hdr.fragment_offset || - ipv4_mask->hdr.hdr_checksum) { - rte_flow_error_set(error, EINVAL, + if (!(ipv4_spec && ipv4_mask)) + break; + + /* Check IPv4 mask and update input set */ + if (ipv4_mask->hdr.version_ihl || + ipv4_mask->hdr.total_length || + 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 |= ICE_INSET_IPV4_SRC; - if (ipv4_mask->hdr.dst_addr == UINT32_MAX) - input_set |= ICE_INSET_IPV4_DST; - if (ipv4_mask->hdr.type_of_service == UINT8_MAX) - input_set |= ICE_INSET_IPV4_TOS; - if (ipv4_mask->hdr.time_to_live == UINT8_MAX) - input_set |= ICE_INSET_IPV4_TTL; - if (ipv4_mask->hdr.next_proto_id == UINT8_MAX) - input_set |= ICE_INSET_IPV4_PROTO; - - filter->input.ip.v4.dst_ip = - ipv4_spec->hdr.src_addr; - filter->input.ip.v4.src_ip = - ipv4_spec->hdr.dst_addr; - filter->input.ip.v4.tos = - ipv4_spec->hdr.type_of_service; - filter->input.ip.v4.ttl = - ipv4_spec->hdr.time_to_live; - filter->input.ip.v4.proto = - ipv4_spec->hdr.next_proto_id; + return -rte_errno; + } + + if (ipv4_last && + (ipv4_last->hdr.version_ihl || + ipv4_last->hdr.type_of_service || + ipv4_last->hdr.time_to_live || + ipv4_last->hdr.total_length | + ipv4_last->hdr.next_proto_id || + ipv4_last->hdr.hdr_checksum || + ipv4_last->hdr.src_addr || + ipv4_last->hdr.dst_addr)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, "Invalid IPv4 last."); + return -rte_errno; + } + + /* Mask for IPv4 src/dst addrs not supported */ + if (ipv4_mask->hdr.src_addr && + ipv4_mask->hdr.src_addr != UINT32_MAX) + return -rte_errno; + if (ipv4_mask->hdr.dst_addr && + ipv4_mask->hdr.dst_addr != UINT32_MAX) + return -rte_errno; + + if (ipv4_mask->hdr.dst_addr == UINT32_MAX) + *input_set |= ICE_INSET_IPV4_DST; + if (ipv4_mask->hdr.src_addr == UINT32_MAX) + *input_set |= ICE_INSET_IPV4_SRC; + if (ipv4_mask->hdr.time_to_live == UINT8_MAX) + *input_set |= ICE_INSET_IPV4_TTL; + if (ipv4_mask->hdr.next_proto_id == UINT8_MAX) + *input_set |= ICE_INSET_IPV4_PROTO; + if (ipv4_mask->hdr.type_of_service == UINT8_MAX) + *input_set |= ICE_INSET_IPV4_TOS; + + p_v4->dst_ip = ipv4_spec->hdr.dst_addr; + p_v4->src_ip = ipv4_spec->hdr.src_addr; + p_v4->ttl = ipv4_spec->hdr.time_to_live; + p_v4->proto = ipv4_spec->hdr.next_proto_id; + p_v4->tos = ipv4_spec->hdr.type_of_service; + + /* fragment Ipv4: + * spec is 0x2000, mask is 0x2000 + */ + if (ipv4_spec->hdr.fragment_offset == + rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG) && + ipv4_mask->hdr.fragment_offset == + rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG)) { + /* all IPv4 fragment packet has the same + * ethertype, if the spec and mask is valid, + * set ethertype into input set. + */ + flow_type = ICE_FLTR_PTYPE_FRAG_IPV4; + *input_set |= ICE_INSET_ETHERTYPE; + input_set_o |= ICE_INSET_ETHERTYPE; + } else if (ipv4_mask->hdr.packet_id == UINT16_MAX) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, "Invalid IPv4 mask."); + return -rte_errno; } - flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; break; case RTE_FLOW_ITEM_TYPE_IPV6: + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; l3 = RTE_FLOW_ITEM_TYPE_IPV6; ipv6_spec = item->spec; ipv6_mask = item->mask; + p_v6 = (tunnel_type && is_outer) ? + &filter->input.ip_outer.v6 : + &filter->input.ip.v6; - if (ipv6_spec && ipv6_mask) { - /* Check IPv6 mask and update input set */ - if (ipv6_mask->hdr.payload_len) { - rte_flow_error_set(error, EINVAL, + if (!(ipv6_spec && ipv6_mask)) + break; + + /* Check IPv6 mask and update input set */ + if (ipv6_mask->hdr.payload_len) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid IPv6 mask"); - return -rte_errno; - } + return -rte_errno; + } - if (!memcmp(ipv6_mask->hdr.src_addr, - ipv6_addr_mask, - RTE_DIM(ipv6_mask->hdr.src_addr))) - input_set |= ICE_INSET_IPV6_SRC; - if (!memcmp(ipv6_mask->hdr.dst_addr, - ipv6_addr_mask, - RTE_DIM(ipv6_mask->hdr.dst_addr))) - input_set |= ICE_INSET_IPV6_DST; - - if ((ipv6_mask->hdr.vtc_flow & - rte_cpu_to_be_32(ICE_IPV6_TC_MASK)) - == rte_cpu_to_be_32(ICE_IPV6_TC_MASK)) - input_set |= ICE_INSET_IPV6_TC; - if (ipv6_mask->hdr.proto == UINT8_MAX) - input_set |= ICE_INSET_IPV6_NEXT_HDR; - if (ipv6_mask->hdr.hop_limits == UINT8_MAX) - input_set |= ICE_INSET_IPV6_HOP_LIMIT; - - rte_memcpy(filter->input.ip.v6.dst_ip, - ipv6_spec->hdr.src_addr, 16); - rte_memcpy(filter->input.ip.v6.src_ip, - ipv6_spec->hdr.dst_addr, 16); - - vtc_flow_cpu = - rte_be_to_cpu_32(ipv6_spec->hdr.vtc_flow); - filter->input.ip.v6.tc = - (uint8_t)(vtc_flow_cpu >> - ICE_FDIR_IPV6_TC_OFFSET); - filter->input.ip.v6.proto = - ipv6_spec->hdr.proto; - filter->input.ip.v6.hlim = - ipv6_spec->hdr.hop_limits; + if (!memcmp(ipv6_mask->hdr.src_addr, ipv6_addr_mask, + RTE_DIM(ipv6_mask->hdr.src_addr))) + *input_set |= ICE_INSET_IPV6_SRC; + if (!memcmp(ipv6_mask->hdr.dst_addr, ipv6_addr_mask, + RTE_DIM(ipv6_mask->hdr.dst_addr))) + *input_set |= ICE_INSET_IPV6_DST; + + if ((ipv6_mask->hdr.vtc_flow & + rte_cpu_to_be_32(ICE_IPV6_TC_MASK)) + == rte_cpu_to_be_32(ICE_IPV6_TC_MASK)) + *input_set |= ICE_INSET_IPV6_TC; + if (ipv6_mask->hdr.proto == UINT8_MAX) + *input_set |= ICE_INSET_IPV6_NEXT_HDR; + if (ipv6_mask->hdr.hop_limits == UINT8_MAX) + *input_set |= ICE_INSET_IPV6_HOP_LIMIT; + + rte_memcpy(&p_v6->dst_ip, ipv6_spec->hdr.dst_addr, 16); + rte_memcpy(&p_v6->src_ip, ipv6_spec->hdr.src_addr, 16); + vtc_flow_cpu = rte_be_to_cpu_32(ipv6_spec->hdr.vtc_flow); + p_v6->tc = (uint8_t)(vtc_flow_cpu >> ICE_FDIR_IPV6_TC_OFFSET); + p_v6->proto = ipv6_spec->hdr.proto; + p_v6->hlim = ipv6_spec->hdr.hop_limits; + break; + case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT: + l3 = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT; + flow_type = ICE_FLTR_PTYPE_FRAG_IPV6; + ipv6_frag_spec = item->spec; + ipv6_frag_mask = item->mask; + + if (!(ipv6_frag_spec && ipv6_frag_mask)) + break; + + /* fragment Ipv6: + * spec is 0x1, mask is 0x1 + */ + if (ipv6_frag_spec->hdr.frag_data == + rte_cpu_to_be_16(1) && + ipv6_frag_mask->hdr.frag_data == + rte_cpu_to_be_16(1)) { + /* all IPv6 fragment packet has the same + * ethertype, if the spec and mask is valid, + * set ethertype into input set. + */ + *input_set |= ICE_INSET_ETHERTYPE; + input_set_o |= ICE_INSET_ETHERTYPE; + } else if (ipv6_frag_mask->hdr.id == UINT32_MAX) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, "Invalid IPv6 mask."); + return -rte_errno; } - flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; break; + case RTE_FLOW_ITEM_TYPE_TCP: + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP; + tcp_spec = item->spec; tcp_mask = item->mask; - if (tcp_spec && tcp_mask) { - /* Check TCP mask and update input set */ - if (tcp_mask->hdr.sent_seq || - tcp_mask->hdr.recv_ack || - tcp_mask->hdr.data_off || - tcp_mask->hdr.tcp_flags || - tcp_mask->hdr.rx_win || - tcp_mask->hdr.cksum || - tcp_mask->hdr.tcp_urp) { - rte_flow_error_set(error, EINVAL, + if (!(tcp_spec && tcp_mask)) + break; + + /* Check TCP mask and update input set */ + if (tcp_mask->hdr.sent_seq || + tcp_mask->hdr.recv_ack || + tcp_mask->hdr.data_off || + tcp_mask->hdr.tcp_flags || + tcp_mask->hdr.rx_win || + tcp_mask->hdr.cksum || + tcp_mask->hdr.tcp_urp) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid TCP mask"); - return -rte_errno; - } + return -rte_errno; + } - if (tcp_mask->hdr.src_port == UINT16_MAX) - input_set |= ICE_INSET_TCP_SRC_PORT; - if (tcp_mask->hdr.dst_port == UINT16_MAX) - input_set |= ICE_INSET_TCP_DST_PORT; - - /* Get filter info */ - if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { - filter->input.ip.v4.dst_port = - 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; - } + /* Mask for TCP src/dst ports not supported */ + if (tcp_mask->hdr.src_port && + tcp_mask->hdr.src_port != UINT16_MAX) + return -rte_errno; + if (tcp_mask->hdr.dst_port && + tcp_mask->hdr.dst_port != UINT16_MAX) + return -rte_errno; + + if (tcp_mask->hdr.src_port == UINT16_MAX) + *input_set |= ICE_INSET_TCP_SRC_PORT; + if (tcp_mask->hdr.dst_port == UINT16_MAX) + *input_set |= ICE_INSET_TCP_DST_PORT; + + /* Get filter info */ + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { + assert(p_v4); + p_v4->dst_port = tcp_spec->hdr.dst_port; + p_v4->src_port = tcp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { + assert(p_v6); + p_v6->dst_port = tcp_spec->hdr.dst_port; + p_v6->src_port = tcp_spec->hdr.src_port; } break; case RTE_FLOW_ITEM_TYPE_UDP: + l4 = RTE_FLOW_ITEM_TYPE_UDP; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP; + udp_spec = item->spec; udp_mask = item->mask; - if (udp_spec && udp_mask) { - /* Check UDP mask and update input set*/ - if (udp_mask->hdr.dgram_len || - udp_mask->hdr.dgram_cksum) { - rte_flow_error_set(error, EINVAL, + if (!(udp_spec && udp_mask)) + break; + + /* Check UDP mask and update input set*/ + 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; - } + return -rte_errno; + } - if (udp_mask->hdr.src_port == UINT16_MAX) - input_set |= ICE_INSET_UDP_SRC_PORT; - if (udp_mask->hdr.dst_port == UINT16_MAX) - input_set |= ICE_INSET_UDP_DST_PORT; - - /* Get filter info */ - if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { - filter->input.ip.v4.dst_port = - 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; - } + /* Mask for UDP src/dst ports not supported */ + if (udp_mask->hdr.src_port && + udp_mask->hdr.src_port != UINT16_MAX) + return -rte_errno; + if (udp_mask->hdr.dst_port && + udp_mask->hdr.dst_port != UINT16_MAX) + return -rte_errno; + + if (udp_mask->hdr.src_port == UINT16_MAX) + *input_set |= ICE_INSET_UDP_SRC_PORT; + if (udp_mask->hdr.dst_port == UINT16_MAX) + *input_set |= ICE_INSET_UDP_DST_PORT; + + /* Get filter info */ + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { + assert(p_v4); + p_v4->dst_port = udp_spec->hdr.dst_port; + p_v4->src_port = udp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { + assert(p_v6); + p_v6->src_port = udp_spec->hdr.src_port; + p_v6->dst_port = udp_spec->hdr.dst_port; } break; case RTE_FLOW_ITEM_TYPE_SCTP: + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_SCTP; + if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_SCTP; + sctp_spec = item->spec; sctp_mask = item->mask; - if (sctp_spec && sctp_mask) { - /* Check SCTP mask and update input set */ - if (sctp_mask->hdr.cksum) { - rte_flow_error_set(error, EINVAL, + if (!(sctp_spec && sctp_mask)) + break; + + /* Check SCTP mask and update input set */ + if (sctp_mask->hdr.cksum) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid UDP mask"); - return -rte_errno; - } + return -rte_errno; + } - if (sctp_mask->hdr.src_port == UINT16_MAX) - input_set |= ICE_INSET_SCTP_SRC_PORT; - if (sctp_mask->hdr.dst_port == UINT16_MAX) - input_set |= ICE_INSET_SCTP_DST_PORT; - - /* Get filter info */ - if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { - filter->input.ip.v4.dst_port = - 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; - } + /* Mask for SCTP src/dst ports not supported */ + if (sctp_mask->hdr.src_port && + sctp_mask->hdr.src_port != UINT16_MAX) + return -rte_errno; + if (sctp_mask->hdr.dst_port && + sctp_mask->hdr.dst_port != UINT16_MAX) + return -rte_errno; + + if (sctp_mask->hdr.src_port == UINT16_MAX) + *input_set |= ICE_INSET_SCTP_SRC_PORT; + if (sctp_mask->hdr.dst_port == UINT16_MAX) + *input_set |= ICE_INSET_SCTP_DST_PORT; + + /* Get filter info */ + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) { + assert(p_v4); + p_v4->dst_port = sctp_spec->hdr.dst_port; + p_v4->src_port = sctp_spec->hdr.src_port; + } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) { + assert(p_v6); + p_v6->dst_port = sctp_spec->hdr.dst_port; + p_v6->src_port = sctp_spec->hdr.src_port; } break; case RTE_FLOW_ITEM_TYPE_VOID: break; + case RTE_FLOW_ITEM_TYPE_VXLAN: + l3 = RTE_FLOW_ITEM_TYPE_END; + vxlan_spec = item->spec; + vxlan_mask = item->mask; + is_outer = false; + + if (!(vxlan_spec && vxlan_mask)) + break; + + if (vxlan_mask->hdr.vx_flags) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid vxlan field"); + return -rte_errno; + } + + if (vxlan_mask->hdr.vx_vni) + *input_set |= ICE_INSET_VXLAN_VNI; + + filter->input.vxlan_data.vni = vxlan_spec->hdr.vx_vni; + + break; + case RTE_FLOW_ITEM_TYPE_GTPU: + l3 = RTE_FLOW_ITEM_TYPE_END; + tunnel_type = ICE_FDIR_TUNNEL_TYPE_GTPU; + gtp_spec = item->spec; + gtp_mask = item->mask; + + if (!(gtp_spec && gtp_mask)) + break; + + if (gtp_mask->v_pt_rsv_flags || + gtp_mask->msg_type || + gtp_mask->msg_len) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid GTP mask"); + return -rte_errno; + } + + if (gtp_mask->teid == UINT32_MAX) + input_set_o |= ICE_INSET_GTPU_TEID; + + filter->input.gtpu_data.teid = gtp_spec->teid; + break; + case RTE_FLOW_ITEM_TYPE_GTP_PSC: + tunnel_type = ICE_FDIR_TUNNEL_TYPE_GTPU_EH; + gtp_psc_spec = item->spec; + gtp_psc_mask = item->mask; + + if (!(gtp_psc_spec && gtp_psc_mask)) + break; + + if (gtp_psc_mask->hdr.qfi == 0x3F) + input_set_o |= ICE_INSET_GTPU_QFI; + + filter->input.gtpu_data.qfi = + gtp_psc_spec->hdr.qfi; + break; + case RTE_FLOW_ITEM_TYPE_ESP: + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + l4 == RTE_FLOW_ITEM_TYPE_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6 && + l4 == RTE_FLOW_ITEM_TYPE_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 && + l4 == RTE_FLOW_ITEM_TYPE_END) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6 && + l4 == RTE_FLOW_ITEM_TYPE_END) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP; + + esp_spec = item->spec; + esp_mask = item->mask; + + if (!(esp_spec && esp_mask)) + break; + + if (esp_mask->hdr.spi == UINT32_MAX) { + if (l4 == RTE_FLOW_ITEM_TYPE_UDP) + *input_set |= ICE_INSET_NAT_T_ESP_SPI; + else + *input_set |= ICE_INSET_ESP_SPI; + } + + if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) + filter->input.ip.v4.sec_parm_idx = + esp_spec->hdr.spi; + else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) + filter->input.ip.v6.sec_parm_idx = + esp_spec->hdr.spi; + break; default: rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Invalid pattern item."); + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid pattern item."); return -rte_errno; } } + if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_EH; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU && + flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_GTPU; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH && + flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV6_GTPU_EH; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_UDP; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_TCP; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_SCTP) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_SCTP; + else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN && + flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) + flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_OTHER; + + filter->tunnel_type = tunnel_type; filter->input.flow_type = flow_type; - filter->input_set = input_set; + filter->input_set_o = input_set_o; + filter->input_set_i = input_set_i; return 0; } @@ -1532,6 +2439,7 @@ ice_fdir_parse(struct ice_adapter *ad, uint32_t array_len, const struct rte_flow_item pattern[], const struct rte_flow_action actions[], + uint32_t priority, void **meta, struct rte_flow_error *error) { @@ -1539,38 +2447,60 @@ ice_fdir_parse(struct ice_adapter *ad, struct ice_fdir_filter_conf *filter = &pf->fdir.conf; struct ice_pattern_match_item *item = NULL; uint64_t input_set; + bool raw = false; int ret; memset(filter, 0, sizeof(*filter)); - item = ice_search_pattern_match_item(pattern, array, array_len, error); + item = ice_search_pattern_match_item(ad, pattern, array, array_len, + error); + + if (!ad->devargs.pipe_mode_support && priority >= 1) + return -rte_errno; + if (!item) return -rte_errno; ret = ice_fdir_parse_pattern(ad, pattern, error, filter); if (ret) - return ret; - input_set = filter->input_set; - if (!input_set || input_set & ~item->input_set_mask) { + goto error; + + if (item->pattern_list[0] == RTE_FLOW_ITEM_TYPE_RAW) + raw = true; + + input_set = filter->input_set_o | filter->input_set_i; + input_set = raw ? ~input_set : input_set; + + if (!input_set || filter->input_set_o & + ~(item->input_set_mask_o | ICE_INSET_ETHERTYPE) || + filter->input_set_i & ~item->input_set_mask_i) { 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; + if (meta) + *meta = filter; - return 0; + rte_free(item); + return ret; +error: + rte_free(filter->prof); + rte_free(filter->pkt_buf); + rte_free(item); + return ret; } static struct ice_flow_parser ice_fdir_parser = { .engine = &ice_fdir_engine, - .array = ice_fdir_pattern, - .array_len = RTE_DIM(ice_fdir_pattern), + .array = ice_fdir_pattern_list, + .array_len = RTE_DIM(ice_fdir_pattern_list), .parse_pattern_action = ice_fdir_parse, .stage = ICE_FLOW_STAGE_DISTRIBUTOR, };