ipsec: add Tx offload template into SA
[dpdk.git] / lib / librte_ipsec / sa.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 "pad.h"
16
17 #define MBUF_MAX_L2_LEN         RTE_LEN2MASK(RTE_MBUF_L2_LEN_BITS, uint64_t)
18 #define MBUF_MAX_L3_LEN         RTE_LEN2MASK(RTE_MBUF_L3_LEN_BITS, uint64_t)
19
20 /* some helper structures */
21 struct crypto_xform {
22         struct rte_crypto_auth_xform *auth;
23         struct rte_crypto_cipher_xform *cipher;
24         struct rte_crypto_aead_xform *aead;
25 };
26
27 /*
28  * helper routine, fills internal crypto_xform structure.
29  */
30 static int
31 fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
32         const struct rte_ipsec_sa_prm *prm)
33 {
34         struct rte_crypto_sym_xform *xf, *xfn;
35
36         memset(xform, 0, sizeof(*xform));
37
38         xf = prm->crypto_xform;
39         if (xf == NULL)
40                 return -EINVAL;
41
42         xfn = xf->next;
43
44         /* for AEAD just one xform required */
45         if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
46                 if (xfn != NULL)
47                         return -EINVAL;
48                 xform->aead = &xf->aead;
49         /*
50          * CIPHER+AUTH xforms are expected in strict order,
51          * depending on SA direction:
52          * inbound: AUTH+CIPHER
53          * outbound: CIPHER+AUTH
54          */
55         } else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
56
57                 /* wrong order or no cipher */
58                 if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
59                                 xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
60                         return -EINVAL;
61
62                 xform->auth = &xf->auth;
63                 xform->cipher = &xfn->cipher;
64
65         } else {
66
67                 /* wrong order or no auth */
68                 if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
69                                 xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
70                         return -EINVAL;
71
72                 xform->cipher = &xf->cipher;
73                 xform->auth = &xfn->auth;
74         }
75
76         return 0;
77 }
78
79 uint64_t __rte_experimental
80 rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
81 {
82         return sa->type;
83 }
84
85 static int32_t
86 ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
87 {
88         uint32_t n, sz, wsz;
89
90         wsz = *wnd_sz;
91         n = 0;
92
93         if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
94
95                 /*
96                  * RFC 4303 recommends 64 as minimum window size.
97                  * there is no point to use ESN mode without SQN window,
98                  * so make sure we have at least 64 window when ESN is enalbed.
99                  */
100                 wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
101                         RTE_IPSEC_SATP_ESN_DISABLE) ?
102                         wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
103                 if (wsz != 0)
104                         n = replay_num_bucket(wsz);
105         }
106
107         if (n > WINDOW_BUCKET_MAX)
108                 return -EINVAL;
109
110         *wnd_sz = wsz;
111         *nb_bucket = n;
112
113         sz = rsn_size(n);
114         if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
115                 sz *= REPLAY_SQN_NUM;
116
117         sz += sizeof(struct rte_ipsec_sa);
118         return sz;
119 }
120
121 void __rte_experimental
122 rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
123 {
124         memset(sa, 0, sa->size);
125 }
126
127 /*
128  * Determine expected SA type based on input parameters.
129  */
130 static int
131 fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
132 {
133         uint64_t tp;
134
135         tp = 0;
136
137         if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
138                 tp |= RTE_IPSEC_SATP_PROTO_AH;
139         else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
140                 tp |= RTE_IPSEC_SATP_PROTO_ESP;
141         else
142                 return -EINVAL;
143
144         if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
145                 tp |= RTE_IPSEC_SATP_DIR_OB;
146         else if (prm->ipsec_xform.direction ==
147                         RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
148                 tp |= RTE_IPSEC_SATP_DIR_IB;
149         else
150                 return -EINVAL;
151
152         if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
153                 if (prm->ipsec_xform.tunnel.type ==
154                                 RTE_SECURITY_IPSEC_TUNNEL_IPV4)
155                         tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
156                 else if (prm->ipsec_xform.tunnel.type ==
157                                 RTE_SECURITY_IPSEC_TUNNEL_IPV6)
158                         tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
159                 else
160                         return -EINVAL;
161
162                 if (prm->tun.next_proto == IPPROTO_IPIP)
163                         tp |= RTE_IPSEC_SATP_IPV4;
164                 else if (prm->tun.next_proto == IPPROTO_IPV6)
165                         tp |= RTE_IPSEC_SATP_IPV6;
166                 else
167                         return -EINVAL;
168         } else if (prm->ipsec_xform.mode ==
169                         RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
170                 tp |= RTE_IPSEC_SATP_MODE_TRANS;
171                 if (prm->trs.proto == IPPROTO_IPIP)
172                         tp |= RTE_IPSEC_SATP_IPV4;
173                 else if (prm->trs.proto == IPPROTO_IPV6)
174                         tp |= RTE_IPSEC_SATP_IPV6;
175                 else
176                         return -EINVAL;
177         } else
178                 return -EINVAL;
179
180         /* check for ESN flag */
181         if (prm->ipsec_xform.options.esn == 0)
182                 tp |= RTE_IPSEC_SATP_ESN_DISABLE;
183         else
184                 tp |= RTE_IPSEC_SATP_ESN_ENABLE;
185
186         /* interpret flags */
187         if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
188                 tp |= RTE_IPSEC_SATP_SQN_ATOM;
189         else
190                 tp |= RTE_IPSEC_SATP_SQN_RAW;
191
192         *type = tp;
193         return 0;
194 }
195
196 /*
197  * Init ESP inbound specific things.
198  */
199 static void
200 esp_inb_init(struct rte_ipsec_sa *sa)
201 {
202         /* these params may differ with new algorithms support */
203         sa->ctp.auth.offset = 0;
204         sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
205         sa->ctp.cipher.offset = sizeof(struct esp_hdr) + sa->iv_len;
206         sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
207 }
208
209 /*
210  * Init ESP inbound tunnel specific things.
211  */
212 static void
213 esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
214 {
215         sa->proto = prm->tun.next_proto;
216         esp_inb_init(sa);
217 }
218
219 /*
220  * Init ESP outbound specific things.
221  */
222 static void
223 esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
224 {
225         uint8_t algo_type;
226
227         sa->sqn.outb.raw = 1;
228
229         /* these params may differ with new algorithms support */
230         sa->ctp.auth.offset = hlen;
231         sa->ctp.auth.length = sizeof(struct esp_hdr) + sa->iv_len + sa->sqh_len;
232
233         algo_type = sa->algo_type;
234
235         switch (algo_type) {
236         case ALGO_TYPE_AES_GCM:
237         case ALGO_TYPE_AES_CTR:
238         case ALGO_TYPE_NULL:
239                 sa->ctp.cipher.offset = hlen + sizeof(struct esp_hdr) +
240                         sa->iv_len;
241                 sa->ctp.cipher.length = 0;
242                 break;
243         case ALGO_TYPE_AES_CBC:
244         case ALGO_TYPE_3DES_CBC:
245                 sa->ctp.cipher.offset = sa->hdr_len + sizeof(struct esp_hdr);
246                 sa->ctp.cipher.length = sa->iv_len;
247                 break;
248         }
249 }
250
251 /*
252  * Init ESP outbound tunnel specific things.
253  */
254 static void
255 esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
256 {
257         sa->proto = prm->tun.next_proto;
258         sa->hdr_len = prm->tun.hdr_len;
259         sa->hdr_l3_off = prm->tun.hdr_l3_off;
260
261         /* update l2_len and l3_len fields for outbound mbuf */
262         sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
263                 sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
264
265         memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
266
267         esp_outb_init(sa, sa->hdr_len);
268 }
269
270 /*
271  * helper function, init SA structure.
272  */
273 static int
274 esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
275         const struct crypto_xform *cxf)
276 {
277         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
278                                 RTE_IPSEC_SATP_MODE_MASK;
279
280         if (cxf->aead != NULL) {
281                 switch (cxf->aead->algo) {
282                 case RTE_CRYPTO_AEAD_AES_GCM:
283                         /* RFC 4106 */
284                         sa->aad_len = sizeof(struct aead_gcm_aad);
285                         sa->icv_len = cxf->aead->digest_length;
286                         sa->iv_ofs = cxf->aead->iv.offset;
287                         sa->iv_len = sizeof(uint64_t);
288                         sa->pad_align = IPSEC_PAD_AES_GCM;
289                         sa->algo_type = ALGO_TYPE_AES_GCM;
290                         break;
291                 default:
292                         return -EINVAL;
293                 }
294         } else {
295                 sa->icv_len = cxf->auth->digest_length;
296                 sa->iv_ofs = cxf->cipher->iv.offset;
297                 sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
298
299                 switch (cxf->cipher->algo) {
300                 case RTE_CRYPTO_CIPHER_NULL:
301                         sa->pad_align = IPSEC_PAD_NULL;
302                         sa->iv_len = 0;
303                         sa->algo_type = ALGO_TYPE_NULL;
304                         break;
305
306                 case RTE_CRYPTO_CIPHER_AES_CBC:
307                         sa->pad_align = IPSEC_PAD_AES_CBC;
308                         sa->iv_len = IPSEC_MAX_IV_SIZE;
309                         sa->algo_type = ALGO_TYPE_AES_CBC;
310                         break;
311
312                 case RTE_CRYPTO_CIPHER_AES_CTR:
313                         /* RFC 3686 */
314                         sa->pad_align = IPSEC_PAD_AES_CTR;
315                         sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
316                         sa->algo_type = ALGO_TYPE_AES_CTR;
317                         break;
318
319                 case RTE_CRYPTO_CIPHER_3DES_CBC:
320                         /* RFC 1851 */
321                         sa->pad_align = IPSEC_PAD_3DES_CBC;
322                         sa->iv_len = IPSEC_3DES_IV_SIZE;
323                         sa->algo_type = ALGO_TYPE_3DES_CBC;
324                         break;
325
326                 default:
327                         return -EINVAL;
328                 }
329         }
330
331         sa->udata = prm->userdata;
332         sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
333         sa->salt = prm->ipsec_xform.salt;
334
335         /* preserve all values except l2_len and l3_len */
336         sa->tx_offload.msk =
337                 ~rte_mbuf_tx_offload(MBUF_MAX_L2_LEN, MBUF_MAX_L3_LEN,
338                                 0, 0, 0, 0, 0);
339
340         switch (sa->type & msk) {
341         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
342         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
343                 esp_inb_tun_init(sa, prm);
344                 break;
345         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
346                 esp_inb_init(sa);
347                 break;
348         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
349         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
350                 esp_outb_tun_init(sa, prm);
351                 break;
352         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
353                 esp_outb_init(sa, 0);
354                 break;
355         }
356
357         return 0;
358 }
359
360 /*
361  * helper function, init SA replay structure.
362  */
363 static void
364 fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket)
365 {
366         sa->replay.win_sz = wnd_sz;
367         sa->replay.nb_bucket = nb_bucket;
368         sa->replay.bucket_index_mask = nb_bucket - 1;
369         sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
370         if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
371                 sa->sqn.inb.rsn[1] = (struct replay_sqn *)
372                         ((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
373 }
374
375 int __rte_experimental
376 rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
377 {
378         uint64_t type;
379         uint32_t nb, wsz;
380         int32_t rc;
381
382         if (prm == NULL)
383                 return -EINVAL;
384
385         /* determine SA type */
386         rc = fill_sa_type(prm, &type);
387         if (rc != 0)
388                 return rc;
389
390         /* determine required size */
391         wsz = prm->replay_win_sz;
392         return ipsec_sa_size(type, &wsz, &nb);
393 }
394
395 int __rte_experimental
396 rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
397         uint32_t size)
398 {
399         int32_t rc, sz;
400         uint32_t nb, wsz;
401         uint64_t type;
402         struct crypto_xform cxf;
403
404         if (sa == NULL || prm == NULL)
405                 return -EINVAL;
406
407         /* determine SA type */
408         rc = fill_sa_type(prm, &type);
409         if (rc != 0)
410                 return rc;
411
412         /* determine required size */
413         wsz = prm->replay_win_sz;
414         sz = ipsec_sa_size(type, &wsz, &nb);
415         if (sz < 0)
416                 return sz;
417         else if (size < (uint32_t)sz)
418                 return -ENOSPC;
419
420         /* only esp is supported right now */
421         if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
422                 return -EINVAL;
423
424         if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
425                         prm->tun.hdr_len > sizeof(sa->hdr))
426                 return -EINVAL;
427
428         rc = fill_crypto_xform(&cxf, type, prm);
429         if (rc != 0)
430                 return rc;
431
432         /* initialize SA */
433
434         memset(sa, 0, sz);
435         sa->type = type;
436         sa->size = sz;
437
438         /* check for ESN flag */
439         sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
440                 UINT32_MAX : UINT64_MAX;
441
442         rc = esp_sa_init(sa, prm, &cxf);
443         if (rc != 0)
444                 rte_ipsec_sa_fini(sa);
445
446         /* fill replay window related fields */
447         if (nb != 0)
448                 fill_sa_replay(sa, wsz, nb);
449
450         return sz;
451 }
452
453 static inline void
454 mbuf_bulk_copy(struct rte_mbuf *dst[], struct rte_mbuf * const src[],
455         uint32_t num)
456 {
457         uint32_t i;
458
459         for (i = 0; i != num; i++)
460                 dst[i] = src[i];
461 }
462
463 /*
464  * setup crypto ops for LOOKASIDE_NONE (pure crypto) type of devices.
465  */
466 static inline void
467 lksd_none_cop_prepare(const struct rte_ipsec_session *ss,
468         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
469 {
470         uint32_t i;
471         struct rte_crypto_sym_op *sop;
472
473         for (i = 0; i != num; i++) {
474                 sop = cop[i]->sym;
475                 cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
476                 cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
477                 cop[i]->sess_type = RTE_CRYPTO_OP_WITH_SESSION;
478                 sop->m_src = mb[i];
479                 __rte_crypto_sym_op_attach_sym_session(sop, ss->crypto.ses);
480         }
481 }
482
483 /*
484  * setup crypto op and crypto sym op for ESP outbound packet.
485  */
486 static inline void
487 esp_outb_cop_prepare(struct rte_crypto_op *cop,
488         const struct rte_ipsec_sa *sa, const uint64_t ivp[IPSEC_MAX_IV_QWORD],
489         const union sym_op_data *icv, uint32_t hlen, uint32_t plen)
490 {
491         struct rte_crypto_sym_op *sop;
492         struct aead_gcm_iv *gcm;
493         struct aesctr_cnt_blk *ctr;
494         uint8_t algo_type = sa->algo_type;
495
496         /* fill sym op fields */
497         sop = cop->sym;
498
499         switch (algo_type) {
500         case ALGO_TYPE_AES_CBC:
501                 /* Cipher-Auth (AES-CBC *) case */
502         case ALGO_TYPE_3DES_CBC:
503                 /* Cipher-Auth (3DES-CBC *) case */
504         case ALGO_TYPE_NULL:
505                 /* NULL case */
506                 sop->cipher.data.offset = sa->ctp.cipher.offset + hlen;
507                 sop->cipher.data.length = sa->ctp.cipher.length + plen;
508                 sop->auth.data.offset = sa->ctp.auth.offset + hlen;
509                 sop->auth.data.length = sa->ctp.auth.length + plen;
510                 sop->auth.digest.data = icv->va;
511                 sop->auth.digest.phys_addr = icv->pa;
512                 break;
513         case ALGO_TYPE_AES_GCM:
514                 /* AEAD (AES_GCM) case */
515                 sop->aead.data.offset = sa->ctp.cipher.offset + hlen;
516                 sop->aead.data.length = sa->ctp.cipher.length + plen;
517                 sop->aead.digest.data = icv->va;
518                 sop->aead.digest.phys_addr = icv->pa;
519                 sop->aead.aad.data = icv->va + sa->icv_len;
520                 sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
521
522                 /* fill AAD IV (located inside crypto op) */
523                 gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
524                         sa->iv_ofs);
525                 aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
526                 break;
527         case ALGO_TYPE_AES_CTR:
528                 /* Cipher-Auth (AES-CTR *) case */
529                 sop->cipher.data.offset = sa->ctp.cipher.offset + hlen;
530                 sop->cipher.data.length = sa->ctp.cipher.length + plen;
531                 sop->auth.data.offset = sa->ctp.auth.offset + hlen;
532                 sop->auth.data.length = sa->ctp.auth.length + plen;
533                 sop->auth.digest.data = icv->va;
534                 sop->auth.digest.phys_addr = icv->pa;
535
536                 ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
537                         sa->iv_ofs);
538                 aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
539                 break;
540         default:
541                 break;
542         }
543 }
544
545 /*
546  * setup/update packet data and metadata for ESP outbound tunnel case.
547  */
548 static inline int32_t
549 esp_outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
550         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
551         union sym_op_data *icv)
552 {
553         uint32_t clen, hlen, l2len, pdlen, pdofs, plen, tlen;
554         struct rte_mbuf *ml;
555         struct esp_hdr *esph;
556         struct esp_tail *espt;
557         char *ph, *pt;
558         uint64_t *iv;
559
560         /* calculate extra header space required */
561         hlen = sa->hdr_len + sa->iv_len + sizeof(*esph);
562
563         /* size of ipsec protected data */
564         l2len = mb->l2_len;
565         plen = mb->pkt_len - l2len;
566
567         /* number of bytes to encrypt */
568         clen = plen + sizeof(*espt);
569         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
570
571         /* pad length + esp tail */
572         pdlen = clen - plen;
573         tlen = pdlen + sa->icv_len;
574
575         /* do append and prepend */
576         ml = rte_pktmbuf_lastseg(mb);
577         if (tlen + sa->sqh_len + sa->aad_len > rte_pktmbuf_tailroom(ml))
578                 return -ENOSPC;
579
580         /* prepend header */
581         ph = rte_pktmbuf_prepend(mb, hlen - l2len);
582         if (ph == NULL)
583                 return -ENOSPC;
584
585         /* append tail */
586         pdofs = ml->data_len;
587         ml->data_len += tlen;
588         mb->pkt_len += tlen;
589         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
590
591         /* update pkt l2/l3 len */
592         mb->tx_offload = (mb->tx_offload & sa->tx_offload.msk) |
593                 sa->tx_offload.val;
594
595         /* copy tunnel pkt header */
596         rte_memcpy(ph, sa->hdr, sa->hdr_len);
597
598         /* update original and new ip header fields */
599         update_tun_l3hdr(sa, ph + sa->hdr_l3_off, mb->pkt_len, sa->hdr_l3_off,
600                         sqn_low16(sqc));
601
602         /* update spi, seqn and iv */
603         esph = (struct esp_hdr *)(ph + sa->hdr_len);
604         iv = (uint64_t *)(esph + 1);
605         copy_iv(iv, ivp, sa->iv_len);
606
607         esph->spi = sa->spi;
608         esph->seq = sqn_low32(sqc);
609
610         /* offset for ICV */
611         pdofs += pdlen + sa->sqh_len;
612
613         /* pad length */
614         pdlen -= sizeof(*espt);
615
616         /* copy padding data */
617         rte_memcpy(pt, esp_pad_bytes, pdlen);
618
619         /* update esp trailer */
620         espt = (struct esp_tail *)(pt + pdlen);
621         espt->pad_len = pdlen;
622         espt->next_proto = sa->proto;
623
624         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
625         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
626
627         return clen;
628 }
629
630 /*
631  * for pure cryptodev (lookaside none) depending on SA settings,
632  * we might have to write some extra data to the packet.
633  */
634 static inline void
635 outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
636         const union sym_op_data *icv)
637 {
638         uint32_t *psqh;
639         struct aead_gcm_aad *aad;
640         uint8_t algo_type = sa->algo_type;
641
642         /* insert SQN.hi between ESP trailer and ICV */
643         if (sa->sqh_len != 0) {
644                 psqh = (uint32_t *)(icv->va - sa->sqh_len);
645                 psqh[0] = sqn_hi32(sqc);
646         }
647
648         /*
649          * fill IV and AAD fields, if any (aad fields are placed after icv),
650          * right now we support only one AEAD algorithm: AES-GCM .
651          */
652         if (algo_type == ALGO_TYPE_AES_GCM) {
653                 aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
654                 aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
655         }
656 }
657
658 /*
659  * setup/update packets and crypto ops for ESP outbound tunnel case.
660  */
661 static uint16_t
662 outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
663         struct rte_crypto_op *cop[], uint16_t num)
664 {
665         int32_t rc;
666         uint32_t i, k, n;
667         uint64_t sqn;
668         rte_be64_t sqc;
669         struct rte_ipsec_sa *sa;
670         union sym_op_data icv;
671         uint64_t iv[IPSEC_MAX_IV_QWORD];
672         struct rte_mbuf *dr[num];
673
674         sa = ss->sa;
675
676         n = num;
677         sqn = esn_outb_update_sqn(sa, &n);
678         if (n != num)
679                 rte_errno = EOVERFLOW;
680
681         k = 0;
682         for (i = 0; i != n; i++) {
683
684                 sqc = rte_cpu_to_be_64(sqn + i);
685                 gen_iv(iv, sqc);
686
687                 /* try to update the packet itself */
688                 rc = esp_outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv);
689
690                 /* success, setup crypto op */
691                 if (rc >= 0) {
692                         mb[k] = mb[i];
693                         outb_pkt_xprepare(sa, sqc, &icv);
694                         esp_outb_cop_prepare(cop[k], sa, iv, &icv, 0, rc);
695                         k++;
696                 /* failure, put packet into the death-row */
697                 } else {
698                         dr[i - k] = mb[i];
699                         rte_errno = -rc;
700                 }
701         }
702
703         /* update cops */
704         lksd_none_cop_prepare(ss, mb, cop, k);
705
706          /* copy not prepared mbufs beyond good ones */
707         if (k != n && k != 0)
708                 mbuf_bulk_copy(mb + k, dr, n - k);
709
710         return k;
711 }
712
713 /*
714  * setup/update packet data and metadata for ESP outbound transport case.
715  */
716 static inline int32_t
717 esp_outb_trs_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
718         const uint64_t ivp[IPSEC_MAX_IV_QWORD], struct rte_mbuf *mb,
719         uint32_t l2len, uint32_t l3len, union sym_op_data *icv)
720 {
721         uint8_t np;
722         uint32_t clen, hlen, pdlen, pdofs, plen, tlen, uhlen;
723         struct rte_mbuf *ml;
724         struct esp_hdr *esph;
725         struct esp_tail *espt;
726         char *ph, *pt;
727         uint64_t *iv;
728
729         uhlen = l2len + l3len;
730         plen = mb->pkt_len - uhlen;
731
732         /* calculate extra header space required */
733         hlen = sa->iv_len + sizeof(*esph);
734
735         /* number of bytes to encrypt */
736         clen = plen + sizeof(*espt);
737         clen = RTE_ALIGN_CEIL(clen, sa->pad_align);
738
739         /* pad length + esp tail */
740         pdlen = clen - plen;
741         tlen = pdlen + sa->icv_len;
742
743         /* do append and insert */
744         ml = rte_pktmbuf_lastseg(mb);
745         if (tlen + sa->sqh_len + sa->aad_len > rte_pktmbuf_tailroom(ml))
746                 return -ENOSPC;
747
748         /* prepend space for ESP header */
749         ph = rte_pktmbuf_prepend(mb, hlen);
750         if (ph == NULL)
751                 return -ENOSPC;
752
753         /* append tail */
754         pdofs = ml->data_len;
755         ml->data_len += tlen;
756         mb->pkt_len += tlen;
757         pt = rte_pktmbuf_mtod_offset(ml, typeof(pt), pdofs);
758
759         /* shift L2/L3 headers */
760         insert_esph(ph, ph + hlen, uhlen);
761
762         /* update ip  header fields */
763         np = update_trs_l3hdr(sa, ph + l2len, mb->pkt_len, l2len, l3len,
764                         IPPROTO_ESP);
765
766         /* update spi, seqn and iv */
767         esph = (struct esp_hdr *)(ph + uhlen);
768         iv = (uint64_t *)(esph + 1);
769         copy_iv(iv, ivp, sa->iv_len);
770
771         esph->spi = sa->spi;
772         esph->seq = sqn_low32(sqc);
773
774         /* offset for ICV */
775         pdofs += pdlen + sa->sqh_len;
776
777         /* pad length */
778         pdlen -= sizeof(*espt);
779
780         /* copy padding data */
781         rte_memcpy(pt, esp_pad_bytes, pdlen);
782
783         /* update esp trailer */
784         espt = (struct esp_tail *)(pt + pdlen);
785         espt->pad_len = pdlen;
786         espt->next_proto = np;
787
788         icv->va = rte_pktmbuf_mtod_offset(ml, void *, pdofs);
789         icv->pa = rte_pktmbuf_iova_offset(ml, pdofs);
790
791         return clen;
792 }
793
794 /*
795  * setup/update packets and crypto ops for ESP outbound transport case.
796  */
797 static uint16_t
798 outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
799         struct rte_crypto_op *cop[], uint16_t num)
800 {
801         int32_t rc;
802         uint32_t i, k, n, l2, l3;
803         uint64_t sqn;
804         rte_be64_t sqc;
805         struct rte_ipsec_sa *sa;
806         union sym_op_data icv;
807         uint64_t iv[IPSEC_MAX_IV_QWORD];
808         struct rte_mbuf *dr[num];
809
810         sa = ss->sa;
811
812         n = num;
813         sqn = esn_outb_update_sqn(sa, &n);
814         if (n != num)
815                 rte_errno = EOVERFLOW;
816
817         k = 0;
818         for (i = 0; i != n; i++) {
819
820                 l2 = mb[i]->l2_len;
821                 l3 = mb[i]->l3_len;
822
823                 sqc = rte_cpu_to_be_64(sqn + i);
824                 gen_iv(iv, sqc);
825
826                 /* try to update the packet itself */
827                 rc = esp_outb_trs_pkt_prepare(sa, sqc, iv, mb[i],
828                                 l2, l3, &icv);
829
830                 /* success, setup crypto op */
831                 if (rc >= 0) {
832                         mb[k] = mb[i];
833                         outb_pkt_xprepare(sa, sqc, &icv);
834                         esp_outb_cop_prepare(cop[k], sa, iv, &icv, l2 + l3, rc);
835                         k++;
836                 /* failure, put packet into the death-row */
837                 } else {
838                         dr[i - k] = mb[i];
839                         rte_errno = -rc;
840                 }
841         }
842
843         /* update cops */
844         lksd_none_cop_prepare(ss, mb, cop, k);
845
846         /* copy not prepared mbufs beyond good ones */
847         if (k != n && k != 0)
848                 mbuf_bulk_copy(mb + k, dr, n - k);
849
850         return k;
851 }
852
853 /*
854  * setup crypto op and crypto sym op for ESP inbound tunnel packet.
855  */
856 static inline int32_t
857 esp_inb_tun_cop_prepare(struct rte_crypto_op *cop,
858         const struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
859         const union sym_op_data *icv, uint32_t pofs, uint32_t plen)
860 {
861         struct rte_crypto_sym_op *sop;
862         struct aead_gcm_iv *gcm;
863         struct aesctr_cnt_blk *ctr;
864         uint64_t *ivc, *ivp;
865         uint32_t clen;
866         uint8_t algo_type = sa->algo_type;
867
868         clen = plen - sa->ctp.cipher.length;
869         if ((int32_t)clen < 0 || (clen & (sa->pad_align - 1)) != 0)
870                 return -EINVAL;
871
872         /* fill sym op fields */
873         sop = cop->sym;
874
875         switch (algo_type) {
876         case ALGO_TYPE_AES_GCM:
877                 sop->aead.data.offset = pofs + sa->ctp.cipher.offset;
878                 sop->aead.data.length = clen;
879                 sop->aead.digest.data = icv->va;
880                 sop->aead.digest.phys_addr = icv->pa;
881                 sop->aead.aad.data = icv->va + sa->icv_len;
882                 sop->aead.aad.phys_addr = icv->pa + sa->icv_len;
883
884                 /* fill AAD IV (located inside crypto op) */
885                 gcm = rte_crypto_op_ctod_offset(cop, struct aead_gcm_iv *,
886                         sa->iv_ofs);
887                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
888                         pofs + sizeof(struct esp_hdr));
889                 aead_gcm_iv_fill(gcm, ivp[0], sa->salt);
890                 break;
891         case ALGO_TYPE_AES_CBC:
892         case ALGO_TYPE_3DES_CBC:
893                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
894                 sop->cipher.data.length = clen;
895                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
896                 sop->auth.data.length = plen - sa->ctp.auth.length;
897                 sop->auth.digest.data = icv->va;
898                 sop->auth.digest.phys_addr = icv->pa;
899
900                 /* copy iv from the input packet to the cop */
901                 ivc = rte_crypto_op_ctod_offset(cop, uint64_t *, sa->iv_ofs);
902                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
903                         pofs + sizeof(struct esp_hdr));
904                 copy_iv(ivc, ivp, sa->iv_len);
905                 break;
906         case ALGO_TYPE_AES_CTR:
907                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
908                 sop->cipher.data.length = clen;
909                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
910                 sop->auth.data.length = plen - sa->ctp.auth.length;
911                 sop->auth.digest.data = icv->va;
912                 sop->auth.digest.phys_addr = icv->pa;
913
914                 /* copy iv from the input packet to the cop */
915                 ctr = rte_crypto_op_ctod_offset(cop, struct aesctr_cnt_blk *,
916                         sa->iv_ofs);
917                 ivp = rte_pktmbuf_mtod_offset(mb, uint64_t *,
918                         pofs + sizeof(struct esp_hdr));
919                 aes_ctr_cnt_blk_fill(ctr, ivp[0], sa->salt);
920                 break;
921         case ALGO_TYPE_NULL:
922                 sop->cipher.data.offset = pofs + sa->ctp.cipher.offset;
923                 sop->cipher.data.length = clen;
924                 sop->auth.data.offset = pofs + sa->ctp.auth.offset;
925                 sop->auth.data.length = plen - sa->ctp.auth.length;
926                 sop->auth.digest.data = icv->va;
927                 sop->auth.digest.phys_addr = icv->pa;
928                 break;
929
930         default:
931                 return -EINVAL;
932         }
933
934         return 0;
935 }
936
937 /*
938  * for pure cryptodev (lookaside none) depending on SA settings,
939  * we might have to write some extra data to the packet.
940  */
941 static inline void
942 inb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
943         const union sym_op_data *icv)
944 {
945         struct aead_gcm_aad *aad;
946
947         /* insert SQN.hi between ESP trailer and ICV */
948         if (sa->sqh_len != 0)
949                 insert_sqh(sqn_hi32(sqc), icv->va, sa->icv_len);
950
951         /*
952          * fill AAD fields, if any (aad fields are placed after icv),
953          * right now we support only one AEAD algorithm: AES-GCM.
954          */
955         if (sa->aad_len != 0) {
956                 aad = (struct aead_gcm_aad *)(icv->va + sa->icv_len);
957                 aead_gcm_aad_fill(aad, sa->spi, sqc, IS_ESN(sa));
958         }
959 }
960
961 /*
962  * setup/update packet data and metadata for ESP inbound tunnel case.
963  */
964 static inline int32_t
965 esp_inb_tun_pkt_prepare(const struct rte_ipsec_sa *sa,
966         const struct replay_sqn *rsn, struct rte_mbuf *mb,
967         uint32_t hlen, union sym_op_data *icv)
968 {
969         int32_t rc;
970         uint64_t sqn;
971         uint32_t icv_ofs, plen;
972         struct rte_mbuf *ml;
973         struct esp_hdr *esph;
974
975         esph = rte_pktmbuf_mtod_offset(mb, struct esp_hdr *, hlen);
976
977         /*
978          * retrieve and reconstruct SQN, then check it, then
979          * convert it back into network byte order.
980          */
981         sqn = rte_be_to_cpu_32(esph->seq);
982         if (IS_ESN(sa))
983                 sqn = reconstruct_esn(rsn->sqn, sqn, sa->replay.win_sz);
984
985         rc = esn_inb_check_sqn(rsn, sa, sqn);
986         if (rc != 0)
987                 return rc;
988
989         sqn = rte_cpu_to_be_64(sqn);
990
991         /* start packet manipulation */
992         plen = mb->pkt_len;
993         plen = plen - hlen;
994
995         ml = rte_pktmbuf_lastseg(mb);
996         icv_ofs = ml->data_len - sa->icv_len + sa->sqh_len;
997
998         /* we have to allocate space for AAD somewhere,
999          * right now - just use free trailing space at the last segment.
1000          * Would probably be more convenient to reserve space for AAD
1001          * inside rte_crypto_op itself
1002          * (again for IV space is already reserved inside cop).
1003          */
1004         if (sa->aad_len + sa->sqh_len > rte_pktmbuf_tailroom(ml))
1005                 return -ENOSPC;
1006
1007         icv->va = rte_pktmbuf_mtod_offset(ml, void *, icv_ofs);
1008         icv->pa = rte_pktmbuf_iova_offset(ml, icv_ofs);
1009
1010         inb_pkt_xprepare(sa, sqn, icv);
1011         return plen;
1012 }
1013
1014 /*
1015  * setup/update packets and crypto ops for ESP inbound case.
1016  */
1017 static uint16_t
1018 inb_pkt_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1019         struct rte_crypto_op *cop[], uint16_t num)
1020 {
1021         int32_t rc;
1022         uint32_t i, k, hl;
1023         struct rte_ipsec_sa *sa;
1024         struct replay_sqn *rsn;
1025         union sym_op_data icv;
1026         struct rte_mbuf *dr[num];
1027
1028         sa = ss->sa;
1029         rsn = rsn_acquire(sa);
1030
1031         k = 0;
1032         for (i = 0; i != num; i++) {
1033
1034                 hl = mb[i]->l2_len + mb[i]->l3_len;
1035                 rc = esp_inb_tun_pkt_prepare(sa, rsn, mb[i], hl, &icv);
1036                 if (rc >= 0)
1037                         rc = esp_inb_tun_cop_prepare(cop[k], sa, mb[i], &icv,
1038                                 hl, rc);
1039
1040                 if (rc == 0)
1041                         mb[k++] = mb[i];
1042                 else {
1043                         dr[i - k] = mb[i];
1044                         rte_errno = -rc;
1045                 }
1046         }
1047
1048         rsn_release(sa, rsn);
1049
1050         /* update cops */
1051         lksd_none_cop_prepare(ss, mb, cop, k);
1052
1053         /* copy not prepared mbufs beyond good ones */
1054         if (k != num && k != 0)
1055                 mbuf_bulk_copy(mb + k, dr, num - k);
1056
1057         return k;
1058 }
1059
1060 /*
1061  *  setup crypto ops for LOOKASIDE_PROTO type of devices.
1062  */
1063 static inline void
1064 lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
1065         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
1066 {
1067         uint32_t i;
1068         struct rte_crypto_sym_op *sop;
1069
1070         for (i = 0; i != num; i++) {
1071                 sop = cop[i]->sym;
1072                 cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
1073                 cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
1074                 cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
1075                 sop->m_src = mb[i];
1076                 __rte_security_attach_session(sop, ss->security.ses);
1077         }
1078 }
1079
1080 /*
1081  *  setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
1082  *  Note that for LOOKASIDE_PROTO all packet modifications will be
1083  *  performed by PMD/HW.
1084  *  SW has only to prepare crypto op.
1085  */
1086 static uint16_t
1087 lksd_proto_prepare(const struct rte_ipsec_session *ss,
1088         struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
1089 {
1090         lksd_proto_cop_prepare(ss, mb, cop, num);
1091         return num;
1092 }
1093
1094 /*
1095  * process ESP inbound tunnel packet.
1096  */
1097 static inline int
1098 esp_inb_tun_single_pkt_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
1099         uint32_t *sqn)
1100 {
1101         uint32_t hlen, icv_len, tlen;
1102         struct esp_hdr *esph;
1103         struct esp_tail *espt;
1104         struct rte_mbuf *ml;
1105         char *pd;
1106
1107         if (mb->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
1108                 return -EBADMSG;
1109
1110         icv_len = sa->icv_len;
1111
1112         ml = rte_pktmbuf_lastseg(mb);
1113         espt = rte_pktmbuf_mtod_offset(ml, struct esp_tail *,
1114                 ml->data_len - icv_len - sizeof(*espt));
1115
1116         /*
1117          * check padding and next proto.
1118          * return an error if something is wrong.
1119          */
1120         pd = (char *)espt - espt->pad_len;
1121         if (espt->next_proto != sa->proto ||
1122                         memcmp(pd, esp_pad_bytes, espt->pad_len))
1123                 return -EINVAL;
1124
1125         /* cut of ICV, ESP tail and padding bytes */
1126         tlen = icv_len + sizeof(*espt) + espt->pad_len;
1127         ml->data_len -= tlen;
1128         mb->pkt_len -= tlen;
1129
1130         /* cut of L2/L3 headers, ESP header and IV */
1131         hlen = mb->l2_len + mb->l3_len;
1132         esph = rte_pktmbuf_mtod_offset(mb, struct esp_hdr *, hlen);
1133         rte_pktmbuf_adj(mb, hlen + sa->ctp.cipher.offset);
1134
1135         /* retrieve SQN for later check */
1136         *sqn = rte_be_to_cpu_32(esph->seq);
1137
1138         /* reset mbuf metatdata: L2/L3 len, packet type */
1139         mb->packet_type = RTE_PTYPE_UNKNOWN;
1140         mb->tx_offload = (mb->tx_offload & sa->tx_offload.msk) |
1141                 sa->tx_offload.val;
1142
1143         /* clear the PKT_RX_SEC_OFFLOAD flag if set */
1144         mb->ol_flags &= ~(mb->ol_flags & PKT_RX_SEC_OFFLOAD);
1145         return 0;
1146 }
1147
1148 /*
1149  * process ESP inbound transport packet.
1150  */
1151 static inline int
1152 esp_inb_trs_single_pkt_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb,
1153         uint32_t *sqn)
1154 {
1155         uint32_t hlen, icv_len, l2len, l3len, tlen;
1156         struct esp_hdr *esph;
1157         struct esp_tail *espt;
1158         struct rte_mbuf *ml;
1159         char *np, *op, *pd;
1160
1161         if (mb->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
1162                 return -EBADMSG;
1163
1164         icv_len = sa->icv_len;
1165
1166         ml = rte_pktmbuf_lastseg(mb);
1167         espt = rte_pktmbuf_mtod_offset(ml, struct esp_tail *,
1168                 ml->data_len - icv_len - sizeof(*espt));
1169
1170         /* check padding, return an error if something is wrong. */
1171         pd = (char *)espt - espt->pad_len;
1172         if (memcmp(pd, esp_pad_bytes, espt->pad_len))
1173                 return -EINVAL;
1174
1175         /* cut of ICV, ESP tail and padding bytes */
1176         tlen = icv_len + sizeof(*espt) + espt->pad_len;
1177         ml->data_len -= tlen;
1178         mb->pkt_len -= tlen;
1179
1180         /* retrieve SQN for later check */
1181         l2len = mb->l2_len;
1182         l3len = mb->l3_len;
1183         hlen = l2len + l3len;
1184         op = rte_pktmbuf_mtod(mb, char *);
1185         esph = (struct esp_hdr *)(op + hlen);
1186         *sqn = rte_be_to_cpu_32(esph->seq);
1187
1188         /* cut off ESP header and IV, update L3 header */
1189         np = rte_pktmbuf_adj(mb, sa->ctp.cipher.offset);
1190         remove_esph(np, op, hlen);
1191         update_trs_l3hdr(sa, np + l2len, mb->pkt_len, l2len, l3len,
1192                         espt->next_proto);
1193
1194         /* reset mbuf packet type */
1195         mb->packet_type &= (RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK);
1196
1197         /* clear the PKT_RX_SEC_OFFLOAD flag if set */
1198         mb->ol_flags &= ~(mb->ol_flags & PKT_RX_SEC_OFFLOAD);
1199         return 0;
1200 }
1201
1202 /*
1203  * for group of ESP inbound packets perform SQN check and update.
1204  */
1205 static inline uint16_t
1206 esp_inb_rsn_update(struct rte_ipsec_sa *sa, const uint32_t sqn[],
1207         struct rte_mbuf *mb[], struct rte_mbuf *dr[], uint16_t num)
1208 {
1209         uint32_t i, k;
1210         struct replay_sqn *rsn;
1211
1212         rsn = rsn_update_start(sa);
1213
1214         k = 0;
1215         for (i = 0; i != num; i++) {
1216                 if (esn_inb_update_sqn(rsn, sa, sqn[i]) == 0)
1217                         mb[k++] = mb[i];
1218                 else
1219                         dr[i - k] = mb[i];
1220         }
1221
1222         rsn_update_finish(sa, rsn);
1223         return k;
1224 }
1225
1226 /*
1227  * process group of ESP inbound tunnel packets.
1228  */
1229 static uint16_t
1230 inb_tun_pkt_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1231         uint16_t num)
1232 {
1233         uint32_t i, k;
1234         struct rte_ipsec_sa *sa;
1235         uint32_t sqn[num];
1236         struct rte_mbuf *dr[num];
1237
1238         sa = ss->sa;
1239
1240         /* process packets, extract seq numbers */
1241
1242         k = 0;
1243         for (i = 0; i != num; i++) {
1244                 /* good packet */
1245                 if (esp_inb_tun_single_pkt_process(sa, mb[i], sqn + k) == 0)
1246                         mb[k++] = mb[i];
1247                 /* bad packet, will drop from furhter processing */
1248                 else
1249                         dr[i - k] = mb[i];
1250         }
1251
1252         /* update seq # and replay winow */
1253         k = esp_inb_rsn_update(sa, sqn, mb, dr + i - k, k);
1254
1255         /* handle unprocessed mbufs */
1256         if (k != num) {
1257                 rte_errno = EBADMSG;
1258                 if (k != 0)
1259                         mbuf_bulk_copy(mb + k, dr, num - k);
1260         }
1261
1262         return k;
1263 }
1264
1265 /*
1266  * process group of ESP inbound transport packets.
1267  */
1268 static uint16_t
1269 inb_trs_pkt_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1270         uint16_t num)
1271 {
1272         uint32_t i, k;
1273         uint32_t sqn[num];
1274         struct rte_ipsec_sa *sa;
1275         struct rte_mbuf *dr[num];
1276
1277         sa = ss->sa;
1278
1279         /* process packets, extract seq numbers */
1280
1281         k = 0;
1282         for (i = 0; i != num; i++) {
1283                 /* good packet */
1284                 if (esp_inb_trs_single_pkt_process(sa, mb[i], sqn + k) == 0)
1285                         mb[k++] = mb[i];
1286                 /* bad packet, will drop from furhter processing */
1287                 else
1288                         dr[i - k] = mb[i];
1289         }
1290
1291         /* update seq # and replay winow */
1292         k = esp_inb_rsn_update(sa, sqn, mb, dr + i - k, k);
1293
1294         /* handle unprocessed mbufs */
1295         if (k != num) {
1296                 rte_errno = EBADMSG;
1297                 if (k != 0)
1298                         mbuf_bulk_copy(mb + k, dr, num - k);
1299         }
1300
1301         return k;
1302 }
1303
1304 /*
1305  * process outbound packets for SA with ESN support,
1306  * for algorithms that require SQN.hibits to be implictly included
1307  * into digest computation.
1308  * In that case we have to move ICV bytes back to their proper place.
1309  */
1310 static uint16_t
1311 outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1312         uint16_t num)
1313 {
1314         uint32_t i, k, icv_len, *icv;
1315         struct rte_mbuf *ml;
1316         struct rte_ipsec_sa *sa;
1317         struct rte_mbuf *dr[num];
1318
1319         sa = ss->sa;
1320
1321         k = 0;
1322         icv_len = sa->icv_len;
1323
1324         for (i = 0; i != num; i++) {
1325                 if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0) {
1326                         ml = rte_pktmbuf_lastseg(mb[i]);
1327                         icv = rte_pktmbuf_mtod_offset(ml, void *,
1328                                 ml->data_len - icv_len);
1329                         remove_sqh(icv, icv_len);
1330                         mb[k++] = mb[i];
1331                 } else
1332                         dr[i - k] = mb[i];
1333         }
1334
1335         /* handle unprocessed mbufs */
1336         if (k != num) {
1337                 rte_errno = EBADMSG;
1338                 if (k != 0)
1339                         mbuf_bulk_copy(mb + k, dr, num - k);
1340         }
1341
1342         return k;
1343 }
1344
1345 /*
1346  * simplest pkt process routine:
1347  * all actual processing is already done by HW/PMD,
1348  * just check mbuf ol_flags.
1349  * used for:
1350  * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
1351  * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
1352  * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
1353  */
1354 static uint16_t
1355 pkt_flag_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
1356         uint16_t num)
1357 {
1358         uint32_t i, k;
1359         struct rte_mbuf *dr[num];
1360
1361         RTE_SET_USED(ss);
1362
1363         k = 0;
1364         for (i = 0; i != num; i++) {
1365                 if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0)
1366                         mb[k++] = mb[i];
1367                 else
1368                         dr[i - k] = mb[i];
1369         }
1370
1371         /* handle unprocessed mbufs */
1372         if (k != num) {
1373                 rte_errno = EBADMSG;
1374                 if (k != 0)
1375                         mbuf_bulk_copy(mb + k, dr, num - k);
1376         }
1377
1378         return k;
1379 }
1380
1381 /*
1382  * prepare packets for inline ipsec processing:
1383  * set ol_flags and attach metadata.
1384  */
1385 static inline void
1386 inline_outb_mbuf_prepare(const struct rte_ipsec_session *ss,
1387         struct rte_mbuf *mb[], uint16_t num)
1388 {
1389         uint32_t i, ol_flags;
1390
1391         ol_flags = ss->security.ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA;
1392         for (i = 0; i != num; i++) {
1393
1394                 mb[i]->ol_flags |= PKT_TX_SEC_OFFLOAD;
1395                 if (ol_flags != 0)
1396                         rte_security_set_pkt_metadata(ss->security.ctx,
1397                                 ss->security.ses, mb[i], NULL);
1398         }
1399 }
1400
1401 /*
1402  * process group of ESP outbound tunnel packets destined for
1403  * INLINE_CRYPTO type of device.
1404  */
1405 static uint16_t
1406 inline_outb_tun_pkt_process(const struct rte_ipsec_session *ss,
1407         struct rte_mbuf *mb[], uint16_t num)
1408 {
1409         int32_t rc;
1410         uint32_t i, k, n;
1411         uint64_t sqn;
1412         rte_be64_t sqc;
1413         struct rte_ipsec_sa *sa;
1414         union sym_op_data icv;
1415         uint64_t iv[IPSEC_MAX_IV_QWORD];
1416         struct rte_mbuf *dr[num];
1417
1418         sa = ss->sa;
1419
1420         n = num;
1421         sqn = esn_outb_update_sqn(sa, &n);
1422         if (n != num)
1423                 rte_errno = EOVERFLOW;
1424
1425         k = 0;
1426         for (i = 0; i != n; i++) {
1427
1428                 sqc = rte_cpu_to_be_64(sqn + i);
1429                 gen_iv(iv, sqc);
1430
1431                 /* try to update the packet itself */
1432                 rc = esp_outb_tun_pkt_prepare(sa, sqc, iv, mb[i], &icv);
1433
1434                 /* success, update mbuf fields */
1435                 if (rc >= 0)
1436                         mb[k++] = mb[i];
1437                 /* failure, put packet into the death-row */
1438                 else {
1439                         dr[i - k] = mb[i];
1440                         rte_errno = -rc;
1441                 }
1442         }
1443
1444         inline_outb_mbuf_prepare(ss, mb, k);
1445
1446         /* copy not processed mbufs beyond good ones */
1447         if (k != n && k != 0)
1448                 mbuf_bulk_copy(mb + k, dr, n - k);
1449
1450         return k;
1451 }
1452
1453 /*
1454  * process group of ESP outbound transport packets destined for
1455  * INLINE_CRYPTO type of device.
1456  */
1457 static uint16_t
1458 inline_outb_trs_pkt_process(const struct rte_ipsec_session *ss,
1459         struct rte_mbuf *mb[], uint16_t num)
1460 {
1461         int32_t rc;
1462         uint32_t i, k, n, l2, l3;
1463         uint64_t sqn;
1464         rte_be64_t sqc;
1465         struct rte_ipsec_sa *sa;
1466         union sym_op_data icv;
1467         uint64_t iv[IPSEC_MAX_IV_QWORD];
1468         struct rte_mbuf *dr[num];
1469
1470         sa = ss->sa;
1471
1472         n = num;
1473         sqn = esn_outb_update_sqn(sa, &n);
1474         if (n != num)
1475                 rte_errno = EOVERFLOW;
1476
1477         k = 0;
1478         for (i = 0; i != n; i++) {
1479
1480                 l2 = mb[i]->l2_len;
1481                 l3 = mb[i]->l3_len;
1482
1483                 sqc = rte_cpu_to_be_64(sqn + i);
1484                 gen_iv(iv, sqc);
1485
1486                 /* try to update the packet itself */
1487                 rc = esp_outb_trs_pkt_prepare(sa, sqc, iv, mb[i],
1488                                 l2, l3, &icv);
1489
1490                 /* success, update mbuf fields */
1491                 if (rc >= 0)
1492                         mb[k++] = mb[i];
1493                 /* failure, put packet into the death-row */
1494                 else {
1495                         dr[i - k] = mb[i];
1496                         rte_errno = -rc;
1497                 }
1498         }
1499
1500         inline_outb_mbuf_prepare(ss, mb, k);
1501
1502         /* copy not processed mbufs beyond good ones */
1503         if (k != n && k != 0)
1504                 mbuf_bulk_copy(mb + k, dr, n - k);
1505
1506         return k;
1507 }
1508
1509 /*
1510  * outbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1511  * actual processing is done by HW/PMD, just set flags and metadata.
1512  */
1513 static uint16_t
1514 outb_inline_proto_process(const struct rte_ipsec_session *ss,
1515                 struct rte_mbuf *mb[], uint16_t num)
1516 {
1517         inline_outb_mbuf_prepare(ss, mb, num);
1518         return num;
1519 }
1520
1521 /*
1522  * Select packet processing function for session on LOOKASIDE_NONE
1523  * type of device.
1524  */
1525 static int
1526 lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
1527                 struct rte_ipsec_sa_pkt_func *pf)
1528 {
1529         int32_t rc;
1530
1531         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
1532                         RTE_IPSEC_SATP_MODE_MASK;
1533
1534         rc = 0;
1535         switch (sa->type & msk) {
1536         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
1537         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
1538                 pf->prepare = inb_pkt_prepare;
1539                 pf->process = inb_tun_pkt_process;
1540                 break;
1541         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
1542                 pf->prepare = inb_pkt_prepare;
1543                 pf->process = inb_trs_pkt_process;
1544                 break;
1545         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
1546         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
1547                 pf->prepare = outb_tun_prepare;
1548                 pf->process = (sa->sqh_len != 0) ?
1549                         outb_sqh_process : pkt_flag_process;
1550                 break;
1551         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
1552                 pf->prepare = outb_trs_prepare;
1553                 pf->process = (sa->sqh_len != 0) ?
1554                         outb_sqh_process : pkt_flag_process;
1555                 break;
1556         default:
1557                 rc = -ENOTSUP;
1558         }
1559
1560         return rc;
1561 }
1562
1563 /*
1564  * Select packet processing function for session on INLINE_CRYPTO
1565  * type of device.
1566  */
1567 static int
1568 inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
1569                 struct rte_ipsec_sa_pkt_func *pf)
1570 {
1571         int32_t rc;
1572
1573         static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
1574                         RTE_IPSEC_SATP_MODE_MASK;
1575
1576         rc = 0;
1577         switch (sa->type & msk) {
1578         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
1579         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
1580                 pf->process = inb_tun_pkt_process;
1581                 break;
1582         case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
1583                 pf->process = inb_trs_pkt_process;
1584                 break;
1585         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
1586         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
1587                 pf->process = inline_outb_tun_pkt_process;
1588                 break;
1589         case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
1590                 pf->process = inline_outb_trs_pkt_process;
1591                 break;
1592         default:
1593                 rc = -ENOTSUP;
1594         }
1595
1596         return rc;
1597 }
1598
1599 /*
1600  * Select packet processing function for given session based on SA parameters
1601  * and type of associated with the session device.
1602  */
1603 int
1604 ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
1605         const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
1606 {
1607         int32_t rc;
1608
1609         rc = 0;
1610         pf[0] = (struct rte_ipsec_sa_pkt_func) { 0 };
1611
1612         switch (ss->type) {
1613         case RTE_SECURITY_ACTION_TYPE_NONE:
1614                 rc = lksd_none_pkt_func_select(sa, pf);
1615                 break;
1616         case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
1617                 rc = inline_crypto_pkt_func_select(sa, pf);
1618                 break;
1619         case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1620                 if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
1621                                 RTE_IPSEC_SATP_DIR_IB)
1622                         pf->process = pkt_flag_process;
1623                 else
1624                         pf->process = outb_inline_proto_process;
1625                 break;
1626         case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
1627                 pf->prepare = lksd_proto_prepare;
1628                 pf->process = pkt_flag_process;
1629                 break;
1630         default:
1631                 rc = -ENOTSUP;
1632         }
1633
1634         return rc;
1635 }