[PATCH v1 09/21] net/ixgbe: reimplement security parser

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


Use the new flow graph API and common flow engine infrastructure to
implement flow parser for security filter. As a result, flow item checks
have become more stringent:

- Mask is now explicitly validated to not have unsupported items in it,
  when previously they were ignored
- Mask is also validated to mask src/dst addresses, as otherwise it is
  inconsistent with rte_flow API

Previously, security parser was a special case, now it is a first class
citizen. A new callback for removing SA's through rte_flow API has been
added to avoid leaking SA's when removing flows.

Signed-off-by: Anatoly Burakov <anatoly.burakov at intel.com>
---
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   2 -
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 120 +------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   1 +
 drivers/net/intel/ixgbe/ixgbe_flow_security.c | 320 ++++++++++++++++++
 drivers/net/intel/ixgbe/ixgbe_ipsec.c         |  54 ++-
 drivers/net/intel/ixgbe/ixgbe_ipsec.h         |   4 +-
 drivers/net/intel/ixgbe/meson.build           |   1 +
 7 files changed, 377 insertions(+), 125 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c

diff --git a/drivers/net/intel/ixgbe/ixgbe_ethdev.h b/drivers/net/intel/ixgbe/ixgbe_ethdev.h
index cde0ee8fda..e08c1ebb52 100644
--- a/drivers/net/intel/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/intel/ixgbe/ixgbe_ethdev.h
@@ -350,8 +350,6 @@ struct ixgbe_l2_tn_info {
 struct rte_flow {
 	struct ci_flow flow;
 	enum rte_filter_type filter_type;
-	/* security flows are not rte_filter_type */
-	bool is_security;
 	void *rule;
 };
 
diff --git a/drivers/net/intel/ixgbe/ixgbe_flow.c b/drivers/net/intel/ixgbe/ixgbe_flow.c
index a77c7694b3..3ba3608ee6 100644
--- a/drivers/net/intel/ixgbe/ixgbe_flow.c
+++ b/drivers/net/intel/ixgbe/ixgbe_flow.c
@@ -79,6 +79,7 @@ const struct ci_flow_engine_list ixgbe_flow_engine_list = {
 		&ixgbe_syn_flow_engine,
 		&ixgbe_l2_tunnel_flow_engine,
 		&ixgbe_ntuple_flow_engine,
+		&ixgbe_security_flow_engine,
 	},
 };
 
