mempool: fix slow allocation of large mempools
[dpdk.git] / lib / librte_ipsec / esp_outb.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <rte_ipsec.h>
6 #include <rte_esp.h>
7 #include <rte_ip.h>
8 #include <rte_errno.h>
9 #include <rte_cryptodev.h>
10
11 #include "sa.h"
12 #include "ipsec_sqn.h"
13 #include "crypto.h"
14 #include "iph.h"
15 #include "misc.h"
16 #include "pad.h"
17
18
19 /*
20  * helper function to fill crypto_sym op for cipher+auth algorithms.
21  * used by outb_cop_prepare(), see below.
22  */
23 static inline void
24 sop_ciph_auth_prepare(struct rte_crypto_sym_op *sop,
25         const struct rte_ipsec_sa *sa, const union sym_op_data *icv,
26         uint32_t pofs, uint32_t plen)
27 {
28         sop->cipher.data.offset = sa->ctp.cipher.offset + pofs;
29         sop->cipher.data.length = sa->ctp.cipher.length + plen;
30         sop->auth.data.offset = sa->ctp.auth.offset + pofs;
31         sop->auth.data.length = sa->ctp.auth.length + plen;
32         sop->auth.digest.data = icv->va;
33         sop->auth.digest.phys_addr = icv->pa;
34 }
35
36 /*
37  * helper function to fill crypto_sym op for cipher+auth algorithms.
38  * used by outb_cop_prepare(), see below.
39  */
40 static inline void
41 sop_aead_prepare(struct rte_crypto_sym_op *sop,
42         const struct rte_ipsec_sa *sa, const union sym_op_data *icv,
43         uint32_t pofs, uint32_t plen)
44 {
45         sop->aead.data.offset = sa->ctp.cipher.offset + pofs;
46         sop->aead.data.length = sa->ctp.cipher.length + plen;
47         sop->aead.digest.data = icv->va;
48         sop->aead.digest.phys_addr = icv->pa;
49         sop->aead.aad.data = icv->va + sa->icv_len;
50         sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
51 }
52
53 /*
54  * setup crypto op and crypto sym op for ESP outbound packet.
55  */
56 static inline void
57 outb_cop_prepare(struct rte_crypto_op *cop,
58         const struct rte_ipsec_sa *sa, const uint64_t ivp[IPSEC_MAX_IV_QWORD],
59         const union sym_op_data *icv, uint32_t hlen, uint32_t plen)
60 {
61         struct rte_crypto_sym_op *sop;
62         struct aead_gcm_iv *gcm;
63         struct aesctr_cnt_blk *ctr;
64         uint32_t algo;
65
66         algo = sa->algo_type;
67
68         /* fill sym op fields */
69         sop = cop->sym;
70
71         switch (algo) {
72         case ALGO_TYPE_AES_CBC:
73                 /* Cipher-Auth (AES-CBC *) case */
74         case ALGO_TYPE_3DES_CBC:
75                 /* Cipher-Auth (3DES-CBC *) case */
76         case ALGO_TYPE_NULL:
77                 /* NULL case */
78                 sop_ciph_auth_prepare(sop, sa, icv, hlen, plen);
79                 break;
80         case ALGO_TYPE_AES_GCM:
81                 /* AEAD (AES_GCM) case */
82                 sop_aead_prepare(sop, sa, icv, hlen, plen);
83
84                 /* fill AAD IV (located inside crypto op) */
85                 gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
86                         sa->iv_ofs);
87                 aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
88                 break;
89         case ALGO_TYPE_AES_CTR:
90                 /* Cipher-Auth (AES-CTR *) case */
91                 sop_ciph_auth_prepare(sop, sa, icv, hlen, plen);
92
93                 /* fill CTR block (located inside crypto op) */
94                 ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
95                         sa->iv_ofs);
96                 aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
97                 break;
98         }
99 }
100
101 /*
102  * setup/update packet data and metadata for ESP outbound tunnel case.
103  */
104 static inline int32_t
105 outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
106         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
107         union sym_op_data *icv, uint8_t sqh_len)
108 {
109         uint32_t clen, hlen, l2len, pdlen, pdofs, plen, tlen;
110         struct rte_mbuf *ml;
111         struct rte_esp_hdr *esph;
112         struct rte_esp_tail *espt;
113         char *ph, *pt;
114         uint64_t *iv;
115
116         /* calculate extra header space required */
117         hlen = sa->hdr_len + sa->iv_len + sizeof(*esph);
118
119         /* size of ipsec protected data */
120         l2len = mb->l2_len;
121         plen = mb->pkt_len - l2len;
122
123         /* number of bytes to encrypt */
124         clen = plen + sizeof(*espt);
125         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
126
127         /* pad length + esp tail */
128         pdlen = clen - plen;
129         tlen = pdlen + sa->icv_len + sqh_len;
130
131         /* do append and prepend */
132         ml = rte_pktmbuf_lastseg(mb);
133         if (tlen + sa->aad_len > rte_pktmbuf_tailroom(ml))
134                 return -ENOSPC;
135
136         /* prepend header */
137         ph = rte_pktmbuf_prepend(mb, hlen - l2len);
138         if (ph == NULL)
139                 return -ENOSPC;
140
141         /* append tail */
142         pdofs = ml->data_len;
143         ml->data_len += tlen;
144         mb->pkt_len += tlen;
145         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
146
147         /* update pkt l2/l3 len */
148         mb->tx_offload = (mb->tx_offload & sa->tx_offload.msk) |
149                 sa->tx_offload.val;
150
151         /* copy tunnel pkt header */
152         rte_memcpy(ph, sa->hdr, sa->hdr_len);
153
154         /* update original and new ip header fields */
155         update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen,
156                         mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc));
157
158         /* update spi, seqn and iv */
159         esph = (struct rte_esp_hdr *)(ph + sa->hdr_len);
160         iv = (uint64_t *)(esph + 1);
161         copy_iv(iv, ivp, sa->iv_len);
162
163         esph->spi = sa->spi;
164         esph->seq = sqn_low32(sqc);
165
166         /* offset for ICV */
167         pdofs += pdlen + sa->sqh_len;
168
169         /* pad length */
170         pdlen -= sizeof(*espt);
171
172         /* copy padding data */
173         rte_memcpy(pt, esp_pad_bytes, pdlen);
174
175         /* update esp trailer */
176         espt = (struct rte_esp_tail *)(pt + pdlen);
177         espt->pad_len = pdlen;
178         espt->next_proto = sa->proto;
179
180         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
181         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
182
183         return clen;
184 }
185
186 /*
187  * for pure cryptodev (lookaside none) depending on SA settings,
188  * we might have to write some extra data to the packet.
189  */
190 static inline void
191 outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
192         const union sym_op_data *icv)
193 {
194         uint32_t *psqh;
195         struct aead_gcm_aad *aad;
196
197         /* insert SQN.hi between ESP trailer and ICV */
198         if (sa->sqh_len != 0) {
199                 psqh = (uint32_t *)(icv->va - sa->sqh_len);
200                 psqh[0] = sqn_hi32(sqc);
201         }
202
203         /*
204          * fill IV and AAD fields, if any (aad fields are placed after icv),
205          * right now we support only one AEAD algorithm: AES-GCM .
206          */
207         if (sa->aad_len != 0) {
208                 aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
209                 aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
210         }
211 }
212
213 /*
214  * setup/update packets and crypto ops for ESP outbound tunnel case.
215  */
216 uint16_t
217 esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
218         struct rte_crypto_op *cop[], uint16_t num)
219 {
220         int32_t rc;
221         uint32_t i, k, n;
222         uint64_t sqn;
223         rte_be64_t sqc;
224         struct rte_ipsec_sa *sa;
225         struct rte_cryptodev_sym_session *cs;
226         union sym_op_data icv;
227         uint64_t iv[IPSEC_MAX_IV_QWORD];
228         uint32_t dr[num];
229
230         sa = ss->sa;
231         cs = ss->crypto.ses;
232
233         n = num;
234         sqn = esn_outb_update_sqn(sa, &n);
235         if (n != num)
236                 rte_errno = EOVERFLOW;
237
238         k = 0;
239         for (i = 0; i != n; i++) {
240
241                 sqc = rte_cpu_to_be_64(sqn + i);
242                 gen_iv(iv, sqc);
243
244                 /* try to update the packet itself */
245                 rc = outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv,
246                                           sa->sqh_len);
247                 /* success, setup crypto op */
248                 if (rc >= 0) {
249                         outb_pkt_xprepare(sa, sqc, &icv);
250                         lksd_none_cop_prepare(cop[k], cs, mb[i]);
251                         outb_cop_prepare(cop[k], sa, iv, &icv, 0, rc);
252                         k++;
253                 /* failure, put packet into the death-row */
254                 } else {
255                         dr[i - k] = i;
256                         rte_errno = -rc;
257                 }
258         }
259
260          /* copy not prepared mbufs beyond good ones */
261         if (k != n && k != 0)
262                 move_bad_mbufs(mb, dr, n, n - k);
263
264         return k;
265 }
266
267 /*
268  * setup/update packet data and metadata for ESP outbound transport case.
269  */
270 static inline int32_t
271 outb_trs_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
272         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
273         uint32_t l2len, uint32_t l3len, union sym_op_data *icv,
274         uint8_t sqh_len)
275 {
276         uint8_t np;
277         uint32_t clen, hlen, pdlen, pdofs, plen, tlen, uhlen;
278         struct rte_mbuf *ml;
279         struct rte_esp_hdr *esph;
280         struct rte_esp_tail *espt;
281         char *ph, *pt;
282         uint64_t *iv;
283
284         uhlen = l2len + l3len;
285         plen = mb->pkt_len - uhlen;
286
287         /* calculate extra header space required */
288         hlen = sa->iv_len + sizeof(*esph);
289
290         /* number of bytes to encrypt */
291         clen = plen + sizeof(*espt);
292         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
293
294         /* pad length + esp tail */
295         pdlen = clen - plen;
296         tlen = pdlen + sa->icv_len + sqh_len;
297
298         /* do append and insert */
299         ml = rte_pktmbuf_lastseg(mb);
300         if (tlen + sa->aad_len > rte_pktmbuf_tailroom(ml))
301                 return -ENOSPC;
302
303         /* prepend space for ESP header */
304         ph = rte_pktmbuf_prepend(mb, hlen);
305         if (ph == NULL)
306                 return -ENOSPC;
307
308         /* append tail */
309         pdofs = ml->data_len;
310         ml->data_len += tlen;
311         mb->pkt_len += tlen;
312         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
313
314         /* shift L2/L3 headers */
315         insert_esph(ph, ph + hlen, uhlen);
316
317         /* update ip  header fields */
318         np = update_trs_l3hdr(sa, ph + l2len, mb->pkt_len - sqh_len, l2len,
319                         l3len, IPPROTO_ESP);
320
321         /* update spi, seqn and iv */
322         esph = (struct rte_esp_hdr *)(ph + uhlen);
323         iv = (uint64_t *)(esph + 1);
324         copy_iv(iv, ivp, sa->iv_len);
325
326         esph->spi = sa->spi;
327         esph->seq = sqn_low32(sqc);
328
329         /* offset for ICV */
330         pdofs += pdlen + sa->sqh_len;
331
332         /* pad length */
333         pdlen -= sizeof(*espt);
334
335         /* copy padding data */
336         rte_memcpy(pt, esp_pad_bytes, pdlen);
337
338         /* update esp trailer */
339         espt = (struct rte_esp_tail *)(pt + pdlen);
340         espt->pad_len = pdlen;
341         espt->next_proto = np;
342
343         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
344         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
345
346         return clen;
347 }
348
349 /*
350  * setup/update packets and crypto ops for ESP outbound transport case.
351  */
352 uint16_t
353 esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
354         struct rte_crypto_op *cop[], uint16_t num)
355 {
356         int32_t rc;
357         uint32_t i, k, n, l2, l3;
358         uint64_t sqn;
359         rte_be64_t sqc;
360         struct rte_ipsec_sa *sa;
361         struct rte_cryptodev_sym_session *cs;
362         union sym_op_data icv;
363         uint64_t iv[IPSEC_MAX_IV_QWORD];
364         uint32_t dr[num];
365
366         sa = ss->sa;
367         cs = ss->crypto.ses;
368
369         n = num;
370         sqn = esn_outb_update_sqn(sa, &n);
371         if (n != num)
372                 rte_errno = EOVERFLOW;
373
374         k = 0;
375         for (i = 0; i != n; i++) {
376
377                 l2 = mb[i]->l2_len;
378                 l3 = mb[i]->l3_len;
379
380                 sqc = rte_cpu_to_be_64(sqn + i);
381                 gen_iv(iv, sqc);
382
383                 /* try to update the packet itself */
384                 rc = outb_trs_pkt_prepare(sa, sqc, iv, mb[i], l2, l3, &icv,
385                                           sa->sqh_len);
386                 /* success, setup crypto op */
387                 if (rc >= 0) {
388                         outb_pkt_xprepare(sa, sqc, &icv);
389                         lksd_none_cop_prepare(cop[k], cs, mb[i]);
390                         outb_cop_prepare(cop[k], sa, iv, &icv, l2 + l3, rc);
391                         k++;
392                 /* failure, put packet into the death-row */
393                 } else {
394                         dr[i - k] = i;
395                         rte_errno = -rc;
396                 }
397         }
398
399         /* copy not prepared mbufs beyond good ones */
400         if (k != n && k != 0)
401                 move_bad_mbufs(mb, dr, n, n - k);
402
403         return k;
404 }
405
406 /*
407  * process outbound packets for SA with ESN support,
408  * for algorithms that require SQN.hibits to be implictly included
409  * into digest computation.
410  * In that case we have to move ICV bytes back to their proper place.
411  */
412 uint16_t
413 esp_outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
414         uint16_t num)
415 {
416         uint32_t i, k, icv_len, *icv;
417         struct rte_mbuf *ml;
418         struct rte_ipsec_sa *sa;
419         uint32_t dr[num];
420
421         sa = ss->sa;
422
423         k = 0;
424         icv_len = sa->icv_len;
425
426         for (i = 0; i != num; i++) {
427                 if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0) {
428                         ml = rte_pktmbuf_lastseg(mb[i]);
429                         /* remove high-order 32 bits of esn from packet len */
430                         mb[i]->pkt_len -= sa->sqh_len;
431                         ml->data_len -= sa->sqh_len;
432                         icv = rte_pktmbuf_mtod_offset(ml, void *,
433                                 ml->data_len - icv_len);
434                         remove_sqh(icv, icv_len);
435                         k++;
436                 } else
437                         dr[i - k] = i;
438         }
439
440         /* handle unprocessed mbufs */
441         if (k != num) {
442                 rte_errno = EBADMSG;
443                 if (k != 0)
444                         move_bad_mbufs(mb, dr, num, num - k);
445         }
446
447         return k;
448 }
449
450 /*
451  * prepare packets for inline ipsec processing:
452  * set ol_flags and attach metadata.
453  */
454 static inline void
455 inline_outb_mbuf_prepare(const struct rte_ipsec_session *ss,
456         struct rte_mbuf *mb[], uint16_t num)
457 {
458         uint32_t i, ol_flags;
459
460         ol_flags = ss->security.ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA;
461         for (i = 0; i != num; i++) {
462
463                 mb[i]->ol_flags |= PKT_TX_SEC_OFFLOAD;
464                 if (ol_flags != 0)
465                         rte_security_set_pkt_metadata(ss->security.ctx,
466                                 ss->security.ses, mb[i], NULL);
467         }
468 }
469
470 /*
471  * process group of ESP outbound tunnel packets destined for
472  * INLINE_CRYPTO type of device.
473  */
474 uint16_t
475 inline_outb_tun_pkt_process(const struct rte_ipsec_session *ss,
476         struct rte_mbuf *mb[], uint16_t num)
477 {
478         int32_t rc;
479         uint32_t i, k, n;
480         uint64_t sqn;
481         rte_be64_t sqc;
482         struct rte_ipsec_sa *sa;
483         union sym_op_data icv;
484         uint64_t iv[IPSEC_MAX_IV_QWORD];
485         uint32_t dr[num];
486
487         sa = ss->sa;
488
489         n = num;
490         sqn = esn_outb_update_sqn(sa, &n);
491         if (n != num)
492                 rte_errno = EOVERFLOW;
493
494         k = 0;
495         for (i = 0; i != n; i++) {
496
497                 sqc = rte_cpu_to_be_64(sqn + i);
498                 gen_iv(iv, sqc);
499
500                 /* try to update the packet itself */
501                 rc = outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv, 0);
502
503                 k += (rc >= 0);
504
505                 /* failure, put packet into the death-row */
506                 if (rc < 0) {
507                         dr[i - k] = i;
508                         rte_errno = -rc;
509                 }
510         }
511
512         /* copy not processed mbufs beyond good ones */
513         if (k != n && k != 0)
514                 move_bad_mbufs(mb, dr, n, n - k);
515
516         inline_outb_mbuf_prepare(ss, mb, k);
517         return k;
518 }
519
520 /*
521  * process group of ESP outbound transport packets destined for
522  * INLINE_CRYPTO type of device.
523  */
524 uint16_t
525 inline_outb_trs_pkt_process(const struct rte_ipsec_session *ss,
526         struct rte_mbuf *mb[], uint16_t num)
527 {
528         int32_t rc;
529         uint32_t i, k, n, l2, l3;
530         uint64_t sqn;
531         rte_be64_t sqc;
532         struct rte_ipsec_sa *sa;
533         union sym_op_data icv;
534         uint64_t iv[IPSEC_MAX_IV_QWORD];
535         uint32_t dr[num];
536
537         sa = ss->sa;
538
539         n = num;
540         sqn = esn_outb_update_sqn(sa, &n);
541         if (n != num)
542                 rte_errno = EOVERFLOW;
543
544         k = 0;
545         for (i = 0; i != n; i++) {
546
547                 l2 = mb[i]->l2_len;
548                 l3 = mb[i]->l3_len;
549
550                 sqc = rte_cpu_to_be_64(sqn + i);
551                 gen_iv(iv, sqc);
552
553                 /* try to update the packet itself */
554                 rc = outb_trs_pkt_prepare(sa, sqc, iv, mb[i],
555                                 l2, l3, &icv, 0);
556
557                 k += (rc >= 0);
558
559                 /* failure, put packet into the death-row */
560                 if (rc < 0) {
561                         dr[i - k] = i;
562                         rte_errno = -rc;
563                 }
564         }
565
566         /* copy not processed mbufs beyond good ones */
567         if (k != n && k != 0)
568                 move_bad_mbufs(mb, dr, n, n - k);
569
570         inline_outb_mbuf_prepare(ss, mb, k);
571         return k;
572 }
573
574 /*
575  * outbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
576  * actual processing is done by HW/PMD, just set flags and metadata.
577  */
578 uint16_t
579 inline_proto_outb_pkt_process(const struct rte_ipsec_session *ss,
580         struct rte_mbuf *mb[], uint16_t num)
581 {
582         inline_outb_mbuf_prepare(ss, mb, num);
583         return num;
584 }