xref: /dpdk/lib/ipsec/sa.c (revision e5fb1a9698e7111473ca0980fdf6c0edb7acdf91)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2020 Intel Corporation
3  */
4 
5 #include <rte_ipsec.h>
6 #include <rte_esp.h>
7 #include <rte_ip.h>
8 #include <rte_errno.h>
9 #include <rte_cryptodev.h>
10 
11 #include "sa.h"
12 #include "ipsec_sqn.h"
13 #include "crypto.h"
14 #include "iph.h"
15 #include "misc.h"
16 #include "pad.h"
17 
18 #define MBUF_MAX_L2_LEN		RTE_LEN2MASK(RTE_MBUF_L2_LEN_BITS, uint64_t)
19 #define MBUF_MAX_L3_LEN		RTE_LEN2MASK(RTE_MBUF_L3_LEN_BITS, uint64_t)
20 
21 /* some helper structures */
22 struct crypto_xform {
23 	struct rte_crypto_auth_xform *auth;
24 	struct rte_crypto_cipher_xform *cipher;
25 	struct rte_crypto_aead_xform *aead;
26 };
27 
28 /*
29  * helper routine, fills internal crypto_xform structure.
30  */
31 static int
32 fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
33 	const struct rte_ipsec_sa_prm *prm)
34 {
35 	struct rte_crypto_sym_xform *xf, *xfn;
36 
37 	memset(xform, 0, sizeof(*xform));
38 
39 	xf = prm->crypto_xform;
40 	if (xf == NULL)
41 		return -EINVAL;
42 
43 	xfn = xf->next;
44 
45 	/* for AEAD just one xform required */
46 	if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
47 		if (xfn != NULL)
48 			return -EINVAL;
49 		xform->aead = &xf->aead;
50 	/*
51 	 * CIPHER+AUTH xforms are expected in strict order,
52 	 * depending on SA direction:
53 	 * inbound: AUTH+CIPHER
54 	 * outbound: CIPHER+AUTH
55 	 */
56 	} else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
57 
58 		/* wrong order or no cipher */
59 		if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
60 				xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
61 			return -EINVAL;
62 
63 		xform->auth = &xf->auth;
64 		xform->cipher = &xfn->cipher;
65 
66 	} else {
67 
68 		/* wrong order or no auth */
69 		if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
70 				xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
71 			return -EINVAL;
72 
73 		xform->cipher = &xf->cipher;
74 		xform->auth = &xfn->auth;
75 	}
76 
77 	return 0;
78 }
79 
80 uint64_t
81 rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
82 {
83 	return sa->type;
84 }
85 
86 /**
87  * Based on number of buckets calculated required size for the
88  * structure that holds replay window and sequence number (RSN) information.
89  */
90 static size_t
91 rsn_size(uint32_t nb_bucket)
92 {
93 	size_t sz;
94 	struct replay_sqn *rsn;
95 
96 	sz = sizeof(*rsn) + nb_bucket * sizeof(rsn->window[0]);
97 	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
98 	return sz;
99 }
100 
101 /*
102  * for given size, calculate required number of buckets.
103  */
104 static uint32_t
105 replay_num_bucket(uint32_t wsz)
106 {
107 	uint32_t nb;
108 
109 	nb = rte_align32pow2(RTE_ALIGN_MUL_CEIL(wsz, WINDOW_BUCKET_SIZE) /
110 		WINDOW_BUCKET_SIZE);
111 	nb = RTE_MAX(nb, (uint32_t)WINDOW_BUCKET_MIN);
112 
113 	return nb;
114 }
115 
116 static int32_t
117 ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
118 {
119 	uint32_t n, sz, wsz;
120 
121 	wsz = *wnd_sz;
122 	n = 0;
123 
124 	if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
125 
126 		/*
127 		 * RFC 4303 recommends 64 as minimum window size.
128 		 * there is no point to use ESN mode without SQN window,
129 		 * so make sure we have at least 64 window when ESN is enalbed.
130 		 */
131 		wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
132 			RTE_IPSEC_SATP_ESN_DISABLE) ?
133 			wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
134 		if (wsz != 0)
135 			n = replay_num_bucket(wsz);
136 	}
137 
138 	if (n > WINDOW_BUCKET_MAX)
139 		return -EINVAL;
140 
141 	*wnd_sz = wsz;
142 	*nb_bucket = n;
143 
144 	sz = rsn_size(n);
145 	if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
146 		sz *= REPLAY_SQN_NUM;
147 
148 	sz += sizeof(struct rte_ipsec_sa);
149 	return sz;
150 }
151 
152 void
153 rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
154 {
155 	memset(sa, 0, sa->size);
156 }
157 
158 /*
159  * Determine expected SA type based on input parameters.
160  */
161 static int
162 fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
163 {
164 	uint64_t tp;
165 
166 	tp = 0;
167 
168 	if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
169 		tp |= RTE_IPSEC_SATP_PROTO_AH;
170 	else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
171 		tp |= RTE_IPSEC_SATP_PROTO_ESP;
172 	else
173 		return -EINVAL;
174 
175 	if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
176 		tp |= RTE_IPSEC_SATP_DIR_OB;
177 	else if (prm->ipsec_xform.direction ==
178 			RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
179 		tp |= RTE_IPSEC_SATP_DIR_IB;
180 	else
181 		return -EINVAL;
182 
183 	if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
184 		if (prm->ipsec_xform.tunnel.type ==
185 				RTE_SECURITY_IPSEC_TUNNEL_IPV4)
186 			tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
187 		else if (prm->ipsec_xform.tunnel.type ==
188 				RTE_SECURITY_IPSEC_TUNNEL_IPV6)
189 			tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
190 		else
191 			return -EINVAL;
192 
193 		if (prm->tun.next_proto == IPPROTO_IPIP)
194 			tp |= RTE_IPSEC_SATP_IPV4;
195 		else if (prm->tun.next_proto == IPPROTO_IPV6)
196 			tp |= RTE_IPSEC_SATP_IPV6;
197 		else
198 			return -EINVAL;
199 	} else if (prm->ipsec_xform.mode ==
200 			RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
201 		tp |= RTE_IPSEC_SATP_MODE_TRANS;
202 		if (prm->trs.proto == IPPROTO_IPIP)
203 			tp |= RTE_IPSEC_SATP_IPV4;
204 		else if (prm->trs.proto == IPPROTO_IPV6)
205 			tp |= RTE_IPSEC_SATP_IPV6;
206 		else
207 			return -EINVAL;
208 	} else
209 		return -EINVAL;
210 
211 	/* check for ESN flag */
212 	if (prm->ipsec_xform.options.esn == 0)
213 		tp |= RTE_IPSEC_SATP_ESN_DISABLE;
214 	else
215 		tp |= RTE_IPSEC_SATP_ESN_ENABLE;
216 
217 	/* check for ECN flag */
218 	if (prm->ipsec_xform.options.ecn == 0)
219 		tp |= RTE_IPSEC_SATP_ECN_DISABLE;
220 	else
221 		tp |= RTE_IPSEC_SATP_ECN_ENABLE;
222 
223 	/* check for DSCP flag */
224 	if (prm->ipsec_xform.options.copy_dscp == 0)
225 		tp |= RTE_IPSEC_SATP_DSCP_DISABLE;
226 	else
227 		tp |= RTE_IPSEC_SATP_DSCP_ENABLE;
228 
229 	/* interpret flags */
230 	if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
231 		tp |= RTE_IPSEC_SATP_SQN_ATOM;
232 	else
233 		tp |= RTE_IPSEC_SATP_SQN_RAW;
234 
235 	*type = tp;
236 	return 0;
237 }
238 
239 /*
240  * Init ESP inbound specific things.
241  */
242 static void
243 esp_inb_init(struct rte_ipsec_sa *sa)
244 {
245 	/* these params may differ with new algorithms support */
246 	sa->ctp.cipher.offset = sizeof(struct rte_esp_hdr) + sa->iv_len;
247 	sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
248 
249 	/*
250 	 * for AEAD and NULL algorithms we can assume that
251 	 * auth and cipher offsets would be equal.
252 	 */
253 	switch (sa->algo_type) {
254 	case ALGO_TYPE_AES_GCM:
255 	case ALGO_TYPE_NULL:
256 		sa->ctp.auth.raw = sa->ctp.cipher.raw;
257 		break;
258 	default:
259 		sa->ctp.auth.offset = 0;
260 		sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
261 		sa->cofs.ofs.cipher.tail = sa->sqh_len;
262 		break;
263 	}
264 
265 	sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
266 }
267 
268 /*
269  * Init ESP inbound tunnel specific things.
270  */
271 static void
272 esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
273 {
274 	sa->proto = prm->tun.next_proto;
275 	esp_inb_init(sa);
276 }
277 
278 /*
279  * Init ESP outbound specific things.
280  */
281 static void
282 esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
283 {
284 	uint8_t algo_type;
285 
286 	sa->sqn.outb = 1;
287 
288 	algo_type = sa->algo_type;
289 
290 	/*
291 	 * Setup auth and cipher length and offset.
292 	 * these params may differ with new algorithms support
293 	 */
294 
295 	switch (algo_type) {
296 	case ALGO_TYPE_AES_GCM:
297 	case ALGO_TYPE_AES_CTR:
298 	case ALGO_TYPE_NULL:
299 		sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr) +
300 			sa->iv_len;
301 		sa->ctp.cipher.length = 0;
302 		break;
303 	case ALGO_TYPE_AES_CBC:
304 	case ALGO_TYPE_3DES_CBC:
305 		sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr);
306 		sa->ctp.cipher.length = sa->iv_len;
307 		break;
308 	}
309 
310 	/*
311 	 * for AEAD and NULL algorithms we can assume that
312 	 * auth and cipher offsets would be equal.
313 	 */
314 	switch (algo_type) {
315 	case ALGO_TYPE_AES_GCM:
316 	case ALGO_TYPE_NULL:
317 		sa->ctp.auth.raw = sa->ctp.cipher.raw;
318 		break;
319 	default:
320 		sa->ctp.auth.offset = hlen;
321 		sa->ctp.auth.length = sizeof(struct rte_esp_hdr) +
322 			sa->iv_len + sa->sqh_len;
323 		break;
324 	}
325 
326 	sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
327 	sa->cofs.ofs.cipher.tail = (sa->ctp.auth.offset + sa->ctp.auth.length) -
328 			(sa->ctp.cipher.offset + sa->ctp.cipher.length);
329 }
330 
331 /*
332  * Init ESP outbound tunnel specific things.
333  */
334 static void
335 esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
336 {
337 	sa->proto = prm->tun.next_proto;
338 	sa->hdr_len = prm->tun.hdr_len;
339 	sa->hdr_l3_off = prm->tun.hdr_l3_off;
340 
341 	/* update l2_len and l3_len fields for outbound mbuf */
342 	sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
343 		sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
344 
345 	memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
346 
347 	esp_outb_init(sa, sa->hdr_len);
348 }
349 
350 /*
351  * helper function, init SA structure.
352  */
353 static int
354 esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
355 	const struct crypto_xform *cxf)
356 {
357 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
358 				RTE_IPSEC_SATP_MODE_MASK;
359 
360 	if (prm->ipsec_xform.options.ecn)
361 		sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
362 
363 	if (prm->ipsec_xform.options.copy_dscp)
364 		sa->tos_mask |= RTE_IPV4_HDR_DSCP_MASK;
365 
366 	if (cxf->aead != NULL) {
367 		switch (cxf->aead->algo) {
368 		case RTE_CRYPTO_AEAD_AES_GCM:
369 			/* RFC 4106 */
370 			sa->aad_len = sizeof(struct aead_gcm_aad);
371 			sa->icv_len = cxf->aead->digest_length;
372 			sa->iv_ofs = cxf->aead->iv.offset;
373 			sa->iv_len = sizeof(uint64_t);
374 			sa->pad_align = IPSEC_PAD_AES_GCM;
375 			sa->algo_type = ALGO_TYPE_AES_GCM;
376 			break;
377 		default:
378 			return -EINVAL;
379 		}
380 	} else {
381 		sa->icv_len = cxf->auth->digest_length;
382 		sa->iv_ofs = cxf->cipher->iv.offset;
383 		sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
384 
385 		switch (cxf->cipher->algo) {
386 		case RTE_CRYPTO_CIPHER_NULL:
387 			sa->pad_align = IPSEC_PAD_NULL;
388 			sa->iv_len = 0;
389 			sa->algo_type = ALGO_TYPE_NULL;
390 			break;
391 
392 		case RTE_CRYPTO_CIPHER_AES_CBC:
393 			sa->pad_align = IPSEC_PAD_AES_CBC;
394 			sa->iv_len = IPSEC_MAX_IV_SIZE;
395 			sa->algo_type = ALGO_TYPE_AES_CBC;
396 			break;
397 
398 		case RTE_CRYPTO_CIPHER_AES_CTR:
399 			/* RFC 3686 */
400 			sa->pad_align = IPSEC_PAD_AES_CTR;
401 			sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
402 			sa->algo_type = ALGO_TYPE_AES_CTR;
403 			break;
404 
405 		case RTE_CRYPTO_CIPHER_3DES_CBC:
406 			/* RFC 1851 */
407 			sa->pad_align = IPSEC_PAD_3DES_CBC;
408 			sa->iv_len = IPSEC_3DES_IV_SIZE;
409 			sa->algo_type = ALGO_TYPE_3DES_CBC;
410 			break;
411 
412 		default:
413 			return -EINVAL;
414 		}
415 	}
416 
417 	sa->udata = prm->userdata;
418 	sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
419 	sa->salt = prm->ipsec_xform.salt;
420 
421 	/* preserve all values except l2_len and l3_len */
422 	sa->tx_offload.msk =
423 		~rte_mbuf_tx_offload(MBUF_MAX_L2_LEN, MBUF_MAX_L3_LEN,
424 				0, 0, 0, 0, 0);
425 
426 	switch (sa->type & msk) {
427 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
428 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
429 		esp_inb_tun_init(sa, prm);
430 		break;
431 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
432 		esp_inb_init(sa);
433 		break;
434 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
435 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
436 		esp_outb_tun_init(sa, prm);
437 		break;
438 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
439 		esp_outb_init(sa, 0);
440 		break;
441 	}
442 
443 	return 0;
444 }
445 
446 /*
447  * helper function, init SA replay structure.
448  */
449 static void
450 fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket)
451 {
452 	sa->replay.win_sz = wnd_sz;
453 	sa->replay.nb_bucket = nb_bucket;
454 	sa->replay.bucket_index_mask = nb_bucket - 1;
455 	sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
456 	if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
457 		sa->sqn.inb.rsn[1] = (struct replay_sqn *)
458 			((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
459 }
460 
461 int
462 rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
463 {
464 	uint64_t type;
465 	uint32_t nb, wsz;
466 	int32_t rc;
467 
468 	if (prm == NULL)
469 		return -EINVAL;
470 
471 	/* determine SA type */
472 	rc = fill_sa_type(prm, &type);
473 	if (rc != 0)
474 		return rc;
475 
476 	/* determine required size */
477 	wsz = prm->ipsec_xform.replay_win_sz;
478 	return ipsec_sa_size(type, &wsz, &nb);
479 }
480 
481 int
482 rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
483 	uint32_t size)
484 {
485 	int32_t rc, sz;
486 	uint32_t nb, wsz;
487 	uint64_t type;
488 	struct crypto_xform cxf;
489 
490 	if (sa == NULL || prm == NULL)
491 		return -EINVAL;
492 
493 	/* determine SA type */
494 	rc = fill_sa_type(prm, &type);
495 	if (rc != 0)
496 		return rc;
497 
498 	/* determine required size */
499 	wsz = prm->ipsec_xform.replay_win_sz;
500 	sz = ipsec_sa_size(type, &wsz, &nb);
501 	if (sz < 0)
502 		return sz;
503 	else if (size < (uint32_t)sz)
504 		return -ENOSPC;
505 
506 	/* only esp is supported right now */
507 	if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
508 		return -EINVAL;
509 
510 	if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
511 			prm->tun.hdr_len > sizeof(sa->hdr))
512 		return -EINVAL;
513 
514 	rc = fill_crypto_xform(&cxf, type, prm);
515 	if (rc != 0)
516 		return rc;
517 
518 	/* initialize SA */
519 
520 	memset(sa, 0, sz);
521 	sa->type = type;
522 	sa->size = sz;
523 
524 	/* check for ESN flag */
525 	sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
526 		UINT32_MAX : UINT64_MAX;
527 
528 	rc = esp_sa_init(sa, prm, &cxf);
529 	if (rc != 0)
530 		rte_ipsec_sa_fini(sa);
531 
532 	/* fill replay window related fields */
533 	if (nb != 0)
534 		fill_sa_replay(sa, wsz, nb);
535 
536 	return sz;
537 }
538 
539 /*
540  *  setup crypto ops for LOOKASIDE_PROTO type of devices.
541  */
542 static inline void
543 lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
544 	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
545 {
546 	uint32_t i;
547 	struct rte_crypto_sym_op *sop;
548 
549 	for (i = 0; i != num; i++) {
550 		sop = cop[i]->sym;
551 		cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
552 		cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
553 		cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
554 		sop->m_src = mb[i];
555 		__rte_security_attach_session(sop, ss->security.ses);
556 	}
557 }
558 
559 /*
560  *  setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
561  *  Note that for LOOKASIDE_PROTO all packet modifications will be
562  *  performed by PMD/HW.
563  *  SW has only to prepare crypto op.
564  */
565 static uint16_t
566 lksd_proto_prepare(const struct rte_ipsec_session *ss,
567 	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
568 {
569 	lksd_proto_cop_prepare(ss, mb, cop, num);
570 	return num;
571 }
572 
573 /*
574  * simplest pkt process routine:
575  * all actual processing is already done by HW/PMD,
576  * just check mbuf ol_flags.
577  * used for:
578  * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
579  * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
580  * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
581  */
582 uint16_t
583 pkt_flag_process(const struct rte_ipsec_session *ss,
584 		struct rte_mbuf *mb[], uint16_t num)
585 {
586 	uint32_t i, k;
587 	uint32_t dr[num];
588 
589 	RTE_SET_USED(ss);
590 
591 	k = 0;
592 	for (i = 0; i != num; i++) {
593 		if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0)
594 			k++;
595 		else
596 			dr[i - k] = i;
597 	}
598 
599 	/* handle unprocessed mbufs */
600 	if (k != num) {
601 		rte_errno = EBADMSG;
602 		if (k != 0)
603 			move_bad_mbufs(mb, dr, num, num - k);
604 	}
605 
606 	return k;
607 }
608 
609 /*
610  * Select packet processing function for session on LOOKASIDE_NONE
611  * type of device.
612  */
613 static int
614 lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
615 		struct rte_ipsec_sa_pkt_func *pf)
616 {
617 	int32_t rc;
618 
619 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
620 			RTE_IPSEC_SATP_MODE_MASK;
621 
622 	rc = 0;
623 	switch (sa->type & msk) {
624 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
625 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
626 		pf->prepare.async = esp_inb_pkt_prepare;
627 		pf->process = esp_inb_tun_pkt_process;
628 		break;
629 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
630 		pf->prepare.async = esp_inb_pkt_prepare;
631 		pf->process = esp_inb_trs_pkt_process;
632 		break;
633 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
634 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
635 		pf->prepare.async = esp_outb_tun_prepare;
636 		pf->process = (sa->sqh_len != 0) ?
637 			esp_outb_sqh_process : pkt_flag_process;
638 		break;
639 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
640 		pf->prepare.async = esp_outb_trs_prepare;
641 		pf->process = (sa->sqh_len != 0) ?
642 			esp_outb_sqh_process : pkt_flag_process;
643 		break;
644 	default:
645 		rc = -ENOTSUP;
646 	}
647 
648 	return rc;
649 }
650 
651 static int
652 cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
653 		struct rte_ipsec_sa_pkt_func *pf)
654 {
655 	int32_t rc;
656 
657 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
658 			RTE_IPSEC_SATP_MODE_MASK;
659 
660 	rc = 0;
661 	switch (sa->type & msk) {
662 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
663 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
664 		pf->prepare.sync = cpu_inb_pkt_prepare;
665 		pf->process = esp_inb_tun_pkt_process;
666 		break;
667 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
668 		pf->prepare.sync = cpu_inb_pkt_prepare;
669 		pf->process = esp_inb_trs_pkt_process;
670 		break;
671 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
672 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
673 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
674 		pf->process = (sa->sqh_len != 0) ?
675 			esp_outb_sqh_process : pkt_flag_process;
676 		break;
677 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
678 		pf->prepare.sync = cpu_outb_trs_pkt_prepare;
679 		pf->process = (sa->sqh_len != 0) ?
680 			esp_outb_sqh_process : pkt_flag_process;
681 		break;
682 	default:
683 		rc = -ENOTSUP;
684 	}
685 
686 	return rc;
687 }
688 
689 /*
690  * Select packet processing function for session on INLINE_CRYPTO
691  * type of device.
692  */
693 static int
694 inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
695 		struct rte_ipsec_sa_pkt_func *pf)
696 {
697 	int32_t rc;
698 
699 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
700 			RTE_IPSEC_SATP_MODE_MASK;
701 
702 	rc = 0;
703 	switch (sa->type & msk) {
704 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
705 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
706 		pf->process = inline_inb_tun_pkt_process;
707 		break;
708 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
709 		pf->process = inline_inb_trs_pkt_process;
710 		break;
711 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
712 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
713 		pf->process = inline_outb_tun_pkt_process;
714 		break;
715 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
716 		pf->process = inline_outb_trs_pkt_process;
717 		break;
718 	default:
719 		rc = -ENOTSUP;
720 	}
721 
722 	return rc;
723 }
724 
725 /*
726  * Select packet processing function for given session based on SA parameters
727  * and type of associated with the session device.
728  */
729 int
730 ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
731 	const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
732 {
733 	int32_t rc;
734 
735 	rc = 0;
736 	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
737 
738 	switch (ss->type) {
739 	case RTE_SECURITY_ACTION_TYPE_NONE:
740 		rc = lksd_none_pkt_func_select(sa, pf);
741 		break;
742 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
743 		rc = inline_crypto_pkt_func_select(sa, pf);
744 		break;
745 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
746 		if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
747 				RTE_IPSEC_SATP_DIR_IB)
748 			pf->process = pkt_flag_process;
749 		else
750 			pf->process = inline_proto_outb_pkt_process;
751 		break;
752 	case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
753 		pf->prepare.async = lksd_proto_prepare;
754 		pf->process = pkt_flag_process;
755 		break;
756 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
757 		rc = cpu_crypto_pkt_func_select(sa, pf);
758 		break;
759 	default:
760 		rc = -ENOTSUP;
761 	}
762 
763 	return rc;
764 }
765