[PATCH v1 12/21] net/i40e: add support for common flow parsing

Anatoly Burakov anatoly.burakov at intel.com
Thu Aug 20 16:00:57 CEST 2026


Implement support for common flow parsing infrastructure in preparation for
migration of flow engines.

Signed-off-by: Anatoly Burakov <anatoly.burakov at intel.com>
---
 drivers/net/intel/i40e/i40e_ethdev.c | 12 +++++++
 drivers/net/intel/i40e/i40e_ethdev.h |  5 +++
 drivers/net/intel/i40e/i40e_flow.c   | 53 +++++++++++++++++++++++++++-
 drivers/net/intel/i40e/i40e_flow.h   | 12 +++++++
 4 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h

diff --git a/drivers/net/intel/i40e/i40e_ethdev.c b/drivers/net/intel/i40e/i40e_ethdev.c
index b6b2d291ee..a9f6a5680b 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.c
+++ b/drivers/net/intel/i40e/i40e_ethdev.c
@@ -42,6 +42,9 @@
 #include "i40e_regs.h"
 #include "rte_pmd_i40e.h"
 #include "i40e_hash.h"
+#include "i40e_flow.h"
+
+#include "../common/flow_engine.h"
 
 #define ETH_I40E_FLOATING_VEB_ARG	"enable_floating_veb"
 #define ETH_I40E_FLOATING_VEB_LIST_ARG	"floating_veb_list"
@@ -1844,6 +1847,10 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
 	/* reset all stats of the device, including pf and main vsi */
 	i40e_dev_stats_reset(dev);
 
+	/* initialize flow engine configuration */
+	ci_flow_engine_conf_init(&pf->flow_engine_conf,
+			&i40e_flow_engine_list, dev->data);
+
 	return 0;
 
 err_init_fdir_filter_list:
@@ -2700,6 +2707,9 @@ i40e_dev_close(struct rte_eth_dev *dev)
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return 0;
 
+	/* uninstall all flows while the HW is still alive */
+	ci_flow_flush(&pf->flow_engine_conf, NULL);
+
 	ret = rte_eth_switch_domain_free(pf->switch_domain_id);
 	if (ret)
 		PMD_INIT_LOG(WARNING, "failed to free switch domain: %d", ret);
@@ -2785,6 +2795,8 @@ i40e_dev_close(struct rte_eth_dev *dev)
 			rte_free(p_flow);
 	}
 
+	ci_flow_engine_conf_reset(&pf->flow_engine_conf);
+
 	/* release the fdir static allocated memory */
 	i40e_fdir_memory_cleanup(pf);
 
diff --git a/drivers/net/intel/i40e/i40e_ethdev.h b/drivers/net/intel/i40e/i40e_ethdev.h
index 1e64a2d280..16b67268f7 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.h
+++ b/drivers/net/intel/i40e/i40e_ethdev.h
@@ -21,6 +21,8 @@
 #include "base/i40e_type.h"
 #include "base/virtchnl.h"
 
