From 1b9c68120a1c50f36e2a085bc4475b3f0972cf84 Mon Sep 17 00:00:00 2001 From: Ting Xu Date: Thu, 4 Nov 2021 10:22:28 +0800 Subject: [PATCH] net/ice: enable protocol agnostic flow offloading in RSS Enable protocol agnostic flow offloading to support raw pattern input for RSS hash flow rule creation. It is based on Parser Library feature. Current rte_flow raw API is utilized. Signed-off-by: Ting Xu Acked-by: Qi Zhang --- doc/guides/rel_notes/release_21_11.rst | 1 + drivers/net/ice/ice_ethdev.h | 9 + drivers/net/ice/ice_hash.c | 286 +++++++++++++++++++++++-- 3 files changed, 274 insertions(+), 22 deletions(-) diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index c98a7e9219..fd0f604377 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -168,6 +168,7 @@ New Features * **Updated Intel ice driver.** * Added protocol agnostic flow offloading support in Flow Director. + * Added protocol agnostic flow offloading support in RSS hash. * Added 1PPS out support by a devargs. * Added IPv4 and L4 (TCP/UDP/SCTP) checksum hash support in RSS flow. * Added DEV_RX_OFFLOAD_TIMESTAMP support. diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index d021e7fd0b..3a5bb9bbc6 100644 --- a/drivers/net/ice/ice_ethdev.h +++ b/drivers/net/ice/ice_ethdev.h @@ -500,6 +500,14 @@ struct ice_fdir_prof_info { u64 fdir_actived_cnt; }; +/** + * Structure to store rss fv entry. + */ +struct ice_rss_prof_info { + struct ice_parser_profile prof; + bool symm; +}; + /** * Structure to store private data for each PF/VF instance. */ @@ -524,6 +532,7 @@ struct ice_adapter { bool ptp_ena; uint64_t time_hw; struct ice_fdir_prof_info fdir_prof_info[ICE_MAX_PTGS]; + struct ice_rss_prof_info rss_prof_info[ICE_MAX_PTGS]; #ifdef RTE_ARCH_X86 bool rx_use_avx2; bool rx_use_avx512; diff --git a/drivers/net/ice/ice_hash.c b/drivers/net/ice/ice_hash.c index 35eff8b17d..4b682a4f35 100644 --- a/drivers/net/ice/ice_hash.c +++ b/drivers/net/ice/ice_hash.c @@ -32,6 +32,7 @@ #define ICE_PHINT_GTPU_EH BIT_ULL(3) #define ICE_PHINT_GTPU_EH_DWN BIT_ULL(4) #define ICE_PHINT_GTPU_EH_UP BIT_ULL(5) +#define ICE_PHINT_RAW BIT_ULL(6) #define ICE_GTPU_EH_DWNLINK 0 #define ICE_GTPU_EH_UPLINK 1 @@ -71,6 +72,7 @@ struct ice_rss_meta { uint8_t hash_function; struct ice_rss_hash_cfg cfg; + struct ice_rss_raw_cfg raw; }; struct ice_hash_flow_cfg { @@ -492,6 +494,7 @@ struct ice_rss_hash_cfg eth_tmplt = { */ static struct ice_pattern_match_item ice_hash_pattern_list[] = { /* IPV4 */ + {pattern_raw, ICE_INSET_NONE, ICE_INSET_NONE, NULL}, {pattern_eth_ipv4, ICE_RSS_TYPE_ETH_IPV4, ICE_INSET_NONE, &ipv4_tmplt}, {pattern_eth_ipv4_udp, ICE_RSS_TYPE_ETH_IPV4_UDP, ICE_INSET_NONE, &ipv4_udp_tmplt}, {pattern_eth_ipv4_tcp, ICE_RSS_TYPE_ETH_IPV4_TCP, ICE_INSET_NONE, &ipv4_tcp_tmplt}, @@ -612,6 +615,9 @@ ice_hash_parse_pattern(const struct rte_flow_item pattern[], uint64_t *phint, } switch (item->type) { + case RTE_FLOW_ITEM_TYPE_RAW: + *phint |= ICE_PHINT_RAW; + break; case RTE_FLOW_ITEM_TYPE_VLAN: *phint |= ICE_PHINT_VLAN; break; @@ -639,6 +645,91 @@ ice_hash_parse_pattern(const struct rte_flow_item pattern[], uint64_t *phint, return 0; } +static int +ice_hash_parse_raw_pattern(struct ice_adapter *ad, + const struct rte_flow_item *item, + struct ice_rss_meta *meta) +{ + const struct rte_flow_item_raw *raw_spec, *raw_mask; + struct ice_parser_profile prof; + struct ice_parser_result rslt; + struct ice_parser *psr; + uint8_t *pkt_buf, *msk_buf; + uint8_t spec_len, pkt_len; + uint8_t tmp_val = 0; + uint8_t tmp_c = 0; + int i, j; + + raw_spec = item->spec; + raw_mask = item->mask; + + spec_len = strlen((char *)(uintptr_t)raw_spec->pattern); + if (strlen((char *)(uintptr_t)raw_mask->pattern) != + spec_len) + return -rte_errno; + + pkt_len = spec_len / 2; + + pkt_buf = rte_zmalloc(NULL, pkt_len, 0); + if (!pkt_buf) + return -ENOMEM; + + msk_buf = rte_zmalloc(NULL, pkt_len, 0); + if (!msk_buf) + return -ENOMEM; + + /* convert string to int array */ + for (i = 0, j = 0; i < spec_len; i += 2, j++) { + tmp_c = raw_spec->pattern[i]; + if (tmp_c >= 'a' && tmp_c <= 'f') + tmp_val = tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + tmp_val = tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + tmp_val = tmp_c - '0'; + + tmp_c = raw_spec->pattern[i + 1]; + if (tmp_c >= 'a' && tmp_c <= 'f') + pkt_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + pkt_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + pkt_buf[j] = tmp_val * 16 + tmp_c - '0'; + + tmp_c = raw_mask->pattern[i]; + if (tmp_c >= 'a' && tmp_c <= 'f') + tmp_val = tmp_c - 0x57; + if (tmp_c >= 'A' && tmp_c <= 'F') + tmp_val = tmp_c - 0x37; + if (tmp_c >= '0' && tmp_c <= '9') + tmp_val = tmp_c - '0'; + + tmp_c = raw_mask->pattern[i + 1]; + if (tmp_c >= 'a' && tmp_c <= 'f') + msk_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + msk_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + msk_buf[j] = tmp_val * 16 + tmp_c - '0'; + } + + if (ice_parser_create(&ad->hw, &psr)) + return -rte_errno; + if (ice_parser_run(psr, pkt_buf, pkt_len, &rslt)) + return -rte_errno; + ice_parser_destroy(psr); + + if (ice_parser_profile_init(&rslt, pkt_buf, msk_buf, + pkt_len, ICE_BLK_RSS, true, &prof)) + return -rte_errno; + + rte_memcpy(&meta->raw.prof, &prof, sizeof(prof)); + + rte_free(pkt_buf); + rte_free(msk_buf); + return 0; +} + static void ice_refine_hash_cfg_l234(struct ice_rss_hash_cfg *hash_cfg, uint64_t rss_type) @@ -999,7 +1090,10 @@ ice_hash_parse_action(struct ice_pattern_match_item *pattern_match_item, RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) { rss_meta->hash_function = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ; - cfg->symm = true; + if (pattern_hint == ICE_PHINT_RAW) + rss_meta->raw.symm = true; + else + cfg->symm = true; } if (rss->level) @@ -1017,6 +1111,10 @@ ice_hash_parse_action(struct ice_pattern_match_item *pattern_match_item, RTE_FLOW_ERROR_TYPE_ACTION, action, "a non-NULL RSS queue is not supported"); + /* If pattern type is raw, no need to refine rss type */ + if (pattern_hint == ICE_PHINT_RAW) + break; + /** * Check simultaneous use of SRC_ONLY and DST_ONLY * of the same level. @@ -1085,6 +1183,17 @@ ice_hash_parse_pattern_action(__rte_unused struct ice_adapter *ad, if (ret) goto error; + if (phint == ICE_PHINT_RAW) { + rss_meta_ptr->raw.raw_ena = true; + ret = ice_hash_parse_raw_pattern(ad, pattern, rss_meta_ptr); + if (ret) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "Parse raw pattern failed"); + goto error; + } + } + /* Check rss action. */ ret = ice_hash_parse_action(pattern_match_item, actions, phint, (void **)&rss_meta_ptr, error); @@ -1099,6 +1208,71 @@ error: return ret; } +static int +ice_hash_add_raw_cfg(struct ice_adapter *ad, + struct ice_rss_raw_cfg *cfg, u16 vsi_handle) +{ + struct ice_parser_profile *prof = &cfg->prof; + struct ice_rss_prof_info *rss_prof; + struct ice_hw *hw = &ad->hw; + int i, ptg, ret; + u64 id; + + id = (u64)ice_find_first_bit(prof->ptypes, UINT16_MAX); + + ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id]; + rss_prof = &ad->rss_prof_info[ptg]; + /* check if ptg already has profile */ + if (rss_prof->prof.fv_num) { + for (i = 0; i < ICE_MAX_FV_WORDS; i++) { + if (rss_prof->prof.fv[i].proto_id != + prof->fv[i].proto_id || + rss_prof->prof.fv[i].offset != + prof->fv[i].offset) + break; + } + + /* current profile is matched, check symmetric hash */ + if (i == ICE_MAX_FV_WORDS) { + if (rss_prof->symm != cfg->symm) + goto update_symm; + + return 0; + } + + /* current profile is not matched, remove it */ + ret = ice_rem_prof_id_flow(hw, ICE_BLK_RSS, + ice_get_hw_vsi_num(hw, vsi_handle), + id); + if (ret) { + PMD_DRV_LOG(ERR, "remove RSS flow failed\n"); + return ret; + } + + ret = ice_rem_prof(hw, ICE_BLK_RSS, id); + if (ret) { + PMD_DRV_LOG(ERR, "remove RSS profile failed\n"); + return ret; + } + } + + /* add new profile */ + ret = ice_flow_set_hw_prof(hw, vsi_handle, 0, prof, ICE_BLK_RSS); + if (ret) { + PMD_DRV_LOG(ERR, "HW profile add failed\n"); + return ret; + } + + rss_prof->symm = cfg->symm; + ice_memcpy(&rss_prof->prof, prof, + sizeof(struct ice_parser_profile), + ICE_NONDMA_TO_NONDMA); + +update_symm: + ice_rss_update_raw_symm(hw, cfg, id); + return 0; +} + static int ice_hash_create(struct ice_adapter *ad, struct rte_flow *flow, @@ -1134,15 +1308,30 @@ ice_hash_create(struct ice_adapter *ad, goto out; } else { - memcpy(&filter_ptr->rss_cfg.hash, &rss_meta->cfg, - sizeof(struct ice_rss_hash_cfg)); - ret = ice_add_rss_cfg_wrap(pf, vsi->idx, - &filter_ptr->rss_cfg.hash); - if (ret) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_HANDLE, NULL, - "rss flow create fail"); - goto error; + if (rss_meta->raw.raw_ena) { + memcpy(&filter_ptr->rss_cfg.raw, &rss_meta->raw, + sizeof(struct ice_rss_raw_cfg)); + ret = ice_hash_add_raw_cfg(ad, &rss_meta->raw, + pf->main_vsi->idx); + if (ret) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "rss flow create fail"); + goto error; + } + } else { + memcpy(&filter_ptr->rss_cfg.hash, &rss_meta->cfg, + sizeof(struct ice_rss_hash_cfg)); + ret = ice_add_rss_cfg_wrap(pf, vsi->idx, + &filter_ptr->rss_cfg.hash); + if (ret) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "rss flow create fail"); + goto error; + } } } @@ -1157,6 +1346,45 @@ error: return -rte_errno; } +static int +ice_hash_rem_raw_cfg(struct ice_adapter *ad, + struct ice_parser_profile *prof, + u16 vsi_handle) +{ + struct ice_hw *hw = &ad->hw; + int ptg, ret; + u16 vsig; + u64 id; + + id = (u64)ice_find_first_bit(prof->ptypes, 0xFFFF); + + ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id]; + + memset(&ad->rss_prof_info[ptg], 0, + sizeof(struct ice_rss_prof_info)); + + /* check if vsig is already removed */ + ret = ice_vsig_find_vsi(hw, ICE_BLK_RSS, + ice_get_hw_vsi_num(hw, vsi_handle), &vsig); + if (!ret && vsig) { + ret = ice_rem_prof_id_flow(hw, ICE_BLK_RSS, + ice_get_hw_vsi_num(hw, vsi_handle), + id); + if (ret) + goto err; + + ret = ice_rem_prof(hw, ICE_BLK_RSS, id); + if (ret) + goto err; + } + + return 0; + +err: + PMD_DRV_LOG(ERR, "HW profile remove failed\n"); + return ret; +} + static int ice_hash_destroy(struct ice_adapter *ad, struct rte_flow *flow, @@ -1178,18 +1406,32 @@ ice_hash_destroy(struct ice_adapter *ad, (1 << VSIQF_HASH_CTL_HASH_SCHEME_S); ICE_WRITE_REG(hw, VSIQF_HASH_CTL(vsi->vsi_id), reg); } else { - ret = ice_rem_rss_cfg_wrap(pf, vsi->idx, - &filter_ptr->rss_cfg.hash); - /* Fixme: Ignore the error if a rule does not exist. - * Currently a rule for inputset change or symm turn on/off - * will overwrite an exist rule, while application still - * have 2 rte_flow handles. - **/ - if (ret && ret != ICE_ERR_DOES_NOT_EXIST) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_HANDLE, NULL, - "rss flow destroy fail"); - goto error; + if (filter_ptr->rss_cfg.raw.raw_ena) { + ret = + ice_hash_rem_raw_cfg(ad, &filter_ptr->rss_cfg.raw.prof, + pf->main_vsi->idx); + if (ret) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "rss flow destroy fail"); + goto error; + } + } else { + ret = ice_rem_rss_cfg_wrap(pf, vsi->idx, + &filter_ptr->rss_cfg.hash); + /* Fixme: Ignore the error if a rule does not exist. + * Currently a rule for inputset change or symm turn + * on/off will overwrite an exist rule, while + * application still have 2 rte_flow handles. + **/ + if (ret && ret != ICE_ERR_DOES_NOT_EXIST) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "rss flow destroy fail"); + goto error; + } } } -- 2.39.5