From: Jie Liu <[email protected]>

This patch adds support for IPsec inline protocol offload for both
inbound and outbound traffic.

- Implement rte_security_ops: session_create, session_destroy.
- Add hardware SA table management.
- Update Rx/Tx data path to handle security offload flags.

The hardware offloads the ESP encapsulation/decapsulation and
cryptographic processing.

Signed-off-by: Jie Liu <[email protected]>
---
 drivers/net/sxe2/meson.build      |    2 +
 drivers/net/sxe2/sxe2_cmd_chnl.c  |  197 ++++
 drivers/net/sxe2/sxe2_cmd_chnl.h  |   20 +
 drivers/net/sxe2/sxe2_drv_cmd.h   |   61 ++
 drivers/net/sxe2/sxe2_ethdev.c    |   14 +
 drivers/net/sxe2/sxe2_ethdev.h    |    3 +
 drivers/net/sxe2/sxe2_ipsec.c     | 1565 +++++++++++++++++++++++++++++
 drivers/net/sxe2/sxe2_ipsec.h     |  254 +++++
 drivers/net/sxe2/sxe2_rx.c        |    5 +
 drivers/net/sxe2/sxe2_security.c  |  335 ++++++
 drivers/net/sxe2/sxe2_security.h  |   77 ++
 drivers/net/sxe2/sxe2_tx.c        |    8 +
 drivers/net/sxe2/sxe2_txrx_poll.c |   55 +
 13 files changed, 2596 insertions(+)
 create mode 100644 drivers/net/sxe2/sxe2_ipsec.c
 create mode 100644 drivers/net/sxe2/sxe2_ipsec.h
 create mode 100644 drivers/net/sxe2/sxe2_security.c
 create mode 100644 drivers/net/sxe2/sxe2_security.h

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index d0aa7fecf0..e3bcfc2876 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -64,6 +64,8 @@ sources += files(
         'sxe2_filter.c',
         'sxe2_rss.c',
         'sxe2_tm.c',
+        'sxe2_ipsec.c',
+        'sxe2_security.c',
 )
 
 allow_internal_get_api = true
\ No newline at end of file
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 19323ffcc4..7711e8e57d 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -877,3 +877,200 @@ int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter)
 l_end:
        return ret;
 }
+
+
+int32_t sxe2_drv_ipsec_get_capa(struct sxe2_adapter *adapter)
+{
+       int32_t ret = -1;
+       struct sxe2_drv_cmd_params cmd = { 0 };
+       struct sxe2_drv_ipsec_capa_resq resp;
+       struct sxe2_common_device *cdev = adapter->cdev;
+
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_CAP_GET,
+                                NULL, 0,
+                                &resp, sizeof(resp));
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret) {
+               PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get ipsec 
specifications, ret=%d", ret);
+               goto l_end;
+       }
+
+       adapter->security_ctx.ipsec_ctx.max_tx_sa = 
rte_le_to_cpu_16(resp.tx_sa_cnt);
+       adapter->security_ctx.ipsec_ctx.max_rx_sa = 
rte_le_to_cpu_16(resp.rx_sa_cnt);
+       adapter->security_ctx.ipsec_ctx.max_tcam = 
rte_le_to_cpu_16(resp.ip_id_cnt);
+       adapter->security_ctx.ipsec_ctx.max_udp_group = 
rte_le_to_cpu_16(resp.udp_group_cnt);
+
+       PMD_DEV_LOG_INFO(adapter, DRV, "Max tx sa:%u, max rx sa:%u, max 
tcam:%u, udp group:%u.",
+                        rte_le_to_cpu_16(resp.tx_sa_cnt),
+                        rte_le_to_cpu_16(resp.rx_sa_cnt),
+                        rte_le_to_cpu_16(resp.ip_id_cnt),
+                        rte_le_to_cpu_16(resp.udp_group_cnt));
+
+l_end:
+       return ret;
+}
+
+int32_t sxe2_drv_ipsec_resource_clear(struct sxe2_adapter *adapter)
+{
+       int32_t ret = -1;
+       struct sxe2_drv_cmd_params cmd = { 0 };
+       struct sxe2_common_device *cdev = adapter->cdev;
+
+       sxe2_drv_cmd_params_fill(adapter, &cmd, 
SXE2_DRV_CMD_IPSEC_RESOURCE_CLEAR,
+                                NULL, 0,
+                                NULL, 0);
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret) {
+               PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear ipsec resource, 
ret=%d", ret);
+               goto l_end;
+       }
+
+l_end:
+       return ret;
+}
+
+int32_t sxe2_drv_ipsec_txsa_add(struct sxe2_adapter *adapter,
+               struct sxe2_ipsec_tx_sa *tx_sa)
+{
+       struct sxe2_drv_cmd_params cmd               = { 0 };
+       struct sxe2_drv_ipsec_txsa_add_req req   = { 0 };
+       struct sxe2_drv_ipsec_txsa_add_resp resp = { 0 };
+       struct sxe2_common_device *cdev = adapter->cdev;
+       int32_t ret                                   = -1;
+       uint32_t mode                                  = 0;
+       uint32_t i                                     = 0;
+
+       if (tx_sa->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+               mode |= IPSEC_TX_ENGINE_SM4;
+       if (tx_sa->mode == SXE2_IPSEC_MODE_ENC_AND_AUTH)
+               mode |= IPSEC_TX_ENCRYPT;
+       req.mode = rte_cpu_to_le_32(mode);
+       for (i = 0; i < SXE2_IPSEC_KEY_LEN; i++) {
+               req.encrypt_keys[i] = tx_sa->enc_key[i];
+               req.auth_keys[i] = tx_sa->auth_key[i];
+       }
+
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_TXSA_ADD,
+                                &req, sizeof(req),
+                                &resp, sizeof(resp));
+
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret) {
+               PMD_DEV_LOG_ERR(adapter, DRV, "failed to add tx sa, ret=%d", 
ret);
+               goto l_end;
+       }
+       tx_sa->hw_sa_id = rte_le_to_cpu_16(resp.index);
+
+l_end:
+       return ret;
+}
+
+int32_t sxe2_drv_ipsec_rxsa_add(struct sxe2_adapter *adapter,
+               struct sxe2_ipsec_rx_sa *rx_sa,
+               struct sxe2_ipsec_rx_tcam *rx_tcam,
+               struct sxe2_ipsec_rx_udp_group *rx_udp_group)
+{
+       struct sxe2_drv_cmd_params cmd               = { 0 };
+       struct sxe2_drv_ipsec_rxsa_add_req req   = { 0 };
+       struct sxe2_drv_ipsec_rxsa_add_resp resp = { 0 };
+       struct sxe2_common_device *cdev = adapter->cdev;
+       int32_t ret                                   = -1;
+       uint32_t mode                                  = 0;
+       uint32_t i                                     = 0;
+
+       if (rx_sa->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+               mode |= IPSEC_RX_ENGINE_SM4;
+       if (rx_sa->mode == SXE2_IPSEC_MODE_ENC_AND_AUTH)
+               mode |= IPSEC_RX_DECRYPT;
+       if (rx_tcam->ip_addr.type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
+               mode |= IPSEC_RX_IPV6;
+               memcpy(req.ipaddr, rx_tcam->ip_addr.dst_ipv6, 
sizeof(req.ipaddr));
+       } else {
+               req.ipaddr[0] = rx_tcam->ip_addr.dst_ipv4;
+       }
+       req.mode = rte_cpu_to_le_32(mode);
+       req.spi = rte_cpu_to_le_32(rx_sa->spi);
+       if (rx_udp_group != NULL) {
+               req.udp_port = 
rte_cpu_to_le_32((uint32_t)rx_udp_group->udp_port);
+               req.sport_en = rx_udp_group->sport_en;
+               req.dport_en = rx_udp_group->dport_en;
+       }
+
+       PMD_DEV_LOG_INFO(adapter, DRV, "Add rx sa, mode: 0x%x, spi: 0x%x, 
udp_port: %u, "
+                        "sport_en: %u, dport_en: %u.",
+                        req.mode, req.spi, req.udp_port, req.sport_en, 
req.dport_en);
+
+       /* encrypt and auth keys */
+       for (i = 0; i < SXE2_IPSEC_KEY_LEN; i++) {
+               req.encrypt_keys[i] = rx_sa->enc_key[i];
+               req.auth_keys[i] = rx_sa->auth_key[i];
+       }
+
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_RXSA_ADD,
+                                &req, sizeof(req),
+                                &resp, sizeof(resp));
+
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret) {
+               PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add rx sa, ret=%d", 
ret);
+               goto l_end;
+       }
+       rx_sa->hw_sa_id = rte_le_to_cpu_16(resp.sa_idx);
+       rx_sa->hw_ip_id = resp.ip_id;
+       rx_tcam->hw_ip_id = resp.ip_id;
+       rx_sa->hw_udp_group_id = resp.udp_group_id;
+       if (rx_udp_group != NULL)
+               rx_udp_group->hw_group_id = resp.udp_group_id;
+
+l_end:
+       return ret;
+}
+
+int32_t sxe2_drv_ipsec_rxsa_delete(struct sxe2_adapter *adapter,
+                                       struct sxe2_ipsec_rx_sa *rx_sa)
+{
+       struct sxe2_drv_ipsec_rxsa_del_req req = { 0 };
+       struct sxe2_drv_cmd_params cmd             = { 0 };
+       struct sxe2_common_device *cdev = adapter->cdev;
+       int32_t ret                                 = -1;
+
+       req.sa_idx = rte_cpu_to_le_16(rx_sa->hw_sa_id);
+       req.spi = rte_cpu_to_le_32(rx_sa->spi);
+       req.ip_id = rx_sa->hw_ip_id;
+       req.group_id = rx_sa->hw_udp_group_id;
+
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_RXSA_DEL,
+                                &req, sizeof(req),
+                                NULL, 0);
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret)
+               PMD_DEV_LOG_ERR(adapter, DRV,
+                               "Failed to delete rx sa, sa id: %u, spi: %u, "
+                               "ip id: %u, udp group id: %u, ret: %d.",
+                               rx_sa->hw_sa_id, rx_sa->spi, rx_sa->hw_ip_id,
+                               rx_sa->hw_udp_group_id, ret);
+
+       return ret;
+}
+
+int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
+                                          uint16_t sa_id)
+{
+       struct sxe2_drv_ipsec_txsa_del_req req = { 0 };
+       struct sxe2_drv_cmd_params cmd             = { 0 };
+       struct sxe2_common_device *cdev = adapter->cdev;
+       int32_t ret                                 = -1;
+
+       req.sa_idx = rte_cpu_to_le_16(sa_id);
+       sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_TXSA_DEL,
+                                &req, sizeof(req),
+                                NULL, 0);
+       ret = sxe2_drv_cmd_exec(cdev, &cmd);
+       if (ret)
+               PMD_DEV_LOG_ERR(adapter, DRV,
+                               "Failed to delete tx sa, sa id: %u, ret: %d.",
+                               sa_id, ret);
+
+       return ret;
+}
+
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 6e209377c7..d8e09a4453 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -44,6 +44,26 @@ int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev);
 
 int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter);
 
+int32_t sxe2_drv_ipsec_resource_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_ipsec_get_capa(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_ipsec_rxsa_add(struct sxe2_adapter *adapter,
+                           struct sxe2_ipsec_rx_sa *rx_sa,
+                           struct sxe2_ipsec_rx_tcam *rx_tcam,
+                           struct sxe2_ipsec_rx_udp_group *rx_udp_group);
+
+int32_t sxe2_drv_ipsec_txsa_add(struct sxe2_adapter *adapter,
+                           struct sxe2_ipsec_tx_sa *tx_sa);
+
+int32_t sxe2_drv_ipsec_rxsa_delete(struct sxe2_adapter *adapter,
+                              struct sxe2_ipsec_rx_sa *rx_sa);
+
+int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
+                              uint16_t sa_id);
+
+int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+
 int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
 
 int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr 
*addr, bool add);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 07f083644c..4d9c2e05a8 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -373,6 +373,67 @@ struct sxe2_tm_add_queue_msg {
        struct sxe2_tm_info info;
 };
 
