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