xref: /dpdk/examples/ipsec-secgw/esp.c (revision 923b5f27656627248979bd15b5aa07eff4932f85)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2016-2017 Intel Corporation
3d299106eSSergio Gonzalez Monroy  */
4d299106eSSergio Gonzalez Monroy 
5d299106eSSergio Gonzalez Monroy #include <stdint.h>
6d299106eSSergio Gonzalez Monroy #include <stdlib.h>
7d299106eSSergio Gonzalez Monroy #include <sys/types.h>
8d299106eSSergio Gonzalez Monroy #include <sys/stat.h>
955d4c775SDaniel Mrzyglod #include <netinet/in.h>
1055d4c775SDaniel Mrzyglod #include <netinet/ip.h>
11906257e9SSergio Gonzalez Monroy #include <netinet/ip6.h>
12d299106eSSergio Gonzalez Monroy #include <fcntl.h>
13d299106eSSergio Gonzalez Monroy #include <unistd.h>
14d299106eSSergio Gonzalez Monroy 
15d299106eSSergio Gonzalez Monroy #include <rte_common.h>
16d299106eSSergio Gonzalez Monroy #include <rte_crypto.h>
17d299106eSSergio Gonzalez Monroy #include <rte_cryptodev.h>
18d299106eSSergio Gonzalez Monroy #include <rte_random.h>
19d299106eSSergio Gonzalez Monroy 
20d299106eSSergio Gonzalez Monroy #include "ipsec.h"
21d299106eSSergio Gonzalez Monroy #include "esp.h"
22d299106eSSergio Gonzalez Monroy #include "ipip.h"
23d299106eSSergio Gonzalez Monroy 
24d299106eSSergio Gonzalez Monroy int
esp_inbound(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)25c64278c0SSergio Gonzalez Monroy esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
26d299106eSSergio Gonzalez Monroy 		struct rte_crypto_op *cop)
27d299106eSSergio Gonzalez Monroy {
28f159e70bSSergio Gonzalez Monroy 	struct ip *ip4;
29d299106eSSergio Gonzalez Monroy 	struct rte_crypto_sym_op *sym_cop;
30f159e70bSSergio Gonzalez Monroy 	int32_t payload_len, ip_hdr_len;
31d299106eSSergio Gonzalez Monroy 
3250705e8eSThomas Monjalon 	RTE_ASSERT(sa != NULL);
334a67af84SMarcin Smoczynski 	if (ipsec_get_action_type(sa) ==
344a67af84SMarcin Smoczynski 			RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)
35ec17993aSAkhil Goyal 		return 0;
36ec17993aSAkhil Goyal 
37ec17993aSAkhil Goyal 	RTE_ASSERT(m != NULL);
3850705e8eSThomas Monjalon 	RTE_ASSERT(cop != NULL);
39d299106eSSergio Gonzalez Monroy 
40f159e70bSSergio Gonzalez Monroy 	ip4 = rte_pktmbuf_mtod(m, struct ip *);
41f159e70bSSergio Gonzalez Monroy 	if (likely(ip4->ip_v == IPVERSION))
42f159e70bSSergio Gonzalez Monroy 		ip_hdr_len = ip4->ip_hl * 4;
43f159e70bSSergio Gonzalez Monroy 	else if (ip4->ip_v == IP6_VERSION)
44f159e70bSSergio Gonzalez Monroy 		/* XXX No option headers supported */
45906257e9SSergio Gonzalez Monroy 		ip_hdr_len = sizeof(struct ip6_hdr);
46f159e70bSSergio Gonzalez Monroy 	else {
47f159e70bSSergio Gonzalez Monroy 		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
48f159e70bSSergio Gonzalez Monroy 				ip4->ip_v);
49f159e70bSSergio Gonzalez Monroy 		return -EINVAL;
50906257e9SSergio Gonzalez Monroy 	}
51906257e9SSergio Gonzalez Monroy 
52906257e9SSergio Gonzalez Monroy 	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
535ef25467SOlivier Matz 		sizeof(struct rte_esp_hdr) - sa->iv_len - sa->digest_len;
54d299106eSSergio Gonzalez Monroy 
55d299106eSSergio Gonzalez Monroy 	if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
565d8f0bafSOlivier Matz 		RTE_LOG_DP(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
57d299106eSSergio Gonzalez Monroy 				payload_len, sa->block_size);
58d299106eSSergio Gonzalez Monroy 		return -EINVAL;
59d299106eSSergio Gonzalez Monroy 	}
60d299106eSSergio Gonzalez Monroy 
61cef50fc6SSergio Gonzalez Monroy 	sym_cop = get_sym_cop(cop);
62d299106eSSergio Gonzalez Monroy 	sym_cop->m_src = m;
63b79e4c00SPablo de Lara 
64b79e4c00SPablo de Lara 	if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
655ef25467SOlivier Matz 		sym_cop->aead.data.offset =
665ef25467SOlivier Matz 			ip_hdr_len + sizeof(struct rte_esp_hdr) + sa->iv_len;
67b79e4c00SPablo de Lara 		sym_cop->aead.data.length = payload_len;
68b79e4c00SPablo de Lara 
69b79e4c00SPablo de Lara 		struct cnt_blk *icb;
70b79e4c00SPablo de Lara 		uint8_t *aad;
715ef25467SOlivier Matz 		uint8_t *iv = RTE_PTR_ADD(ip4, ip_hdr_len +
725ef25467SOlivier Matz 					sizeof(struct rte_esp_hdr));
73b79e4c00SPablo de Lara 
74b79e4c00SPablo de Lara 		icb = get_cnt_blk(m);
75b79e4c00SPablo de Lara 		icb->salt = sa->salt;
76b79e4c00SPablo de Lara 		memcpy(&icb->iv, iv, 8);
77b79e4c00SPablo de Lara 		icb->cnt = rte_cpu_to_be_32(1);
78b79e4c00SPablo de Lara 
79b79e4c00SPablo de Lara 		aad = get_aad(m);
805ef25467SOlivier Matz 		memcpy(aad, iv - sizeof(struct rte_esp_hdr), 8);
81b79e4c00SPablo de Lara 		sym_cop->aead.aad.data = aad;
82bfa9a8a4SThomas Monjalon 		sym_cop->aead.aad.phys_addr = rte_pktmbuf_iova_offset(m,
83b79e4c00SPablo de Lara 				aad - rte_pktmbuf_mtod(m, uint8_t *));
84b79e4c00SPablo de Lara 
85b79e4c00SPablo de Lara 		sym_cop->aead.digest.data = rte_pktmbuf_mtod_offset(m, void*,
86b79e4c00SPablo de Lara 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
87bfa9a8a4SThomas Monjalon 		sym_cop->aead.digest.phys_addr = rte_pktmbuf_iova_offset(m,
88b79e4c00SPablo de Lara 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
89b79e4c00SPablo de Lara 	} else {
905ef25467SOlivier Matz 		sym_cop->cipher.data.offset =  ip_hdr_len +
915ef25467SOlivier Matz 			sizeof(struct rte_esp_hdr) +
92906257e9SSergio Gonzalez Monroy 			sa->iv_len;
93d299106eSSergio Gonzalez Monroy 		sym_cop->cipher.data.length = payload_len;
94d299106eSSergio Gonzalez Monroy 
95a9121c40SSergio Gonzalez Monroy 		struct cnt_blk *icb;
965ef25467SOlivier Matz 		uint8_t *iv = RTE_PTR_ADD(ip4, ip_hdr_len +
975ef25467SOlivier Matz 					sizeof(struct rte_esp_hdr));
98dad71e99SPablo de Lara 		uint8_t *iv_ptr = rte_crypto_op_ctod_offset(cop,
99dad71e99SPablo de Lara 					uint8_t *, IV_OFFSET);
100cef50fc6SSergio Gonzalez Monroy 
101cef50fc6SSergio Gonzalez Monroy 		switch (sa->cipher_algo) {
102cef50fc6SSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_NULL:
103*923b5f27SGagandeep Singh 		case RTE_CRYPTO_CIPHER_DES_CBC:
1041bc489caSHemant Agrawal 		case RTE_CRYPTO_CIPHER_3DES_CBC:
105cef50fc6SSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_AES_CBC:
106dad71e99SPablo de Lara 			/* Copy IV at the end of crypto operation */
107dad71e99SPablo de Lara 			rte_memcpy(iv_ptr, iv, sa->iv_len);
108a9121c40SSergio Gonzalez Monroy 			break;
1094470c22dSSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_AES_CTR:
110a9121c40SSergio Gonzalez Monroy 			icb = get_cnt_blk(m);
111a9121c40SSergio Gonzalez Monroy 			icb->salt = sa->salt;
112a9121c40SSergio Gonzalez Monroy 			memcpy(&icb->iv, iv, 8);
113a9121c40SSergio Gonzalez Monroy 			icb->cnt = rte_cpu_to_be_32(1);
114cef50fc6SSergio Gonzalez Monroy 			break;
115cef50fc6SSergio Gonzalez Monroy 		default:
116cef50fc6SSergio Gonzalez Monroy 			RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
117cef50fc6SSergio Gonzalez Monroy 					sa->cipher_algo);
118cef50fc6SSergio Gonzalez Monroy 			return -EINVAL;
119cef50fc6SSergio Gonzalez Monroy 		}
120d299106eSSergio Gonzalez Monroy 
121a9121c40SSergio Gonzalez Monroy 		switch (sa->auth_algo) {
122a9121c40SSergio Gonzalez Monroy 		case RTE_CRYPTO_AUTH_NULL:
123a9121c40SSergio Gonzalez Monroy 		case RTE_CRYPTO_AUTH_SHA1_HMAC:
124b5350285SZbigniew Bodek 		case RTE_CRYPTO_AUTH_SHA256_HMAC:
125*923b5f27SGagandeep Singh 		case RTE_CRYPTO_AUTH_AES_XCBC_MAC:
126a9121c40SSergio Gonzalez Monroy 			sym_cop->auth.data.offset = ip_hdr_len;
1275ef25467SOlivier Matz 			sym_cop->auth.data.length = sizeof(struct rte_esp_hdr) +
128a9121c40SSergio Gonzalez Monroy 				sa->iv_len + payload_len;
129a9121c40SSergio Gonzalez Monroy 			break;
130a9121c40SSergio Gonzalez Monroy 		default:
131a9121c40SSergio Gonzalez Monroy 			RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
132a9121c40SSergio Gonzalez Monroy 					sa->auth_algo);
133a9121c40SSergio Gonzalez Monroy 			return -EINVAL;
134a9121c40SSergio Gonzalez Monroy 		}
135a9121c40SSergio Gonzalez Monroy 
136d299106eSSergio Gonzalez Monroy 		sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
137d299106eSSergio Gonzalez Monroy 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
138bfa9a8a4SThomas Monjalon 		sym_cop->auth.digest.phys_addr = rte_pktmbuf_iova_offset(m,
139d299106eSSergio Gonzalez Monroy 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
140b79e4c00SPablo de Lara 	}
141d299106eSSergio Gonzalez Monroy 
142d299106eSSergio Gonzalez Monroy 	return 0;
143d299106eSSergio Gonzalez Monroy }
144d299106eSSergio Gonzalez Monroy 
145d299106eSSergio Gonzalez Monroy int
esp_inbound_post(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)146c64278c0SSergio Gonzalez Monroy esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
147d299106eSSergio Gonzalez Monroy 		struct rte_crypto_op *cop)
148d299106eSSergio Gonzalez Monroy {
149f159e70bSSergio Gonzalez Monroy 	struct ip *ip4, *ip;
150f159e70bSSergio Gonzalez Monroy 	struct ip6_hdr *ip6;
151d299106eSSergio Gonzalez Monroy 	uint8_t *nexthdr, *pad_len;
152d299106eSSergio Gonzalez Monroy 	uint8_t *padding;
153d299106eSSergio Gonzalez Monroy 	uint16_t i;
1544a67af84SMarcin Smoczynski 	struct rte_ipsec_session *ips;
155d299106eSSergio Gonzalez Monroy 
15650705e8eSThomas Monjalon 	RTE_ASSERT(m != NULL);
15750705e8eSThomas Monjalon 	RTE_ASSERT(sa != NULL);
15850705e8eSThomas Monjalon 	RTE_ASSERT(cop != NULL);
159d299106eSSergio Gonzalez Monroy 
160ba66534fSMarcin Smoczynski 	ips = ipsec_get_primary_session(sa);
1614a67af84SMarcin Smoczynski 
1624a67af84SMarcin Smoczynski 	if ((ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
1634a67af84SMarcin Smoczynski 			(ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
164daa02b5cSOlivier Matz 		if (m->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) {
165daa02b5cSOlivier Matz 			if (m->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)
166ec17993aSAkhil Goyal 				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
167ec17993aSAkhil Goyal 			else
168ec17993aSAkhil Goyal 				cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
169ec17993aSAkhil Goyal 		} else
170ec17993aSAkhil Goyal 			cop->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
171ec17993aSAkhil Goyal 	}
172ec17993aSAkhil Goyal 
173d299106eSSergio Gonzalez Monroy 	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
174da7a540eSBernard Iremonger 		RTE_LOG(ERR, IPSEC_ESP, "%s() failed crypto op\n", __func__);
175d299106eSSergio Gonzalez Monroy 		return -1;
176d299106eSSergio Gonzalez Monroy 	}
177d299106eSSergio Gonzalez Monroy 
1784a67af84SMarcin Smoczynski 	if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
1794a67af84SMarcin Smoczynski 		ips->security.ol_flags & RTE_SECURITY_RX_HW_TRAILER_OFFLOAD) {
180ec17993aSAkhil Goyal 		nexthdr = &m->inner_esp_next_proto;
181ec17993aSAkhil Goyal 	} else {
182d299106eSSergio Gonzalez Monroy 		nexthdr = rte_pktmbuf_mtod_offset(m, uint8_t*,
183d299106eSSergio Gonzalez Monroy 				rte_pktmbuf_pkt_len(m) - sa->digest_len - 1);
184d299106eSSergio Gonzalez Monroy 		pad_len = nexthdr - 1;
185d299106eSSergio Gonzalez Monroy 
186d299106eSSergio Gonzalez Monroy 		padding = pad_len - *pad_len;
187d299106eSSergio Gonzalez Monroy 		for (i = 0; i < *pad_len; i++) {
1886723ea61SSergio Gonzalez Monroy 			if (padding[i] != i + 1) {
189f159e70bSSergio Gonzalez Monroy 				RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
190d299106eSSergio Gonzalez Monroy 				return -EINVAL;
191d299106eSSergio Gonzalez Monroy 			}
192d299106eSSergio Gonzalez Monroy 		}
193d299106eSSergio Gonzalez Monroy 
194d299106eSSergio Gonzalez Monroy 		if (rte_pktmbuf_trim(m, *pad_len + 2 + sa->digest_len)) {
1951f49ec15SThomas Monjalon 			RTE_LOG(ERR, IPSEC_ESP,
196d299106eSSergio Gonzalez Monroy 					"failed to remove pad_len + digest\n");
197d299106eSSergio Gonzalez Monroy 			return -EINVAL;
198d299106eSSergio Gonzalez Monroy 		}
199ec17993aSAkhil Goyal 	}
200d299106eSSergio Gonzalez Monroy 
201b1a3ac78SMariusz Drost 	if (unlikely(IS_TRANSPORT(sa->flags))) {
202f159e70bSSergio Gonzalez Monroy 		ip = rte_pktmbuf_mtod(m, struct ip *);
203f159e70bSSergio Gonzalez Monroy 		ip4 = (struct ip *)rte_pktmbuf_adj(m,
2045ef25467SOlivier Matz 				sizeof(struct rte_esp_hdr) + sa->iv_len);
205f159e70bSSergio Gonzalez Monroy 		if (likely(ip->ip_v == IPVERSION)) {
206f159e70bSSergio Gonzalez Monroy 			memmove(ip4, ip, ip->ip_hl * 4);
207f159e70bSSergio Gonzalez Monroy 			ip4->ip_p = *nexthdr;
208f159e70bSSergio Gonzalez Monroy 			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
209f159e70bSSergio Gonzalez Monroy 		} else {
210f159e70bSSergio Gonzalez Monroy 			ip6 = (struct ip6_hdr *)ip4;
211f159e70bSSergio Gonzalez Monroy 			/* XXX No option headers supported */
212f159e70bSSergio Gonzalez Monroy 			memmove(ip6, ip, sizeof(struct ip6_hdr));
213f159e70bSSergio Gonzalez Monroy 			ip6->ip6_nxt = *nexthdr;
214b43a8131STomasz Duszynski 			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m) -
215b43a8131STomasz Duszynski 					      sizeof(struct ip6_hdr));
216f159e70bSSergio Gonzalez Monroy 		}
217f159e70bSSergio Gonzalez Monroy 	} else
2185ef25467SOlivier Matz 		ipip_inbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len);
219906257e9SSergio Gonzalez Monroy 
220906257e9SSergio Gonzalez Monroy 	return 0;
221d299106eSSergio Gonzalez Monroy }
222d299106eSSergio Gonzalez Monroy 
223d299106eSSergio Gonzalez Monroy int
esp_outbound(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)224c64278c0SSergio Gonzalez Monroy esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
225d299106eSSergio Gonzalez Monroy 		struct rte_crypto_op *cop)
226d299106eSSergio Gonzalez Monroy {
227906257e9SSergio Gonzalez Monroy 	struct ip *ip4;
228906257e9SSergio Gonzalez Monroy 	struct ip6_hdr *ip6;
2295ef25467SOlivier Matz 	struct rte_esp_hdr *esp = NULL;
230ec17993aSAkhil Goyal 	uint8_t *padding = NULL, *new_ip, nlp;
231d299106eSSergio Gonzalez Monroy 	struct rte_crypto_sym_op *sym_cop;
232f159e70bSSergio Gonzalez Monroy 	int32_t i;
233f159e70bSSergio Gonzalez Monroy 	uint16_t pad_payload_len, pad_len, ip_hdr_len;
2344a67af84SMarcin Smoczynski 	struct rte_ipsec_session *ips;
235d299106eSSergio Gonzalez Monroy 
23650705e8eSThomas Monjalon 	RTE_ASSERT(m != NULL);
23750705e8eSThomas Monjalon 	RTE_ASSERT(sa != NULL);
238d299106eSSergio Gonzalez Monroy 
239ba66534fSMarcin Smoczynski 	ips = ipsec_get_primary_session(sa);
240906257e9SSergio Gonzalez Monroy 	ip_hdr_len = 0;
241f159e70bSSergio Gonzalez Monroy 
242f159e70bSSergio Gonzalez Monroy 	ip4 = rte_pktmbuf_mtod(m, struct ip *);
243f159e70bSSergio Gonzalez Monroy 	if (likely(ip4->ip_v == IPVERSION)) {
244b1a3ac78SMariusz Drost 		if (unlikely(IS_TRANSPORT(sa->flags))) {
245f159e70bSSergio Gonzalez Monroy 			ip_hdr_len = ip4->ip_hl * 4;
246f159e70bSSergio Gonzalez Monroy 			nlp = ip4->ip_p;
247f159e70bSSergio Gonzalez Monroy 		} else
248f159e70bSSergio Gonzalez Monroy 			nlp = IPPROTO_IPIP;
249f159e70bSSergio Gonzalez Monroy 	} else if (ip4->ip_v == IP6_VERSION) {
250b1a3ac78SMariusz Drost 		if (unlikely(IS_TRANSPORT(sa->flags))) {
251f159e70bSSergio Gonzalez Monroy 			/* XXX No option headers supported */
252906257e9SSergio Gonzalez Monroy 			ip_hdr_len = sizeof(struct ip6_hdr);
253f159e70bSSergio Gonzalez Monroy 			ip6 = (struct ip6_hdr *)ip4;
254f159e70bSSergio Gonzalez Monroy 			nlp = ip6->ip6_nxt;
255f159e70bSSergio Gonzalez Monroy 		} else
256f159e70bSSergio Gonzalez Monroy 			nlp = IPPROTO_IPV6;
257f159e70bSSergio Gonzalez Monroy 	} else {
258f159e70bSSergio Gonzalez Monroy 		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
259f159e70bSSergio Gonzalez Monroy 				ip4->ip_v);
260f159e70bSSergio Gonzalez Monroy 		return -EINVAL;
261f159e70bSSergio Gonzalez Monroy 	}
262f159e70bSSergio Gonzalez Monroy 
263f159e70bSSergio Gonzalez Monroy 	/* Padded payload length */
264f159e70bSSergio Gonzalez Monroy 	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) -
265f159e70bSSergio Gonzalez Monroy 			ip_hdr_len + 2, sa->block_size);
266f159e70bSSergio Gonzalez Monroy 	pad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);
267f159e70bSSergio Gonzalez Monroy 
268b1a3ac78SMariusz Drost 	RTE_ASSERT(IS_TUNNEL(sa->flags) || IS_TRANSPORT(sa->flags));
269f159e70bSSergio Gonzalez Monroy 
270b1a3ac78SMariusz Drost 	if (likely(IS_IP4_TUNNEL(sa->flags)))
271f159e70bSSergio Gonzalez Monroy 		ip_hdr_len = sizeof(struct ip);
272b1a3ac78SMariusz Drost 	else if (IS_IP6_TUNNEL(sa->flags))
273f159e70bSSergio Gonzalez Monroy 		ip_hdr_len = sizeof(struct ip6_hdr);
274b1a3ac78SMariusz Drost 	else if (!IS_TRANSPORT(sa->flags)) {
275f159e70bSSergio Gonzalez Monroy 		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
276f159e70bSSergio Gonzalez Monroy 				sa->flags);
277f159e70bSSergio Gonzalez Monroy 		return -EINVAL;
278906257e9SSergio Gonzalez Monroy 	}
279d299106eSSergio Gonzalez Monroy 
280d299106eSSergio Gonzalez Monroy 	/* Check maximum packet size */
2815ef25467SOlivier Matz 	if (unlikely(ip_hdr_len + sizeof(struct rte_esp_hdr) + sa->iv_len +
282906257e9SSergio Gonzalez Monroy 			pad_payload_len + sa->digest_len > IP_MAXPACKET)) {
283906257e9SSergio Gonzalez Monroy 		RTE_LOG(ERR, IPSEC_ESP, "ipsec packet is too big\n");
284d299106eSSergio Gonzalez Monroy 		return -EINVAL;
285d299106eSSergio Gonzalez Monroy 	}
286d299106eSSergio Gonzalez Monroy 
287ec17993aSAkhil Goyal 	/* Add trailer padding if it is not constructed by HW */
2884a67af84SMarcin Smoczynski 	if (ips->type != RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
2894a67af84SMarcin Smoczynski 		(ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
2904a67af84SMarcin Smoczynski 		 !(ips->security.ol_flags &
2914a67af84SMarcin Smoczynski 			 RTE_SECURITY_TX_HW_TRAILER_OFFLOAD))) {
292ec17993aSAkhil Goyal 		padding = (uint8_t *)rte_pktmbuf_append(m, pad_len +
293ec17993aSAkhil Goyal 							sa->digest_len);
294906257e9SSergio Gonzalez Monroy 		if (unlikely(padding == NULL)) {
295ec17993aSAkhil Goyal 			RTE_LOG(ERR, IPSEC_ESP,
296ec17993aSAkhil Goyal 					"not enough mbuf trailing space\n");
297906257e9SSergio Gonzalez Monroy 			return -ENOSPC;
298906257e9SSergio Gonzalez Monroy 		}
299906257e9SSergio Gonzalez Monroy 		rte_prefetch0(padding);
300ec17993aSAkhil Goyal 	}
301d299106eSSergio Gonzalez Monroy 
302b1a3ac78SMariusz Drost 	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
303906257e9SSergio Gonzalez Monroy 	case IP4_TUNNEL:
3045ef25467SOlivier Matz 		ip4 = ip4ip_outbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len,
305906257e9SSergio Gonzalez Monroy 				&sa->src, &sa->dst);
3065ef25467SOlivier Matz 		esp = (struct rte_esp_hdr *)(ip4 + 1);
307906257e9SSergio Gonzalez Monroy 		break;
308906257e9SSergio Gonzalez Monroy 	case IP6_TUNNEL:
3095ef25467SOlivier Matz 		ip6 = ip6ip_outbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len,
310906257e9SSergio Gonzalez Monroy 				&sa->src, &sa->dst);
3115ef25467SOlivier Matz 		esp = (struct rte_esp_hdr *)(ip6 + 1);
312906257e9SSergio Gonzalez Monroy 		break;
313f159e70bSSergio Gonzalez Monroy 	case TRANSPORT:
314f159e70bSSergio Gonzalez Monroy 		new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
3155ef25467SOlivier Matz 				sizeof(struct rte_esp_hdr) + sa->iv_len);
316f159e70bSSergio Gonzalez Monroy 		memmove(new_ip, ip4, ip_hdr_len);
3175ef25467SOlivier Matz 		esp = (struct rte_esp_hdr *)(new_ip + ip_hdr_len);
318f159e70bSSergio Gonzalez Monroy 		ip4 = (struct ip *)new_ip;
3193417350eSTomasz Duszynski 		if (likely(ip4->ip_v == IPVERSION)) {
320f159e70bSSergio Gonzalez Monroy 			ip4->ip_p = IPPROTO_ESP;
321f159e70bSSergio Gonzalez Monroy 			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
322f159e70bSSergio Gonzalez Monroy 		} else {
323f159e70bSSergio Gonzalez Monroy 			ip6 = (struct ip6_hdr *)new_ip;
324f159e70bSSergio Gonzalez Monroy 			ip6->ip6_nxt = IPPROTO_ESP;
325b43a8131STomasz Duszynski 			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m) -
326b43a8131STomasz Duszynski 					      sizeof(struct ip6_hdr));
327f159e70bSSergio Gonzalez Monroy 		}
328906257e9SSergio Gonzalez Monroy 	}
329d299106eSSergio Gonzalez Monroy 
330906257e9SSergio Gonzalez Monroy 	sa->seq++;
331906257e9SSergio Gonzalez Monroy 	esp->spi = rte_cpu_to_be_32(sa->spi);
332cef50fc6SSergio Gonzalez Monroy 	esp->seq = rte_cpu_to_be_32((uint32_t)sa->seq);
333d299106eSSergio Gonzalez Monroy 
334ec17993aSAkhil Goyal 	/* set iv */
335cef50fc6SSergio Gonzalez Monroy 	uint64_t *iv = (uint64_t *)(esp + 1);
336ec17993aSAkhil Goyal 	if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
337ec17993aSAkhil Goyal 		*iv = rte_cpu_to_be_64(sa->seq);
338ec17993aSAkhil Goyal 	} else {
339ec17993aSAkhil Goyal 		switch (sa->cipher_algo) {
340ec17993aSAkhil Goyal 		case RTE_CRYPTO_CIPHER_NULL:
341*923b5f27SGagandeep Singh 		case RTE_CRYPTO_CIPHER_DES_CBC:
3421bc489caSHemant Agrawal 		case RTE_CRYPTO_CIPHER_3DES_CBC:
343ec17993aSAkhil Goyal 		case RTE_CRYPTO_CIPHER_AES_CBC:
344ec17993aSAkhil Goyal 			memset(iv, 0, sa->iv_len);
345ec17993aSAkhil Goyal 			break;
346ec17993aSAkhil Goyal 		case RTE_CRYPTO_CIPHER_AES_CTR:
347ec17993aSAkhil Goyal 			*iv = rte_cpu_to_be_64(sa->seq);
348ec17993aSAkhil Goyal 			break;
349ec17993aSAkhil Goyal 		default:
350ec17993aSAkhil Goyal 			RTE_LOG(ERR, IPSEC_ESP,
351ec17993aSAkhil Goyal 				"unsupported cipher algorithm %u\n",
352ec17993aSAkhil Goyal 				sa->cipher_algo);
353ec17993aSAkhil Goyal 			return -EINVAL;
354ec17993aSAkhil Goyal 		}
355ec17993aSAkhil Goyal 	}
356cef50fc6SSergio Gonzalez Monroy 
3574a67af84SMarcin Smoczynski 	if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
3584a67af84SMarcin Smoczynski 		if (ips->security.ol_flags &
3594a67af84SMarcin Smoczynski 				RTE_SECURITY_TX_HW_TRAILER_OFFLOAD) {
360ec17993aSAkhil Goyal 			/* Set the inner esp next protocol for HW trailer */
361ec17993aSAkhil Goyal 			m->inner_esp_next_proto = nlp;
362ec17993aSAkhil Goyal 			m->packet_type |= RTE_PTYPE_TUNNEL_ESP;
363ec17993aSAkhil Goyal 		} else {
364ec17993aSAkhil Goyal 			padding[pad_len - 2] = pad_len - 2;
365ec17993aSAkhil Goyal 			padding[pad_len - 1] = nlp;
366ec17993aSAkhil Goyal 		}
367ec17993aSAkhil Goyal 		goto done;
368ec17993aSAkhil Goyal 	}
369ec17993aSAkhil Goyal 
370ec17993aSAkhil Goyal 	RTE_ASSERT(cop != NULL);
371cef50fc6SSergio Gonzalez Monroy 	sym_cop = get_sym_cop(cop);
372cef50fc6SSergio Gonzalez Monroy 	sym_cop->m_src = m;
373b79e4c00SPablo de Lara 
374b79e4c00SPablo de Lara 	if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
375b79e4c00SPablo de Lara 		uint8_t *aad;
376b79e4c00SPablo de Lara 
377b79e4c00SPablo de Lara 		sym_cop->aead.data.offset = ip_hdr_len +
3785ef25467SOlivier Matz 			sizeof(struct rte_esp_hdr) + sa->iv_len;
379b79e4c00SPablo de Lara 		sym_cop->aead.data.length = pad_payload_len;
380b79e4c00SPablo de Lara 
381b79e4c00SPablo de Lara 		/* Fill pad_len using default sequential scheme */
382b79e4c00SPablo de Lara 		for (i = 0; i < pad_len - 2; i++)
383b79e4c00SPablo de Lara 			padding[i] = i + 1;
384b79e4c00SPablo de Lara 		padding[pad_len - 2] = pad_len - 2;
385b79e4c00SPablo de Lara 		padding[pad_len - 1] = nlp;
386b79e4c00SPablo de Lara 
387b79e4c00SPablo de Lara 		struct cnt_blk *icb = get_cnt_blk(m);
388b79e4c00SPablo de Lara 		icb->salt = sa->salt;
3892a41fb7cSAviad Yehezkel 		icb->iv = rte_cpu_to_be_64(sa->seq);
390b79e4c00SPablo de Lara 		icb->cnt = rte_cpu_to_be_32(1);
391b79e4c00SPablo de Lara 
392b79e4c00SPablo de Lara 		aad = get_aad(m);
393b79e4c00SPablo de Lara 		memcpy(aad, esp, 8);
394b79e4c00SPablo de Lara 		sym_cop->aead.aad.data = aad;
395bfa9a8a4SThomas Monjalon 		sym_cop->aead.aad.phys_addr = rte_pktmbuf_iova_offset(m,
396b79e4c00SPablo de Lara 				aad - rte_pktmbuf_mtod(m, uint8_t *));
397b79e4c00SPablo de Lara 
398b79e4c00SPablo de Lara 		sym_cop->aead.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
399b79e4c00SPablo de Lara 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
400bfa9a8a4SThomas Monjalon 		sym_cop->aead.digest.phys_addr = rte_pktmbuf_iova_offset(m,
401b79e4c00SPablo de Lara 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
402b79e4c00SPablo de Lara 	} else {
403cef50fc6SSergio Gonzalez Monroy 		switch (sa->cipher_algo) {
404cef50fc6SSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_NULL:
405*923b5f27SGagandeep Singh 		case RTE_CRYPTO_CIPHER_DES_CBC:
4061bc489caSHemant Agrawal 		case RTE_CRYPTO_CIPHER_3DES_CBC:
407cef50fc6SSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_AES_CBC:
408cef50fc6SSergio Gonzalez Monroy 			sym_cop->cipher.data.offset = ip_hdr_len +
4095ef25467SOlivier Matz 				sizeof(struct rte_esp_hdr);
410cef50fc6SSergio Gonzalez Monroy 			sym_cop->cipher.data.length = pad_payload_len + sa->iv_len;
411cef50fc6SSergio Gonzalez Monroy 			break;
4124470c22dSSergio Gonzalez Monroy 		case RTE_CRYPTO_CIPHER_AES_CTR:
413a9121c40SSergio Gonzalez Monroy 			sym_cop->cipher.data.offset = ip_hdr_len +
4145ef25467SOlivier Matz 				sizeof(struct rte_esp_hdr) + sa->iv_len;
415a9121c40SSergio Gonzalez Monroy 			sym_cop->cipher.data.length = pad_payload_len;
416a9121c40SSergio Gonzalez Monroy 			break;
417cef50fc6SSergio Gonzalez Monroy 		default:
418cef50fc6SSergio Gonzalez Monroy 			RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
419cef50fc6SSergio Gonzalez Monroy 					sa->cipher_algo);
420cef50fc6SSergio Gonzalez Monroy 			return -EINVAL;
421cef50fc6SSergio Gonzalez Monroy 		}
422d299106eSSergio Gonzalez Monroy 
423d299106eSSergio Gonzalez Monroy 		/* Fill pad_len using default sequential scheme */
424d299106eSSergio Gonzalez Monroy 		for (i = 0; i < pad_len - 2; i++)
425d299106eSSergio Gonzalez Monroy 			padding[i] = i + 1;
426d299106eSSergio Gonzalez Monroy 		padding[pad_len - 2] = pad_len - 2;
427f159e70bSSergio Gonzalez Monroy 		padding[pad_len - 1] = nlp;
428d299106eSSergio Gonzalez Monroy 
429cef50fc6SSergio Gonzalez Monroy 		struct cnt_blk *icb = get_cnt_blk(m);
430cef50fc6SSergio Gonzalez Monroy 		icb->salt = sa->salt;
4312a41fb7cSAviad Yehezkel 		icb->iv = rte_cpu_to_be_64(sa->seq);
432cef50fc6SSergio Gonzalez Monroy 		icb->cnt = rte_cpu_to_be_32(1);
433d299106eSSergio Gonzalez Monroy 
434a9121c40SSergio Gonzalez Monroy 		switch (sa->auth_algo) {
435a9121c40SSergio Gonzalez Monroy 		case RTE_CRYPTO_AUTH_NULL:
436a9121c40SSergio Gonzalez Monroy 		case RTE_CRYPTO_AUTH_SHA1_HMAC:
437b5350285SZbigniew Bodek 		case RTE_CRYPTO_AUTH_SHA256_HMAC:
438*923b5f27SGagandeep Singh 		case RTE_CRYPTO_AUTH_AES_XCBC_MAC:
439906257e9SSergio Gonzalez Monroy 			sym_cop->auth.data.offset = ip_hdr_len;
4405ef25467SOlivier Matz 			sym_cop->auth.data.length = sizeof(struct rte_esp_hdr) +
441cef50fc6SSergio Gonzalez Monroy 				sa->iv_len + pad_payload_len;
442cef50fc6SSergio Gonzalez Monroy 			break;
443cef50fc6SSergio Gonzalez Monroy 		default:
444a9121c40SSergio Gonzalez Monroy 			RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
445a9121c40SSergio Gonzalez Monroy 					sa->auth_algo);
446cef50fc6SSergio Gonzalez Monroy 			return -EINVAL;
447cef50fc6SSergio Gonzalez Monroy 		}
448d299106eSSergio Gonzalez Monroy 
449d299106eSSergio Gonzalez Monroy 		sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
450906257e9SSergio Gonzalez Monroy 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
451bfa9a8a4SThomas Monjalon 		sym_cop->auth.digest.phys_addr = rte_pktmbuf_iova_offset(m,
452906257e9SSergio Gonzalez Monroy 				rte_pktmbuf_pkt_len(m) - sa->digest_len);
453b79e4c00SPablo de Lara 	}
454d299106eSSergio Gonzalez Monroy 
455ec17993aSAkhil Goyal done:
456d299106eSSergio Gonzalez Monroy 	return 0;
457d299106eSSergio Gonzalez Monroy }
458d299106eSSergio Gonzalez Monroy 
459d299106eSSergio Gonzalez Monroy int
esp_outbound_post(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)460ec17993aSAkhil Goyal esp_outbound_post(struct rte_mbuf *m,
461ec17993aSAkhil Goyal 		  struct ipsec_sa *sa,
462d299106eSSergio Gonzalez Monroy 		  struct rte_crypto_op *cop)
463d299106eSSergio Gonzalez Monroy {
4644a67af84SMarcin Smoczynski 	enum rte_security_session_action_type type;
46550705e8eSThomas Monjalon 	RTE_ASSERT(m != NULL);
46650705e8eSThomas Monjalon 	RTE_ASSERT(sa != NULL);
467d299106eSSergio Gonzalez Monroy 
4684a67af84SMarcin Smoczynski 	type = ipsec_get_action_type(sa);
4694a67af84SMarcin Smoczynski 
4704a67af84SMarcin Smoczynski 	if ((type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
4714a67af84SMarcin Smoczynski 			(type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
472daa02b5cSOlivier Matz 		m->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD;
473ec17993aSAkhil Goyal 	} else {
474ec17993aSAkhil Goyal 		RTE_ASSERT(cop != NULL);
475d299106eSSergio Gonzalez Monroy 		if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
476da7a540eSBernard Iremonger 			RTE_LOG(ERR, IPSEC_ESP, "%s() failed crypto op\n",
477da7a540eSBernard Iremonger 				__func__);
478d299106eSSergio Gonzalez Monroy 			return -1;
479d299106eSSergio Gonzalez Monroy 		}
480ec17993aSAkhil Goyal 	}
481d299106eSSergio Gonzalez Monroy 
482d299106eSSergio Gonzalez Monroy 	return 0;
483d299106eSSergio Gonzalez Monroy }
484