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