[v6] net/i40e: implement hash function in rte flow API
Checks
Commit Message
implement set hash global configurations, set symmetric hash enable
and set hash input set in rte flow API.
Signed-off-by: Chenxu Di <chenxux.di@intel.com>
---
v6:
-Modified the docs and various name.
v5:
-Modified the doc i40e.rst and various name.
v4:
-added check for l3 pctype with l4 input set.
v3:
-modified the doc i40e.rst
v2:
-canceled remove legacy filter functions.
---
doc/guides/nics/i40e.rst | 14 +
doc/guides/rel_notes/release_20_05.rst | 7 +
drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++--
drivers/net/i40e/i40e_ethdev.h | 18 +
drivers/net/i40e/i40e_flow.c | 186 ++++++++--
5 files changed, 624 insertions(+), 72 deletions(-)
Comments
Hi Chenux,
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Chenxu Di
> Sent: Monday, March 30, 2020 8:40 AM
> To: dev@dpdk.org
> Cc: Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>; Di, ChenxuX
> <chenxux.di@intel.com>
> Subject: [dpdk-dev] [PATCH v6] net/i40e: implement hash function in rte
> flow API
>
> implement set hash global configurations, set symmetric hash enable and
> set hash input set in rte flow API.
>
> Signed-off-by: Chenxu Di <chenxux.di@intel.com>
> ---
> v6:
> -Modified the docs and various name.
> v5:
> -Modified the doc i40e.rst and various name.
> v4:
> -added check for l3 pctype with l4 input set.
> v3:
> -modified the doc i40e.rst
> v2:
> -canceled remove legacy filter functions.
> ---
> doc/guides/nics/i40e.rst | 14 +
> doc/guides/rel_notes/release_20_05.rst | 7 +
> drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++--
> drivers/net/i40e/i40e_ethdev.h | 18 +
> drivers/net/i40e/i40e_flow.c | 186 ++++++++--
> 5 files changed, 624 insertions(+), 72 deletions(-)
>
> diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> d6e578eda..92590dadc 100644
> --- a/doc/guides/nics/i40e.rst
> +++ b/doc/guides/nics/i40e.rst
> @@ -569,6 +569,20 @@ 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
> +~~~~~~~~~~~~~~~~~~~
> +Enable set hash input set and hash enable in generic flow API.
> +For the reason queue region configuration in i40e is for all PCTYPE,
> +pctype must be empty while configuring queue region.
> +The pctype in pattern and actions must be matched.
> +Exampale, set queue region configuration queue 0, 1, 2, 3 and Enable
> +hash for ipv4-tcp and configure input set with l3-src-only:
> +
> + testpmd> flow create 0 ingress pattern end actions rss types end \
> + queues 0 1 2 3 end / end
> + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \
> + actions rss types ipv4-tcp l3-src-only end queues end / 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..92c314e66 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_info_list);
> +
> /* initialize Traffic Manager configuration */
> i40e_tm_conf_init(dev);
>
> @@ -12329,10 +12332,12 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)
> 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 *rss_list = &pf->rss_info_list;
> + struct i40e_flow_rss_filter *rss_item;
> +
> + TAILQ_FOREACH(rss_item, rss_list, next) {
> + i40e_config_rss_filter(pf, &rss_item->rss_filter_info, TRUE);
> + }
> }
>
> static void
> @@ -12956,31 +12961,234 @@ i40e_action_rss_same(const struct
> rte_flow_action_rss *comp,
> sizeof(*with->queue) * with->queue_num)); }
>
> -int
> -i40e_config_rss_filter(struct i40e_pf *pf,
> - struct i40e_rte_flow_rss_conf *conf, bool add)
> +/* config rss hash input set */
> +static int
> +i40e_config_rss_inputset(struct i40e_pf *pf, uint64_t types)
> {
> 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 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_type_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},
> };
> - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
>
> - if (!add) {
> - if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) {
The function i40e_action_rss_same() is no longer used.
Should it be removed from i40e_ethdev.c and i40e_ethdev.h?
> - i40e_pf_disable_rss(pf);
> - memset(rss_info, 0,
> - sizeof(struct i40e_rte_flow_rss_conf));
> - return 0;
> + ret = 0;
> +
> + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD;
> 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_type_table); j++) {
> + if ((types & inset_type_table[j].type) ==
> + inset_type_table[j].type) {
> + if (inset_type_table[j].field ==
> + RTE_ETH_INPUT_SET_UNKNOWN) {
> + return -EINVAL;
> + }
> + conf.field[conf.inset_size] =
> + inset_type_table[j].field;
> + conf.inset_size++;
> + }
> }
> +
> + if (conf.inset_size) {
> + ret = i40e_hash_filter_inset_select(hw, &conf);
> + if (ret)
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/* set existing rule invalid if it is covered */ static void
> +i40e_config_rss_invalidate_previous_rule(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_flow_rss_filter *rss_item;
> + uint64_t rss_inset;
> +
> + /* to check pctype same need without input set bits */
> + 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_info_list, next) {
> + if (!rss_item->rss_filter_info.valid)
> + continue;
> +
> + /* config rss queue rule */
> + if (conf->conf.queue_num &&
> + rss_item->rss_filter_info.conf.queue_num)
> + rss_item->rss_filter_info.valid = false;
> +
> + /* config rss input set rule */
> + 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;
> +
> + /* config rss function symmetric rule */
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
> + rss_item->rss_filter_info.conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
> + rss_item->rss_filter_info.valid = false;
> +
> + /* config rss function xor or toeplitz rule */
> + if (rss_item->rss_filter_info.conf.func !=
> + RTE_ETH_HASH_FUNCTION_DEFAULT &&
> + conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT
> &&
> + (rss_item->rss_filter_info.conf.types & rss_inset) ==
> + (conf->conf.types & rss_inset))
> + rss_item->rss_filter_info.valid = false;
> + }
> +}
> +
> +/* config rss hash enable and set hash input set */ static int
> +i40e_config_hash_pctype_add(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;
> +
> + /* Confirm hash input set */
> + if (i40e_config_rss_inputset(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);
> +
> + i40e_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss queue region */
> +static int
> +i40e_config_hash_queue_add(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 +13208,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 +13219,215 @@ 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_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss hash function */
> +static int
> +i40e_config_hash_function_add(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + struct rte_eth_hash_global_conf g_cfg;
> + uint64_t rss_inset;
> +
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){
> + i40e_set_symmetric_hash_enable_per_port(hw, 1);
> + } else {
> + rss_inset = ~(ETH_RSS_L3_SRC_ONLY |
> ETH_RSS_L3_DST_ONLY |
> + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
> + g_cfg.hash_func = conf->conf.func;
> + g_cfg.sym_hash_enable_mask[0] = conf->conf.types &
> rss_inset;
> + g_cfg.valid_bit_mask[0] = conf->conf.types & rss_inset;
> + i40e_set_hash_filter_global_config(hw, &g_cfg);
> + }
> +
> + i40e_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss hena disable and set hash input set to defalut */
Typo: defalut should be default in above comment.
static
> +int i40e_config_hash_pctype_del(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;
> +
> + /* set hash enable register to disable */
> + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types);
> + i40e_hw_rss_hash_set(pf, &rss_conf);
> +
> + 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;
> +
> + /* set hash input set default */
> + 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;
> +
> + return 0;
> +}
> +
> +/* config rss queue region to default */ static int
> +i40e_config_hash_queue_del(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;
> +}
> +
> +/* config rss hash function to default */ static int
> +i40e_config_hash_function_del(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + uint32_t i;
> + uint16_t j;
> +
> + /* set symmetric hash to default status */
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
> + i40e_set_symmetric_hash_enable_per_port(hw, 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");
> + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD;
> i++) {
> + if (!(conf->conf.types & (1ull << i)))
> + continue;
> +
> + /* set hash global config disable */
> + 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);
> + }
> }
>
> - i40e_hw_rss_hash_set(pf, &rss_conf);
> + return 0;
> +}
>
> - if (i40e_rss_conf_init(rss_info, &conf->conf))
> - return -EINVAL;
> +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) {
> + /* config rss queue region */
> + ret = i40e_config_hash_queue_add(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_DEFAULT) {
> + /* config hash function */
> + ret = i40e_config_hash_function_add(pf, conf);
> + if (ret)
> + return ret;
> +
> + update_conf.func = conf->conf.func;
> + } else {
> + /* config hash enable and input set for each pctype
> */
> + ret = i40e_config_hash_pctype_add(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_config_hash_queue_del(pf);
> + else if (conf->conf.func !=
> RTE_ETH_HASH_FUNCTION_DEFAULT)
> + i40e_config_hash_function_del(pf, conf);
> + else
> + i40e_config_hash_pctype_del(pf, conf);
> + }
>
> return 0;
> }
> diff --git a/drivers/net/i40e/i40e_ethdev.h
> b/drivers/net/i40e/i40e_ethdev.h index aac89de91..929e6b7c7 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_flow_rss_filter);
> +
> +/* rss filter list structure */
> +struct i40e_flow_rss_filter {
> + TAILQ_ENTRY(i40e_flow_rss_filter) next;
> + struct i40e_rte_flow_rss_conf rss_filter_info;
> };
>
> struct i40e_vf_msg_cfg {
> @@ -1039,6 +1056,7 @@ struct i40e_pf {
> 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_rss_conf_list rss_info_list; /* rss rull 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; diff --git
> a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index
> d877ac250..d67cd648e 100644
> --- a/drivers/net/i40e/i40e_flow.c
> +++ b/drivers/net/i40e/i40e_flow.c
> @@ -4424,10 +4424,10 @@ 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:
> @@ -4438,15 +4438,66 @@ 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 or symmetric hash enable 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");
> + "no valid rules");
> return -rte_errno;
> }
>
> @@ -4692,19 +4745,40 @@ 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,
> + "pctype 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_SYMMETRIC_TOEPLITZ
> &&
> + (p_info.types || rss->types || rss->queue_num))
> + return rte_flow_error_set
> + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
> act,
> + "pctype and queues must be empty while"
> + " setting SYMMETRIC hash function");
> +
> /* Parse RSS related parameters from configuration */
> - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
> + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX)
> 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, @@ -4748,17 +4822,18 @@ i40e_parse_rss_filter(struct rte_eth_dev
> *dev, {
> int ret;
> struct i40e_queue_regions info;
> - uint8_t action_flag = 0;
> + struct i40e_rss_pattern_info p_info;
>
> 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 +4852,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_flow_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_flow_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 rull new created is always valid
> + * the existing rull covered by new rull will be set invalid
> + */
> + rss_filter->rss_filter_info.valid = true;
> +
> + TAILQ_INSERT_TAIL(&pf->rss_info_list, rss_filter, next);
> +
> + return 0;
> }
>
> static int
> @@ -4794,10 +4887,20 @@ 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_flow_rss_filter *rss_filter;
>
> - 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(rss_filter, &pf->rss_info_list, next) {
> + if (!memcmp(&rss_filter->rss_filter_info, conf,
> + sizeof(struct rte_flow_action_rss))) {
> + TAILQ_REMOVE(&pf->rss_info_list, rss_filter, next);
> + rte_free(rss_filter);
> + }
> + }
> return 0;
> }
>
> @@ -4940,7 +5043,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_info_list,
> + i40e_rss_conf_list);
> break;
> default:
> goto free_flow;
> @@ -4990,7 +5094,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_flow_rss_filter *)flow->rule)-
> >rss_filter_info);
> break;
> default:
> PMD_DRV_LOG(WARNING, "Filter type (%d) not
> supported", @@ -5248,13 +5352,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_flow_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
Regards,
Bernard
Hi Chenxu,
<snip>
> > > -----Original Message-----
> > > From: dev <dev-bounces@dpdk.org> On Behalf Of Chenxu Di
> > > Sent: Monday, March 30, 2020 8:40 AM
> > > To: dev@dpdk.org
> > > Cc: Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> > > <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>; Di,
> > > ChenxuX <chenxux.di@intel.com>
> > > Subject: [dpdk-dev] [PATCH v6] net/i40e: implement hash function in
> > > rte flow API
> > >
> > > implement set hash global configurations, set symmetric hash enable
> > > and set hash input set in rte flow API.
> > >
> > > Signed-off-by: Chenxu Di <chenxux.di@intel.com>
>
> [snip]
>
> > > -struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
> > >
> > > -if (!add) {
> > > -if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) {
> >
> >
> > The function i40e_action_rss_same() is no longer used.
> > Should it be removed from i40e_ethdev.c and i40e_ethdev.h?
> >
>
> It seems like no one use the function.
> However I check the commit of the function and find the
> commit(ac8d22de23) is so large.
> I don't know it is ok if remove it.
Best to check with Qi or Beilei if it is ok to remove this function.
>
> >
> > > -i40e_pf_disable_rss(pf);
> > > -memset(rss_info, 0,
> > > -sizeof(struct i40e_rte_flow_rss_conf)); -return 0;
> > > +ret = 0;
> > > +
> > > +for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD;
> > > 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_type_table);
> > > +j++) { if ((types &
> > > +inset_type_table[j].type) ==
> > > + inset_type_table[j].type) {
> > > +if (inset_type_table[j].field ==
> > > + RTE_ETH_INPUT_SET_UNKNOWN) {
> > > +return -EINVAL;
> > > +}
> > > +conf.field[conf.inset_size] =
> > > +inset_type_table[j].field;
> > > +conf.inset_size++;
> > > +}
> > > }
> > > +
> > > +if (conf.inset_size) {
> > > +ret = i40e_hash_filter_inset_select(hw, &conf); if (ret) return
> > > +ret; } }
> > > +
> > > +return ret;
> > > +}
> > > +
> > > +/* set existing rule invalid if it is covered */ static void
> > > +i40e_config_rss_invalidate_previous_rule(struct i40e_pf *pf, struct
> > > +i40e_rte_flow_rss_conf *conf) { struct i40e_flow_rss_filter
> > > +*rss_item; uint64_t rss_inset;
> > > +
> > > +/* to check pctype same need without input set bits */ 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_info_list, next) { if
> > > +(!rss_item->rss_filter_info.valid)
> > > +continue;
> > > +
> > > +/* config rss queue rule */
> > > +if (conf->conf.queue_num &&
> > > + rss_item->rss_filter_info.conf.queue_num)
> > > +rss_item->rss_filter_info.valid = false;
> > > +
> > > +/* config rss input set rule */
> > > +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;
> > > +
> > > +/* config rss function symmetric rule */ if (conf->conf.func ==
> > > + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
> > > + rss_item->rss_filter_info.conf.func ==
> > > + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
> > > +rss_item->rss_filter_info.valid = false;
> > > +
> > > +/* config rss function xor or toeplitz rule */ if
> > > +(rss_item->rss_filter_info.conf.func !=
> > > + RTE_ETH_HASH_FUNCTION_DEFAULT &&
> > > + conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT
> > > &&
> > > + (rss_item->rss_filter_info.conf.types & rss_inset) ==
> > > + (conf->conf.types & rss_inset)) rss_item->rss_filter_info.valid
> > > += false; } }
> > > +
> > > +/* config rss hash enable and set hash input set */ static int
> > > +i40e_config_hash_pctype_add(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;
> > > +
> > > +/* Confirm hash input set */
> > > +if (i40e_config_rss_inputset(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);
> > > +
> > > +i40e_config_rss_invalidate_previous_rule(pf, conf);
> > > +
> > > +return 0;
> > > +}
> > > +
> > > +/* config rss queue region */
> > > +static int
> > > +i40e_config_hash_queue_add(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 +13208,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 +13219,215 @@
> > > 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_config_rss_invalidate_previous_rule(pf, conf);
> > > +
> > > +return 0;
> > > +}
> > > +
> > > +/* config rss hash function */
> > > +static int
> > > +i40e_config_hash_function_add(struct i40e_pf *pf, struct
> > > +i40e_rte_flow_rss_conf *conf) { struct i40e_hw *hw =
> > > +I40E_PF_TO_HW(pf); struct rte_eth_hash_global_conf g_cfg; uint64_t
> > > +rss_inset;
> > > +
> > > +if (conf->conf.func ==
> > > +RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){
> > > +i40e_set_symmetric_hash_enable_per_port(hw, 1); } else { rss_inset
> > > += ~(ETH_RSS_L3_SRC_ONLY |
> > > ETH_RSS_L3_DST_ONLY |
> > > + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY); g_cfg.hash_func
> =
> > > +conf->conf.func; g_cfg.sym_hash_enable_mask[0] = conf->conf.types
> &
> > > rss_inset;
> > > +g_cfg.valid_bit_mask[0] = conf->conf.types & rss_inset;
> > > +i40e_set_hash_filter_global_config(hw, &g_cfg); }
> > > +
> > > +i40e_config_rss_invalidate_previous_rule(pf, conf);
> > > +
> > > +return 0;
> > > +}
> > > +
> > > +/* config rss hena disable and set hash input set to defalut */
> >
> > Typo: defalut should be default in above comment.
> >
>
> Yeah ,I will fix it
>
> > static
> > > +int i40e_config_hash_pctype_del(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;
> > > +
>
> [snip]
>
> > > --
> > > 2.17.1
> >
Regards,
Bernard
> -----Original Message-----
> From: Di, ChenxuX <chenxux.di@intel.com>
> Sent: Monday, March 30, 2020 3:40 PM
> To: dev@dpdk.org
> Cc: Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>; Di, ChenxuX
> <chenxux.di@intel.com>
> Subject: [PATCH v6] net/i40e: implement hash function in rte flow API
>
> implement set hash global configurations, set symmetric hash enable and
> set hash input set in rte flow API.
>
> Signed-off-by: Chenxu Di <chenxux.di@intel.com>
> ---
> v6:
> -Modified the docs and various name.
> v5:
> -Modified the doc i40e.rst and various name.
> v4:
> -added check for l3 pctype with l4 input set.
> v3:
> -modified the doc i40e.rst
> v2:
> -canceled remove legacy filter functions.
> ---
> doc/guides/nics/i40e.rst | 14 +
> doc/guides/rel_notes/release_20_05.rst | 7 +
> drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++--
> drivers/net/i40e/i40e_ethdev.h | 18 +
> drivers/net/i40e/i40e_flow.c | 186 ++++++++--
> 5 files changed, 624 insertions(+), 72 deletions(-)
>
> diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> d6e578eda..92590dadc 100644
> --- a/doc/guides/nics/i40e.rst
> +++ b/doc/guides/nics/i40e.rst
> @@ -569,6 +569,20 @@ 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
> +~~~~~~~~~~~~~~~~~~~
> +Enable set hash input set and hash enable in generic flow API.
> +For the reason queue region configuration in i40e is for all PCTYPE,
> +pctype must be empty while configuring queue region.
> +The pctype in pattern and actions must be matched.
> +Exampale, set queue region configuration queue 0, 1, 2, 3 and Enable
> +hash for ipv4-tcp and configure input set with l3-src-only:
> +
> + testpmd> flow create 0 ingress pattern end actions rss types end \
> + queues 0 1 2 3 end / end
> + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \
> + actions rss types ipv4-tcp l3-src-only end queues end / 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..92c314e66 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_info_list);
> +
> /* initialize Traffic Manager configuration */
> i40e_tm_conf_init(dev);
>
> @@ -12329,10 +12332,12 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)
> 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 *rss_list = &pf->rss_info_list;
> + struct i40e_flow_rss_filter *rss_item;
> +
> + TAILQ_FOREACH(rss_item, rss_list, next) {
> + i40e_config_rss_filter(pf, &rss_item->rss_filter_info, TRUE);
> + }
> }
>
> static void
> @@ -12956,31 +12961,234 @@ i40e_action_rss_same(const struct
> rte_flow_action_rss *comp,
> sizeof(*with->queue) * with->queue_num)); }
>
> -int
> -i40e_config_rss_filter(struct i40e_pf *pf,
> - struct i40e_rte_flow_rss_conf *conf, bool add)
> +/* config rss hash input set */
> +static int
> +i40e_config_rss_inputset(struct i40e_pf *pf, uint64_t types)
> {
> 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 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_type_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},
> };
> - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
>
> - 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;
> + ret = 0;
> +
> + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++)
> {
> + if (!(pf->adapter->flow_types_mask & (1ull << i)) ||
> + !(types & (1ull << i)))
> + continue;
> +
> + conf.op = RTE_ETH_INPUT_SET_SELECT;
Is conf.op still used?
> + conf.flow_type = i;
> + conf.inset_size = 0;
> + for (j = 0; j < RTE_DIM(inset_type_table); j++) {
> + if ((types & inset_type_table[j].type) ==
> + inset_type_table[j].type) {
> + if (inset_type_table[j].field ==
> + RTE_ETH_INPUT_SET_UNKNOWN) {
> + return -EINVAL;
> + }
> + conf.field[conf.inset_size] =
> + inset_type_table[j].field;
> + conf.inset_size++;
> + }
> }
> +
> + if (conf.inset_size) {
> + ret = i40e_hash_filter_inset_select(hw, &conf);
> + if (ret)
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +/* set existing rule invalid if it is covered */ static void
> +i40e_config_rss_invalidate_previous_rule(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_flow_rss_filter *rss_item;
> + uint64_t rss_inset;
> +
> + /* to check pctype same need without input set bits */
What's does it mean?
> + 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_info_list, next) {
> + if (!rss_item->rss_filter_info.valid)
> + continue;
> +
> + /* config rss queue rule */
> + if (conf->conf.queue_num &&
> + rss_item->rss_filter_info.conf.queue_num)
> + rss_item->rss_filter_info.valid = false;
> +
> + /* config rss input set rule */
It's better to check and rework all the comments.
> + 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;
> +
> + /* config rss function symmetric rule */
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
> + rss_item->rss_filter_info.conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
> + rss_item->rss_filter_info.valid = false;
> +
> + /* config rss function xor or toeplitz rule */
> + if (rss_item->rss_filter_info.conf.func !=
> + RTE_ETH_HASH_FUNCTION_DEFAULT &&
> + conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT
> &&
> + (rss_item->rss_filter_info.conf.types & rss_inset) ==
> + (conf->conf.types & rss_inset))
> + rss_item->rss_filter_info.valid = false;
> + }
> +}
> +
> +/* config rss hash enable and set hash input set */ static int
> +i40e_config_hash_pctype_add(struct i40e_pf *pf,
Is it for config rss hash
> + 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;
> +
> + /* Confirm hash input set */
> + if (i40e_config_rss_inputset(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);
> +
> + i40e_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss queue region */
> +static int
> +i40e_config_hash_queue_add(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 +13208,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 +13219,215 @@ 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_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss hash function */
> +static int
> +i40e_config_hash_function_add(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + struct rte_eth_hash_global_conf g_cfg;
> + uint64_t rss_inset;
> +
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){
> + i40e_set_symmetric_hash_enable_per_port(hw, 1);
> + } else {
> + rss_inset = ~(ETH_RSS_L3_SRC_ONLY |
> ETH_RSS_L3_DST_ONLY |
> + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
> + g_cfg.hash_func = conf->conf.func;
> + g_cfg.sym_hash_enable_mask[0] = conf->conf.types &
> rss_inset;
> + g_cfg.valid_bit_mask[0] = conf->conf.types & rss_inset;
> + i40e_set_hash_filter_global_config(hw, &g_cfg);
> + }
> +
> + i40e_config_rss_invalidate_previous_rule(pf, conf);
> +
> + return 0;
> +}
> +
> +/* config rss hena disable and set hash input set to defalut */ static
Disable RSS hash and configure default input set
> +int i40e_config_hash_pctype_del(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;
> +
> + /* set hash enable register to disable */
> + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types);
> + i40e_hw_rss_hash_set(pf, &rss_conf);
> +
> + 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;
> +
> + /* set hash input set default */
> + 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;
> +
> + return 0;
> +}
> +
> +/* config rss queue region to default */ static int
> +i40e_config_hash_queue_del(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;
> +}
> +
> +/* config rss hash function to default */ static int
> +i40e_config_hash_function_del(struct i40e_pf *pf,
> + struct i40e_rte_flow_rss_conf *conf)
> +{
> + struct i40e_hw *hw = I40E_PF_TO_HW(pf);
> + uint32_t i;
> + uint16_t j;
> +
> + /* set symmetric hash to default status */
> + if (conf->conf.func ==
> + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
> + i40e_set_symmetric_hash_enable_per_port(hw, 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");
> + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++)
> {
> + if (!(conf->conf.types & (1ull << i)))
> + continue;
> +
> + /* set hash global config disable */
> + 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);
> + }
> }
>
> - i40e_hw_rss_hash_set(pf, &rss_conf);
> + return 0;
> +}
>
> - if (i40e_rss_conf_init(rss_info, &conf->conf))
> - return -EINVAL;
> +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) {
> + /* config rss queue region */
> + ret = i40e_config_hash_queue_add(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_DEFAULT) {
> + /* config hash function */
> + ret = i40e_config_hash_function_add(pf, conf);
> + if (ret)
> + return ret;
> +
> + update_conf.func = conf->conf.func;
> + } else {
> + /* config hash enable and input set for each pctype
> */
> + ret = i40e_config_hash_pctype_add(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_config_hash_queue_del(pf);
> + else if (conf->conf.func !=
> RTE_ETH_HASH_FUNCTION_DEFAULT)
> + i40e_config_hash_function_del(pf, conf);
> + else
> + i40e_config_hash_pctype_del(pf, conf);
> + }
>
> return 0;
> }
> diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
> index aac89de91..929e6b7c7 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_flow_rss_filter);
> +
> +/* rss filter list structure */
> +struct i40e_flow_rss_filter {
> + TAILQ_ENTRY(i40e_flow_rss_filter) next;
> + struct i40e_rte_flow_rss_conf rss_filter_info;
> };
>
> struct i40e_vf_msg_cfg {
> @@ -1039,6 +1056,7 @@ struct i40e_pf {
> 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_rss_conf_list rss_info_list; /* rss rull list */
Rull->rule?
> 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; diff --git
> a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index
> d877ac250..d67cd648e 100644
> --- a/drivers/net/i40e/i40e_flow.c
> +++ b/drivers/net/i40e/i40e_flow.c
> @@ -4424,10 +4424,10 @@ 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:
> @@ -4438,15 +4438,66 @@ 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 or symmetric hash enable 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");
> + "no valid rules");
> return -rte_errno;
> }
>
> @@ -4692,19 +4745,40 @@ 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,
> + "pctype 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_SYMMETRIC_TOEPLITZ
> &&
> + (p_info.types || rss->types || rss->queue_num))
> + return rte_flow_error_set
> + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
> act,
> + "pctype and queues must be empty while"
> + " setting SYMMETRIC hash function");
> +
> /* Parse RSS related parameters from configuration */
> - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
> + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX)
> 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, @@ -4748,17 +4822,18 @@ i40e_parse_rss_filter(struct rte_eth_dev
> *dev, {
> int ret;
> struct i40e_queue_regions info;
> - uint8_t action_flag = 0;
> + struct i40e_rss_pattern_info p_info;
>
> 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 +4852,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_flow_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_flow_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 rull new created is always valid
> + * the existing rull covered by new rull will be set invalid
> + */
Rull-> rule?
> + rss_filter->rss_filter_info.valid = true;
> +
> + TAILQ_INSERT_TAIL(&pf->rss_info_list, rss_filter, next);
> +
> + return 0;
> }
>
> static int
> @@ -4794,10 +4887,20 @@ 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_flow_rss_filter *rss_filter;
>
> - 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(rss_filter, &pf->rss_info_list, next) {
Better to use TAILQ_FOREACH_SAFE since there's TAILQ_REMOVE.
> + if (!memcmp(&rss_filter->rss_filter_info, conf,
> + sizeof(struct rte_flow_action_rss))) {
> + TAILQ_REMOVE(&pf->rss_info_list, rss_filter, next);
> + rte_free(rss_filter);
> + }
> + }
> return 0;
> }
>
> @@ -4940,7 +5043,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_info_list,
> + i40e_rss_conf_list);
> break;
> default:
> goto free_flow;
> @@ -4990,7 +5094,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_flow_rss_filter *)flow->rule)-
> >rss_filter_info);
> break;
> default:
> PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
> @@ -5248,13 +5352,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_flow_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
@@ -569,6 +569,20 @@ 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
+~~~~~~~~~~~~~~~~~~~
+Enable set hash input set and hash enable in generic flow API.
+For the reason queue region configuration in i40e is for all PCTYPE,
+pctype must be empty while configuring queue region.
+The pctype in pattern and actions must be matched.
+Exampale, set queue region configuration queue 0, 1, 2, 3 and
+Enable hash for ipv4-tcp and configure input set with l3-src-only:
+
+ testpmd> flow create 0 ingress pattern end actions rss types end \
+ queues 0 1 2 3 end / end
+ testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \
+ actions rss types ipv4-tcp l3-src-only end queues end / end
+
Limitations or Known issues
---------------------------
@@ -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
-------------
@@ -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_info_list);
+
/* initialize Traffic Manager configuration */
i40e_tm_conf_init(dev);
@@ -12329,10 +12332,12 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)
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 *rss_list = &pf->rss_info_list;
+ struct i40e_flow_rss_filter *rss_item;
+
+ TAILQ_FOREACH(rss_item, rss_list, next) {
+ i40e_config_rss_filter(pf, &rss_item->rss_filter_info, TRUE);
+ }
}
static void
@@ -12956,31 +12961,234 @@ i40e_action_rss_same(const struct rte_flow_action_rss *comp,
sizeof(*with->queue) * with->queue_num));
}
-int
-i40e_config_rss_filter(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf, bool add)
+/* config rss hash input set */
+static int
+i40e_config_rss_inputset(struct i40e_pf *pf, uint64_t types)
{
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 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_type_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},
};
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- 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;
+ ret = 0;
+
+ for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; 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_type_table); j++) {
+ if ((types & inset_type_table[j].type) ==
+ inset_type_table[j].type) {
+ if (inset_type_table[j].field ==
+ RTE_ETH_INPUT_SET_UNKNOWN) {
+ return -EINVAL;
+ }
+ conf.field[conf.inset_size] =
+ inset_type_table[j].field;
+ conf.inset_size++;
+ }
}
+
+ if (conf.inset_size) {
+ ret = i40e_hash_filter_inset_select(hw, &conf);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/* set existing rule invalid if it is covered */
+static void
+i40e_config_rss_invalidate_previous_rule(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ struct i40e_flow_rss_filter *rss_item;
+ uint64_t rss_inset;
+
+ /* to check pctype same need without input set bits */
+ 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_info_list, next) {
+ if (!rss_item->rss_filter_info.valid)
+ continue;
+
+ /* config rss queue rule */
+ if (conf->conf.queue_num &&
+ rss_item->rss_filter_info.conf.queue_num)
+ rss_item->rss_filter_info.valid = false;
+
+ /* config rss input set rule */
+ 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;
+
+ /* config rss function symmetric rule */
+ if (conf->conf.func ==
+ RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
+ rss_item->rss_filter_info.conf.func ==
+ RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
+ rss_item->rss_filter_info.valid = false;
+
+ /* config rss function xor or toeplitz rule */
+ if (rss_item->rss_filter_info.conf.func !=
+ RTE_ETH_HASH_FUNCTION_DEFAULT &&
+ conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT &&
+ (rss_item->rss_filter_info.conf.types & rss_inset) ==
+ (conf->conf.types & rss_inset))
+ rss_item->rss_filter_info.valid = false;
+ }
+}
+
+/* config rss hash enable and set hash input set */
+static int
+i40e_config_hash_pctype_add(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;
+
+ /* Confirm hash input set */
+ if (i40e_config_rss_inputset(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);
+
+ i40e_config_rss_invalidate_previous_rule(pf, conf);
+
+ return 0;
+}
+
+/* config rss queue region */
+static int
+i40e_config_hash_queue_add(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 +13208,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 +13219,215 @@ 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_config_rss_invalidate_previous_rule(pf, conf);
+
+ return 0;
+}
+
+/* config rss hash function */
+static int
+i40e_config_hash_function_add(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct rte_eth_hash_global_conf g_cfg;
+ uint64_t rss_inset;
+
+ if (conf->conf.func ==
+ RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){
+ i40e_set_symmetric_hash_enable_per_port(hw, 1);
+ } else {
+ rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY |
+ ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
+ g_cfg.hash_func = conf->conf.func;
+ g_cfg.sym_hash_enable_mask[0] = conf->conf.types & rss_inset;
+ g_cfg.valid_bit_mask[0] = conf->conf.types & rss_inset;
+ i40e_set_hash_filter_global_config(hw, &g_cfg);
+ }
+
+ i40e_config_rss_invalidate_previous_rule(pf, conf);
+
+ return 0;
+}
+
+/* config rss hena disable and set hash input set to defalut */
+static int
+i40e_config_hash_pctype_del(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;
+
+ /* set hash enable register to disable */
+ rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types);
+ i40e_hw_rss_hash_set(pf, &rss_conf);
+
+ 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;
+
+ /* set hash input set default */
+ 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;
+
+ return 0;
+}
+
+/* config rss queue region to default */
+static int
+i40e_config_hash_queue_del(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;
+}
+
+/* config rss hash function to default */
+static int
+i40e_config_hash_function_del(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ uint32_t i;
+ uint16_t j;
+
+ /* set symmetric hash to default status */
+ if (conf->conf.func ==
+ RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+ i40e_set_symmetric_hash_enable_per_port(hw, 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");
+ for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) {
+ if (!(conf->conf.types & (1ull << i)))
+ continue;
+
+ /* set hash global config disable */
+ 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);
+ }
}
- i40e_hw_rss_hash_set(pf, &rss_conf);
+ return 0;
+}
- if (i40e_rss_conf_init(rss_info, &conf->conf))
- return -EINVAL;
+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) {
+ /* config rss queue region */
+ ret = i40e_config_hash_queue_add(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_DEFAULT) {
+ /* config hash function */
+ ret = i40e_config_hash_function_add(pf, conf);
+ if (ret)
+ return ret;
+
+ update_conf.func = conf->conf.func;
+ } else {
+ /* config hash enable and input set for each pctype */
+ ret = i40e_config_hash_pctype_add(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_config_hash_queue_del(pf);
+ else if (conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT)
+ i40e_config_hash_function_del(pf, conf);
+ else
+ i40e_config_hash_pctype_del(pf, conf);
+ }
return 0;
}
@@ -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_flow_rss_filter);
+
+/* rss filter list structure */
+struct i40e_flow_rss_filter {
+ TAILQ_ENTRY(i40e_flow_rss_filter) next;
+ struct i40e_rte_flow_rss_conf rss_filter_info;
};
struct i40e_vf_msg_cfg {
@@ -1039,6 +1056,7 @@ struct i40e_pf {
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_rss_conf_list rss_info_list; /* rss rull 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;
@@ -4424,10 +4424,10 @@ 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:
@@ -4438,15 +4438,66 @@ 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 or symmetric hash enable 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");
+ "no valid rules");
return -rte_errno;
}
@@ -4692,19 +4745,40 @@ 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,
+ "pctype 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_SYMMETRIC_TOEPLITZ &&
+ (p_info.types || rss->types || rss->queue_num))
+ return rte_flow_error_set
+ (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "pctype and queues must be empty while"
+ " setting SYMMETRIC hash function");
+
/* Parse RSS related parameters from configuration */
- if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
+ if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX)
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,
@@ -4748,17 +4822,18 @@ i40e_parse_rss_filter(struct rte_eth_dev *dev,
{
int ret;
struct i40e_queue_regions info;
- uint8_t action_flag = 0;
+ struct i40e_rss_pattern_info p_info;
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 +4852,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_flow_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_flow_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 rull new created is always valid
+ * the existing rull covered by new rull will be set invalid
+ */
+ rss_filter->rss_filter_info.valid = true;
+
+ TAILQ_INSERT_TAIL(&pf->rss_info_list, rss_filter, next);
+
+ return 0;
}
static int
@@ -4794,10 +4887,20 @@ 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_flow_rss_filter *rss_filter;
- 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(rss_filter, &pf->rss_info_list, next) {
+ if (!memcmp(&rss_filter->rss_filter_info, conf,
+ sizeof(struct rte_flow_action_rss))) {
+ TAILQ_REMOVE(&pf->rss_info_list, rss_filter, next);
+ rte_free(rss_filter);
+ }
+ }
return 0;
}
@@ -4940,7 +5043,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_info_list,
+ i40e_rss_conf_list);
break;
default:
goto free_flow;
@@ -4990,7 +5094,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_flow_rss_filter *)flow->rule)->rss_filter_info);
break;
default:
PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
@@ -5248,13 +5352,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_flow_rss_filter *)flow->rule)->rss_filter_info);
+ if (ret)
+ return ret;
+ }
+ TAILQ_REMOVE(&pf->flow_list, flow, node);
+ rte_free(flow);
+ }
+
return ret;
}