+#include "../common/flow_engine.h"
+
 #define I40E_AQ_LEN               32
 #define I40E_AQ_BUF_SZ            4096
 /* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
@@ -278,6 +280,7 @@ enum i40e_flxpld_layer_idx {
  * Struct to store flow created.
  */
 struct rte_flow {
+	struct ci_flow base;
 	TAILQ_ENTRY(rte_flow) node;
 	enum rte_filter_type filter_type;
 	void *rule;
@@ -1182,6 +1185,8 @@ struct i40e_pf {
 	/* The floating enable flag for the specific VF */
 	bool floating_veb_list[I40E_MAX_VF];
 	struct i40e_flow_list flow_list;
+	/* flow engine configuration */
+	struct ci_flow_engine_conf flow_engine_conf;
 	bool mpls_replace_flag;  /* 1 - MPLS filter replace is done */
 	bool gtp_replace_flag;   /* 1 - GTP-C/U filter replace is done */
 	bool qinq_replace_flag;  /* QINQ filter replace is done */
diff --git a/drivers/net/intel/i40e/i40e_flow.c b/drivers/net/intel/i40e/i40e_flow.c
index f0eea61b1e..b8b4e56414 100644
--- a/drivers/net/intel/i40e/i40e_flow.c
+++ b/drivers/net/intel/i40e/i40e_flow.c
@@ -26,9 +26,12 @@
 #include "base/i40e_prototype.h"
 #include "i40e_ethdev.h"
 #include "i40e_hash.h"
+#include "i40e_flow.h"
 
 #include "../common/flow_check.h"
 
+const struct ci_flow_engine_list i40e_flow_engine_list = {0};
+
 #define I40E_IPV6_TC_MASK	(0xFF << I40E_FDIR_IPv6_TC_OFFSET)
 #define I40E_IPV6_FRAG_HEADER	44
 #define I40E_TENANT_ARRAY_NUM	3
@@ -1268,6 +1271,25 @@ i40e_flow_dev_dump(struct rte_eth_dev *dev,
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct rte_flow *p_flow;
 	bool found = false;
+	int ret;
+
+	/* try the new flow engine first */
+	ret = ci_flow_dump(&pf->flow_engine_conf, flow, file, error);
+
+	/*
+	 * There are multiple possible situations here:
+	 *
+	 * - User requested to dump all flows
+	 * - User requested to dump a specific flow
+	 *
+	 * For the first case, we keep going because legacy engines might still
+	 * have flows we want to dump.
+	 *
+	 * For the second case, we only keep going if the flow we were asked to
+	 * dump was not found in the new engines.
+	 */
+	if (flow != NULL && ret == 0)
+		return 0;
 
 	TAILQ_FOREACH(p_flow, &pf->flow_list, node) {
 		size_t rule_size = 0;
@@ -3892,8 +3914,15 @@ i40e_flow_validate(struct rte_eth_dev *dev,
 		   const struct rte_flow_action actions[],
 		   struct rte_flow_error *error)
 {
+	struct i40e_pf *pf = dev->data->dev_private;
 	/* creates dummy context */
 	struct i40e_filter_ctx filter_ctx = {0};
+	int ret;
+
+	/* try the new engine first */
+	ret = ci_flow_validate(&pf->flow_engine_conf, attr, pattern, actions, error);
+	if (ret == 0)
+		return 0;
 
 	return i40e_flow_check(dev, attr, pattern, actions, &filter_ctx, error);
 }
@@ -3911,6 +3940,11 @@ i40e_flow_create(struct rte_eth_dev *dev,
 	struct i40e_fdir_info *fdir_info = &pf->fdir;
 	int ret;
 
+	/* try the new engine first */
+	flow = ci_flow_create(&pf->flow_engine_conf, attr, pattern, actions, error);
+	if (flow != NULL)
+		return flow;
+
 	ret = i40e_flow_check(dev, attr, pattern, actions, &filter_ctx, error);
 	if (ret < 0)
 		return NULL;
@@ -4017,6 +4051,11 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 	struct i40e_fdir_info *fdir_info = &pf->fdir;
 	int ret = 0;
 
+	/* try the new engine first */
+	ret = ci_flow_destroy(&pf->flow_engine_conf, flow, error);
+	if (ret == 0)
+		return 0;
+
 	switch (filter_type) {
 	case RTE_ETH_FILTER_ETHERTYPE:
 		ret = i40e_flow_destroy_ethertype_filter(pf,
@@ -4161,6 +4200,11 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int ret;
 
+	/* flush the new engine first */
+	ret = ci_flow_flush(&pf->flow_engine_conf, error);
+	if (ret != 0)
+		return ret;
+
 	ret = i40e_flow_flush_fdir_filter(pf);
 	if (ret) {
 		rte_flow_error_set(error, -ret,
@@ -4310,14 +4354,21 @@ i40e_flow_flush_tunnel_filter(struct i40e_pf *pf)
 }
 
 static int
-i40e_flow_query(struct rte_eth_dev *dev __rte_unused,
+i40e_flow_query(struct rte_eth_dev *dev,
 		struct rte_flow *flow,
 		const struct rte_flow_action *actions,
 		void *data, struct rte_flow_error *error)
 {
+	struct i40e_pf *pf = dev->data->dev_private;
 	struct i40e_rss_filter *rss_rule = (struct i40e_rss_filter *)flow->rule;
 	enum rte_filter_type filter_type = flow->filter_type;
 	struct rte_flow_action_rss *rss_conf = data;
+	int ret;
+
+	/* try the new engine first */
+	ret = ci_flow_query(&pf->flow_engine_conf, flow, actions, data, error);
+	if (ret == 0)
+		return 0;
 
 	if (!rss_rule) {
 		rte_flow_error_set(error, EINVAL,
diff --git a/drivers/net/intel/i40e/i40e_flow.h b/drivers/net/intel/i40e/i40e_flow.h
new file mode 100644
index 0000000000..c958868661
--- /dev/null
+++ b/drivers/net/intel/i40e/i40e_flow.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#ifndef _I40E_FLOW_H_
+#define _I40E_FLOW_H_
+
+#include "../common/flow_engine.h"
+
+extern const struct ci_flow_engine_list i40e_flow_engine_list;
+
+#endif /* _I40E_FLOW_H_ */
-- 
2.52.0



More information about the dev mailing list