@@ -156,94 +157,6 @@ ixgbe_flow_actions_check(const struct ci_flow_actions *actions,
  * normally the packets should use network order.
  */
 
-static int
-ixgbe_parse_security_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
-		const struct rte_flow_item pattern[], const struct rte_flow_action actions[],
-		struct rte_flow_error *error)
-{
-	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	const struct rte_flow_action_security *security;
-	struct rte_security_session *session;
-	const struct rte_flow_item *item;
-	struct ci_flow_actions parsed_actions;
-	struct ci_flow_actions_check_param ap_param = {
-		.allowed_types = (const enum rte_flow_action_type[]){
-			/* only security is allowed here */
-			RTE_FLOW_ACTION_TYPE_SECURITY,
-			RTE_FLOW_ACTION_TYPE_END
-		},
-		.max_actions = 1,
-	};
-	const struct rte_flow_action *action;
-	struct ip_spec spec;
-	int ret;
-
-	if (hw->mac.type != ixgbe_mac_82599EB &&
-			hw->mac.type != ixgbe_mac_X540 &&
-			hw->mac.type != ixgbe_mac_X550 &&
-			hw->mac.type != ixgbe_mac_X550EM_x &&
-			hw->mac.type != ixgbe_mac_X550EM_a &&
-			hw->mac.type != ixgbe_mac_E610)
-		return -ENOTSUP;
-
-	/* validate attributes */
-	ret = ci_flow_check_attr(attr, NULL, error);
-	if (ret)
-		return ret;
-
-	/* parse requested actions */
-	ret = ci_flow_check_actions(actions, &ap_param, &parsed_actions, error);
-	if (ret)
-		return ret;
-
-	action = parsed_actions.actions[0];
-	security = action->conf;
-
-	/* get the IP pattern*/
-	item = next_no_void_pattern(pattern, NULL);
-	while (item->type != RTE_FLOW_ITEM_TYPE_IPV4 &&
-			item->type != RTE_FLOW_ITEM_TYPE_IPV6) {
-		if (item->last || item->type == RTE_FLOW_ITEM_TYPE_END) {
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "IP pattern missing.");
-			return -rte_errno;
-		}
-		item = next_no_void_pattern(pattern, item);
-	}
-	if (item->spec == NULL) {
-		rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM_SPEC, item,
-				"NULL IP pattern.");
-		return -rte_errno;
-	}
-	spec.is_ipv6 = item->type == RTE_FLOW_ITEM_TYPE_IPV6;
-	if (spec.is_ipv6) {
-		const struct rte_flow_item_ipv6 *ipv6 = item->spec;
-		spec.spec.ipv6 = *ipv6;
-	} else {
-		const struct rte_flow_item_ipv4 *ipv4 = item->spec;
-		spec.spec.ipv4 = *ipv4;
-	}
-
-	/*
-	 * we get pointer to security session from security action, which is
-	 * const. however, we do need to act on the session, so either we do
-	 * some kind of pointer based lookup to get session pointer internally
-	 * (which quickly gets unwieldy for lots of flows case), or we simply
-	 * cast away constness. the latter path was chosen.
-	 */
-	session = RTE_CAST_PTR(struct rte_security_session *, security->security_session);
-	ret = ixgbe_crypto_add_ingress_sa_from_flow(session, &spec);
-	if (ret) {
-		rte_flow_error_set(error, -ret,
-				RTE_FLOW_ERROR_TYPE_ACTION, action,
-				"Failed to add security session.");
-		return -rte_errno;
-	}
-	return 0;
-}
-
 /* search next no void pattern and skip fuzzy */
 static inline
 const struct rte_flow_item *next_no_fuzzy_pattern(
@@ -1906,15 +1819,6 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
 	TAILQ_INSERT_TAIL(&adapter->flow_list,
 				&ixgbe_flow_mem_ptr->base, entries);
 
-	/**
-	 *  Special case for flow action type RTE_FLOW_ACTION_TYPE_SECURITY
-	 */
-	ret = ixgbe_parse_security_filter(dev, attr, pattern, actions, error);
-	if (!ret) {
-		flow->is_security = true;
-		return flow;
-	}
-
 	memset(&fdir_rule, 0, sizeof(struct ixgbe_fdir_rule));
 	ret = ixgbe_parse_fdir_filter(dev, attr, pattern,
 				actions, &fdir_rule, error);
@@ -2005,13 +1909,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,
 
 	/* fall back to legacy engines */
 
-	/**
-	 *  Special case for flow action type RTE_FLOW_ACTION_TYPE_SECURITY
-	 */
-	ret = ixgbe_parse_security_filter(dev, attr, pattern, actions, error);
-	if (!ret)
-		return 0;
-
 	memset(&fdir_rule, 0, sizeof(struct ixgbe_fdir_rule));
 	ret = ixgbe_parse_fdir_filter(dev, attr, pattern,
 				actions, &fdir_rule, error);
@@ -2065,12 +1962,6 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 				"Flow not found for this port");
 	}
 
-	/* Special case for SECURITY flows */
-	if (flow->is_security) {
-		ret = 0;
-		goto free;
-	}
-
 	switch (filter_type) {
 	case RTE_ETH_FILTER_FDIR:
 		fdir_rule_ptr = (struct ixgbe_fdir_rule_ele *)pmd_flow->rule;
@@ -2110,7 +2001,6 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 		return ret;
 	}
 
-free:
 	TAILQ_REMOVE(&adapter->flow_list, flow_mem_base, entries);
 	rte_free(flow_mem_base);
 	rte_free(flow);
