@@ -585,9 +585,9 @@ Generic flow API
- ``RSS Flow``
RSS Flow supports to set hash input set, hash function, enable hash
- and configure queue region.
+ and configure queues.
For example:
- Configure queue region as queue 0, 1, 2, 3.
+ Configure queues as queue 0, 1, 2, 3.
.. code-block:: console
@@ -39,6 +39,7 @@
#include "i40e_pf.h"
#include "i40e_regs.h"
#include "rte_pmd_i40e.h"
+#include "i40e_hash.h"
#define ETH_I40E_FLOATING_VEB_ARG "enable_floating_veb"
#define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list"
@@ -399,7 +400,6 @@ static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf,
static void i40e_tunnel_filter_restore(struct i40e_pf *pf);
static void i40e_filter_restore(struct i40e_pf *pf);
static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev);
-static int i40e_pf_config_rss(struct i40e_pf *pf);
static const char *const valid_keys[] = {
ETH_I40E_FLOATING_VEB_ARG,
@@ -1767,10 +1767,6 @@ static inline void i40e_config_automask(struct i40e_pf *pf)
/* initialize queue region configuration */
i40e_init_queue_region_conf(dev);
- /* initialize RSS configuration from rte_flow */
- memset(&pf->rss_info, 0,
- sizeof(struct i40e_rte_flow_rss_conf));
-
/* reset all stats of the device, including pf and main vsi */
i40e_dev_stats_reset(dev);
@@ -4542,7 +4538,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
{
struct i40e_pf *pf;
struct i40e_hw *hw;
- int ret;
if (!vsi || !lut)
return -EINVAL;
@@ -4551,12 +4546,16 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
hw = I40E_VSI_TO_HW(vsi);
if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
- ret = i40e_aq_set_rss_lut(hw, vsi->vsi_id,
- vsi->type != I40E_VSI_SRIOV,
- lut, lut_size);
- if (ret) {
- PMD_DRV_LOG(ERR, "Failed to set RSS lookup table");
- return ret;
+ enum i40e_status_code status;
+
+ status = i40e_aq_set_rss_lut(hw, vsi->vsi_id,
+ vsi->type != I40E_VSI_SRIOV,
+ lut, lut_size);
+ if (status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to update RSS lookup table, error status: %d",
+ status);
+ return -EIO;
}
} else {
uint32_t *lut_dw = (uint32_t *)lut;
@@ -7689,7 +7688,7 @@ struct i40e_vsi *
}
/* Disable RSS */
-static void
+void
i40e_pf_disable_rss(struct i40e_pf *pf)
{
struct i40e_hw *hw = I40E_PF_TO_HW(pf);
@@ -7707,7 +7706,6 @@ struct i40e_vsi *
uint16_t key_idx = (vsi->type == I40E_VSI_SRIOV) ?
I40E_VFQF_HKEY_MAX_INDEX :
I40E_PFQF_HKEY_MAX_INDEX;
- int ret = 0;
if (!key || key_len == 0) {
PMD_DRV_LOG(DEBUG, "No key to be configured");
@@ -7720,11 +7718,16 @@ struct i40e_vsi *
if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
struct i40e_aqc_get_set_rss_key_data *key_dw =
- (struct i40e_aqc_get_set_rss_key_data *)key;
+ (struct i40e_aqc_get_set_rss_key_data *)key;
+ enum i40e_status_code status =
+ i40e_aq_set_rss_key(hw, vsi->vsi_id, key_dw);
- ret = i40e_aq_set_rss_key(hw, vsi->vsi_id, key_dw);
- if (ret)
- PMD_INIT_LOG(ERR, "Failed to configure RSS key via AQ");
+ if (status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to configure RSS key via AQ, error status: %d",
+ status);
+ return -EIO;
+ }
} else {
uint32_t *hash_key = (uint32_t *)key;
uint16_t i;
@@ -7744,7 +7747,7 @@ struct i40e_vsi *
I40E_WRITE_FLUSH(hw);
}
- return ret;
+ return 0;
}
static int
@@ -9037,7 +9040,7 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
}
/* Calculate the maximum number of contiguous PF queues that are configured */
-static int
+int
i40e_pf_calc_configured_queues_num(struct i40e_pf *pf)
{
struct rte_eth_dev_data *data = pf->dev_data;
@@ -9056,19 +9059,72 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
return num;
}
-/* Configure RSS */
-static int
-i40e_pf_config_rss(struct i40e_pf *pf)
+/* Reset the global configure of hash function and input sets */
+static void
+i40e_pf_global_rss_reset(struct i40e_pf *pf)
{
- enum rte_eth_rx_mq_mode mq_mode = pf->dev_data->dev_conf.rxmode.mq_mode;
struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct rte_eth_rss_conf rss_conf;
- uint32_t i, lut = 0;
- uint16_t j, num;
+ uint32_t reg, reg_val;
+ int i;
- /*
- * 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.
+ /* Reset global RSS function sets */
+ reg_val = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
+ if (!(reg_val & I40E_GLQF_CTL_HTOEP_MASK)) {
+ reg_val |= I40E_GLQF_CTL_HTOEP_MASK;
+ i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg_val);
+ }
+
+ for (i = 0; i <= I40E_FILTER_PCTYPE_L2_PAYLOAD; i++) {
+ uint64_t inset;
+ int j, pctype;
+
+ if (hw->mac.type == I40E_MAC_X722)
+ pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(i));
+ else
+ pctype = i;
+
+ /* Reset pctype insets */
+ inset = i40e_get_default_input_set(i);
+ if (inset) {
+ pf->hash_input_set[pctype] = inset;
+ inset = i40e_translate_input_set_reg(hw->mac.type,
+ inset);
+
+ reg = I40E_GLQF_HASH_INSET(0, pctype);
+ i40e_check_write_global_reg(hw, reg, (uint32_t)inset);
+ reg = I40E_GLQF_HASH_INSET(1, pctype);
+ i40e_check_write_global_reg(hw, reg,
+ (uint32_t)(inset >> 32));
+
+ /* Clear unused mask registers of the pctype */
+ for (j = 0; j < I40E_INSET_MASK_NUM_REG; j++) {
+ reg = I40E_GLQF_HASH_MSK(j, pctype);
+ i40e_check_write_global_reg(hw, reg, 0);
+ }
+ }
+
+ /* Reset pctype symmetric sets */
+ reg = I40E_GLQF_HSYM(pctype);
+ reg_val = i40e_read_rx_ctl(hw, reg);
+ if (reg_val & I40E_GLQF_HSYM_SYMH_ENA_MASK) {
+ reg_val &= ~I40E_GLQF_HSYM_SYMH_ENA_MASK;
+ i40e_write_global_rx_ctl(hw, reg, reg_val);
+ }
+ }
+ I40E_WRITE_FLUSH(hw);
+}
+
+int
+i40e_pf_reset_rss_reta(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = &pf->adapter->hw;
+ uint8_t lut[ETH_RSS_RETA_SIZE_512];
+ uint32_t i;
+ int 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.
*/
if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
num = i40e_pf_calc_configured_queues_num(pf);
@@ -9076,48 +9132,89 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
num = pf->dev_data->nb_rx_queues;
num = RTE_MIN(num, I40E_MAX_Q_PER_TC);
- PMD_INIT_LOG(INFO, "Max of contiguous %u PF queues are configured",
- num);
+ if (num <= 0)
+ return 0;
- if (num == 0) {
- PMD_INIT_LOG(ERR,
- "No PF queues are configured to enable RSS for port %u",
- pf->dev_data->port_id);
- return -ENOTSUP;
- }
+ for (i = 0; i < hw->func_caps.rss_table_size; i++)
+ lut[i] = (uint8_t)(i % (uint32_t)num);
- if (pf->adapter->rss_reta_updated == 0) {
- for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
- if (j == num)
- j = 0;
- lut = (lut << 8) | (j & ((0x1 <<
- hw->func_caps.rss_table_entry_width) - 1));
- if ((i & 3) == 3)
- I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2),
- rte_bswap32(lut));
- }
- }
+ return i40e_set_rss_lut(pf->main_vsi, lut, (uint16_t)i);
+}
- rss_conf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf;
- if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0 ||
- !(mq_mode & ETH_MQ_RX_RSS_FLAG)) {
- i40e_pf_disable_rss(pf);
- 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 */
+int
+i40e_pf_reset_rss_key(struct i40e_pf *pf)
+{
+ const uint8_t key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+ sizeof(uint32_t);
+ uint8_t *rss_key;
+
+ /* Reset key */
+ rss_key = pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_key;
+ if (!rss_key ||
+ pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_key_len < key_len) {
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);
+ rss_key = (uint8_t *)rss_key_default;
+ }
+
+ return i40e_set_rss_key(pf->main_vsi, rss_key, key_len);
+}
+
+static int
+i40e_pf_rss_reset(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+
+ int ret;
+
+ pf->hash_filter_enable = 0;
+ i40e_pf_disable_rss(pf);
+ i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+ if (!pf->support_multi_driver)
+ i40e_pf_global_rss_reset(pf);
+
+ /* Reset RETA table */
+ if (pf->adapter->rss_reta_updated == 0) {
+ ret = i40e_pf_reset_rss_reta(pf);
+ if (ret)
+ return ret;
+ }
+
+ return i40e_pf_reset_rss_key(pf);
+}
+
+/* Configure RSS */
+int
+i40e_pf_config_rss(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw;
+ enum rte_eth_rx_mq_mode mq_mode;
+ uint64_t rss_hf, hena;
+ int ret;
+
+ ret = i40e_pf_rss_reset(pf);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Reset RSS failed, RSS has been disabled");
+ return ret;
}
- return i40e_hw_rss_hash_set(pf, &rss_conf);
+ rss_hf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
+ mq_mode = pf->dev_data->dev_conf.rxmode.mq_mode;
+ if (!(rss_hf & pf->adapter->flow_types_mask) ||
+ !(mq_mode & ETH_MQ_RX_RSS_FLAG))
+ return 0;
+
+ hw = I40E_PF_TO_HW(pf);
+ hena = i40e_config_hena(pf->adapter, rss_hf);
+ i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
+ i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}
static int
@@ -9283,24 +9380,20 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
}
/* Set the symmetric hash enable configurations per port */
-static void
+void
i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
{
uint32_t reg = i40e_read_rx_ctl(hw, I40E_PRTQF_CTL_0);
if (enable > 0) {
- if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
- PMD_DRV_LOG(INFO,
- "Symmetric hash has already been enabled");
+ if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)
return;
- }
+
reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
} else {
- if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
- PMD_DRV_LOG(INFO,
- "Symmetric hash has already been disabled");
+ if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK))
return;
- }
+
reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
}
i40e_write_rx_ctl(hw, I40E_PRTQF_CTL_0, reg);
@@ -10151,9 +10244,8 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
{
struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
enum i40e_filter_pctype pctype;
- uint64_t input_set, inset_reg = 0;
- uint32_t mask_reg[I40E_INSET_MASK_NUM_REG] = {0};
- int ret, i, num;
+ uint64_t input_set;
+ int ret;
if (!conf) {
PMD_DRV_LOG(ERR, "Invalid pointer");
@@ -10165,31 +10257,42 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
return -EINVAL;
}
- if (pf->support_multi_driver) {
- PMD_DRV_LOG(ERR, "Hash input set setting is not supported.");
- return -ENOTSUP;
- }
-
pctype = i40e_flowtype_to_pctype(pf->adapter, conf->flow_type);
if (pctype == I40E_FILTER_PCTYPE_INVALID) {
PMD_DRV_LOG(ERR, "invalid flow_type input.");
return -EINVAL;
}
- if (hw->mac.type == I40E_MAC_X722) {
- /* get translated pctype value in fd pctype register */
- pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl(hw,
- I40E_GLQF_FD_PCTYPES((int)pctype));
- }
-
ret = i40e_parse_input_set(&input_set, pctype, conf->field,
conf->inset_size);
- if (ret) {
- PMD_DRV_LOG(ERR, "Failed to parse input set");
- return -EINVAL;
+ if (ret)
+ return ret;
+
+ return i40e_set_hash_inset(hw, input_set, pctype,
+ (conf->op == RTE_ETH_INPUT_SET_ADD) ?
+ true : false);
+}
+
+int
+i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,
+ uint32_t pctype, bool add)
+{
+ struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
+ uint32_t mask_reg[I40E_INSET_MASK_NUM_REG] = {0};
+ uint64_t inset_reg = 0;
+ int num, i;
+
+ if (pf->support_multi_driver) {
+ PMD_DRV_LOG(ERR,
+ "Modify input set is not permitted when multi-driver enabled.");
+ return -EPERM;
}
- if (conf->op == RTE_ETH_INPUT_SET_ADD) {
+ /* For X722, get translated pctype in fd pctype register */
+ if (hw->mac.type == I40E_MAC_X722)
+ pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+ if (add) {
/* get inset value in register */
inset_reg = i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, pctype));
inset_reg <<= I40E_32_BIT_WIDTH;
@@ -12623,25 +12726,13 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
}
}
-/* Restore RSS filter */
-static inline void
-i40e_rss_filter_restore(struct i40e_pf *pf)
-{
- struct i40e_rss_conf_list *list = &pf->rss_config_list;
- struct i40e_rss_filter *filter;
-
- TAILQ_FOREACH(filter, list, next) {
- i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE);
- }
-}
-
static void
i40e_filter_restore(struct i40e_pf *pf)
{
i40e_ethertype_filter_restore(pf);
i40e_tunnel_filter_restore(pf);
i40e_fdir_filter_restore(pf);
- i40e_rss_filter_restore(pf);
+ (void)i40e_hash_filter_restore(pf);
}
bool
@@ -13219,551 +13310,6 @@ struct i40e_customized_pctype*
return ret;
}
-int
-i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
- const struct rte_flow_action_rss *in)
-{
- if (in->key_len > RTE_DIM(out->key) ||
- in->queue_num > RTE_DIM(out->queue))
- return -EINVAL;
- if (!in->key && in->key_len)
- return -EINVAL;
- out->conf = (struct rte_flow_action_rss){
- .func = in->func,
- .level = in->level,
- .types = in->types,
- .key_len = in->key_len,
- .queue_num = in->queue_num,
- .queue = memcpy(out->queue, in->queue,
- sizeof(*in->queue) * in->queue_num),
- };
- if (in->key)
- out->conf.key = memcpy(out->key, in->key, in->key_len);
- return 0;
-}
-
-/* Write HENA register to enable hash */
-static int
-i40e_rss_hash_set(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *rss_conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint8_t *key = (void *)(uintptr_t)rss_conf->conf.key;
- uint64_t hena;
- int ret;
-
- ret = i40e_set_rss_key(pf->main_vsi, key,
- rss_conf->conf.key_len);
- if (ret)
- return ret;
-
- hena = i40e_config_hena(pf->adapter, rss_conf->conf.types);
- i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
- i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
- I40E_WRITE_FLUSH(hw);
-
- return 0;
-}
-
-/* Configure hash input set */
-static int
-i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct rte_eth_input_set_conf conf;
- uint64_t mask0;
- int ret = 0;
- uint32_t j;
- int i;
- static const struct {
- uint64_t type;
- enum rte_eth_input_set_field field;
- } inset_match_table[] = {
- {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP4},
- {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP4},
- {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
- {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
-
- {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP4},
- {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP4},
- {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP4},
- {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP4},
- {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP4},
- {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP4},
- {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP4},
- {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP4},
- {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
- {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
-
- {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP6},
- {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP6},
- {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
- {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
-
- {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP6},
- {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP6},
- {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP6},
- {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP6},
- {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP6},
- {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP6},
- {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
- {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
-
- {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY,
- RTE_ETH_INPUT_SET_L3_SRC_IP6},
- {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY,
- RTE_ETH_INPUT_SET_L3_DST_IP6},
- {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
- {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY,
- RTE_ETH_INPUT_SET_UNKNOWN},
- };
-
- mask0 = types & pf->adapter->flow_types_mask;
- conf.op = RTE_ETH_INPUT_SET_SELECT;
- conf.inset_size = 0;
- for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) {
- if (mask0 & (1ULL << i)) {
- conf.flow_type = i;
- break;
- }
- }
-
- for (j = 0; j < RTE_DIM(inset_match_table); j++) {
- if ((types & inset_match_table[j].type) ==
- inset_match_table[j].type) {
- if (inset_match_table[j].field ==
- RTE_ETH_INPUT_SET_UNKNOWN)
- return -EINVAL;
-
- conf.field[conf.inset_size] =
- inset_match_table[j].field;
- conf.inset_size++;
- }
- }
-
- if (conf.inset_size) {
- ret = i40e_hash_filter_inset_select(hw, &conf);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-/* Look up the conflicted rule then mark it as invalid */
-static void
-i40e_rss_mark_invalid_rule(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_rss_filter *rss_item;
- uint64_t rss_inset;
-
- /* Clear input set bits before comparing the pctype */
- rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY |
- ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
-
- /* Look up the conflicted rule then mark it as invalid */
- TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) {
- if (!rss_item->rss_filter_info.valid)
- continue;
-
- if (conf->conf.queue_num &&
- rss_item->rss_filter_info.conf.queue_num)
- rss_item->rss_filter_info.valid = false;
-
- 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;
-
- if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
- rss_item->rss_filter_info.conf.func ==
- RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
- rss_item->rss_filter_info.valid = false;
- }
-}
-
-/* Configure RSS hash function */
-static int
-i40e_rss_config_hash_function(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint32_t reg, i;
- uint64_t mask0;
- uint16_t j;
-
- if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
- reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
- if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
- PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR");
- I40E_WRITE_FLUSH(hw);
- i40e_rss_mark_invalid_rule(pf, conf);
-
- return 0;
- }
- reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
-
- i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
- I40E_WRITE_FLUSH(hw);
- i40e_rss_mark_invalid_rule(pf, conf);
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
- mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
- i40e_set_symmetric_hash_enable_per_port(hw, 1);
- for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
- if (mask0 & (1UL << i))
- break;
- }
-
- if (i == UINT64_BIT)
- return -EINVAL;
-
- for (j = I40E_FILTER_PCTYPE_INVALID + 1;
- j < I40E_FILTER_PCTYPE_MAX; j++) {
- if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
- i40e_write_global_rx_ctl(hw,
- I40E_GLQF_HSYM(j),
- I40E_GLQF_HSYM_SYMH_ENA_MASK);
- }
- }
-
- return 0;
-}
-
-/* Enable RSS according to the configuration */
-static int
-i40e_rss_enable_hash(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct i40e_rte_flow_rss_conf rss_conf;
-
- if (!(conf->conf.types & pf->adapter->flow_types_mask))
- return -ENOTSUP;
-
- memset(&rss_conf, 0, sizeof(rss_conf));
- rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
- /* Configure hash input set */
- if (i40e_rss_conf_hash_inset(pf, conf->conf.types))
- return -EINVAL;
-
- if (rss_conf.conf.key == NULL || rss_conf.conf.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.conf.key = (uint8_t *)rss_key_default;
- rss_conf.conf.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.conf.types |= rss_info->conf.types;
- i40e_rss_hash_set(pf, &rss_conf);
-
- if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
- i40e_rss_config_hash_function(pf, conf);
-
- i40e_rss_mark_invalid_rule(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS queue region */
-static int
-i40e_rss_config_queue_region(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint32_t lut = 0;
- uint16_t j, num;
- uint32_t i;
-
- /* 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, conf->conf.queue_num);
- 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;
- }
-
- /* 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) | (conf->conf.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);
- }
-
- i40e_rss_mark_invalid_rule(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS hash function to default */
-static int
-i40e_rss_clear_hash_function(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint32_t i, reg;
- uint64_t mask0;
- uint16_t j;
-
- if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
- reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
- if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
- PMD_DRV_LOG(DEBUG,
- "Hash function already set to Toeplitz");
- I40E_WRITE_FLUSH(hw);
-
- return 0;
- }
- reg |= I40E_GLQF_CTL_HTOEP_MASK;
-
- i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
- I40E_WRITE_FLUSH(hw);
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
- mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
- for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
- if (mask0 & (1UL << i))
- break;
- }
-
- if (i == UINT64_BIT)
- return -EINVAL;
-
- for (j = I40E_FILTER_PCTYPE_INVALID + 1;
- j < I40E_FILTER_PCTYPE_MAX; j++) {
- if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
- i40e_write_global_rx_ctl(hw,
- I40E_GLQF_HSYM(j),
- 0);
- }
- }
-
- return 0;
-}
-
-/* Disable RSS hash and configure default input set */
-static int
-i40e_rss_disable_hash(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct i40e_rte_flow_rss_conf rss_conf;
- uint32_t i;
-
- memset(&rss_conf, 0, sizeof(rss_conf));
- rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
- /* Disable RSS hash */
- rss_conf.conf.types = rss_info->conf.types & ~(conf->conf.types);
- i40e_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;
-
- /* Configure default input set */
- struct rte_eth_input_set_conf input_conf = {
- .op = RTE_ETH_INPUT_SET_SELECT,
- .flow_type = i,
- .inset_size = 1,
- };
- input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT;
- i40e_hash_filter_inset_select(hw, &input_conf);
- }
-
- rss_info->conf.types = rss_conf.conf.types;
-
- i40e_rss_clear_hash_function(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS queue region to default */
-static int
-i40e_rss_clear_queue_region(struct i40e_pf *pf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- uint16_t queue[I40E_MAX_Q_PER_TC];
- uint32_t num_rxq, i;
- uint32_t lut = 0;
- 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;
- }
-
- /* Fill in redirection table */
- for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
- if (j == num)
- j = 0;
- lut = (lut << 8) | (queue[j] & ((0x1 <<
- hw->func_caps.rss_table_entry_width) - 1));
- if ((i & 3) == 3)
- I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
- }
-
- rss_info->conf.queue_num = 0;
- memset(&rss_info->conf.queue, 0, sizeof(uint16_t));
-
- return 0;
-}
-
-int
-i40e_config_rss_filter(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf, bool add)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct rte_flow_action_rss update_conf = rss_info->conf;
- int ret = 0;
-
- if (add) {
- if (conf->conf.queue_num) {
- /* Configure RSS queue region */
- ret = i40e_rss_config_queue_region(pf, conf);
- if (ret)
- return ret;
-
- update_conf.queue_num = conf->conf.queue_num;
- update_conf.queue = conf->conf.queue;
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
- /* Configure hash function */
- ret = i40e_rss_config_hash_function(pf, conf);
- if (ret)
- return ret;
-
- update_conf.func = conf->conf.func;
- } else {
- /* Configure hash enable and input set */
- ret = i40e_rss_enable_hash(pf, conf);
- if (ret)
- return ret;
-
- update_conf.types |= conf->conf.types;
- update_conf.key = conf->conf.key;
- update_conf.key_len = conf->conf.key_len;
- }
-
- /* Update RSS info in pf */
- if (i40e_rss_conf_init(rss_info, &update_conf))
- return -EINVAL;
- } else {
- if (!conf->valid)
- return 0;
-
- if (conf->conf.queue_num)
- i40e_rss_clear_queue_region(pf);
- else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
- i40e_rss_clear_hash_function(pf, conf);
- else
- i40e_rss_disable_hash(pf, conf);
- }
-
- return 0;
-}
-
RTE_LOG_REGISTER(i40e_logtype_init, pmd.net.i40e.init, NOTICE);
RTE_LOG_REGISTER(i40e_logtype_driver, pmd.net.i40e.driver, NOTICE);
#ifdef RTE_LIBRTE_I40E_DEBUG_RX
@@ -16,6 +16,8 @@
#include "rte_pmd_i40e.h"
#include "base/i40e_register.h"
+#include "base/i40e_type.h"
+#include "base/virtchnl.h"
#define I40E_VLAN_TAG_SIZE 4
@@ -1047,17 +1049,24 @@ struct i40e_customized_pctype {
bool valid; /* Check if it's valid */
};
+#define I40E_MAX_PCTYPE_PER_RSS 8
+
struct i40e_rte_flow_rss_conf {
- struct rte_flow_action_rss conf; /**< RSS parameters. */
- uint16_t queue_region_conf; /**< Queue region config flag */
+ struct rte_flow_action_rss conf; /**< RSS parameters. */
+
uint8_t key[(I40E_VFQF_HKEY_MAX_INDEX > I40E_PFQF_HKEY_MAX_INDEX ?
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 */
-};
+ sizeof(uint32_t)]; /**< Hash key. */
+ uint16_t queue[ETH_RSS_RETA_SIZE_512]; /**< Queues indices to use. */
-TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter);
+ uint8_t pctypes[I40E_MAX_PCTYPE_PER_RSS];
+ uint8_t pctype_count;
+
+ uint8_t region_flags; /**< configure a queue region, yes(1)/no(0) */
+ uint8_t region_priority;/**< queue region priority */
+ uint8_t region_queue_num;
+ uint16_t region_queue_start;
+};
/* RSS filter list structure */
struct i40e_rss_filter {
@@ -1065,6 +1074,8 @@ struct i40e_rss_filter {
struct i40e_rte_flow_rss_conf rss_filter_info;
};
+TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter);
+
struct i40e_vf_msg_cfg {
/* maximal VF message during a statistic period */
uint32_t max_msg;
@@ -1119,6 +1130,7 @@ struct i40e_pf {
uint16_t fdir_qp_offset;
uint16_t hash_lut_size; /* The size of hash lookup table */
+ uint64_t hash_enabled_queues;
/* input set bits for each pctype */
uint64_t hash_input_set[I40E_FILTER_PCTYPE_MAX];
/* store VXLAN UDP ports */
@@ -1133,7 +1145,6 @@ struct i40e_pf {
struct i40e_fdir_info fdir; /* flow director info */
struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */
struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */
- struct i40e_rte_flow_rss_conf rss_info; /* RSS info */
struct i40e_rss_conf_list rss_config_list; /* RSS rule list */
struct i40e_queue_regions queue_region; /* queue region info */
struct i40e_fc_conf fc_conf; /* Flow control conf */
@@ -1151,7 +1162,7 @@ struct i40e_pf {
bool dport_replace_flag; /* Destination port replace is done */
struct i40e_tm_conf tm_conf;
bool support_multi_driver; /* 1 - support multiple driver */
-
+ bool hash_filter_enable;
/* Dynamic Device Personalization */
bool gtp_support; /* 1 - support GTP-C and GTP-U */
bool esp_support; /* 1 - support ESP SPI */
@@ -1364,6 +1375,8 @@ int i40e_select_filter_input_set(struct i40e_hw *hw,
struct rte_eth_input_set_conf *conf,
enum rte_filter_type filter);
void i40e_fdir_filter_restore(struct i40e_pf *pf);
+int i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,
+ uint32_t pctype, bool add);
int i40e_hash_filter_inset_select(struct i40e_hw *hw,
struct rte_eth_input_set_conf *conf);
int i40e_fdir_filter_inset_select(struct i40e_pf *pf,
@@ -1425,7 +1438,8 @@ int i40e_add_macvlan_filters(struct i40e_vsi *vsi,
bool is_device_supported(struct rte_eth_dev *dev, struct rte_pci_driver *drv);
bool is_i40e_supported(struct rte_eth_dev *dev);
bool is_i40evf_supported(struct rte_eth_dev *dev);
-
+void i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw,
+ uint8_t enable);
int i40e_validate_input_set(enum i40e_filter_pctype pctype,
enum rte_filter_type filter, uint64_t inset);
int i40e_generate_inset_mask_reg(uint64_t inset, uint32_t *mask,
@@ -1448,12 +1462,13 @@ int i40e_flush_queue_region_all_conf(struct rte_eth_dev *dev,
struct i40e_hw *hw, struct i40e_pf *pf, uint16_t on);
void i40e_init_queue_region_conf(struct rte_eth_dev *dev);
void i40e_flex_payload_reg_set_default(struct i40e_hw *hw);
+void i40e_pf_disable_rss(struct i40e_pf *pf);
+int i40e_pf_calc_configured_queues_num(struct i40e_pf *pf);
+int i40e_pf_reset_rss_reta(struct i40e_pf *pf);
+int i40e_pf_reset_rss_key(struct i40e_pf *pf);
+int i40e_pf_config_rss(struct i40e_pf *pf);
int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len);
int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size);
-int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
- const struct rte_flow_action_rss *in);
-int i40e_config_rss_filter(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf, bool add);
int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params);
int i40e_vf_representor_uninit(struct rte_eth_dev *ethdev);
@@ -23,6 +23,7 @@
#include "base/i40e_type.h"
#include "base/i40e_prototype.h"
#include "i40e_ethdev.h"
+#include "i40e_hash.h"
#define I40E_IPV6_TC_MASK (0xFF << I40E_FDIR_IPv6_TC_OFFSET)
#define I40E_IPV6_FRAG_HEADER 44
@@ -115,7 +116,6 @@ static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
static int i40e_flow_flush_ethertype_filter(struct i40e_pf *pf);
static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
-static int i40e_flow_flush_rss_filter(struct rte_eth_dev *dev);
static int
i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
@@ -4699,566 +4699,6 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
return ret;
}
-/**
- * This function is used to do configuration i40e existing RSS with rte_flow.
- * It also enable queue region configuration using flow API for i40e.
- * pattern can be used indicate what parameters will be include in flow,
- * like user_priority or flowtype for queue region or HASH function for RSS.
- * Action is used to transmit parameter like queue index and HASH
- * function for RSS, or flowtype for queue region configuration.
- * For example:
- * pattern:
- * Case 1: try to transform patterns to pctype. valid pctype will be
- * used in parse action.
- * Case 2: only ETH, indicate flowtype for queue region will be parsed.
- * Case 3: only VLAN, indicate user_priority for queue region will be parsed.
- * So, pattern choice is depened on the purpose of configuration of
- * that flow.
- * action:
- * action RSS will be used to transmit valid parameter with
- * struct rte_flow_action_rss for all the 3 case.
- */
-static int
-i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev,
- const struct rte_flow_item *pattern,
- struct rte_flow_error *error,
- 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;
- 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_ipv4_esp, ETH_RSS_ESP },
- { pattern_fdir_ipv4_udp_esp, ETH_RSS_ESP },
- { 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 },
- { pattern_ethertype, ETH_RSS_L2_PAYLOAD },
- { pattern_fdir_ipv6_esp, ETH_RSS_ESP },
- { pattern_fdir_ipv6_udp_esp, ETH_RSS_ESP },
- };
-
- 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 pattern to RSS offload types */
- 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;
- break;
- }
- }
-
- rte_free(items);
-
- for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
- if (item->last) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ITEM,
- item,
- "Not support range");
- return -rte_errno;
- }
- item_type = item->type;
- switch (item_type) {
- case RTE_FLOW_ITEM_TYPE_ETH:
- p_info->action_flag = 1;
- break;
- case RTE_FLOW_ITEM_TYPE_VLAN:
- vlan_spec = item->spec;
- vlan_mask = item->mask;
- if (vlan_spec && vlan_mask) {
- if (vlan_mask->tci ==
- rte_cpu_to_be_16(I40E_TCI_MASK)) {
- info->region[0].user_priority[0] =
- (rte_be_to_cpu_16(
- vlan_spec->tci) >> 13) & 0x7;
- info->region[0].user_priority_num = 1;
- info->queue_region_number = 1;
- p_info->action_flag = 0;
- }
- }
- break;
- default:
- p_info->action_flag = 0;
- memset(info, 0, sizeof(struct i40e_queue_regions));
- return 0;
- }
- }
-
- return 0;
-}
-
-/**
- * This function is used to parse RSS queue index, total queue number and
- * hash functions, If the purpose of this configuration is for queue region
- * configuration, it will set queue_region_conf flag to TRUE, else to FALSE.
- * In queue region configuration, it also need to parse hardware flowtype
- * and user_priority from configuration, it will also cheeck the validity
- * of these parameters. For example, The queue region sizes should
- * be any of the following values: 1, 2, 4, 8, 16, 32, 64, the
- * hw_flowtype or PCTYPE max index should be 63, the user priority
- * max index should be 7, and so on. And also, queue index should be
- * continuous sequence and queue region index should be part of RSS
- * queue index for this port.
- * For hash params, the pctype in action and pattern must be same.
- * Set queue index must be with non-types.
- */
-static int
-i40e_flow_parse_rss_action(struct rte_eth_dev *dev,
- const struct rte_flow_action *actions,
- struct rte_flow_error *error,
- struct i40e_rss_pattern_info p_info,
- struct i40e_queue_regions *conf_info,
- union i40e_filter_t *filter)
-{
- const struct rte_flow_action *act;
- const struct rte_flow_action_rss *rss;
- 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_queue_regions *info = &pf->queue_region;
- 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, m, tmp, nb_types;
- uint32_t index = 0;
- uint64_t hf_bit = 1;
-
- static const struct {
- uint64_t rss_type;
- enum i40e_filter_pctype pctype;
- } pctype_match_table[] = {
- {ETH_RSS_FRAG_IPV4,
- I40E_FILTER_PCTYPE_FRAG_IPV4},
- {ETH_RSS_NONFRAG_IPV4_TCP,
- I40E_FILTER_PCTYPE_NONF_IPV4_TCP},
- {ETH_RSS_NONFRAG_IPV4_UDP,
- I40E_FILTER_PCTYPE_NONF_IPV4_UDP},
- {ETH_RSS_NONFRAG_IPV4_SCTP,
- I40E_FILTER_PCTYPE_NONF_IPV4_SCTP},
- {ETH_RSS_NONFRAG_IPV4_OTHER,
- I40E_FILTER_PCTYPE_NONF_IPV4_OTHER},
- {ETH_RSS_FRAG_IPV6,
- I40E_FILTER_PCTYPE_FRAG_IPV6},
- {ETH_RSS_NONFRAG_IPV6_TCP,
- I40E_FILTER_PCTYPE_NONF_IPV6_TCP},
- {ETH_RSS_NONFRAG_IPV6_UDP,
- I40E_FILTER_PCTYPE_NONF_IPV6_UDP},
- {ETH_RSS_NONFRAG_IPV6_SCTP,
- I40E_FILTER_PCTYPE_NONF_IPV6_SCTP},
- {ETH_RSS_NONFRAG_IPV6_OTHER,
- I40E_FILTER_PCTYPE_NONF_IPV6_OTHER},
- {ETH_RSS_L2_PAYLOAD,
- I40E_FILTER_PCTYPE_L2_PAYLOAD},
- };
-
- static const struct {
- uint64_t rss_type;
- enum i40e_filter_pctype pctype;
- } pctype_match_table_x722[] = {
- {ETH_RSS_NONFRAG_IPV4_TCP,
- I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK},
- {ETH_RSS_NONFRAG_IPV4_UDP,
- I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP},
- {ETH_RSS_NONFRAG_IPV4_UDP,
- I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP},
- {ETH_RSS_NONFRAG_IPV6_TCP,
- I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK},
- {ETH_RSS_NONFRAG_IPV6_UDP,
- I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP},
- {ETH_RSS_NONFRAG_IPV6_UDP,
- I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP},
- };
-
- NEXT_ITEM_OF_ACTION(act, actions, index);
- rss = act->conf;
-
- /**
- * RSS only supports forwarding,
- * check if the first not void action is RSS.
- */
- if (act->type != RTE_FLOW_ACTION_TYPE_RSS) {
- memset(rss_config, 0, sizeof(struct i40e_rte_flow_rss_conf));
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act, "Not supported action.");
- return -rte_errno;
- }
-
- if (p_info.action_flag && rss->queue_num) {
- for (j = 0; j < RTE_DIM(pctype_match_table); j++) {
- if (rss->types & pctype_match_table[j].rss_type) {
- conf_info->region[0].hw_flowtype[0] =
- (uint8_t)pctype_match_table[j].pctype;
- conf_info->region[0].flowtype_num = 1;
- conf_info->queue_region_number = 1;
- break;
- }
- }
-
- if (hw->mac.type == I40E_MAC_X722)
- for (j = 0; j < RTE_DIM(pctype_match_table_x722); j++) {
- if (rss->types &
- pctype_match_table_x722[j].rss_type) {
- m = conf_info->region[0].flowtype_num;
- conf_info->region[0].hw_flowtype[m] =
- pctype_match_table_x722[j].pctype;
- conf_info->region[0].flowtype_num++;
- conf_info->queue_region_number = 1;
- }
- }
- }
-
- /**
- * Do some queue region related parameters check
- * in order to keep queue index for queue region to be
- * continuous sequence and also to be part of RSS
- * queue index for this port.
- */
- if (conf_info->queue_region_number) {
- for (i = 0; i < rss->queue_num; i++) {
- for (j = 0; j < rss_info->conf.queue_num; j++) {
- if (rss->queue[i] == rss_info->conf.queue[j])
- break;
- }
- if (j == rss_info->conf.queue_num) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "no valid queues");
- return -rte_errno;
- }
- }
-
- for (i = 0; i < rss->queue_num - 1; i++) {
- if (rss->queue[i + 1] != rss->queue[i] + 1) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "no valid queues");
- return -rte_errno;
- }
- }
- }
-
- /* Parse queue region related parameters from configuration */
- for (n = 0; n < conf_info->queue_region_number; n++) {
- if (conf_info->region[n].user_priority_num ||
- conf_info->region[n].flowtype_num) {
- if (!((rte_is_power_of_2(rss->queue_num)) &&
- rss->queue_num <= 64)) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "The region sizes should be any of the following values: 1, 2, 4, 8, 16, 32, 64 as long as the "
- "total number of queues do not exceed the VSI allocation");
- return -rte_errno;
- }
-
- if (conf_info->region[n].user_priority[n] >=
- I40E_MAX_USER_PRIORITY) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "the user priority max index is 7");
- return -rte_errno;
- }
-
- if (conf_info->region[n].hw_flowtype[n] >=
- I40E_FILTER_PCTYPE_MAX) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "the hw_flowtype or PCTYPE max index is 63");
- return -rte_errno;
- }
-
- for (i = 0; i < info->queue_region_number; i++) {
- if (info->region[i].queue_num ==
- rss->queue_num &&
- info->region[i].queue_start_index ==
- rss->queue[0])
- break;
- }
-
- if (i == info->queue_region_number) {
- if (i > I40E_REGION_MAX_INDEX) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "the queue region max index is 7");
- return -rte_errno;
- }
-
- info->region[i].queue_num =
- rss->queue_num;
- info->region[i].queue_start_index =
- rss->queue[0];
- info->region[i].region_id =
- info->queue_region_number;
-
- j = info->region[i].user_priority_num;
- tmp = conf_info->region[n].user_priority[0];
- if (conf_info->region[n].user_priority_num) {
- info->region[i].user_priority[j] = tmp;
- info->region[i].user_priority_num++;
- }
-
- for (m = 0; m < conf_info->region[n].flowtype_num; m++) {
- j = info->region[i].flowtype_num;
- tmp = conf_info->region[n].hw_flowtype[m];
- info->region[i].hw_flowtype[j] = tmp;
- info->region[i].flowtype_num++;
- }
- info->queue_region_number++;
- } else {
- j = info->region[i].user_priority_num;
- tmp = conf_info->region[n].user_priority[0];
- if (conf_info->region[n].user_priority_num) {
- info->region[i].user_priority[j] = tmp;
- info->region[i].user_priority_num++;
- }
-
- for (m = 0; m < conf_info->region[n].flowtype_num; m++) {
- j = info->region[i].flowtype_num;
- tmp = conf_info->region[n].hw_flowtype[m];
- info->region[i].hw_flowtype[j] = tmp;
- info->region[i].flowtype_num++;
- }
- }
- }
-
- rss_config->queue_region_conf = TRUE;
- }
-
- /**
- * Return function if this flow is used for queue region configuration
- */
- if (rss_config->queue_region_conf)
- return 0;
-
- if (!rss) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "invalid rule");
- return -rte_errno;
- }
-
- for (n = 0; n < rss->queue_num; n++) {
- if (rss->queue[n] >= dev->data->nb_rx_queues) {
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act,
- "queue id > max number of queues");
- return -rte_errno;
- }
- }
-
- if (rss->queue_num && (p_info.types || rss->types))
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "RSS types must be empty while configuring queue region");
-
- /* validate pattern and pctype */
- if (!(rss->types & p_info.types) &&
- (rss->types || p_info.types) && !rss->queue_num)
- return rte_flow_error_set
- (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
- act, "invalid pctype");
-
- nb_types = 0;
- for (n = 0; n < RTE_ETH_FLOW_MAX; n++) {
- if (rss->types & (hf_bit << n))
- nb_types++;
- if (nb_types > 1)
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
- act, "multi pctype is not supported");
- }
-
- if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
- (p_info.types || rss->types || rss->queue_num))
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "pattern, type and queues must be empty while"
- " setting hash function as simple_xor");
-
- if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
- !(p_info.types && rss->types))
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "pctype and queues can not be empty while"
- " setting hash function as symmetric toeplitz");
-
- /* Parse RSS related parameters from configuration */
- if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX ||
- rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ)
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "RSS hash functions are not supported");
- if (rss->level)
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "a nonzero RSS encapsulation level is not supported");
- if (rss->key_len && rss->key_len > RTE_DIM(rss_config->key))
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "RSS hash key too large");
- if (rss->queue_num > RTE_DIM(rss_config->queue))
- return rte_flow_error_set
- (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "too many queues for RSS context");
- if (i40e_rss_conf_init(rss_config, rss))
- return rte_flow_error_set
- (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act,
- "RSS context initialization failure");
-
- index++;
-
- /* check if the next not void action is END */
- NEXT_ITEM_OF_ACTION(act, actions, index);
- if (act->type != RTE_FLOW_ACTION_TYPE_END) {
- memset(rss_config, 0, sizeof(struct i40e_rte_flow_rss_conf));
- rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION,
- act, "Not supported action.");
- return -rte_errno;
- }
- rss_config->queue_region_conf = FALSE;
-
- return 0;
-}
-
-static int
-i40e_parse_rss_filter(struct rte_eth_dev *dev,
- const struct rte_flow_attr *attr,
- const struct rte_flow_item pattern[],
- const struct rte_flow_action actions[],
- union i40e_filter_t *filter,
- struct rte_flow_error *error)
-{
- struct i40e_rss_pattern_info p_info;
- struct i40e_queue_regions info;
- int ret;
-
- memset(&info, 0, sizeof(struct i40e_queue_regions));
- memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info));
-
- ret = i40e_flow_parse_rss_pattern(dev, pattern,
- error, &p_info, &info);
- if (ret)
- return ret;
-
- ret = i40e_flow_parse_rss_action(dev, actions, error,
- p_info, &info, filter);
- if (ret)
- return ret;
-
- ret = i40e_flow_parse_attr(attr, error);
- if (ret)
- return ret;
-
- cons_filter_type = RTE_ETH_FILTER_HASH;
-
- return 0;
-}
-
-static int
-i40e_config_rss_filter_set(struct rte_eth_dev *dev,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
- struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct i40e_rss_filter *rss_filter;
- int ret;
-
- if (conf->queue_region_conf) {
- ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
- } else {
- ret = i40e_config_rss_filter(pf, conf, 1);
- }
-
- if (ret)
- return ret;
-
- rss_filter = rte_zmalloc("i40e_rss_filter",
- sizeof(*rss_filter), 0);
- if (rss_filter == NULL) {
- PMD_DRV_LOG(ERR, "Failed to alloc memory.");
- return -ENOMEM;
- }
- rss_filter->rss_filter_info = *conf;
- /* the rule new created is always valid
- * the existing rule covered by new rule will be set invalid
- */
- rss_filter->rss_filter_info.valid = true;
-
- TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next);
-
- return 0;
-}
-
-static int
-i40e_config_rss_filter_del(struct rte_eth_dev *dev,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
- struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct i40e_rss_filter *rss_filter;
- void *temp;
-
- if (conf->queue_region_conf)
- i40e_flush_queue_region_all_conf(dev, hw, pf, 0);
- else
- i40e_config_rss_filter(pf, conf, 0);
-
- TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) {
- if (!memcmp(&rss_filter->rss_filter_info, conf,
- sizeof(struct rte_flow_action_rss))) {
- TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next);
- rte_free(rss_filter);
- }
- }
- return 0;
-}
-
static int
i40e_flow_validate(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
@@ -5299,9 +4739,13 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
i++;
if ((actions + i)->type == RTE_FLOW_ACTION_TYPE_RSS) {
- ret = i40e_parse_rss_filter(dev, attr, pattern,
- actions, &cons_filter, error);
- return ret;
+ ret = i40e_flow_parse_attr(attr, error);
+ if (ret)
+ return ret;
+
+ cons_filter_type = RTE_ETH_FILTER_HASH;
+ return i40e_hash_parse(dev, pattern, actions + i,
+ &cons_filter.rss_conf, error);
}
i = 0;
@@ -5416,12 +4860,11 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
i40e_tunnel_filter_list);
break;
case RTE_ETH_FILTER_HASH:
- ret = i40e_config_rss_filter_set(dev,
- &cons_filter.rss_conf);
+ ret = i40e_hash_filter_create(pf, &cons_filter.rss_conf);
if (ret)
goto free_flow;
flow->rule = TAILQ_LAST(&pf->rss_config_list,
- i40e_rss_conf_list);
+ i40e_rss_conf_list);
break;
default:
goto free_flow;
@@ -5474,8 +4917,7 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
}
break;
case RTE_ETH_FILTER_HASH:
- ret = i40e_config_rss_filter_del(dev,
- &((struct i40e_rss_filter *)flow->rule)->rss_filter_info);
+ ret = i40e_hash_filter_destroy(pf, flow->rule);
break;
default:
PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
@@ -5623,14 +5065,11 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
return -rte_errno;
}
- ret = i40e_flow_flush_rss_filter(dev);
- if (ret) {
+ ret = i40e_hash_filter_flush(pf);
+ if (ret)
rte_flow_error_set(error, -ret,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to flush RSS flows.");
- return -rte_errno;
- }
-
return ret;
}
@@ -5747,36 +5186,6 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
return ret;
}
-/* remove the RSS filter */
-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_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);
-
- /* Delete RSS flows in flow list. */
- TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
- if (flow->filter_type != RTE_ETH_FILTER_HASH)
- continue;
-
- if (flow->rule) {
- ret = i40e_config_rss_filter_del(dev,
- &((struct i40e_rss_filter *)flow->rule)->rss_filter_info);
- if (ret)
- return ret;
- }
- TAILQ_REMOVE(&pf->flow_list, flow, node);
- rte_free(flow);
- }
-
- return ret;
-}
-
static int
i40e_flow_query(struct rte_eth_dev *dev __rte_unused,
struct rte_flow *flow,
new file mode 100644
@@ -0,0 +1,1315 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include <rte_malloc.h>
+#include <rte_tailq.h>
+#include "base/i40e_prototype.h"
+#include "i40e_logs.h"
+#include "i40e_ethdev.h"
+#include "i40e_hash.h"
+
+#ifndef BIT
+#define BIT(n) (1UL << (n))
+#endif
+
+#ifndef BIT_ULL
+#define BIT_ULL(n) (1ULL << (n))
+#endif
+
+#define I40E_TCI_MASK 0xFFFF
+
+/* Pattern item headers */
+#define I40E_HASH_HDR_ETH 0x01ULL
+#define I40E_HASH_HDR_IPV4 0x10ULL
+#define I40E_HASH_HDR_IPV6 0x20ULL
+#define I40E_HASH_HDR_TCP 0x100ULL
+#define I40E_HASH_HDR_UDP 0x200ULL
+#define I40E_HASH_HDR_SCTP 0x400ULL
+#define I40E_HASH_HDR_ESP 0x10000ULL
+#define I40E_HASH_HDR_L2TPV3 0x20000ULL
+#define I40E_HASH_HDR_AH 0x40000ULL
+#define I40E_HASH_HDR_GTPC 0x100000ULL
+#define I40E_HASH_HDR_GTPU 0x200000ULL
+
+#define I40E_HASH_HDR_INNER_SHIFT 32
+#define I40E_HASH_HDR_IPV4_INNER (I40E_HASH_HDR_IPV4 << \
+ I40E_HASH_HDR_INNER_SHIFT)
+#define I40E_HASH_HDR_IPV6_INNER (I40E_HASH_HDR_IPV6 << \
+ I40E_HASH_HDR_INNER_SHIFT)
+
+/* ETH */
+#define I40E_PHINT_ETH I40E_HASH_HDR_ETH
+
+/* IPv4 */
+#define I40E_PHINT_IPV4 (I40E_HASH_HDR_ETH | I40E_HASH_HDR_IPV4)
+#define I40E_PHINT_IPV4_TCP (I40E_PHINT_IPV4 | I40E_HASH_HDR_TCP)
+#define I40E_PHINT_IPV4_UDP (I40E_PHINT_IPV4 | I40E_HASH_HDR_UDP)
+#define I40E_PHINT_IPV4_SCTP (I40E_PHINT_IPV4 | I40E_HASH_HDR_SCTP)
+
+/* IPv6 */
+#define I40E_PHINT_IPV6 (I40E_HASH_HDR_ETH | I40E_HASH_HDR_IPV6)
+#define I40E_PHINT_IPV6_TCP (I40E_PHINT_IPV6 | I40E_HASH_HDR_TCP)
+#define I40E_PHINT_IPV6_UDP (I40E_PHINT_IPV6 | I40E_HASH_HDR_UDP)
+#define I40E_PHINT_IPV6_SCTP (I40E_PHINT_IPV6 | I40E_HASH_HDR_SCTP)
+
+/* ESP */
+#define I40E_PHINT_IPV4_ESP (I40E_PHINT_IPV4 | I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV6_ESP (I40E_PHINT_IPV6 | I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV4_UDP_ESP (I40E_PHINT_IPV4_UDP | \
+ I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV6_UDP_ESP (I40E_PHINT_IPV6_UDP | \
+ I40E_HASH_HDR_ESP)
+
+/* GTPC */
+#define I40E_PHINT_IPV4_GTPC (I40E_PHINT_IPV4_UDP | \
+ I40E_HASH_HDR_GTPC)
+#define I40E_PHINT_IPV6_GTPC (I40E_PHINT_IPV6_UDP | \
+ I40E_HASH_HDR_GTPC)
+
+/* GTPU */
+#define I40E_PHINT_IPV4_GTPU (I40E_PHINT_IPV4_UDP | \
+ I40E_HASH_HDR_GTPU)
+#define I40E_PHINT_IPV4_GTPU_IPV4 (I40E_PHINT_IPV4_GTPU | \
+ I40E_HASH_HDR_IPV4_INNER)
+#define I40E_PHINT_IPV4_GTPU_IPV6 (I40E_PHINT_IPV4_GTPU | \
+ I40E_HASH_HDR_IPV6_INNER)
+#define I40E_PHINT_IPV6_GTPU (I40E_PHINT_IPV6_UDP | \
+ I40E_HASH_HDR_GTPU)
+#define I40E_PHINT_IPV6_GTPU_IPV4 (I40E_PHINT_IPV6_GTPU | \
+ I40E_HASH_HDR_IPV4_INNER)
+#define I40E_PHINT_IPV6_GTPU_IPV6 (I40E_PHINT_IPV6_GTPU | \
+ I40E_HASH_HDR_IPV6_INNER)
+
+/* L2TPV3 */
+#define I40E_PHINT_IPV4_L2TPV3 (I40E_PHINT_IPV4 | I40E_HASH_HDR_L2TPV3)
+#define I40E_PHINT_IPV6_L2TPV3 (I40E_PHINT_IPV6 | I40E_HASH_HDR_L2TPV3)
+
+/* AH */
+#define I40E_PHINT_IPV4_AH (I40E_PHINT_IPV4 | I40E_HASH_HDR_AH)
+#define I40E_PHINT_IPV6_AH (I40E_PHINT_IPV6 | I40E_HASH_HDR_AH)
+
+/* Structure of mapping RSS type to input set */
+struct i40e_hash_map_rss_inset {
+ uint64_t rss_type;
+ uint64_t inset;
+};
+
+const struct i40e_hash_map_rss_inset i40e_hash_rss_inset[] = {
+ /* IPv4 */
+ { ETH_RSS_IPV4, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+ { ETH_RSS_FRAG_IPV4, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+
+ { ETH_RSS_NONFRAG_IPV4_OTHER,
+ I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+
+ { ETH_RSS_NONFRAG_IPV4_TCP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+ { ETH_RSS_NONFRAG_IPV4_UDP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+ { ETH_RSS_NONFRAG_IPV4_SCTP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT | I40E_INSET_SCTP_VT },
+
+ /* IPv6 */
+ { ETH_RSS_IPV6, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+ { ETH_RSS_FRAG_IPV6, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+
+ { ETH_RSS_NONFRAG_IPV6_OTHER,
+ I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+
+ { ETH_RSS_NONFRAG_IPV6_TCP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+ { ETH_RSS_NONFRAG_IPV6_UDP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+ { ETH_RSS_NONFRAG_IPV6_SCTP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+ I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT | I40E_INSET_SCTP_VT },
+
+ /* Ether */
+ { ETH_RSS_L2_PAYLOAD, I40E_INSET_LAST_ETHER_TYPE },
+ { ETH_RSS_ETH, I40E_INSET_DMAC | I40E_INSET_SMAC },
+
+ /* VLAN */
+ { ETH_RSS_S_VLAN, I40E_INSET_VLAN_OUTER },
+ { ETH_RSS_C_VLAN, I40E_INSET_VLAN_INNER },
+};
+
+#define I40E_HASH_VOID_NEXT_ALLOW BIT_ULL(RTE_FLOW_ITEM_TYPE_ETH)
+
+#define I40E_HASH_ETH_NEXT_ALLOW (BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV4) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV6) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_VLAN))
+
+#define I40E_HASH_IP_NEXT_ALLOW (BIT_ULL(RTE_FLOW_ITEM_TYPE_TCP) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_UDP) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_SCTP) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_ESP) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_L2TPV3OIP) |\
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_AH))
+
+#define I40E_HASH_UDP_NEXT_ALLOW BIT_ULL(RTE_FLOW_ITEM_TYPE_GTPU)
+
+#define I40E_HASH_GTPU_NEXT_ALLOW (BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV4) | \
+ BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV6))
+
+static const uint64_t pattern_next_allow_items[] = {
+ [RTE_FLOW_ITEM_TYPE_VOID] = I40E_HASH_VOID_NEXT_ALLOW,
+ [RTE_FLOW_ITEM_TYPE_ETH] = I40E_HASH_ETH_NEXT_ALLOW,
+ [RTE_FLOW_ITEM_TYPE_IPV4] = I40E_HASH_IP_NEXT_ALLOW,
+ [RTE_FLOW_ITEM_TYPE_IPV6] = I40E_HASH_IP_NEXT_ALLOW,
+ [RTE_FLOW_ITEM_TYPE_UDP] = I40E_HASH_UDP_NEXT_ALLOW,
+ [RTE_FLOW_ITEM_TYPE_GTPU] = I40E_HASH_GTPU_NEXT_ALLOW,
+};
+
+static const uint64_t pattern_item_header[] = {
+ [RTE_FLOW_ITEM_TYPE_ETH] = I40E_HASH_HDR_ETH,
+ [RTE_FLOW_ITEM_TYPE_IPV4] = I40E_HASH_HDR_IPV4,
+ [RTE_FLOW_ITEM_TYPE_IPV6] = I40E_HASH_HDR_IPV6,
+ [RTE_FLOW_ITEM_TYPE_TCP] = I40E_HASH_HDR_TCP,
+ [RTE_FLOW_ITEM_TYPE_UDP] = I40E_HASH_HDR_UDP,
+ [RTE_FLOW_ITEM_TYPE_SCTP] = I40E_HASH_HDR_SCTP,
+ [RTE_FLOW_ITEM_TYPE_ESP] = I40E_HASH_HDR_ESP,
+ [RTE_FLOW_ITEM_TYPE_GTPU] = I40E_HASH_HDR_GTPU,
+ [RTE_FLOW_ITEM_TYPE_L2TPV3OIP] = I40E_HASH_HDR_L2TPV3,
+ [RTE_FLOW_ITEM_TYPE_AH] = I40E_HASH_HDR_AH,
+};
+
+/* Structure of matched pattern */
+struct i40e_hash_match_pattern {
+ uint64_t pattern_type;
+ uint64_t rss_mask; /* Supported RSS type for this pattern */
+ bool custom_pctype_flag;/* true for custom packet type */
+ uint8_t pctype;
+};
+
+#define I40E_HASH_MAP_PATTERN(pattern, rss_mask, pctype) { \
+ pattern, rss_mask, false, pctype }
+
+#define I40E_HASH_MAP_CUS_PATTERN(pattern, rss_mask, cus_pctype) { \
+ pattern, rss_mask, true, cus_pctype }
+
+#define I40E_HASH_VLAN_RSS_MASK (ETH_RSS_S_VLAN | ETH_RSS_C_VLAN)
+#define I40E_HASH_L2_RSS_MASK (ETH_RSS_ETH | ETH_RSS_L2_SRC_ONLY | \
+ ETH_RSS_L2_SRC_ONLY)
+
+#define I40E_HASH_L23_RSS_MASK (I40E_HASH_L2_RSS_MASK | \
+ I40E_HASH_VLAN_RSS_MASK | \
+ ETH_RSS_L3_SRC_ONLY | \
+ ETH_RSS_L3_SRC_ONLY)
+
+#define I40E_HASH_L234_RSS_MASK (I40E_HASH_L23_RSS_MASK | \
+ ETH_RSS_PORT | ETH_RSS_L3_SRC_ONLY | \
+ ETH_RSS_L3_SRC_ONLY)
+
+#define I40E_HASH_IPV4_L234_RSS_MASK (I40E_HASH_L234_RSS_MASK | ETH_RSS_IPV4)
+#define I40E_HASH_IPV6_L234_RSS_MASK (I40E_HASH_L234_RSS_MASK | ETH_RSS_IPV6)
+
+/* Current supported patterns and RSS types.
+ * All items that have the same pattern types are together.
+ */
+static const struct i40e_hash_match_pattern match_patterns[] = {
+ /* Ether */
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_ETH,
+ ETH_RSS_L2_PAYLOAD | I40E_HASH_L2_RSS_MASK,
+ I40E_FILTER_PCTYPE_L2_PAYLOAD),
+
+ /* IPv4 */
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4,
+ ETH_RSS_FRAG_IPV4 | I40E_HASH_L23_RSS_MASK,
+ I40E_FILTER_PCTYPE_FRAG_IPV4),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4,
+ ETH_RSS_NONFRAG_IPV4_OTHER |
+ I40E_HASH_L23_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV4_OTHER),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_TCP,
+ ETH_RSS_NONFRAG_IPV4_TCP |
+ I40E_HASH_IPV4_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV4_TCP),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_UDP,
+ ETH_RSS_NONFRAG_IPV4_UDP |
+ I40E_HASH_IPV4_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV4_UDP),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_SCTP,
+ ETH_RSS_NONFRAG_IPV4_SCTP |
+ I40E_HASH_IPV4_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV4_SCTP),
+
+ /* IPv6 */
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6,
+ ETH_RSS_FRAG_IPV6 | I40E_HASH_L23_RSS_MASK,
+ I40E_FILTER_PCTYPE_FRAG_IPV6),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6,
+ ETH_RSS_NONFRAG_IPV6_OTHER |
+ I40E_HASH_L23_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV6_OTHER),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_TCP,
+ ETH_RSS_NONFRAG_IPV6_TCP |
+ I40E_HASH_IPV6_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV6_TCP),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_UDP,
+ ETH_RSS_NONFRAG_IPV6_UDP |
+ I40E_HASH_IPV6_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV6_UDP),
+
+ I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_SCTP,
+ ETH_RSS_NONFRAG_IPV6_SCTP |
+ I40E_HASH_IPV6_L234_RSS_MASK,
+ I40E_FILTER_PCTYPE_NONF_IPV6_SCTP),
+
+ /* ESP */
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_ESP,
+ ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV4),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_ESP,
+ ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV6),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_UDP_ESP,
+ ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV4_UDP),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_UDP_ESP,
+ ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV6_UDP),
+
+ /* GTPC */
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPC,
+ I40E_HASH_IPV4_L234_RSS_MASK,
+ I40E_CUSTOMIZED_GTPC),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPC,
+ I40E_HASH_IPV6_L234_RSS_MASK,
+ I40E_CUSTOMIZED_GTPC),
+
+ /* GTPU */
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU,
+ I40E_HASH_IPV4_L234_RSS_MASK,
+ I40E_CUSTOMIZED_GTPU),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU_IPV4,
+ ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV4),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU_IPV6,
+ ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV6),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU,
+ I40E_HASH_IPV6_L234_RSS_MASK,
+ I40E_CUSTOMIZED_GTPU),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU_IPV4,
+ ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV4),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU_IPV6,
+ ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV6),
+
+ /* L2TPV3 */
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_L2TPV3,
+ ETH_RSS_L2TPV3, I40E_CUSTOMIZED_IPV4_L2TPV3),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_L2TPV3,
+ ETH_RSS_L2TPV3, I40E_CUSTOMIZED_IPV6_L2TPV3),
+
+ /* AH */
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_AH, ETH_RSS_AH,
+ I40E_CUSTOMIZED_AH_IPV4),
+ I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_AH, ETH_RSS_AH,
+ I40E_CUSTOMIZED_AH_IPV6),
+};
+
+static int
+i40e_hash_get_pattern_type(const struct rte_flow_item pattern[],
+ struct rte_flow_error *error,
+ uint64_t *pattern_types)
+{
+ const char *message = "Pattern not supported";
+ enum rte_flow_item_type prev_item_type = RTE_FLOW_ITEM_TYPE_VOID;
+ enum rte_flow_item_type last_item_type = prev_item_type;
+ uint64_t item_hdr, pattern_hdrs = 0;
+ bool inner_flag = false;
+ int vlan_count = 0;
+
+ for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+ if (pattern->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+
+ if (pattern->mask || pattern->spec || pattern->last) {
+ message = "Header info should not be specified";
+ goto not_sup;
+ }
+
+ /* Check the previous item allows this sub-item. */
+ if (prev_item_type >= RTE_DIM(pattern_next_allow_items) ||
+ !(pattern_next_allow_items[prev_item_type] &
+ BIT_ULL(pattern->type)))
+ goto not_sup;
+
+ /* For VLAN item, it does no matter about to pattern type
+ * recognition. So just count the number of VLAN and do not
+ * change the value of prev_item_type.
+ */
+ last_item_type = pattern->type;
+ if (last_item_type == RTE_FLOW_ITEM_TYPE_VLAN) {
+ if (vlan_count >= 2)
+ goto not_sup;
+ vlan_count++;
+ continue;
+ }
+
+ prev_item_type = last_item_type;
+ assert(last_item_type < RTE_DIM(pattern_item_header));
+ item_hdr = pattern_item_header[last_item_type];
+ assert(item_hdr);
+
+ if (inner_flag) {
+ item_hdr <<= I40E_HASH_HDR_INNER_SHIFT;
+
+ /* Inner layer should not have GTPU item */
+ if (last_item_type == RTE_FLOW_ITEM_TYPE_GTPU)
+ goto not_sup;
+
+ } else if (last_item_type == RTE_FLOW_ITEM_TYPE_GTPU) {
+ inner_flag = true;
+ vlan_count = 0;
+ }
+
+ if (item_hdr & pattern_hdrs)
+ goto not_sup;
+
+ pattern_hdrs |= item_hdr;
+ }
+
+ if (pattern_hdrs && last_item_type != RTE_FLOW_ITEM_TYPE_VLAN) {
+ *pattern_types = pattern_hdrs;
+ return 0;
+ }
+
+not_sup:
+ return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+ pattern, message);
+}
+
+static int
+i40e_hash_get_x722_ext_pctypes(const struct i40e_hash_match_pattern *match,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ uint8_t *pctypes = rss_conf->pctypes;
+ uint8_t count = rss_conf->pctype_count;
+
+ switch (match->pctype) {
+ case I40E_FILTER_PCTYPE_NONF_IPV4_TCP:
+ if (count >= RTE_DIM(rss_conf->pctypes))
+ goto out_of_range;
+
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK;
+ break;
+
+ case I40E_FILTER_PCTYPE_NONF_IPV4_UDP:
+ if (count + 2 > (int)RTE_DIM(rss_conf->pctypes))
+ goto out_of_range;
+
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP;
+ break;
+
+ case I40E_FILTER_PCTYPE_NONF_IPV6_TCP:
+ if (count >= RTE_DIM(rss_conf->pctypes))
+ goto out_of_range;
+
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK;
+ break;
+
+ case I40E_FILTER_PCTYPE_NONF_IPV6_UDP:
+ if (count + 2 > (int)RTE_DIM(rss_conf->pctypes))
+ goto out_of_range;
+
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP;
+ pctypes[count++] = I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP;
+ break;
+ }
+
+ rss_conf->pctype_count = count;
+ return 0;
+
+out_of_range:
+ return rte_flow_error_set(error, ERANGE,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "RSS PCTYPE number out of range");
+}
+
+static int
+i40e_hash_get_pctypes(const struct rte_eth_dev *dev,
+ const struct i40e_hash_match_pattern *match,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ if (rss_conf->pctype_count >= RTE_DIM(rss_conf->pctypes))
+ return rte_flow_error_set(error, ERANGE,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL,
+ "RSS PCTYPE number out of range");
+
+ if (match->custom_pctype_flag) {
+ struct i40e_pf *pf;
+ struct i40e_customized_pctype *custom_type;
+
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ custom_type = i40e_find_customized_pctype(pf, match->pctype);
+ if (!custom_type || !custom_type->valid)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ NULL,
+ "PCTYPE not supported");
+
+ rss_conf->pctypes[rss_conf->pctype_count] = custom_type->pctype;
+ rss_conf->pctype_count++;
+ } else {
+ struct i40e_hw *hw;
+
+ rss_conf->pctypes[rss_conf->pctype_count] = match->pctype;
+ rss_conf->pctype_count++;
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ if (hw->mac.type == I40E_MAC_X722)
+ return i40e_hash_get_x722_ext_pctypes(match,
+ rss_conf, error);
+ }
+
+ return 0;
+}
+
+static int
+i40e_hash_get_pattern_pctypes(const struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action_rss *rss_act,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ uint64_t pattern_types = 0;
+ bool match_flag = false;
+ int i, ret;
+
+ ret = i40e_hash_get_pattern_type(pattern, error, &pattern_types);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < (int)RTE_DIM(match_patterns); i++) {
+ const struct i40e_hash_match_pattern *match =
+ &match_patterns[i];
+
+ /* Check pattern types match. All items that have the same
+ * pattern types are together, so if the pattern types match
+ * previous item but they doesn't match current item, it means
+ * the pattern types do not match all remain items.
+ */
+ if (pattern_types != match->pattern_type) {
+ if (match_flag)
+ break;
+ continue;
+ }
+ match_flag = true;
+
+ /* Check RSS types match */
+ if ((rss_act->types & ~match->rss_mask) == 0) {
+ ret = i40e_hash_get_pctypes(dev, match,
+ rss_conf, error);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (rss_conf->pctype_count)
+ return 0;
+
+ if (match_flag)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "RSS types not supported");
+
+ return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+ NULL, "Pattern not supported");
+}
+
+static int
+i40e_hash_config_pctype_inset(struct i40e_hw *hw, uint64_t rss_types,
+ uint64_t inset, uint32_t pctype)
+{
+ uint64_t mask;
+
+ /* If SRC_ONLY and DST_ONLY of the same level are used simultaneously,
+ * it is the same case as none of them are added.
+ */
+ mask = rss_types & (ETH_RSS_L2_SRC_ONLY | ETH_RSS_L2_DST_ONLY);
+ if (mask == ETH_RSS_L2_SRC_ONLY)
+ inset &= ~I40E_INSET_DMAC;
+ else if (mask == ETH_RSS_L2_DST_ONLY)
+ inset &= ~I40E_INSET_SMAC;
+
+ mask = rss_types & (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
+ if (mask == ETH_RSS_L4_SRC_ONLY)
+ inset &= ~I40E_INSET_DST_PORT;
+ else if (mask == ETH_RSS_L4_DST_ONLY)
+ inset &= ~I40E_INSET_SRC_PORT;
+
+ mask = rss_types & (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY);
+ if (mask == ETH_RSS_L3_SRC_ONLY)
+ inset &= ~(I40E_INSET_IPV4_DST | I40E_INSET_IPV6_DST);
+ else if (mask == ETH_RSS_L3_DST_ONLY)
+ inset &= ~(I40E_INSET_IPV4_SRC | I40E_INSET_IPV6_SRC);
+
+ return i40e_set_hash_inset(hw, inset, pctype, false);
+}
+
+static int
+i40e_hash_config_func(struct i40e_hw *hw, enum rte_eth_hash_function func)
+{
+ struct i40e_pf *pf;
+ uint32_t reg;
+ uint8_t symmetric = 0;
+
+ reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
+
+ if (func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+ if (!(reg & I40E_GLQF_CTL_HTOEP_MASK))
+ goto set_symmetric;
+
+ reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+ } else {
+ if (func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
+ symmetric = 1;
+
+ if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+ goto set_symmetric;
+
+ reg |= I40E_GLQF_CTL_HTOEP_MASK;
+ }
+
+ pf = &((struct i40e_adapter *)hw->back)->pf;
+ if (pf->support_multi_driver) {
+ PMD_DRV_LOG(ERR,
+ "Modify hash function is not permitted when multi-driver enabled");
+ return -EPERM;
+ }
+
+ PMD_DRV_LOG(INFO, "NIC hash function is setting to %d", func);
+ i40e_write_rx_ctl(hw, I40E_GLQF_CTL, reg);
+ I40E_WRITE_FLUSH(hw);
+
+set_symmetric:
+ i40e_set_symmetric_hash_enable_per_port(hw, symmetric);
+ return 0;
+}
+
+static int
+i40e_hash_config_pctype_symmetric(struct i40e_hw *hw, uint32_t pctype,
+ enum rte_eth_hash_function func)
+{
+ struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
+ uint32_t reg;
+
+ /* For X722, get translated pctype in fd pctype register */
+ if (hw->mac.type == I40E_MAC_X722)
+ pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+ reg = i40e_read_rx_ctl(hw, I40E_GLQF_HSYM(pctype));
+ if (func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+ if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
+ return 0;
+ reg |= I40E_GLQF_HSYM_SYMH_ENA_MASK;
+ } else {
+ if (!(reg & I40E_GLQF_HSYM_SYMH_ENA_MASK))
+ return 0;
+ reg &= ~I40E_GLQF_HSYM_SYMH_ENA_MASK;
+ }
+
+ if (pf->support_multi_driver) {
+ PMD_DRV_LOG(ERR,
+ "Enable/Disable symmetric hash is not permitted when multi-driver enabled");
+ return -EPERM;
+ }
+
+ i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype), reg);
+ I40E_WRITE_FLUSH(hw);
+ return 0;
+}
+
+static void
+i40e_hash_enable_pctype(struct i40e_hw *hw,
+ uint32_t pctype, bool enable)
+{
+ uint32_t reg, reg_val, mask;
+
+ /* For X722, get translated pctype in fd pctype register */
+ if (hw->mac.type == I40E_MAC_X722)
+ pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+ if (pctype < 32) {
+ mask = 1U << pctype;
+ reg = I40E_PFQF_HENA(0);
+ } else {
+ mask = 1U << (pctype - 32);
+ reg = I40E_PFQF_HENA(1);
+ }
+
+ reg_val = i40e_read_rx_ctl(hw, reg);
+
+ if (enable) {
+ if (reg_val & mask)
+ return;
+
+ reg_val |= mask;
+ } else {
+ if (!(reg_val & mask))
+ return;
+
+ reg_val &= ~mask;
+ }
+
+ i40e_write_rx_ctl(hw, reg, reg_val);
+ I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40e_hash_config_pctype(struct i40e_hw *hw,
+ const struct rte_flow_action_rss *rss_act,
+ uint32_t pctype)
+{
+ uint64_t inset = 0;
+ int i, ret;
+
+ if (rss_act->types == 0) {
+ i40e_hash_enable_pctype(hw, pctype, false);
+ return 0;
+ }
+
+ /* Get input sets */
+ for (i = 0; i < (int)RTE_DIM(i40e_hash_rss_inset); i++) {
+ if (rss_act->types & i40e_hash_rss_inset[i].rss_type)
+ inset |= i40e_hash_rss_inset[i].inset;
+ }
+
+ if (inset) {
+ ret = i40e_hash_config_pctype_inset(hw, rss_act->types,
+ inset, pctype);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+ ret = i40e_hash_config_pctype_symmetric(hw, pctype,
+ rss_act->func);
+ if (ret)
+ return ret;
+ }
+
+ i40e_hash_enable_pctype(hw, pctype, true);
+ return 0;
+}
+
+static int
+i40e_hash_reset_pctype(struct i40e_hw *hw,
+ const struct rte_flow_action_rss *rss_act,
+ uint32_t pctype)
+{
+ const enum rte_eth_hash_function def_func =
+ RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+ uint64_t inset = 0;
+ int ret;
+
+ i40e_hash_enable_pctype(hw, pctype, false);
+
+ inset = i40e_get_default_input_set(pctype);
+ if (inset) {
+ ret = i40e_set_hash_inset(hw, inset, pctype, false);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT &&
+ rss_act->func != def_func) {
+ ret = i40e_hash_config_pctype_symmetric(hw, pctype, def_func);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+i40e_hash_config_region(struct i40e_pf *pf,
+ const struct i40e_rte_flow_rss_conf *rss_conf)
+{
+ struct i40e_hw *hw = &pf->adapter->hw;
+ struct rte_eth_dev *dev = pf->adapter->eth_dev;
+ struct i40e_queue_region_info *regions = pf->queue_region.region;
+ uint32_t num = pf->queue_region.queue_region_number;
+ uint32_t i, region_id_mask = 0;
+
+ if (!rss_conf->region_queue_num)
+ return 0;
+
+ RTE_BUILD_BUG_ON(I40E_REGION_MAX_INDEX > 31);
+
+ /* Re-configure the region if it existed */
+ for (i = 0; i < num; i++) {
+ if (rss_conf->region_queue_start ==
+ regions[i].queue_start_index &&
+ rss_conf->region_queue_num == regions[i].queue_num) {
+ regions[i].user_priority[0] = rss_conf->region_priority;
+
+ return i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
+ }
+
+ region_id_mask |= BIT(regions[i].region_id);
+ }
+
+ if (num > I40E_REGION_MAX_INDEX) {
+ PMD_DRV_LOG(ERR, "Queue region resource used up");
+ return -ERANGE;
+ }
+
+ /* Add a new region */
+
+ pf->queue_region.queue_region_number++;
+ memset(®ions[num], 0, sizeof(regions[0]));
+
+ for (i = 0; i <= I40E_REGION_MAX_INDEX; i++)
+ if (!(BIT(i) & region_id_mask))
+ break;
+
+ regions[num].region_id = i;
+ regions[num].queue_num = rss_conf->region_queue_num;
+ regions[num].queue_start_index = rss_conf->region_queue_start;
+ regions[num].user_priority[0] = rss_conf->region_priority;
+ regions[num].user_priority_num = 1;
+
+ return i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
+}
+
+static int
+i40e_hash_config(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *rss_conf)
+{
+ struct rte_flow_action_rss *rss_info = &rss_conf->conf;
+ struct i40e_hw *hw = &pf->adapter->hw;
+ uint32_t i;
+ int ret;
+
+ if (rss_conf->region_flags)
+ return i40e_hash_config_region(pf, rss_conf);
+
+ if (rss_info->key_len > 0) {
+ ret = i40e_set_rss_key(pf->main_vsi, rss_conf->key,
+ rss_info->key_len);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_info->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+ ret = i40e_hash_config_func(hw, rss_conf->conf.func);
+ if (ret)
+ return ret;
+ }
+
+ /* Update lookup table */
+ if (rss_info->queue_num > 0) {
+ uint8_t lut[ETH_RSS_RETA_SIZE_512];
+ uint32_t j = 0;
+
+ for (i = 0; i < hw->func_caps.rss_table_size; i++) {
+ lut[i] = (uint8_t)rss_info->queue[j];
+ j = (j == rss_info->queue_num - 1) ? 0 : (j + 1);
+ }
+
+ ret = i40e_set_rss_lut(pf->main_vsi, lut, (uint16_t)i);
+ if (ret)
+ return ret;
+
+ pf->hash_enabled_queues = 0;
+ for (i = 0; i < rss_info->queue_num; i++)
+ pf->hash_enabled_queues |= BIT_ULL(lut[i]);
+
+ pf->adapter->rss_reta_updated = 0;
+ }
+
+ if (rss_conf->pctype_count <= 0)
+ return 0;
+
+ if (!pf->hash_filter_enable) {
+ i40e_pf_disable_rss(pf);
+ pf->hash_filter_enable = true;
+ }
+
+ for (i = 0; i < rss_conf->pctype_count; i++) {
+ ret = i40e_hash_config_pctype(hw, &rss_conf->conf,
+ rss_conf->pctypes[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+i40e_hash_parse_key(const struct rte_flow_action_rss *rss_act,
+ struct i40e_rte_flow_rss_conf *rss_conf)
+{
+ const uint8_t *key = rss_act->key;
+
+ if (rss_act->key_len != sizeof(rss_conf->key)) {
+ const uint32_t rss_key_default[] = {0x6b793944,
+ 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+ 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+ 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
+ PMD_DRV_LOG(WARNING, "RSS key invalid, set to default");
+ key = (const uint8_t *)rss_key_default;
+ }
+
+ memcpy(rss_conf->key, key, sizeof(rss_conf->key));
+ rss_conf->conf.key = rss_conf->key;
+ rss_conf->conf.key_len = sizeof(rss_conf->key);
+}
+
+static int
+i40e_hash_parse_queues(const struct rte_eth_dev *dev,
+ const struct rte_flow_action_rss *rss_act,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ const char *message;
+ struct i40e_pf *pf;
+ struct i40e_hw *hw;
+ uint16_t i;
+ int max_queue;
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ if (!rss_act->queue_num ||
+ rss_act->queue_num > hw->func_caps.rss_table_size) {
+ message = "Invalid RSS queue number";
+ goto invalid;
+ }
+
+ if (rss_act->key_len)
+ PMD_DRV_LOG(WARNING,
+ "RSS key is ignored when queues specified");
+
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
+ max_queue = i40e_pf_calc_configured_queues_num(pf);
+ else
+ max_queue = pf->dev_data->nb_rx_queues;
+
+ max_queue = RTE_MIN(max_queue, I40E_MAX_Q_PER_TC);
+
+ for (i = 0; i < rss_act->queue_num; i++) {
+ if ((int)rss_act->queue[i] >= max_queue) {
+ message = "Invalid RSS queues";
+ goto invalid;
+ }
+ }
+
+ memcpy(rss_conf->queue, rss_act->queue,
+ rss_act->queue_num * sizeof(rss_conf->queue[0]));
+ rss_conf->conf.queue = rss_conf->queue;
+ rss_conf->conf.queue_num = rss_act->queue_num;
+
+ return 0;
+
+invalid:
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, message);
+}
+
+static int
+i40e_hash_parse_queue_region(const struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action_rss *rss_act,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ struct i40e_pf *pf;
+ const struct rte_flow_item_vlan *vlan_spec, *vlan_mask;
+ uint64_t hash_queues;
+ uint32_t i;
+
+ if (pattern[1].type != RTE_FLOW_ITEM_TYPE_END)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+ &pattern[1],
+ "Pattern not supported.");
+
+ vlan_spec = pattern->spec;
+ vlan_mask = pattern->mask;
+ if (!vlan_spec || !vlan_mask ||
+ vlan_mask->tci != rte_cpu_to_be_16(I40E_TCI_MASK))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ pattern,
+ "Pattern error.");
+
+ if (!rss_act->queue)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "Queues not specified");
+
+ if (rss_act->types)
+ PMD_DRV_LOG(WARNING,
+ "RSS type is ignored when configure queue region");
+
+ if (rss_act->key_len)
+ PMD_DRV_LOG(WARNING,
+ "RSS key is ignored when configure queue region");
+
+ RTE_BUILD_BUG_ON(I40E_MAX_Q_PER_TC > 64);
+
+ if (!rss_act->queue_num ||
+ rss_act->queue_num > I40E_MAX_Q_PER_TC ||
+ !rte_is_power_of_2(rss_act->queue_num))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "Queue number error");
+
+ hash_queues = BIT_ULL(rss_act->queue[0]);
+
+ for (i = 1; i < rss_act->queue_num; i++) {
+ if (rss_act->queue[i - 1] + 1 != rss_act->queue[i]) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL,
+ "Queues must be incremented continuously");
+ return -EINVAL;
+ }
+
+ hash_queues |= BIT_ULL(rss_act->queue[i]);
+ }
+
+ pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ if (hash_queues & ~pf->hash_enabled_queues)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "Invalid queues");
+
+ rss_conf->region_queue_num = (uint8_t)rss_act->queue_num;
+ rss_conf->region_queue_start = rss_act->queue[0];
+ rss_conf->region_priority = rte_be_to_cpu_16(vlan_spec->tci) >> 13;
+ rss_conf->region_flags = 1;
+ return 0;
+}
+
+static bool
+i40e_hash_validate_rss_types(uint64_t rss_types)
+{
+ uint64_t type, mask;
+
+ /* Validate L2 */
+ type = ETH_RSS_ETH & rss_types;
+ mask = (ETH_RSS_L2_SRC_ONLY | ETH_RSS_L2_DST_ONLY) & rss_types;
+ if (!type && mask)
+ return false;
+
+ /* Validate L4 */
+ type = (ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_NONFRAG_IPV4_UDP |
+ ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_NONFRAG_IPV6_TCP |
+ ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_NONFRAG_IPV6_SCTP) &
+ rss_types;
+ mask = (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY) & rss_types;
+ if (!type && mask)
+ return false;
+
+ /* Validate L3 */
+ type = type | ((ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
+ ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_IPV6 |
+ ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER) & rss_types);
+ mask = (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY) & rss_types;
+ if (!type && mask)
+ return false;
+
+ return true;
+}
+
+static int
+i40e_hash_parse_pattern_act(const struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action_rss *rss_act,
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ if (rss_act->queue) {
+ const char *message =
+ "RSS Queues are not supported when pattern specified";
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, message);
+ }
+
+ if (!i40e_hash_validate_rss_types(rss_act->types))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ NULL, "RSS types are invalid");
+
+ rss_conf->conf.types = rss_act->types;
+ return i40e_hash_get_pattern_pctypes(dev, pattern, rss_act,
+ rss_conf, error);
+}
+
+int
+i40e_hash_parse(const struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_action_rss *rss_act;
+
+ if (actions[1].type != RTE_FLOW_ACTION_TYPE_END)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ &actions[1],
+ "Only support one action for RSS.");
+
+ rss_act = (const struct rte_flow_action_rss *)actions[0].conf;
+ if (rss_act->level)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+ actions,
+ "RSS level is not supported");
+
+ while (pattern->type == RTE_FLOW_ITEM_TYPE_VOID)
+ pattern++;
+
+ if (pattern[0].type == RTE_FLOW_ITEM_TYPE_VLAN)
+ return i40e_hash_parse_queue_region(dev, pattern, rss_act,
+ rss_conf, error);
+
+ if (pattern[0].type == RTE_FLOW_ITEM_TYPE_END) {
+ if (rss_act->types)
+ PMD_DRV_LOG(INFO,
+ "RSS types are not supported when no pattern specified");
+
+ if (rss_act->queue)
+ return i40e_hash_parse_queues(dev, rss_act,
+ rss_conf, error);
+
+ if (rss_act->key) {
+ i40e_hash_parse_key(rss_act, rss_conf);
+ return 0;
+ }
+
+ PMD_DRV_LOG(WARNING, "Nothing change");
+ return 0;
+ }
+
+ if (rss_act->key)
+ i40e_hash_parse_key(rss_act, rss_conf);
+
+ rss_conf->conf.func = rss_act->func;
+ return i40e_hash_parse_pattern_act(dev, pattern, rss_act,
+ rss_conf, error);
+}
+
+int
+i40e_hash_filter_restore(struct i40e_pf *pf)
+{
+ struct i40e_rss_filter *filter;
+ int ret;
+
+ TAILQ_FOREACH(filter, &pf->rss_config_list, next) {
+ ret = i40e_hash_config(pf, &filter->rss_filter_info);
+ if (ret) {
+ pf->hash_filter_enable = 0;
+ i40e_pf_disable_rss(pf);
+ PMD_DRV_LOG(ERR,
+ "Re-configure RSS failed, RSS has been disabled");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void
+i40e_hash_invalidate_conf(const struct i40e_rte_flow_rss_conf *ref_conf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ int i, j;
+
+ if (ref_conf->region_flags) {
+ if (conf->region_flags &&
+ ref_conf->region_queue_start == conf->region_queue_start &&
+ ref_conf->region_queue_num == conf->region_queue_num)
+ conf->region_queue_num = 0;
+
+ return;
+ }
+
+ if (conf->region_flags)
+ return;
+
+ /* Set same PCTYPE input sets invalid */
+ for (i = 0; i < ref_conf->pctype_count; i++) {
+ for (j = 0; j < conf->pctype_count; j++) {
+ if (ref_conf->pctypes[i] == conf->pctypes[j]) {
+ conf->pctype_count--;
+ if (conf->pctype_count - j > 0)
+ memcpy(&conf->pctypes[j],
+ &conf->pctypes[j + 1],
+ (conf->pctype_count - j) *
+ sizeof(conf->pctypes[0]));
+ break;
+ }
+ }
+ }
+
+ if (ref_conf->conf.key_len && conf->conf.key_len) {
+ conf->conf.key_len = 0;
+ conf->conf.key = NULL;
+ }
+
+ if (ref_conf->conf.queue_num && conf->conf.queue_num) {
+ conf->conf.queue_num = 0;
+ conf->conf.queue = NULL;
+ }
+
+ if (ref_conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT)
+ conf->conf.func = RTE_ETH_HASH_FUNCTION_DEFAULT;
+}
+
+int
+i40e_hash_filter_create(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *rss_conf)
+{
+ struct i40e_rss_filter *filter, *old;
+ struct i40e_rte_flow_rss_conf *new_conf;
+ int ret;
+
+ filter = rte_zmalloc("i40e_rss_filter", sizeof(*filter), 0);
+ if (!filter) {
+ PMD_DRV_LOG(ERR, "Failed to allocate memory.");
+ return -ENOMEM;
+ }
+
+ new_conf = &filter->rss_filter_info;
+
+ memcpy(new_conf, rss_conf, sizeof(*new_conf));
+ if (rss_conf->conf.queue_num)
+ new_conf->conf.queue = new_conf->queue;
+ if (rss_conf->conf.key_len)
+ new_conf->conf.key = new_conf->key;
+
+ ret = i40e_hash_config(pf, rss_conf);
+ if (ret) {
+ rte_free(filter);
+ if (i40e_pf_config_rss(pf))
+ return ret;
+
+ (void)i40e_hash_filter_restore(pf);
+ return ret;
+ }
+
+ TAILQ_FOREACH(old, &pf->rss_config_list, next)
+ i40e_hash_invalidate_conf(new_conf, &old->rss_filter_info);
+
+ TAILQ_INSERT_TAIL(&pf->rss_config_list, filter, next);
+ return 0;
+}
+
+static int
+i40e_hash_reset_conf(struct i40e_pf *pf,
+ const struct i40e_rte_flow_rss_conf *rss_conf)
+{
+ const struct rte_flow_action_rss *rss_act = &rss_conf->conf;
+ struct i40e_hw *hw = &pf->adapter->hw;
+ const enum rte_eth_hash_function def_func =
+ RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+ uint32_t i;
+ int ret;
+
+ if (rss_conf->region_queue_num)
+ return i40e_flush_queue_region_all_conf(pf->adapter->eth_dev,
+ hw, pf, 0);
+
+ for (i = 0; i < rss_conf->pctype_count; i++) {
+ ret = i40e_hash_reset_pctype(hw, rss_act, rss_conf->pctypes[i]);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT &&
+ rss_act->func != def_func) {
+ ret = i40e_hash_config_func(hw, def_func);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_act->key) {
+ ret = i40e_pf_reset_rss_key(pf);
+ if (ret)
+ return ret;
+ }
+
+ if (rss_act->queue && !pf->adapter->rss_reta_updated) {
+ pf->hash_enabled_queues = 0;
+ return i40e_pf_reset_rss_reta(pf);
+ }
+
+ return 0;
+}
+
+int
+i40e_hash_filter_destroy(struct i40e_pf *pf,
+ const struct i40e_rss_filter *rss_filter)
+{
+ struct i40e_rss_filter *filter;
+ int ret;
+
+ TAILQ_FOREACH(filter, &pf->rss_config_list, next) {
+ if (rss_filter == filter) {
+ ret = i40e_hash_reset_conf(pf,
+ &filter->rss_filter_info);
+ if (ret)
+ return ret;
+
+ TAILQ_REMOVE(&pf->rss_config_list, filter, next);
+ rte_free(filter);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int
+i40e_hash_filter_flush(struct i40e_pf *pf)
+{
+ struct rte_flow *flow, *next;
+
+ TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, next) {
+ if (flow->filter_type != RTE_ETH_FILTER_HASH)
+ continue;
+
+ if (flow->rule) {
+ struct i40e_rss_filter *filter = flow->rule;
+ int ret;
+
+ ret = i40e_hash_reset_conf(pf,
+ &filter->rss_filter_info);
+ if (ret)
+ return ret;
+
+ TAILQ_REMOVE(&pf->rss_config_list, filter, next);
+ rte_free(filter);
+ }
+
+ TAILQ_REMOVE(&pf->flow_list, flow, node);
+ rte_free(flow);
+ }
+
+ assert(!pf->rss_config_list.tqh_first);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _I40E_HASH_H_
+#define _I40E_HASH_H_
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include "i40e_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int i40e_hash_parse(const struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct i40e_rte_flow_rss_conf *rss_conf,
+ struct rte_flow_error *error);
+
+int i40e_hash_filter_create(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *rss_conf);
+
+int i40e_hash_filter_restore(struct i40e_pf *pf);
+int i40e_hash_filter_destroy(struct i40e_pf *pf,
+ const struct i40e_rss_filter *rss_filter);
+int i40e_hash_filter_flush(struct i40e_pf *pf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I40E_HASH_H_ */
@@ -17,6 +17,7 @@ sources = files(
'i40e_fdir.c',
'i40e_flow.c',
'i40e_tm.c',
+ 'i40e_hash.c',
'i40e_vf_representor.c',
'rte_pmd_i40e.c'
)