From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id B2621A0577; Tue, 14 Apr 2020 08:43:09 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 0FECC1C025; Tue, 14 Apr 2020 08:43:09 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 687E53B5 for ; Tue, 14 Apr 2020 08:43:06 +0200 (CEST) IronPort-SDR: 9n9aiSlGG983/sqVUdnKpWYsIBXPqSwH7HbjytJXv8NgGw14C+lIdwWmg2le2kzOLbjd+hc2Oq wPk9aX7XhXtw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Apr 2020 23:43:04 -0700 IronPort-SDR: Qpk6B4w0ke83+8QDrtjv65CQv088qmj+jQmfzUEFR0+XEzJVRoANRiTv8G8LWODISC20VBcmZz ntfbWyYVkMMA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,381,1580803200"; d="scan'208";a="332084046" Received: from unknown (HELO localhost.localdomain) ([10.239.255.70]) by orsmga001.jf.intel.com with ESMTP; 13 Apr 2020 23:43:02 -0700 From: Chenxu Di To: dev@dpdk.org Cc: beilei.xing@intel.com, Chenxu Di Date: Tue, 14 Apr 2020 06:36:48 +0000 Message-Id: <20200414063648.86590-1-chenxux.di@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200318014710.13577-1-chenxux.di@intel.com> References: <20200318014710.13577-1-chenxux.di@intel.com> Subject: [dpdk-dev] [PATCH v8] net/i40e: enable advanced RSS X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch supports: - symmetric hash configuration - Input set configuration Signed-off-by: Chenxu Di --- doc/guides/nics/i40e.rst | 35 ++ doc/guides/rel_notes/release_20_05.rst | 7 + drivers/net/i40e/i40e_ethdev.c | 509 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 22 +- drivers/net/i40e/i40e_flow.c | 199 ++++++++-- 5 files changed, 683 insertions(+), 89 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..1f8fca285 100644 --- a/doc/guides/nics/i40e.rst +++ b/doc/guides/nics/i40e.rst @@ -569,6 +569,41 @@ details please refer to :doc:`../testpmd_app_ug/index`. testpmd> set port (port_id) queue-region flush (on|off) testpmd> show port (port_id) queue-region +Generic flow API +~~~~~~~~~~~~~~~~~~~ + +- ``RSS Flow`` + + RSS Flow supports to set hash input set, hash function, enable hash + and configure queue region. + For example: + Configure queue region as queue 0, 1, 2, 3. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues 0 1 2 3 end / end + + Enable hash and set input set for ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp l3-src-only end queues end / end + + Set symmetric hash enable for flow type ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp end queues end func symmetric_toeplitz / end + + Set hash function as simple xor. + + .. code-block:: console + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues end func simple_xor / end + Limitations or Known issues --------------------------- diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst index 000bbf501..bf5f399fe 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,13 @@ New Features * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit. +* **Updated Intel i40e driver.** + + Updated i40e PMD with new features and improvements, including: + + * Added support for RSS using L3/L4 source/destination only. + * Added support for setting hash function in rte flow. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..efc113842 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -1656,6 +1656,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) /* initialize mirror rule list */ TAILQ_INIT(&pf->mirror_list); + /* initialize RSS rule list */ + TAILQ_INIT(&pf->rss_config_list); + /* initialize Traffic Manager configuration */ i40e_tm_conf_init(dev); @@ -12325,14 +12328,16 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf) } } -/* Restore rss filter */ +/* Restore RSS filter */ static inline void i40e_rss_filter_restore(struct i40e_pf *pf) { - struct i40e_rte_flow_rss_conf *conf = - &pf->rss_info; - if (conf->conf.queue_num) - i40e_config_rss_filter(pf, conf, TRUE); + struct i40e_rss_conf_list *list = &pf->rss_config_list; + struct i40e_rss_filter *filter; + + TAILQ_FOREACH(filter, list, next) { + i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE); + } } static void @@ -12942,45 +12947,274 @@ i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, return 0; } -int -i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with) +/* Configure hash input set */ +static int +i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types) { - return (comp->func == with->func && - comp->level == with->level && - comp->types == with->types && - comp->key_len == with->key_len && - comp->queue_num == with->queue_num && - !memcmp(comp->key, with->key, with->key_len) && - !memcmp(comp->queue, with->queue, - sizeof(*with->queue) * with->queue_num)); + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct rte_eth_input_set_conf conf; + int i, ret; + uint32_t j; + static const struct { + uint64_t type; + enum rte_eth_input_set_field field; + } inset_match_table[] = { + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + }; + + ret = 0; + + for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(types & (1ULL << i))) + continue; + + conf.op = RTE_ETH_INPUT_SET_SELECT; + conf.flow_type = i; + conf.inset_size = 0; + for (j = 0; j < RTE_DIM(inset_match_table); j++) { + if ((types & inset_match_table[j].type) == + inset_match_table[j].type) { + if (inset_match_table[j].field == + RTE_ETH_INPUT_SET_UNKNOWN) { + return -EINVAL; + } + conf.field[conf.inset_size] = + inset_match_table[j].field; + conf.inset_size++; + } + } + + if (conf.inset_size) { + ret = i40e_hash_filter_inset_select(hw, &conf); + if (ret) + return ret; + } + } + + return ret; } -int -i40e_config_rss_filter(struct i40e_pf *pf, - struct i40e_rte_flow_rss_conf *conf, bool add) +/* Look up the conflicted rule then mark it as invalid */ +static void +i40e_rss_mark_invalid_rule(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_rss_filter *rss_item; + uint64_t rss_inset; + + /* Clear input set bits before comparing the pctype */ + rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY | + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY); + + TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) { + if (!rss_item->rss_filter_info.valid) + continue; + + /* Rule for queue region */ + if (conf->conf.queue_num && + rss_item->rss_filter_info.conf.queue_num) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash input set */ + if (conf->conf.types && + (rss_item->rss_filter_info.conf.types & + rss_inset) == + (conf->conf.types & rss_inset)) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash function */ + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + rss_item->rss_filter_info.conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + rss_item->rss_filter_info.valid = false; + } +} + +/* Configure RSS hash function */ +static int +i40e_rss_config_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) { struct i40e_hw *hw = I40E_PF_TO_HW(pf); - uint32_t i, lut = 0; - uint16_t j, num; - struct rte_eth_rss_conf rss_conf = { - .rss_key = conf->conf.key_len ? - (void *)(uintptr_t)conf->conf.key : NULL, - .rss_key_len = conf->conf.key_len, - .rss_hf = conf->conf.types, - }; - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t reg, i; + uint16_t j; - if (!add) { - if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) { - i40e_pf_disable_rss(pf); - memset(rss_info, 0, - sizeof(struct i40e_rte_flow_rss_conf)); - return 0; + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) { + i40e_set_symmetric_hash_enable_per_port(hw, 1); + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (!(mask0 & (1UL << i))) + continue; + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + I40E_GLQF_HSYM_SYMH_ENA_MASK); + } } + + return 0; + } + + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) { + PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR"); + goto out; + } + reg &= ~I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Enable RSS according to the configuration */ +static int +i40e_rss_enable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, + struct rte_eth_rss_conf *rss_conf) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + + if (!(rss_conf->rss_hf & pf->adapter->flow_types_mask)) + return -ENOTSUP; + + /* Configure hash input set */ + if (i40e_rss_conf_hash_inset(pf, rss_conf->rss_hf)) return -EINVAL; + + if (rss_conf->rss_key == NULL || rss_conf->rss_key_len < + (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { + /* Random default keys */ + static uint32_t rss_key_default[] = {0x6b793944, + 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, + 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, + 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; + + rss_conf->rss_key = (uint8_t *)rss_key_default; + rss_conf->rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * + sizeof(uint32_t); + PMD_DRV_LOG(INFO, + "No valid RSS key config for i40e, using default\n"); } + rss_conf->rss_hf |= rss_info->conf.types; + i40e_hw_rss_hash_set(pf, rss_conf); + + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) + i40e_rss_config_hash_function(pf, conf); + + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS queue region */ +static int +i40e_rss_config_queue_region(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint32_t i, lut; + uint16_t j, num; + /* If both VMDQ and RSS enabled, not all of PF queues are configured. * It's necessary to calculate the actual PF queues that are configured. */ @@ -13000,6 +13234,7 @@ i40e_config_rss_filter(struct i40e_pf *pf, return -ENOTSUP; } + lut = 0; /* Fill in redirection table */ for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { if (j == num) @@ -13010,29 +13245,203 @@ i40e_config_rss_filter(struct i40e_pf *pf, I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); } - if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) { - i40e_pf_disable_rss(pf); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS hash function to default */ +static int +i40e_rss_clear_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t i, reg; + uint16_t j; + + if (conf->conf.func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (mask0 & (1UL << i)) { + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & + (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + 0); + } + } + } + return 0; } - if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < - (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { - /* Random default keys */ - static uint32_t rss_key_default[] = {0x6b793944, - 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, - 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, - 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; - rss_conf.rss_key = (uint8_t *)rss_key_default; - rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * - sizeof(uint32_t); - PMD_DRV_LOG(INFO, - "No valid RSS key config for i40e, using default\n"); + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (reg & I40E_GLQF_CTL_HTOEP_MASK) { + PMD_DRV_LOG(DEBUG, + "Hash function already set to Toeplitz"); + goto out; } + reg |= I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + + return 0; +} +/* Disable RSS hash and configure default input set */ +static int +i40e_rss_disable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_eth_rss_conf rss_conf = { + .rss_key = pf->rss_info.conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = pf->rss_info.conf.key_len, + }; + uint32_t i; + + /* Disable RSS hash */ + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types); i40e_hw_rss_hash_set(pf, &rss_conf); - if (i40e_rss_conf_init(rss_info, &conf->conf)) - return -EINVAL; + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(conf->conf.types & (1ULL << i))) + continue; + + /* Configure default input set */ + struct rte_eth_input_set_conf input_conf = { + .op = RTE_ETH_INPUT_SET_SELECT, + .flow_type = i, + .inset_size = 1, + }; + input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT; + i40e_hash_filter_inset_select(hw, &input_conf); + } + + rss_info->conf.types = rss_conf.rss_hf; + + i40e_rss_clear_hash_function(pf, conf); + + return 0; +} + +/* Configure RSS queue region to default */ +static int +i40e_rss_clear_queue_region(struct i40e_pf *pf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint16_t queue[I40E_MAX_Q_PER_TC]; + uint32_t num_rxq, i, lut; + uint16_t j, num; + + num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, I40E_MAX_Q_PER_TC); + + for (j = 0; j < num_rxq; j++) + queue[j] = j; + + /* If both VMDQ and RSS enabled, not all of PF queues are configured. + * It's necessary to calculate the actual PF queues that are configured. + */ + if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG) + num = i40e_pf_calc_configured_queues_num(pf); + else + num = pf->dev_data->nb_rx_queues; + + num = RTE_MIN(num, num_rxq); + PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured", + num); + + if (num == 0) { + PMD_DRV_LOG(ERR, + "No PF queues are configured to enable RSS for port %u", + pf->dev_data->port_id); + return -ENOTSUP; + } + + lut = 0; + /* Fill in redirection table */ + for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { + if (j == num) + j = 0; + lut = (lut << 8) | (queue[j] & ((0x1 << + hw->func_caps.rss_table_entry_width) - 1)); + if ((i & 3) == 3) + I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); + } + + rss_info->conf.queue_num = 0; + memset(&rss_info->conf.queue, 0, sizeof(uint16_t)); + + return 0; +} + +int +i40e_config_rss_filter(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, bool add) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_flow_action_rss update_conf = rss_info->conf; + struct rte_eth_rss_conf rss_conf = { + .rss_key = conf->conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = conf->conf.key_len, + .rss_hf = conf->conf.types, + }; + int ret = 0; + + if (add) { + if (conf->conf.queue_num) { + /* Configure RSS queue region */ + ret = i40e_rss_config_queue_region(pf, conf); + if (ret) + return ret; + + update_conf.queue_num = conf->conf.queue_num; + update_conf.queue = conf->conf.queue; + } else if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + /* Configure hash function */ + ret = i40e_rss_config_hash_function(pf, conf); + if (ret) + return ret; + + update_conf.func = conf->conf.func; + } else { + /* Configure hash enable and input set */ + ret = i40e_rss_enable_hash(pf, conf, &rss_conf); + if (ret) + return ret; + + update_conf.types = rss_conf.rss_hf; + update_conf.key = rss_conf.rss_key; + update_conf.key_len = rss_conf.rss_key_len; + } + + /* Update RSS info in pf */ + if (i40e_rss_conf_init(rss_info, &update_conf)) + return -EINVAL; + } else { + if (!conf->valid) + return 0; + + if (conf->conf.queue_num) + i40e_rss_clear_queue_region(pf); + else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + i40e_rss_clear_hash_function(pf, conf); + else + i40e_rss_disable_hash(pf, conf); + } return 0; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..e9d90fa35 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -194,6 +194,9 @@ enum i40e_flxpld_layer_idx { #define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK \ I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT) +#define I40E_RSS_TYPE_NONE 0ULL +#define I40E_RSS_TYPE_INVALID 1ULL + #define I40E_INSET_NONE 0x00000000000000000ULL /* bit0 ~ bit 7 */ @@ -749,6 +752,11 @@ struct i40e_queue_regions { struct i40e_queue_region_info region[I40E_REGION_MAX_INDEX + 1]; }; +struct i40e_rss_pattern_info { + uint8_t action_flag; + uint64_t types; +}; + /* Tunnel filter number HW supports */ #define I40E_MAX_TUNNEL_FILTER_NUM 400 @@ -968,6 +976,15 @@ struct i40e_rte_flow_rss_conf { I40E_VFQF_HKEY_MAX_INDEX : I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)]; /* Hash key. */ uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. */ + bool valid; /* Check if it's valid */ +}; + +TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter); + +/* RSS filter list structure */ +struct i40e_rss_filter { + TAILQ_ENTRY(i40e_rss_filter) next; + struct i40e_rte_flow_rss_conf rss_filter_info; }; struct i40e_vf_msg_cfg { @@ -1038,7 +1055,8 @@ struct i40e_pf { struct i40e_fdir_info fdir; /* flow director info */ struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */ struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */ - struct i40e_rte_flow_rss_conf rss_info; /* rss info */ + struct i40e_rte_flow_rss_conf rss_info; /* RSS info */ + struct i40e_rss_conf_list rss_config_list; /* RSS rule list */ struct i40e_queue_regions queue_region; /* queue region info */ struct i40e_fc_conf fc_conf; /* Flow control conf */ struct i40e_mirror_rule_list mirror_list; @@ -1338,8 +1356,6 @@ int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len); int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size); int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, const struct rte_flow_action_rss *in); -int i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with); int i40e_config_rss_filter(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *conf, bool add); int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index d877ac250..f4f3c3abd 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -4424,29 +4424,80 @@ i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev, * function for RSS, or flowtype for queue region configuration. * For example: * pattern: - * Case 1: only ETH, indicate flowtype for queue region will be parsed. - * Case 2: only VLAN, indicate user_priority for queue region will be parsed. - * Case 3: none, indicate RSS related will be parsed in action. - * Any pattern other the ETH or VLAN will be treated as invalid except END. + * Case 1: try to transform patterns to pctype. valid pctype will be + * used in parse action. + * Case 2: only ETH, indicate flowtype for queue region will be parsed. + * Case 3: only VLAN, indicate user_priority for queue region will be parsed. * So, pattern choice is depened on the purpose of configuration of * that flow. * action: - * action RSS will be uaed to transmit valid parameter with + * action RSS will be used to transmit valid parameter with * struct rte_flow_action_rss for all the 3 case. */ static int i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - uint8_t *action_flag, + struct i40e_rss_pattern_info *p_info, struct i40e_queue_regions *info) { const struct rte_flow_item_vlan *vlan_spec, *vlan_mask; const struct rte_flow_item *item = pattern; enum rte_flow_item_type item_type; - - if (item->type == RTE_FLOW_ITEM_TYPE_END) + struct rte_flow_item *items; + uint32_t item_num = 0; /* non-void item number of pattern*/ + uint32_t i = 0; + static const struct { + enum rte_flow_item_type *item_array; + uint64_t type; + } i40e_rss_pctype_patterns[] = { + { pattern_fdir_ipv4, + ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER }, + { pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP }, + { pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP }, + { pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP }, + { pattern_fdir_ipv6, + ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER }, + { pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP }, + { pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP }, + { pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP }, + }; + + p_info->types = I40E_RSS_TYPE_INVALID; + + if (item->type == RTE_FLOW_ITEM_TYPE_END) { + p_info->types = I40E_RSS_TYPE_NONE; return 0; + } + + /* convert flow to pctype */ + while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { + if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID) + item_num++; + i++; + } + item_num++; + + items = rte_zmalloc("i40e_pattern", + item_num * sizeof(struct rte_flow_item), 0); + if (!items) { + rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM, + NULL, "No memory for PMD internal items."); + return -ENOMEM; + } + + i40e_pattern_skip_void_item(items, pattern); + + for (i = 0; i < RTE_DIM(i40e_rss_pctype_patterns); i++) { + if (i40e_match_pattern(i40e_rss_pctype_patterns[i].item_array, + items)) { + p_info->types = i40e_rss_pctype_patterns[i].type; + rte_free(items); + return 0; + } + } + + rte_free(items); for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { if (item->last) { @@ -4459,7 +4510,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, item_type = item->type; switch (item_type) { case RTE_FLOW_ITEM_TYPE_ETH: - *action_flag = 1; + p_info->action_flag = 1; break; case RTE_FLOW_ITEM_TYPE_VLAN: vlan_spec = item->spec; @@ -4472,7 +4523,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, vlan_spec->tci) >> 13) & 0x7; info->region[0].user_priority_num = 1; info->queue_region_number = 1; - *action_flag = 0; + p_info->action_flag = 0; } } break; @@ -4500,12 +4551,14 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, * max index should be 7, and so on. And also, queue index should be * continuous sequence and queue region index should be part of rss * queue index for this port. + * For hash params, the pctype in action and pattern must be same. + * Set queue index must be with non-types. */ static int i40e_flow_parse_rss_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - uint8_t action_flag, + struct i40e_rss_pattern_info p_info, struct i40e_queue_regions *conf_info, union i40e_filter_t *filter) { @@ -4516,7 +4569,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, struct i40e_rte_flow_rss_conf *rss_config = &filter->rss_conf; struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; - uint16_t i, j, n, tmp; + uint16_t i, j, n, tmp, nb_types; uint32_t index = 0; uint64_t hf_bit = 1; @@ -4535,7 +4588,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, return -rte_errno; } - if (action_flag) { + if (p_info.action_flag) { for (n = 0; n < 64; n++) { if (rss->types & (hf_bit << n)) { conf_info->region[0].hw_flowtype[0] = n; @@ -4674,11 +4727,11 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, if (rss_config->queue_region_conf) return 0; - if (!rss || !rss->queue_num) { + if (!rss) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, - "no valid queues"); + "invalid rule"); return -rte_errno; } @@ -4692,19 +4745,48 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, } } - if (rss_info->conf.queue_num) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, - act, - "rss only allow one valid rule"); - return -rte_errno; + if (rss->queue_num && (p_info.types || rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "rss types must be empty while configuring queue region"); + + /* validate pattern and pctype */ + if (!(rss->types & p_info.types) && + (rss->types || p_info.types) && !rss->queue_num) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + act, "invaild pctype"); + + nb_types = 0; + for (n = 0; n < RTE_ETH_FLOW_MAX; n++) { + if (rss->types & (hf_bit << n)) + nb_types++; + if (nb_types > 1) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, + act, "multi pctype is not supported"); } + if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + (p_info.types || rss->types || rss->queue_num)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pattern, type and queues must be empty while" + " setting hash function as simple_xor"); + + if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ && + !(p_info.types && rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pctype and queues can not be empty while" + " setting hash function as symmetric toeplitz"); + /* Parse RSS related parameters from configuration */ - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX || + rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, - "non-default RSS hash functions are not supported"); + "RSS hash functions are not supported"); if (rss->level) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, @@ -4746,19 +4828,20 @@ i40e_parse_rss_filter(struct rte_eth_dev *dev, union i40e_filter_t *filter, struct rte_flow_error *error) { - int ret; + struct i40e_rss_pattern_info p_info; struct i40e_queue_regions info; - uint8_t action_flag = 0; + int ret; memset(&info, 0, sizeof(struct i40e_queue_regions)); + memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info)); ret = i40e_flow_parse_rss_pattern(dev, pattern, - error, &action_flag, &info); + error, &p_info, &info); if (ret) return ret; ret = i40e_flow_parse_rss_action(dev, actions, error, - action_flag, &info, filter); + p_info, &info, filter); if (ret) return ret; @@ -4777,15 +4860,33 @@ i40e_config_rss_filter_set(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; int ret; if (conf->queue_region_conf) { ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1); - conf->queue_region_conf = 0; } else { ret = i40e_config_rss_filter(pf, conf, 1); } - return ret; + + if (ret) + return ret; + + rss_filter = rte_zmalloc("i40e_rss_filter", + sizeof(*rss_filter), 0); + if (rss_filter == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + rss_filter->rss_filter_info = *conf; + /* the rule new created is always valid + * the existing rule covered by new rule will be set invalid + */ + rss_filter->rss_filter_info.valid = true; + + TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next); + + return 0; } static int @@ -4794,10 +4895,21 @@ i40e_config_rss_filter_del(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; + void *temp; - i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + if (conf->queue_region_conf) + i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + else + i40e_config_rss_filter(pf, conf, 0); - i40e_config_rss_filter(pf, conf, 0); + TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) { + if (!memcmp(&rss_filter->rss_filter_info, conf, + sizeof(struct rte_flow_action_rss))) { + TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next); + rte_free(rss_filter); + } + } return 0; } @@ -4940,7 +5052,8 @@ i40e_flow_create(struct rte_eth_dev *dev, &cons_filter.rss_conf); if (ret) goto free_flow; - flow->rule = &pf->rss_info; + flow->rule = TAILQ_LAST(&pf->rss_config_list, + i40e_rss_conf_list); break; default: goto free_flow; @@ -4990,7 +5103,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, break; case RTE_ETH_FILTER_HASH: ret = i40e_config_rss_filter_del(dev, - (struct i40e_rte_flow_rss_conf *)flow->rule); + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); break; default: PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", @@ -5248,13 +5361,27 @@ static int i40e_flow_flush_rss_filter(struct rte_eth_dev *dev) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_flow *flow; + void *temp; int32_t ret = -EINVAL; ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0); - if (rss_info->conf.queue_num) - ret = i40e_config_rss_filter(pf, rss_info, FALSE); + /* Delete rss flows in flow list. */ + TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) { + if (flow->filter_type != RTE_ETH_FILTER_HASH) + continue; + + if (flow->rule) { + ret = i40e_config_rss_filter_del(dev, + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); + if (ret) + return ret; + } + TAILQ_REMOVE(&pf->flow_list, flow, node); + rte_free(flow); + } + return ret; } -- 2.17.1