remove legacy filter functions already implemented in rte_flow for drivers igb, ixgbe, and i40e. implement hash function include set hash function and set hash input set in rte_flow for driver i40e. Chenxu Di (4): net/e1000: remove the legacy filter functions net/ixgbe: remove the legacy filter functions net/i40e: remove the legacy filter functions net/i40e: implement hash function in rte flow API doc/guides/nics/i40e.rst | 14 + doc/guides/rel_notes/release_20_05.rst | 9 + drivers/net/e1000/igb_ethdev.c | 36 - drivers/net/i40e/i40e_ethdev.c | 913 +++++++++++-------------- drivers/net/i40e/i40e_ethdev.h | 26 +- drivers/net/i40e/i40e_fdir.c | 393 ----------- drivers/net/i40e/i40e_flow.c | 186 ++++- drivers/net/ixgbe/ixgbe_ethdev.c | 78 --- drivers/net/ixgbe/ixgbe_fdir.c | 11 - 9 files changed, 610 insertions(+), 1056 deletions(-) -- 2.17.1
remove the legacy filter functions in Intel igb driver. Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- doc/guides/rel_notes/release_20_05.rst | 9 +++++++ drivers/net/e1000/igb_ethdev.c | 36 -------------------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst index 2190eaf85..e79f8d841 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -56,6 +56,15 @@ New Features Also, make sure to start the actual text at the margin. ========================================================= +* **remove legacy filter API and switch to rte flow** + + remove legacy filter API functions and switch to rte_flow in drivers, including: + + * remove legacy filter API functions in the Intel igb driver. + * remove legacy filter API functions in the Intel ixgbe driver. + * remove legacy filter API functions in the Intel i40 driver. + * Added support set hash function and set hash input set in rte flow API. + Removed Items ------------- diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c index 520fba8fa..2d660eb7e 100644 --- a/drivers/net/e1000/igb_ethdev.c +++ b/drivers/net/e1000/igb_ethdev.c @@ -3716,16 +3716,6 @@ eth_igb_syn_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = eth_igb_syn_filter_set(dev, - (struct rte_eth_syn_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = eth_igb_syn_filter_set(dev, - (struct rte_eth_syn_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = eth_igb_syn_filter_get(dev, (struct rte_eth_syn_filter *)arg); @@ -4207,12 +4197,6 @@ eth_igb_flex_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = eth_igb_add_del_flex_filter(dev, filter, TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = eth_igb_add_del_flex_filter(dev, filter, FALSE); - break; case RTE_ETH_FILTER_GET: ret = eth_igb_get_flex_filter(dev, filter); break; @@ -4713,16 +4697,6 @@ igb_ntuple_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = igb_add_del_ntuple_filter(dev, - (struct rte_eth_ntuple_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = igb_add_del_ntuple_filter(dev, - (struct rte_eth_ntuple_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = igb_get_ntuple_filter(dev, (struct rte_eth_ntuple_filter *)arg); @@ -4894,16 +4868,6 @@ igb_ethertype_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = igb_add_del_ethertype_filter(dev, - (struct rte_eth_ethertype_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = igb_add_del_ethertype_filter(dev, - (struct rte_eth_ethertype_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = igb_get_ethertype_filter(dev, (struct rte_eth_ethertype_filter *)arg); -- 2.17.1
remove the legacy filter functions in Intel ixgbe driver Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- drivers/net/ixgbe/ixgbe_ethdev.c | 78 -------------------------------- drivers/net/ixgbe/ixgbe_fdir.c | 11 ----- 2 files changed, 89 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c index 23b3f5b0c..89f8deade 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.c +++ b/drivers/net/ixgbe/ixgbe_ethdev.c @@ -369,9 +369,6 @@ static int ixgbe_dev_l2_tunnel_offload_set struct rte_eth_l2_tunnel_conf *l2_tunnel, uint32_t mask, uint8_t en); -static int ixgbe_dev_l2_tunnel_filter_handle(struct rte_eth_dev *dev, - enum rte_filter_op filter_op, - void *arg); static int ixgbe_dev_udp_tunnel_port_add(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *udp_tunnel); @@ -6426,16 +6423,6 @@ ixgbe_syn_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = ixgbe_syn_filter_set(dev, - (struct rte_eth_syn_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = ixgbe_syn_filter_set(dev, - (struct rte_eth_syn_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = ixgbe_syn_filter_get(dev, (struct rte_eth_syn_filter *)arg); @@ -6853,16 +6840,6 @@ ixgbe_ntuple_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = ixgbe_add_del_ntuple_filter(dev, - (struct rte_eth_ntuple_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = ixgbe_add_del_ntuple_filter(dev, - (struct rte_eth_ntuple_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = ixgbe_get_ntuple_filter(dev, (struct rte_eth_ntuple_filter *)arg); @@ -7004,16 +6981,6 @@ ixgbe_ethertype_filter_handle(struct rte_eth_dev *dev, } switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = ixgbe_add_del_ethertype_filter(dev, - (struct rte_eth_ethertype_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = ixgbe_add_del_ethertype_filter(dev, - (struct rte_eth_ethertype_filter *)arg, - FALSE); - break; case RTE_ETH_FILTER_GET: ret = ixgbe_get_ethertype_filter(dev, (struct rte_eth_ethertype_filter *)arg); @@ -7047,9 +7014,6 @@ ixgbe_dev_filter_ctrl(struct rte_eth_dev *dev, case RTE_ETH_FILTER_FDIR: ret = ixgbe_fdir_ctrl_func(dev, filter_op, arg); break; - case RTE_ETH_FILTER_L2_TUNNEL: - ret = ixgbe_dev_l2_tunnel_filter_handle(dev, filter_op, arg); - break; case RTE_ETH_FILTER_GENERIC: if (filter_op != RTE_ETH_FILTER_GET) return -EINVAL; @@ -8121,48 +8085,6 @@ ixgbe_dev_l2_tunnel_filter_del(struct rte_eth_dev *dev, return ret; } -/** - * ixgbe_dev_l2_tunnel_filter_handle - Handle operations for l2 tunnel filter. - * @dev: pointer to rte_eth_dev structure - * @filter_op:operation will be taken. - * @arg: a pointer to specific structure corresponding to the filter_op - */ -static int -ixgbe_dev_l2_tunnel_filter_handle(struct rte_eth_dev *dev, - enum rte_filter_op filter_op, - void *arg) -{ - int ret; - - if (filter_op == RTE_ETH_FILTER_NOP) - return 0; - - if (arg == NULL) { - PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u.", - filter_op); - return -EINVAL; - } - - switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = ixgbe_dev_l2_tunnel_filter_add - (dev, - (struct rte_eth_l2_tunnel_conf *)arg, - FALSE); - break; - case RTE_ETH_FILTER_DELETE: - ret = ixgbe_dev_l2_tunnel_filter_del - (dev, - (struct rte_eth_l2_tunnel_conf *)arg); - break; - default: - PMD_DRV_LOG(ERR, "unsupported operation %u.", filter_op); - ret = -EINVAL; - break; - } - return ret; -} - static int ixgbe_e_tag_forwarding_en_dis(struct rte_eth_dev *dev, bool en) { diff --git a/drivers/net/ixgbe/ixgbe_fdir.c b/drivers/net/ixgbe/ixgbe_fdir.c index 166dae1e0..9ba26cd52 100644 --- a/drivers/net/ixgbe/ixgbe_fdir.c +++ b/drivers/net/ixgbe/ixgbe_fdir.c @@ -1555,21 +1555,10 @@ ixgbe_fdir_ctrl_func(struct rte_eth_dev *dev, return -EINVAL; switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = ixgbe_add_del_fdir_filter(dev, - (struct rte_eth_fdir_filter *)arg, FALSE, FALSE); - break; case RTE_ETH_FILTER_UPDATE: ret = ixgbe_add_del_fdir_filter(dev, (struct rte_eth_fdir_filter *)arg, FALSE, TRUE); break; - case RTE_ETH_FILTER_DELETE: - ret = ixgbe_add_del_fdir_filter(dev, - (struct rte_eth_fdir_filter *)arg, TRUE, FALSE); - break; - case RTE_ETH_FILTER_FLUSH: - ret = ixgbe_fdir_flush(dev); - break; case RTE_ETH_FILTER_INFO: ixgbe_fdir_info_get(dev, (struct rte_eth_fdir_info *)arg); break; -- 2.17.1
remove the legacy filter functions in Intel i40e driver Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- drivers/net/i40e/i40e_ethdev.c | 454 --------------------------------- drivers/net/i40e/i40e_ethdev.h | 8 - drivers/net/i40e/i40e_fdir.c | 393 ---------------------------- 3 files changed, 855 deletions(-) diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9fbda1c34..1ee60f18e 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -317,9 +317,6 @@ static int i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev, static int i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *udp_tunnel); static void i40e_filter_input_set_init(struct i40e_pf *pf); -static int i40e_ethertype_filter_handle(struct rte_eth_dev *dev, - enum rte_filter_op filter_op, - void *arg); static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type, enum rte_filter_op filter_op, @@ -4204,119 +4201,6 @@ i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index) } } -/* Set perfect match or hash match of MAC and VLAN for a VF */ -static int -i40e_vf_mac_filter_set(struct i40e_pf *pf, - struct rte_eth_mac_filter *filter, - bool add) -{ - struct i40e_hw *hw; - struct i40e_mac_filter_info mac_filter; - struct rte_ether_addr old_mac; - struct rte_ether_addr *new_mac; - struct i40e_pf_vf *vf = NULL; - uint16_t vf_id; - int ret; - - if (pf == NULL) { - PMD_DRV_LOG(ERR, "Invalid PF argument."); - return -EINVAL; - } - hw = I40E_PF_TO_HW(pf); - - if (filter == NULL) { - PMD_DRV_LOG(ERR, "Invalid mac filter argument."); - return -EINVAL; - } - - new_mac = &filter->mac_addr; - - if (rte_is_zero_ether_addr(new_mac)) { - PMD_DRV_LOG(ERR, "Invalid ethernet address."); - return -EINVAL; - } - - vf_id = filter->dst_id; - - if (vf_id > pf->vf_num - 1 || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - vf = &pf->vfs[vf_id]; - - if (add && rte_is_same_ether_addr(new_mac, &pf->dev_addr)) { - PMD_DRV_LOG(INFO, "Ignore adding permanent MAC address."); - return -EINVAL; - } - - if (add) { - rte_memcpy(&old_mac, hw->mac.addr, RTE_ETHER_ADDR_LEN); - rte_memcpy(hw->mac.addr, new_mac->addr_bytes, - RTE_ETHER_ADDR_LEN); - rte_memcpy(&mac_filter.mac_addr, &filter->mac_addr, - RTE_ETHER_ADDR_LEN); - - mac_filter.filter_type = filter->filter_type; - ret = i40e_vsi_add_mac(vf->vsi, &mac_filter); - if (ret != I40E_SUCCESS) { - PMD_DRV_LOG(ERR, "Failed to add MAC filter."); - return -1; - } - rte_ether_addr_copy(new_mac, &pf->dev_addr); - } else { - rte_memcpy(hw->mac.addr, hw->mac.perm_addr, - RTE_ETHER_ADDR_LEN); - ret = i40e_vsi_delete_mac(vf->vsi, &filter->mac_addr); - if (ret != I40E_SUCCESS) { - PMD_DRV_LOG(ERR, "Failed to delete MAC filter."); - return -1; - } - - /* Clear device address as it has been removed */ - if (rte_is_same_ether_addr(&pf->dev_addr, new_mac)) - memset(&pf->dev_addr, 0, sizeof(struct rte_ether_addr)); - } - - return 0; -} - -/* MAC filter handle */ -static int -i40e_mac_filter_handle(struct rte_eth_dev *dev, enum rte_filter_op filter_op, - void *arg) -{ - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct rte_eth_mac_filter *filter; - struct i40e_hw *hw = I40E_PF_TO_HW(pf); - int ret = I40E_NOT_SUPPORTED; - - filter = (struct rte_eth_mac_filter *)(arg); - - switch (filter_op) { - case RTE_ETH_FILTER_NOP: - ret = I40E_SUCCESS; - break; - case RTE_ETH_FILTER_ADD: - i40e_pf_disable_irq0(hw); - if (filter->is_vf) - ret = i40e_vf_mac_filter_set(pf, filter, 1); - i40e_pf_enable_irq0(hw); - break; - case RTE_ETH_FILTER_DELETE: - i40e_pf_disable_irq0(hw); - if (filter->is_vf) - ret = i40e_vf_mac_filter_set(pf, filter, 0); - i40e_pf_enable_irq0(hw); - break; - default: - PMD_DRV_LOG(ERR, "unknown operation %u", filter_op); - ret = I40E_ERR_PARAM; - break; - } - - return ret; -} - static int i40e_get_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size) { @@ -7868,145 +7752,6 @@ i40e_sw_tunnel_filter_del(struct i40e_pf *pf, return 0; } -int -i40e_dev_tunnel_filter_set(struct i40e_pf *pf, - struct rte_eth_tunnel_filter_conf *tunnel_filter, - uint8_t add) -{ - uint16_t ip_type; - uint32_t ipv4_addr, ipv4_addr_le; - uint8_t i, tun_type = 0; - /* internal varialbe to convert ipv6 byte order */ - uint32_t convert_ipv6[4]; - int val, ret = 0; - struct i40e_hw *hw = I40E_PF_TO_HW(pf); - struct i40e_vsi *vsi = pf->main_vsi; - struct i40e_aqc_cloud_filters_element_bb *cld_filter; - struct i40e_aqc_cloud_filters_element_bb *pfilter; - struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel; - struct i40e_tunnel_filter *tunnel, *node; - struct i40e_tunnel_filter check_filter; /* Check if filter exists */ - - cld_filter = rte_zmalloc("tunnel_filter", - sizeof(struct i40e_aqc_add_rm_cloud_filt_elem_ext), - 0); - - if (NULL == cld_filter) { - PMD_DRV_LOG(ERR, "Failed to alloc memory."); - return -ENOMEM; - } - pfilter = cld_filter; - - rte_ether_addr_copy(&tunnel_filter->outer_mac, - (struct rte_ether_addr *)&pfilter->element.outer_mac); - rte_ether_addr_copy(&tunnel_filter->inner_mac, - (struct rte_ether_addr *)&pfilter->element.inner_mac); - - pfilter->element.inner_vlan = - rte_cpu_to_le_16(tunnel_filter->inner_vlan); - if (tunnel_filter->ip_type == RTE_TUNNEL_IPTYPE_IPV4) { - ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV4; - ipv4_addr = rte_be_to_cpu_32(tunnel_filter->ip_addr.ipv4_addr); - ipv4_addr_le = rte_cpu_to_le_32(ipv4_addr); - rte_memcpy(&pfilter->element.ipaddr.v4.data, - &ipv4_addr_le, - sizeof(pfilter->element.ipaddr.v4.data)); - } else { - ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV6; - for (i = 0; i < 4; i++) { - convert_ipv6[i] = - rte_cpu_to_le_32(rte_be_to_cpu_32(tunnel_filter->ip_addr.ipv6_addr[i])); - } - rte_memcpy(&pfilter->element.ipaddr.v6.data, - &convert_ipv6, - sizeof(pfilter->element.ipaddr.v6.data)); - } - - /* check tunneled type */ - switch (tunnel_filter->tunnel_type) { - case RTE_TUNNEL_TYPE_VXLAN: - tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN; - break; - case RTE_TUNNEL_TYPE_NVGRE: - tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC; - break; - case RTE_TUNNEL_TYPE_IP_IN_GRE: - tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_IP; - break; - case RTE_TUNNEL_TYPE_VXLAN_GPE: - tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE; - break; - default: - /* Other tunnel types is not supported. */ - PMD_DRV_LOG(ERR, "tunnel type is not supported."); - rte_free(cld_filter); - return -EINVAL; - } - - val = i40e_dev_get_filter_type(tunnel_filter->filter_type, - &pfilter->element.flags); - if (val < 0) { - rte_free(cld_filter); - return -EINVAL; - } - - pfilter->element.flags |= rte_cpu_to_le_16( - I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE | - ip_type | (tun_type << I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT)); - pfilter->element.tenant_id = rte_cpu_to_le_32(tunnel_filter->tenant_id); - pfilter->element.queue_number = - rte_cpu_to_le_16(tunnel_filter->queue_id); - - /* Check if there is the filter in SW list */ - memset(&check_filter, 0, sizeof(check_filter)); - i40e_tunnel_filter_convert(cld_filter, &check_filter); - node = i40e_sw_tunnel_filter_lookup(tunnel_rule, &check_filter.input); - if (add && node) { - PMD_DRV_LOG(ERR, "Conflict with existing tunnel rules!"); - rte_free(cld_filter); - return -EINVAL; - } - - if (!add && !node) { - PMD_DRV_LOG(ERR, "There's no corresponding tunnel filter!"); - rte_free(cld_filter); - return -EINVAL; - } - - if (add) { - ret = i40e_aq_add_cloud_filters(hw, - vsi->seid, &cld_filter->element, 1); - if (ret < 0) { - PMD_DRV_LOG(ERR, "Failed to add a tunnel filter."); - rte_free(cld_filter); - return -ENOTSUP; - } - tunnel = rte_zmalloc("tunnel_filter", sizeof(*tunnel), 0); - if (tunnel == NULL) { - PMD_DRV_LOG(ERR, "Failed to alloc memory."); - rte_free(cld_filter); - return -ENOMEM; - } - - rte_memcpy(tunnel, &check_filter, sizeof(check_filter)); - ret = i40e_sw_tunnel_filter_insert(pf, tunnel); - if (ret < 0) - rte_free(tunnel); - } else { - ret = i40e_aq_rem_cloud_filters(hw, vsi->seid, - &cld_filter->element, 1); - if (ret < 0) { - PMD_DRV_LOG(ERR, "Failed to delete a tunnel filter."); - rte_free(cld_filter); - return -ENOTSUP; - } - ret = i40e_sw_tunnel_filter_del(pf, &node->input); - } - - rte_free(cld_filter); - return ret; -} - #define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_TR_WORD0 0x48 #define I40E_TR_VXLAN_GRE_KEY_MASK 0x4 #define I40E_TR_GENEVE_KEY_MASK 0x8 @@ -8809,40 +8554,6 @@ i40e_pf_config_rss(struct i40e_pf *pf) return i40e_hw_rss_hash_set(pf, &rss_conf); } -static int -i40e_tunnel_filter_param_check(struct i40e_pf *pf, - struct rte_eth_tunnel_filter_conf *filter) -{ - if (pf == NULL || filter == NULL) { - PMD_DRV_LOG(ERR, "Invalid parameter"); - return -EINVAL; - } - - if (filter->queue_id >= pf->dev_data->nb_rx_queues) { - PMD_DRV_LOG(ERR, "Invalid queue ID"); - return -EINVAL; - } - - if (filter->inner_vlan > RTE_ETHER_MAX_VLAN_ID) { - PMD_DRV_LOG(ERR, "Invalid inner VLAN ID"); - return -EINVAL; - } - - if ((filter->filter_type & ETH_TUNNEL_FILTER_OMAC) && - (rte_is_zero_ether_addr(&filter->outer_mac))) { - PMD_DRV_LOG(ERR, "Cannot add NULL outer MAC address"); - return -EINVAL; - } - - if ((filter->filter_type & ETH_TUNNEL_FILTER_IMAC) && - (rte_is_zero_ether_addr(&filter->inner_mac))) { - PMD_DRV_LOG(ERR, "Cannot add NULL inner MAC address"); - return -EINVAL; - } - - return 0; -} - #define I40E_GL_PRS_FVBM_MSK_ENA 0x80000000 #define I40E_GL_PRS_FVBM(_i) (0x00269760 + ((_i) * 4)) static int @@ -8928,40 +8639,6 @@ i40e_filter_ctrl_global_config(struct rte_eth_dev *dev, return ret; } -static int -i40e_tunnel_filter_handle(struct rte_eth_dev *dev, - enum rte_filter_op filter_op, - void *arg) -{ - struct rte_eth_tunnel_filter_conf *filter; - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - int ret = I40E_SUCCESS; - - filter = (struct rte_eth_tunnel_filter_conf *)(arg); - - if (i40e_tunnel_filter_param_check(pf, filter) < 0) - return I40E_ERR_PARAM; - - switch (filter_op) { - case RTE_ETH_FILTER_NOP: - if (!(pf->flags & I40E_FLAG_VXLAN)) - ret = I40E_NOT_SUPPORTED; - break; - case RTE_ETH_FILTER_ADD: - ret = i40e_dev_tunnel_filter_set(pf, filter, 1); - break; - case RTE_ETH_FILTER_DELETE: - ret = i40e_dev_tunnel_filter_set(pf, filter, 0); - break; - default: - PMD_DRV_LOG(ERR, "unknown operation %u", filter_op); - ret = I40E_ERR_PARAM; - break; - } - - return ret; -} - static int i40e_pf_config_mq_rx(struct i40e_pf *pf) { @@ -9923,89 +9600,6 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw, return 0; } -int -i40e_fdir_filter_inset_select(struct i40e_pf *pf, - struct rte_eth_input_set_conf *conf) -{ - struct i40e_hw *hw = I40E_PF_TO_HW(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; - - if (!hw || !conf) { - PMD_DRV_LOG(ERR, "Invalid pointer"); - return -EFAULT; - } - if (conf->op != RTE_ETH_INPUT_SET_SELECT && - conf->op != RTE_ETH_INPUT_SET_ADD) { - PMD_DRV_LOG(ERR, "Unsupported input set operation"); - return -EINVAL; - } - - 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; - } - - 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; - } - - /* get inset value in register */ - inset_reg = i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 1)); - inset_reg <<= I40E_32_BIT_WIDTH; - inset_reg |= i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 0)); - - /* Can not change the inset reg for flex payload for fdir, - * it is done by writing I40E_PRTQF_FD_FLXINSET - * in i40e_set_flex_mask_on_pctype. - */ - if (conf->op == RTE_ETH_INPUT_SET_SELECT) - inset_reg &= I40E_REG_INSET_FLEX_PAYLOAD_WORDS; - else - input_set |= pf->fdir.input_set[pctype]; - num = i40e_generate_inset_mask_reg(input_set, mask_reg, - I40E_INSET_MASK_NUM_REG); - if (num < 0) - return -EINVAL; - if (pf->support_multi_driver && num > 0) { - PMD_DRV_LOG(ERR, "FDIR bit mask is not supported."); - return -ENOTSUP; - } - - inset_reg |= i40e_translate_input_set_reg(hw->mac.type, input_set); - - i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 0), - (uint32_t)(inset_reg & UINT32_MAX)); - i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 1), - (uint32_t)((inset_reg >> - I40E_32_BIT_WIDTH) & UINT32_MAX)); - - if (!pf->support_multi_driver) { - for (i = 0; i < num; i++) - i40e_check_write_global_reg(hw, - I40E_GLQF_FD_MSK(i, pctype), - mask_reg[i]); - /*clear unused mask registers of the pctype */ - for (i = num; i < I40E_INSET_MASK_NUM_REG; i++) - i40e_check_write_global_reg(hw, - I40E_GLQF_FD_MSK(i, pctype), - 0); - } else { - PMD_DRV_LOG(ERR, "FDIR bit mask is not supported."); - } - I40E_WRITE_FLUSH(hw); - - pf->fdir.input_set[pctype] = input_set; - return 0; -} - static int i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info) { @@ -10263,45 +9857,6 @@ i40e_ethertype_filter_set(struct i40e_pf *pf, return ret; } -/* - * Handle operations for ethertype filter. - */ -static int -i40e_ethertype_filter_handle(struct rte_eth_dev *dev, - enum rte_filter_op filter_op, - void *arg) -{ - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - int ret = 0; - - if (filter_op == RTE_ETH_FILTER_NOP) - return ret; - - if (arg == NULL) { - PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u", - filter_op); - return -EINVAL; - } - - switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = i40e_ethertype_filter_set(pf, - (struct rte_eth_ethertype_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = i40e_ethertype_filter_set(pf, - (struct rte_eth_ethertype_filter *)arg, - FALSE); - break; - default: - PMD_DRV_LOG(ERR, "unsupported operation %u", filter_op); - ret = -ENOSYS; - break; - } - return ret; -} - static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type, @@ -10321,15 +9876,6 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev, case RTE_ETH_FILTER_HASH: ret = i40e_hash_filter_ctrl(dev, filter_op, arg); break; - case RTE_ETH_FILTER_MACVLAN: - ret = i40e_mac_filter_handle(dev, filter_op, arg); - break; - case RTE_ETH_FILTER_ETHERTYPE: - ret = i40e_ethertype_filter_handle(dev, filter_op, arg); - break; - case RTE_ETH_FILTER_TUNNEL: - ret = i40e_tunnel_filter_handle(dev, filter_op, arg); - break; case RTE_ETH_FILTER_FDIR: ret = i40e_fdir_ctrl_func(dev, filter_op, arg); break; diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..22170dec6 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -1256,8 +1256,6 @@ int i40e_select_filter_input_set(struct i40e_hw *hw, void i40e_fdir_filter_restore(struct i40e_pf *pf); 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, - struct rte_eth_input_set_conf *conf); int i40e_pf_host_send_msg_to_vf(struct i40e_pf_vf *vf, uint32_t opcode, uint32_t retval, uint8_t *msg, uint16_t msglen); @@ -1285,15 +1283,9 @@ uint64_t i40e_get_default_input_set(uint16_t pctype); int i40e_ethertype_filter_set(struct i40e_pf *pf, struct rte_eth_ethertype_filter *filter, bool add); -int i40e_add_del_fdir_filter(struct rte_eth_dev *dev, - const struct rte_eth_fdir_filter *filter, - bool add); int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, const struct i40e_fdir_filter_conf *filter, bool add); -int i40e_dev_tunnel_filter_set(struct i40e_pf *pf, - struct rte_eth_tunnel_filter_conf *tunnel_filter, - uint8_t add); int i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, struct i40e_tunnel_filter_conf *tunnel_filter, uint8_t add); diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index 931f25976..6e052fbf9 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -84,10 +84,6 @@ (1ULL << RTE_ETH_FLOW_NONFRAG_IPV6_OTHER) | \ (1ULL << RTE_ETH_FLOW_L2_PAYLOAD)) -static int i40e_fdir_filter_programming(struct i40e_pf *pf, - enum i40e_filter_pctype pctype, - const struct rte_eth_fdir_filter *filter, - bool add); static int i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input, struct i40e_fdir_filter *filter); static struct i40e_fdir_filter * @@ -813,155 +809,6 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input, } -/* - * i40e_fdir_construct_pkt - construct packet based on fields in input - * @pf: board private structure - * @fdir_input: input set of the flow director entry - * @raw_pkt: a packet to be constructed - */ -static int -i40e_fdir_construct_pkt(struct i40e_pf *pf, - const struct rte_eth_fdir_input *fdir_input, - unsigned char *raw_pkt) -{ - unsigned char *payload, *ptr; - struct rte_udp_hdr *udp; - struct rte_tcp_hdr *tcp; - struct rte_sctp_hdr *sctp; - uint8_t size, dst = 0; - uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/ - int len; - - /* fill the ethernet and IP head */ - len = i40e_fdir_fill_eth_ip_head(fdir_input, raw_pkt, - !!fdir_input->flow_ext.vlan_tci); - if (len < 0) - return -EINVAL; - - /* fill the L4 head */ - switch (fdir_input->flow_type) { - case RTE_ETH_FLOW_NONFRAG_IPV4_UDP: - udp = (struct rte_udp_hdr *)(raw_pkt + len); - payload = (unsigned char *)udp + sizeof(struct rte_udp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - udp->src_port = fdir_input->flow.udp4_flow.dst_port; - udp->dst_port = fdir_input->flow.udp4_flow.src_port; - udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); - break; - - case RTE_ETH_FLOW_NONFRAG_IPV4_TCP: - tcp = (struct rte_tcp_hdr *)(raw_pkt + len); - payload = (unsigned char *)tcp + sizeof(struct rte_tcp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - tcp->src_port = fdir_input->flow.tcp4_flow.dst_port; - tcp->dst_port = fdir_input->flow.tcp4_flow.src_port; - tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; - break; - - case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: - sctp = (struct rte_sctp_hdr *)(raw_pkt + len); - payload = (unsigned char *)sctp + sizeof(struct rte_sctp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - sctp->src_port = fdir_input->flow.sctp4_flow.dst_port; - sctp->dst_port = fdir_input->flow.sctp4_flow.src_port; - sctp->tag = fdir_input->flow.sctp4_flow.verify_tag; - break; - - case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: - case RTE_ETH_FLOW_FRAG_IPV4: - payload = raw_pkt + len; - set_idx = I40E_FLXPLD_L3_IDX; - break; - - case RTE_ETH_FLOW_NONFRAG_IPV6_UDP: - udp = (struct rte_udp_hdr *)(raw_pkt + len); - payload = (unsigned char *)udp + sizeof(struct rte_udp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - udp->src_port = fdir_input->flow.udp6_flow.dst_port; - udp->dst_port = fdir_input->flow.udp6_flow.src_port; - udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); - break; - - case RTE_ETH_FLOW_NONFRAG_IPV6_TCP: - tcp = (struct rte_tcp_hdr *)(raw_pkt + len); - payload = (unsigned char *)tcp + sizeof(struct rte_tcp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; - tcp->src_port = fdir_input->flow.udp6_flow.dst_port; - tcp->dst_port = fdir_input->flow.udp6_flow.src_port; - break; - - case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: - sctp = (struct rte_sctp_hdr *)(raw_pkt + len); - payload = (unsigned char *)sctp + sizeof(struct rte_sctp_hdr); - /* - * The source and destination fields in the transmitted packet - * need to be presented in a reversed order with respect - * to the expected received packets. - */ - sctp->src_port = fdir_input->flow.sctp6_flow.dst_port; - sctp->dst_port = fdir_input->flow.sctp6_flow.src_port; - sctp->tag = fdir_input->flow.sctp6_flow.verify_tag; - break; - - case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: - case RTE_ETH_FLOW_FRAG_IPV6: - payload = raw_pkt + len; - set_idx = I40E_FLXPLD_L3_IDX; - break; - case RTE_ETH_FLOW_L2_PAYLOAD: - payload = raw_pkt + len; - /* - * ARP packet is a special case on which the payload - * starts after the whole ARP header - */ - if (fdir_input->flow.l2_flow.ether_type == - rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) - payload += sizeof(struct rte_arp_hdr); - set_idx = I40E_FLXPLD_L2_IDX; - break; - default: - PMD_DRV_LOG(ERR, "unknown flow type %u.", fdir_input->flow_type); - return -EINVAL; - } - - /* fill the flexbytes to payload */ - for (i = 0; i < I40E_MAX_FLXPLD_FIED; i++) { - pit_idx = set_idx * I40E_MAX_FLXPLD_FIED + i; - size = pf->fdir.flex_set[pit_idx].size; - if (size == 0) - continue; - dst = pf->fdir.flex_set[pit_idx].dst_offset * sizeof(uint16_t); - ptr = payload + - pf->fdir.flex_set[pit_idx].src_offset * sizeof(uint16_t); - rte_memcpy(ptr, - &fdir_input->flow_ext.flexbytes[dst], - size * sizeof(uint16_t)); - } - - return 0; -} - static struct i40e_customized_pctype * i40e_flow_fdir_find_customized_pctype(struct i40e_pf *pf, uint8_t pctype) { @@ -1607,68 +1454,6 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct i40e_fdir_input *input) return 0; } -/* - * i40e_add_del_fdir_filter - add or remove a flow director filter. - * @pf: board private structure - * @filter: fdir filter entry - * @add: 0 - delete, 1 - add - */ -int -i40e_add_del_fdir_filter(struct rte_eth_dev *dev, - const struct rte_eth_fdir_filter *filter, - bool add) -{ - struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; - enum i40e_filter_pctype pctype; - int ret = 0; - - if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) { - PMD_DRV_LOG(ERR, "FDIR is not enabled, please" - " check the mode in fdir_conf."); - return -ENOTSUP; - } - - pctype = i40e_flowtype_to_pctype(pf->adapter, filter->input.flow_type); - if (pctype == I40E_FILTER_PCTYPE_INVALID) { - PMD_DRV_LOG(ERR, "invalid flow_type input."); - return -EINVAL; - } - if (filter->action.rx_queue >= pf->dev_data->nb_rx_queues) { - PMD_DRV_LOG(ERR, "Invalid queue ID"); - return -EINVAL; - } - if (filter->input.flow_ext.is_vf && - filter->input.flow_ext.dst_id >= pf->vf_num) { - PMD_DRV_LOG(ERR, "Invalid VF ID"); - return -EINVAL; - } - - memset(pkt, 0, I40E_FDIR_PKT_LEN); - - ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt); - if (ret < 0) { - PMD_DRV_LOG(ERR, "construct packet for fdir fails."); - return ret; - } - - 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_fdir_filter_programming(pf, pctype, filter, add); - if (ret < 0) { - PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).", - pctype); - return ret; - } - - return ret; -} - /** * i40e_flow_add_del_fdir_filter - add or remove a flow director filter. * @pf: board private structure @@ -1771,141 +1556,6 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, return ret; } -/* - * i40e_fdir_filter_programming - Program a flow director filter rule. - * Is done by Flow Director Programming Descriptor followed by packet - * structure that contains the filter fields need to match. - * @pf: board private structure - * @pctype: pctype - * @filter: fdir filter entry - * @add: 0 - delete, 1 - add - */ -static int -i40e_fdir_filter_programming(struct i40e_pf *pf, - enum i40e_filter_pctype pctype, - const struct rte_eth_fdir_filter *filter, - bool add) -{ - struct i40e_tx_queue *txq = pf->fdir.txq; - struct i40e_rx_queue *rxq = pf->fdir.rxq; - const struct rte_eth_fdir_action *fdir_action = &filter->action; - volatile struct i40e_tx_desc *txdp; - volatile struct i40e_filter_program_desc *fdirdp; - uint32_t td_cmd; - uint16_t vsi_id, i; - uint8_t dest; - - PMD_DRV_LOG(INFO, "filling filter programming descriptor."); - fdirdp = (volatile struct i40e_filter_program_desc *) - (&(txq->tx_ring[txq->tx_tail])); - - fdirdp->qindex_flex_ptype_vsi = - rte_cpu_to_le_32((fdir_action->rx_queue << - I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & - I40E_TXD_FLTR_QW0_QINDEX_MASK); - - fdirdp->qindex_flex_ptype_vsi |= - rte_cpu_to_le_32((fdir_action->flex_off << - I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) & - I40E_TXD_FLTR_QW0_FLEXOFF_MASK); - - fdirdp->qindex_flex_ptype_vsi |= - rte_cpu_to_le_32((pctype << - I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) & - I40E_TXD_FLTR_QW0_PCTYPE_MASK); - - if (filter->input.flow_ext.is_vf) - vsi_id = pf->vfs[filter->input.flow_ext.dst_id].vsi->vsi_id; - else - /* Use LAN VSI Id by default */ - vsi_id = pf->main_vsi->vsi_id; - fdirdp->qindex_flex_ptype_vsi |= - rte_cpu_to_le_32(((uint32_t)vsi_id << - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & - I40E_TXD_FLTR_QW0_DEST_VSI_MASK); - - fdirdp->dtype_cmd_cntindex = - rte_cpu_to_le_32(I40E_TX_DESC_DTYPE_FILTER_PROG); - - if (add) - fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32( - I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << - I40E_TXD_FLTR_QW1_PCMD_SHIFT); - else - fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32( - I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << - I40E_TXD_FLTR_QW1_PCMD_SHIFT); - - if (fdir_action->behavior == RTE_ETH_FDIR_REJECT) - dest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET; - else if (fdir_action->behavior == RTE_ETH_FDIR_ACCEPT) - dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; - else if (fdir_action->behavior == RTE_ETH_FDIR_PASSTHRU) - dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER; - else { - PMD_DRV_LOG(ERR, "Failed to program FDIR filter:" - " unsupported fdir behavior."); - return -EINVAL; - } - - fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32((dest << - I40E_TXD_FLTR_QW1_DEST_SHIFT) & - I40E_TXD_FLTR_QW1_DEST_MASK); - - fdirdp->dtype_cmd_cntindex |= - rte_cpu_to_le_32((fdir_action->report_status<< - I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) & - I40E_TXD_FLTR_QW1_FD_STATUS_MASK); - - fdirdp->dtype_cmd_cntindex |= - rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK); - fdirdp->dtype_cmd_cntindex |= - rte_cpu_to_le_32( - ((uint32_t)pf->fdir.match_counter_index << - I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & - I40E_TXD_FLTR_QW1_CNTINDEX_MASK); - - fdirdp->fd_id = rte_cpu_to_le_32(filter->soft_id); - - PMD_DRV_LOG(INFO, "filling transmit descriptor."); - txdp = &(txq->tx_ring[txq->tx_tail + 1]); - txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr); - td_cmd = I40E_TX_DESC_CMD_EOP | - I40E_TX_DESC_CMD_RS | - I40E_TX_DESC_CMD_DUMMY; - - txdp->cmd_type_offset_bsz = - i40e_build_ctob(td_cmd, 0, I40E_FDIR_PKT_LEN, 0); - - txq->tx_tail += 2; /* set 2 descriptors above, fdirdp and txdp */ - if (txq->tx_tail >= txq->nb_tx_desc) - txq->tx_tail = 0; - /* Update the tx tail register */ - rte_wmb(); - I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail); - for (i = 0; i < I40E_FDIR_MAX_WAIT_US; i++) { - if ((txdp->cmd_type_offset_bsz & - rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) == - rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) - break; - rte_delay_us(1); - } - if (i >= I40E_FDIR_MAX_WAIT_US) { - PMD_DRV_LOG(ERR, "Failed to program FDIR filter:" - " time out to get DD on tx queue."); - return -ETIMEDOUT; - } - /* totally delay 10 ms to check programming status*/ - for (; i < I40E_FDIR_MAX_WAIT_US; i++) { - if (i40e_check_fdir_programming_status(rxq) >= 0) - return 0; - rte_delay_us(1); - } - PMD_DRV_LOG(ERR, - "Failed to program FDIR filter: programming status reported."); - return -ETIMEDOUT; -} - /* * i40e_flow_fdir_filter_programming - Program a flow director filter rule. * Is done by Flow Director Programming Descriptor followed by packet @@ -2224,32 +1874,6 @@ i40e_fdir_stats_get(struct rte_eth_dev *dev, struct rte_eth_fdir_stats *stat) I40E_PFQF_FDSTAT_BEST_CNT_SHIFT); } -static int -i40e_fdir_filter_set(struct rte_eth_dev *dev, - struct rte_eth_fdir_filter_info *info) -{ - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - int ret = 0; - - if (!info) { - PMD_DRV_LOG(ERR, "Invalid pointer"); - return -EFAULT; - } - - switch (info->info_type) { - case RTE_ETH_FDIR_FILTER_INPUT_SET_SELECT: - ret = i40e_fdir_filter_inset_select(pf, - &(info->info.input_set_conf)); - break; - default: - PMD_DRV_LOG(ERR, "FD filter info type (%d) not supported", - info->info_type); - return -EINVAL; - } - - return ret; -} - /* * i40e_fdir_ctrl_func - deal with all operations on flow director. * @pf: board private structure @@ -2274,26 +1898,9 @@ i40e_fdir_ctrl_func(struct rte_eth_dev *dev, return -EINVAL; switch (filter_op) { - case RTE_ETH_FILTER_ADD: - ret = i40e_add_del_fdir_filter(dev, - (struct rte_eth_fdir_filter *)arg, - TRUE); - break; - case RTE_ETH_FILTER_DELETE: - ret = i40e_add_del_fdir_filter(dev, - (struct rte_eth_fdir_filter *)arg, - FALSE); - break; - case RTE_ETH_FILTER_FLUSH: - ret = i40e_fdir_flush(dev); - break; case RTE_ETH_FILTER_INFO: i40e_fdir_info_get(dev, (struct rte_eth_fdir_info *)arg); break; - case RTE_ETH_FILTER_SET: - ret = i40e_fdir_filter_set(dev, - (struct rte_eth_fdir_filter_info *)arg); - break; case RTE_ETH_FILTER_STATS: i40e_fdir_stats_get(dev, (struct rte_eth_fdir_stats *)arg); break; -- 2.17.1
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> --- doc/guides/nics/i40e.rst | 14 + drivers/net/i40e/i40e_ethdev.c | 451 ++++++++++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 18 ++ drivers/net/i40e/i40e_flow.c | 186 +++++++++++--- 4 files changed, 597 insertions(+), 72 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..9ba87b032 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. +For exampale, to set queue region configuration queue 0, 1, 2, 3 +and set PCTYPE ipv4-tcp hash enable and set input set l3-src-only: + + testpmd> flow create 0 ingress pattern end actions rss types end \ + func 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 queue end / end + Limitations or Known issues --------------------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 1ee60f18e..e32138023 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -1653,6 +1653,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); @@ -11864,10 +11867,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_rte_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 @@ -12491,31 +12496,214 @@ 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_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_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_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}, }; - 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) { + 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_rte_flow_rss_filter *rss_item; + uint64_t input_bits; + + /* to check pctype same need without input set bits */ + input_bits = ~(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 & + input_bits) == + (conf->conf.types & input_bits)) + 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 & input_bits) == + (conf->conf.types & input_bits)) + 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. */ @@ -12535,6 +12723,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) @@ -12545,29 +12734,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 input_bits; + + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){ + i40e_set_symmetric_hash_enable_per_port(hw, 1); + } else { + input_bits = ~(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 & input_bits; + g_cfg.valid_bit_mask[0] = conf->conf.types & input_bits; + 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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 22170dec6..35701c6bc 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_rte_flow_rss_filter); + +/* rss filter list structure */ +struct i40e_rte_flow_rss_filter { + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
On Wed, 18 Mar 2020 01:47:06 +0000
Chenxu Di <chenxux.di@intel.com> wrote:
> remove legacy filter functions already implemented in rte_flow
> for drivers igb, ixgbe, and i40e.
> implement hash function include set hash function and set hash
> input set in rte_flow for driver i40e.
>
> Chenxu Di (4):
> net/e1000: remove the legacy filter functions
> net/ixgbe: remove the legacy filter functions
> net/i40e: remove the legacy filter functions
> net/i40e: implement hash function in rte flow API
>
> doc/guides/nics/i40e.rst | 14 +
> doc/guides/rel_notes/release_20_05.rst | 9 +
> drivers/net/e1000/igb_ethdev.c | 36 -
> drivers/net/i40e/i40e_ethdev.c | 913 +++++++++++--------------
> drivers/net/i40e/i40e_ethdev.h | 26 +-
> drivers/net/i40e/i40e_fdir.c | 393 -----------
> drivers/net/i40e/i40e_flow.c | 186 ++++-
> drivers/net/ixgbe/ixgbe_ethdev.c | 78 ---
> drivers/net/ixgbe/ixgbe_fdir.c | 11 -
> 9 files changed, 610 insertions(+), 1056 deletions(-)
>
This looks like an API break for users using the legacy filter API.
Even though filter_ctrl is marked as deprecated. That probably has
to wait for 20.11 until it is removed. At that point, drop the ethdev
ops handle, the rte_eth_dev_filter_ctrl API (etc) and fix all the test
code.
> -----Original Message----- > From: Di, ChenxuX <chenxux.di@intel.com> > Sent: Wednesday, March 18, 2020 09:47 > To: dev@dpdk.org > Cc: Yang, Qiming <qiming.yang@intel.com>; Di, ChenxuX > <chenxux.di@intel.com> > Subject: [PATCH 1/4] net/e1000: remove the legacy filter functions > > remove the legacy filter functions in Intel igb driver. > > Signed-off-by: Chenxu Di <chenxux.di@intel.com> > --- > doc/guides/rel_notes/release_20_05.rst | 9 +++++++ > drivers/net/e1000/igb_ethdev.c | 36 -------------------------- > 2 files changed, 9 insertions(+), 36 deletions(-) > > diff --git a/doc/guides/rel_notes/release_20_05.rst > b/doc/guides/rel_notes/release_20_05.rst > index 2190eaf85..e79f8d841 100644 > --- a/doc/guides/rel_notes/release_20_05.rst > +++ b/doc/guides/rel_notes/release_20_05.rst > @@ -56,6 +56,15 @@ New Features > Also, make sure to start the actual text at the margin. > > ========================================================= > > +* **remove legacy filter API and switch to rte flow** > + > + remove legacy filter API functions and switch to rte_flow in drivers, > including: > + > + * remove legacy filter API functions in the Intel igb driver. > + * remove legacy filter API functions in the Intel ixgbe driver. > + * remove legacy filter API functions in the Intel i40 driver. You only delete parts of the legacy function. > + * Added support set hash function and set hash input set in rte flow API. > + > > Removed Items > ------------- > diff --git a/drivers/net/e1000/igb_ethdev.c > b/drivers/net/e1000/igb_ethdev.c index 520fba8fa..2d660eb7e 100644 > --- a/drivers/net/e1000/igb_ethdev.c > +++ b/drivers/net/e1000/igb_ethdev.c > @@ -3716,16 +3716,6 @@ eth_igb_syn_filter_handle(struct rte_eth_dev > *dev, > } > > switch (filter_op) { > - case RTE_ETH_FILTER_ADD: > - ret = eth_igb_syn_filter_set(dev, > - (struct rte_eth_syn_filter *)arg, > - TRUE); > - break; > - case RTE_ETH_FILTER_DELETE: > - ret = eth_igb_syn_filter_set(dev, > - (struct rte_eth_syn_filter *)arg, > - FALSE); > - break; > case RTE_ETH_FILTER_GET: > ret = eth_igb_syn_filter_get(dev, > (struct rte_eth_syn_filter *)arg); > @@ -4207,12 +4197,6 @@ eth_igb_flex_filter_handle(struct rte_eth_dev > *dev, > } > > switch (filter_op) { > - case RTE_ETH_FILTER_ADD: > - ret = eth_igb_add_del_flex_filter(dev, filter, TRUE); > - break; > - case RTE_ETH_FILTER_DELETE: > - ret = eth_igb_add_del_flex_filter(dev, filter, FALSE); > - break; > case RTE_ETH_FILTER_GET: > ret = eth_igb_get_flex_filter(dev, filter); > break; > @@ -4713,16 +4697,6 @@ igb_ntuple_filter_handle(struct rte_eth_dev *dev, > } > > switch (filter_op) { > - case RTE_ETH_FILTER_ADD: > - ret = igb_add_del_ntuple_filter(dev, > - (struct rte_eth_ntuple_filter *)arg, > - TRUE); > - break; > - case RTE_ETH_FILTER_DELETE: > - ret = igb_add_del_ntuple_filter(dev, > - (struct rte_eth_ntuple_filter *)arg, > - FALSE); > - break; > case RTE_ETH_FILTER_GET: > ret = igb_get_ntuple_filter(dev, > (struct rte_eth_ntuple_filter *)arg); @@ -4894,16 > +4868,6 @@ igb_ethertype_filter_handle(struct rte_eth_dev *dev, > } > > switch (filter_op) { > - case RTE_ETH_FILTER_ADD: > - ret = igb_add_del_ethertype_filter(dev, > - (struct rte_eth_ethertype_filter *)arg, > - TRUE); > - break; > - case RTE_ETH_FILTER_DELETE: > - ret = igb_add_del_ethertype_filter(dev, > - (struct rte_eth_ethertype_filter *)arg, > - FALSE); > - break; > case RTE_ETH_FILTER_GET: > ret = igb_get_ethertype_filter(dev, > (struct rte_eth_ethertype_filter *)arg); > -- > 2.17.1
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> --- v2: -canceled remove legacy filter functions. --- doc/guides/nics/i40e.rst | 14 + doc/guides/rel_notes/release_20_05.rst | 6 + drivers/net/i40e/i40e_ethdev.c | 451 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 18 + drivers/net/i40e/i40e_flow.c | 186 ++++++++-- 5 files changed, 603 insertions(+), 72 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..9ba87b032 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. +For exampale, to set queue region configuration queue 0, 1, 2, 3 +and set PCTYPE ipv4-tcp hash enable and set input set l3-src-only: + + testpmd> flow create 0 ingress pattern end actions rss types end \ + func 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 queue 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..89ce8de6c 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,12 @@ 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 set hash function and set hash input set in rte flow API. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..62e4ef7a7 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_rte_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,214 @@ 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_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_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_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}, }; - 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) { + 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_rte_flow_rss_filter *rss_item; + uint64_t input_bits; + + /* to check pctype same need without input set bits */ + input_bits = ~(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 & + input_bits) == + (conf->conf.types & input_bits)) + 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 & input_bits) == + (conf->conf.types & input_bits)) + 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 +13188,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 +13199,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 input_bits; + + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){ + i40e_set_symmetric_hash_enable_per_port(hw, 1); + } else { + input_bits = ~(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 & input_bits; + g_cfg.valid_bit_mask[0] = conf->conf.types & input_bits; + 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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); + +/* rss filter list structure */ +struct i40e_rte_flow_rss_filter { + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
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> --- 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 | 6 + drivers/net/i40e/i40e_ethdev.c | 451 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 18 + drivers/net/i40e/i40e_flow.c | 186 ++++++++-- 5 files changed, 603 insertions(+), 72 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..03b117a99 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. +For exampale, to set queue region configuration queue 0, 1, 2, 3 +and set PCTYPE ipv4-tcp hash enable and set input set 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..89ce8de6c 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,12 @@ 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 set hash function and set hash input set in rte flow API. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..62e4ef7a7 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_rte_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,214 @@ 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_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_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_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}, }; - 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) { + 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_rte_flow_rss_filter *rss_item; + uint64_t input_bits; + + /* to check pctype same need without input set bits */ + input_bits = ~(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 & + input_bits) == + (conf->conf.types & input_bits)) + 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 & input_bits) == + (conf->conf.types & input_bits)) + 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 +13188,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 +13199,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 input_bits; + + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){ + i40e_set_symmetric_hash_enable_per_port(hw, 1); + } else { + input_bits = ~(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 & input_bits; + g_cfg.valid_bit_mask[0] = conf->conf.types & input_bits; + 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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); + +/* rss filter list structure */ +struct i40e_rte_flow_rss_filter { + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
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> --- 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 | 6 + drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++-- drivers/net/i40e/i40e_ethdev.h | 18 + drivers/net/i40e/i40e_flow.c | 186 ++++++++-- 5 files changed, 623 insertions(+), 72 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..03b117a99 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. +For exampale, to set queue region configuration queue 0, 1, 2, 3 +and set PCTYPE ipv4-tcp hash enable and set input set 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..89ce8de6c 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,12 @@ 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 set hash function and set hash input set in rte flow API. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..e80553010 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_rte_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_rte_flow_rss_filter *rss_item; + uint64_t input_bits; + + /* to check pctype same need without input set bits */ + input_bits = ~(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 & + input_bits) == + (conf->conf.types & input_bits)) + 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 & input_bits) == + (conf->conf.types & input_bits)) + 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 input_bits; + + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){ + i40e_set_symmetric_hash_enable_per_port(hw, 1); + } else { + input_bits = ~(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 & input_bits; + g_cfg.valid_bit_mask[0] = conf->conf.types & input_bits; + 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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); + +/* rss filter list structure */ +struct i40e_rte_flow_rss_filter { + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
Comments inline, I think many various name is not suitable. BTW you should CC Beilei and Zhaowei to review. Qiming > -----Original Message----- > From: Di, ChenxuX <chenxux.di@intel.com> > Sent: Monday, March 23, 2020 16:25 > To: dev@dpdk.org > Cc: Yang, Qiming <qiming.yang@intel.com>; Di, ChenxuX > <chenxux.di@intel.com> > Subject: [PATCH v4] 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> > --- > 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 | 6 + > drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++-- > drivers/net/i40e/i40e_ethdev.h | 18 + > drivers/net/i40e/i40e_flow.c | 186 ++++++++-- > 5 files changed, 623 insertions(+), 72 deletions(-) > > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index > d6e578eda..03b117a99 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. > +For exampale, to set queue region configuration queue 0, 1, 2, 3 and > +set PCTYPE ipv4-tcp hash enable and set input set 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 > + Do we have generic flow API statement in I40e in history? Can you merge this part to the whole statement, I think this feature is an adding for generic flow API not create API. > 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..89ce8de6c 100644 > --- a/doc/guides/rel_notes/release_20_05.rst > +++ b/doc/guides/rel_notes/release_20_05.rst > @@ -62,6 +62,12 @@ 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 set hash function and set hash input set in rte flow API. Add support for doing sth and sth > + > > Removed Items > ------------- > diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c > index 9539b0470..e80553010 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_rte_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[] = { I still confuse about why this table should define within function not in this header file or other place? > + {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_rte_flow_rss_filter *rss_item; > + uint64_t input_bits; Why not named rss_inset? > + > + /* to check pctype same need without input set bits */ > + input_bits = ~(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 & > + input_bits) == > + (conf->conf.types & input_bits)) > + 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 & input_bits) == > + (conf->conf.types & input_bits)) > + 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 input_bits; Same as above. > + > + if (conf->conf.func == > + RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ){ > + i40e_set_symmetric_hash_enable_per_port(hw, 1); > + } else { > + input_bits = ~(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 & > input_bits; > + g_cfg.valid_bit_mask[0] = conf->conf.types & input_bits; > + 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; > } > diff --git a/drivers/net/i40e/i40e_ethdev.h > b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); > + > +/* rss filter list structure */ > +struct i40e_rte_flow_rss_filter { > + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
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> --- 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 | 6 + drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++-- drivers/net/i40e/i40e_ethdev.h | 18 + drivers/net/i40e/i40e_flow.c | 186 ++++++++-- 5 files changed, 623 insertions(+), 72 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..03b117a99 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. +For exampale, to set queue region configuration queue 0, 1, 2, 3 +and set PCTYPE ipv4-tcp hash enable and set input set 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..12e85118f 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,12 @@ 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. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..2727eef80 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_rte_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_rte_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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); + +/* rss filter list structure */ +struct i40e_rte_flow_rss_filter { + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
Hi Chenxu, > -----Original Message----- > From: dev <dev-bounces@dpdk.org> On Behalf Of Chenxu Di > Sent: Tuesday, March 24, 2020 8:18 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 v5] 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> > --- > 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 | 6 + > drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++-- > drivers/net/i40e/i40e_ethdev.h | 18 + > drivers/net/i40e/i40e_flow.c | 186 ++++++++-- > 5 files changed, 623 insertions(+), 72 deletions(-) > > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index > d6e578eda..03b117a99 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. > +For exampale, to set queue region configuration queue 0, 1, 2, 3 and > +set PCTYPE ipv4-tcp hash enable and set input set 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..12e85118f 100644 > --- a/doc/guides/rel_notes/release_20_05.rst > +++ b/doc/guides/rel_notes/release_20_05.rst > @@ -62,6 +62,12 @@ 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. > + > > Removed Items > ------------- > diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c > index 9539b0470..2727eef80 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_rte_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_rte_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; > } > diff --git a/drivers/net/i40e/i40e_ethdev.h > b/drivers/net/i40e/i40e_ethdev.h index aac89de91..1e4e64ea7 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_rte_flow_rss_filter); > + > +/* rss filter list structure */ > +struct i40e_rte_flow_rss_filter { > + TAILQ_ENTRY(i40e_rte_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..4774fde6d 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)) Should the line above be if (conf_info->queue_region_number && (p_info.types || rss->types)) to allow RSS configuration of types and queues in a single rule, for example: flow create 0 ingress pattern eth / end actions rss types udp end queues 2 3 end / end > + 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_rte_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_rte_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_rte_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_rte_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_rte_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>
> [snip]
>
> > > --- 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))
> >
> > Should the line above be
> >
> > if (conf_info->queue_region_number && (p_info.types || rss->types))
> >
> > to allow RSS configuration of types and queues in a single rule, for example:
> >
> > flow create 0 ingress pattern eth / end actions rss types udp end
> > queues 2 3 end / end
> >
>
> For the conf_info->queue_region_number and rss->queue_num, In the old
> codes, if there is eth or vlan, the conf_info->queue_region_number will be
> set as 1 in the function parse pattern.
> And in the parse action function it will check the conf_info-
> >queue_region_number.
> If conf_info->queue_region_number == 1, it will do some things and return.
> It will not do the things but do others while conf_info-
> >queue_region_number == 0.
> And after parse it will call the function i40e_flush_queue_region_all_conf() if
> conf_info->queue_region_number == 1 While call the function
> i40e_config_rss_filter() if conf_info->queue_region_number == 0.
>
> So what I changed is only when conf_info->queue_region_number == 0.
>
> Btw, in i40e, the queue configuration is for a port, it can't be for one rule or
> one type.
> So I don't think it is a good idea for allowing RSS configuration of types and
> queues in a single rule.
Would you suggest two rules as follows?
To configure the queues:
flow create 0 ingress pattern end actions rss queues 2 3 end / end
To configure the hash:
flow create 0 ingress pattern eth / ipv4 / end actions rss types ipv4 end key_len 0 queues end / end
(above rule is used on the ice pmd)
Regards,
Bernard
> -----Original Message----- > From: Di, ChenxuX <chenxux.di@intel.com> > Sent: Tuesday, March 24, 2020 4:18 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 v5] net/i40e: implement hash function in rte flow API > > implement set hash global configurations, set symmetric hash enable and What does the global configuration mean? > set hash input set in rte flow API. > > Signed-off-by: Chenxu Di <chenxux.di@intel.com> > --- > 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 | 6 + > drivers/net/i40e/i40e_ethdev.c | 471 +++++++++++++++++++++++-- > drivers/net/i40e/i40e_ethdev.h | 18 + > drivers/net/i40e/i40e_flow.c | 186 ++++++++-- > 5 files changed, 623 insertions(+), 72 deletions(-) > > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index > d6e578eda..03b117a99 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. > +For exampale, to set queue region configuration queue 0, 1, 2, 3 and Example. > +set PCTYPE ipv4-tcp hash enable and set input set l3-src-only: 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..12e85118f 100644 > --- a/doc/guides/rel_notes/release_20_05.rst > +++ b/doc/guides/rel_notes/release_20_05.rst > @@ -62,6 +62,12 @@ 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. Not only input set configuration, but also other functions. And it's for rte flow. > + > > Removed Items > ------------- > diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c > index 9539b0470..2727eef80 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_rte_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; Since you defined ret, better to use ret as return value. > + 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_rte_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 /* Disable RSS and configure with default input set */ > +int i40e_config_hash_pctype_del(struct i40e_pf *pf, Why use pctype in the function name? > + 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) { Seems the function name is not related to queue region in above comments. > + 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..1e4e64ea7 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; Why is 'action_flag' in pattern_info? > + 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_rte_flow_rss_filter); > + > +/* rss filter list structure */ > +struct i40e_rte_flow_rss_filter { Don't use _rte_ in PMD. > + TAILQ_ENTRY(i40e_rte_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 */ Typo: rule list > struct i40e_queue_regions queue_region; /* queue region info */ > struct i40e_fc_conf fc_conf; /* Flow control conf */ > struct i40e_mirror_rule_list mirror_list; diff --git > a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index > d877ac250..4774fde6d 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_rte_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_rte_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_rte_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_rte_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_rte_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
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; + 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; } 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
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
This patch supports: - symmetric hash by rte_flow RSS action. - input set change by rte_flow RSS action. Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- v7: -Updated code about symmetric hash function --- doc/guides/nics/i40e.rst | 35 ++ doc/guides/rel_notes/release_20_05.rst | 7 + drivers/net/i40e/i40e_ethdev.c | 509 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 22 +- drivers/net/i40e/i40e_flow.c | 197 ++++++++-- 5 files changed, 682 insertions(+), 88 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..1f8fca285 100644 --- a/doc/guides/nics/i40e.rst +++ b/doc/guides/nics/i40e.rst @@ -569,6 +569,41 @@ details please refer to :doc:`../testpmd_app_ug/index`. testpmd> set port (port_id) queue-region flush (on|off) testpmd> show port (port_id) queue-region +Generic flow API +~~~~~~~~~~~~~~~~~~~ + +- ``RSS Flow`` + + RSS Flow supports to set hash input set, hash function, enable hash + and configure queue region. + For example: + Configure queue region as queue 0, 1, 2, 3. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues 0 1 2 3 end / end + + Enable hash and set input set for ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp l3-src-only end queues end / end + + Set symmetric hash enable for flow type ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp end queues end func symmetric_toeplitz / end + + Set hash function as simple xor. + + .. code-block:: console + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues end func simple_xor / end + Limitations or Known issues --------------------------- diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst index 000bbf501..bf5f399fe 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,13 @@ New Features * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit. +* **Updated Intel i40e driver.** + + Updated i40e PMD with new features and improvements, including: + + * Added support for RSS using L3/L4 source/destination only. + * Added support for setting hash function in rte flow. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..f33c23377 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -1656,6 +1656,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) /* initialize mirror rule list */ TAILQ_INIT(&pf->mirror_list); + /* initialize RSS rule list */ + TAILQ_INIT(&pf->rss_config_list); + /* initialize Traffic Manager configuration */ i40e_tm_conf_init(dev); @@ -12325,14 +12328,16 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf) } } -/* Restore rss filter */ +/* Restore RSS filter */ static inline void i40e_rss_filter_restore(struct i40e_pf *pf) { - struct i40e_rte_flow_rss_conf *conf = - &pf->rss_info; - if (conf->conf.queue_num) - i40e_config_rss_filter(pf, conf, TRUE); + struct i40e_rss_conf_list *list = &pf->rss_config_list; + struct i40e_rss_filter *filter; + + TAILQ_FOREACH(filter, list, next) { + i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE); + } } static void @@ -12942,45 +12947,274 @@ i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, return 0; } -int -i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with) +/* Set hash input set */ +static int +i40e_rss_set_hash_inputset(struct i40e_pf *pf, uint64_t types) { - return (comp->func == with->func && - comp->level == with->level && - comp->types == with->types && - comp->key_len == with->key_len && - comp->queue_num == with->queue_num && - !memcmp(comp->key, with->key, with->key_len) && - !memcmp(comp->queue, with->queue, - sizeof(*with->queue) * with->queue_num)); + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct rte_eth_input_set_conf conf; + int i, ret; + uint32_t j; + static const struct { + uint64_t type; + enum rte_eth_input_set_field field; + } inset_match_table[] = { + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + }; + + ret = 0; + + for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(types & (1ULL << i))) + continue; + + conf.op = RTE_ETH_INPUT_SET_SELECT; + conf.flow_type = i; + conf.inset_size = 0; + for (j = 0; j < RTE_DIM(inset_match_table); j++) { + if ((types & inset_match_table[j].type) == + inset_match_table[j].type) { + if (inset_match_table[j].field == + RTE_ETH_INPUT_SET_UNKNOWN) { + return -EINVAL; + } + conf.field[conf.inset_size] = + inset_match_table[j].field; + conf.inset_size++; + } + } + + if (conf.inset_size) { + ret = i40e_hash_filter_inset_select(hw, &conf); + if (ret) + return ret; + } + } + + return ret; } -int -i40e_config_rss_filter(struct i40e_pf *pf, - struct i40e_rte_flow_rss_conf *conf, bool add) +/* Look up the conflicted rule then mark it as invalid */ +static void +i40e_rss_mark_invalid_rule(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_rss_filter *rss_item; + uint64_t rss_inset; + + /* Clear input set bits before comparing the pctype */ + rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY | + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY); + + TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) { + if (!rss_item->rss_filter_info.valid) + continue; + + /* Rule for queue region */ + if (conf->conf.queue_num && + rss_item->rss_filter_info.conf.queue_num) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash input set */ + if (conf->conf.types && + (rss_item->rss_filter_info.conf.types & + rss_inset) == + (conf->conf.types & rss_inset)) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash function */ + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + rss_item->rss_filter_info.conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + rss_item->rss_filter_info.valid = false; + } +} + +/* Configure RSS hash function */ +static int +i40e_rss_config_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) { struct i40e_hw *hw = I40E_PF_TO_HW(pf); - uint32_t i, lut = 0; - uint16_t j, num; - struct rte_eth_rss_conf rss_conf = { - .rss_key = conf->conf.key_len ? - (void *)(uintptr_t)conf->conf.key : NULL, - .rss_key_len = conf->conf.key_len, - .rss_hf = conf->conf.types, - }; - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t reg, i; + uint16_t j; - if (!add) { - if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) { - i40e_pf_disable_rss(pf); - memset(rss_info, 0, - sizeof(struct i40e_rte_flow_rss_conf)); - return 0; + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) { + i40e_set_symmetric_hash_enable_per_port(hw, 1); + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (!(mask0 & (1UL << i))) + continue; + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + I40E_GLQF_HSYM_SYMH_ENA_MASK); + } } + + return 0; + } + + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) { + PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR"); + goto out; + } + reg &= ~I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Set hash input set and enable hash */ +static int +i40e_rss_enable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, + struct rte_eth_rss_conf *rss_conf) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + + if (!(rss_conf->rss_hf & pf->adapter->flow_types_mask)) + return -ENOTSUP; + + /* Confirm hash input set */ + if (i40e_rss_set_hash_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); + + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) + i40e_rss_config_hash_function(pf, conf); + + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS queue region */ +static int +i40e_rss_config_queue_region(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint32_t i, lut; + uint16_t j, num; + /* If both VMDQ and RSS enabled, not all of PF queues are configured. * It's necessary to calculate the actual PF queues that are configured. */ @@ -13000,6 +13234,7 @@ i40e_config_rss_filter(struct i40e_pf *pf, return -ENOTSUP; } + lut = 0; /* Fill in redirection table */ for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { if (j == num) @@ -13010,29 +13245,203 @@ i40e_config_rss_filter(struct i40e_pf *pf, I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); } - if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) { - i40e_pf_disable_rss(pf); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS hash function to default */ +static int +i40e_rss_clear_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t i, reg; + uint16_t j; + + if (conf->conf.func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (mask0 & (1UL << i)) { + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & + (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + 0); + } + } + } + return 0; } - if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < - (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { - /* Random default keys */ - static uint32_t rss_key_default[] = {0x6b793944, - 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, - 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, - 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; - rss_conf.rss_key = (uint8_t *)rss_key_default; - rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * - sizeof(uint32_t); - PMD_DRV_LOG(INFO, - "No valid RSS key config for i40e, using default\n"); + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (reg & I40E_GLQF_CTL_HTOEP_MASK) { + PMD_DRV_LOG(DEBUG, + "Hash function already set to Toeplitz"); + goto out; } + reg |= I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + + return 0; +} +/* Disable RSS hash and configure default input set */ +static int +i40e_rss_disable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_eth_rss_conf rss_conf = { + .rss_key = pf->rss_info.conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = pf->rss_info.conf.key_len, + }; + uint32_t i; + + /* Disable RSS hash */ + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types); i40e_hw_rss_hash_set(pf, &rss_conf); - if (i40e_rss_conf_init(rss_info, &conf->conf)) - return -EINVAL; + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(conf->conf.types & (1ULL << i))) + continue; + + /* Configure default input set */ + struct rte_eth_input_set_conf input_conf = { + .op = RTE_ETH_INPUT_SET_SELECT, + .flow_type = i, + .inset_size = 1, + }; + input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT; + i40e_hash_filter_inset_select(hw, &input_conf); + } + + rss_info->conf.types = rss_conf.rss_hf; + + i40e_rss_clear_hash_function(pf, conf); + + return 0; +} + +/* Configure RSS queue region to default */ +static int +i40e_rss_clear_queue_region(struct i40e_pf *pf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint16_t queue[I40E_MAX_Q_PER_TC]; + uint32_t num_rxq, i, lut; + uint16_t j, num; + + num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, I40E_MAX_Q_PER_TC); + + for (j = 0; j < num_rxq; j++) + queue[j] = j; + + /* If both VMDQ and RSS enabled, not all of PF queues are configured. + * It's necessary to calculate the actual PF queues that are configured. + */ + if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG) + num = i40e_pf_calc_configured_queues_num(pf); + else + num = pf->dev_data->nb_rx_queues; + + num = RTE_MIN(num, num_rxq); + PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured", + num); + + if (num == 0) { + PMD_DRV_LOG(ERR, + "No PF queues are configured to enable RSS for port %u", + pf->dev_data->port_id); + return -ENOTSUP; + } + + lut = 0; + /* Fill in redirection table */ + for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { + if (j == num) + j = 0; + lut = (lut << 8) | (queue[j] & ((0x1 << + hw->func_caps.rss_table_entry_width) - 1)); + if ((i & 3) == 3) + I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); + } + + rss_info->conf.queue_num = 0; + memset(&rss_info->conf.queue, 0, sizeof(uint16_t)); + + return 0; +} + +int +i40e_config_rss_filter(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, bool add) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_flow_action_rss update_conf = rss_info->conf; + struct rte_eth_rss_conf rss_conf = { + .rss_key = conf->conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = conf->conf.key_len, + .rss_hf = conf->conf.types, + }; + int ret = 0; + + if (add) { + if (conf->conf.queue_num) { + /* Configure RSS queue region */ + ret = i40e_rss_config_queue_region(pf, conf); + if (ret) + return ret; + + update_conf.queue_num = conf->conf.queue_num; + update_conf.queue = conf->conf.queue; + } else if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + /* Configure hash function */ + ret = i40e_rss_config_hash_function(pf, conf); + if (ret) + return ret; + + update_conf.func = conf->conf.func; + } else { + /* Configure hash enable and input set */ + ret = i40e_rss_enable_hash(pf, conf, &rss_conf); + if (ret) + return ret; + + update_conf.types = rss_conf.rss_hf; + update_conf.key = rss_conf.rss_key; + update_conf.key_len = rss_conf.rss_key_len; + } + + /* Update RSS info in pf */ + if (i40e_rss_conf_init(rss_info, &update_conf)) + return -EINVAL; + } else { + if (!conf->valid) + return 0; + + if (conf->conf.queue_num) + i40e_rss_clear_queue_region(pf); + else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + i40e_rss_clear_hash_function(pf, conf); + else + i40e_rss_disable_hash(pf, conf); + } return 0; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..e9d90fa35 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -194,6 +194,9 @@ enum i40e_flxpld_layer_idx { #define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK \ I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT) +#define I40E_RSS_TYPE_NONE 0ULL +#define I40E_RSS_TYPE_INVALID 1ULL + #define I40E_INSET_NONE 0x00000000000000000ULL /* bit0 ~ bit 7 */ @@ -749,6 +752,11 @@ struct i40e_queue_regions { struct i40e_queue_region_info region[I40E_REGION_MAX_INDEX + 1]; }; +struct i40e_rss_pattern_info { + uint8_t action_flag; + uint64_t types; +}; + /* Tunnel filter number HW supports */ #define I40E_MAX_TUNNEL_FILTER_NUM 400 @@ -968,6 +976,15 @@ struct i40e_rte_flow_rss_conf { I40E_VFQF_HKEY_MAX_INDEX : I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)]; /* Hash key. */ uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. */ + bool valid; /* Check if it's valid */ +}; + +TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter); + +/* RSS filter list structure */ +struct i40e_rss_filter { + TAILQ_ENTRY(i40e_rss_filter) next; + struct i40e_rte_flow_rss_conf rss_filter_info; }; struct i40e_vf_msg_cfg { @@ -1038,7 +1055,8 @@ struct i40e_pf { struct i40e_fdir_info fdir; /* flow director info */ struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */ struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */ - struct i40e_rte_flow_rss_conf rss_info; /* rss info */ + struct i40e_rte_flow_rss_conf rss_info; /* RSS info */ + struct i40e_rss_conf_list rss_config_list; /* RSS rule list */ struct i40e_queue_regions queue_region; /* queue region info */ struct i40e_fc_conf fc_conf; /* Flow control conf */ struct i40e_mirror_rule_list mirror_list; @@ -1338,8 +1356,6 @@ int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len); int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size); int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, const struct rte_flow_action_rss *in); -int i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with); int i40e_config_rss_filter(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *conf, bool add); int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index d877ac250..c7d92ab44 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -4424,29 +4424,80 @@ i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev, * function for RSS, or flowtype for queue region configuration. * For example: * pattern: - * Case 1: only ETH, indicate flowtype for queue region will be parsed. - * Case 2: only VLAN, indicate user_priority for queue region will be parsed. - * Case 3: none, indicate RSS related will be parsed in action. - * Any pattern other the ETH or VLAN will be treated as invalid except END. + * Case 1: try to transform patterns to pctype. valid pctype will be + * used in parse action. + * Case 2: only ETH, indicate flowtype for queue region will be parsed. + * Case 3: only VLAN, indicate user_priority for queue region will be parsed. * So, pattern choice is depened on the purpose of configuration of * that flow. * action: - * action RSS will be uaed to transmit valid parameter with + * action RSS will be used to transmit valid parameter with * struct rte_flow_action_rss for all the 3 case. */ static int i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - uint8_t *action_flag, + struct i40e_rss_pattern_info *p_info, struct i40e_queue_regions *info) { const struct rte_flow_item_vlan *vlan_spec, *vlan_mask; const struct rte_flow_item *item = pattern; enum rte_flow_item_type item_type; - - if (item->type == RTE_FLOW_ITEM_TYPE_END) + struct rte_flow_item *items; + uint32_t item_num = 0; /* non-void item number of pattern*/ + uint32_t i = 0; + static const struct { + enum rte_flow_item_type *item_array; + uint64_t type; + } i40e_rss_pctype_patterns[] = { + { pattern_fdir_ipv4, + ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER }, + { pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP }, + { pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP }, + { pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP }, + { pattern_fdir_ipv6, + ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER }, + { pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP }, + { pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP }, + { pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP }, + }; + + p_info->types = I40E_RSS_TYPE_INVALID; + + if (item->type == RTE_FLOW_ITEM_TYPE_END) { + p_info->types = I40E_RSS_TYPE_NONE; return 0; + } + + /* convert flow to pctype */ + while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { + if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID) + item_num++; + i++; + } + item_num++; + + items = rte_zmalloc("i40e_pattern", + item_num * sizeof(struct rte_flow_item), 0); + if (!items) { + rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM, + NULL, "No memory for PMD internal items."); + return -ENOMEM; + } + + i40e_pattern_skip_void_item(items, pattern); + + for (i = 0; i < RTE_DIM(i40e_rss_pctype_patterns); i++) { + if (i40e_match_pattern(i40e_rss_pctype_patterns[i].item_array, + items)) { + p_info->types = i40e_rss_pctype_patterns[i].type; + rte_free(items); + return 0; + } + } + + rte_free(items); for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { if (item->last) { @@ -4459,7 +4510,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, item_type = item->type; switch (item_type) { case RTE_FLOW_ITEM_TYPE_ETH: - *action_flag = 1; + p_info->action_flag = 1; break; case RTE_FLOW_ITEM_TYPE_VLAN: vlan_spec = item->spec; @@ -4472,7 +4523,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, vlan_spec->tci) >> 13) & 0x7; info->region[0].user_priority_num = 1; info->queue_region_number = 1; - *action_flag = 0; + p_info->action_flag = 0; } } break; @@ -4500,12 +4551,14 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, * max index should be 7, and so on. And also, queue index should be * continuous sequence and queue region index should be part of rss * queue index for this port. + * For hash params, the pctype in action and pattern must be same. + * Set queue index must be with non-types. */ static int i40e_flow_parse_rss_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - uint8_t action_flag, + struct i40e_rss_pattern_info p_info, struct i40e_queue_regions *conf_info, union i40e_filter_t *filter) { @@ -4516,7 +4569,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, struct i40e_rte_flow_rss_conf *rss_config = &filter->rss_conf; struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; - uint16_t i, j, n, tmp; + uint16_t i, j, n, tmp, nb_types; uint32_t index = 0; uint64_t hf_bit = 1; @@ -4535,7 +4588,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, return -rte_errno; } - if (action_flag) { + if (p_info.action_flag) { for (n = 0; n < 64; n++) { if (rss->types & (hf_bit << n)) { conf_info->region[0].hw_flowtype[0] = n; @@ -4674,11 +4727,11 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, if (rss_config->queue_region_conf) return 0; - if (!rss || !rss->queue_num) { + if (!rss) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, - "no valid queues"); + "invalid rule"); return -rte_errno; } @@ -4692,19 +4745,48 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, } } - if (rss_info->conf.queue_num) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, - act, - "rss only allow one valid rule"); - return -rte_errno; + if (rss->queue_num && (p_info.types || rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "rss types must be empty while configuring queue region"); + + /* validate pattern and pctype */ + if (!(rss->types & p_info.types) && + (rss->types || p_info.types) && !rss->queue_num) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + act, "invaild pctype"); + + nb_types = 0; + for (n = 0; n < RTE_ETH_FLOW_MAX; n++) { + if (rss->types & (hf_bit << n)) + nb_types++; + if (nb_types > 1) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, + act, "multi pctype is not supported"); } + if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + (p_info.types || rss->types || rss->queue_num)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pattern, type and queues must be empty while" + " setting hash function as simple_xor"); + + if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ && + !(p_info.types && rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pctype and queues can not be empty while" + " setting hash function as symmetric toeplitz"); + /* Parse RSS related parameters from configuration */ - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX || + rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, - "non-default RSS hash functions are not supported"); + "RSS hash functions are not supported"); if (rss->level) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, @@ -4748,17 +4830,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 +4860,33 @@ i40e_config_rss_filter_set(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; int ret; if (conf->queue_region_conf) { ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1); - conf->queue_region_conf = 0; } else { ret = i40e_config_rss_filter(pf, conf, 1); } - return ret; + + if (ret) + return ret; + + rss_filter = rte_zmalloc("i40e_rss_filter", + sizeof(*rss_filter), 0); + if (rss_filter == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + rss_filter->rss_filter_info = *conf; + /* the rule new created is always valid + * the existing rule covered by new rule will be set invalid + */ + rss_filter->rss_filter_info.valid = true; + + TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next); + + return 0; } static int @@ -4794,10 +4895,21 @@ i40e_config_rss_filter_del(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; + void *temp; - i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + if (conf->queue_region_conf) + i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + else + i40e_config_rss_filter(pf, conf, 0); - i40e_config_rss_filter(pf, conf, 0); + TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) { + if (!memcmp(&rss_filter->rss_filter_info, conf, + sizeof(struct rte_flow_action_rss))) { + TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next); + rte_free(rss_filter); + } + } return 0; } @@ -4940,7 +5052,8 @@ i40e_flow_create(struct rte_eth_dev *dev, &cons_filter.rss_conf); if (ret) goto free_flow; - flow->rule = &pf->rss_info; + flow->rule = TAILQ_LAST(&pf->rss_config_list, + i40e_rss_conf_list); break; default: goto free_flow; @@ -4990,7 +5103,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, break; case RTE_ETH_FILTER_HASH: ret = i40e_config_rss_filter_del(dev, - (struct i40e_rte_flow_rss_conf *)flow->rule); + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); break; default: PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", @@ -5248,13 +5361,27 @@ static int i40e_flow_flush_rss_filter(struct rte_eth_dev *dev) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_flow *flow; + void *temp; int32_t ret = -EINVAL; ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0); - if (rss_info->conf.queue_num) - ret = i40e_config_rss_filter(pf, rss_info, FALSE); + /* Delete rss flows in flow list. */ + TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) { + if (flow->filter_type != RTE_ETH_FILTER_HASH) + continue; + + if (flow->rule) { + ret = i40e_config_rss_filter_del(dev, + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); + if (ret) + return ret; + } + TAILQ_REMOVE(&pf->flow_list, flow, node); + rte_free(flow); + } + return ret; } -- 2.17.1
This patch supports: - symmetric hash configuration - Input set configuration Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- doc/guides/nics/i40e.rst | 35 ++ doc/guides/rel_notes/release_20_05.rst | 7 + drivers/net/i40e/i40e_ethdev.c | 509 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 22 +- drivers/net/i40e/i40e_flow.c | 199 ++++++++-- 5 files changed, 683 insertions(+), 89 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..1f8fca285 100644 --- a/doc/guides/nics/i40e.rst +++ b/doc/guides/nics/i40e.rst @@ -569,6 +569,41 @@ details please refer to :doc:`../testpmd_app_ug/index`. testpmd> set port (port_id) queue-region flush (on|off) testpmd> show port (port_id) queue-region +Generic flow API +~~~~~~~~~~~~~~~~~~~ + +- ``RSS Flow`` + + RSS Flow supports to set hash input set, hash function, enable hash + and configure queue region. + For example: + Configure queue region as queue 0, 1, 2, 3. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues 0 1 2 3 end / end + + Enable hash and set input set for ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp l3-src-only end queues end / end + + Set symmetric hash enable for flow type ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp end queues end func symmetric_toeplitz / end + + Set hash function as simple xor. + + .. code-block:: console + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues end func simple_xor / end + Limitations or Known issues --------------------------- diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst index 000bbf501..bf5f399fe 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -62,6 +62,13 @@ New Features * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit. +* **Updated Intel i40e driver.** + + Updated i40e PMD with new features and improvements, including: + + * Added support for RSS using L3/L4 source/destination only. + * Added support for setting hash function in rte flow. + Removed Items ------------- diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 9539b0470..efc113842 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -1656,6 +1656,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) /* initialize mirror rule list */ TAILQ_INIT(&pf->mirror_list); + /* initialize RSS rule list */ + TAILQ_INIT(&pf->rss_config_list); + /* initialize Traffic Manager configuration */ i40e_tm_conf_init(dev); @@ -12325,14 +12328,16 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf) } } -/* Restore rss filter */ +/* Restore RSS filter */ static inline void i40e_rss_filter_restore(struct i40e_pf *pf) { - struct i40e_rte_flow_rss_conf *conf = - &pf->rss_info; - if (conf->conf.queue_num) - i40e_config_rss_filter(pf, conf, TRUE); + struct i40e_rss_conf_list *list = &pf->rss_config_list; + struct i40e_rss_filter *filter; + + TAILQ_FOREACH(filter, list, next) { + i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE); + } } static void @@ -12942,45 +12947,274 @@ i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, return 0; } -int -i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with) +/* Configure hash input set */ +static int +i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types) { - return (comp->func == with->func && - comp->level == with->level && - comp->types == with->types && - comp->key_len == with->key_len && - comp->queue_num == with->queue_num && - !memcmp(comp->key, with->key, with->key_len) && - !memcmp(comp->queue, with->queue, - sizeof(*with->queue) * with->queue_num)); + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct rte_eth_input_set_conf conf; + int i, ret; + uint32_t j; + static const struct { + uint64_t type; + enum rte_eth_input_set_field field; + } inset_match_table[] = { + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP4}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, + + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY, + RTE_ETH_INPUT_SET_L3_SRC_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY, + RTE_ETH_INPUT_SET_L3_DST_IP6}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY, + RTE_ETH_INPUT_SET_UNKNOWN}, + }; + + ret = 0; + + for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(types & (1ULL << i))) + continue; + + conf.op = RTE_ETH_INPUT_SET_SELECT; + conf.flow_type = i; + conf.inset_size = 0; + for (j = 0; j < RTE_DIM(inset_match_table); j++) { + if ((types & inset_match_table[j].type) == + inset_match_table[j].type) { + if (inset_match_table[j].field == + RTE_ETH_INPUT_SET_UNKNOWN) { + return -EINVAL; + } + conf.field[conf.inset_size] = + inset_match_table[j].field; + conf.inset_size++; + } + } + + if (conf.inset_size) { + ret = i40e_hash_filter_inset_select(hw, &conf); + if (ret) + return ret; + } + } + + return ret; } -int -i40e_config_rss_filter(struct i40e_pf *pf, - struct i40e_rte_flow_rss_conf *conf, bool add) +/* Look up the conflicted rule then mark it as invalid */ +static void +i40e_rss_mark_invalid_rule(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_rss_filter *rss_item; + uint64_t rss_inset; + + /* Clear input set bits before comparing the pctype */ + rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY | + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY); + + TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) { + if (!rss_item->rss_filter_info.valid) + continue; + + /* Rule for queue region */ + if (conf->conf.queue_num && + rss_item->rss_filter_info.conf.queue_num) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash input set */ + if (conf->conf.types && + (rss_item->rss_filter_info.conf.types & + rss_inset) == + (conf->conf.types & rss_inset)) + rss_item->rss_filter_info.valid = false; + + /* Rule for hash function */ + if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + rss_item->rss_filter_info.conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + rss_item->rss_filter_info.valid = false; + } +} + +/* Configure RSS hash function */ +static int +i40e_rss_config_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) { struct i40e_hw *hw = I40E_PF_TO_HW(pf); - uint32_t i, lut = 0; - uint16_t j, num; - struct rte_eth_rss_conf rss_conf = { - .rss_key = conf->conf.key_len ? - (void *)(uintptr_t)conf->conf.key : NULL, - .rss_key_len = conf->conf.key_len, - .rss_hf = conf->conf.types, - }; - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t reg, i; + uint16_t j; - if (!add) { - if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) { - i40e_pf_disable_rss(pf); - memset(rss_info, 0, - sizeof(struct i40e_rte_flow_rss_conf)); - return 0; + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) { + i40e_set_symmetric_hash_enable_per_port(hw, 1); + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (!(mask0 & (1UL << i))) + continue; + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + I40E_GLQF_HSYM_SYMH_ENA_MASK); + } } + + return 0; + } + + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) { + PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR"); + goto out; + } + reg &= ~I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Enable RSS according to the configuration */ +static int +i40e_rss_enable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, + struct rte_eth_rss_conf *rss_conf) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + + if (!(rss_conf->rss_hf & pf->adapter->flow_types_mask)) + return -ENOTSUP; + + /* Configure hash input set */ + if (i40e_rss_conf_hash_inset(pf, rss_conf->rss_hf)) return -EINVAL; + + if (rss_conf->rss_key == NULL || rss_conf->rss_key_len < + (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { + /* Random default keys */ + static uint32_t rss_key_default[] = {0x6b793944, + 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, + 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, + 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; + + rss_conf->rss_key = (uint8_t *)rss_key_default; + rss_conf->rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * + sizeof(uint32_t); + PMD_DRV_LOG(INFO, + "No valid RSS key config for i40e, using default\n"); } + rss_conf->rss_hf |= rss_info->conf.types; + i40e_hw_rss_hash_set(pf, rss_conf); + + if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) + i40e_rss_config_hash_function(pf, conf); + + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS queue region */ +static int +i40e_rss_config_queue_region(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint32_t i, lut; + uint16_t j, num; + /* If both VMDQ and RSS enabled, not all of PF queues are configured. * It's necessary to calculate the actual PF queues that are configured. */ @@ -13000,6 +13234,7 @@ i40e_config_rss_filter(struct i40e_pf *pf, return -ENOTSUP; } + lut = 0; /* Fill in redirection table */ for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { if (j == num) @@ -13010,29 +13245,203 @@ i40e_config_rss_filter(struct i40e_pf *pf, I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); } - if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) { - i40e_pf_disable_rss(pf); + i40e_rss_mark_invalid_rule(pf, conf); + + return 0; +} + +/* Configure RSS hash function to default */ +static int +i40e_rss_clear_hash_function(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint64_t mask0 = conf->conf.types & pf->adapter->flow_types_mask; + uint32_t i, reg; + uint16_t j; + + if (conf->conf.func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + for (i = RTE_ETH_FLOW_UNKNOWN + 1; + mask0 && i < UINT64_BIT; i++) { + if (mask0 & (1UL << i)) { + for (j = I40E_FILTER_PCTYPE_INVALID + 1; + j < I40E_FILTER_PCTYPE_MAX; j++) { + if (pf->adapter->pctypes_tbl[i] & + (1ULL << j)) + i40e_write_global_rx_ctl(hw, + I40E_GLQF_HSYM(j), + 0); + } + } + } + return 0; } - if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < - (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { - /* Random default keys */ - static uint32_t rss_key_default[] = {0x6b793944, - 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, - 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, - 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; - rss_conf.rss_key = (uint8_t *)rss_key_default; - rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * - sizeof(uint32_t); - PMD_DRV_LOG(INFO, - "No valid RSS key config for i40e, using default\n"); + /* Simple XOR */ + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); + if (reg & I40E_GLQF_CTL_HTOEP_MASK) { + PMD_DRV_LOG(DEBUG, + "Hash function already set to Toeplitz"); + goto out; } + reg |= I40E_GLQF_CTL_HTOEP_MASK; + + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); + +out: + I40E_WRITE_FLUSH(hw); + + return 0; +} +/* Disable RSS hash and configure default input set */ +static int +i40e_rss_disable_hash(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_eth_rss_conf rss_conf = { + .rss_key = pf->rss_info.conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = pf->rss_info.conf.key_len, + }; + uint32_t i; + + /* Disable RSS hash */ + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types); i40e_hw_rss_hash_set(pf, &rss_conf); - if (i40e_rss_conf_init(rss_info, &conf->conf)) - return -EINVAL; + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) { + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || + !(conf->conf.types & (1ULL << i))) + continue; + + /* Configure default input set */ + struct rte_eth_input_set_conf input_conf = { + .op = RTE_ETH_INPUT_SET_SELECT, + .flow_type = i, + .inset_size = 1, + }; + input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT; + i40e_hash_filter_inset_select(hw, &input_conf); + } + + rss_info->conf.types = rss_conf.rss_hf; + + i40e_rss_clear_hash_function(pf, conf); + + return 0; +} + +/* Configure RSS queue region to default */ +static int +i40e_rss_clear_queue_region(struct i40e_pf *pf) +{ + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + uint16_t queue[I40E_MAX_Q_PER_TC]; + uint32_t num_rxq, i, lut; + uint16_t j, num; + + num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, I40E_MAX_Q_PER_TC); + + for (j = 0; j < num_rxq; j++) + queue[j] = j; + + /* If both VMDQ and RSS enabled, not all of PF queues are configured. + * It's necessary to calculate the actual PF queues that are configured. + */ + if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG) + num = i40e_pf_calc_configured_queues_num(pf); + else + num = pf->dev_data->nb_rx_queues; + + num = RTE_MIN(num, num_rxq); + PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured", + num); + + if (num == 0) { + PMD_DRV_LOG(ERR, + "No PF queues are configured to enable RSS for port %u", + pf->dev_data->port_id); + return -ENOTSUP; + } + + lut = 0; + /* Fill in redirection table */ + for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { + if (j == num) + j = 0; + lut = (lut << 8) | (queue[j] & ((0x1 << + hw->func_caps.rss_table_entry_width) - 1)); + if ((i & 3) == 3) + I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); + } + + rss_info->conf.queue_num = 0; + memset(&rss_info->conf.queue, 0, sizeof(uint16_t)); + + return 0; +} + +int +i40e_config_rss_filter(struct i40e_pf *pf, + struct i40e_rte_flow_rss_conf *conf, bool add) +{ + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; + struct rte_flow_action_rss update_conf = rss_info->conf; + struct rte_eth_rss_conf rss_conf = { + .rss_key = conf->conf.key_len ? + (void *)(uintptr_t)conf->conf.key : NULL, + .rss_key_len = conf->conf.key_len, + .rss_hf = conf->conf.types, + }; + int ret = 0; + + if (add) { + if (conf->conf.queue_num) { + /* Configure RSS queue region */ + ret = i40e_rss_config_queue_region(pf, conf); + if (ret) + return ret; + + update_conf.queue_num = conf->conf.queue_num; + update_conf.queue = conf->conf.queue; + } else if (conf->conf.func == + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { + /* Configure hash function */ + ret = i40e_rss_config_hash_function(pf, conf); + if (ret) + return ret; + + update_conf.func = conf->conf.func; + } else { + /* Configure hash enable and input set */ + ret = i40e_rss_enable_hash(pf, conf, &rss_conf); + if (ret) + return ret; + + update_conf.types = rss_conf.rss_hf; + update_conf.key = rss_conf.rss_key; + update_conf.key_len = rss_conf.rss_key_len; + } + + /* Update RSS info in pf */ + if (i40e_rss_conf_init(rss_info, &update_conf)) + return -EINVAL; + } else { + if (!conf->valid) + return 0; + + if (conf->conf.queue_num) + i40e_rss_clear_queue_region(pf); + else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) + i40e_rss_clear_hash_function(pf, conf); + else + i40e_rss_disable_hash(pf, conf); + } return 0; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index aac89de91..e9d90fa35 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -194,6 +194,9 @@ enum i40e_flxpld_layer_idx { #define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK \ I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT) +#define I40E_RSS_TYPE_NONE 0ULL +#define I40E_RSS_TYPE_INVALID 1ULL + #define I40E_INSET_NONE 0x00000000000000000ULL /* bit0 ~ bit 7 */ @@ -749,6 +752,11 @@ struct i40e_queue_regions { struct i40e_queue_region_info region[I40E_REGION_MAX_INDEX + 1]; }; +struct i40e_rss_pattern_info { + uint8_t action_flag; + uint64_t types; +}; + /* Tunnel filter number HW supports */ #define I40E_MAX_TUNNEL_FILTER_NUM 400 @@ -968,6 +976,15 @@ struct i40e_rte_flow_rss_conf { I40E_VFQF_HKEY_MAX_INDEX : I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)]; /* Hash key. */ uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. */ + bool valid; /* Check if it's valid */ +}; + +TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter); + +/* RSS filter list structure */ +struct i40e_rss_filter { + TAILQ_ENTRY(i40e_rss_filter) next; + struct i40e_rte_flow_rss_conf rss_filter_info; }; struct i40e_vf_msg_cfg { @@ -1038,7 +1055,8 @@ struct i40e_pf { struct i40e_fdir_info fdir; /* flow director info */ struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */ struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */ - struct i40e_rte_flow_rss_conf rss_info; /* rss info */ + struct i40e_rte_flow_rss_conf rss_info; /* RSS info */ + struct i40e_rss_conf_list rss_config_list; /* RSS rule list */ struct i40e_queue_regions queue_region; /* queue region info */ struct i40e_fc_conf fc_conf; /* Flow control conf */ struct i40e_mirror_rule_list mirror_list; @@ -1338,8 +1356,6 @@ int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len); int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size); int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, const struct rte_flow_action_rss *in); -int i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with); int i40e_config_rss_filter(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *conf, bool add); int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index d877ac250..f4f3c3abd 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -4424,29 +4424,80 @@ i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev, * function for RSS, or flowtype for queue region configuration. * For example: * pattern: - * Case 1: only ETH, indicate flowtype for queue region will be parsed. - * Case 2: only VLAN, indicate user_priority for queue region will be parsed. - * Case 3: none, indicate RSS related will be parsed in action. - * Any pattern other the ETH or VLAN will be treated as invalid except END. + * Case 1: try to transform patterns to pctype. valid pctype will be + * used in parse action. + * Case 2: only ETH, indicate flowtype for queue region will be parsed. + * Case 3: only VLAN, indicate user_priority for queue region will be parsed. * So, pattern choice is depened on the purpose of configuration of * that flow. * action: - * action RSS will be uaed to transmit valid parameter with + * action RSS will be used to transmit valid parameter with * struct rte_flow_action_rss for all the 3 case. */ static int i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - uint8_t *action_flag, + struct i40e_rss_pattern_info *p_info, struct i40e_queue_regions *info) { const struct rte_flow_item_vlan *vlan_spec, *vlan_mask; const struct rte_flow_item *item = pattern; enum rte_flow_item_type item_type; - - if (item->type == RTE_FLOW_ITEM_TYPE_END) + struct rte_flow_item *items; + uint32_t item_num = 0; /* non-void item number of pattern*/ + uint32_t i = 0; + static const struct { + enum rte_flow_item_type *item_array; + uint64_t type; + } i40e_rss_pctype_patterns[] = { + { pattern_fdir_ipv4, + ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER }, + { pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP }, + { pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP }, + { pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP }, + { pattern_fdir_ipv6, + ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER }, + { pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP }, + { pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP }, + { pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP }, + }; + + p_info->types = I40E_RSS_TYPE_INVALID; + + if (item->type == RTE_FLOW_ITEM_TYPE_END) { + p_info->types = I40E_RSS_TYPE_NONE; return 0; + } + + /* convert flow to pctype */ + while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { + if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID) + item_num++; + i++; + } + item_num++; + + items = rte_zmalloc("i40e_pattern", + item_num * sizeof(struct rte_flow_item), 0); + if (!items) { + rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM, + NULL, "No memory for PMD internal items."); + return -ENOMEM; + } + + i40e_pattern_skip_void_item(items, pattern); + + for (i = 0; i < RTE_DIM(i40e_rss_pctype_patterns); i++) { + if (i40e_match_pattern(i40e_rss_pctype_patterns[i].item_array, + items)) { + p_info->types = i40e_rss_pctype_patterns[i].type; + rte_free(items); + return 0; + } + } + + rte_free(items); for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { if (item->last) { @@ -4459,7 +4510,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, item_type = item->type; switch (item_type) { case RTE_FLOW_ITEM_TYPE_ETH: - *action_flag = 1; + p_info->action_flag = 1; break; case RTE_FLOW_ITEM_TYPE_VLAN: vlan_spec = item->spec; @@ -4472,7 +4523,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, vlan_spec->tci) >> 13) & 0x7; info->region[0].user_priority_num = 1; info->queue_region_number = 1; - *action_flag = 0; + p_info->action_flag = 0; } } break; @@ -4500,12 +4551,14 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, * max index should be 7, and so on. And also, queue index should be * continuous sequence and queue region index should be part of rss * queue index for this port. + * For hash params, the pctype in action and pattern must be same. + * Set queue index must be with non-types. */ static int i40e_flow_parse_rss_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - uint8_t action_flag, + struct i40e_rss_pattern_info p_info, struct i40e_queue_regions *conf_info, union i40e_filter_t *filter) { @@ -4516,7 +4569,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, struct i40e_rte_flow_rss_conf *rss_config = &filter->rss_conf; struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; - uint16_t i, j, n, tmp; + uint16_t i, j, n, tmp, nb_types; uint32_t index = 0; uint64_t hf_bit = 1; @@ -4535,7 +4588,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, return -rte_errno; } - if (action_flag) { + if (p_info.action_flag) { for (n = 0; n < 64; n++) { if (rss->types & (hf_bit << n)) { conf_info->region[0].hw_flowtype[0] = n; @@ -4674,11 +4727,11 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, if (rss_config->queue_region_conf) return 0; - if (!rss || !rss->queue_num) { + if (!rss) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, - "no valid queues"); + "invalid rule"); return -rte_errno; } @@ -4692,19 +4745,48 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, } } - if (rss_info->conf.queue_num) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, - act, - "rss only allow one valid rule"); - return -rte_errno; + if (rss->queue_num && (p_info.types || rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "rss types must be empty while configuring queue region"); + + /* validate pattern and pctype */ + if (!(rss->types & p_info.types) && + (rss->types || p_info.types) && !rss->queue_num) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + act, "invaild pctype"); + + nb_types = 0; + for (n = 0; n < RTE_ETH_FLOW_MAX; n++) { + if (rss->types & (hf_bit << n)) + nb_types++; + if (nb_types > 1) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, + act, "multi pctype is not supported"); } + if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + (p_info.types || rss->types || rss->queue_num)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pattern, type and queues must be empty while" + " setting hash function as simple_xor"); + + if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ && + !(p_info.types && rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pctype and queues can not be empty while" + " setting hash function as symmetric toeplitz"); + /* Parse RSS related parameters from configuration */ - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX || + rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, - "non-default RSS hash functions are not supported"); + "RSS hash functions are not supported"); if (rss->level) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, @@ -4746,19 +4828,20 @@ i40e_parse_rss_filter(struct rte_eth_dev *dev, union i40e_filter_t *filter, struct rte_flow_error *error) { - int ret; + struct i40e_rss_pattern_info p_info; struct i40e_queue_regions info; - uint8_t action_flag = 0; + int ret; memset(&info, 0, sizeof(struct i40e_queue_regions)); + memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info)); ret = i40e_flow_parse_rss_pattern(dev, pattern, - error, &action_flag, &info); + error, &p_info, &info); if (ret) return ret; ret = i40e_flow_parse_rss_action(dev, actions, error, - action_flag, &info, filter); + p_info, &info, filter); if (ret) return ret; @@ -4777,15 +4860,33 @@ i40e_config_rss_filter_set(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; int ret; if (conf->queue_region_conf) { ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1); - conf->queue_region_conf = 0; } else { ret = i40e_config_rss_filter(pf, conf, 1); } - return ret; + + if (ret) + return ret; + + rss_filter = rte_zmalloc("i40e_rss_filter", + sizeof(*rss_filter), 0); + if (rss_filter == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + rss_filter->rss_filter_info = *conf; + /* the rule new created is always valid + * the existing rule covered by new rule will be set invalid + */ + rss_filter->rss_filter_info.valid = true; + + TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next); + + return 0; } static int @@ -4794,10 +4895,21 @@ i40e_config_rss_filter_del(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; + void *temp; - i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + if (conf->queue_region_conf) + i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + else + i40e_config_rss_filter(pf, conf, 0); - i40e_config_rss_filter(pf, conf, 0); + TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) { + if (!memcmp(&rss_filter->rss_filter_info, conf, + sizeof(struct rte_flow_action_rss))) { + TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next); + rte_free(rss_filter); + } + } return 0; } @@ -4940,7 +5052,8 @@ i40e_flow_create(struct rte_eth_dev *dev, &cons_filter.rss_conf); if (ret) goto free_flow; - flow->rule = &pf->rss_info; + flow->rule = TAILQ_LAST(&pf->rss_config_list, + i40e_rss_conf_list); break; default: goto free_flow; @@ -4990,7 +5103,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, break; case RTE_ETH_FILTER_HASH: ret = i40e_config_rss_filter_del(dev, - (struct i40e_rte_flow_rss_conf *)flow->rule); + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); break; default: PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", @@ -5248,13 +5361,27 @@ static int i40e_flow_flush_rss_filter(struct rte_eth_dev *dev) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_flow *flow; + void *temp; int32_t ret = -EINVAL; ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0); - if (rss_info->conf.queue_num) - ret = i40e_config_rss_filter(pf, rss_info, FALSE); + /* Delete rss flows in flow list. */ + TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) { + if (flow->filter_type != RTE_ETH_FILTER_HASH) + continue; + + if (flow->rule) { + ret = i40e_config_rss_filter_del(dev, + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); + if (ret) + return ret; + } + TAILQ_REMOVE(&pf->flow_list, flow, node); + rte_free(flow); + } + return ret; } -- 2.17.1
Hi Chenxu, > -----Original Message----- > From: dev <dev-bounces@dpdk.org> On Behalf Of Chenxu Di > Sent: Tuesday, April 14, 2020 7:37 AM > To: dev@dpdk.org > Cc: Xing, Beilei <beilei.xing@intel.com>; Di, ChenxuX > <chenxux.di@intel.com> > Subject: [dpdk-dev] [PATCH v8] net/i40e: enable advanced RSS > > This patch supports: > > - symmetric hash configuration > - Input set configuration > > Signed-off-by: Chenxu Di <chenxux.di@intel.com> > --- > doc/guides/nics/i40e.rst | 35 ++ > doc/guides/rel_notes/release_20_05.rst | 7 + > drivers/net/i40e/i40e_ethdev.c | 509 ++++++++++++++++++++++--- > drivers/net/i40e/i40e_ethdev.h | 22 +- > drivers/net/i40e/i40e_flow.c | 199 ++++++++-- > 5 files changed, 683 insertions(+), 89 deletions(-) > > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index > d6e578eda..1f8fca285 100644 > --- a/doc/guides/nics/i40e.rst > +++ b/doc/guides/nics/i40e.rst > @@ -569,6 +569,41 @@ details please refer to > :doc:`../testpmd_app_ug/index`. > testpmd> set port (port_id) queue-region flush (on|off) > testpmd> show port (port_id) queue-region > > +Generic flow API > +~~~~~~~~~~~~~~~~~~~ > + > +- ``RSS Flow`` > + > + RSS Flow supports to set hash input set, hash function, enable hash > + and configure queue region. > + For example: > + Configure queue region as queue 0, 1, 2, 3. > + > + .. code-block:: console > + > + testpmd> flow create 0 ingress pattern end actions rss types end \ > + queues 0 1 2 3 end / end > + > + Enable hash and set input set for ipv4-tcp. > + > + .. code-block:: console > + > + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ > + actions rss types ipv4-tcp l3-src-only end queues end / end > + /dpdk# make doc-guides-html sphinx processing guides-html... /root/dpdk_ipsec_gitlab_1/doc/guides/nics/i40e.rst:603: ERROR: Error in "code-block" directive: maximum 1 argument(s) allowed, 19 supplied. .. code-block:: console testpmd> flow create 0 ingress pattern end actions rss types end \ queues end func simple_xor / end > + Set symmetric hash enable for flow type ipv4-tcp. > + > + .. code-block:: console > + > + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ > + actions rss types ipv4-tcp end queues end func symmetric_toeplitz > + / end > + > + Set hash function as simple xor. > + > + .. code-block:: console > + testpmd> flow create 0 ingress pattern end actions rss types end \ > + queues end func simple_xor / end > + > Limitations or Known issues > --------------------------- > > diff --git a/doc/guides/rel_notes/release_20_05.rst > b/doc/guides/rel_notes/release_20_05.rst > index 000bbf501..bf5f399fe 100644 > --- a/doc/guides/rel_notes/release_20_05.rst > +++ b/doc/guides/rel_notes/release_20_05.rst > @@ -62,6 +62,13 @@ New Features > > * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit. > > +* **Updated Intel i40e driver.** > + > + Updated i40e PMD with new features and improvements, including: > + > + * Added support for RSS using L3/L4 source/destination only. > + * Added support for setting hash function in rte flow. > + > > Removed Items > ------------- > diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c > index 9539b0470..efc113842 100644 > --- a/drivers/net/i40e/i40e_ethdev.c > +++ b/drivers/net/i40e/i40e_ethdev.c > @@ -1656,6 +1656,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void > *init_params __rte_unused) > /* initialize mirror rule list */ > TAILQ_INIT(&pf->mirror_list); > > + /* initialize RSS rule list */ > + TAILQ_INIT(&pf->rss_config_list); > + > /* initialize Traffic Manager configuration */ > i40e_tm_conf_init(dev); > > @@ -12325,14 +12328,16 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf) > } > } > > -/* Restore rss filter */ > +/* Restore RSS filter */ > static inline void > i40e_rss_filter_restore(struct i40e_pf *pf) { > - struct i40e_rte_flow_rss_conf *conf = > - &pf->rss_info; > - if (conf->conf.queue_num) > - i40e_config_rss_filter(pf, conf, TRUE); > + struct i40e_rss_conf_list *list = &pf->rss_config_list; > + struct i40e_rss_filter *filter; > + > + TAILQ_FOREACH(filter, list, next) { > + i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE); > + } > } > > static void > @@ -12942,45 +12947,274 @@ i40e_rss_conf_init(struct > i40e_rte_flow_rss_conf *out, > return 0; > } > > -int > -i40e_action_rss_same(const struct rte_flow_action_rss *comp, > - const struct rte_flow_action_rss *with) > +/* Configure hash input set */ > +static int > +i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types) > { > - return (comp->func == with->func && > - comp->level == with->level && > - comp->types == with->types && > - comp->key_len == with->key_len && > - comp->queue_num == with->queue_num && > - !memcmp(comp->key, with->key, with->key_len) && > - !memcmp(comp->queue, with->queue, > - sizeof(*with->queue) * with->queue_num)); > + struct i40e_hw *hw = I40E_PF_TO_HW(pf); > + struct rte_eth_input_set_conf conf; > + int i, ret; > + uint32_t j; > + static const struct { > + uint64_t type; > + enum rte_eth_input_set_field field; > + } inset_match_table[] = { > + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP4}, > + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP4}, > + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + > + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP4}, > + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP4}, > + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP4}, > + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP4}, > + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP4}, > + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP4}, > + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV4_OTHER | > ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP4}, > + {ETH_RSS_NONFRAG_IPV4_OTHER | > ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP4}, > + {ETH_RSS_NONFRAG_IPV4_OTHER | > ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + {ETH_RSS_NONFRAG_IPV4_OTHER | > ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + > + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP6}, > + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP6}, > + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + > + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP6}, > + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP6}, > + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_TCP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP6}, > + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP6}, > + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_UDP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP6}, > + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP6}, > + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT}, > + {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT}, > + > + {ETH_RSS_NONFRAG_IPV6_OTHER | > ETH_RSS_L3_SRC_ONLY, > + RTE_ETH_INPUT_SET_L3_SRC_IP6}, > + {ETH_RSS_NONFRAG_IPV6_OTHER | > ETH_RSS_L3_DST_ONLY, > + RTE_ETH_INPUT_SET_L3_DST_IP6}, > + {ETH_RSS_NONFRAG_IPV6_OTHER | > ETH_RSS_L4_SRC_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + {ETH_RSS_NONFRAG_IPV6_OTHER | > ETH_RSS_L4_DST_ONLY, > + RTE_ETH_INPUT_SET_UNKNOWN}, > + }; > + > + ret = 0; > + > + for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; > i++) { > + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || > + !(types & (1ULL << i))) > + continue; > + > + conf.op = RTE_ETH_INPUT_SET_SELECT; > + conf.flow_type = i; > + conf.inset_size = 0; > + for (j = 0; j < RTE_DIM(inset_match_table); j++) { > + if ((types & inset_match_table[j].type) == > + inset_match_table[j].type) { > + if (inset_match_table[j].field == > + RTE_ETH_INPUT_SET_UNKNOWN) { > + return -EINVAL; > + } > + conf.field[conf.inset_size] = > + inset_match_table[j].field; > + conf.inset_size++; > + } > + } > + > + if (conf.inset_size) { > + ret = i40e_hash_filter_inset_select(hw, &conf); > + if (ret) > + return ret; > + } > + } > + > + return ret; > } > > -int > -i40e_config_rss_filter(struct i40e_pf *pf, > - struct i40e_rte_flow_rss_conf *conf, bool add) > +/* Look up the conflicted rule then mark it as invalid */ static void > +i40e_rss_mark_invalid_rule(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf) > +{ > + struct i40e_rss_filter *rss_item; > + uint64_t rss_inset; > + > + /* Clear input set bits before comparing the pctype */ > + rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY | > + ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY); > + > + TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) { > + if (!rss_item->rss_filter_info.valid) > + continue; > + > + /* Rule for queue region */ > + if (conf->conf.queue_num && > + rss_item->rss_filter_info.conf.queue_num) > + rss_item->rss_filter_info.valid = false; > + > + /* Rule for hash input set */ > + if (conf->conf.types && > + (rss_item->rss_filter_info.conf.types & > + rss_inset) == > + (conf->conf.types & rss_inset)) > + rss_item->rss_filter_info.valid = false; > + > + /* Rule for hash function */ > + if (conf->conf.func == > + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && > + rss_item->rss_filter_info.conf.func == > + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) > + rss_item->rss_filter_info.valid = false; > + } > +} > + > +/* Configure RSS hash function */ > +static int > +i40e_rss_config_hash_function(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf) > { > struct i40e_hw *hw = I40E_PF_TO_HW(pf); > - uint32_t i, lut = 0; > - uint16_t j, num; > - struct rte_eth_rss_conf rss_conf = { > - .rss_key = conf->conf.key_len ? > - (void *)(uintptr_t)conf->conf.key : NULL, > - .rss_key_len = conf->conf.key_len, > - .rss_hf = conf->conf.types, > - }; > - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + uint64_t mask0 = conf->conf.types & pf->adapter- > >flow_types_mask; > + uint32_t reg, i; > + uint16_t j; > > - if (!add) { > - if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) { > - i40e_pf_disable_rss(pf); > - memset(rss_info, 0, > - sizeof(struct i40e_rte_flow_rss_conf)); > - return 0; > + if (conf->conf.func == > RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) { > + i40e_set_symmetric_hash_enable_per_port(hw, 1); > + for (i = RTE_ETH_FLOW_UNKNOWN + 1; > + mask0 && i < UINT64_BIT; i++) { > + if (!(mask0 & (1UL << i))) > + continue; > + for (j = I40E_FILTER_PCTYPE_INVALID + 1; > + j < I40E_FILTER_PCTYPE_MAX; j++) { > + if (pf->adapter->pctypes_tbl[i] & (1ULL << j)) > + i40e_write_global_rx_ctl(hw, > + I40E_GLQF_HSYM(j), > + > I40E_GLQF_HSYM_SYMH_ENA_MASK); > + } > } > + > + return 0; > + } > + > + /* Simple XOR */ > + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); > + if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) { > + PMD_DRV_LOG(DEBUG, "Hash function already set to Simple > XOR"); > + goto out; > + } > + reg &= ~I40E_GLQF_CTL_HTOEP_MASK; > + > + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); > + > +out: > + I40E_WRITE_FLUSH(hw); > + i40e_rss_mark_invalid_rule(pf, conf); > + > + return 0; > +} > + > +/* Enable RSS according to the configuration */ static int > +i40e_rss_enable_hash(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf, > + struct rte_eth_rss_conf *rss_conf) > +{ > + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + > + if (!(rss_conf->rss_hf & pf->adapter->flow_types_mask)) > + return -ENOTSUP; > + > + /* Configure hash input set */ > + if (i40e_rss_conf_hash_inset(pf, rss_conf->rss_hf)) > return -EINVAL; > + > + if (rss_conf->rss_key == NULL || rss_conf->rss_key_len < > + (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { > + /* Random default keys */ > + static uint32_t rss_key_default[] = {0x6b793944, > + 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, > + 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, > + 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; > + > + rss_conf->rss_key = (uint8_t *)rss_key_default; > + rss_conf->rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) > * > + sizeof(uint32_t); > + PMD_DRV_LOG(INFO, > + "No valid RSS key config for i40e, using default\n"); > } > > + rss_conf->rss_hf |= rss_info->conf.types; > + i40e_hw_rss_hash_set(pf, rss_conf); > + > + if (conf->conf.func == > RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) > + i40e_rss_config_hash_function(pf, conf); > + > + i40e_rss_mark_invalid_rule(pf, conf); > + > + return 0; > +} > + > +/* Configure RSS queue region */ > +static int > +i40e_rss_config_queue_region(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf) > +{ > + struct i40e_hw *hw = I40E_PF_TO_HW(pf); > + uint32_t i, lut; > + uint16_t j, num; > + > /* If both VMDQ and RSS enabled, not all of PF queues are > configured. > * It's necessary to calculate the actual PF queues that are configured. > */ > @@ -13000,6 +13234,7 @@ i40e_config_rss_filter(struct i40e_pf *pf, > return -ENOTSUP; > } > > + lut = 0; > /* Fill in redirection table */ > for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { > if (j == num) > @@ -13010,29 +13245,203 @@ i40e_config_rss_filter(struct i40e_pf *pf, > I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); > } > > - if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) { > - i40e_pf_disable_rss(pf); > + i40e_rss_mark_invalid_rule(pf, conf); > + > + return 0; > +} > + > +/* Configure RSS hash function to default */ static int > +i40e_rss_clear_hash_function(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf) > +{ > + struct i40e_hw *hw = I40E_PF_TO_HW(pf); > + uint64_t mask0 = conf->conf.types & pf->adapter- > >flow_types_mask; > + uint32_t i, reg; > + uint16_t j; > + > + if (conf->conf.func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { > + for (i = RTE_ETH_FLOW_UNKNOWN + 1; > + mask0 && i < UINT64_BIT; i++) { > + if (mask0 & (1UL << i)) { > + for (j = I40E_FILTER_PCTYPE_INVALID + 1; > + j < I40E_FILTER_PCTYPE_MAX; j++) { > + if (pf->adapter->pctypes_tbl[i] & > + (1ULL << j)) > + i40e_write_global_rx_ctl(hw, > + I40E_GLQF_HSYM(j), > + 0); > + } > + } > + } > + > return 0; > } > - if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < > - (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { > - /* Random default keys */ > - static uint32_t rss_key_default[] = {0x6b793944, > - 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, > - 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, > - 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; > > - rss_conf.rss_key = (uint8_t *)rss_key_default; > - rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * > - sizeof(uint32_t); > - PMD_DRV_LOG(INFO, > - "No valid RSS key config for i40e, using default\n"); > + /* Simple XOR */ > + reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL); > + if (reg & I40E_GLQF_CTL_HTOEP_MASK) { > + PMD_DRV_LOG(DEBUG, > + "Hash function already set to Toeplitz"); > + goto out; > } > + reg |= I40E_GLQF_CTL_HTOEP_MASK; > + > + i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg); > + > +out: > + I40E_WRITE_FLUSH(hw); > + > + return 0; > +} > > +/* Disable RSS hash and configure default input set */ static int > +i40e_rss_disable_hash(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf) > +{ > + struct i40e_hw *hw = I40E_PF_TO_HW(pf); > + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + struct rte_eth_rss_conf rss_conf = { > + .rss_key = pf->rss_info.conf.key_len ? > + (void *)(uintptr_t)conf->conf.key : NULL, > + .rss_key_len = pf->rss_info.conf.key_len, > + }; > + uint32_t i; > + > + /* Disable RSS hash */ > + rss_conf.rss_hf = rss_info->conf.types & ~(conf->conf.types); > i40e_hw_rss_hash_set(pf, &rss_conf); > > - if (i40e_rss_conf_init(rss_info, &conf->conf)) > - return -EINVAL; > + for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; > i++) { > + if (!(pf->adapter->flow_types_mask & (1ULL << i)) || > + !(conf->conf.types & (1ULL << i))) > + continue; > + > + /* Configure default input set */ > + struct rte_eth_input_set_conf input_conf = { > + .op = RTE_ETH_INPUT_SET_SELECT, > + .flow_type = i, > + .inset_size = 1, > + }; > + input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT; > + i40e_hash_filter_inset_select(hw, &input_conf); > + } > + > + rss_info->conf.types = rss_conf.rss_hf; > + > + i40e_rss_clear_hash_function(pf, conf); > + > + return 0; > +} > + > +/* Configure RSS queue region to default */ static int > +i40e_rss_clear_queue_region(struct i40e_pf *pf) { > + struct i40e_hw *hw = I40E_PF_TO_HW(pf); > + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + uint16_t queue[I40E_MAX_Q_PER_TC]; > + uint32_t num_rxq, i, lut; > + uint16_t j, num; > + > + num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, > I40E_MAX_Q_PER_TC); > + > + for (j = 0; j < num_rxq; j++) > + queue[j] = j; > + > + /* If both VMDQ and RSS enabled, not all of PF queues are > configured. > + * It's necessary to calculate the actual PF queues that are configured. > + */ > + if (pf->dev_data->dev_conf.rxmode.mq_mode & > ETH_MQ_RX_VMDQ_FLAG) > + num = i40e_pf_calc_configured_queues_num(pf); > + else > + num = pf->dev_data->nb_rx_queues; > + > + num = RTE_MIN(num, num_rxq); > + PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are > configured", > + num); > + > + if (num == 0) { > + PMD_DRV_LOG(ERR, > + "No PF queues are configured to enable RSS for port > %u", > + pf->dev_data->port_id); > + return -ENOTSUP; > + } > + > + lut = 0; > + /* Fill in redirection table */ > + for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) { > + if (j == num) > + j = 0; > + lut = (lut << 8) | (queue[j] & ((0x1 << > + hw->func_caps.rss_table_entry_width) - 1)); > + if ((i & 3) == 3) > + I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut); > + } > + > + rss_info->conf.queue_num = 0; > + memset(&rss_info->conf.queue, 0, sizeof(uint16_t)); > + > + return 0; > +} > + > +int > +i40e_config_rss_filter(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf, bool add) { > + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + struct rte_flow_action_rss update_conf = rss_info->conf; > + struct rte_eth_rss_conf rss_conf = { > + .rss_key = conf->conf.key_len ? > + (void *)(uintptr_t)conf->conf.key : NULL, > + .rss_key_len = conf->conf.key_len, > + .rss_hf = conf->conf.types, > + }; > + int ret = 0; > + > + if (add) { > + if (conf->conf.queue_num) { > + /* Configure RSS queue region */ > + ret = i40e_rss_config_queue_region(pf, conf); > + if (ret) > + return ret; > + > + update_conf.queue_num = conf->conf.queue_num; > + update_conf.queue = conf->conf.queue; > + } else if (conf->conf.func == > + RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) { > + /* Configure hash function */ > + ret = i40e_rss_config_hash_function(pf, conf); > + if (ret) > + return ret; > + > + update_conf.func = conf->conf.func; > + } else { > + /* Configure hash enable and input set */ > + ret = i40e_rss_enable_hash(pf, conf, &rss_conf); > + if (ret) > + return ret; > + > + update_conf.types = rss_conf.rss_hf; > + update_conf.key = rss_conf.rss_key; > + update_conf.key_len = rss_conf.rss_key_len; > + } > + > + /* Update RSS info in pf */ > + if (i40e_rss_conf_init(rss_info, &update_conf)) > + return -EINVAL; > + } else { > + if (!conf->valid) > + return 0; > + > + if (conf->conf.queue_num) > + i40e_rss_clear_queue_region(pf); > + else if (conf->conf.func == > RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) > + i40e_rss_clear_hash_function(pf, conf); > + else > + i40e_rss_disable_hash(pf, conf); > + } > > return 0; > } > diff --git a/drivers/net/i40e/i40e_ethdev.h > b/drivers/net/i40e/i40e_ethdev.h index aac89de91..e9d90fa35 100644 > --- a/drivers/net/i40e/i40e_ethdev.h > +++ b/drivers/net/i40e/i40e_ethdev.h > @@ -194,6 +194,9 @@ enum i40e_flxpld_layer_idx { #define > I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK \ > I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT) > > +#define I40E_RSS_TYPE_NONE 0ULL > +#define I40E_RSS_TYPE_INVALID 1ULL > + > #define I40E_INSET_NONE 0x00000000000000000ULL > > /* bit0 ~ bit 7 */ > @@ -749,6 +752,11 @@ struct i40e_queue_regions { > struct i40e_queue_region_info region[I40E_REGION_MAX_INDEX + > 1]; }; > > +struct i40e_rss_pattern_info { > + uint8_t action_flag; > + uint64_t types; > +}; > + > /* Tunnel filter number HW supports */ > #define I40E_MAX_TUNNEL_FILTER_NUM 400 > > @@ -968,6 +976,15 @@ struct i40e_rte_flow_rss_conf { > I40E_VFQF_HKEY_MAX_INDEX : > I40E_PFQF_HKEY_MAX_INDEX + 1) * > sizeof(uint32_t)]; /* Hash key. */ > uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. > */ > + bool valid; /* Check if it's valid */ > +}; > + > +TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter); > + > +/* RSS filter list structure */ > +struct i40e_rss_filter { > + TAILQ_ENTRY(i40e_rss_filter) next; > + struct i40e_rte_flow_rss_conf rss_filter_info; > }; > > struct i40e_vf_msg_cfg { > @@ -1038,7 +1055,8 @@ struct i40e_pf { > struct i40e_fdir_info fdir; /* flow director info */ > struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */ > struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */ > - struct i40e_rte_flow_rss_conf rss_info; /* rss info */ > + struct i40e_rte_flow_rss_conf rss_info; /* RSS info */ > + struct i40e_rss_conf_list rss_config_list; /* RSS rule list */ > struct i40e_queue_regions queue_region; /* queue region info */ > struct i40e_fc_conf fc_conf; /* Flow control conf */ > struct i40e_mirror_rule_list mirror_list; @@ -1338,8 +1356,6 @@ int > i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len); int > i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size); int > i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, > const struct rte_flow_action_rss *in); -int > i40e_action_rss_same(const struct rte_flow_action_rss *comp, > - const struct rte_flow_action_rss *with); > int i40e_config_rss_filter(struct i40e_pf *pf, > struct i40e_rte_flow_rss_conf *conf, bool add); int > i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); > diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c > index d877ac250..f4f3c3abd 100644 > --- a/drivers/net/i40e/i40e_flow.c > +++ b/drivers/net/i40e/i40e_flow.c > @@ -4424,29 +4424,80 @@ i40e_flow_parse_qinq_filter(struct rte_eth_dev > *dev, > * function for RSS, or flowtype for queue region configuration. > * For example: > * pattern: > - * Case 1: only ETH, indicate flowtype for queue region will be parsed. > - * Case 2: only VLAN, indicate user_priority for queue region will be parsed. > - * Case 3: none, indicate RSS related will be parsed in action. > - * Any pattern other the ETH or VLAN will be treated as invalid except END. > + * Case 1: try to transform patterns to pctype. valid pctype will be > + * used in parse action. > + * Case 2: only ETH, indicate flowtype for queue region will be parsed. > + * Case 3: only VLAN, indicate user_priority for queue region will be parsed. > * So, pattern choice is depened on the purpose of configuration of > * that flow. > * action: > - * action RSS will be uaed to transmit valid parameter with > + * action RSS will be used to transmit valid parameter with > * struct rte_flow_action_rss for all the 3 case. > */ > static int > i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, > const struct rte_flow_item *pattern, > struct rte_flow_error *error, > - uint8_t *action_flag, > + struct i40e_rss_pattern_info *p_info, > struct i40e_queue_regions *info) { > const struct rte_flow_item_vlan *vlan_spec, *vlan_mask; > const struct rte_flow_item *item = pattern; > enum rte_flow_item_type item_type; > - > - if (item->type == RTE_FLOW_ITEM_TYPE_END) > + struct rte_flow_item *items; > + uint32_t item_num = 0; /* non-void item number of pattern*/ > + uint32_t i = 0; > + static const struct { > + enum rte_flow_item_type *item_array; > + uint64_t type; > + } i40e_rss_pctype_patterns[] = { > + { pattern_fdir_ipv4, > + ETH_RSS_FRAG_IPV4 | > ETH_RSS_NONFRAG_IPV4_OTHER }, > + { pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP }, > + { pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP }, > + { pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP }, > + { pattern_fdir_ipv6, > + ETH_RSS_FRAG_IPV6 | > ETH_RSS_NONFRAG_IPV6_OTHER }, > + { pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP }, > + { pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP }, > + { pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP }, > + }; > + > + p_info->types = I40E_RSS_TYPE_INVALID; > + > + if (item->type == RTE_FLOW_ITEM_TYPE_END) { > + p_info->types = I40E_RSS_TYPE_NONE; > return 0; > + } > + > + /* convert flow to pctype */ > + while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { > + if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID) > + item_num++; > + i++; > + } > + item_num++; > + > + items = rte_zmalloc("i40e_pattern", > + item_num * sizeof(struct rte_flow_item), 0); > + if (!items) { > + rte_flow_error_set(error, ENOMEM, > RTE_FLOW_ERROR_TYPE_ITEM_NUM, > + NULL, "No memory for PMD internal > items."); > + return -ENOMEM; > + } > + > + i40e_pattern_skip_void_item(items, pattern); > + > + for (i = 0; i < RTE_DIM(i40e_rss_pctype_patterns); i++) { > + if > (i40e_match_pattern(i40e_rss_pctype_patterns[i].item_array, > + items)) { > + p_info->types = i40e_rss_pctype_patterns[i].type; > + rte_free(items); > + return 0; > + } > + } > + > + rte_free(items); > > for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { > if (item->last) { > @@ -4459,7 +4510,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct > rte_eth_dev *dev, > item_type = item->type; > switch (item_type) { > case RTE_FLOW_ITEM_TYPE_ETH: > - *action_flag = 1; > + p_info->action_flag = 1; > break; > case RTE_FLOW_ITEM_TYPE_VLAN: > vlan_spec = item->spec; > @@ -4472,7 +4523,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct > rte_eth_dev *dev, > vlan_spec->tci) >> 13) & 0x7; > info->region[0].user_priority_num = > 1; > info->queue_region_number = 1; > - *action_flag = 0; > + p_info->action_flag = 0; > } > } > break; > @@ -4500,12 +4551,14 @@ i40e_flow_parse_rss_pattern(__rte_unused > struct rte_eth_dev *dev, > * max index should be 7, and so on. And also, queue index should be > * continuous sequence and queue region index should be part of rss > * queue index for this port. > + * For hash params, the pctype in action and pattern must be same. > + * Set queue index must be with non-types. > */ > static int > i40e_flow_parse_rss_action(struct rte_eth_dev *dev, > const struct rte_flow_action *actions, > struct rte_flow_error *error, > - uint8_t action_flag, > + struct i40e_rss_pattern_info p_info, > struct i40e_queue_regions *conf_info, > union i40e_filter_t *filter) > { > @@ -4516,7 +4569,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev > *dev, > struct i40e_rte_flow_rss_conf *rss_config = > &filter->rss_conf; > struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > - uint16_t i, j, n, tmp; > + uint16_t i, j, n, tmp, nb_types; > uint32_t index = 0; > uint64_t hf_bit = 1; > > @@ -4535,7 +4588,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev > *dev, > return -rte_errno; > } > > - if (action_flag) { > + if (p_info.action_flag) { > for (n = 0; n < 64; n++) { > if (rss->types & (hf_bit << n)) { > conf_info->region[0].hw_flowtype[0] = n; > @@ -4674,11 +4727,11 @@ i40e_flow_parse_rss_action(struct rte_eth_dev > *dev, > if (rss_config->queue_region_conf) > return 0; > > - if (!rss || !rss->queue_num) { > + if (!rss) { > rte_flow_error_set(error, EINVAL, > RTE_FLOW_ERROR_TYPE_ACTION, > act, > - "no valid queues"); > + "invalid rule"); > return -rte_errno; > } > > @@ -4692,19 +4745,48 @@ i40e_flow_parse_rss_action(struct rte_eth_dev > *dev, > } > } > > - if (rss_info->conf.queue_num) { > - rte_flow_error_set(error, EINVAL, > - RTE_FLOW_ERROR_TYPE_ACTION, > - act, > - "rss only allow one valid rule"); > - return -rte_errno; > + if (rss->queue_num && (p_info.types || rss->types)) > + return rte_flow_error_set > + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, > act, > + "rss types must be empty while configuring queue > region"); > + > + /* validate pattern and pctype */ > + if (!(rss->types & p_info.types) && > + (rss->types || p_info.types) && !rss->queue_num) > + return rte_flow_error_set > + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, > + act, "invaild pctype"); > + > + nb_types = 0; > + for (n = 0; n < RTE_ETH_FLOW_MAX; n++) { > + if (rss->types & (hf_bit << n)) > + nb_types++; > + if (nb_types > 1) > + return rte_flow_error_set > + (error, ENOTSUP, > RTE_FLOW_ERROR_TYPE_ACTION, > + act, "multi pctype is not supported"); > } > > + if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && > + (p_info.types || rss->types || rss->queue_num)) > + return rte_flow_error_set > + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, > act, > + "pattern, type and queues must be empty while" > + " setting hash function as simple_xor"); > + > + if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ > && > + !(p_info.types && rss->types)) > + return rte_flow_error_set > + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, > act, > + "pctype and queues can not be empty while" > + " setting hash function as symmetric toeplitz"); > + > /* Parse RSS related parameters from configuration */ > - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) > + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX || > + rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) > return rte_flow_error_set > (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, > act, > - "non-default RSS hash functions are not > supported"); > + "RSS hash functions are not supported"); > if (rss->level) > return rte_flow_error_set > (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, > act, @@ -4746,19 +4828,20 @@ i40e_parse_rss_filter(struct rte_eth_dev > *dev, > union i40e_filter_t *filter, > struct rte_flow_error *error) > { > - int ret; > + struct i40e_rss_pattern_info p_info; > struct i40e_queue_regions info; > - uint8_t action_flag = 0; > + int ret; > > memset(&info, 0, sizeof(struct i40e_queue_regions)); > + memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info)); > > ret = i40e_flow_parse_rss_pattern(dev, pattern, > - error, &action_flag, &info); > + error, &p_info, &info); > if (ret) > return ret; > > ret = i40e_flow_parse_rss_action(dev, actions, error, > - action_flag, &info, filter); > + p_info, &info, filter); > if (ret) > return ret; > > @@ -4777,15 +4860,33 @@ i40e_config_rss_filter_set(struct rte_eth_dev > *dev, { > struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data- > >dev_private); > struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data- > >dev_private); > + struct i40e_rss_filter *rss_filter; > int ret; > > if (conf->queue_region_conf) { > ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1); > - conf->queue_region_conf = 0; > } else { > ret = i40e_config_rss_filter(pf, conf, 1); > } > - return ret; > + > + if (ret) > + return ret; > + > + rss_filter = rte_zmalloc("i40e_rss_filter", > + sizeof(*rss_filter), 0); > + if (rss_filter == NULL) { > + PMD_DRV_LOG(ERR, "Failed to alloc memory."); > + return -ENOMEM; > + } > + rss_filter->rss_filter_info = *conf; > + /* the rule new created is always valid > + * the existing rule covered by new rule will be set invalid > + */ > + rss_filter->rss_filter_info.valid = true; > + > + TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next); > + > + return 0; > } > > static int > @@ -4794,10 +4895,21 @@ i40e_config_rss_filter_del(struct rte_eth_dev > *dev, { > struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data- > >dev_private); > struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data- > >dev_private); > + struct i40e_rss_filter *rss_filter; > + void *temp; > > - i40e_flush_queue_region_all_conf(dev, hw, pf, 0); > + if (conf->queue_region_conf) > + i40e_flush_queue_region_all_conf(dev, hw, pf, 0); > + else > + i40e_config_rss_filter(pf, conf, 0); > > - i40e_config_rss_filter(pf, conf, 0); > + TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) { > + if (!memcmp(&rss_filter->rss_filter_info, conf, > + sizeof(struct rte_flow_action_rss))) { > + TAILQ_REMOVE(&pf->rss_config_list, rss_filter, > next); > + rte_free(rss_filter); > + } > + } > return 0; > } > > @@ -4940,7 +5052,8 @@ i40e_flow_create(struct rte_eth_dev *dev, > &cons_filter.rss_conf); > if (ret) > goto free_flow; > - flow->rule = &pf->rss_info; > + flow->rule = TAILQ_LAST(&pf->rss_config_list, > + i40e_rss_conf_list); > break; > default: > goto free_flow; > @@ -4990,7 +5103,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, > break; > case RTE_ETH_FILTER_HASH: > ret = i40e_config_rss_filter_del(dev, > - (struct i40e_rte_flow_rss_conf *)flow->rule); > + &((struct i40e_rss_filter *)flow->rule)- > >rss_filter_info); > break; > default: > PMD_DRV_LOG(WARNING, "Filter type (%d) not > supported", @@ -5248,13 +5361,27 @@ static int > i40e_flow_flush_rss_filter(struct rte_eth_dev *dev) { > struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data- > >dev_private); > - struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data- > >dev_private); > + struct rte_flow *flow; > + void *temp; > int32_t ret = -EINVAL; > > ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0); > > - if (rss_info->conf.queue_num) > - ret = i40e_config_rss_filter(pf, rss_info, FALSE); > + /* Delete rss flows in flow list. */ > + TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) { > + if (flow->filter_type != RTE_ETH_FILTER_HASH) > + continue; > + > + if (flow->rule) { > + ret = i40e_config_rss_filter_del(dev, > + &((struct i40e_rss_filter *)flow->rule)- > >rss_filter_info); > + if (ret) > + return ret; > + } > + TAILQ_REMOVE(&pf->flow_list, flow, node); > + rte_free(flow); > + } > + > return ret; > } > -- > 2.17.1 Regards, Bernard.
> -----Original Message----- > From: Di, ChenxuX <chenxux.di@intel.com> > Sent: Tuesday, April 14, 2020 2:37 PM > To: dev@dpdk.org > Cc: Xing, Beilei <beilei.xing@intel.com>; Di, ChenxuX <chenxux.di@intel.com> > Subject: [PATCH v8] net/i40e: enable advanced RSS > > This patch supports: > > - symmetric hash configuration > - Input set configuration > > Signed-off-by: Chenxu Di <chenxux.di@intel.com> > --- > doc/guides/nics/i40e.rst | 35 ++ > doc/guides/rel_notes/release_20_05.rst | 7 + > drivers/net/i40e/i40e_ethdev.c | 509 ++++++++++++++++++++++--- > drivers/net/i40e/i40e_ethdev.h | 22 +- > drivers/net/i40e/i40e_flow.c | 199 ++++++++-- > 5 files changed, 683 insertions(+), 89 deletions(-) > > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index > d6e578eda..1f8fca285 100644 > --- a/doc/guides/nics/i40e.rst > +++ b/doc/guides/nics/i40e.rst > @@ -569,6 +569,41 @@ details please refer > to :doc:`../testpmd_app_ug/index`. > + > +/* Enable RSS according to the configuration */ static int > +i40e_rss_enable_hash(struct i40e_pf *pf, > + struct i40e_rte_flow_rss_conf *conf, > + struct rte_eth_rss_conf *rss_conf) I think one parameter for RSS configuration is enough, why need two parameters here? Beilei > +{ > + struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info; > + > + if (!(rss_conf->rss_hf & pf->adapter->flow_types_mask)) > + return -ENOTSUP; > + > + /* Configure hash input set */ > + if (i40e_rss_conf_hash_inset(pf, rss_conf->rss_hf)) > return -EINVAL; > + > + if (rss_conf->rss_key == NULL || rss_conf->rss_key_len < > + (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) { > + /* Random default keys */ > + static uint32_t rss_key_default[] = {0x6b793944, > + 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8, > + 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605, > + 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581}; > + > + rss_conf->rss_key = (uint8_t *)rss_key_default; > + rss_conf->rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * > + sizeof(uint32_t); > + PMD_DRV_LOG(INFO, > + "No valid RSS key config for i40e, using default\n"); > } > > + rss_conf->rss_hf |= rss_info->conf.types; > + i40e_hw_rss_hash_set(pf, rss_conf); > + > + if (conf->conf.func == > RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) > + i40e_rss_config_hash_function(pf, conf); > + > + i40e_rss_mark_invalid_rule(pf, conf); > + > + return 0; > +} > +
This patch supports: - Symmetric hash configuration - Hash input set configuration Signed-off-by: Chenxu Di <chenxux.di@intel.com> --- v9: -Updated code about enable hash. --- doc/guides/nics/i40e.rst | 37 ++ doc/guides/rel_notes/release_20_05.rst | 2 + drivers/net/i40e/i40e_ethdev.c | 528 ++++++++++++++++++++++--- drivers/net/i40e/i40e_ethdev.h | 22 +- drivers/net/i40e/i40e_flow.c | 209 ++++++++-- 5 files changed, 703 insertions(+), 95 deletions(-) diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index d6e578eda..f72a54ba6 100644 --- a/doc/guides/nics/i40e.rst +++ b/doc/guides/nics/i40e.rst @@ -44,6 +44,7 @@ Features of the i40e PMD are: - Queue region configuration - Virtual Function Port Representors - Malicious Device Drive event catch and notify +- Generic flow API Prerequisites ------------- @@ -569,6 +570,42 @@ details please refer to :doc:`../testpmd_app_ug/index`. testpmd> set port (port_id) queue-region flush (on|off) testpmd> show port (port_id) queue-region +Generic flow API +~~~~~~~~~~~~~~~~~~~ + +- ``RSS Flow`` + + RSS Flow supports to set hash input set, hash function, enable hash + and configure queue region. + For example: + Configure queue region as queue 0, 1, 2, 3. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues 0 1 2 3 end / end + + Enable hash and set input set for ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp l3-src-only end queues end / end + + Set symmetric hash enable for flow type ipv4-tcp. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern eth / ipv4 / tcp / end \ + actions rss types ipv4-tcp end queues end func symmetric_toeplitz / end + + Set hash function as simple xor. + + .. code-block:: console + + testpmd> flow create 0 ingress pattern end actions rss types end \ + queues end func simple_xor / end + Limitations or Known issues --------------------------- diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst index e32746291..76e8dfb7d 100644 --- a/doc/guides/rel_notes/release_20_05.rst +++ b/doc/guides/rel_notes/release_20_05.rst @@ -83,6 +83,8 @@ New Features Updated i40e PMD with new features and improvements, including: * Enable MAC address as FDIR input set for ipv4-other, ipv4-udp and ipv4-tcp. + * Added support for RSS using L3/L4 source/destination only. + * Added support for setting hash function in rte flow. * **Updated Amazon ena driver.** diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 60de68fd8..5ac3714be 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -1657,6 +1657,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) /* initialize mirror rule list */ TAILQ_INIT(&pf->mirror_list); + /* initialize RSS rule list */ + TAILQ_INIT(&pf->rss_config_list); + /* initialize Traffic Manager configuration */ i40e_tm_conf_init(dev); @@ -1676,7 +1679,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused) /* initialize queue region configuration */ i40e_init_queue_region_conf(dev); - /* initialize rss configuration from rte_flow */ + /* initialize RSS configuration from rte_flow */ memset(&pf->rss_info, 0, sizeof(struct i40e_rte_flow_rss_conf)); @@ -12329,14 +12332,16 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf) } } -/* Restore rss filter */ +/* Restore RSS filter */ static inline void i40e_rss_filter_restore(struct i40e_pf *pf) { - struct i40e_rte_flow_rss_conf *conf = - &pf->rss_info; - if (conf->conf.queue_num) - i40e_config_rss_filter(pf, conf, TRUE); + struct i40e_rss_conf_list *list = &pf->rss_config_list; + struct i40e_rss_filter *filter; + + TAILQ_FOREACH(filter, list, next) { + i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE); + } } static void @@ -12946,45 +12951,300 @@ i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, return 0; } -int -i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with) +/* Write HENA register to enable hash */ +static int +i40e_rss_hash_set(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *rss_conf) { - return (comp->func == with->func && - comp->level == with->level && - comp->types == with->types && - comp->key_len == with->key_len && - comp->queue_num == with->queue_num && - !memcmp(comp->key, with->key, with->key_len) && - !memcmp(comp->queue, with->queue, - sizeof(*with->queue) * with->queue_num)); + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + 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; } -int -i40e_config_rss_filter(struct i40e_pf *pf, - struct i40e_rte_flow_rss_conf *conf, bool add) +/* 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); - 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; + 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}, }; - 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)); + 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; + } + + 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. */ @@ -13014,29 +13274,195 @@ 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); - return 0; + 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; + } + + 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); + } } - 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"); + 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); } - i40e_hw_rss_hash_set(pf, &rss_conf); + rss_info->conf.types = rss_conf.conf.types; - if (i40e_rss_conf_init(rss_info, &conf->conf)) - return -EINVAL; + 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; } diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 461959e08..e5d0ce53f 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -192,6 +192,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 */ @@ -754,6 +757,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 @@ -973,6 +981,15 @@ struct i40e_rte_flow_rss_conf { I40E_VFQF_HKEY_MAX_INDEX : I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)]; /* Hash key. */ uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. */ + bool valid; /* Check if it's valid */ +}; + +TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter); + +/* RSS filter list structure */ +struct i40e_rss_filter { + TAILQ_ENTRY(i40e_rss_filter) next; + struct i40e_rte_flow_rss_conf rss_filter_info; }; struct i40e_vf_msg_cfg { @@ -1043,7 +1060,8 @@ struct i40e_pf { struct i40e_fdir_info fdir; /* flow director info */ struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */ struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */ - struct i40e_rte_flow_rss_conf rss_info; /* rss info */ + struct i40e_rte_flow_rss_conf rss_info; /* RSS info */ + struct i40e_rss_conf_list rss_config_list; /* RSS rule list */ struct i40e_queue_regions queue_region; /* queue region info */ struct i40e_fc_conf fc_conf; /* Flow control conf */ struct i40e_mirror_rule_list mirror_list; @@ -1343,8 +1361,6 @@ int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len); int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size); int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out, const struct rte_flow_action_rss *in); -int i40e_action_rss_same(const struct rte_flow_action_rss *comp, - const struct rte_flow_action_rss *with); int i40e_config_rss_filter(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *conf, bool add); int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c index b1861a7db..1d0eaf61c 100644 --- a/drivers/net/i40e/i40e_flow.c +++ b/drivers/net/i40e/i40e_flow.c @@ -4475,29 +4475,80 @@ i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev, * function for RSS, or flowtype for queue region configuration. * For example: * pattern: - * Case 1: only ETH, indicate flowtype for queue region will be parsed. - * Case 2: only VLAN, indicate user_priority for queue region will be parsed. - * Case 3: none, indicate RSS related will be parsed in action. - * Any pattern other the ETH or VLAN will be treated as invalid except END. + * Case 1: try to transform patterns to pctype. valid pctype will be + * used in parse action. + * Case 2: only ETH, indicate flowtype for queue region will be parsed. + * Case 3: only VLAN, indicate user_priority for queue region will be parsed. * So, pattern choice is depened on the purpose of configuration of * that flow. * action: - * action RSS will be uaed to transmit valid parameter with + * action RSS will be used to transmit valid parameter with * struct rte_flow_action_rss for all the 3 case. */ static int i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, const struct rte_flow_item *pattern, struct rte_flow_error *error, - uint8_t *action_flag, + struct i40e_rss_pattern_info *p_info, struct i40e_queue_regions *info) { const struct rte_flow_item_vlan *vlan_spec, *vlan_mask; const struct rte_flow_item *item = pattern; enum rte_flow_item_type item_type; - - if (item->type == RTE_FLOW_ITEM_TYPE_END) + struct rte_flow_item *items; + uint32_t item_num = 0; /* non-void item number of pattern*/ + uint32_t i = 0; + static const struct { + enum rte_flow_item_type *item_array; + uint64_t type; + } i40e_rss_pctype_patterns[] = { + { pattern_fdir_ipv4, + ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER }, + { pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP }, + { pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP }, + { pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP }, + { pattern_fdir_ipv6, + ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER }, + { pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP }, + { pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP }, + { pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP }, + }; + + p_info->types = I40E_RSS_TYPE_INVALID; + + if (item->type == RTE_FLOW_ITEM_TYPE_END) { + p_info->types = I40E_RSS_TYPE_NONE; return 0; + } + + /* Convert 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; + rte_free(items); + return 0; + } + } + + rte_free(items); for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { if (item->last) { @@ -4510,7 +4561,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; @@ -4523,7 +4574,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; @@ -4540,7 +4591,7 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, } /** - * This function is used to parse rss queue index, total queue number and + * 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 @@ -4549,14 +4600,16 @@ i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev, * 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 + * continuous sequence and queue region index should be part of RSS * queue index for this port. + * For hash params, the pctype in action and pattern must be same. + * Set queue index must be with non-types. */ static int i40e_flow_parse_rss_action(struct rte_eth_dev *dev, const struct rte_flow_action *actions, struct rte_flow_error *error, - uint8_t action_flag, + struct i40e_rss_pattern_info p_info, struct i40e_queue_regions *conf_info, union i40e_filter_t *filter) { @@ -4567,7 +4620,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; @@ -4575,7 +4628,7 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, rss = act->conf; /** - * rss only supports forwarding, + * RSS only supports forwarding, * check if the first not void action is RSS. */ if (act->type != RTE_FLOW_ACTION_TYPE_RSS) { @@ -4586,7 +4639,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; @@ -4725,11 +4778,11 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, if (rss_config->queue_region_conf) return 0; - if (!rss || !rss->queue_num) { + if (!rss) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, - "no valid queues"); + "invalid rule"); return -rte_errno; } @@ -4743,19 +4796,48 @@ i40e_flow_parse_rss_action(struct rte_eth_dev *dev, } } - if (rss_info->conf.queue_num) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, - act, - "rss only allow one valid rule"); - return -rte_errno; + if (rss->queue_num && (p_info.types || rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "RSS types must be empty while configuring queue region"); + + /* validate pattern and pctype */ + if (!(rss->types & p_info.types) && + (rss->types || p_info.types) && !rss->queue_num) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + act, "invaild pctype"); + + nb_types = 0; + for (n = 0; n < RTE_ETH_FLOW_MAX; n++) { + if (rss->types & (hf_bit << n)) + nb_types++; + if (nb_types > 1) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, + act, "multi pctype is not supported"); } + if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR && + (p_info.types || rss->types || rss->queue_num)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pattern, type and queues must be empty while" + " setting hash function as simple_xor"); + + if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ && + !(p_info.types && rss->types)) + return rte_flow_error_set + (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, + "pctype and queues can not be empty while" + " setting hash function as symmetric toeplitz"); + /* Parse RSS related parameters from configuration */ - if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) + if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX || + rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, - "non-default RSS hash functions are not supported"); + "RSS hash functions are not supported"); if (rss->level) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act, @@ -4797,19 +4879,20 @@ i40e_parse_rss_filter(struct rte_eth_dev *dev, union i40e_filter_t *filter, struct rte_flow_error *error) { - int ret; + struct i40e_rss_pattern_info p_info; struct i40e_queue_regions info; - uint8_t action_flag = 0; + int ret; memset(&info, 0, sizeof(struct i40e_queue_regions)); + memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info)); ret = i40e_flow_parse_rss_pattern(dev, pattern, - error, &action_flag, &info); + error, &p_info, &info); if (ret) return ret; ret = i40e_flow_parse_rss_action(dev, actions, error, - action_flag, &info, filter); + p_info, &info, filter); if (ret) return ret; @@ -4828,15 +4911,33 @@ i40e_config_rss_filter_set(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; int ret; if (conf->queue_region_conf) { ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1); - conf->queue_region_conf = 0; } else { ret = i40e_config_rss_filter(pf, conf, 1); } - return ret; + + if (ret) + return ret; + + rss_filter = rte_zmalloc("i40e_rss_filter", + sizeof(*rss_filter), 0); + if (rss_filter == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + rss_filter->rss_filter_info = *conf; + /* the rule new created is always valid + * the existing rule covered by new rule will be set invalid + */ + rss_filter->rss_filter_info.valid = true; + + TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next); + + return 0; } static int @@ -4845,10 +4946,21 @@ i40e_config_rss_filter_del(struct rte_eth_dev *dev, { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_rss_filter *rss_filter; + void *temp; - i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + if (conf->queue_region_conf) + i40e_flush_queue_region_all_conf(dev, hw, pf, 0); + else + i40e_config_rss_filter(pf, conf, 0); - i40e_config_rss_filter(pf, conf, 0); + TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) { + if (!memcmp(&rss_filter->rss_filter_info, conf, + sizeof(struct rte_flow_action_rss))) { + TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next); + rte_free(rss_filter); + } + } return 0; } @@ -4991,7 +5103,8 @@ i40e_flow_create(struct rte_eth_dev *dev, &cons_filter.rss_conf); if (ret) goto free_flow; - flow->rule = &pf->rss_info; + flow->rule = TAILQ_LAST(&pf->rss_config_list, + i40e_rss_conf_list); break; default: goto free_flow; @@ -5041,7 +5154,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev, break; case RTE_ETH_FILTER_HASH: ret = i40e_config_rss_filter_del(dev, - (struct i40e_rte_flow_rss_conf *)flow->rule); + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); break; default: PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", @@ -5189,7 +5302,7 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error) if (ret) { rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, - "Failed to flush rss flows."); + "Failed to flush RSS flows."); return -rte_errno; } @@ -5294,18 +5407,32 @@ i40e_flow_flush_tunnel_filter(struct i40e_pf *pf) return ret; } -/* remove the rss filter */ +/* 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_rte_flow_rss_conf *rss_info = &pf->rss_info; struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_flow *flow; + void *temp; int32_t ret = -EINVAL; ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0); - if (rss_info->conf.queue_num) - ret = i40e_config_rss_filter(pf, rss_info, FALSE); + /* Delete RSS flows in flow list. */ + TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) { + if (flow->filter_type != RTE_ETH_FILTER_HASH) + continue; + + if (flow->rule) { + ret = i40e_config_rss_filter_del(dev, + &((struct i40e_rss_filter *)flow->rule)->rss_filter_info); + if (ret) + return ret; + } + TAILQ_REMOVE(&pf->flow_list, flow, node); + rte_free(flow); + } + return ret; } -- 2.17.1
> -----Original Message-----
> From: Di, ChenxuX <chenxux.di@intel.com>
> Sent: Wednesday, April 15, 2020 4:46 PM
> To: dev@dpdk.org
> Cc: Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Di, ChenxuX <chenxux.di@intel.com>
> Subject: [PATCH v9] net/i40e: enable hash configuration in RSS flow
>
> This patch supports:
>
> - Symmetric hash configuration
> - Hash input set configuration
>
> Signed-off-by: Chenxu Di <chenxux.di@intel.com>
Acked-by: Beilei Xing <beilei.xing@intel.com>
On 04/15, Xing, Beilei wrote:
>
>
>> -----Original Message-----
>> From: Di, ChenxuX <chenxux.di@intel.com>
>> Sent: Wednesday, April 15, 2020 4:46 PM
>> To: dev@dpdk.org
>> Cc: Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
>> <beilei.xing@intel.com>; Di, ChenxuX <chenxux.di@intel.com>
>> Subject: [PATCH v9] net/i40e: enable hash configuration in RSS flow
>>
>> This patch supports:
>>
>> - Symmetric hash configuration
>> - Hash input set configuration
>>
>> Signed-off-by: Chenxu Di <chenxux.di@intel.com>
>
>Acked-by: Beilei Xing <beilei.xing@intel.com>
Applied to dpdk-next-net-intel, Thanks.