1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2016-2017 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang #include <stdint.h>
6a9643ea8Slogwang #include <stdlib.h>
7a9643ea8Slogwang #include <sys/types.h>
8a9643ea8Slogwang #include <sys/stat.h>
9a9643ea8Slogwang #include <netinet/in.h>
10a9643ea8Slogwang #include <netinet/ip.h>
11a9643ea8Slogwang #include <netinet/ip6.h>
12a9643ea8Slogwang #include <fcntl.h>
13a9643ea8Slogwang #include <unistd.h>
14a9643ea8Slogwang
15a9643ea8Slogwang #include <rte_common.h>
16a9643ea8Slogwang #include <rte_crypto.h>
17a9643ea8Slogwang #include <rte_cryptodev.h>
18a9643ea8Slogwang #include <rte_random.h>
19a9643ea8Slogwang
20a9643ea8Slogwang #include "ipsec.h"
21a9643ea8Slogwang #include "esp.h"
22a9643ea8Slogwang #include "ipip.h"
23a9643ea8Slogwang
24a9643ea8Slogwang int
esp_inbound(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)25a9643ea8Slogwang esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
26a9643ea8Slogwang struct rte_crypto_op *cop)
27a9643ea8Slogwang {
28a9643ea8Slogwang struct ip *ip4;
29a9643ea8Slogwang struct rte_crypto_sym_op *sym_cop;
30a9643ea8Slogwang int32_t payload_len, ip_hdr_len;
31a9643ea8Slogwang
32a9643ea8Slogwang RTE_ASSERT(sa != NULL);
33*4418919fSjohnjiang if (ipsec_get_action_type(sa) ==
34*4418919fSjohnjiang RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)
352bfe3f2eSlogwang return 0;
362bfe3f2eSlogwang
372bfe3f2eSlogwang RTE_ASSERT(m != NULL);
38a9643ea8Slogwang RTE_ASSERT(cop != NULL);
39a9643ea8Slogwang
40a9643ea8Slogwang ip4 = rte_pktmbuf_mtod(m, struct ip *);
41a9643ea8Slogwang if (likely(ip4->ip_v == IPVERSION))
42a9643ea8Slogwang ip_hdr_len = ip4->ip_hl * 4;
43a9643ea8Slogwang else if (ip4->ip_v == IP6_VERSION)
44a9643ea8Slogwang /* XXX No option headers supported */
45a9643ea8Slogwang ip_hdr_len = sizeof(struct ip6_hdr);
46a9643ea8Slogwang else {
47a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
48a9643ea8Slogwang ip4->ip_v);
49a9643ea8Slogwang return -EINVAL;
50a9643ea8Slogwang }
51a9643ea8Slogwang
52a9643ea8Slogwang payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
53*4418919fSjohnjiang sizeof(struct rte_esp_hdr) - sa->iv_len - sa->digest_len;
54a9643ea8Slogwang
55a9643ea8Slogwang if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
562bfe3f2eSlogwang RTE_LOG_DP(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
57a9643ea8Slogwang payload_len, sa->block_size);
58a9643ea8Slogwang return -EINVAL;
59a9643ea8Slogwang }
60a9643ea8Slogwang
612bfe3f2eSlogwang sym_cop = get_sym_cop(cop);
62a9643ea8Slogwang sym_cop->m_src = m;
632bfe3f2eSlogwang
642bfe3f2eSlogwang if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
65*4418919fSjohnjiang sym_cop->aead.data.offset =
66*4418919fSjohnjiang ip_hdr_len + sizeof(struct rte_esp_hdr) + sa->iv_len;
672bfe3f2eSlogwang sym_cop->aead.data.length = payload_len;
682bfe3f2eSlogwang
692bfe3f2eSlogwang struct cnt_blk *icb;
702bfe3f2eSlogwang uint8_t *aad;
71*4418919fSjohnjiang uint8_t *iv = RTE_PTR_ADD(ip4, ip_hdr_len +
72*4418919fSjohnjiang sizeof(struct rte_esp_hdr));
732bfe3f2eSlogwang
742bfe3f2eSlogwang icb = get_cnt_blk(m);
752bfe3f2eSlogwang icb->salt = sa->salt;
762bfe3f2eSlogwang memcpy(&icb->iv, iv, 8);
772bfe3f2eSlogwang icb->cnt = rte_cpu_to_be_32(1);
782bfe3f2eSlogwang
792bfe3f2eSlogwang aad = get_aad(m);
80*4418919fSjohnjiang memcpy(aad, iv - sizeof(struct rte_esp_hdr), 8);
812bfe3f2eSlogwang sym_cop->aead.aad.data = aad;
822bfe3f2eSlogwang sym_cop->aead.aad.phys_addr = rte_pktmbuf_iova_offset(m,
832bfe3f2eSlogwang aad - rte_pktmbuf_mtod(m, uint8_t *));
842bfe3f2eSlogwang
852bfe3f2eSlogwang sym_cop->aead.digest.data = rte_pktmbuf_mtod_offset(m, void*,
862bfe3f2eSlogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
872bfe3f2eSlogwang sym_cop->aead.digest.phys_addr = rte_pktmbuf_iova_offset(m,
882bfe3f2eSlogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
892bfe3f2eSlogwang } else {
90*4418919fSjohnjiang sym_cop->cipher.data.offset = ip_hdr_len +
91*4418919fSjohnjiang sizeof(struct rte_esp_hdr) +
92a9643ea8Slogwang sa->iv_len;
93a9643ea8Slogwang sym_cop->cipher.data.length = payload_len;
94a9643ea8Slogwang
952bfe3f2eSlogwang struct cnt_blk *icb;
96*4418919fSjohnjiang uint8_t *iv = RTE_PTR_ADD(ip4, ip_hdr_len +
97*4418919fSjohnjiang sizeof(struct rte_esp_hdr));
982bfe3f2eSlogwang uint8_t *iv_ptr = rte_crypto_op_ctod_offset(cop,
992bfe3f2eSlogwang uint8_t *, IV_OFFSET);
100a9643ea8Slogwang
1012bfe3f2eSlogwang switch (sa->cipher_algo) {
1022bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_NULL:
103d30ea906Sjfb8856606 case RTE_CRYPTO_CIPHER_3DES_CBC:
1042bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CBC:
1052bfe3f2eSlogwang /* Copy IV at the end of crypto operation */
1062bfe3f2eSlogwang rte_memcpy(iv_ptr, iv, sa->iv_len);
1072bfe3f2eSlogwang break;
1082bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CTR:
1092bfe3f2eSlogwang icb = get_cnt_blk(m);
1102bfe3f2eSlogwang icb->salt = sa->salt;
1112bfe3f2eSlogwang memcpy(&icb->iv, iv, 8);
1122bfe3f2eSlogwang icb->cnt = rte_cpu_to_be_32(1);
1132bfe3f2eSlogwang break;
1142bfe3f2eSlogwang default:
1152bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
1162bfe3f2eSlogwang sa->cipher_algo);
1172bfe3f2eSlogwang return -EINVAL;
1182bfe3f2eSlogwang }
1192bfe3f2eSlogwang
1202bfe3f2eSlogwang switch (sa->auth_algo) {
1212bfe3f2eSlogwang case RTE_CRYPTO_AUTH_NULL:
1222bfe3f2eSlogwang case RTE_CRYPTO_AUTH_SHA1_HMAC:
1232bfe3f2eSlogwang case RTE_CRYPTO_AUTH_SHA256_HMAC:
124a9643ea8Slogwang sym_cop->auth.data.offset = ip_hdr_len;
125*4418919fSjohnjiang sym_cop->auth.data.length = sizeof(struct rte_esp_hdr) +
126a9643ea8Slogwang sa->iv_len + payload_len;
1272bfe3f2eSlogwang break;
1282bfe3f2eSlogwang default:
1292bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
1302bfe3f2eSlogwang sa->auth_algo);
1312bfe3f2eSlogwang return -EINVAL;
1322bfe3f2eSlogwang }
133a9643ea8Slogwang
134a9643ea8Slogwang sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
135a9643ea8Slogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
1362bfe3f2eSlogwang sym_cop->auth.digest.phys_addr = rte_pktmbuf_iova_offset(m,
137a9643ea8Slogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
1382bfe3f2eSlogwang }
139a9643ea8Slogwang
140a9643ea8Slogwang return 0;
141a9643ea8Slogwang }
142a9643ea8Slogwang
143a9643ea8Slogwang int
esp_inbound_post(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)144a9643ea8Slogwang esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
145a9643ea8Slogwang struct rte_crypto_op *cop)
146a9643ea8Slogwang {
147a9643ea8Slogwang struct ip *ip4, *ip;
148a9643ea8Slogwang struct ip6_hdr *ip6;
149a9643ea8Slogwang uint8_t *nexthdr, *pad_len;
150a9643ea8Slogwang uint8_t *padding;
151a9643ea8Slogwang uint16_t i;
152*4418919fSjohnjiang struct rte_ipsec_session *ips;
153a9643ea8Slogwang
154a9643ea8Slogwang RTE_ASSERT(m != NULL);
155a9643ea8Slogwang RTE_ASSERT(sa != NULL);
156a9643ea8Slogwang RTE_ASSERT(cop != NULL);
157a9643ea8Slogwang
158*4418919fSjohnjiang ips = ipsec_get_primary_session(sa);
159*4418919fSjohnjiang
160*4418919fSjohnjiang if ((ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
161*4418919fSjohnjiang (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
1622bfe3f2eSlogwang if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
1632bfe3f2eSlogwang if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
1642bfe3f2eSlogwang cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
1652bfe3f2eSlogwang else
1662bfe3f2eSlogwang cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
1672bfe3f2eSlogwang } else
1682bfe3f2eSlogwang cop->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
1692bfe3f2eSlogwang }
1702bfe3f2eSlogwang
171a9643ea8Slogwang if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
1721646932aSjfb8856606 RTE_LOG(ERR, IPSEC_ESP, "%s() failed crypto op\n", __func__);
173a9643ea8Slogwang return -1;
174a9643ea8Slogwang }
175a9643ea8Slogwang
176*4418919fSjohnjiang if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
177*4418919fSjohnjiang ips->security.ol_flags & RTE_SECURITY_RX_HW_TRAILER_OFFLOAD) {
1782bfe3f2eSlogwang nexthdr = &m->inner_esp_next_proto;
1792bfe3f2eSlogwang } else {
180a9643ea8Slogwang nexthdr = rte_pktmbuf_mtod_offset(m, uint8_t*,
181a9643ea8Slogwang rte_pktmbuf_pkt_len(m) - sa->digest_len - 1);
182a9643ea8Slogwang pad_len = nexthdr - 1;
183a9643ea8Slogwang
184a9643ea8Slogwang padding = pad_len - *pad_len;
185a9643ea8Slogwang for (i = 0; i < *pad_len; i++) {
186a9643ea8Slogwang if (padding[i] != i + 1) {
187a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
188a9643ea8Slogwang return -EINVAL;
189a9643ea8Slogwang }
190a9643ea8Slogwang }
191a9643ea8Slogwang
192a9643ea8Slogwang if (rte_pktmbuf_trim(m, *pad_len + 2 + sa->digest_len)) {
193a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP,
194a9643ea8Slogwang "failed to remove pad_len + digest\n");
195a9643ea8Slogwang return -EINVAL;
196a9643ea8Slogwang }
1972bfe3f2eSlogwang }
198a9643ea8Slogwang
1994b05018fSfengbojiang if (unlikely(IS_TRANSPORT(sa->flags))) {
200a9643ea8Slogwang ip = rte_pktmbuf_mtod(m, struct ip *);
201a9643ea8Slogwang ip4 = (struct ip *)rte_pktmbuf_adj(m,
202*4418919fSjohnjiang sizeof(struct rte_esp_hdr) + sa->iv_len);
203a9643ea8Slogwang if (likely(ip->ip_v == IPVERSION)) {
204a9643ea8Slogwang memmove(ip4, ip, ip->ip_hl * 4);
205a9643ea8Slogwang ip4->ip_p = *nexthdr;
206a9643ea8Slogwang ip4->ip_len = htons(rte_pktmbuf_data_len(m));
207a9643ea8Slogwang } else {
208a9643ea8Slogwang ip6 = (struct ip6_hdr *)ip4;
209a9643ea8Slogwang /* XXX No option headers supported */
210a9643ea8Slogwang memmove(ip6, ip, sizeof(struct ip6_hdr));
211a9643ea8Slogwang ip6->ip6_nxt = *nexthdr;
2122bfe3f2eSlogwang ip6->ip6_plen = htons(rte_pktmbuf_data_len(m) -
2132bfe3f2eSlogwang sizeof(struct ip6_hdr));
214a9643ea8Slogwang }
215a9643ea8Slogwang } else
216*4418919fSjohnjiang ipip_inbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len);
217a9643ea8Slogwang
218a9643ea8Slogwang return 0;
219a9643ea8Slogwang }
220a9643ea8Slogwang
221a9643ea8Slogwang int
esp_outbound(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)222a9643ea8Slogwang esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
223a9643ea8Slogwang struct rte_crypto_op *cop)
224a9643ea8Slogwang {
225a9643ea8Slogwang struct ip *ip4;
226a9643ea8Slogwang struct ip6_hdr *ip6;
227*4418919fSjohnjiang struct rte_esp_hdr *esp = NULL;
2282bfe3f2eSlogwang uint8_t *padding = NULL, *new_ip, nlp;
229a9643ea8Slogwang struct rte_crypto_sym_op *sym_cop;
230a9643ea8Slogwang int32_t i;
231a9643ea8Slogwang uint16_t pad_payload_len, pad_len, ip_hdr_len;
232*4418919fSjohnjiang struct rte_ipsec_session *ips;
233a9643ea8Slogwang
234a9643ea8Slogwang RTE_ASSERT(m != NULL);
235a9643ea8Slogwang RTE_ASSERT(sa != NULL);
236a9643ea8Slogwang
237*4418919fSjohnjiang ips = ipsec_get_primary_session(sa);
238a9643ea8Slogwang ip_hdr_len = 0;
239a9643ea8Slogwang
240a9643ea8Slogwang ip4 = rte_pktmbuf_mtod(m, struct ip *);
241a9643ea8Slogwang if (likely(ip4->ip_v == IPVERSION)) {
2424b05018fSfengbojiang if (unlikely(IS_TRANSPORT(sa->flags))) {
243a9643ea8Slogwang ip_hdr_len = ip4->ip_hl * 4;
244a9643ea8Slogwang nlp = ip4->ip_p;
245a9643ea8Slogwang } else
246a9643ea8Slogwang nlp = IPPROTO_IPIP;
247a9643ea8Slogwang } else if (ip4->ip_v == IP6_VERSION) {
2484b05018fSfengbojiang if (unlikely(IS_TRANSPORT(sa->flags))) {
249a9643ea8Slogwang /* XXX No option headers supported */
250a9643ea8Slogwang ip_hdr_len = sizeof(struct ip6_hdr);
251a9643ea8Slogwang ip6 = (struct ip6_hdr *)ip4;
252a9643ea8Slogwang nlp = ip6->ip6_nxt;
253a9643ea8Slogwang } else
254a9643ea8Slogwang nlp = IPPROTO_IPV6;
255a9643ea8Slogwang } else {
256a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
257a9643ea8Slogwang ip4->ip_v);
258a9643ea8Slogwang return -EINVAL;
259a9643ea8Slogwang }
260a9643ea8Slogwang
261a9643ea8Slogwang /* Padded payload length */
262a9643ea8Slogwang pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) -
263a9643ea8Slogwang ip_hdr_len + 2, sa->block_size);
264a9643ea8Slogwang pad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);
265a9643ea8Slogwang
2664b05018fSfengbojiang RTE_ASSERT(IS_TUNNEL(sa->flags) || IS_TRANSPORT(sa->flags));
267a9643ea8Slogwang
2684b05018fSfengbojiang if (likely(IS_IP4_TUNNEL(sa->flags)))
269a9643ea8Slogwang ip_hdr_len = sizeof(struct ip);
2704b05018fSfengbojiang else if (IS_IP6_TUNNEL(sa->flags))
271a9643ea8Slogwang ip_hdr_len = sizeof(struct ip6_hdr);
2724b05018fSfengbojiang else if (!IS_TRANSPORT(sa->flags)) {
273a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
274a9643ea8Slogwang sa->flags);
275a9643ea8Slogwang return -EINVAL;
276a9643ea8Slogwang }
277a9643ea8Slogwang
278a9643ea8Slogwang /* Check maximum packet size */
279*4418919fSjohnjiang if (unlikely(ip_hdr_len + sizeof(struct rte_esp_hdr) + sa->iv_len +
280a9643ea8Slogwang pad_payload_len + sa->digest_len > IP_MAXPACKET)) {
281a9643ea8Slogwang RTE_LOG(ERR, IPSEC_ESP, "ipsec packet is too big\n");
282a9643ea8Slogwang return -EINVAL;
283a9643ea8Slogwang }
284a9643ea8Slogwang
2852bfe3f2eSlogwang /* Add trailer padding if it is not constructed by HW */
286*4418919fSjohnjiang if (ips->type != RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
287*4418919fSjohnjiang (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
288*4418919fSjohnjiang !(ips->security.ol_flags &
289*4418919fSjohnjiang RTE_SECURITY_TX_HW_TRAILER_OFFLOAD))) {
2902bfe3f2eSlogwang padding = (uint8_t *)rte_pktmbuf_append(m, pad_len +
2912bfe3f2eSlogwang sa->digest_len);
292a9643ea8Slogwang if (unlikely(padding == NULL)) {
2932bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP,
2942bfe3f2eSlogwang "not enough mbuf trailing space\n");
295a9643ea8Slogwang return -ENOSPC;
296a9643ea8Slogwang }
297a9643ea8Slogwang rte_prefetch0(padding);
2982bfe3f2eSlogwang }
299a9643ea8Slogwang
3004b05018fSfengbojiang switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
301a9643ea8Slogwang case IP4_TUNNEL:
302*4418919fSjohnjiang ip4 = ip4ip_outbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len,
303a9643ea8Slogwang &sa->src, &sa->dst);
304*4418919fSjohnjiang esp = (struct rte_esp_hdr *)(ip4 + 1);
305a9643ea8Slogwang break;
306a9643ea8Slogwang case IP6_TUNNEL:
307*4418919fSjohnjiang ip6 = ip6ip_outbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len,
308a9643ea8Slogwang &sa->src, &sa->dst);
309*4418919fSjohnjiang esp = (struct rte_esp_hdr *)(ip6 + 1);
310a9643ea8Slogwang break;
311a9643ea8Slogwang case TRANSPORT:
312a9643ea8Slogwang new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
313*4418919fSjohnjiang sizeof(struct rte_esp_hdr) + sa->iv_len);
314a9643ea8Slogwang memmove(new_ip, ip4, ip_hdr_len);
315*4418919fSjohnjiang esp = (struct rte_esp_hdr *)(new_ip + ip_hdr_len);
316a9643ea8Slogwang ip4 = (struct ip *)new_ip;
3172bfe3f2eSlogwang if (likely(ip4->ip_v == IPVERSION)) {
318a9643ea8Slogwang ip4->ip_p = IPPROTO_ESP;
319a9643ea8Slogwang ip4->ip_len = htons(rte_pktmbuf_data_len(m));
320a9643ea8Slogwang } else {
321a9643ea8Slogwang ip6 = (struct ip6_hdr *)new_ip;
322a9643ea8Slogwang ip6->ip6_nxt = IPPROTO_ESP;
3232bfe3f2eSlogwang ip6->ip6_plen = htons(rte_pktmbuf_data_len(m) -
3242bfe3f2eSlogwang sizeof(struct ip6_hdr));
325a9643ea8Slogwang }
326a9643ea8Slogwang }
327a9643ea8Slogwang
328a9643ea8Slogwang sa->seq++;
329a9643ea8Slogwang esp->spi = rte_cpu_to_be_32(sa->spi);
3302bfe3f2eSlogwang esp->seq = rte_cpu_to_be_32((uint32_t)sa->seq);
331a9643ea8Slogwang
3322bfe3f2eSlogwang /* set iv */
3332bfe3f2eSlogwang uint64_t *iv = (uint64_t *)(esp + 1);
3342bfe3f2eSlogwang if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
3352bfe3f2eSlogwang *iv = rte_cpu_to_be_64(sa->seq);
3362bfe3f2eSlogwang } else {
3372bfe3f2eSlogwang switch (sa->cipher_algo) {
3382bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_NULL:
339d30ea906Sjfb8856606 case RTE_CRYPTO_CIPHER_3DES_CBC:
3402bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CBC:
3412bfe3f2eSlogwang memset(iv, 0, sa->iv_len);
3422bfe3f2eSlogwang break;
3432bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CTR:
3442bfe3f2eSlogwang *iv = rte_cpu_to_be_64(sa->seq);
3452bfe3f2eSlogwang break;
3462bfe3f2eSlogwang default:
3472bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP,
3482bfe3f2eSlogwang "unsupported cipher algorithm %u\n",
3492bfe3f2eSlogwang sa->cipher_algo);
3502bfe3f2eSlogwang return -EINVAL;
3512bfe3f2eSlogwang }
3522bfe3f2eSlogwang }
3532bfe3f2eSlogwang
354*4418919fSjohnjiang if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
355*4418919fSjohnjiang if (ips->security.ol_flags &
356*4418919fSjohnjiang RTE_SECURITY_TX_HW_TRAILER_OFFLOAD) {
3572bfe3f2eSlogwang /* Set the inner esp next protocol for HW trailer */
3582bfe3f2eSlogwang m->inner_esp_next_proto = nlp;
3592bfe3f2eSlogwang m->packet_type |= RTE_PTYPE_TUNNEL_ESP;
3602bfe3f2eSlogwang } else {
3612bfe3f2eSlogwang padding[pad_len - 2] = pad_len - 2;
3622bfe3f2eSlogwang padding[pad_len - 1] = nlp;
3632bfe3f2eSlogwang }
3642bfe3f2eSlogwang goto done;
3652bfe3f2eSlogwang }
3662bfe3f2eSlogwang
3672bfe3f2eSlogwang RTE_ASSERT(cop != NULL);
3682bfe3f2eSlogwang sym_cop = get_sym_cop(cop);
3692bfe3f2eSlogwang sym_cop->m_src = m;
3702bfe3f2eSlogwang
3712bfe3f2eSlogwang if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
3722bfe3f2eSlogwang uint8_t *aad;
3732bfe3f2eSlogwang
3742bfe3f2eSlogwang sym_cop->aead.data.offset = ip_hdr_len +
375*4418919fSjohnjiang sizeof(struct rte_esp_hdr) + sa->iv_len;
3762bfe3f2eSlogwang sym_cop->aead.data.length = pad_payload_len;
377a9643ea8Slogwang
378a9643ea8Slogwang /* Fill pad_len using default sequential scheme */
379a9643ea8Slogwang for (i = 0; i < pad_len - 2; i++)
380a9643ea8Slogwang padding[i] = i + 1;
381a9643ea8Slogwang padding[pad_len - 2] = pad_len - 2;
382a9643ea8Slogwang padding[pad_len - 1] = nlp;
383a9643ea8Slogwang
3842bfe3f2eSlogwang struct cnt_blk *icb = get_cnt_blk(m);
3852bfe3f2eSlogwang icb->salt = sa->salt;
3862bfe3f2eSlogwang icb->iv = rte_cpu_to_be_64(sa->seq);
3872bfe3f2eSlogwang icb->cnt = rte_cpu_to_be_32(1);
388a9643ea8Slogwang
3892bfe3f2eSlogwang aad = get_aad(m);
3902bfe3f2eSlogwang memcpy(aad, esp, 8);
3912bfe3f2eSlogwang sym_cop->aead.aad.data = aad;
3922bfe3f2eSlogwang sym_cop->aead.aad.phys_addr = rte_pktmbuf_iova_offset(m,
3932bfe3f2eSlogwang aad - rte_pktmbuf_mtod(m, uint8_t *));
3942bfe3f2eSlogwang
3952bfe3f2eSlogwang sym_cop->aead.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
3962bfe3f2eSlogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
3972bfe3f2eSlogwang sym_cop->aead.digest.phys_addr = rte_pktmbuf_iova_offset(m,
3982bfe3f2eSlogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
3992bfe3f2eSlogwang } else {
4002bfe3f2eSlogwang switch (sa->cipher_algo) {
4012bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_NULL:
402d30ea906Sjfb8856606 case RTE_CRYPTO_CIPHER_3DES_CBC:
4032bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CBC:
4042bfe3f2eSlogwang sym_cop->cipher.data.offset = ip_hdr_len +
405*4418919fSjohnjiang sizeof(struct rte_esp_hdr);
4062bfe3f2eSlogwang sym_cop->cipher.data.length = pad_payload_len + sa->iv_len;
4072bfe3f2eSlogwang break;
4082bfe3f2eSlogwang case RTE_CRYPTO_CIPHER_AES_CTR:
4092bfe3f2eSlogwang sym_cop->cipher.data.offset = ip_hdr_len +
410*4418919fSjohnjiang sizeof(struct rte_esp_hdr) + sa->iv_len;
411a9643ea8Slogwang sym_cop->cipher.data.length = pad_payload_len;
4122bfe3f2eSlogwang break;
4132bfe3f2eSlogwang default:
4142bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
4152bfe3f2eSlogwang sa->cipher_algo);
4162bfe3f2eSlogwang return -EINVAL;
4172bfe3f2eSlogwang }
418a9643ea8Slogwang
4192bfe3f2eSlogwang /* Fill pad_len using default sequential scheme */
4202bfe3f2eSlogwang for (i = 0; i < pad_len - 2; i++)
4212bfe3f2eSlogwang padding[i] = i + 1;
4222bfe3f2eSlogwang padding[pad_len - 2] = pad_len - 2;
4232bfe3f2eSlogwang padding[pad_len - 1] = nlp;
424a9643ea8Slogwang
4252bfe3f2eSlogwang struct cnt_blk *icb = get_cnt_blk(m);
4262bfe3f2eSlogwang icb->salt = sa->salt;
4272bfe3f2eSlogwang icb->iv = rte_cpu_to_be_64(sa->seq);
4282bfe3f2eSlogwang icb->cnt = rte_cpu_to_be_32(1);
4292bfe3f2eSlogwang
4302bfe3f2eSlogwang switch (sa->auth_algo) {
4312bfe3f2eSlogwang case RTE_CRYPTO_AUTH_NULL:
4322bfe3f2eSlogwang case RTE_CRYPTO_AUTH_SHA1_HMAC:
4332bfe3f2eSlogwang case RTE_CRYPTO_AUTH_SHA256_HMAC:
434a9643ea8Slogwang sym_cop->auth.data.offset = ip_hdr_len;
435*4418919fSjohnjiang sym_cop->auth.data.length = sizeof(struct rte_esp_hdr) +
4362bfe3f2eSlogwang sa->iv_len + pad_payload_len;
4372bfe3f2eSlogwang break;
4382bfe3f2eSlogwang default:
4392bfe3f2eSlogwang RTE_LOG(ERR, IPSEC_ESP, "unsupported auth algorithm %u\n",
4402bfe3f2eSlogwang sa->auth_algo);
4412bfe3f2eSlogwang return -EINVAL;
4422bfe3f2eSlogwang }
443a9643ea8Slogwang
444a9643ea8Slogwang sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
445a9643ea8Slogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
4462bfe3f2eSlogwang sym_cop->auth.digest.phys_addr = rte_pktmbuf_iova_offset(m,
447a9643ea8Slogwang rte_pktmbuf_pkt_len(m) - sa->digest_len);
4482bfe3f2eSlogwang }
449a9643ea8Slogwang
4502bfe3f2eSlogwang done:
451a9643ea8Slogwang return 0;
452a9643ea8Slogwang }
453a9643ea8Slogwang
454a9643ea8Slogwang int
esp_outbound_post(struct rte_mbuf * m,struct ipsec_sa * sa,struct rte_crypto_op * cop)4552bfe3f2eSlogwang esp_outbound_post(struct rte_mbuf *m,
4562bfe3f2eSlogwang struct ipsec_sa *sa,
457a9643ea8Slogwang struct rte_crypto_op *cop)
458a9643ea8Slogwang {
459*4418919fSjohnjiang enum rte_security_session_action_type type;
460a9643ea8Slogwang RTE_ASSERT(m != NULL);
461a9643ea8Slogwang RTE_ASSERT(sa != NULL);
462a9643ea8Slogwang
463*4418919fSjohnjiang type = ipsec_get_action_type(sa);
464*4418919fSjohnjiang
465*4418919fSjohnjiang if ((type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
466*4418919fSjohnjiang (type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
4672bfe3f2eSlogwang m->ol_flags |= PKT_TX_SEC_OFFLOAD;
4682bfe3f2eSlogwang } else {
4692bfe3f2eSlogwang RTE_ASSERT(cop != NULL);
470a9643ea8Slogwang if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
4711646932aSjfb8856606 RTE_LOG(ERR, IPSEC_ESP, "%s() failed crypto op\n",
4721646932aSjfb8856606 __func__);
473a9643ea8Slogwang return -1;
474a9643ea8Slogwang }
4752bfe3f2eSlogwang }
476a9643ea8Slogwang
477a9643ea8Slogwang return 0;
478a9643ea8Slogwang }
479