xref: /dpdk/lib/ipsec/sa.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2018-2020 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_ipsec.h>
699a2dd95SBruce Richardson #include <rte_esp.h>
799a2dd95SBruce Richardson #include <rte_ip.h>
801eef590SRadu Nicolau #include <rte_udp.h>
999a2dd95SBruce Richardson #include <rte_errno.h>
1099a2dd95SBruce Richardson #include <rte_cryptodev.h>
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson #include "sa.h"
1399a2dd95SBruce Richardson #include "ipsec_sqn.h"
1499a2dd95SBruce Richardson #include "crypto.h"
1599a2dd95SBruce Richardson #include "iph.h"
1699a2dd95SBruce Richardson #include "misc.h"
1799a2dd95SBruce Richardson #include "pad.h"
1899a2dd95SBruce Richardson 
1999a2dd95SBruce Richardson #define MBUF_MAX_L2_LEN		RTE_LEN2MASK(RTE_MBUF_L2_LEN_BITS, uint64_t)
2099a2dd95SBruce Richardson #define MBUF_MAX_L3_LEN		RTE_LEN2MASK(RTE_MBUF_L3_LEN_BITS, uint64_t)
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson /* some helper structures */
2399a2dd95SBruce Richardson struct crypto_xform {
2499a2dd95SBruce Richardson 	struct rte_crypto_auth_xform *auth;
2599a2dd95SBruce Richardson 	struct rte_crypto_cipher_xform *cipher;
2699a2dd95SBruce Richardson 	struct rte_crypto_aead_xform *aead;
2799a2dd95SBruce Richardson };
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson /*
3099a2dd95SBruce Richardson  * helper routine, fills internal crypto_xform structure.
3199a2dd95SBruce Richardson  */
3299a2dd95SBruce Richardson static int
3399a2dd95SBruce Richardson fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
3499a2dd95SBruce Richardson 	const struct rte_ipsec_sa_prm *prm)
3599a2dd95SBruce Richardson {
3699a2dd95SBruce Richardson 	struct rte_crypto_sym_xform *xf, *xfn;
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson 	memset(xform, 0, sizeof(*xform));
3999a2dd95SBruce Richardson 
4099a2dd95SBruce Richardson 	xf = prm->crypto_xform;
4199a2dd95SBruce Richardson 	if (xf == NULL)
4299a2dd95SBruce Richardson 		return -EINVAL;
4399a2dd95SBruce Richardson 
4499a2dd95SBruce Richardson 	xfn = xf->next;
4599a2dd95SBruce Richardson 
4699a2dd95SBruce Richardson 	/* for AEAD just one xform required */
4799a2dd95SBruce Richardson 	if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
4899a2dd95SBruce Richardson 		if (xfn != NULL)
4999a2dd95SBruce Richardson 			return -EINVAL;
5099a2dd95SBruce Richardson 		xform->aead = &xf->aead;
51c99d2619SRadu Nicolau 
52c99d2619SRadu Nicolau 	/* GMAC has only auth */
53c99d2619SRadu Nicolau 	} else if (xf->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
54c99d2619SRadu Nicolau 			xf->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) {
55c99d2619SRadu Nicolau 		if (xfn != NULL)
56c99d2619SRadu Nicolau 			return -EINVAL;
57c99d2619SRadu Nicolau 		xform->auth = &xf->auth;
58c99d2619SRadu Nicolau 		xform->cipher = &xfn->cipher;
59c99d2619SRadu Nicolau 
6099a2dd95SBruce Richardson 	/*
6199a2dd95SBruce Richardson 	 * CIPHER+AUTH xforms are expected in strict order,
6299a2dd95SBruce Richardson 	 * depending on SA direction:
6399a2dd95SBruce Richardson 	 * inbound: AUTH+CIPHER
6499a2dd95SBruce Richardson 	 * outbound: CIPHER+AUTH
6599a2dd95SBruce Richardson 	 */
6699a2dd95SBruce Richardson 	} else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
6799a2dd95SBruce Richardson 
6899a2dd95SBruce Richardson 		/* wrong order or no cipher */
6999a2dd95SBruce Richardson 		if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
7099a2dd95SBruce Richardson 				xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
7199a2dd95SBruce Richardson 			return -EINVAL;
7299a2dd95SBruce Richardson 
7399a2dd95SBruce Richardson 		xform->auth = &xf->auth;
7499a2dd95SBruce Richardson 		xform->cipher = &xfn->cipher;
7599a2dd95SBruce Richardson 
7699a2dd95SBruce Richardson 	} else {
7799a2dd95SBruce Richardson 
7899a2dd95SBruce Richardson 		/* wrong order or no auth */
7999a2dd95SBruce Richardson 		if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
8099a2dd95SBruce Richardson 				xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
8199a2dd95SBruce Richardson 			return -EINVAL;
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 		xform->cipher = &xf->cipher;
8499a2dd95SBruce Richardson 		xform->auth = &xfn->auth;
8599a2dd95SBruce Richardson 	}
8699a2dd95SBruce Richardson 
8799a2dd95SBruce Richardson 	return 0;
8899a2dd95SBruce Richardson }
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson uint64_t
9199a2dd95SBruce Richardson rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
9299a2dd95SBruce Richardson {
9399a2dd95SBruce Richardson 	return sa->type;
9499a2dd95SBruce Richardson }
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson /**
9799a2dd95SBruce Richardson  * Based on number of buckets calculated required size for the
9899a2dd95SBruce Richardson  * structure that holds replay window and sequence number (RSN) information.
9999a2dd95SBruce Richardson  */
10099a2dd95SBruce Richardson static size_t
10199a2dd95SBruce Richardson rsn_size(uint32_t nb_bucket)
10299a2dd95SBruce Richardson {
10399a2dd95SBruce Richardson 	size_t sz;
10499a2dd95SBruce Richardson 	struct replay_sqn *rsn;
10599a2dd95SBruce Richardson 
10699a2dd95SBruce Richardson 	sz = sizeof(*rsn) + nb_bucket * sizeof(rsn->window[0]);
10799a2dd95SBruce Richardson 	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
10899a2dd95SBruce Richardson 	return sz;
10999a2dd95SBruce Richardson }
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson /*
11299a2dd95SBruce Richardson  * for given size, calculate required number of buckets.
11399a2dd95SBruce Richardson  */
11499a2dd95SBruce Richardson static uint32_t
11599a2dd95SBruce Richardson replay_num_bucket(uint32_t wsz)
11699a2dd95SBruce Richardson {
11799a2dd95SBruce Richardson 	uint32_t nb;
11899a2dd95SBruce Richardson 
11999a2dd95SBruce Richardson 	nb = rte_align32pow2(RTE_ALIGN_MUL_CEIL(wsz, WINDOW_BUCKET_SIZE) /
12099a2dd95SBruce Richardson 		WINDOW_BUCKET_SIZE);
12199a2dd95SBruce Richardson 	nb = RTE_MAX(nb, (uint32_t)WINDOW_BUCKET_MIN);
12299a2dd95SBruce Richardson 
12399a2dd95SBruce Richardson 	return nb;
12499a2dd95SBruce Richardson }
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson static int32_t
12799a2dd95SBruce Richardson ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
12899a2dd95SBruce Richardson {
12999a2dd95SBruce Richardson 	uint32_t n, sz, wsz;
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson 	wsz = *wnd_sz;
13299a2dd95SBruce Richardson 	n = 0;
13399a2dd95SBruce Richardson 
13499a2dd95SBruce Richardson 	if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
13599a2dd95SBruce Richardson 
13699a2dd95SBruce Richardson 		/*
13799a2dd95SBruce Richardson 		 * RFC 4303 recommends 64 as minimum window size.
13899a2dd95SBruce Richardson 		 * there is no point to use ESN mode without SQN window,
13999a2dd95SBruce Richardson 		 * so make sure we have at least 64 window when ESN is enalbed.
14099a2dd95SBruce Richardson 		 */
14199a2dd95SBruce Richardson 		wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
14299a2dd95SBruce Richardson 			RTE_IPSEC_SATP_ESN_DISABLE) ?
14399a2dd95SBruce Richardson 			wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
14499a2dd95SBruce Richardson 		if (wsz != 0)
14599a2dd95SBruce Richardson 			n = replay_num_bucket(wsz);
14699a2dd95SBruce Richardson 	}
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	if (n > WINDOW_BUCKET_MAX)
14999a2dd95SBruce Richardson 		return -EINVAL;
15099a2dd95SBruce Richardson 
15199a2dd95SBruce Richardson 	*wnd_sz = wsz;
15299a2dd95SBruce Richardson 	*nb_bucket = n;
15399a2dd95SBruce Richardson 
15499a2dd95SBruce Richardson 	sz = rsn_size(n);
15599a2dd95SBruce Richardson 	if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
15699a2dd95SBruce Richardson 		sz *= REPLAY_SQN_NUM;
15799a2dd95SBruce Richardson 
15899a2dd95SBruce Richardson 	sz += sizeof(struct rte_ipsec_sa);
15999a2dd95SBruce Richardson 	return sz;
16099a2dd95SBruce Richardson }
16199a2dd95SBruce Richardson 
16299a2dd95SBruce Richardson void
16399a2dd95SBruce Richardson rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
16499a2dd95SBruce Richardson {
16599a2dd95SBruce Richardson 	memset(sa, 0, sa->size);
16699a2dd95SBruce Richardson }
16799a2dd95SBruce Richardson 
16899a2dd95SBruce Richardson /*
16999a2dd95SBruce Richardson  * Determine expected SA type based on input parameters.
17099a2dd95SBruce Richardson  */
17199a2dd95SBruce Richardson static int
17299a2dd95SBruce Richardson fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
17399a2dd95SBruce Richardson {
17499a2dd95SBruce Richardson 	uint64_t tp;
17599a2dd95SBruce Richardson 
17699a2dd95SBruce Richardson 	tp = 0;
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson 	if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
17999a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_PROTO_AH;
18099a2dd95SBruce Richardson 	else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
18199a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_PROTO_ESP;
18299a2dd95SBruce Richardson 	else
18399a2dd95SBruce Richardson 		return -EINVAL;
18499a2dd95SBruce Richardson 
18599a2dd95SBruce Richardson 	if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
18699a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_DIR_OB;
18799a2dd95SBruce Richardson 	else if (prm->ipsec_xform.direction ==
18899a2dd95SBruce Richardson 			RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
18999a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_DIR_IB;
19099a2dd95SBruce Richardson 	else
19199a2dd95SBruce Richardson 		return -EINVAL;
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson 	if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
19499a2dd95SBruce Richardson 		if (prm->ipsec_xform.tunnel.type ==
19599a2dd95SBruce Richardson 				RTE_SECURITY_IPSEC_TUNNEL_IPV4)
19699a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
19799a2dd95SBruce Richardson 		else if (prm->ipsec_xform.tunnel.type ==
19899a2dd95SBruce Richardson 				RTE_SECURITY_IPSEC_TUNNEL_IPV6)
19999a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
20099a2dd95SBruce Richardson 		else
20199a2dd95SBruce Richardson 			return -EINVAL;
20299a2dd95SBruce Richardson 
20399a2dd95SBruce Richardson 		if (prm->tun.next_proto == IPPROTO_IPIP)
20499a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_IPV4;
20599a2dd95SBruce Richardson 		else if (prm->tun.next_proto == IPPROTO_IPV6)
20699a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_IPV6;
20799a2dd95SBruce Richardson 		else
20899a2dd95SBruce Richardson 			return -EINVAL;
20999a2dd95SBruce Richardson 	} else if (prm->ipsec_xform.mode ==
21099a2dd95SBruce Richardson 			RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
21199a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_MODE_TRANS;
21299a2dd95SBruce Richardson 		if (prm->trs.proto == IPPROTO_IPIP)
21399a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_IPV4;
21499a2dd95SBruce Richardson 		else if (prm->trs.proto == IPPROTO_IPV6)
21599a2dd95SBruce Richardson 			tp |= RTE_IPSEC_SATP_IPV6;
21699a2dd95SBruce Richardson 		else
21799a2dd95SBruce Richardson 			return -EINVAL;
21899a2dd95SBruce Richardson 	} else
21999a2dd95SBruce Richardson 		return -EINVAL;
22099a2dd95SBruce Richardson 
22101eef590SRadu Nicolau 	/* check for UDP encapsulation flag */
22201eef590SRadu Nicolau 	if (prm->ipsec_xform.options.udp_encap == 1)
22301eef590SRadu Nicolau 		tp |= RTE_IPSEC_SATP_NATT_ENABLE;
22401eef590SRadu Nicolau 
22599a2dd95SBruce Richardson 	/* check for ESN flag */
22699a2dd95SBruce Richardson 	if (prm->ipsec_xform.options.esn == 0)
22799a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_ESN_DISABLE;
22899a2dd95SBruce Richardson 	else
22999a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_ESN_ENABLE;
23099a2dd95SBruce Richardson 
23199a2dd95SBruce Richardson 	/* check for ECN flag */
23299a2dd95SBruce Richardson 	if (prm->ipsec_xform.options.ecn == 0)
23399a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_ECN_DISABLE;
23499a2dd95SBruce Richardson 	else
23599a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_ECN_ENABLE;
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	/* check for DSCP flag */
23899a2dd95SBruce Richardson 	if (prm->ipsec_xform.options.copy_dscp == 0)
23999a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_DSCP_DISABLE;
24099a2dd95SBruce Richardson 	else
24199a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_DSCP_ENABLE;
24299a2dd95SBruce Richardson 
24399a2dd95SBruce Richardson 	/* interpret flags */
24499a2dd95SBruce Richardson 	if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
24599a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_SQN_ATOM;
24699a2dd95SBruce Richardson 	else
24799a2dd95SBruce Richardson 		tp |= RTE_IPSEC_SATP_SQN_RAW;
24899a2dd95SBruce Richardson 
24999a2dd95SBruce Richardson 	*type = tp;
25099a2dd95SBruce Richardson 	return 0;
25199a2dd95SBruce Richardson }
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson /*
25499a2dd95SBruce Richardson  * Init ESP inbound specific things.
25599a2dd95SBruce Richardson  */
25699a2dd95SBruce Richardson static void
25799a2dd95SBruce Richardson esp_inb_init(struct rte_ipsec_sa *sa)
25899a2dd95SBruce Richardson {
25999a2dd95SBruce Richardson 	/* these params may differ with new algorithms support */
26099a2dd95SBruce Richardson 	sa->ctp.cipher.offset = sizeof(struct rte_esp_hdr) + sa->iv_len;
26199a2dd95SBruce Richardson 	sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
26299a2dd95SBruce Richardson 
26399a2dd95SBruce Richardson 	/*
264c99d2619SRadu Nicolau 	 * for AEAD algorithms we can assume that
26599a2dd95SBruce Richardson 	 * auth and cipher offsets would be equal.
26699a2dd95SBruce Richardson 	 */
26799a2dd95SBruce Richardson 	switch (sa->algo_type) {
26899a2dd95SBruce Richardson 	case ALGO_TYPE_AES_GCM:
269c99d2619SRadu Nicolau 	case ALGO_TYPE_AES_CCM:
270c99d2619SRadu Nicolau 	case ALGO_TYPE_CHACHA20_POLY1305:
27199a2dd95SBruce Richardson 		sa->ctp.auth.raw = sa->ctp.cipher.raw;
27299a2dd95SBruce Richardson 		break;
27399a2dd95SBruce Richardson 	default:
27499a2dd95SBruce Richardson 		sa->ctp.auth.offset = 0;
27599a2dd95SBruce Richardson 		sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
27699a2dd95SBruce Richardson 		sa->cofs.ofs.cipher.tail = sa->sqh_len;
27799a2dd95SBruce Richardson 		break;
27899a2dd95SBruce Richardson 	}
27999a2dd95SBruce Richardson 
28099a2dd95SBruce Richardson 	sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
28199a2dd95SBruce Richardson }
28299a2dd95SBruce Richardson 
28399a2dd95SBruce Richardson /*
28499a2dd95SBruce Richardson  * Init ESP inbound tunnel specific things.
28599a2dd95SBruce Richardson  */
28699a2dd95SBruce Richardson static void
28799a2dd95SBruce Richardson esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
28899a2dd95SBruce Richardson {
28999a2dd95SBruce Richardson 	sa->proto = prm->tun.next_proto;
29099a2dd95SBruce Richardson 	esp_inb_init(sa);
29199a2dd95SBruce Richardson }
29299a2dd95SBruce Richardson 
29399a2dd95SBruce Richardson /*
29499a2dd95SBruce Richardson  * Init ESP outbound specific things.
29599a2dd95SBruce Richardson  */
29699a2dd95SBruce Richardson static void
2972ed40da8SRadu Nicolau esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen, uint64_t sqn)
29899a2dd95SBruce Richardson {
29999a2dd95SBruce Richardson 	uint8_t algo_type;
30099a2dd95SBruce Richardson 
3012ed40da8SRadu Nicolau 	sa->sqn.outb = sqn > 1 ? sqn : 1;
30299a2dd95SBruce Richardson 
30399a2dd95SBruce Richardson 	algo_type = sa->algo_type;
30499a2dd95SBruce Richardson 
30599a2dd95SBruce Richardson 	/*
30699a2dd95SBruce Richardson 	 * Setup auth and cipher length and offset.
30799a2dd95SBruce Richardson 	 * these params may differ with new algorithms support
30899a2dd95SBruce Richardson 	 */
30999a2dd95SBruce Richardson 
31099a2dd95SBruce Richardson 	switch (algo_type) {
31199a2dd95SBruce Richardson 	case ALGO_TYPE_AES_GCM:
312c99d2619SRadu Nicolau 	case ALGO_TYPE_AES_CCM:
313c99d2619SRadu Nicolau 	case ALGO_TYPE_CHACHA20_POLY1305:
31499a2dd95SBruce Richardson 	case ALGO_TYPE_AES_CTR:
31599a2dd95SBruce Richardson 	case ALGO_TYPE_NULL:
31699a2dd95SBruce Richardson 		sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr) +
31799a2dd95SBruce Richardson 			sa->iv_len;
31899a2dd95SBruce Richardson 		sa->ctp.cipher.length = 0;
31999a2dd95SBruce Richardson 		break;
32099a2dd95SBruce Richardson 	case ALGO_TYPE_AES_CBC:
32199a2dd95SBruce Richardson 	case ALGO_TYPE_3DES_CBC:
32299a2dd95SBruce Richardson 		sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr);
32399a2dd95SBruce Richardson 		sa->ctp.cipher.length = sa->iv_len;
32499a2dd95SBruce Richardson 		break;
325c99d2619SRadu Nicolau 	case ALGO_TYPE_AES_GMAC:
326c99d2619SRadu Nicolau 		sa->ctp.cipher.offset = 0;
327c99d2619SRadu Nicolau 		sa->ctp.cipher.length = 0;
328c99d2619SRadu Nicolau 		break;
32999a2dd95SBruce Richardson 	}
33099a2dd95SBruce Richardson 
33199a2dd95SBruce Richardson 	/*
332c99d2619SRadu Nicolau 	 * for AEAD algorithms we can assume that
33399a2dd95SBruce Richardson 	 * auth and cipher offsets would be equal.
33499a2dd95SBruce Richardson 	 */
33599a2dd95SBruce Richardson 	switch (algo_type) {
33699a2dd95SBruce Richardson 	case ALGO_TYPE_AES_GCM:
337c99d2619SRadu Nicolau 	case ALGO_TYPE_AES_CCM:
338c99d2619SRadu Nicolau 	case ALGO_TYPE_CHACHA20_POLY1305:
33999a2dd95SBruce Richardson 		sa->ctp.auth.raw = sa->ctp.cipher.raw;
34099a2dd95SBruce Richardson 		break;
34199a2dd95SBruce Richardson 	default:
34299a2dd95SBruce Richardson 		sa->ctp.auth.offset = hlen;
34399a2dd95SBruce Richardson 		sa->ctp.auth.length = sizeof(struct rte_esp_hdr) +
34499a2dd95SBruce Richardson 			sa->iv_len + sa->sqh_len;
34599a2dd95SBruce Richardson 		break;
34699a2dd95SBruce Richardson 	}
34799a2dd95SBruce Richardson 
34899a2dd95SBruce Richardson 	sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
34999a2dd95SBruce Richardson 	sa->cofs.ofs.cipher.tail = (sa->ctp.auth.offset + sa->ctp.auth.length) -
35099a2dd95SBruce Richardson 			(sa->ctp.cipher.offset + sa->ctp.cipher.length);
35199a2dd95SBruce Richardson }
35299a2dd95SBruce Richardson 
35399a2dd95SBruce Richardson /*
35499a2dd95SBruce Richardson  * Init ESP outbound tunnel specific things.
35599a2dd95SBruce Richardson  */
35699a2dd95SBruce Richardson static void
35799a2dd95SBruce Richardson esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
35899a2dd95SBruce Richardson {
35999a2dd95SBruce Richardson 	sa->proto = prm->tun.next_proto;
36099a2dd95SBruce Richardson 	sa->hdr_len = prm->tun.hdr_len;
36199a2dd95SBruce Richardson 	sa->hdr_l3_off = prm->tun.hdr_l3_off;
36299a2dd95SBruce Richardson 
36301eef590SRadu Nicolau 	memcpy(sa->hdr, prm->tun.hdr, prm->tun.hdr_len);
36401eef590SRadu Nicolau 
36501eef590SRadu Nicolau 	/* insert UDP header if UDP encapsulation is inabled */
36601eef590SRadu Nicolau 	if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
36701eef590SRadu Nicolau 		struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
36801eef590SRadu Nicolau 				&sa->hdr[prm->tun.hdr_len];
36901eef590SRadu Nicolau 		sa->hdr_len += sizeof(struct rte_udp_hdr);
37001eef590SRadu Nicolau 		udph->src_port = prm->ipsec_xform.udp.sport;
37101eef590SRadu Nicolau 		udph->dst_port = prm->ipsec_xform.udp.dport;
37201eef590SRadu Nicolau 		udph->dgram_cksum = 0;
37301eef590SRadu Nicolau 	}
37401eef590SRadu Nicolau 
37599a2dd95SBruce Richardson 	/* update l2_len and l3_len fields for outbound mbuf */
37699a2dd95SBruce Richardson 	sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
37799a2dd95SBruce Richardson 		sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
37899a2dd95SBruce Richardson 
3792ed40da8SRadu Nicolau 	esp_outb_init(sa, sa->hdr_len, prm->ipsec_xform.esn.value);
38099a2dd95SBruce Richardson }
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson /*
38399a2dd95SBruce Richardson  * helper function, init SA structure.
38499a2dd95SBruce Richardson  */
38599a2dd95SBruce Richardson static int
38699a2dd95SBruce Richardson esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
38799a2dd95SBruce Richardson 	const struct crypto_xform *cxf)
38899a2dd95SBruce Richardson {
38999a2dd95SBruce Richardson 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
39001eef590SRadu Nicolau 				RTE_IPSEC_SATP_MODE_MASK |
39101eef590SRadu Nicolau 				RTE_IPSEC_SATP_NATT_MASK;
39299a2dd95SBruce Richardson 
39399a2dd95SBruce Richardson 	if (prm->ipsec_xform.options.ecn)
39499a2dd95SBruce Richardson 		sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
39599a2dd95SBruce Richardson 
39699a2dd95SBruce Richardson 	if (prm->ipsec_xform.options.copy_dscp)
39799a2dd95SBruce Richardson 		sa->tos_mask |= RTE_IPV4_HDR_DSCP_MASK;
39899a2dd95SBruce Richardson 
39999a2dd95SBruce Richardson 	if (cxf->aead != NULL) {
40099a2dd95SBruce Richardson 		switch (cxf->aead->algo) {
40199a2dd95SBruce Richardson 		case RTE_CRYPTO_AEAD_AES_GCM:
40299a2dd95SBruce Richardson 			/* RFC 4106 */
40399a2dd95SBruce Richardson 			sa->aad_len = sizeof(struct aead_gcm_aad);
40499a2dd95SBruce Richardson 			sa->icv_len = cxf->aead->digest_length;
40599a2dd95SBruce Richardson 			sa->iv_ofs = cxf->aead->iv.offset;
40699a2dd95SBruce Richardson 			sa->iv_len = sizeof(uint64_t);
40799a2dd95SBruce Richardson 			sa->pad_align = IPSEC_PAD_AES_GCM;
40899a2dd95SBruce Richardson 			sa->algo_type = ALGO_TYPE_AES_GCM;
40999a2dd95SBruce Richardson 			break;
410c99d2619SRadu Nicolau 		case RTE_CRYPTO_AEAD_AES_CCM:
411c99d2619SRadu Nicolau 			/* RFC 4309 */
412c99d2619SRadu Nicolau 			sa->aad_len = sizeof(struct aead_ccm_aad);
413c99d2619SRadu Nicolau 			sa->icv_len = cxf->aead->digest_length;
414c99d2619SRadu Nicolau 			sa->iv_ofs = cxf->aead->iv.offset;
415c99d2619SRadu Nicolau 			sa->iv_len = sizeof(uint64_t);
416c99d2619SRadu Nicolau 			sa->pad_align = IPSEC_PAD_AES_CCM;
417c99d2619SRadu Nicolau 			sa->algo_type = ALGO_TYPE_AES_CCM;
418c99d2619SRadu Nicolau 			break;
419c99d2619SRadu Nicolau 		case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
420c99d2619SRadu Nicolau 			/* RFC 7634 & 8439*/
421c99d2619SRadu Nicolau 			sa->aad_len = sizeof(struct aead_chacha20_poly1305_aad);
422c99d2619SRadu Nicolau 			sa->icv_len = cxf->aead->digest_length;
423c99d2619SRadu Nicolau 			sa->iv_ofs = cxf->aead->iv.offset;
424c99d2619SRadu Nicolau 			sa->iv_len = sizeof(uint64_t);
425c99d2619SRadu Nicolau 			sa->pad_align = IPSEC_PAD_CHACHA20_POLY1305;
426c99d2619SRadu Nicolau 			sa->algo_type = ALGO_TYPE_CHACHA20_POLY1305;
427c99d2619SRadu Nicolau 			break;
42899a2dd95SBruce Richardson 		default:
42999a2dd95SBruce Richardson 			return -EINVAL;
43099a2dd95SBruce Richardson 		}
431c99d2619SRadu Nicolau 	} else if (cxf->auth->algo == RTE_CRYPTO_AUTH_AES_GMAC) {
432c99d2619SRadu Nicolau 		/* RFC 4543 */
433c99d2619SRadu Nicolau 		/* AES-GMAC is a special case of auth that needs IV */
434c99d2619SRadu Nicolau 		sa->pad_align = IPSEC_PAD_AES_GMAC;
435c99d2619SRadu Nicolau 		sa->iv_len = sizeof(uint64_t);
436c99d2619SRadu Nicolau 		sa->icv_len = cxf->auth->digest_length;
437c99d2619SRadu Nicolau 		sa->iv_ofs = cxf->auth->iv.offset;
438c99d2619SRadu Nicolau 		sa->algo_type = ALGO_TYPE_AES_GMAC;
439c99d2619SRadu Nicolau 
44099a2dd95SBruce Richardson 	} else {
44199a2dd95SBruce Richardson 		sa->icv_len = cxf->auth->digest_length;
44299a2dd95SBruce Richardson 		sa->iv_ofs = cxf->cipher->iv.offset;
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson 		switch (cxf->cipher->algo) {
44599a2dd95SBruce Richardson 		case RTE_CRYPTO_CIPHER_NULL:
44699a2dd95SBruce Richardson 			sa->pad_align = IPSEC_PAD_NULL;
44799a2dd95SBruce Richardson 			sa->iv_len = 0;
44899a2dd95SBruce Richardson 			sa->algo_type = ALGO_TYPE_NULL;
44999a2dd95SBruce Richardson 			break;
45099a2dd95SBruce Richardson 
45199a2dd95SBruce Richardson 		case RTE_CRYPTO_CIPHER_AES_CBC:
45299a2dd95SBruce Richardson 			sa->pad_align = IPSEC_PAD_AES_CBC;
45399a2dd95SBruce Richardson 			sa->iv_len = IPSEC_MAX_IV_SIZE;
45499a2dd95SBruce Richardson 			sa->algo_type = ALGO_TYPE_AES_CBC;
45599a2dd95SBruce Richardson 			break;
45699a2dd95SBruce Richardson 
45799a2dd95SBruce Richardson 		case RTE_CRYPTO_CIPHER_AES_CTR:
45899a2dd95SBruce Richardson 			/* RFC 3686 */
45999a2dd95SBruce Richardson 			sa->pad_align = IPSEC_PAD_AES_CTR;
46099a2dd95SBruce Richardson 			sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
46199a2dd95SBruce Richardson 			sa->algo_type = ALGO_TYPE_AES_CTR;
46299a2dd95SBruce Richardson 			break;
46399a2dd95SBruce Richardson 
46499a2dd95SBruce Richardson 		case RTE_CRYPTO_CIPHER_3DES_CBC:
46599a2dd95SBruce Richardson 			/* RFC 1851 */
46699a2dd95SBruce Richardson 			sa->pad_align = IPSEC_PAD_3DES_CBC;
46799a2dd95SBruce Richardson 			sa->iv_len = IPSEC_3DES_IV_SIZE;
46899a2dd95SBruce Richardson 			sa->algo_type = ALGO_TYPE_3DES_CBC;
46999a2dd95SBruce Richardson 			break;
47099a2dd95SBruce Richardson 
47199a2dd95SBruce Richardson 		default:
47299a2dd95SBruce Richardson 			return -EINVAL;
47399a2dd95SBruce Richardson 		}
47499a2dd95SBruce Richardson 	}
47599a2dd95SBruce Richardson 
476c99d2619SRadu Nicolau 	sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
47799a2dd95SBruce Richardson 	sa->udata = prm->userdata;
47899a2dd95SBruce Richardson 	sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
47999a2dd95SBruce Richardson 	sa->salt = prm->ipsec_xform.salt;
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson 	/* preserve all values except l2_len and l3_len */
48299a2dd95SBruce Richardson 	sa->tx_offload.msk =
48399a2dd95SBruce Richardson 		~rte_mbuf_tx_offload(MBUF_MAX_L2_LEN, MBUF_MAX_L3_LEN,
48499a2dd95SBruce Richardson 				0, 0, 0, 0, 0);
48599a2dd95SBruce Richardson 
48699a2dd95SBruce Richardson 	switch (sa->type & msk) {
48799a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
48899a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
48999a2dd95SBruce Richardson 		esp_inb_tun_init(sa, prm);
49099a2dd95SBruce Richardson 		break;
49199a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
49299a2dd95SBruce Richardson 		esp_inb_init(sa);
49399a2dd95SBruce Richardson 		break;
49401eef590SRadu Nicolau 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4 |
49501eef590SRadu Nicolau 			RTE_IPSEC_SATP_NATT_ENABLE):
49601eef590SRadu Nicolau 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6 |
49701eef590SRadu Nicolau 			RTE_IPSEC_SATP_NATT_ENABLE):
49899a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
49999a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
50099a2dd95SBruce Richardson 		esp_outb_tun_init(sa, prm);
50199a2dd95SBruce Richardson 		break;
50201eef590SRadu Nicolau 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS |
50301eef590SRadu Nicolau 			RTE_IPSEC_SATP_NATT_ENABLE):
50499a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
5052ed40da8SRadu Nicolau 		esp_outb_init(sa, 0, prm->ipsec_xform.esn.value);
50699a2dd95SBruce Richardson 		break;
50799a2dd95SBruce Richardson 	}
50899a2dd95SBruce Richardson 
50999a2dd95SBruce Richardson 	return 0;
51099a2dd95SBruce Richardson }
51199a2dd95SBruce Richardson 
51299a2dd95SBruce Richardson /*
51399a2dd95SBruce Richardson  * helper function, init SA replay structure.
51499a2dd95SBruce Richardson  */
51599a2dd95SBruce Richardson static void
5162ed40da8SRadu Nicolau fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket,
5172ed40da8SRadu Nicolau 	uint64_t sqn)
51899a2dd95SBruce Richardson {
51999a2dd95SBruce Richardson 	sa->replay.win_sz = wnd_sz;
52099a2dd95SBruce Richardson 	sa->replay.nb_bucket = nb_bucket;
52199a2dd95SBruce Richardson 	sa->replay.bucket_index_mask = nb_bucket - 1;
52299a2dd95SBruce Richardson 	sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
5232ed40da8SRadu Nicolau 	sa->sqn.inb.rsn[0]->sqn = sqn;
5242ed40da8SRadu Nicolau 	if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM) {
52599a2dd95SBruce Richardson 		sa->sqn.inb.rsn[1] = (struct replay_sqn *)
52699a2dd95SBruce Richardson 			((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
5272ed40da8SRadu Nicolau 		sa->sqn.inb.rsn[1]->sqn = sqn;
5282ed40da8SRadu Nicolau 	}
52999a2dd95SBruce Richardson }
53099a2dd95SBruce Richardson 
53199a2dd95SBruce Richardson int
53299a2dd95SBruce Richardson rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
53399a2dd95SBruce Richardson {
53499a2dd95SBruce Richardson 	uint64_t type;
53599a2dd95SBruce Richardson 	uint32_t nb, wsz;
53699a2dd95SBruce Richardson 	int32_t rc;
53799a2dd95SBruce Richardson 
53899a2dd95SBruce Richardson 	if (prm == NULL)
53999a2dd95SBruce Richardson 		return -EINVAL;
54099a2dd95SBruce Richardson 
54199a2dd95SBruce Richardson 	/* determine SA type */
54299a2dd95SBruce Richardson 	rc = fill_sa_type(prm, &type);
54399a2dd95SBruce Richardson 	if (rc != 0)
54499a2dd95SBruce Richardson 		return rc;
54599a2dd95SBruce Richardson 
54699a2dd95SBruce Richardson 	/* determine required size */
54799a2dd95SBruce Richardson 	wsz = prm->ipsec_xform.replay_win_sz;
54899a2dd95SBruce Richardson 	return ipsec_sa_size(type, &wsz, &nb);
54999a2dd95SBruce Richardson }
55099a2dd95SBruce Richardson 
55199a2dd95SBruce Richardson int
55299a2dd95SBruce Richardson rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
55399a2dd95SBruce Richardson 	uint32_t size)
55499a2dd95SBruce Richardson {
55599a2dd95SBruce Richardson 	int32_t rc, sz;
55699a2dd95SBruce Richardson 	uint32_t nb, wsz;
55799a2dd95SBruce Richardson 	uint64_t type;
55899a2dd95SBruce Richardson 	struct crypto_xform cxf;
55999a2dd95SBruce Richardson 
56099a2dd95SBruce Richardson 	if (sa == NULL || prm == NULL)
56199a2dd95SBruce Richardson 		return -EINVAL;
56299a2dd95SBruce Richardson 
56399a2dd95SBruce Richardson 	/* determine SA type */
56499a2dd95SBruce Richardson 	rc = fill_sa_type(prm, &type);
56599a2dd95SBruce Richardson 	if (rc != 0)
56699a2dd95SBruce Richardson 		return rc;
56799a2dd95SBruce Richardson 
56899a2dd95SBruce Richardson 	/* determine required size */
56999a2dd95SBruce Richardson 	wsz = prm->ipsec_xform.replay_win_sz;
57099a2dd95SBruce Richardson 	sz = ipsec_sa_size(type, &wsz, &nb);
57199a2dd95SBruce Richardson 	if (sz < 0)
57299a2dd95SBruce Richardson 		return sz;
57399a2dd95SBruce Richardson 	else if (size < (uint32_t)sz)
57499a2dd95SBruce Richardson 		return -ENOSPC;
57599a2dd95SBruce Richardson 
57699a2dd95SBruce Richardson 	/* only esp is supported right now */
57799a2dd95SBruce Richardson 	if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
57899a2dd95SBruce Richardson 		return -EINVAL;
57999a2dd95SBruce Richardson 
58001eef590SRadu Nicolau 	if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
58101eef590SRadu Nicolau 		uint32_t hlen = prm->tun.hdr_len;
58201eef590SRadu Nicolau 		if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE)
58301eef590SRadu Nicolau 			hlen += sizeof(struct rte_udp_hdr);
58401eef590SRadu Nicolau 		if (hlen > sizeof(sa->hdr))
58599a2dd95SBruce Richardson 			return -EINVAL;
58601eef590SRadu Nicolau 	}
58799a2dd95SBruce Richardson 
58899a2dd95SBruce Richardson 	rc = fill_crypto_xform(&cxf, type, prm);
58999a2dd95SBruce Richardson 	if (rc != 0)
59099a2dd95SBruce Richardson 		return rc;
59199a2dd95SBruce Richardson 
59299a2dd95SBruce Richardson 	/* initialize SA */
59399a2dd95SBruce Richardson 
59499a2dd95SBruce Richardson 	memset(sa, 0, sz);
59599a2dd95SBruce Richardson 	sa->type = type;
59699a2dd95SBruce Richardson 	sa->size = sz;
59799a2dd95SBruce Richardson 
59899a2dd95SBruce Richardson 	/* check for ESN flag */
59999a2dd95SBruce Richardson 	sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
60099a2dd95SBruce Richardson 		UINT32_MAX : UINT64_MAX;
60199a2dd95SBruce Richardson 
60299a2dd95SBruce Richardson 	rc = esp_sa_init(sa, prm, &cxf);
60399a2dd95SBruce Richardson 	if (rc != 0)
60499a2dd95SBruce Richardson 		rte_ipsec_sa_fini(sa);
60599a2dd95SBruce Richardson 
60699a2dd95SBruce Richardson 	/* fill replay window related fields */
60799a2dd95SBruce Richardson 	if (nb != 0)
6082ed40da8SRadu Nicolau 		fill_sa_replay(sa, wsz, nb, prm->ipsec_xform.esn.value);
60999a2dd95SBruce Richardson 
61099a2dd95SBruce Richardson 	return sz;
61199a2dd95SBruce Richardson }
61299a2dd95SBruce Richardson 
61399a2dd95SBruce Richardson /*
61499a2dd95SBruce Richardson  *  setup crypto ops for LOOKASIDE_PROTO type of devices.
61599a2dd95SBruce Richardson  */
61699a2dd95SBruce Richardson static inline void
61799a2dd95SBruce Richardson lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
61899a2dd95SBruce Richardson 	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
61999a2dd95SBruce Richardson {
62099a2dd95SBruce Richardson 	uint32_t i;
62199a2dd95SBruce Richardson 	struct rte_crypto_sym_op *sop;
62299a2dd95SBruce Richardson 
62399a2dd95SBruce Richardson 	for (i = 0; i != num; i++) {
62499a2dd95SBruce Richardson 		sop = cop[i]->sym;
62599a2dd95SBruce Richardson 		cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
62699a2dd95SBruce Richardson 		cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
62799a2dd95SBruce Richardson 		cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
62899a2dd95SBruce Richardson 		sop->m_src = mb[i];
62999a2dd95SBruce Richardson 		__rte_security_attach_session(sop, ss->security.ses);
63099a2dd95SBruce Richardson 	}
63199a2dd95SBruce Richardson }
63299a2dd95SBruce Richardson 
63399a2dd95SBruce Richardson /*
63499a2dd95SBruce Richardson  *  setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
63599a2dd95SBruce Richardson  *  Note that for LOOKASIDE_PROTO all packet modifications will be
63699a2dd95SBruce Richardson  *  performed by PMD/HW.
63799a2dd95SBruce Richardson  *  SW has only to prepare crypto op.
63899a2dd95SBruce Richardson  */
63999a2dd95SBruce Richardson static uint16_t
64099a2dd95SBruce Richardson lksd_proto_prepare(const struct rte_ipsec_session *ss,
64199a2dd95SBruce Richardson 	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
64299a2dd95SBruce Richardson {
64399a2dd95SBruce Richardson 	lksd_proto_cop_prepare(ss, mb, cop, num);
64499a2dd95SBruce Richardson 	return num;
64599a2dd95SBruce Richardson }
64699a2dd95SBruce Richardson 
64799a2dd95SBruce Richardson /*
64899a2dd95SBruce Richardson  * simplest pkt process routine:
64999a2dd95SBruce Richardson  * all actual processing is already done by HW/PMD,
65099a2dd95SBruce Richardson  * just check mbuf ol_flags.
65199a2dd95SBruce Richardson  * used for:
65299a2dd95SBruce Richardson  * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
65399a2dd95SBruce Richardson  * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
65499a2dd95SBruce Richardson  * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
65599a2dd95SBruce Richardson  */
65699a2dd95SBruce Richardson uint16_t
65799a2dd95SBruce Richardson pkt_flag_process(const struct rte_ipsec_session *ss,
65899a2dd95SBruce Richardson 		struct rte_mbuf *mb[], uint16_t num)
65999a2dd95SBruce Richardson {
66068977baaSRadu Nicolau 	uint32_t i, k, bytes;
66199a2dd95SBruce Richardson 	uint32_t dr[num];
66299a2dd95SBruce Richardson 
66399a2dd95SBruce Richardson 	RTE_SET_USED(ss);
66499a2dd95SBruce Richardson 
66599a2dd95SBruce Richardson 	k = 0;
66668977baaSRadu Nicolau 	bytes = 0;
66799a2dd95SBruce Richardson 	for (i = 0; i != num; i++) {
668*daa02b5cSOlivier Matz 		if ((mb[i]->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED) == 0) {
66999a2dd95SBruce Richardson 			k++;
67068977baaSRadu Nicolau 			bytes += mb[i]->pkt_len;
67168977baaSRadu Nicolau 		}
67299a2dd95SBruce Richardson 		else
67399a2dd95SBruce Richardson 			dr[i - k] = i;
67499a2dd95SBruce Richardson 	}
67599a2dd95SBruce Richardson 
67668977baaSRadu Nicolau 	ss->sa->statistics.count += k;
67768977baaSRadu Nicolau 	ss->sa->statistics.bytes += bytes;
67868977baaSRadu Nicolau 
67999a2dd95SBruce Richardson 	/* handle unprocessed mbufs */
68099a2dd95SBruce Richardson 	if (k != num) {
68199a2dd95SBruce Richardson 		rte_errno = EBADMSG;
68299a2dd95SBruce Richardson 		if (k != 0)
68399a2dd95SBruce Richardson 			move_bad_mbufs(mb, dr, num, num - k);
68499a2dd95SBruce Richardson 	}
68599a2dd95SBruce Richardson 
68699a2dd95SBruce Richardson 	return k;
68799a2dd95SBruce Richardson }
68899a2dd95SBruce Richardson 
68999a2dd95SBruce Richardson /*
69099a2dd95SBruce Richardson  * Select packet processing function for session on LOOKASIDE_NONE
69199a2dd95SBruce Richardson  * type of device.
69299a2dd95SBruce Richardson  */
69399a2dd95SBruce Richardson static int
69499a2dd95SBruce Richardson lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
69599a2dd95SBruce Richardson 		struct rte_ipsec_sa_pkt_func *pf)
69699a2dd95SBruce Richardson {
69799a2dd95SBruce Richardson 	int32_t rc;
69899a2dd95SBruce Richardson 
69999a2dd95SBruce Richardson 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
70099a2dd95SBruce Richardson 			RTE_IPSEC_SATP_MODE_MASK;
70199a2dd95SBruce Richardson 
70299a2dd95SBruce Richardson 	rc = 0;
70399a2dd95SBruce Richardson 	switch (sa->type & msk) {
70499a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
70599a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
70699a2dd95SBruce Richardson 		pf->prepare.async = esp_inb_pkt_prepare;
70799a2dd95SBruce Richardson 		pf->process = esp_inb_tun_pkt_process;
70899a2dd95SBruce Richardson 		break;
70999a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
71099a2dd95SBruce Richardson 		pf->prepare.async = esp_inb_pkt_prepare;
71199a2dd95SBruce Richardson 		pf->process = esp_inb_trs_pkt_process;
71299a2dd95SBruce Richardson 		break;
71399a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
71499a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
71599a2dd95SBruce Richardson 		pf->prepare.async = esp_outb_tun_prepare;
71699a2dd95SBruce Richardson 		pf->process = (sa->sqh_len != 0) ?
71799a2dd95SBruce Richardson 			esp_outb_sqh_process : pkt_flag_process;
71899a2dd95SBruce Richardson 		break;
71999a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
72099a2dd95SBruce Richardson 		pf->prepare.async = esp_outb_trs_prepare;
72199a2dd95SBruce Richardson 		pf->process = (sa->sqh_len != 0) ?
72299a2dd95SBruce Richardson 			esp_outb_sqh_process : pkt_flag_process;
72399a2dd95SBruce Richardson 		break;
72499a2dd95SBruce Richardson 	default:
72599a2dd95SBruce Richardson 		rc = -ENOTSUP;
72699a2dd95SBruce Richardson 	}
72799a2dd95SBruce Richardson 
72899a2dd95SBruce Richardson 	return rc;
72999a2dd95SBruce Richardson }
73099a2dd95SBruce Richardson 
73199a2dd95SBruce Richardson static int
73299a2dd95SBruce Richardson cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
73399a2dd95SBruce Richardson 		struct rte_ipsec_sa_pkt_func *pf)
73499a2dd95SBruce Richardson {
73599a2dd95SBruce Richardson 	int32_t rc;
73699a2dd95SBruce Richardson 
73799a2dd95SBruce Richardson 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
73899a2dd95SBruce Richardson 			RTE_IPSEC_SATP_MODE_MASK;
73999a2dd95SBruce Richardson 
74099a2dd95SBruce Richardson 	rc = 0;
74199a2dd95SBruce Richardson 	switch (sa->type & msk) {
74299a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
74399a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
74499a2dd95SBruce Richardson 		pf->prepare.sync = cpu_inb_pkt_prepare;
74599a2dd95SBruce Richardson 		pf->process = esp_inb_tun_pkt_process;
74699a2dd95SBruce Richardson 		break;
74799a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
74899a2dd95SBruce Richardson 		pf->prepare.sync = cpu_inb_pkt_prepare;
74999a2dd95SBruce Richardson 		pf->process = esp_inb_trs_pkt_process;
75099a2dd95SBruce Richardson 		break;
75199a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
75299a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
75399a2dd95SBruce Richardson 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
75499a2dd95SBruce Richardson 		pf->process = (sa->sqh_len != 0) ?
75599a2dd95SBruce Richardson 			esp_outb_sqh_process : pkt_flag_process;
75699a2dd95SBruce Richardson 		break;
75799a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
75899a2dd95SBruce Richardson 		pf->prepare.sync = cpu_outb_trs_pkt_prepare;
75999a2dd95SBruce Richardson 		pf->process = (sa->sqh_len != 0) ?
76099a2dd95SBruce Richardson 			esp_outb_sqh_process : pkt_flag_process;
76199a2dd95SBruce Richardson 		break;
76299a2dd95SBruce Richardson 	default:
76399a2dd95SBruce Richardson 		rc = -ENOTSUP;
76499a2dd95SBruce Richardson 	}
76599a2dd95SBruce Richardson 
76699a2dd95SBruce Richardson 	return rc;
76799a2dd95SBruce Richardson }
76899a2dd95SBruce Richardson 
76999a2dd95SBruce Richardson /*
77099a2dd95SBruce Richardson  * Select packet processing function for session on INLINE_CRYPTO
77199a2dd95SBruce Richardson  * type of device.
77299a2dd95SBruce Richardson  */
77399a2dd95SBruce Richardson static int
77499a2dd95SBruce Richardson inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
77599a2dd95SBruce Richardson 		struct rte_ipsec_sa_pkt_func *pf)
77699a2dd95SBruce Richardson {
77799a2dd95SBruce Richardson 	int32_t rc;
77899a2dd95SBruce Richardson 
77999a2dd95SBruce Richardson 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
78099a2dd95SBruce Richardson 			RTE_IPSEC_SATP_MODE_MASK;
78199a2dd95SBruce Richardson 
78299a2dd95SBruce Richardson 	rc = 0;
78399a2dd95SBruce Richardson 	switch (sa->type & msk) {
78499a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
78599a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
78699a2dd95SBruce Richardson 		pf->process = inline_inb_tun_pkt_process;
78799a2dd95SBruce Richardson 		break;
78899a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
78999a2dd95SBruce Richardson 		pf->process = inline_inb_trs_pkt_process;
79099a2dd95SBruce Richardson 		break;
79199a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
79299a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
79399a2dd95SBruce Richardson 		pf->process = inline_outb_tun_pkt_process;
79499a2dd95SBruce Richardson 		break;
79599a2dd95SBruce Richardson 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
79699a2dd95SBruce Richardson 		pf->process = inline_outb_trs_pkt_process;
79799a2dd95SBruce Richardson 		break;
79899a2dd95SBruce Richardson 	default:
79999a2dd95SBruce Richardson 		rc = -ENOTSUP;
80099a2dd95SBruce Richardson 	}
80199a2dd95SBruce Richardson 
80299a2dd95SBruce Richardson 	return rc;
80399a2dd95SBruce Richardson }
80499a2dd95SBruce Richardson 
80599a2dd95SBruce Richardson /*
80699a2dd95SBruce Richardson  * Select packet processing function for given session based on SA parameters
80799a2dd95SBruce Richardson  * and type of associated with the session device.
80899a2dd95SBruce Richardson  */
80999a2dd95SBruce Richardson int
81099a2dd95SBruce Richardson ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
81199a2dd95SBruce Richardson 	const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
81299a2dd95SBruce Richardson {
81399a2dd95SBruce Richardson 	int32_t rc;
81499a2dd95SBruce Richardson 
81599a2dd95SBruce Richardson 	rc = 0;
81699a2dd95SBruce Richardson 	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
81799a2dd95SBruce Richardson 
81899a2dd95SBruce Richardson 	switch (ss->type) {
81999a2dd95SBruce Richardson 	case RTE_SECURITY_ACTION_TYPE_NONE:
82099a2dd95SBruce Richardson 		rc = lksd_none_pkt_func_select(sa, pf);
82199a2dd95SBruce Richardson 		break;
82299a2dd95SBruce Richardson 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
82399a2dd95SBruce Richardson 		rc = inline_crypto_pkt_func_select(sa, pf);
82499a2dd95SBruce Richardson 		break;
82599a2dd95SBruce Richardson 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
82699a2dd95SBruce Richardson 		if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
82799a2dd95SBruce Richardson 				RTE_IPSEC_SATP_DIR_IB)
82899a2dd95SBruce Richardson 			pf->process = pkt_flag_process;
82999a2dd95SBruce Richardson 		else
83099a2dd95SBruce Richardson 			pf->process = inline_proto_outb_pkt_process;
83199a2dd95SBruce Richardson 		break;
83299a2dd95SBruce Richardson 	case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
83399a2dd95SBruce Richardson 		pf->prepare.async = lksd_proto_prepare;
83499a2dd95SBruce Richardson 		pf->process = pkt_flag_process;
83599a2dd95SBruce Richardson 		break;
83699a2dd95SBruce Richardson 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
83799a2dd95SBruce Richardson 		rc = cpu_crypto_pkt_func_select(sa, pf);
83899a2dd95SBruce Richardson 		break;
83999a2dd95SBruce Richardson 	default:
84099a2dd95SBruce Richardson 		rc = -ENOTSUP;
84199a2dd95SBruce Richardson 	}
84299a2dd95SBruce Richardson 
84399a2dd95SBruce Richardson 	return rc;
84499a2dd95SBruce Richardson }
845