summaryrefslogtreecommitdiffstats
path: root/src/spdk/dpdk/lib/librte_ipsec/sa.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/spdk/dpdk/lib/librte_ipsec/sa.c
parentInitial commit. (diff)
downloadceph-upstream.tar.xz
ceph-upstream.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/dpdk/lib/librte_ipsec/sa.c')
-rw-r--r--src/spdk/dpdk/lib/librte_ipsec/sa.c764
1 files changed, 764 insertions, 0 deletions
diff --git a/src/spdk/dpdk/lib/librte_ipsec/sa.c b/src/spdk/dpdk/lib/librte_ipsec/sa.c
new file mode 100644
index 000000000..e59189d21
--- /dev/null
+++ b/src/spdk/dpdk/lib/librte_ipsec/sa.c
@@ -0,0 +1,764 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2020 Intel Corporation
+ */
+
+#include <rte_ipsec.h>
+#include <rte_esp.h>
+#include <rte_ip.h>
+#include <rte_errno.h>
+#include <rte_cryptodev.h>
+
+#include "sa.h"
+#include "ipsec_sqn.h"
+#include "crypto.h"
+#include "iph.h"
+#include "misc.h"
+#include "pad.h"
+
+#define MBUF_MAX_L2_LEN RTE_LEN2MASK(RTE_MBUF_L2_LEN_BITS, uint64_t)
+#define MBUF_MAX_L3_LEN RTE_LEN2MASK(RTE_MBUF_L3_LEN_BITS, uint64_t)
+
+/* some helper structures */
+struct crypto_xform {
+ struct rte_crypto_auth_xform *auth;
+ struct rte_crypto_cipher_xform *cipher;
+ struct rte_crypto_aead_xform *aead;
+};
+
+/*
+ * helper routine, fills internal crypto_xform structure.
+ */
+static int
+fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
+ const struct rte_ipsec_sa_prm *prm)
+{
+ struct rte_crypto_sym_xform *xf, *xfn;
+
+ memset(xform, 0, sizeof(*xform));
+
+ xf = prm->crypto_xform;
+ if (xf == NULL)
+ return -EINVAL;
+
+ xfn = xf->next;
+
+ /* for AEAD just one xform required */
+ if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
+ if (xfn != NULL)
+ return -EINVAL;
+ xform->aead = &xf->aead;
+ /*
+ * CIPHER+AUTH xforms are expected in strict order,
+ * depending on SA direction:
+ * inbound: AUTH+CIPHER
+ * outbound: CIPHER+AUTH
+ */
+ } else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
+
+ /* wrong order or no cipher */
+ if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
+ xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
+ return -EINVAL;
+
+ xform->auth = &xf->auth;
+ xform->cipher = &xfn->cipher;
+
+ } else {
+
+ /* wrong order or no auth */
+ if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
+ xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
+ return -EINVAL;
+
+ xform->cipher = &xf->cipher;
+ xform->auth = &xfn->auth;
+ }
+
+ return 0;
+}
+
+uint64_t
+rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
+{
+ return sa->type;
+}
+
+/**
+ * Based on number of buckets calculated required size for the
+ * structure that holds replay window and sequence number (RSN) information.
+ */
+static size_t
+rsn_size(uint32_t nb_bucket)
+{
+ size_t sz;
+ struct replay_sqn *rsn;
+
+ sz = sizeof(*rsn) + nb_bucket * sizeof(rsn->window[0]);
+ sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
+ return sz;
+}
+
+/*
+ * for given size, calculate required number of buckets.
+ */
+static uint32_t
+replay_num_bucket(uint32_t wsz)
+{
+ uint32_t nb;
+
+ nb = rte_align32pow2(RTE_ALIGN_MUL_CEIL(wsz, WINDOW_BUCKET_SIZE) /
+ WINDOW_BUCKET_SIZE);
+ nb = RTE_MAX(nb, (uint32_t)WINDOW_BUCKET_MIN);
+
+ return nb;
+}
+
+static int32_t
+ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
+{
+ uint32_t n, sz, wsz;
+
+ wsz = *wnd_sz;
+ n = 0;
+
+ if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
+
+ /*
+ * RFC 4303 recommends 64 as minimum window size.
+ * there is no point to use ESN mode without SQN window,
+ * so make sure we have at least 64 window when ESN is enalbed.
+ */
+ wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
+ RTE_IPSEC_SATP_ESN_DISABLE) ?
+ wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
+ if (wsz != 0)
+ n = replay_num_bucket(wsz);
+ }
+
+ if (n > WINDOW_BUCKET_MAX)
+ return -EINVAL;
+
+ *wnd_sz = wsz;
+ *nb_bucket = n;
+
+ sz = rsn_size(n);
+ if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
+ sz *= REPLAY_SQN_NUM;
+
+ sz += sizeof(struct rte_ipsec_sa);
+ return sz;
+}
+
+void
+rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
+{
+ memset(sa, 0, sa->size);
+}
+
+/*
+ * Determine expected SA type based on input parameters.
+ */
+static int
+fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
+{
+ uint64_t tp;
+
+ tp = 0;
+
+ if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
+ tp |= RTE_IPSEC_SATP_PROTO_AH;
+ else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
+ tp |= RTE_IPSEC_SATP_PROTO_ESP;
+ else
+ return -EINVAL;
+
+ if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+ tp |= RTE_IPSEC_SATP_DIR_OB;
+ else if (prm->ipsec_xform.direction ==
+ RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
+ tp |= RTE_IPSEC_SATP_DIR_IB;
+ else
+ return -EINVAL;
+
+ if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
+ if (prm->ipsec_xform.tunnel.type ==
+ RTE_SECURITY_IPSEC_TUNNEL_IPV4)
+ tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
+ else if (prm->ipsec_xform.tunnel.type ==
+ RTE_SECURITY_IPSEC_TUNNEL_IPV6)
+ tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
+ else
+ return -EINVAL;
+
+ if (prm->tun.next_proto == IPPROTO_IPIP)
+ tp |= RTE_IPSEC_SATP_IPV4;
+ else if (prm->tun.next_proto == IPPROTO_IPV6)
+ tp |= RTE_IPSEC_SATP_IPV6;
+ else
+ return -EINVAL;
+ } else if (prm->ipsec_xform.mode ==
+ RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
+ tp |= RTE_IPSEC_SATP_MODE_TRANS;
+ if (prm->trs.proto == IPPROTO_IPIP)
+ tp |= RTE_IPSEC_SATP_IPV4;
+ else if (prm->trs.proto == IPPROTO_IPV6)
+ tp |= RTE_IPSEC_SATP_IPV6;
+ else
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ /* check for ESN flag */
+ if (prm->ipsec_xform.options.esn == 0)
+ tp |= RTE_IPSEC_SATP_ESN_DISABLE;
+ else
+ tp |= RTE_IPSEC_SATP_ESN_ENABLE;
+
+ /* check for ECN flag */
+ if (prm->ipsec_xform.options.ecn == 0)
+ tp |= RTE_IPSEC_SATP_ECN_DISABLE;
+ else
+ tp |= RTE_IPSEC_SATP_ECN_ENABLE;
+
+ /* check for DSCP flag */
+ if (prm->ipsec_xform.options.copy_dscp == 0)
+ tp |= RTE_IPSEC_SATP_DSCP_DISABLE;
+ else
+ tp |= RTE_IPSEC_SATP_DSCP_ENABLE;
+
+ /* interpret flags */
+ if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
+ tp |= RTE_IPSEC_SATP_SQN_ATOM;
+ else
+ tp |= RTE_IPSEC_SATP_SQN_RAW;
+
+ *type = tp;
+ return 0;
+}
+
+/*
+ * Init ESP inbound specific things.
+ */
+static void
+esp_inb_init(struct rte_ipsec_sa *sa)
+{
+ /* these params may differ with new algorithms support */
+ sa->ctp.cipher.offset = sizeof(struct rte_esp_hdr) + sa->iv_len;
+ sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
+
+ /*
+ * for AEAD and NULL algorithms we can assume that
+ * auth and cipher offsets would be equal.
+ */
+ switch (sa->algo_type) {
+ case ALGO_TYPE_AES_GCM:
+ case ALGO_TYPE_NULL:
+ sa->ctp.auth.raw = sa->ctp.cipher.raw;
+ break;
+ default:
+ sa->ctp.auth.offset = 0;
+ sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
+ sa->cofs.ofs.cipher.tail = sa->sqh_len;
+ break;
+ }
+
+ sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
+}
+
+/*
+ * Init ESP inbound tunnel specific things.
+ */
+static void
+esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
+{
+ sa->proto = prm->tun.next_proto;
+ esp_inb_init(sa);
+}
+
+/*
+ * Init ESP outbound specific things.
+ */
+static void
+esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
+{
+ uint8_t algo_type;
+
+ sa->sqn.outb = 1;
+
+ algo_type = sa->algo_type;
+
+ /*
+ * Setup auth and cipher length and offset.
+ * these params may differ with new algorithms support
+ */
+
+ switch (algo_type) {
+ case ALGO_TYPE_AES_GCM:
+ case ALGO_TYPE_AES_CTR:
+ case ALGO_TYPE_NULL:
+ sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr) +
+ sa->iv_len;
+ sa->ctp.cipher.length = 0;
+ break;
+ case ALGO_TYPE_AES_CBC:
+ case ALGO_TYPE_3DES_CBC:
+ sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr);
+ sa->ctp.cipher.length = sa->iv_len;
+ break;
+ }
+
+ /*
+ * for AEAD and NULL algorithms we can assume that
+ * auth and cipher offsets would be equal.
+ */
+ switch (algo_type) {
+ case ALGO_TYPE_AES_GCM:
+ case ALGO_TYPE_NULL:
+ sa->ctp.auth.raw = sa->ctp.cipher.raw;
+ break;
+ default:
+ sa->ctp.auth.offset = hlen;
+ sa->ctp.auth.length = sizeof(struct rte_esp_hdr) +
+ sa->iv_len + sa->sqh_len;
+ break;
+ }
+
+ sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
+ sa->cofs.ofs.cipher.tail = (sa->ctp.auth.offset + sa->ctp.auth.length) -
+ (sa->ctp.cipher.offset + sa->ctp.cipher.length);
+}
+
+/*
+ * Init ESP outbound tunnel specific things.
+ */
+static void
+esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
+{
+ sa->proto = prm->tun.next_proto;
+ sa->hdr_len = prm->tun.hdr_len;
+ sa->hdr_l3_off = prm->tun.hdr_l3_off;
+
+ /* update l2_len and l3_len fields for outbound mbuf */
+ sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
+ sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
+
+ memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
+
+ esp_outb_init(sa, sa->hdr_len);
+}
+
+/*
+ * helper function, init SA structure.
+ */
+static int
+esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
+ const struct crypto_xform *cxf)
+{
+ static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
+ RTE_IPSEC_SATP_MODE_MASK;
+
+ if (prm->ipsec_xform.options.ecn)
+ sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
+
+ if (prm->ipsec_xform.options.copy_dscp)
+ sa->tos_mask |= RTE_IPV4_HDR_DSCP_MASK;
+
+ if (cxf->aead != NULL) {
+ switch (cxf->aead->algo) {
+ case RTE_CRYPTO_AEAD_AES_GCM:
+ /* RFC 4106 */
+ sa->aad_len = sizeof(struct aead_gcm_aad);
+ sa->icv_len = cxf->aead->digest_length;
+ sa->iv_ofs = cxf->aead->iv.offset;
+ sa->iv_len = sizeof(uint64_t);
+ sa->pad_align = IPSEC_PAD_AES_GCM;
+ sa->algo_type = ALGO_TYPE_AES_GCM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ sa->icv_len = cxf->auth->digest_length;
+ sa->iv_ofs = cxf->cipher->iv.offset;
+ sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
+
+ switch (cxf->cipher->algo) {
+ case RTE_CRYPTO_CIPHER_NULL:
+ sa->pad_align = IPSEC_PAD_NULL;
+ sa->iv_len = 0;
+ sa->algo_type = ALGO_TYPE_NULL;
+ break;
+
+ case RTE_CRYPTO_CIPHER_AES_CBC:
+ sa->pad_align = IPSEC_PAD_AES_CBC;
+ sa->iv_len = IPSEC_MAX_IV_SIZE;
+ sa->algo_type = ALGO_TYPE_AES_CBC;
+ break;
+
+ case RTE_CRYPTO_CIPHER_AES_CTR:
+ /* RFC 3686 */
+ sa->pad_align = IPSEC_PAD_AES_CTR;
+ sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
+ sa->algo_type = ALGO_TYPE_AES_CTR;
+ break;
+
+ case RTE_CRYPTO_CIPHER_3DES_CBC:
+ /* RFC 1851 */
+ sa->pad_align = IPSEC_PAD_3DES_CBC;
+ sa->iv_len = IPSEC_3DES_IV_SIZE;
+ sa->algo_type = ALGO_TYPE_3DES_CBC;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ sa->udata = prm->userdata;
+ sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
+ sa->salt = prm->ipsec_xform.salt;
+
+ /* preserve all values except l2_len and l3_len */
+ sa->tx_offload.msk =
+ ~rte_mbuf_tx_offload(MBUF_MAX_L2_LEN, MBUF_MAX_L3_LEN,
+ 0, 0, 0, 0, 0);
+
+ switch (sa->type & msk) {
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ esp_inb_tun_init(sa, prm);
+ break;
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
+ esp_inb_init(sa);
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ esp_outb_tun_init(sa, prm);
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
+ esp_outb_init(sa, 0);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * helper function, init SA replay structure.
+ */
+static void
+fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket)
+{
+ sa->replay.win_sz = wnd_sz;
+ sa->replay.nb_bucket = nb_bucket;
+ sa->replay.bucket_index_mask = nb_bucket - 1;
+ sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
+ if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
+ sa->sqn.inb.rsn[1] = (struct replay_sqn *)
+ ((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
+}
+
+int
+rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
+{
+ uint64_t type;
+ uint32_t nb, wsz;
+ int32_t rc;
+
+ if (prm == NULL)
+ return -EINVAL;
+
+ /* determine SA type */
+ rc = fill_sa_type(prm, &type);
+ if (rc != 0)
+ return rc;
+
+ /* determine required size */
+ wsz = prm->ipsec_xform.replay_win_sz;
+ return ipsec_sa_size(type, &wsz, &nb);
+}
+
+int
+rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
+ uint32_t size)
+{
+ int32_t rc, sz;
+ uint32_t nb, wsz;
+ uint64_t type;
+ struct crypto_xform cxf;
+
+ if (sa == NULL || prm == NULL)
+ return -EINVAL;
+
+ /* determine SA type */
+ rc = fill_sa_type(prm, &type);
+ if (rc != 0)
+ return rc;
+
+ /* determine required size */
+ wsz = prm->ipsec_xform.replay_win_sz;
+ sz = ipsec_sa_size(type, &wsz, &nb);
+ if (sz < 0)
+ return sz;
+ else if (size < (uint32_t)sz)
+ return -ENOSPC;
+
+ /* only esp is supported right now */
+ if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
+ return -EINVAL;
+
+ if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
+ prm->tun.hdr_len > sizeof(sa->hdr))
+ return -EINVAL;
+
+ rc = fill_crypto_xform(&cxf, type, prm);
+ if (rc != 0)
+ return rc;
+
+ /* initialize SA */
+
+ memset(sa, 0, sz);
+ sa->type = type;
+ sa->size = sz;
+
+ /* check for ESN flag */
+ sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
+ UINT32_MAX : UINT64_MAX;
+
+ rc = esp_sa_init(sa, prm, &cxf);
+ if (rc != 0)
+ rte_ipsec_sa_fini(sa);
+
+ /* fill replay window related fields */
+ if (nb != 0)
+ fill_sa_replay(sa, wsz, nb);
+
+ return sz;
+}
+
+/*
+ * setup crypto ops for LOOKASIDE_PROTO type of devices.
+ */
+static inline void
+lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
+ struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
+{
+ uint32_t i;
+ struct rte_crypto_sym_op *sop;
+
+ for (i = 0; i != num; i++) {
+ sop = cop[i]->sym;
+ cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
+ cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+ cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
+ sop->m_src = mb[i];
+ __rte_security_attach_session(sop, ss->security.ses);
+ }
+}
+
+/*
+ * setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
+ * Note that for LOOKASIDE_PROTO all packet modifications will be
+ * performed by PMD/HW.
+ * SW has only to prepare crypto op.
+ */
+static uint16_t
+lksd_proto_prepare(const struct rte_ipsec_session *ss,
+ struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
+{
+ lksd_proto_cop_prepare(ss, mb, cop, num);
+ return num;
+}
+
+/*
+ * simplest pkt process routine:
+ * all actual processing is already done by HW/PMD,
+ * just check mbuf ol_flags.
+ * used for:
+ * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
+ * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
+ * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
+ */
+uint16_t
+pkt_flag_process(const struct rte_ipsec_session *ss,
+ struct rte_mbuf *mb[], uint16_t num)
+{
+ uint32_t i, k;
+ uint32_t dr[num];
+
+ RTE_SET_USED(ss);
+
+ k = 0;
+ for (i = 0; i != num; i++) {
+ if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0)
+ k++;
+ else
+ dr[i - k] = i;
+ }
+
+ /* handle unprocessed mbufs */
+ if (k != num) {
+ rte_errno = EBADMSG;
+ if (k != 0)
+ move_bad_mbufs(mb, dr, num, num - k);
+ }
+
+ return k;
+}
+
+/*
+ * Select packet processing function for session on LOOKASIDE_NONE
+ * type of device.
+ */
+static int
+lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
+ struct rte_ipsec_sa_pkt_func *pf)
+{
+ int32_t rc;
+
+ static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
+ RTE_IPSEC_SATP_MODE_MASK;
+
+ rc = 0;
+ switch (sa->type & msk) {
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->prepare.async = esp_inb_pkt_prepare;
+ pf->process = esp_inb_tun_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->prepare.async = esp_inb_pkt_prepare;
+ pf->process = esp_inb_trs_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->prepare.async = esp_outb_tun_prepare;
+ pf->process = (sa->sqh_len != 0) ?
+ esp_outb_sqh_process : pkt_flag_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->prepare.async = esp_outb_trs_prepare;
+ pf->process = (sa->sqh_len != 0) ?
+ esp_outb_sqh_process : pkt_flag_process;
+ break;
+ default:
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}
+
+static int
+cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
+ struct rte_ipsec_sa_pkt_func *pf)
+{
+ int32_t rc;
+
+ static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
+ RTE_IPSEC_SATP_MODE_MASK;
+
+ rc = 0;
+ switch (sa->type & msk) {
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->prepare.sync = cpu_inb_pkt_prepare;
+ pf->process = esp_inb_tun_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->prepare.sync = cpu_inb_pkt_prepare;
+ pf->process = esp_inb_trs_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->prepare.sync = cpu_outb_tun_pkt_prepare;
+ pf->process = (sa->sqh_len != 0) ?
+ esp_outb_sqh_process : pkt_flag_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->prepare.sync = cpu_outb_trs_pkt_prepare;
+ pf->process = (sa->sqh_len != 0) ?
+ esp_outb_sqh_process : pkt_flag_process;
+ break;
+ default:
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}
+
+/*
+ * Select packet processing function for session on INLINE_CRYPTO
+ * type of device.
+ */
+static int
+inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
+ struct rte_ipsec_sa_pkt_func *pf)
+{
+ int32_t rc;
+
+ static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
+ RTE_IPSEC_SATP_MODE_MASK;
+
+ rc = 0;
+ switch (sa->type & msk) {
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->process = inline_inb_tun_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->process = inline_inb_trs_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
+ pf->process = inline_outb_tun_pkt_process;
+ break;
+ case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
+ pf->process = inline_outb_trs_pkt_process;
+ break;
+ default:
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}
+
+/*
+ * Select packet processing function for given session based on SA parameters
+ * and type of associated with the session device.
+ */
+int
+ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
+ const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
+{
+ int32_t rc;
+
+ rc = 0;
+ pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
+
+ switch (ss->type) {
+ case RTE_SECURITY_ACTION_TYPE_NONE:
+ rc = lksd_none_pkt_func_select(sa, pf);
+ break;
+ case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
+ rc = inline_crypto_pkt_func_select(sa, pf);
+ break;
+ case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
+ if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
+ RTE_IPSEC_SATP_DIR_IB)
+ pf->process = pkt_flag_process;
+ else
+ pf->process = inline_proto_outb_pkt_process;
+ break;
+ case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
+ pf->prepare.async = lksd_proto_prepare;
+ pf->process = pkt_flag_process;
+ break;
+ case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
+ rc = cpu_crypto_pkt_func_select(sa, pf);
+ break;
+ default:
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}