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