+struct sxe2_drv_ipsec_capa_resq {
+       __le16 tx_sa_cnt;
+       __le16 rx_sa_cnt;
+       __le16 ip_id_cnt;
+       __le16 udp_group_cnt;
+};
+
+#define SXE2_IPSEC_KEY_LEN (32)
+#define SXE2_IPV6_ADDR_LEN (4)
+struct sxe2_drv_ipsec_txsa_add_req {
+       __le32 mode;
+       uint8_t encrypt_keys[SXE2_IPSEC_KEY_LEN];
+       uint8_t auth_keys[SXE2_IPSEC_KEY_LEN];
+       bool func_type;
+       uint8_t func_id;
+       uint8_t drv_id;
+};
+
+struct sxe2_drv_ipsec_txsa_add_resp {
+       __le16 index;
+};
+
+struct sxe2_drv_ipsec_rxsa_add_req {
+       __le32 mode;
+       __le32 spi;
+       __le32 ipaddr[SXE2_IPV6_ADDR_LEN];
+       __le32 udp_port;
+       uint8_t sport_en;
+       uint8_t dport_en;
+       uint8_t is_over_sdn;
+       uint8_t sdn_group_id;
+       uint8_t encrypt_keys[SXE2_IPSEC_KEY_LEN];
+       uint8_t auth_keys[SXE2_IPSEC_KEY_LEN];
+       bool func_type;
+       uint8_t func_id;
+       uint8_t drv_id;
+};
+
+struct sxe2_drv_ipsec_rxsa_add_resp {
+       uint8_t ip_id;
+       uint8_t udp_group_id;
+       __le16 sa_idx;
+};
+
+struct sxe2_drv_ipsec_txsa_del_req {
+       __le16 sa_idx;
+       bool func_type;
+       uint8_t func_id;
+       uint8_t drv_id;
+};
+
+struct sxe2_drv_ipsec_rxsa_del_req {
+       uint8_t ip_id;
+       uint8_t group_id;
+       __le16 sa_idx;
+       __le32 spi;
+       bool func_type;
+       uint8_t func_id;
+       uint8_t drv_id;
+};
+
 enum sxe2_drv_cmd_module {
        SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
        SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index a095888c00..00c0552d4a 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -298,6 +298,11 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
        if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_PTP)
                dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
 
+       if (sxe2_ipsec_supported(adapter)) {
+               dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SECURITY;
+               dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_SECURITY;
+       }
+
        if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) {
                dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
                dev_info->flow_type_rss_offloads  |= SXE2_RSS_HF_SUPPORT_ALL;
@@ -1053,6 +1058,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
                goto init_eth_err;
        }
 