@@ -2163,9 +2053,6 @@ ixgbe_flow_flush(struct rte_eth_dev *dev,
 static const char *
 ixgbe_flow_rule_engine_name(const struct rte_flow *flow)
 {
-	if (flow->is_security)
-		return "security";
-
 	switch (flow->filter_type) {
 	case RTE_ETH_FILTER_NTUPLE:
 		return "ntuple";
@@ -2187,9 +2074,6 @@ ixgbe_flow_rule_engine_name(const struct rte_flow *flow)
 static size_t
 ixgbe_flow_rule_size(const struct rte_flow *flow)
 {
-	if (flow->is_security)
-		return 0;
-
 	switch (flow->filter_type) {
 	case RTE_ETH_FILTER_NTUPLE:
 		return sizeof(struct rte_eth_ntuple_filter);
@@ -2211,7 +2095,7 @@ ixgbe_flow_rule_size(const struct rte_flow *flow)
 static const void *
 ixgbe_flow_rule_data(const struct rte_flow *flow)
 {
-	if (flow->is_security || flow->rule == NULL)
+	if (flow->rule == NULL)
 		return NULL;
 
 	return RTE_PTR_ADD(flow->rule, sizeof(struct ixgbe_filter_ele_base));
diff --git a/drivers/net/intel/ixgbe/ixgbe_flow.h b/drivers/net/intel/ixgbe/ixgbe_flow.h
index 6f082e9402..87cf028245 100644
--- a/drivers/net/intel/ixgbe/ixgbe_flow.h
+++ b/drivers/net/intel/ixgbe/ixgbe_flow.h
@@ -19,5 +19,6 @@ extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
 extern const struct ci_flow_engine ixgbe_syn_flow_engine;
 extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;
 extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;
+extern const struct ci_flow_engine ixgbe_security_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
diff --git a/drivers/net/intel/ixgbe/ixgbe_flow_security.c b/drivers/net/intel/ixgbe/ixgbe_flow_security.c
new file mode 100644
index 0000000000..af0d4abd4b
--- /dev/null
+++ b/drivers/net/intel/ixgbe/ixgbe_flow_security.c
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#include <rte_common.h>
+#include <rte_flow.h>
+#include <rte_flow_graph.h>
+#include <rte_ether.h>
+#include <rte_security_driver.h>
+
+#include "ixgbe_ethdev.h"
+#include "ixgbe_flow.h"
+#include "../common/flow_check.h"
+#include "../common/flow_util.h"
+#include "../common/flow_engine.h"
+
+struct ixgbe_security_filter {
+	struct ip_spec spec;
+	struct rte_security_session *session;
+	uint32_t sa_idx;
+};
+
+struct ixgbe_security_flow {
+	struct rte_flow flow;
+	struct ixgbe_security_filter security;
+};
+
+struct ixgbe_security_ctx {
+	struct ci_flow_engine_ctx base;
+	struct ixgbe_security_filter security;
+};
+
+/**
+ * Ntuple security filter graph implementation
+ * Pattern: START -> IPV4 | IPV6 -> END
+ */
+
+enum ixgbe_security_node_id {
+	IXGBE_SECURITY_NODE_START = RTE_FLOW_NODE_FIRST,
+	IXGBE_SECURITY_NODE_IPV4,
+	IXGBE_SECURITY_NODE_IPV6,
+	IXGBE_SECURITY_NODE_END,
+	IXGBE_SECURITY_NODE_MAX,
+};
+
+static int
+ixgbe_validate_security_ipv4(const void *ctx __rte_unused,
+		const struct rte_flow_item *item,
+		struct rte_flow_error *error)
+{
+	const struct rte_flow_item_ipv4 *ipv4_mask = item->mask;
+
+	/* only src/dst addresses are supported */
+	if (ipv4_mask->hdr.version_ihl ||
+	    ipv4_mask->hdr.type_of_service ||
+	    ipv4_mask->hdr.total_length ||
+	    ipv4_mask->hdr.packet_id ||
+	    ipv4_mask->hdr.fragment_offset ||
+	    ipv4_mask->hdr.next_proto_id ||
+	    ipv4_mask->hdr.time_to_live ||
+	    ipv4_mask->hdr.hdr_checksum) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Invalid IPv4 mask");
+	}
+
+	/* both src/dst addresses must be fully masked */
+	if (!CI_FIELD_IS_MASKED(&ipv4_mask->hdr.src_addr) ||
+	    !CI_FIELD_IS_MASKED(&ipv4_mask->hdr.dst_addr)) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Invalid IPv4 mask");
+	}
+
+	return 0;
+}
+
+static int
+ixgbe_process_security_ipv4(void *ctx, const struct rte_flow_item *item,
+		struct rte_flow_error *error __rte_unused)
+{
+	struct ixgbe_security_ctx *sec_ctx = (struct ixgbe_security_ctx *)ctx;
+	const struct rte_flow_item_ipv4 *ipv4_spec = item->spec;
+
+	/* copy entire spec */
+	sec_ctx->security.spec.spec.ipv4 = *ipv4_spec;
+	sec_ctx->security.spec.is_ipv6 = false;
+
+	return 0;
+}
+
+static int
+ixgbe_validate_security_ipv6(const void *ctx __rte_unused,
+			  const struct rte_flow_item *item,
+			  struct rte_flow_error *error)
+{
+	const struct rte_flow_item_ipv6 *ipv6_mask = item->mask;
+
+	/* only src/dst addresses are supported */
+	if (ipv6_mask->hdr.vtc_flow ||
+	    ipv6_mask->hdr.payload_len ||
+	    ipv6_mask->hdr.proto ||
+	    ipv6_mask->hdr.hop_limits) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Invalid IPv6 mask");
+	}
+	/* both src/dst addresses must be fully masked */
+	if (!CI_FIELD_IS_MASKED(&ipv6_mask->hdr.src_addr) ||
+	    !CI_FIELD_IS_MASKED(&ipv6_mask->hdr.dst_addr)) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"Invalid IPv6 mask");
+	}
+
+	return 0;
+}
+
+static int
+ixgbe_process_security_ipv6(void *ctx, const struct rte_flow_item *item,
+		struct rte_flow_error *error __rte_unused)
+{
+	struct ixgbe_security_ctx *sec_ctx = (struct ixgbe_security_ctx *)ctx;
+	const struct rte_flow_item_ipv6 *ipv6_spec = item->spec;
+
+	/* copy entire spec */
+	sec_ctx->security.spec.spec.ipv6 = *ipv6_spec;
+	sec_ctx->security.spec.is_ipv6 = true;
+
+	return 0;
+}
+
+static const struct rte_flow_graph ixgbe_security_graph = {
+	.nodes = (struct rte_flow_graph_node[]) {
+		[IXGBE_SECURITY_NODE_START] = {
+			.name = "START",
+		},
+		[IXGBE_SECURITY_NODE_IPV4] = {
+			.name = "IPV4",
+			.type = RTE_FLOW_ITEM_TYPE_IPV4,
+			.constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+			.validate = ixgbe_validate_security_ipv4,
+			.process = ixgbe_process_security_ipv4,
+		},
+		[IXGBE_SECURITY_NODE_IPV6] = {
+			.name = "IPV6",
+			.type = RTE_FLOW_ITEM_TYPE_IPV6,
+			.constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+			.validate = ixgbe_validate_security_ipv6,
+			.process = ixgbe_process_security_ipv6,
+		},
+		[IXGBE_SECURITY_NODE_END] = {
+			.name = "END",
+			.type = RTE_FLOW_ITEM_TYPE_END,
+		},
+	},
+	.edges = (struct rte_flow_graph_edge[]) {
+		[IXGBE_SECURITY_NODE_START] = {
+			.next = (const size_t[]) {
+				IXGBE_SECURITY_NODE_IPV4,
+				IXGBE_SECURITY_NODE_IPV6,
+				RTE_FLOW_NODE_EDGE_END
+			}
+		},
+		[IXGBE_SECURITY_NODE_IPV4] = {
+			.next = (const size_t[]) {
+				IXGBE_SECURITY_NODE_END,
+				RTE_FLOW_NODE_EDGE_END
+			}
+		},
+		[IXGBE_SECURITY_NODE_IPV6] = {
+			.next = (const size_t[]) {
+				IXGBE_SECURITY_NODE_END,
+				RTE_FLOW_NODE_EDGE_END
+			}
+		},
+	},
+};
+
+static int
+ixgbe_flow_security_ctx_parse(const struct rte_flow_action *actions,
+		const struct rte_flow_attr *attr,
+		struct ci_flow_engine_ctx *ctx,
+		struct rte_flow_error *error)
+{
+	struct ixgbe_security_ctx *sec_ctx = (struct ixgbe_security_ctx *)ctx;
+	struct ci_flow_actions parsed_actions;
+	struct ci_flow_actions_check_param ap_param = {
+		.allowed_types = (const enum rte_flow_action_type[]){
+			/* only security is allowed here */
+			RTE_FLOW_ACTION_TYPE_SECURITY,
+			RTE_FLOW_ACTION_TYPE_END
+		},
+		.max_actions = 1,
+	};
+	const struct rte_flow_action_security *security;
+	struct rte_security_session *session;
+	const struct ixgbe_crypto_session *ic_session;
+	int ret;
+
+	/* validate attributes */
+	ret = ci_flow_check_attr(attr, NULL, error);
+	if (ret)
+		return ret;
+
+	/* parse requested actions */
+	ret = ci_flow_check_actions(actions, &ap_param, &parsed_actions, error);
+	if (ret)
+		return ret;
+
+	security = (const struct rte_flow_action_security *)parsed_actions.actions[0]->conf;
+
+	if (security->security_session == NULL) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, &parsed_actions.actions[0],
+				"NULL security session");
+	}
+
+	/* cast away constness since we need to store the session pointer in the context */
+	session = RTE_CAST_PTR(struct rte_security_session *, security->security_session);
+
+	/* verify that the session is of a correct type */
+	ic_session = SECURITY_GET_SESS_PRIV(session);
+	if (ic_session->dev_data != ctx->dev_data) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, &parsed_actions.actions[0],
+				"Security session was created for a different device");
+	}
+	if (ic_session->op != IXGBE_OP_AUTHENTICATED_DECRYPTION) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, &parsed_actions.actions[0],
+				"Only authenticated decryption is supported");
+	}
+	sec_ctx->security.session = session;
+
+	return 0;
+}
+
+static int
+ixgbe_flow_security_ctx_to_flow(const struct ci_flow_engine_ctx *ctx,
+		struct ci_flow *flow,
+		struct rte_flow_error *error __rte_unused)
+{
+	const struct ixgbe_security_ctx *security_ctx = (const struct ixgbe_security_ctx *)ctx;
+	struct ixgbe_security_flow *security_flow = (struct ixgbe_security_flow *)flow;
+
+	security_flow->security = security_ctx->security;
+
+	return 0;
+}
+
+static int
+ixgbe_flow_security_flow_install(struct ci_flow *flow,
+		struct rte_flow_error *error)
+{
+	struct ixgbe_security_flow *security_flow = (struct ixgbe_security_flow *)flow;
+	struct ixgbe_security_filter *filter = &security_flow->security;
+	int ret;
+	uint32_t sa_idx = 0;
+
+	ret = ixgbe_crypto_add_ingress_sa_from_flow(filter->session, &filter->spec, &sa_idx);
+	if (ret) {
+		return rte_flow_error_set(error, -ret,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to add ingress SA from flow");
+	}
+	filter->sa_idx = sa_idx;
+	return 0;
+}
+
+static int
+ixgbe_flow_security_flow_uninstall(struct ci_flow *flow,
+		struct rte_flow_error *error)
+{
+	struct ixgbe_security_flow *security_flow = (struct ixgbe_security_flow *)flow;
+	struct ixgbe_security_filter *filter = &security_flow->security;
+	int ret;
+
+	ret = ixgbe_crypto_remove_ingress_sa_from_flow(filter->session, filter->sa_idx);
+	if (ret) {
+		return rte_flow_error_set(error, -ret,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to remove ingress SA from flow");
+	}
+	return 0;
+}
+
+static int
+ixgbe_flow_security_engine_init(const struct ci_flow_engine *engine __rte_unused,
+		struct rte_eth_dev_data *dev_data,
+		void *priv __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev_data->dev_private);
+
+	if (hw->mac.type == ixgbe_mac_82599EB ||
+			hw->mac.type == ixgbe_mac_X540 ||
+			hw->mac.type == ixgbe_mac_X550 ||
+			hw->mac.type == ixgbe_mac_X550EM_x ||
+			hw->mac.type == ixgbe_mac_X550EM_a ||
+			hw->mac.type == ixgbe_mac_E610)
+		return 0;
+
+	return -ENOTSUP;
+}
+
+static const struct ci_flow_engine_ops ixgbe_security_ops = {
+	.engine_init = ixgbe_flow_security_engine_init,
+	.ctx_parse = ixgbe_flow_security_ctx_parse,
+	.ctx_to_flow = ixgbe_flow_security_ctx_to_flow,
+	.flow_install = ixgbe_flow_security_flow_install,
+	.flow_uninstall = ixgbe_flow_security_flow_uninstall,
+};
+
+const struct ci_flow_engine ixgbe_security_flow_engine = {
+	.name = "security",
+	.ctx_size = sizeof(struct ixgbe_security_ctx),
+	.flow_size = sizeof(struct ixgbe_security_flow),
+	.ops = &ixgbe_security_ops,
+	.graph = &ixgbe_security_graph,
+};
diff --git a/drivers/net/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/intel/ixgbe/ixgbe_ipsec.c
index 3c35326016..fe97bec929 100644
--- a/drivers/net/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/intel/ixgbe/ixgbe_ipsec.c
@@ -143,7 +143,7 @@ ixgbe_crypto_clear_ipsec_tables(struct rte_eth_dev *dev)
 }
 
 static int
-ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
+ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session, uint32_t *sa_index_out)
 {
 	struct rte_eth_dev_data *dev_data = ic_session->dev_data;
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev_data->dev_private);
@@ -245,6 +245,9 @@ ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
 		rte_memzero_explicit(key, sizeof(key));
 	}
 
+	if (sa_index_out != NULL)
+		*sa_index_out = sa_index;
+
 	return 0;
 }
 
@@ -329,6 +332,37 @@ ixgbe_crypto_remove_sa(struct ixgbe_crypto_session *ic_session)
 	return 0;
 }
 
+/* Decryption-only removal by SA index; the IP entry is found via the SA entry. */
+static int
+ixgbe_crypto_remove_rx_sa_by_idx(struct ixgbe_crypto_session *ic_session,
+		uint32_t sa_idx)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(ic_session->dev_data->dev_private);
+	struct ixgbe_ipsec *priv =
+			IXGBE_DEV_PRIVATE_TO_IPSEC(ic_session->dev_data->dev_private);
+	struct ixgbe_crypto_rx_sa_table *rxsa = &priv->rx_sa_tbl[sa_idx];
+	uint32_t ip_index = rxsa->ip_index;
+	struct ixgbe_crypto_rx_ip_table *rxip = &priv->rx_ip_tbl[ip_index];
+	const uint8_t key[16] = {0};
+
+	/* Disable and clear Rx SPI and key table entries*/
+	ixgbe_crypto_write_rx_spi(hw, sa_idx, 0, 0, false);
+	ixgbe_crypto_write_rx_key(hw, sa_idx, key, 0, 0, false);
+
+	/* Clear the SA table entry*/
+	*rxsa = (struct ixgbe_crypto_rx_sa_table){0};
+
+	/* If last used then clear the IP table entry*/
+	rxip->ref_count--;
+	if (rxip->ref_count == 0) {
+		const struct ipaddr ip = {0};
+		ixgbe_crypto_write_rx_ip(hw, ip_index, &ip, false);
+		*rxip = (struct ixgbe_crypto_rx_ip_table){0};
+	}
+
+	return 0;
+}
+
 static int
 ixgbe_crypto_create_session(void *device,
 		struct rte_security_session_conf *conf,
@@ -377,7 +411,7 @@ ixgbe_crypto_create_session(void *device,
 	ic_session->dev_data = eth_dev->data;
 
 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) {
-		if (ixgbe_crypto_add_sa(ic_session)) {
+		if (ixgbe_crypto_add_sa(ic_session, NULL)) {
 			PMD_DRV_LOG(ERR, "Failed to add SA");
 			return -EPERM;
 		}
@@ -634,7 +668,7 @@ ixgbe_crypto_enable_ipsec(struct rte_eth_dev *dev)
 
 int
 ixgbe_crypto_add_ingress_sa_from_flow(struct rte_security_session *sess,
-		const struct ip_spec *spec)
+		const struct ip_spec *spec, uint32_t *sa_index)
 {
 	struct ixgbe_crypto_session *ic_session = SECURITY_GET_SESS_PRIV(sess);
 
@@ -654,12 +688,24 @@ ixgbe_crypto_add_ingress_sa_from_flow(struct rte_security_session *sess,
 			ic_session->src_ip.ipv4 = ipv4->hdr.src_addr;
 			ic_session->dst_ip.ipv4 = ipv4->hdr.dst_addr;
 		}
-		return ixgbe_crypto_add_sa(ic_session);
+		return ixgbe_crypto_add_sa(ic_session, sa_index);
 	}
 
 	return 0;
 }
 
+int
+ixgbe_crypto_remove_ingress_sa_from_flow(struct rte_security_session *sess,
+		uint32_t sa_index)
+{
+	struct ixgbe_crypto_session *ic_session = SECURITY_GET_SESS_PRIV(sess);
+
+	if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION)
+		return ixgbe_crypto_remove_rx_sa_by_idx(ic_session, sa_index);
+
+	return 0;
+}
+
 static struct rte_security_ops ixgbe_security_ops = {
 	.session_create = ixgbe_crypto_create_session,
 	.session_update = NULL,
diff --git a/drivers/net/intel/ixgbe/ixgbe_ipsec.h b/drivers/net/intel/ixgbe/ixgbe_ipsec.h
index 1099b5f598..55ecd91c5d 100644
--- a/drivers/net/intel/ixgbe/ixgbe_ipsec.h
+++ b/drivers/net/intel/ixgbe/ixgbe_ipsec.h
@@ -123,7 +123,9 @@ struct ip_spec {
 	} spec;
 };
 int ixgbe_crypto_add_ingress_sa_from_flow(struct rte_security_session *sess,
-		const struct ip_spec *ip_spec);
+		const struct ip_spec *ip_spec, uint32_t *sa_index);
+int ixgbe_crypto_remove_ingress_sa_from_flow(struct rte_security_session *sess,
+		uint32_t sa_index);
 
 
 
diff --git a/drivers/net/intel/ixgbe/meson.build b/drivers/net/intel/ixgbe/meson.build
index f3052daf4f..65ffe19939 100644
--- a/drivers/net/intel/ixgbe/meson.build
+++ b/drivers/net/intel/ixgbe/meson.build
@@ -15,6 +15,7 @@ sources += files(
         'ixgbe_flow_syn.c',
         'ixgbe_flow_l2tun.c',
         'ixgbe_flow_ntuple.c',
+        'ixgbe_flow_security.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
-- 
2.52.0



More information about the dev mailing list