@@ -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
@@ -36,6 +36,7 @@ sources = files(
'nfp_mtr.c',
'nfp_net_common.c',
'nfp_net_ctrl.c',
+ 'nfp_net_flow.c',
'nfp_rxtx.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);
@@ -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
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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__ */