+       ret = sxe2_security_init(dev);
+       if (ret) {
+               PMD_LOG_ERR(INIT, "Failed to initialize security, ret=%d", ret);
+               goto init_security_err;
+       }
+
        ret = sxe2_rss_disable(dev);
        if (ret) {
                PMD_LOG_ERR(INIT, "Failed to disable rss, ret=%d", ret);
@@ -1067,6 +1078,8 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 
        goto l_end;
 
+init_security_err:
+       sxe2_eth_uinit(dev);
 init_sched_err:
 init_rss_err:
 init_eth_err:
@@ -1085,6 +1098,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
        (void)sxe2_rss_disable(dev);
        (void)sxe2_sched_uinit(dev);
        sxe2_vsi_uninit(dev);
+       sxe2_security_uinit(dev);
        sxe2_dev_pci_map_uinit(dev);
        sxe2_eth_uinit(dev);
 
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 609e1e92ba..32a67ed344 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -19,6 +19,8 @@
 #include "sxe2_queue.h"
 #include "sxe2_mac.h"
 #include "sxe2_osal.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
 #include "sxe2_tm.h"
 #include "sxe2_filter.h"
 
@@ -312,6 +314,7 @@ struct sxe2_adapter {
        struct sxe2_sched_hw_cap      sched_ctxt;
        struct sxe2_tm_context        tm_ctxt;
        struct sxe2_devargs           devargs;
+       struct sxe2_security_ctx      security_ctx;
        struct sxe2_switchdev_info    switchdev_info;
        bool                          rule_started;
        bool                          flow_isolated;
diff --git a/drivers/net/sxe2/sxe2_ipsec.c b/drivers/net/sxe2/sxe2_ipsec.c
new file mode 100644
index 0000000000..9fd29bd6e5
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ipsec.c
@@ -0,0 +1,1565 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_malloc.h>
+#include <rte_bitmap.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_common_log.h"
+
+bool sxe2_ipsec_supported(struct sxe2_adapter *adapter)
+{
+       uint64_t cap = adapter->cap_flags;
+
+       return !!(cap & SXE2_DEV_CAPS_OFFLOAD_IPSEC);
+}
+
+bool sxe2_ipsec_valid_tx_offloads(uint64_t offloads)
+{
+       bool ret = true;
+       uint64_t tso_features = 0;
+       uint64_t cksum_features = 0;
+
+       if (offloads & RTE_ETH_TX_OFFLOAD_SECURITY) {
+               tso_features = RTE_ETH_TX_OFFLOAD_TCP_TSO |
+                       RTE_ETH_TX_OFFLOAD_UDP_TSO |
+                       RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
+                       RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
+                       RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO |
+                       RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
+               if (offloads & tso_features) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with TSO offload.");
+                       ret = false;
+                       goto l_end;
+               }
+
+               cksum_features = RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+                       RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+                       RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+                       RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+                       RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+                       RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+               if (offloads & cksum_features) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with checksum offload.");
+                       ret = false;
+                       goto l_end;
+               }
+
+               if (offloads & (RTE_ETH_TX_OFFLOAD_VLAN_INSERT | 
RTE_ETH_TX_OFFLOAD_QINQ_INSERT)) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with vlan offload.");
+                       ret = false;
+                       goto l_end;
+               }
+       }
+
+l_end:
+       return ret;
+}
+
+bool sxe2_ipsec_valid_rx_offloads(uint64_t offloads)
+{
+       bool ret = true;
+
+       if (offloads & RTE_ETH_RX_OFFLOAD_SECURITY) {
+               if (offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with LRO offload.");
+                       ret = false;
+                       goto l_end;
+               }
+
+               if (offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with checksum offload.");
+                       ret = false;
+                       goto l_end;
+               }
+
+               if (offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with keep CRC offload.");
+                       ret = false;
+                       goto l_end;
+               }
+
+               if (offloads & RTE_ETH_RX_OFFLOAD_VLAN) {
+                       PMD_LOG_ERR(DRV, "Security offload is not compatible 
with vlan offload.");
+                       ret = false;
+                       goto l_end;
+               }
+       }
+
+l_end:
+       return ret;
+}
+
+static int32_t sxe2_ipsec_bitmap_mem_init(struct rte_bitmap **d_bmp, void 
**d_mem, uint32_t bits)
+{
+       struct rte_bitmap *bmp = NULL;
+       uint32_t bmp_size           = 0;
+       void *mem              = NULL;
+       int32_t ret                = -1;
+
+       bmp_size = rte_bitmap_get_memory_footprint(bits);
+
+       mem = rte_zmalloc("ipsec bitmap", bmp_size, RTE_CACHE_LINE_SIZE);
+       if (mem == NULL) {
+               PMD_LOG_ERR(DRV, "Alloc ipsec bitmap memory failed.");
+               ret = -ENOMEM;
+               goto l_end;
+       }
+
+       bmp = rte_bitmap_init(bits, mem, bmp_size);
+       if (bmp == NULL) {
+               PMD_LOG_ERR(DRV, "Failed to init ipsec bitmap.");
+               rte_free(mem);
+               ret = -ENOMEM;
+               goto l_end;
+       }
+
+       *d_bmp = bmp;
+       *d_mem = mem;
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t sxe2_ipsec_bitmap_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+       int32_t ret  = -1;
+
+       ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp,
+                       &sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem, 
sxe2_sctx->ipsec_ctx.max_tx_sa);
+       if (ret)
+               goto l_end;
+
+       ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp,
+                       &sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem, 
sxe2_sctx->ipsec_ctx.max_rx_sa);
+       if (ret) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp,
+                       &sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem, 
sxe2_sctx->ipsec_ctx.max_tcam);
+       if (ret) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+               sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp,
+                       &sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem, 
sxe2_sctx->ipsec_ctx.max_udp_group);
+       if (ret) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+               sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+               sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+               sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+               goto l_end;
+       }
+
+l_end:
+       return ret;
+}
+
+static uint16_t sxe2_ipsec_id_alloc(struct rte_bitmap *bmp, uint16_t bits)
+{
+       uint16_t i = 0;
+       uint16_t index = 0XFFFF;
+
+       for (i = 0; i < bits; i++) {
+               if (!rte_bitmap_get(bmp, i)) {
+                       index = i;
+                       rte_bitmap_set(bmp, i);
+                       break;
+               }
+       }
+
+       return index;
+}
+
+static void sxe2_ipsec_id_free(struct rte_bitmap *bmp, uint16_t pos)
+{
+       rte_bitmap_clear(bmp, pos);
+}
+
+static struct rte_cryptodev_symmetric_capability *
+sxe2_ipsec_cipher_cap_get(struct rte_cryptodev_capabilities *crypto_cap,
+                       enum rte_crypto_cipher_algorithm algo)
+{
+       struct rte_cryptodev_symmetric_capability *capability = NULL;
+       uint8_t index                                              = 0;
+
+       for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+               if (crypto_cap[index].sym.xform_type == 
RTE_CRYPTO_SYM_XFORM_CIPHER &&
+                       crypto_cap[index].sym.cipher.algo == algo) {
+                       capability = &crypto_cap[index].sym;
+                       goto l_end;
+               }
+       }
+
+l_end:
+       return capability;
+}
+
+static struct rte_cryptodev_symmetric_capability *
+sxe2_ipsec_auth_cap_get(struct rte_cryptodev_capabilities *crypto_cap,
+                       enum rte_crypto_auth_algorithm algo)
+{
+       struct rte_cryptodev_symmetric_capability *capability = NULL;
+       uint8_t index                                              = 0;
+
+       for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+               if (crypto_cap[index].sym.xform_type == 
RTE_CRYPTO_SYM_XFORM_AUTH &&
+                       crypto_cap[index].sym.auth.algo == algo) {
+                       capability = &crypto_cap[index].sym;
+                       goto l_end;
+               }
+       }
+
+l_end:
+       return capability;
+}
+
+static bool sxe2_security_valid_key(uint16_t src_key, uint16_t max_key,
+                                   uint16_t min_key, uint16_t increment)
+{
+       bool is_valid = false;
+
+       if (src_key < min_key || src_key > max_key) {
+               is_valid = false;
+               goto l_end;
+       }
+
+       if (increment == 0) {
+               is_valid = true;
+               goto l_end;
+       }
+
+       if ((uint16_t)(src_key - min_key) % increment) {
+               is_valid = false;
+               goto l_end;
+       }
+
+       if (src_key > SXE2_IPSEC_MAX_KEY_LEN) {
+               is_valid = false;
+               goto l_end;
+       }
+
+       is_valid = true;
+
+l_end:
+       return is_valid;
+}
+
+static int32_t
+sxe2_ipsec_valid_cipher(enum rte_crypto_cipher_operation cipher_op,
+                       struct rte_cryptodev_capabilities *crypto_cap,
+                       struct rte_crypto_sym_xform *xform)
+{
+       const struct rte_cryptodev_symmetric_capability *capability = NULL;
+       uint16_t src_key                                = 0;
+       uint16_t max_key                                = 0;
+       uint16_t min_key                                = 0;
+       uint16_t increment                              = 0;
+       int32_t ret                                    = -1;
+
+       if (xform->cipher.op != cipher_op) {
+               PMD_LOG_ERR(DRV, "Invalid cipher direction specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       capability = sxe2_ipsec_cipher_cap_get(crypto_cap, xform->cipher.algo);
+       if (!capability) {
+               PMD_LOG_ERR(DRV, "Invalid cipher algo specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       src_key = xform->cipher.key.length;
+       min_key = capability->cipher.key_size.min;
+       max_key = capability->cipher.key_size.max;
+       increment = capability->cipher.key_size.increment;
+       if (!sxe2_security_valid_key(src_key, max_key, min_key, increment)) {
+               PMD_LOG_ERR(DRV, "Invalid cipher key size specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_valid_auth(enum rte_crypto_auth_operation auth_op,
+                     struct rte_cryptodev_capabilities *crypto_cap,
+                     struct rte_crypto_sym_xform *xform)
+{
+       const struct rte_cryptodev_symmetric_capability *capability = NULL;
+       uint16_t src_key                                = 0;
+       uint16_t max_key                                = 0;
+       uint16_t min_key                                = 0;
+       uint16_t increment                              = 0;
+       int32_t ret                                    = -1;
+
+       if (xform->auth.op != auth_op) {
+               PMD_LOG_ERR(DRV, "Invalid auth direction specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       capability = sxe2_ipsec_auth_cap_get(crypto_cap, xform->auth.algo);
+       if (!capability) {
+               PMD_LOG_ERR(DRV, "Invalid auth algo specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       src_key = xform->auth.key.length;
+       min_key = capability->auth.key_size.min;
+       max_key = capability->auth.key_size.max;
+       increment = capability->auth.key_size.increment;
+       if (!sxe2_security_valid_key(src_key, max_key, min_key, increment)) {
+               PMD_LOG_ERR(DRV, "Invalid auth key size specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static bool
+sxe2_ipsec_valid_algo(enum rte_crypto_auth_algorithm auth_algo,
+                     enum rte_crypto_cipher_algorithm cipher_algo)
+{
+       bool ret = false;
+
+       if ((cipher_algo == SXE2_RTE_CRYPTO_CIPHER_AES_CBC &&
+                auth_algo == SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC) ||
+               (cipher_algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC &&
+                auth_algo == SXE2_RTE_CRYPTO_AUTH_SM3_HMAC)) {
+               ret = true;
+               goto l_end;
+       }
+
+l_end:
+       return ret;
+}
+
+static enum sxe2_ipsec_algorithm
+sxe2_ipsec_algo_gen(enum rte_crypto_cipher_algorithm cipher_algo)
+{
+       enum sxe2_ipsec_algorithm algo = SXE2_IPSEC_ALGO_INVALID;
+
+       if (cipher_algo == SXE2_RTE_CRYPTO_CIPHER_AES_CBC)
+               algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+       else if (cipher_algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+               algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+
+       return algo;
+}
+
+static int32_t
+       sxe2_ipsec_valid_xform(struct sxe2_security_ctx *sxe2_sctx,
+                              struct rte_security_session_conf *conf)
+{
+       struct rte_crypto_sym_xform *xform = NULL;
+       struct rte_cryptodev_capabilities *crypto_cap =
+               
sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].crypto_capabilities;
+       enum rte_crypto_auth_algorithm auth_algo = RTE_CRYPTO_AUTH_NULL;
+       enum rte_crypto_cipher_algorithm cipher_algo = RTE_CRYPTO_CIPHER_NULL;
+       int32_t ret = -1;
+
+       if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
+               conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+               xform = conf->crypto_xform;
+               cipher_algo = xform->cipher.algo;
+               ret = sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+                                             crypto_cap, xform);
+               if (ret)
+                       goto l_end;
+
+               if (conf->crypto_xform->next) {
+                       if (conf->crypto_xform->next->type == 
RTE_CRYPTO_SYM_XFORM_AUTH) {
+                               auth_algo = conf->crypto_xform->next->auth.algo;
+                               if (!sxe2_ipsec_valid_algo(auth_algo, 
cipher_algo)) {
+                                       PMD_LOG_ERR(DRV, "Invalid algo group.");
+                                       ret = -EINVAL;
+                                       goto l_end;
+                               }
+                               xform = conf->crypto_xform->next;
+                               ret = 
sxe2_ipsec_valid_auth(RTE_CRYPTO_AUTH_OP_GENERATE,
+                                                                       
crypto_cap, xform);
+                               if (ret)
+                                       goto l_end;
+                       } else {
+                               PMD_LOG_ERR(DRV, "Encrypt direction next xform 
only verify.");
+                               ret = -EINVAL;
+                               goto l_end;
+                       }
+               }
+       } else if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+               conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+               xform = conf->crypto_xform;
+               ret = sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_DECRYPT,
+                                                                               
crypto_cap, xform);
+               if (ret)
+                       goto l_end;
+
+       } else if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+               conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+               xform = conf->crypto_xform;
+               ret = sxe2_ipsec_valid_auth(RTE_CRYPTO_AUTH_OP_VERIFY, 
crypto_cap, xform);
+               if (ret)
+                       goto l_end;
+
+               if (conf->crypto_xform->next &&
+                       conf->crypto_xform->next->type == 
RTE_CRYPTO_SYM_XFORM_CIPHER) {
+                       auth_algo = conf->crypto_xform->auth.algo;
+                       cipher_algo = conf->crypto_xform->next->cipher.algo;
+                       if (!sxe2_ipsec_valid_algo(auth_algo, cipher_algo)) {
+                               PMD_LOG_ERR(DRV, "Invalid algo group.");
+                               ret = -EINVAL;
+                               goto l_end;
+                       }
+                       xform = conf->crypto_xform->next;
+                       ret = 
sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_DECRYPT,
+                                                                               
crypto_cap, xform);
+                       if (ret)
+                               goto l_end;
+               } else {
+                       PMD_LOG_ERR(DRV, "Not support decrypt direction only 
verify, but not decrypt.");
+                       ret = -EINVAL;
+                       goto l_end;
+               }
+       } else {
+               PMD_LOG_ERR(DRV, "Encrypt/decrypt xform invalid.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_valid_udp(struct rte_security_session_conf *conf)
+{
+       int32_t ret = -1;
+       uint16_t sport = conf->ipsec.udp.sport;
+       uint16_t dport = conf->ipsec.udp.dport;
+
+       if (conf->ipsec.options.udp_encap == 0) {
+               ret = 0;
+               goto l_end;
+       }
+
+       if (sport == 0 && dport == 0) {
+               PMD_LOG_ERR(DRV, "Invalid udp port, cannot be zero.");
+               ret = -1;
+               goto l_end;
+       }
+
+       if (sport != 0 && dport != 0 && sport != dport) {
+               PMD_LOG_ERR(DRV, "Invalid udp port, if sport and dport is not 
zero, must be equal.");
+               ret = -1;
+               goto l_end;
+       }
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_session_conf_valid(struct sxe2_security_ctx *sxe2_sctx,
+                             struct rte_security_session_conf *conf)
+{
+       int32_t ret = -1;
+
+       if (sxe2_sctx == NULL) {
+               PMD_LOG_ERR(DRV, "Invalid  security ctx.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->action_type !=
+               
sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].action) {
+               PMD_LOG_ERR(DRV, "Invalid action specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->ipsec.mode !=
+               
sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].ipsec.mode) {
+               PMD_LOG_ERR(DRV, "Invalid IPsec mode specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->ipsec.proto !=
+           
sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].ipsec.proto) {
+               PMD_LOG_ERR(DRV, "Invalid IPsec protocol specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->ipsec.options.esn) {
+               PMD_LOG_ERR(DRV, "Not support esn.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+               conf->ipsec.spi == 0) {
+               PMD_LOG_ERR(DRV, "spi cannot be zero.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       if (conf->crypto_xform == NULL) {
+               PMD_LOG_ERR(DRV, "Invalid ipsec xform specified");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_valid_udp(conf);
+       if (ret)
+               goto l_end;
+
+       ret = sxe2_ipsec_valid_xform(sxe2_sctx, conf);
+       if (ret)
+               goto l_end;
+
+l_end:
+       return ret;
+}
+
+static void
+sxe2_ipsec_session_save(struct sxe2_security_ctx *sxe2_sctx,
+                       struct rte_security_session_conf *conf,
+                       struct sxe2_security_session *sxe2_sess, uint16_t 
sa_id, uint16_t index)
+{
+       enum rte_crypto_cipher_algorithm cipher_algo   = RTE_CRYPTO_CIPHER_NULL;
+
+       sxe2_sess->adapter = sxe2_sctx->adapter;
+       sxe2_sess->direction = conf->ipsec.direction;
+       sxe2_sess->protocol = conf->protocol;
+       sxe2_sess->mode = conf->ipsec.mode;
+       sxe2_sess->sa_proto = conf->ipsec.proto;
+       sxe2_sess->sa.spi = conf->ipsec.spi;
+       sxe2_sess->sa.hw_idx = sa_id;
+       sxe2_sess->sa.sw_idx = index;
+
+       if (conf->ipsec.options.esn) {
+               sxe2_sess->esn.enabled = true;
+               sxe2_sess->esn.value = conf->ipsec.esn.value;
+       }
+
+       if (sxe2_sess->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
+               sxe2_sess->type = conf->ipsec.tunnel.type;
+
+       if (conf->ipsec.options.udp_encap) {
+               sxe2_sess->udp_cap.enabled = true;
+               memcpy(&sxe2_sess->udp_cap.value, &conf->ipsec.udp,
+                       sizeof(struct rte_security_ipsec_udp_param));
+       }
+
+       sxe2_sess->pkt_metadata_template.sa_idx = sa_id;
+       sxe2_sess->pkt_metadata_template.ol_flags |= SXE2_IPSEC_OL_FLAGS_IS_TUN;
+       sxe2_sess->pkt_metadata_template.ol_flags |= SXE2_IPSEC_OL_FLAGS_IS_ESP;
+
+       if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
+               conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+               cipher_algo = conf->crypto_xform->cipher.algo;
+               sxe2_sess->pkt_metadata_template.algo = 
sxe2_ipsec_algo_gen(cipher_algo);
+               if (conf->crypto_xform->next)
+                       sxe2_sess->pkt_metadata_template.mode = 
SXE2_IPSEC_MODE_ENC_AND_AUTH;
+               else
+                       sxe2_sess->pkt_metadata_template.mode = 
SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+       }
+
+       PMD_LOG_INFO(DRV,
+               "Save security info to session ctx, said:%u, spi:%u, mode:%u, 
algo:%u",
+               sa_id, sxe2_sess->sa.spi,
+               sxe2_sess->pkt_metadata_template.mode,
+               sxe2_sess->pkt_metadata_template.algo);
+}
+
+static void
+sxe2_ipsec_tx_sa_fill(struct sxe2_ipsec_tx_sa *tx_sa,
+                     struct rte_security_session_conf *conf)
+{
+       uint8_t *dst = NULL;
+       uint8_t len  = 0;
+
+       memcpy(&tx_sa->xform, &conf->ipsec, sizeof(struct 
rte_security_ipsec_xform));
+
+       if (conf->crypto_xform->next)
+               tx_sa->mode = SXE2_IPSEC_MODE_ENC_AND_AUTH;
+       else
+               tx_sa->mode = SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+
+       if (conf->crypto_xform->cipher.algo == 
SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+               tx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+       else
+               tx_sa->algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+
+       dst = tx_sa->enc_key;
+       len = conf->crypto_xform->cipher.key.length;
+       memcpy(dst, conf->crypto_xform->cipher.key.data, len);
+
+       if (conf->crypto_xform->next) {
+               dst = tx_sa->auth_key;
+               len = conf->crypto_xform->next->auth.key.length;
+               memcpy(dst, conf->crypto_xform->next->auth.key.data, len);
+       }
+}
+
+static int32_t
+sxe2_ipsec_tx_sa_add(struct sxe2_security_ctx *sxe2_sctx,
+                    struct rte_security_session_conf *conf,
+                    struct sxe2_security_session *sxe2_sess)
+{
+       struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+       struct rte_bitmap *bmp          = sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp;
+       uint16_t bits                        = sxe2_sctx->ipsec_ctx.max_tx_sa;
+       uint16_t index                       = 0xFFFF;
+       int32_t ret                         = -1;
+
+       rte_spinlock_lock(&sxe2_sctx->security_lock);
+       index = sxe2_ipsec_id_alloc(bmp, bits);
+       rte_spinlock_unlock(&sxe2_sctx->security_lock);
+       if (index == 0xFFFF) {
+               PMD_LOG_ERR(DRV, "Failed to allocate ipsec tx sa index.");
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       tx_sa = &sxe2_sctx->ipsec_ctx.tx_sa[index];
+
+       sxe2_ipsec_tx_sa_fill(tx_sa, conf);
+
+       ret = sxe2_drv_ipsec_txsa_add(sxe2_sctx->adapter, tx_sa);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Failed to add tx sa.");
+               ret = -EIO;
+               rte_spinlock_lock(&sxe2_sctx->security_lock);
+               sxe2_ipsec_id_free(bmp, index);
+               rte_spinlock_unlock(&sxe2_sctx->security_lock);
+               goto l_end;
+       }
+
+       sxe2_ipsec_session_save(sxe2_sctx, conf, sxe2_sess, tx_sa->hw_sa_id, 
tx_sa->id);
+
+       PMD_LOG_INFO(DRV, "Add tx sa success, tx sa id: %u, index: %u.",
+               tx_sa->hw_sa_id, tx_sa->id);
+
+l_end:
+       return ret;
+}
+
+static uint16_t
+sxe2_ipsec_tcam_id_find(struct sxe2_ipsec_rx_tcam *rx_tcam,
+                       struct rte_security_ipsec_tunnel_param tunnel, uint16_t 
len)
+{
+       struct sxe2_ipsec_rx_tcam *per = NULL;
+       uint16_t tcam_id = 0XFFFF;
+       uint16_t i       = 0;
+
+       for (i = 0; i < len; i++) {
+               per = &rx_tcam[i];
+               if (per->ip_addr.type == tunnel.type) {
+                       if (tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4 &&
+                       per->ip_addr.dst_ipv4 == 
(uint32_t)tunnel.ipv4.dst_ip.s_addr) {
+                               tcam_id = i;
+                               goto l_end;
+                       }
+                       if (tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
+                               if (!memcmp(&tunnel.ipv6, 
&per->ip_addr.dst_ipv6,
+                               sizeof(tunnel.ipv6))) {
+                                       tcam_id = i;
+                                       goto l_end;
+                               }
+                       }
+               }
+       }
+
+l_end:
+       return tcam_id;
+}
+
+static uint16_t
+sxe2_ipsec_group_id_find(struct sxe2_ipsec_rx_udp_group *rx_udp_group,
+                        uint16_t udp_port, uint8_t sport_en, uint8_t dport_en, 
uint16_t len)
+{
+       struct sxe2_ipsec_rx_udp_group *per = NULL;
+       uint16_t group_id = 0XFFFF;
+       uint16_t i;
+
+       for (i = 0; i < len; i++) {
+               per = &rx_udp_group[i];
+               if (per->udp_port == udp_port && per->sport_en == sport_en &&
+                       per->dport_en == dport_en) {
+                       group_id = i;
+                       goto l_end;
+               }
+       }
+
+l_end:
+       return group_id;
+}
+
+static void
+sxe2_ipsec_rx_sa_fill(struct sxe2_ipsec_rx_sa *rx_sa,
+                     struct rte_security_session_conf *conf)
+{
+       uint8_t *dst = NULL;
+       uint8_t len = 0;
+
+       memcpy(&rx_sa->xform, &conf->ipsec, sizeof(struct 
rte_security_ipsec_xform));
+
+       if (conf->crypto_xform->next)
+               rx_sa->mode = SXE2_IPSEC_MODE_ENC_AND_AUTH;
+       else
+               rx_sa->mode = SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+
+       if (conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+               if (conf->crypto_xform->cipher.algo == 
SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+                       rx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+               else
+                       rx_sa->algo = 
SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+       } else {
+               if (conf->crypto_xform->auth.algo == 
SXE2_RTE_CRYPTO_AUTH_SM3_HMAC)
+                       rx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+               else
+                       rx_sa->algo = 
SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+       }
+
+       if (conf->crypto_xform->next) {
+               dst = rx_sa->auth_key;
+               len = conf->crypto_xform->auth.key.length;
+               memcpy(dst, conf->crypto_xform->auth.key.data, len);
+
+               dst = rx_sa->enc_key;
+               len = conf->crypto_xform->next->cipher.key.length;
+               memcpy(dst, conf->crypto_xform->next->cipher.key.data, len);
+       } else {
+               dst = rx_sa->enc_key;
+               len = conf->crypto_xform->cipher.key.length;
+               memcpy(dst, conf->crypto_xform->cipher.key.data, len);
+       }
+
+       rx_sa->spi = conf->ipsec.spi;
+}
+
+static int32_t
+sxe2_ipsec_rx_tcam_fill(struct sxe2_security_ctx *sxe2_sctx, uint16_t *tcam_id,
+                       struct rte_security_session_conf *conf)
+{
+       int32_t ret = -1;
+       uint16_t len = sxe2_sctx->ipsec_ctx.max_tcam;
+       struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+
+       *tcam_id = sxe2_ipsec_tcam_id_find(sxe2_sctx->ipsec_ctx.rx_tcam,
+                       conf->ipsec.tunnel, len);
+       if (*tcam_id == 0XFFFF) {
+               *tcam_id = 
sxe2_ipsec_id_alloc(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp, len);
+               if (*tcam_id == 0xFFFF) {
+                       ret = -ENOMEM;
+                       goto l_end;
+               }
+               rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[*tcam_id];
+
+               rx_tcam->ip_addr.type = conf->ipsec.tunnel.type;
+               if (rx_tcam->ip_addr.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
+                       rx_tcam->ip_addr.dst_ipv4 = 
(uint32_t)conf->ipsec.tunnel.ipv4.dst_ip.s_addr;
+               } else {
+                       memcpy(&rx_tcam->ip_addr.dst_ipv6, 
&conf->ipsec.tunnel.ipv6.dst_addr,
+                               sizeof(rx_tcam->ip_addr.dst_ipv6));
+               }
+       } else {
+               rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[*tcam_id];
+       }
+       rx_tcam->ref_cnt++;
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_udp_group_fill(struct sxe2_security_ctx *sxe2_sctx, uint16_t 
*udp_group_id,
+                            struct rte_security_session_conf *conf)
+{
+       int32_t ret = -1;
+       uint16_t len = sxe2_sctx->ipsec_ctx.max_udp_group;
+       struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+       uint8_t sport_en = 0;
+       uint8_t dport_en = 0;
+       uint16_t udp_port = 0;
+
+       if (!conf->ipsec.options.udp_encap) {
+               ret = 0;
+               goto l_end;
+       }
+
+       if (conf->ipsec.udp.sport) {
+               sport_en = 1;
+               udp_port = conf->ipsec.udp.sport;
+       } else {
+               sport_en = 0;
+       }
+       if (conf->ipsec.udp.dport) {
+               dport_en = 1;
+               udp_port = conf->ipsec.udp.dport;
+       } else {
+               dport_en = 0;
+       }
+
+       *udp_group_id = 
sxe2_ipsec_group_id_find(sxe2_sctx->ipsec_ctx.rx_udp_group,
+                       udp_port, sport_en, dport_en, len);
+       if (*udp_group_id == 0XFFFF) {
+               *udp_group_id = 
sxe2_ipsec_id_alloc(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp, len);
+               if (*udp_group_id == 0xFFFF) {
+                       ret = -ENOMEM;
+                       goto l_end;
+               }
+               rx_udp_group = 
&sxe2_sctx->ipsec_ctx.rx_udp_group[*udp_group_id];
+               rx_udp_group->sport_en = sport_en;
+               rx_udp_group->dport_en = dport_en;
+               rx_udp_group->udp_port = udp_port;
+       } else {
+               rx_udp_group = 
&sxe2_sctx->ipsec_ctx.rx_udp_group[*udp_group_id];
+       }
+       rx_udp_group->ref_cnt++;
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_sa_add(struct sxe2_security_ctx *sxe2_sctx,
+                    struct rte_security_session_conf *conf,
+                    struct sxe2_security_session *sxe2_sess)
+{
+       struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+       struct sxe2_ipsec_rx_sa *rx_sa     = NULL;
+       struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+       struct rte_bitmap *rx_sa_bmp        = 
sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp;
+       struct rte_bitmap *rx_tcam_bmp      = 
sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp;
+       uint16_t sa_bits                         = 
sxe2_sctx->ipsec_ctx.max_rx_sa;
+       uint16_t sa_id                           = 0xFFFF;
+       uint16_t tcam_id                         = 0xFFFF;
+       uint16_t udp_group_id                    = 0xFFFF;
+       int32_t ret                             = -1;
+
+       rte_spinlock_lock(&sxe2_sctx->security_lock);
+       sa_id = sxe2_ipsec_id_alloc(rx_sa_bmp, sa_bits);
+       if (sa_id == 0xFFFF) {
+               PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx sa index.");
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       rx_sa = &sxe2_sctx->ipsec_ctx.rx_sa[sa_id];
+       sxe2_ipsec_rx_sa_fill(rx_sa, conf);
+
+       ret = sxe2_ipsec_rx_tcam_fill(sxe2_sctx, &tcam_id, conf);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx tcam index.");
+               sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+               goto l_end;
+       }
+       rx_sa->tcam_id = tcam_id;
+       rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[tcam_id];
+
+       ret = sxe2_ipsec_rx_udp_group_fill(sxe2_sctx, &udp_group_id, conf);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx udp group 
index.");
+               sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+               sxe2_ipsec_id_free(rx_tcam_bmp, tcam_id);
+               goto l_end;
+       }
+
+       if (udp_group_id != 0XFFFF) {
+               rx_sa->udp_group_id = (uint8_t)udp_group_id;
+               rx_udp_group = &sxe2_sctx->ipsec_ctx.rx_udp_group[udp_group_id];
+       } else {
+               rx_sa->udp_group_id = 0XFF;
+       }
+
+       ret = sxe2_drv_ipsec_rxsa_add(sxe2_sctx->adapter, rx_sa, rx_tcam, 
rx_udp_group);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Failed to add rx sa.");
+               sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+               rx_tcam->ref_cnt--;
+               if (rx_tcam->ref_cnt == 0)
+                       sxe2_ipsec_id_free(rx_tcam_bmp, tcam_id);
+
+               if (rx_udp_group != NULL) {
+                       rx_udp_group->ref_cnt--;
+                       if (rx_udp_group->ref_cnt == 0)
+                               
sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp,
+                                                  udp_group_id);
+               }
+
+               ret = -EIO;
+               goto l_end;
+       }
+
+       sxe2_ipsec_session_save(sxe2_sctx, conf, sxe2_sess, rx_sa->hw_sa_id, 
rx_sa->id);
+
+       PMD_LOG_INFO(DRV, "Add rx sa success, rx sa id: %u, rx ip id: %u, group 
id: %u, index: %u.",
+                               rx_sa->hw_sa_id, rx_sa->hw_ip_id, 
rx_sa->udp_group_id, rx_sa->id);
+
+l_end:
+       rte_spinlock_unlock(&sxe2_sctx->security_lock);
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_hw_table_add(struct sxe2_security_ctx *sxe2_sctx,
+                       struct rte_security_session_conf *conf,
+                       struct sxe2_security_session *sxe2_sess)
+{
+       int32_t ret = -1;
+
+       switch (conf->ipsec.direction) {
+       case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
+               ret = sxe2_ipsec_tx_sa_add(sxe2_sctx, conf, sxe2_sess);
+               break;
+       case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
+               ret = sxe2_ipsec_rx_sa_add(sxe2_sctx, conf, sxe2_sess);
+               break;
+       default:
+               PMD_LOG_ERR(DRV, "Invalid sa direction.");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+int sxe2_ipsec_session_create(void *device,
+                             struct rte_security_session_conf *conf,
+                             struct sxe2_security_session *sxe2_sess)
+{
+       struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       int32_t ret = -1;
+
+       ret = sxe2_ipsec_session_conf_valid(sxe2_sctx, conf);
+       if (ret) {
+               PMD_LOG_ERR(DRV, "Input ipsec session conf invalid.");
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_hw_table_add(sxe2_sctx, conf, sxe2_sess);
+       if (ret)
+               goto l_end;
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_tx_sa_delete(struct sxe2_security_ctx *sxe2_sctx,
+                       struct sxe2_security_session *sxe2_sess)
+{
+       struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+       uint16_t sa_id = sxe2_sess->sa.hw_idx;
+       uint16_t sw_sa_id = sxe2_sess->sa.sw_idx;
+       int32_t ret   = -1;
+
+       if (sw_sa_id >= sxe2_sctx->ipsec_ctx.max_tx_sa) {
+               ret = 0;
+               PMD_LOG_WARN(DRV, "invalid sw sa id: %u.", sw_sa_id);
+               goto l_end;
+       }
+
+       if (!rte_bitmap_get(sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp, sw_sa_id)) {
+               ret = 0;
+               PMD_LOG_WARN(DRV, "bitmap not set, index: %u.", sw_sa_id);
+               goto l_end;
+       }
+
+       tx_sa = &sxe2_sctx->ipsec_ctx.tx_sa[sw_sa_id];
+
+       if (tx_sa->hw_sa_id != sa_id) {
+               ret = 0;
+               PMD_LOG_WARN(DRV, "invalid hw sa id: %u != %u.", sa_id, 
tx_sa->hw_sa_id);
+               goto l_end;
+       }
+
+       ret = sxe2_drv_ipsec_txsa_delete(sxe2_sctx->adapter, sa_id);
+       if (ret)
+               goto l_end;
+
+       rte_spinlock_lock(&sxe2_sctx->security_lock);
+       sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp, sw_sa_id);
+       rte_spinlock_unlock(&sxe2_sctx->security_lock);
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_sa_delete(struct sxe2_security_ctx *sxe2_sctx,
+                       struct sxe2_security_session *sxe2_sess)
+{
+       struct sxe2_ipsec_rx_udp_group *rx_udp = NULL;
+       struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+       struct sxe2_ipsec_rx_sa *rx_sa = NULL;
+       uint16_t sa_id                            = sxe2_sess->sa.hw_idx;
+       uint16_t sw_sa_id                         = sxe2_sess->sa.sw_idx;
+       int32_t ret                              = -1;
+
+       if (sw_sa_id >= sxe2_sctx->ipsec_ctx.max_rx_sa) {
+               ret = 0;
+               PMD_LOG_WARN(DRV, "invalid sw sa id: %u.", sw_sa_id);
+               goto l_end;
+       }
+
+       if (!rte_bitmap_get(sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp, sw_sa_id)) {
+               ret = 0;
+               PMD_LOG_INFO(DRV, "bitmap not set, id: %u.", sw_sa_id);
+               goto l_end;
+       }
+
+       rx_sa = &sxe2_sctx->ipsec_ctx.rx_sa[sw_sa_id];
+
+       if (rx_sa->hw_sa_id != sa_id) {
+               ret = 0;
+               PMD_LOG_WARN(DRV, "invalid hw sa id: %u != %u.", sa_id, 
rx_sa->hw_sa_id);
+               goto l_end;
+       }
+
+       ret = sxe2_drv_ipsec_rxsa_delete(sxe2_sctx->adapter, rx_sa);
+       if (ret)
+               goto l_end;
+
+       rte_spinlock_lock(&sxe2_sctx->security_lock);
+       sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp, sw_sa_id);
+
+       rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[rx_sa->tcam_id];
+       rx_tcam->ref_cnt--;
+       if (rx_tcam->ref_cnt == 0)
+               sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp, 
rx_sa->tcam_id);
+
+       if (rx_sa->udp_group_id == 0xFF) {
+               PMD_LOG_INFO(DRV, "Not need to release udp group resource.");
+               rte_spinlock_unlock(&sxe2_sctx->security_lock);
+               goto l_end;
+       }
+       rx_udp = &sxe2_sctx->ipsec_ctx.rx_udp_group[rx_sa->udp_group_id];
+       rx_udp->ref_cnt--;
+       if (rx_udp->ref_cnt == 0)
+               sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp, 
rx_sa->udp_group_id);
+       rte_spinlock_unlock(&sxe2_sctx->security_lock);
+
+l_end:
+       return ret;
+}
+
+static int32_t
+sxe2_ipsec_hw_table_delete(struct sxe2_security_ctx *sxe2_sctx,
+                          struct sxe2_security_session *sxe2_sess)
+{
+       int32_t ret = -1;
+
+       switch (sxe2_sess->direction) {
+       case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
+               ret = sxe2_ipsec_tx_sa_delete(sxe2_sctx, sxe2_sess);
+               break;
+       case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
+               ret = sxe2_ipsec_rx_sa_delete(sxe2_sctx, sxe2_sess);
+               break;
+       default:
+               PMD_LOG_ERR(DRV, "Invalid sa direction.");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+int sxe2_ipsec_session_destroy(void *device, struct rte_security_session 
*session)
+{
+       struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       struct sxe2_security_session *sxe2_sess = NULL;
+       sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+       int32_t ret = -1;
+
+       if (unlikely(sxe2_sess == NULL || sxe2_sess->adapter != adapter)) {
+               PMD_LOG_ERR(DRV, "Invalid device adapter.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_hw_table_delete(sxe2_sctx, sxe2_sess);
+       if (ret) {
+               ret = -EIO;
+               PMD_LOG_ERR(DRV, "Failed to delete ipsec hw tables.");
+               goto l_end;
+       }
+
+       memset(sxe2_sess, 0, sizeof(struct sxe2_security_session));
+
+       PMD_LOG_INFO(DRV, "Delete ipsec session success, sa_id: %u, spi: %u.",
+                       sxe2_sess->sa.hw_idx, sxe2_sess->sa.spi);
+
+l_end:
+       return ret;
+}
+
+int sxe2_ipsec_pkt_metadata_set(void *device, struct rte_security_session 
*session,
+                               struct rte_mbuf *m, void *params)
+{
+       struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       struct sxe2_security_session *sxe2_sess = NULL;
+       struct sxe2_ipsec_pkt_metadata *md             = NULL;
+       uint16_t offset                                      = 0;
+       int32_t ret                                         = -1;
+
+       sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+       if (unlikely(sxe2_sess == NULL || sxe2_sess->adapter != adapter)) {
+               PMD_LOG_ERR(DRV, "Invalid parameters.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       offset = ((struct sxe2_ipsec_metadata_params 
*)params)->esp_header_offset;
+       if (offset <= IPSEC_ESP_OFFSET_MIN || offset >= IPSEC_ESP_OFFSET_MAX) {
+               PMD_LOG_ERR(DRV, "Invalid esp header offset.");
+               ret = -EINVAL;
+               goto l_end;
+       }
+
+       md = RTE_MBUF_DYNFIELD(m, sxe2_sctx->ipsec_ctx.md_offset, struct 
sxe2_ipsec_pkt_metadata *);
+
+       memcpy(md, &sxe2_sess->pkt_metadata_template, sizeof(struct 
sxe2_ipsec_pkt_metadata));
+       md->esp_head_offset = offset;
+
+       PMD_LOG_INFO(DRV, "ipsec metadata set, offset:%u, said:%u, mode:%u, 
algo:%u.", offset,
+               sxe2_sess->pkt_metadata_template.sa_idx, 
sxe2_sess->pkt_metadata_template.mode,
+               sxe2_sess->pkt_metadata_template.algo);
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+int sxe2_ipsec_pkt_md_offset_get(struct sxe2_adapter *adapter)
+{
+       return adapter->security_ctx.ipsec_ctx.md_offset;
+}
+
+static void sxe2_ipsec_enc_aes_cbc_fill(struct rte_cryptodev_capabilities *cap)
+{
+       cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+       cap->sym.cipher.algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC;
+
+       cap->sym.cipher.block_size = SXE2_SECURITY_BLOCK_SIZE_16;
+
+       cap->sym.cipher.key_size.min = SXE2_IPSEC_AES_KEY_MIN;
+       cap->sym.cipher.key_size.max = SXE2_IPSEC_AES_KEY_MAX;
+       cap->sym.cipher.key_size.increment = SXE2_IPSEC_AES_KEY_INC;
+
+       cap->sym.cipher.iv_size.min = SXE2_IPSEC_AES_IV_MIN;
+       cap->sym.cipher.iv_size.max = SXE2_IPSEC_AES_IV_MAX;
+       cap->sym.cipher.iv_size.increment = SXE2_IPSEC_AES_IV_INC;
+
+       cap->sym.cipher.dataunit_set |= 
RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES;
+}
+
+static void sxe2_ipsec_enc_sm4_cbc_fill(struct rte_cryptodev_capabilities *cap)
+{
+       cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+       cap->sym.cipher.algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC;
+
+       cap->sym.cipher.block_size = SXE2_SECURITY_BLOCK_SIZE_16;
+
+       cap->sym.cipher.key_size.min = SXE2_IPSEC_SM4_KEY_MIN;
+       cap->sym.cipher.key_size.max = SXE2_IPSEC_SM4_KEY_MAX;
+       cap->sym.cipher.key_size.increment = SXE2_IPSEC_SM4_KEY_INC;
+
+       cap->sym.cipher.iv_size.min = SXE2_IPSEC_SM4_IV_MIN;
+       cap->sym.cipher.iv_size.max = SXE2_IPSEC_SM4_IV_MAX;
+       cap->sym.cipher.iv_size.increment = SXE2_IPSEC_SM4_IV_INC;
+
+       cap->sym.cipher.dataunit_set |= 
RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES;
+}
+
+static void sxe2_ipsec_auth_sha_hmac_fill(struct rte_cryptodev_capabilities 
*cap)
+{
+       cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+       cap->sym.auth.algo = SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC;
+
+       cap->sym.auth.block_size = SXE2_SECURITY_BLOCK_SIZE_64;
+
+       cap->sym.auth.key_size.min = SXE2_IPSEC_SHA_KEY_MIN;
+       cap->sym.auth.key_size.max = SXE2_IPSEC_SHA_KEY_MAX;
+       cap->sym.auth.key_size.increment = SXE2_IPSEC_SHA_KEY_INC;
+
+       cap->sym.auth.iv_size.min = SXE2_IPSEC_SHA_IV_MIN;
+       cap->sym.auth.iv_size.max = SXE2_IPSEC_SHA_IV_MAX;
+       cap->sym.auth.iv_size.increment = SXE2_IPSEC_SHA_IV_INC;
+
+       cap->sym.auth.digest_size.min = SXE2_IPSEC_SHA_DIGEST_MIN;
+       cap->sym.auth.digest_size.max = SXE2_IPSEC_SHA_DIGEST_MAX;
+       cap->sym.auth.digest_size.increment = SXE2_IPSEC_SHA_DIGEST_INC;
+
+       cap->sym.auth.aad_size.min = SXE2_IPSEC_AAD_MIN;
+       cap->sym.auth.aad_size.max = SXE2_IPSEC_AAD_MAX;
+       cap->sym.auth.aad_size.increment = SXE2_IPSEC_AAD_INC;
+}
+
+static void sxe2_ipsec_auth_sm3_hmac_fill(struct rte_cryptodev_capabilities 
*cap)
+{
+       cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+       cap->sym.auth.algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC;
+
+       cap->sym.auth.block_size = SXE2_SECURITY_BLOCK_SIZE_64;
+
+       cap->sym.auth.key_size.min = SXE2_IPSEC_SM3_KEY_MIN;
+       cap->sym.auth.key_size.max = SXE2_IPSEC_SM3_KEY_MAX;
+       cap->sym.auth.key_size.increment = SXE2_IPSEC_SM3_KEY_INC;
+
+       cap->sym.auth.iv_size.min = SXE2_IPSEC_SM3_IV_MIN;
+       cap->sym.auth.iv_size.max = SXE2_IPSEC_SM3_IV_MAX;
+       cap->sym.auth.iv_size.increment = SXE2_IPSEC_SM3_IV_INC;
+
+       cap->sym.auth.digest_size.min = SXE2_IPSEC_SM3_DIGEST_MIN;
+       cap->sym.auth.digest_size.max = SXE2_IPSEC_SM3_DIGEST_MAX;
+       cap->sym.auth.digest_size.increment = SXE2_IPSEC_SM3_DIGEST_INC;
+
+       cap->sym.auth.aad_size.min = SXE2_IPSEC_AAD_MIN;
+       cap->sym.auth.aad_size.max = SXE2_IPSEC_AAD_MAX;
+       cap->sym.auth.aad_size.increment = SXE2_IPSEC_AAD_INC;
+}
+
+static int32_t
+sxe2_ipsec_capabilities_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+       struct rte_cryptodev_capabilities *capabilities = NULL;
+       struct sxe2_security_capabilities *sxe2_cap   =
+                       
&sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+       int32_t ret                                         = -1;
+       uint8_t index                                        = 0;
+
+       sxe2_cap->action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
+       sxe2_cap->ipsec.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+       sxe2_cap->ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+       sxe2_cap->ipsec.options.stats = 1;
+
+       capabilities = rte_zmalloc("security_caps",
+                               sizeof(struct rte_cryptodev_capabilities) * 
SXE2_IPSEC_CAP_MAX, 0);
+       if (capabilities == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+
+       for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+               capabilities[index].op = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
+               switch (index) {
+               case SXE2_IPSEC_CAP_ENC_AES_CBC:
+                       sxe2_ipsec_enc_aes_cbc_fill(&capabilities[index]);
+                       break;
+               case SXE2_IPSEC_CAP_ENC_SM4_CBC:
+                       sxe2_ipsec_enc_sm4_cbc_fill(&capabilities[index]);
+                       break;
+               case SXE2_IPSEC_CAP_AUTH_SHA256_HMAC:
+                       sxe2_ipsec_auth_sha_hmac_fill(&capabilities[index]);
+                       break;
+               case SXE2_IPSEC_CAP_AUTH_SM3_HMAC:
+                       sxe2_ipsec_auth_sm3_hmac_fill(&capabilities[index]);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       sxe2_cap->crypto_capabilities = capabilities;
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+static void
+sxe2_ipsec_tx_sa_init(struct sxe2_ipsec_tx_sa *tx_sa, uint16_t len)
+{
+       struct sxe2_ipsec_tx_sa *per = NULL;
+       uint16_t i;
+
+       memset(tx_sa, 0, sizeof(struct sxe2_ipsec_tx_sa) * len);
+       for (i = 0; i < len; i++) {
+               per = &tx_sa[i];
+               per->id = i;
+       }
+}
+
+static void
+sxe2_ipsec_rx_sa_init(struct sxe2_ipsec_rx_sa *rx_sa, uint16_t len)
+{
+       struct sxe2_ipsec_rx_sa *per = NULL;
+       uint16_t i;
+
+       memset(rx_sa, 0, sizeof(struct sxe2_ipsec_rx_sa) * len);
+       for (i = 0; i < len; i++) {
+               per = &rx_sa[i];
+               per->id = i;
+       }
+}
+
+static void
+sxe2_ipsec_rx_tcam_init(struct sxe2_ipsec_rx_tcam *rx_tcam, uint16_t len)
+{
+       struct sxe2_ipsec_rx_tcam *per = NULL;
+       uint16_t i;
+
+       memset(rx_tcam, 0, sizeof(struct sxe2_ipsec_rx_tcam) * len);
+       for (i = 0; i < len; i++) {
+               per = &rx_tcam[i];
+               per->id = i;
+       }
+}
+
+static void
+sxe2_ipsec_rx_udp_group_init(struct sxe2_ipsec_rx_udp_group *rx_udp_group, 
uint16_t len)
+{
+       struct sxe2_ipsec_rx_udp_group *per = NULL;
+       uint16_t i;
+
+       memset(rx_udp_group, 0, sizeof(struct sxe2_ipsec_rx_udp_group) * len);
+       for (i = 0; i < len; i++) {
+               per = &rx_udp_group[i];
+               per->id = i;
+       }
+}
+
+static int32_t
+sxe2_ipsec_hw_table_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+       struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+       struct sxe2_ipsec_rx_sa *rx_sa = NULL;
+       struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+       struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+       uint16_t max_tx_sa = sxe2_sctx->ipsec_ctx.max_tx_sa;
+       uint16_t max_rx_sa = sxe2_sctx->ipsec_ctx.max_rx_sa;
+       uint16_t max_tcam  = sxe2_sctx->ipsec_ctx.max_tcam;
+       uint16_t max_udp_group  = sxe2_sctx->ipsec_ctx.max_udp_group;
+       int32_t ret       = -1;
+
+       tx_sa = rte_zmalloc("sxe2_ipsec_tx_sa", sizeof(struct sxe2_ipsec_tx_sa) 
* max_tx_sa, 0);
+       if (tx_sa == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       sxe2_ipsec_tx_sa_init(tx_sa, max_tx_sa);
+       sxe2_sctx->ipsec_ctx.tx_sa = tx_sa;
+
+       rx_sa = rte_zmalloc("sxe2_ipsec_rx_sa", sizeof(struct sxe2_ipsec_rx_sa) 
* max_rx_sa, 0);
+       if (rx_sa == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       sxe2_ipsec_rx_sa_init(rx_sa, max_rx_sa);
+       sxe2_sctx->ipsec_ctx.rx_sa = rx_sa;
+
+       rx_tcam = rte_zmalloc("sxe2_ipsec_rx_tcam",
+                               sizeof(struct sxe2_ipsec_rx_tcam) * max_tcam, 
0);
+       if (rx_tcam == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       sxe2_ipsec_rx_tcam_init(rx_tcam, max_tcam);
+       sxe2_sctx->ipsec_ctx.rx_tcam = rx_tcam;
+
+       rx_udp_group = rte_zmalloc("sxe2_ipsec_rx_udp_group",
+                               sizeof(struct sxe2_ipsec_rx_udp_group) * 
max_udp_group, 0);
+       if (rx_udp_group == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+       sxe2_ipsec_rx_udp_group_init(rx_udp_group, max_udp_group);
+       sxe2_sctx->ipsec_ctx.rx_udp_group = rx_udp_group;
+
+       ret = 0;
+
+l_end:
+       if (ret) {
+               if (tx_sa != NULL) {
+                       rte_free(tx_sa);
+                       sxe2_sctx->ipsec_ctx.tx_sa = NULL;
+               }
+               if (rx_sa != NULL) {
+                       rte_free(rx_sa);
+                       sxe2_sctx->ipsec_ctx.rx_sa = NULL;
+               }
+               if (rx_tcam != NULL) {
+                       rte_free(rx_tcam);
+                       sxe2_sctx->ipsec_ctx.rx_tcam = NULL;
+               }
+               if (rx_udp_group != NULL) {
+                       rte_free(rx_udp_group);
+                       sxe2_sctx->ipsec_ctx.rx_udp_group = NULL;
+               }
+       }
+       return ret;
+}
+
+int32_t sxe2_ipsec_init(struct sxe2_adapter *adapter)
+{
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       struct sxe2_security_capabilities *sxe2_cap = NULL;
+       int32_t ret                               = -1;
+       struct rte_mbuf_dynfield pkt_md_dynfield = {
+       .name = "sxe2_ipsec_pkt_metadata",
+               .size = sizeof(struct sxe2_ipsec_pkt_metadata),
+               .align = alignof(struct sxe2_ipsec_pkt_metadata)
+       };
+
+       PMD_LOG_INFO(INIT, "Init ipsec.");
+
+       sxe2_sctx->ipsec_ctx.md_offset = 
rte_mbuf_dynfield_register(&pkt_md_dynfield);
+       if (sxe2_sctx->ipsec_ctx.md_offset < 0) {
+               PMD_LOG_ERR(INIT, "Failed to register ipsec mbuf dynamic 
field.");
+               ret = -EIO;
+               goto l_end;
+       }
+
+       ret = sxe2_ipsec_capabilities_init(sxe2_sctx);
+       if (ret) {
+               PMD_LOG_ERR(INIT, "Failed to init ipsec capabilities.");
+               goto l_end;
+       }
+
+       ret = sxe2_drv_ipsec_get_capa(adapter);
+       if (ret) {
+               PMD_LOG_ERR(INIT, "Failed to get ipsec capabilities.");
+               goto l_caps_free;
+       }
+
+       ret = sxe2_ipsec_bitmap_init(sxe2_sctx);
+       if (ret) {
+               PMD_LOG_ERR(INIT, "Failed to init ipsec bitmap.");
+               goto l_caps_free;
+       }
+
+       ret = sxe2_ipsec_hw_table_init(sxe2_sctx);
+       if (ret) {
+               PMD_LOG_ERR(INIT, "Failed to init ipsec hw table.");
+               goto l_bitmap_free;
+       }
+
+       goto l_end;
+
+l_bitmap_free:
+
+       if (sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem = NULL;
+       }
+l_caps_free:
+       sxe2_cap = &sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+       if (sxe2_cap->crypto_capabilities != NULL) {
+               rte_free(sxe2_cap->crypto_capabilities);
+               sxe2_cap->crypto_capabilities = NULL;
+       }
+l_end:
+       return ret;
+}
+
+void sxe2_ipsec_uinit(struct sxe2_adapter *adapter)
+{
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       struct sxe2_security_capabilities *sxe2_cap   =
+                       
&sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+       struct sxe2_ipsec_tx_sa *tx_sa = sxe2_sctx->ipsec_ctx.tx_sa;
+       struct sxe2_ipsec_rx_sa *rx_sa = sxe2_sctx->ipsec_ctx.rx_sa;
+       struct sxe2_ipsec_rx_tcam *rx_tcam = sxe2_sctx->ipsec_ctx.rx_tcam;
+       struct sxe2_ipsec_rx_udp_group *rx_udp_group = 
sxe2_sctx->ipsec_ctx.rx_udp_group;
+
+       PMD_LOG_INFO(INIT, "Uinit ipsec.");
+
+       (void)sxe2_drv_ipsec_resource_clear(adapter);
+
+       if (sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+       }
+       if (sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem != NULL) {
+               rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem);
+               sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem = NULL;
+       }
+
+       if (tx_sa != NULL) {
+               rte_free(tx_sa);
+               sxe2_sctx->ipsec_ctx.tx_sa = NULL;
+       }
+       if (rx_sa != NULL) {
+               rte_free(rx_sa);
+               sxe2_sctx->ipsec_ctx.rx_sa = NULL;
+       }
+       if (rx_tcam != NULL) {
+               rte_free(rx_tcam);
+               sxe2_sctx->ipsec_ctx.rx_tcam = NULL;
+       }
+       if (rx_udp_group != NULL) {
+               rte_free(rx_udp_group);
+               sxe2_sctx->ipsec_ctx.rx_udp_group = NULL;
+       }
+
+       if (sxe2_cap->crypto_capabilities != NULL) {
+               rte_free(sxe2_cap->crypto_capabilities);
+               sxe2_cap->crypto_capabilities = NULL;
+       }
+}
diff --git a/drivers/net/sxe2/sxe2_ipsec.h b/drivers/net/sxe2/sxe2_ipsec.h
new file mode 100644
index 0000000000..02930ddb4f
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ipsec.h
@@ -0,0 +1,254 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+#ifndef __SXE2_IPSEC_H__
+#define __SXE2_IPSEC_H__
+
+#include <rte_security.h>
+#include <rte_security_driver.h>
+
+struct sxe2_adapter;
+struct sxe2_security_session;
+
+#define        SXE2_IPSEC_AES_KEY_MIN    (32)
+#define        SXE2_IPSEC_AES_KEY_MAX    (32)
+#define        SXE2_IPSEC_AES_KEY_INC    (0)
+
+#define        SXE2_IPSEC_SM4_KEY_MIN    (16)
+#define        SXE2_IPSEC_SM4_KEY_MAX    (16)
+#define        SXE2_IPSEC_SM4_KEY_INC    (0)
+
+#define        SXE2_IPSEC_SHA_KEY_MIN    (32)
+#define        SXE2_IPSEC_SHA_KEY_MAX    (32)
+#define        SXE2_IPSEC_SHA_KEY_INC    (0)
+
+#define        SXE2_IPSEC_SM3_KEY_MIN    (32)
+#define        SXE2_IPSEC_SM3_KEY_MAX    (32)
+#define        SXE2_IPSEC_SM3_KEY_INC    (0)
+
+#define        SXE2_IPSEC_AES_IV_MIN    (16)
+#define        SXE2_IPSEC_AES_IV_MAX    (16)
+#define        SXE2_IPSEC_AES_IV_INC    (0)
+
+#define        SXE2_IPSEC_SM4_IV_MIN    (16)
+#define        SXE2_IPSEC_SM4_IV_MAX    (16)
+#define        SXE2_IPSEC_SM4_IV_INC    (0)
+
+#define        SXE2_IPSEC_SHA_IV_MIN    (0)
+#define        SXE2_IPSEC_SHA_IV_MAX    (32)
+#define        SXE2_IPSEC_SHA_IV_INC    (16)
+
+#define        SXE2_IPSEC_SM3_IV_MIN    (0)
+#define        SXE2_IPSEC_SM3_IV_MAX    (32)
+#define        SXE2_IPSEC_SM3_IV_INC    (16)
+
+#define        SXE2_IPSEC_SHA_DIGEST_MIN    (32)
+#define        SXE2_IPSEC_SHA_DIGEST_MAX    (32)
+#define        SXE2_IPSEC_SHA_DIGEST_INC    (0)
+
+#define        SXE2_IPSEC_SM3_DIGEST_MIN    (32)
+#define        SXE2_IPSEC_SM3_DIGEST_MAX    (32)
+#define        SXE2_IPSEC_SM3_DIGEST_INC    (0)
+
+#define        SXE2_IPSEC_AAD_MIN           (0)
+#define        SXE2_IPSEC_AAD_MAX           (0)
+#define        SXE2_IPSEC_AAD_INC           (0)
+
+#define        SXE2_IPSEC_MAX_KEY_LEN           (32)
+#define        SXE2_IPSEC_MIN_KEY_LEN       (0)
+
+#define SXE2_IPSEC_OL_FLAGS_IS_TUN    (0x1 << 0)
+#define SXE2_IPSEC_OL_FLAGS_IS_ESP    (0x1 << 1)
+
+#define SXE2_IPSEC_DEFAULT_SA_OFFSET  (0)
+#define SXE2_IPSEC_DEFAULT_SA_LEN     (1024)
+
+#define IPSEC_TX_ENCRYPT    (RTE_BIT32(0))
+#define IPSEC_TX_ENGINE_SM4 (RTE_BIT32(1))
+
+#define IPSEC_RX_VALID      (RTE_BIT32(0))
+#define IPSEC_RX_IPV6       (RTE_BIT32(2))
+#define IPSEC_RX_DECRYPT    (RTE_BIT32(3))
+#define IPSEC_RX_ENGINE_SM4 (RTE_BIT32(4))
+
+#define IPSEC_IPV6_LEN                 (4)
+#define IPSEC_ESP_OFFSET_MIN           (16)
+#define IPSEC_ESP_OFFSET_MAX           (256)
+
+enum sxe2_ipsec_cap {
+       SXE2_IPSEC_CAP_ENC_AES_CBC      = 0,
+       SXE2_IPSEC_CAP_ENC_SM4_CBC      = 1,
+       SXE2_IPSEC_CAP_AUTH_SHA256_HMAC = 2,
+       SXE2_IPSEC_CAP_AUTH_SM3_HMAC    = 3,
+       SXE2_IPSEC_CAP_MAX              = 4,
+};
+
+enum sxe2_ipsec_icv_len {
+       SXE2_IPSEC_ICV_0_BYTES = 0,
+       SXE2_IPSEC_ICV_12_BYTES,
+       SXE2_IPSEC_ICV_16_BYTES,
+       SXE2_IPSEC_ICV_INVALID,
+};
+
+enum sxe2_ipsec_bypass_dir {
+       SXE2_IPSEC_BYPASS_DIR_RX = 0,
+       SXE2_IPSEC_BYPASS_DIR_TX,
+       SXE2_IPSEC_BYPASS_DIR_INVALID,
+};
+
+enum sxe2_ipsec_bypass_status {
+       SXE2_IPSEC_BYPASS_STATUS_DISABLE = 0,
+       SXE2_IPSEC_BYPASS_STATUS_ENABLE,
+       SXE2_IPSEC_BYPASS_STATUS_INVALID,
+};
+
+enum sxe2_ipsec_status {
+       SXE2_IPSEC_ENC_BYPASS = 0,
+       SXE2_IPSEC_ENC_ENABLE,
+       SXE2_IPSEC_ENC_INVALID,
+};
+
+enum sxe2_ipsec_mode {
+       SXE2_IPSEC_MODE_ENC_AND_AUTH = 0,
+       SXE2_IPSEC_MODE_ONLY_ENCRYPT,
+       SXE2_IPSEC_MODE_INVALID,
+};
+
+struct sxe2_ipsec_ip_param {
+       enum rte_security_ipsec_tunnel_type type;
+       union {
+               uint32_t dst_ipv4;
+               uint32_t dst_ipv6[IPSEC_IPV6_LEN];
+       };
+};
+
+enum sxe2_ipsec_algorithm {
+       SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC = 0,
+       SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC,
+       SXE2_IPSEC_ALGO_INVALID,
+};
+
+struct sxe2_ipsec_pkt_metadata {
+       uint16_t                  sa_idx;
+       uint16_t                  esp_head_offset;
+       uint8_t                   ol_flags;
+       uint8_t                   mode;
+       uint8_t                   algo;
+};
+
+struct sxe2_ipsec_bitmap {
+       struct rte_bitmap *tx_sa_bmp;
+       struct rte_bitmap *rx_sa_bmp;
+       struct rte_bitmap *rx_tcam_bmp;
+       struct rte_bitmap *rx_udp_bmp;
+       void *tx_sa_mem;
+       void *rx_sa_mem;
+       void *rx_tcam_mem;
+       void *rx_udp_mem;
+};
+
+struct sxe2_ipsec_security_sa {
+       uint32_t spi;
+       uint16_t hw_idx;
+       uint16_t sw_idx;
+};
+
+struct sxe2_ipsec_esn {
+       union {
+               uint64_t value;
+               struct {
+                       uint32_t hi;
+                       uint32_t low;
+               };
+       };
+       uint8_t enabled;
+};
+
+struct sxe2_ipsec_udp {
+       struct rte_security_ipsec_udp_param value;
+       uint8_t enabled;
+};
+
+struct sxe2_ipsec_tx_sa {
+       struct rte_security_ipsec_xform xform;
+       uint16_t id;
+       uint16_t hw_sa_id;
+       enum sxe2_ipsec_mode mode;
+       enum sxe2_ipsec_algorithm algo;
+       uint8_t enc_key[SXE2_IPSEC_MAX_KEY_LEN];
+       uint8_t auth_key[SXE2_IPSEC_MAX_KEY_LEN];
+};
+
+struct sxe2_ipsec_rx_sa {
+       struct rte_security_ipsec_xform xform;
+       uint32_t spi;
+       uint16_t id;
+       uint16_t hw_sa_id;
+       uint8_t hw_ip_id;
+       uint8_t hw_udp_group_id;
+       uint8_t tcam_id;
+       uint8_t udp_group_id;
+       uint8_t sdn_group_id;
+       enum sxe2_ipsec_mode mode;
+       enum sxe2_ipsec_algorithm algo;
+       uint8_t enc_key[SXE2_IPSEC_MAX_KEY_LEN];
+       uint8_t auth_key[SXE2_IPSEC_MAX_KEY_LEN];
+};
+
+struct sxe2_ipsec_rx_tcam {
+       struct sxe2_ipsec_ip_param ip_addr;
+       uint16_t id;
+       uint8_t hw_ip_id;
+       uint8_t ref_cnt;
+};
+
+struct sxe2_ipsec_rx_udp_group {
+       uint16_t udp_port;
+       uint8_t sport_en;
+       uint8_t dport_en;
+       uint8_t id;
+       uint8_t hw_group_id;
+       uint8_t ref_cnt;
+};
+
+struct sxe2_ipsec_ctx {
+       struct sxe2_ipsec_tx_sa             *tx_sa;
+       struct sxe2_ipsec_rx_sa             *rx_sa;
+       struct sxe2_ipsec_rx_tcam           *rx_tcam;
+       struct sxe2_ipsec_rx_udp_group      *rx_udp_group;
+       struct sxe2_ipsec_bitmap            bmp;
+       int                                  md_offset;
+       uint16_t                                  max_tx_sa;
+       uint16_t                                  max_rx_sa;
+       uint16_t                                  max_tcam;
+       uint8_t                                   max_udp_group;
+};
+
+struct sxe2_ipsec_metadata_params {
+       uint16_t esp_header_offset;
+       uint16_t reserved;
+};
+
+bool sxe2_ipsec_supported(struct sxe2_adapter *adapter);
+
+bool sxe2_ipsec_valid_tx_offloads(uint64_t offloads);
+
+bool sxe2_ipsec_valid_rx_offloads(uint64_t offloads);
+
+int sxe2_ipsec_pkt_md_offset_get(struct sxe2_adapter *adapter);
+
+int sxe2_ipsec_session_create(void *device,
+                             struct rte_security_session_conf *conf,
+                             struct sxe2_security_session *sxe2_sess);
+
+int sxe2_ipsec_session_destroy(void *device,
+               struct rte_security_session *session);
+
+int sxe2_ipsec_pkt_metadata_set(void *device, struct rte_security_session 
*session,
+                               struct rte_mbuf *m, void *params);
+
+int32_t sxe2_ipsec_init(struct sxe2_adapter *adapter);
+
+void sxe2_ipsec_uinit(struct sxe2_adapter *adapter);
+
+#endif /* __SXE2_IPSEC_H__ */
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 28832d5f71..007192c7d8 100644
--- a/drivers/net/sxe2/sxe2_rx.c
+++ b/drivers/net/sxe2/sxe2_rx.c
@@ -294,6 +294,11 @@ int32_t __rte_cold sxe2_rx_queue_setup(struct rte_eth_dev 
*dev,
                goto l_end;
        }
 
+       if (!sxe2_ipsec_valid_rx_offloads(offloads)) {
+               ret = -EINVAL;
+               goto l_end;
+       }
+
        rxq = sxe2_rx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
        if (rxq == NULL) {
                PMD_LOG_ERR(RX, "rx queue[%d] resource alloc failed", 
queue_idx);
diff --git a/drivers/net/sxe2/sxe2_security.c b/drivers/net/sxe2/sxe2_security.c
new file mode 100644
index 0000000000..bc59d1b880
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_security.c
@@ -0,0 +1,335 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_malloc.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
+#include "sxe2_common_log.h"
+
+static unsigned int
+sxe2_security_session_size_get(void *device __rte_unused)
+{
+       return sizeof(struct sxe2_security_session);
+}
+
+static int
+sxe2_security_session_create(void *device,
+                            struct rte_security_session_conf *conf,
+                            struct rte_security_session *session)
+{
+       int32_t ret = -1;
+       struct sxe2_security_session *sxe2_sess = NULL;
+       sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+
+       switch (conf->protocol) {
+       case RTE_SECURITY_PROTOCOL_IPSEC:
+               ret = sxe2_ipsec_session_create(device, conf, sxe2_sess);
+               break;
+       default:
+               PMD_LOG_ERR(DRV, "Invalid security protocol.");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int
+sxe2_security_session_destroy(void *device, struct rte_security_session 
*session)
+{
+       int32_t ret = -1;
+       struct sxe2_security_session *sxe2_sess = NULL;
+       sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+
+       switch (sxe2_sess->protocol) {
+       case RTE_SECURITY_PROTOCOL_IPSEC:
+               ret = sxe2_ipsec_session_destroy(device, session);
+               break;
+       default:
+               PMD_LOG_ERR(DRV, "Invalid security protocol.");
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int
+sxe2_security_pkt_metadata_set(void *device,
+                              struct rte_security_session *session,
+                              struct rte_mbuf *m, void *params)
+{
+       struct sxe2_security_session *sxe2_sess = NULL;
+       sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+       int32_t ret = -1;
+
+       switch (sxe2_sess->protocol) {
+       case RTE_SECURITY_PROTOCOL_IPSEC:
+               ret = sxe2_ipsec_pkt_metadata_set(device, session, m, params);
+               break;
+       default:
+               PMD_LOG_ERR(DRV, "Invalid security protocol.");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static const struct rte_security_capability *
+sxe2_security_capabilities_get(void *device __rte_unused)
+{
+       static const struct rte_cryptodev_capabilities
+       ipsec_crypto_capabilities[] = {
+               {
+                       .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                       {.sym = {
+                               .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+                               {.cipher = {
+                                       .algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC,
+                                       .block_size = 
SXE2_SECURITY_BLOCK_SIZE_16,
+                                       .key_size = {
+                                               .min = SXE2_IPSEC_AES_KEY_MIN,
+                                               .max = SXE2_IPSEC_AES_KEY_MAX,
+                                               .increment = 
SXE2_IPSEC_AES_KEY_INC
+                                       },
+                                       .iv_size = {
+                                               .min = SXE2_IPSEC_AES_IV_MIN,
+                                               .max = SXE2_IPSEC_AES_IV_MAX,
+                                               .increment = 
SXE2_IPSEC_AES_IV_INC
+                                       },
+                                       .dataunit_set = 
RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES,
+                               }, }
+                       }, }
+               },
+               {
+                       .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                       {.sym = {
+                               .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+                               {.cipher = {
+                                       .algo = 
SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC,
+                                       .block_size = 
SXE2_SECURITY_BLOCK_SIZE_16,
+                                       .key_size = {
+                                               .min = SXE2_IPSEC_SM4_KEY_MIN,
+                                               .max = SXE2_IPSEC_SM4_KEY_MAX,
+                                               .increment = 
SXE2_IPSEC_SM4_KEY_INC
+                                       },
+                                       .iv_size = {
+                                               .min = SXE2_IPSEC_SM4_IV_MIN,
+                                               .max = SXE2_IPSEC_SM4_IV_MAX,
+                                               .increment = 
SXE2_IPSEC_SM4_IV_INC
+                                       },
+                                       .dataunit_set = 
RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES,
+                               }, }
+                       }, }
+               },
+               {
+                       .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                       {.sym = {
+                               .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+                               {.auth = {
+                                       .algo = 
SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC,
+                                       .block_size = 
SXE2_SECURITY_BLOCK_SIZE_64,
+                                       .key_size = {
+                                               .min = SXE2_IPSEC_SHA_KEY_MIN,
+                                               .max = SXE2_IPSEC_SHA_KEY_MAX,
+                                               .increment = 
SXE2_IPSEC_SHA_KEY_INC
+                                       },
+                                       .digest_size = {
+                                               .min = 
SXE2_IPSEC_SHA_DIGEST_MIN,
+                                               .max = 
SXE2_IPSEC_SHA_DIGEST_MAX,
+                                               .increment = 
SXE2_IPSEC_SHA_DIGEST_INC
+                                       },
+                                       .iv_size = {
+                                               .min = SXE2_IPSEC_SHA_IV_MIN,
+                                               .max = SXE2_IPSEC_SHA_IV_MAX,
+                                               .increment = 
SXE2_IPSEC_SHA_IV_INC
+                                       },
+                                       .aad_size = {
+                                               .min = SXE2_IPSEC_AAD_MIN,
+                                               .max = SXE2_IPSEC_AAD_MAX,
+                                               .increment = SXE2_IPSEC_AAD_INC
+                                       }
+                               }, }
+                       }, }
+               },
+               {
+                       .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                       {.sym = {
+                               .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+                               {.auth = {
+                                       .algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC,
+                                       .block_size = 
SXE2_SECURITY_BLOCK_SIZE_64,
+                                       .key_size = {
+                                               .min = SXE2_IPSEC_SM3_KEY_MIN,
+                                               .max = SXE2_IPSEC_SM3_KEY_MAX,
+                                               .increment = 
SXE2_IPSEC_SM3_KEY_INC
+                                       },
+                                       .digest_size = {
+                                               .min = 
SXE2_IPSEC_SM3_DIGEST_MIN,
+                                               .max = 
SXE2_IPSEC_SM3_DIGEST_MAX,
+                                               .increment = 
SXE2_IPSEC_SM3_DIGEST_INC
+                                       },
+                                       .iv_size = {
+                                               .min = SXE2_IPSEC_SM3_IV_MIN,
+                                               .max = SXE2_IPSEC_SM3_IV_MAX,
+                                               .increment = 
SXE2_IPSEC_SM3_IV_INC
+                                       },
+                                       .aad_size = {
+                                               .min = SXE2_IPSEC_AAD_MIN,
+                                               .max = SXE2_IPSEC_AAD_MAX,
+                                               .increment = SXE2_IPSEC_AAD_INC
+                                       }
+                               }, }
+                       }, }
+               },
+               {
+                       .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
+                       {.sym = {
+                               .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
+                       }, }
+               }
+       };
+
+       static const struct rte_security_capability
+       sxe2_security_capabilities[] = {
+               {
+                       .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+                       .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+                       {.ipsec = {
+                               .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+                               .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+                               .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
+                               .options = {
+                                       .esn = 0,
+                                       .udp_encap = 1,
+                                       .copy_dscp = 0,
+                                       .copy_flabel = 0,
+                                       .copy_df = 0,
+                                       .dec_ttl = 0,
+                                       .ecn = 0,
+                                       .stats = 1,
+                                       .iv_gen_disable = 0,
+                                       .tunnel_hdr_verify = 1,
+                                       .udp_ports_verify = 1,
+                                       .ip_csum_enable = 0,
+                                       .l4_csum_enable = 0,
+                                       .ip_reassembly_en = 0,
+                                       .ingress_oop = 0
+                       } } },
+                       .crypto_capabilities = ipsec_crypto_capabilities,
+                       .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
+               },
+               {
+                       .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+                       .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+                       {.ipsec = {
+                               .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+                               .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+                               .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
+                               .options = {
+                                       .esn = 0,
+                                       .udp_encap = 1,
+                                       .copy_dscp = 0,
+                                       .copy_flabel = 0,
+                                       .copy_df = 0,
+                                       .dec_ttl = 0,
+                                       .ecn = 0,
+                                       .stats = 1,
+                                       .iv_gen_disable = 0,
+                                       .tunnel_hdr_verify = 1,
+                                       .udp_ports_verify = 1,
+                                       .ip_csum_enable = 0,
+                                       .l4_csum_enable = 0,
+                                       .ip_reassembly_en = 0,
+                                       .ingress_oop = 0
+                       } } },
+                       .crypto_capabilities = ipsec_crypto_capabilities,
+                       .ol_flags = 0
+               },
+               {
+                       .action = RTE_SECURITY_ACTION_TYPE_NONE
+               }
+       };
+
+       return sxe2_security_capabilities;
+}
+
+static struct rte_security_ops sxe2_security_ops = {
+       .session_get_size               = sxe2_security_session_size_get,
+       .session_create                 = sxe2_security_session_create,
+       .session_destroy                = sxe2_security_session_destroy,
+       .set_pkt_metadata               = sxe2_security_pkt_metadata_set,
+       .capabilities_get               = sxe2_security_capabilities_get,
+};
+
+int32_t sxe2_security_init(struct rte_eth_dev *dev)
+{
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+       struct rte_security_ctx *sctx = NULL;
+       struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+       int32_t ret = -1;
+
+       if (!sxe2_ipsec_supported(adapter)) {
+               ret = 0;
+               PMD_LOG_INFO(INIT, "Not support security feature.");
+               goto l_end;
+       }
+
+       PMD_LOG_INFO(INIT, "Init security feature.");
+
+       sctx = rte_zmalloc("security_ctx", sizeof(struct rte_security_ctx), 0);
+       if (sctx == NULL) {
+               ret = -ENOMEM;
+               goto l_end;
+       }
+
+       sctx->device = dev;
+       sctx->ops = &sxe2_security_ops;
+       sctx->sess_cnt = 0;
+       sctx->flags = 0;
+       dev->security_ctx = (void *)sctx;
+
+       rte_spinlock_init(&sxe2_sctx->security_lock);
+       sxe2_sctx->adapter = adapter;
+
+       if (sxe2_ipsec_supported(adapter)) {
+               ret = sxe2_ipsec_init(adapter);
+               if (ret) {
+                       rte_free(sctx);
+                       sctx = NULL;
+                       dev->security_ctx = NULL;
+                       goto l_end;
+               }
+       }
+
+       ret = 0;
+
+l_end:
+       return ret;
+}
+
+void sxe2_security_uinit(struct rte_eth_dev *dev)
+{
+       struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+       struct rte_security_ctx *sctx = dev->security_ctx;
+
+       if (!sxe2_ipsec_supported(adapter)) {
+               PMD_LOG_INFO(INIT, "Not support security feature.");
+               goto l_end;
+       }
+
+       PMD_LOG_INFO(INIT, "Uinit security feature.");
+
+       if (sctx != NULL) {
+               rte_free(sctx);
+               sctx = NULL;
+       }
+
+       sxe2_ipsec_uinit(adapter);
+
+l_end:
+       return;
+}
diff --git a/drivers/net/sxe2/sxe2_security.h b/drivers/net/sxe2/sxe2_security.h
new file mode 100644
index 0000000000..366c0614bd
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_security.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_SECURITY_H__
+#define __SXE2_SECURITY_H__
+
+#include <rte_security.h>
+#include <rte_cryptodev.h>
+#include <rte_security_driver.h>
+
+#include "sxe2_ipsec.h"
+
+#define SXE2_DEV_TO_SECURITY(eth) \
+       ((struct rte_security_ctx *)(((struct rte_eth_dev *)eth)->security_ctx))
+
+#define SXE2_RTE_CRYPTO_CIPHER_AES_CBC   (RTE_CRYPTO_CIPHER_AES_CBC)
+
+#define SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC   (RTE_CRYPTO_CIPHER_SM4_CBC)
+
+#define SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC  (RTE_CRYPTO_AUTH_SHA256_HMAC)
+
+#define SXE2_RTE_CRYPTO_AUTH_SM3_HMAC   (RTE_CRYPTO_AUTH_SM3_HMAC)
+
+enum sxe2_security_protocol {
+       SXE2_SECURITY_PROTOCOL_IPSEC       = 0,
+       SXE2_SECURITY_PROTOCOL_MAX         = 1,
+};
+
+enum sxe2_security_xform {
+       SXE2_SECURITY_IPSEC_EN       = 0,
+       SXE2_SECURITY_IPSEC_DE       = 1,
+       SXE2_SECURITY_NUM_MAX        = 2,
+};
+
+enum sxe2_security_block_size {
+       SXE2_SECURITY_BLOCK_SIZE_16        = 16,
+       SXE2_SECURITY_BLOCK_SIZE_64        = 64,
+};
+
+struct sxe2_security_ipsec_caps {
+       enum rte_security_ipsec_sa_protocol   proto;
+       enum rte_security_ipsec_sa_mode       mode;
+       struct rte_security_ipsec_sa_options  options;
+};
+
+struct sxe2_security_capabilities {
+       struct rte_cryptodev_capabilities     *crypto_capabilities;
+       enum rte_security_session_action_type action;
+       struct sxe2_security_ipsec_caps      ipsec;
+};
+
+struct sxe2_security_session {
+       struct sxe2_adapter                   *adapter;
+       struct sxe2_ipsec_pkt_metadata        pkt_metadata_template;
+       struct sxe2_ipsec_security_sa         sa;
+       struct sxe2_ipsec_esn                 esn;
+       struct sxe2_ipsec_udp                 udp_cap;
+       enum rte_security_session_protocol     protocol;
+       enum rte_security_ipsec_sa_direction   direction;
+       enum rte_security_ipsec_sa_mode        mode;
+       enum rte_security_ipsec_sa_protocol    sa_proto;
+       enum rte_security_ipsec_tunnel_type    type;
+};
+
+struct sxe2_security_ctx {
+       struct sxe2_adapter                 *adapter;
+       struct sxe2_security_capabilities   
sxe2_capabilities[SXE2_SECURITY_PROTOCOL_MAX];
+       struct sxe2_ipsec_ctx               ipsec_ctx;
+       rte_spinlock_t                       security_lock;
+};
+
+int32_t sxe2_security_init(struct rte_eth_dev *dev);
+
+void sxe2_security_uinit(struct rte_eth_dev *dev);
+
+#endif /* __SXE2_SECURITY_H__ */
diff --git a/drivers/net/sxe2/sxe2_tx.c b/drivers/net/sxe2/sxe2_tx.c
index a280edc9c5..f49238ceef 100644
--- a/drivers/net/sxe2/sxe2_tx.c
+++ b/drivers/net/sxe2/sxe2_tx.c
@@ -304,6 +304,11 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev 
*dev,
        }
 
        offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
+       if (!sxe2_ipsec_valid_tx_offloads(offloads)) {
+               ret = -EINVAL;
+               goto end;
+       }
+
        txq = sxe2_tx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
        if (txq == NULL) {
                PMD_LOG_ERR(TX, "failed to alloc sxe2vf tx queue:%u resource", 
queue_idx);
@@ -327,6 +332,9 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev 
*dev,
        txq->ops               = sxe2_tx_default_ops_get();
        txq->ops.queue_reset(txq);
 
+       if (sxe2_ipsec_supported(adapter) && txq->offloads & 
RTE_ETH_TX_OFFLOAD_SECURITY)
+               txq->ipsec_pkt_md_offset = 
sxe2_ipsec_pkt_md_offset_get(adapter);
+
        dev->data->tx_queues[queue_idx] = txq;
        ret = 0;
 
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c 
b/drivers/net/sxe2/sxe2_txrx_poll.c
index 3c6fe37404..8b6e585c36 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -307,6 +307,25 @@ static __rte_always_inline void sxe2_desc_tso_fill(struct 
rte_mbuf *tx_pkt,
        return;
 }
 
+static __rte_always_inline void sxe2_desc_ipsec_fill(struct rte_mbuf *tx_pkt,
+                       struct sxe2_tx_queue *txq, uint16_t *ipsec_offset,
+                       uint64_t *desc_type_cmd_tso_mss)
+{
+       struct sxe2_ipsec_pkt_metadata *md = NULL;
+       uint16_t ipsec_pkt_md_offset = txq->ipsec_pkt_md_offset;
+
+       md = RTE_MBUF_DYNFIELD(tx_pkt, ipsec_pkt_md_offset, struct 
sxe2_ipsec_pkt_metadata *);
+       *ipsec_offset = md->esp_head_offset;
+       *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_EN;
+       if (md->mode == SXE2_IPSEC_MODE_ONLY_ENCRYPT)
+               *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_MODE;
+
+       if (md->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+               *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_ENGINE;
+
+       *desc_type_cmd_tso_mss |= (uint64_t)(md->sa_idx) << 
SXE2_TX_CTXT_DESC_IPSEC_SA_SHIFT;
+}
+
 static __rte_always_inline uint64_t
 sxe2_tx_data_desc_build_cobt(uint32_t cmd, uint32_t offset, uint16_t buf_size, 
uint16_t l2tag)
 {
@@ -426,6 +445,11 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf 
**tx_pkts, uint16_t nb_pkt
                        else if (offloads & RTE_MBUF_F_TX_IEEE1588_TMST)
                                desc_type_cmd_tso_mss |= 
SXE2_TX_CTXT_DESC_CMD_TSYN_MASK;
 
+                       if (offloads & RTE_MBUF_F_TX_SEC_OFFLOAD) {
+                               sxe2_desc_ipsec_fill(tx_pkt, txq, &ipsec_offset,
+                                                    &desc_type_cmd_tso_mss);
+                       }
+
                        if (offloads & RTE_MBUF_F_TX_QINQ) {
                                desc_l2tag2 = tx_pkt->vlan_tci_outer;
                                desc_type_cmd_tso_mss |= 
SXE2_TX_CTXT_DESC_CMD_IL2TAG2_MASK;
@@ -786,6 +810,36 @@ static inline void sxe2_rx_desc_ptp_para_fill(struct 
sxe2_rx_queue *rxq,
                             rxq->ts_low);
        }
 }
+
+static inline void sxe2_rx_desc_ipsec_para_fill(struct sxe2_rx_queue *rxq 
__rte_unused,
+               struct rte_mbuf *mbuf, union sxe2_rx_desc *desc)
+{
+       uint32_t status_lrocnt_fdpf_id = 
rte_le_to_cpu_32(desc->wb.status_lrocnt_fdpf_id);
+       enum sxe2_rx_desc_ipsec_status ipsec_status;
+
+       if (status_lrocnt_fdpf_id & SXE2_RX_DESC_IPSEC_PKT_MASK) {
+               mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD;
+               ipsec_status = 
SXE2_RX_DESC_IPSEC_STATUS_VAL_GET(status_lrocnt_fdpf_id);
+               switch (ipsec_status) {
+               case SXE2_RX_DESC_IPSEC_STATUS_SUCCESS:
+                       break;
+               case SXE2_RX_DESC_IPSEC_STATUS_PKG_OVER_2K:
+               case SXE2_RX_DESC_IPSEC_STATUS_SPI_IP_INVALID:
+               case SXE2_RX_DESC_IPSEC_STATUS_SA_INVALID:
+               case SXE2_RX_DESC_IPSEC_STATUS_NOT_ALIGN:
+               case SXE2_RX_DESC_IPSEC_STATUS_ICV_ERROR:
+               case SXE2_RX_DESC_IPSEC_STATUS_BY_PASSH:
+               case SXE2_RX_DESC_IPSEC_STATUS_MAC_BY_PASSH:
+                       PMD_LOG_INFO(RX, "IPsec status error:%d", ipsec_status);
+                       mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
+                       break;
+               default:
+                       PMD_LOG_INFO(RX, "Invalid ipsec status:%d", 
ipsec_status);
+                       mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
+                       break;
+               }
+       }
+}
 #endif
 
 static __rte_always_inline void
@@ -803,6 +857,7 @@ sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, 
struct rte_mbuf *mbuf
        sxe2_rx_desc_vlan_para_fill(mbuf, rxd);
        sxe2_rx_desc_filter_para_fill(rxq, mbuf, rxd);
 #ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+       sxe2_rx_desc_ipsec_para_fill(rxq, mbuf, rxd);
        sxe2_rx_desc_ptp_para_fill(rxq, mbuf, rxd);
 #endif
 
-- 
2.47.3

Reply via email to