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 <[email protected]>
---
 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

Reply via email to