Add the structures and functions to process flow table, which is used in the rte_flow offload logics. This module is used for the CoreNIC firmware.
Signed-off-by: Chaoyong He <chaoyong...@corigine.com> Reviewed-by: Long Wu <long...@corigine.com> Reviewed-by: Peng Zhang <peng.zh...@corigine.com> --- drivers/common/nfp/nfp_common_ctrl.h | 1 + drivers/net/nfp/meson.build | 1 + drivers/net/nfp/nfp_ethdev.c | 27 ++++- drivers/net/nfp/nfp_net_common.h | 11 ++ drivers/net/nfp/nfp_net_flow.c | 166 +++++++++++++++++++++++++++ drivers/net/nfp/nfp_net_flow.h | 28 +++++ 6 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 drivers/net/nfp/nfp_net_flow.c create mode 100644 drivers/net/nfp/nfp_net_flow.h diff --git a/drivers/common/nfp/nfp_common_ctrl.h b/drivers/common/nfp/nfp_common_ctrl.h index d09fd2b892..cbde987736 100644 --- a/drivers/common/nfp/nfp_common_ctrl.h +++ b/drivers/common/nfp/nfp_common_ctrl.h @@ -223,6 +223,7 @@ struct nfp_net_fw_ver { #define NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP (0x1 << 3) /**< SA short match lookup */ #define NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP (0x1 << 4) /**< SA long match lookup */ #define NFP_NET_CFG_CTRL_MULTI_PF (0x1 << 5) +#define NFP_NET_CFG_CTRL_FLOW_STEER (0x1 << 8) /**< Flow Steering */ #define NFP_NET_CFG_CTRL_IN_ORDER (0x1 << 11) /**< Virtio in-order flag */ #define NFP_NET_CFG_CAP_WORD1 0x00a4 diff --git a/drivers/net/nfp/meson.build b/drivers/net/nfp/meson.build index 8407073af8..0d0a0bd8f4 100644 --- a/drivers/net/nfp/meson.build +++ b/drivers/net/nfp/meson.build @@ -36,6 +36,7 @@ sources = files( 'nfp_mtr.c', 'nfp_net_common.c', 'nfp_net_ctrl.c', + 'nfp_net_flow.c', 'nfp_rxtx.c', ) diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c index 537b4fe792..d0a1950ff3 100644 --- a/drivers/net/nfp/nfp_ethdev.c +++ b/drivers/net/nfp/nfp_ethdev.c @@ -23,6 +23,7 @@ #include "nfp_cpp_bridge.h" #include "nfp_ipsec.h" #include "nfp_logs.h" +#include "nfp_net_flow.h" #define NFP_PF_DRIVER_NAME net_nfp_pf @@ -151,6 +152,10 @@ nfp_net_start(struct rte_eth_dev *dev) ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP | NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP; + /* Enable flow steer by extend ctrl word1. */ + if ((cap_extend & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) + ctrl_extend |= NFP_NET_CFG_CTRL_FLOW_STEER; + update = NFP_NET_CFG_UPDATE_GEN; if (nfp_ext_reconfig(hw, ctrl_extend, update) != 0) return -EIO; @@ -323,6 +328,10 @@ nfp_net_uninit(struct rte_eth_dev *eth_dev) struct nfp_net_hw *net_hw; net_hw = eth_dev->data->dev_private; + + if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) + nfp_net_flow_priv_uninit(net_hw->pf_dev, net_hw->idx); + rte_free(net_hw->eth_xstats_base); nfp_ipsec_uninit(eth_dev); if (net_hw->mac_stats_area != NULL) @@ -762,6 +771,14 @@ nfp_net_init(struct rte_eth_dev *eth_dev) /* Recording current stats counters values */ nfp_net_stats_reset(eth_dev); + if ((hw->cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) { + err = nfp_net_flow_priv_init(pf_dev, port); + if (err != 0) { + PMD_INIT_LOG(ERR, "Init net flow priv failed"); + goto xstats_free; + } + } + return 0; xstats_free: @@ -1195,13 +1212,11 @@ nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev, port_cleanup: for (i = 0; i < app_fw_nic->total_phyports; i++) { id = nfp_function_id_get(pf_dev, i); + hw = app_fw_nic->ports[id]; - if (app_fw_nic->ports[id] != NULL && - app_fw_nic->ports[id]->eth_dev != NULL) { - struct rte_eth_dev *tmp_dev; - tmp_dev = app_fw_nic->ports[id]->eth_dev; - nfp_net_uninit(tmp_dev); - rte_eth_dev_release_port(tmp_dev); + if (hw != NULL && hw->eth_dev != NULL) { + nfp_net_uninit(hw->eth_dev); + rte_eth_dev_release_port(hw->eth_dev); } } nfp_cpp_area_release_free(pf_dev->ctrl_area); diff --git a/drivers/net/nfp/nfp_net_common.h b/drivers/net/nfp/nfp_net_common.h index ded491cbdc..eb668a1505 100644 --- a/drivers/net/nfp/nfp_net_common.h +++ b/drivers/net/nfp/nfp_net_common.h @@ -108,6 +108,14 @@ struct nfp_pf_dev { struct nfp_multi_pf multi_pf; }; +#define NFP_NET_FLOW_LIMIT 1024 + +struct nfp_net_priv { + uint32_t hash_seed; /**< Hash seed for hash tables in this structure. */ + struct rte_hash *flow_table; /**< Hash table to store flow rules. */ + uint16_t flow_count; /**< Flow count in hash table */ +}; + struct nfp_app_fw_nic { /** Backpointer to the PF device */ struct nfp_pf_dev *pf_dev; @@ -177,6 +185,9 @@ struct nfp_net_hw { struct nfp_net_tlv_caps tlv_caps; struct nfp_net_ipsec_data *ipsec_data; + + /** Used for rte_flow of CoreNIC firmware */ + struct nfp_net_priv *priv; }; static inline uint32_t diff --git a/drivers/net/nfp/nfp_net_flow.c b/drivers/net/nfp/nfp_net_flow.c new file mode 100644 index 0000000000..25da9ed8ac --- /dev/null +++ b/drivers/net/nfp/nfp_net_flow.c @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2023 Corigine, Inc. + * All rights reserved. + */ + +#include "nfp_net_flow.h" + +#include <rte_flow_driver.h> +#include <rte_hash.h> +#include <rte_jhash.h> +#include <rte_malloc.h> + +#include "nfp_logs.h" + +__rte_unused static int +nfp_net_flow_table_add(struct nfp_net_priv *priv, + struct rte_flow *nfp_flow) +{ + int ret; + + ret = rte_hash_add_key_data(priv->flow_table, &nfp_flow->hash_key, nfp_flow); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Add to flow table failed."); + return ret; + } + + return 0; +} + +__rte_unused static int +nfp_net_flow_table_delete(struct nfp_net_priv *priv, + struct rte_flow *nfp_flow) +{ + int ret; + + ret = rte_hash_del_key(priv->flow_table, &nfp_flow->hash_key); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Delete from flow table failed."); + return ret; + } + + return 0; +} + +__rte_unused static struct rte_flow * +nfp_net_flow_table_search(struct nfp_net_priv *priv, + struct rte_flow *nfp_flow) +{ + int index; + struct rte_flow *flow_find; + + index = rte_hash_lookup_data(priv->flow_table, &nfp_flow->hash_key, + (void **)&flow_find); + if (index < 0) { + PMD_DRV_LOG(DEBUG, "Data NOT found in the flow table."); + return NULL; + } + + return flow_find; +} + +__rte_unused static struct rte_flow * +nfp_net_flow_alloc(uint32_t match_len, + uint32_t action_len, + uint32_t port_id) +{ + char *data; + struct rte_flow *nfp_flow; + struct nfp_net_flow_payload *payload; + + nfp_flow = rte_zmalloc("nfp_flow", sizeof(struct rte_flow), 0); + if (nfp_flow == NULL) + return NULL; + + data = rte_zmalloc("nfp_flow_payload", match_len + action_len, 0); + if (data == NULL) + goto free_flow; + + nfp_flow->port_id = port_id; + payload = &nfp_flow->payload; + payload->match_len = match_len; + payload->action_len = action_len; + payload->match_data = data; + payload->action_data = data + match_len; + + return nfp_flow; + +free_flow: + rte_free(nfp_flow); + + return NULL; +} + +__rte_unused static void +nfp_net_flow_free(struct rte_flow *nfp_flow) +{ + rte_free(nfp_flow->payload.match_data); + rte_free(nfp_flow); +} + +int +nfp_net_flow_priv_init(struct nfp_pf_dev *pf_dev, + uint16_t port) +{ + int ret = 0; + struct nfp_net_priv *priv; + char flow_name[RTE_HASH_NAMESIZE]; + struct nfp_app_fw_nic *app_fw_nic; + const char *pci_name = strchr(pf_dev->pci_dev->name, ':') + 1; + + snprintf(flow_name, sizeof(flow_name), "%s_fl_%u", pci_name, port); + + struct rte_hash_parameters flow_hash_params = { + .name = flow_name, + .entries = NFP_NET_FLOW_LIMIT, + .hash_func = rte_jhash, + .socket_id = rte_socket_id(), + .key_len = sizeof(uint32_t), + .extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY, + }; + + priv = rte_zmalloc("nfp_app_nic_priv", sizeof(struct nfp_net_priv), 0); + if (priv == NULL) { + PMD_INIT_LOG(ERR, "NFP app nic priv creation failed"); + ret = -ENOMEM; + goto exit; + } + + app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv); + app_fw_nic->ports[port]->priv = priv; + priv->hash_seed = (uint32_t)rte_rand(); + + /* Flow table */ + flow_hash_params.hash_func_init_val = priv->hash_seed; + priv->flow_table = rte_hash_create(&flow_hash_params); + if (priv->flow_table == NULL) { + PMD_INIT_LOG(ERR, "flow hash table creation failed"); + ret = -ENOMEM; + goto free_priv; + } + + return 0; + +free_priv: + rte_free(priv); +exit: + return ret; +} + +void +nfp_net_flow_priv_uninit(struct nfp_pf_dev *pf_dev, + uint16_t port) +{ + struct nfp_net_priv *priv; + struct nfp_app_fw_nic *app_fw_nic; + + if (pf_dev == NULL) + return; + + app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv); + priv = app_fw_nic->ports[port]->priv; + if (priv != NULL) + rte_hash_free(priv->flow_table); + + rte_free(priv); +} diff --git a/drivers/net/nfp/nfp_net_flow.h b/drivers/net/nfp/nfp_net_flow.h new file mode 100644 index 0000000000..5ec80ba3b6 --- /dev/null +++ b/drivers/net/nfp/nfp_net_flow.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2023 Corigine, Inc. + * All rights reserved. + */ + +#ifndef __NFP_NET_FLOW_H__ +#define __NFP_NET_FLOW_H__ + +#include "nfp_net_common.h" + +struct nfp_net_flow_payload { + uint16_t cmsg_type; + uint8_t match_len; + uint8_t action_len; + char *match_data; + char *action_data; +}; + +struct rte_flow { + struct nfp_net_flow_payload payload; + uint32_t hash_key; + uint32_t port_id; +}; + +int nfp_net_flow_priv_init(struct nfp_pf_dev *pf_dev, uint16_t port); +void nfp_net_flow_priv_uninit(struct nfp_pf_dev *pf_dev, uint16_t port); + +#endif /* __NFP_NET_FLOW_H__ */ -- 2.39.1