14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606  * Copyright(c) 2016-2020 Intel Corporation
34418919fSjohnjiang  */
44418919fSjohnjiang #include <sys/types.h>
54418919fSjohnjiang #include <netinet/in.h>
64418919fSjohnjiang #include <netinet/ip.h>
74418919fSjohnjiang 
84418919fSjohnjiang #include <rte_branch_prediction.h>
94418919fSjohnjiang #include <rte_log.h>
104418919fSjohnjiang #include <rte_cryptodev.h>
114418919fSjohnjiang #include <rte_ethdev.h>
124418919fSjohnjiang #include <rte_mbuf.h>
134418919fSjohnjiang 
144418919fSjohnjiang #include "ipsec.h"
15*2d9fd380Sjfb8856606 #include "ipsec-secgw.h"
164418919fSjohnjiang 
174418919fSjohnjiang #define SATP_OUT_IPV4(t)	\
184418919fSjohnjiang 	((((t) & RTE_IPSEC_SATP_MODE_MASK) == RTE_IPSEC_SATP_MODE_TRANS && \
194418919fSjohnjiang 	(((t) & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4)) || \
204418919fSjohnjiang 	((t) & RTE_IPSEC_SATP_MODE_MASK) == RTE_IPSEC_SATP_MODE_TUNLV4)
214418919fSjohnjiang 
224418919fSjohnjiang /* helper routine to free bulk of crypto-ops and related packets */
234418919fSjohnjiang static inline void
free_cops(struct rte_crypto_op * cop[],uint32_t n)244418919fSjohnjiang free_cops(struct rte_crypto_op *cop[], uint32_t n)
254418919fSjohnjiang {
264418919fSjohnjiang 	uint32_t i;
274418919fSjohnjiang 
284418919fSjohnjiang 	for (i = 0; i != n; i++)
294418919fSjohnjiang 		rte_pktmbuf_free(cop[i]->sym->m_src);
304418919fSjohnjiang }
314418919fSjohnjiang 
324418919fSjohnjiang /* helper routine to enqueue bulk of crypto ops */
334418919fSjohnjiang static inline void
enqueue_cop_bulk(struct cdev_qp * cqp,struct rte_crypto_op * cop[],uint32_t num)344418919fSjohnjiang enqueue_cop_bulk(struct cdev_qp *cqp, struct rte_crypto_op *cop[], uint32_t num)
354418919fSjohnjiang {
364418919fSjohnjiang 	uint32_t i, k, len, n;
374418919fSjohnjiang 
384418919fSjohnjiang 	len = cqp->len;
394418919fSjohnjiang 
404418919fSjohnjiang 	/*
414418919fSjohnjiang 	 * if cqp is empty and we have enough ops,
424418919fSjohnjiang 	 * then queue them to the PMD straightway.
434418919fSjohnjiang 	 */
444418919fSjohnjiang 	if (num >= RTE_DIM(cqp->buf) * 3 / 4 && len == 0) {
454418919fSjohnjiang 		n = rte_cryptodev_enqueue_burst(cqp->id, cqp->qp, cop, num);
464418919fSjohnjiang 		cqp->in_flight += n;
474418919fSjohnjiang 		free_cops(cop + n, num - n);
484418919fSjohnjiang 		return;
494418919fSjohnjiang 	}
504418919fSjohnjiang 
514418919fSjohnjiang 	k = 0;
524418919fSjohnjiang 
534418919fSjohnjiang 	do {
544418919fSjohnjiang 		n = RTE_DIM(cqp->buf) - len;
554418919fSjohnjiang 		n = RTE_MIN(num - k, n);
564418919fSjohnjiang 
574418919fSjohnjiang 		/* put packets into cqp */
584418919fSjohnjiang 		for (i = 0; i != n; i++)
594418919fSjohnjiang 			cqp->buf[len + i] = cop[k + i];
604418919fSjohnjiang 
614418919fSjohnjiang 		len += n;
624418919fSjohnjiang 		k += n;
634418919fSjohnjiang 
644418919fSjohnjiang 		/* if cqp is full then, enqueue crypto-ops to PMD */
654418919fSjohnjiang 		if (len == RTE_DIM(cqp->buf)) {
664418919fSjohnjiang 			n = rte_cryptodev_enqueue_burst(cqp->id, cqp->qp,
674418919fSjohnjiang 					cqp->buf, len);
684418919fSjohnjiang 			cqp->in_flight += n;
694418919fSjohnjiang 			free_cops(cqp->buf + n, len - n);
704418919fSjohnjiang 			len = 0;
714418919fSjohnjiang 		}
724418919fSjohnjiang 
734418919fSjohnjiang 
744418919fSjohnjiang 	} while (k != num);
754418919fSjohnjiang 
764418919fSjohnjiang 	cqp->len = len;
774418919fSjohnjiang }
784418919fSjohnjiang 
794418919fSjohnjiang static inline int
fill_ipsec_session(struct rte_ipsec_session * ss,struct ipsec_ctx * ctx,struct ipsec_sa * sa)804418919fSjohnjiang fill_ipsec_session(struct rte_ipsec_session *ss, struct ipsec_ctx *ctx,
814418919fSjohnjiang 	struct ipsec_sa *sa)
824418919fSjohnjiang {
834418919fSjohnjiang 	int32_t rc;
844418919fSjohnjiang 
854418919fSjohnjiang 	/* setup crypto section */
86*2d9fd380Sjfb8856606 	if (ss->type == RTE_SECURITY_ACTION_TYPE_NONE ||
87*2d9fd380Sjfb8856606 			ss->type == RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
884418919fSjohnjiang 		RTE_ASSERT(ss->crypto.ses == NULL);
894418919fSjohnjiang 		rc = create_lookaside_session(ctx, sa, ss);
904418919fSjohnjiang 		if (rc != 0)
914418919fSjohnjiang 			return rc;
924418919fSjohnjiang 	/* setup session action type */
934418919fSjohnjiang 	} else if (ss->type == RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL) {
944418919fSjohnjiang 		RTE_ASSERT(ss->security.ses == NULL);
954418919fSjohnjiang 		rc = create_lookaside_session(ctx, sa, ss);
964418919fSjohnjiang 		if (rc != 0)
974418919fSjohnjiang 			return rc;
984418919fSjohnjiang 	} else
994418919fSjohnjiang 		RTE_ASSERT(0);
1004418919fSjohnjiang 
1014418919fSjohnjiang 	rc = rte_ipsec_session_prepare(ss);
1024418919fSjohnjiang 	if (rc != 0)
1034418919fSjohnjiang 		memset(ss, 0, sizeof(*ss));
1044418919fSjohnjiang 
1054418919fSjohnjiang 	return rc;
1064418919fSjohnjiang }
1074418919fSjohnjiang 
1084418919fSjohnjiang /*
1094418919fSjohnjiang  * group input packets byt the SA they belong to.
1104418919fSjohnjiang  */
1114418919fSjohnjiang static uint32_t
sa_group(void * sa_ptr[],struct rte_mbuf * pkts[],struct rte_ipsec_group grp[],uint32_t num)1124418919fSjohnjiang sa_group(void *sa_ptr[], struct rte_mbuf *pkts[],
1134418919fSjohnjiang 	struct rte_ipsec_group grp[], uint32_t num)
1144418919fSjohnjiang {
1154418919fSjohnjiang 	uint32_t i, n, spi;
1164418919fSjohnjiang 	void *sa;
1174418919fSjohnjiang 	void * const nosa = &spi;
1184418919fSjohnjiang 
1194418919fSjohnjiang 	sa = nosa;
1200c6bd470Sfengbojiang 	grp[0].m = pkts;
1214418919fSjohnjiang 	for (i = 0, n = 0; i != num; i++) {
1224418919fSjohnjiang 
1234418919fSjohnjiang 		if (sa != sa_ptr[i]) {
1244418919fSjohnjiang 			grp[n].cnt = pkts + i - grp[n].m;
1254418919fSjohnjiang 			n += (sa != nosa);
1264418919fSjohnjiang 			grp[n].id.ptr = sa_ptr[i];
1274418919fSjohnjiang 			grp[n].m = pkts + i;
1284418919fSjohnjiang 			sa = sa_ptr[i];
1294418919fSjohnjiang 		}
1304418919fSjohnjiang 	}
1314418919fSjohnjiang 
1324418919fSjohnjiang 	/* terminate last group */
1334418919fSjohnjiang 	if (sa != nosa) {
1344418919fSjohnjiang 		grp[n].cnt = pkts + i - grp[n].m;
1354418919fSjohnjiang 		n++;
1364418919fSjohnjiang 	}
1374418919fSjohnjiang 
1384418919fSjohnjiang 	return n;
1394418919fSjohnjiang }
1404418919fSjohnjiang 
1414418919fSjohnjiang /*
1424418919fSjohnjiang  * helper function, splits processed packets into ipv4/ipv6 traffic.
1434418919fSjohnjiang  */
1444418919fSjohnjiang static inline void
copy_to_trf(struct ipsec_traffic * trf,uint64_t satp,struct rte_mbuf * mb[],uint32_t num)1454418919fSjohnjiang copy_to_trf(struct ipsec_traffic *trf, uint64_t satp, struct rte_mbuf *mb[],
1464418919fSjohnjiang 	uint32_t num)
1474418919fSjohnjiang {
1484418919fSjohnjiang 	uint32_t j, ofs, s;
1494418919fSjohnjiang 	struct traffic_type *out;
1504418919fSjohnjiang 
1514418919fSjohnjiang 	/*
1524418919fSjohnjiang 	 * determine traffic type(ipv4/ipv6) and offset for ACL classify
1534418919fSjohnjiang 	 * based on SA type
1544418919fSjohnjiang 	 */
1554418919fSjohnjiang 	if ((satp & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
1564418919fSjohnjiang 		if ((satp & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) {
1574418919fSjohnjiang 			out = &trf->ip4;
1584418919fSjohnjiang 			ofs = offsetof(struct ip, ip_p);
1594418919fSjohnjiang 		} else {
1604418919fSjohnjiang 			out = &trf->ip6;
1614418919fSjohnjiang 			ofs = offsetof(struct ip6_hdr, ip6_nxt);
1624418919fSjohnjiang 		}
1634418919fSjohnjiang 	} else if (SATP_OUT_IPV4(satp)) {
1644418919fSjohnjiang 		out = &trf->ip4;
1654418919fSjohnjiang 		ofs = offsetof(struct ip, ip_p);
1664418919fSjohnjiang 	} else {
1674418919fSjohnjiang 		out = &trf->ip6;
1684418919fSjohnjiang 		ofs = offsetof(struct ip6_hdr, ip6_nxt);
1694418919fSjohnjiang 	}
1704418919fSjohnjiang 
1714418919fSjohnjiang 	for (j = 0, s = out->num; j != num; j++) {
1724418919fSjohnjiang 		out->data[s + j] = rte_pktmbuf_mtod_offset(mb[j],
1734418919fSjohnjiang 				void *, ofs);
1744418919fSjohnjiang 		out->pkts[s + j] = mb[j];
1754418919fSjohnjiang 	}
1764418919fSjohnjiang 
1774418919fSjohnjiang 	out->num += num;
1784418919fSjohnjiang }
1794418919fSjohnjiang 
1804418919fSjohnjiang static uint32_t
ipsec_prepare_crypto_group(struct ipsec_ctx * ctx,struct ipsec_sa * sa,struct rte_ipsec_session * ips,struct rte_mbuf ** m,unsigned int cnt)1814418919fSjohnjiang ipsec_prepare_crypto_group(struct ipsec_ctx *ctx, struct ipsec_sa *sa,
1824418919fSjohnjiang 		struct rte_ipsec_session *ips, struct rte_mbuf **m,
1834418919fSjohnjiang 		unsigned int cnt)
1844418919fSjohnjiang {
1854418919fSjohnjiang 	struct cdev_qp *cqp;
1864418919fSjohnjiang 	struct rte_crypto_op *cop[cnt];
1874418919fSjohnjiang 	uint32_t j, k;
1884418919fSjohnjiang 	struct ipsec_mbuf_metadata *priv;
1894418919fSjohnjiang 
1904418919fSjohnjiang 	cqp = &ctx->tbl[sa->cdev_id_qp];
1914418919fSjohnjiang 
1924418919fSjohnjiang 	/* for that app each mbuf has it's own crypto op */
1934418919fSjohnjiang 	for (j = 0; j != cnt; j++) {
1944418919fSjohnjiang 		priv = get_priv(m[j]);
1954418919fSjohnjiang 		cop[j] = &priv->cop;
1964418919fSjohnjiang 		/*
1974418919fSjohnjiang 		 * this is just to satisfy inbound_sa_check()
1984418919fSjohnjiang 		 * should be removed in future.
1994418919fSjohnjiang 		 */
2004418919fSjohnjiang 		priv->sa = sa;
2014418919fSjohnjiang 	}
2024418919fSjohnjiang 
2034418919fSjohnjiang 	/* prepare and enqueue crypto ops */
2044418919fSjohnjiang 	k = rte_ipsec_pkt_crypto_prepare(ips, m, cop, cnt);
2054418919fSjohnjiang 	if (k != 0)
2064418919fSjohnjiang 		enqueue_cop_bulk(cqp, cop, k);
2074418919fSjohnjiang 
2084418919fSjohnjiang 	return k;
2094418919fSjohnjiang }
2104418919fSjohnjiang 
2114418919fSjohnjiang /*
212*2d9fd380Sjfb8856606  * helper routine for inline and cpu(synchronous) processing
213*2d9fd380Sjfb8856606  * this is just to satisfy inbound_sa_check() and get_hop_for_offload_pkt().
214*2d9fd380Sjfb8856606  * Should be removed in future.
215*2d9fd380Sjfb8856606  */
216*2d9fd380Sjfb8856606 static inline void
prep_process_group(void * sa,struct rte_mbuf * mb[],uint32_t cnt)217*2d9fd380Sjfb8856606 prep_process_group(void *sa, struct rte_mbuf *mb[], uint32_t cnt)
218*2d9fd380Sjfb8856606 {
219*2d9fd380Sjfb8856606 	uint32_t j;
220*2d9fd380Sjfb8856606 	struct ipsec_mbuf_metadata *priv;
221*2d9fd380Sjfb8856606 
222*2d9fd380Sjfb8856606 	for (j = 0; j != cnt; j++) {
223*2d9fd380Sjfb8856606 		priv = get_priv(mb[j]);
224*2d9fd380Sjfb8856606 		priv->sa = sa;
225*2d9fd380Sjfb8856606 	}
226*2d9fd380Sjfb8856606 }
227*2d9fd380Sjfb8856606 
228*2d9fd380Sjfb8856606 /*
229*2d9fd380Sjfb8856606  * finish processing of packets successfully decrypted by an inline processor
230*2d9fd380Sjfb8856606  */
231*2d9fd380Sjfb8856606 static uint32_t
ipsec_process_inline_group(struct rte_ipsec_session * ips,void * sa,struct ipsec_traffic * trf,struct rte_mbuf * mb[],uint32_t cnt)232*2d9fd380Sjfb8856606 ipsec_process_inline_group(struct rte_ipsec_session *ips, void *sa,
233*2d9fd380Sjfb8856606 	struct ipsec_traffic *trf, struct rte_mbuf *mb[], uint32_t cnt)
234*2d9fd380Sjfb8856606 {
235*2d9fd380Sjfb8856606 	uint64_t satp;
236*2d9fd380Sjfb8856606 	uint32_t k;
237*2d9fd380Sjfb8856606 
238*2d9fd380Sjfb8856606 	/* get SA type */
239*2d9fd380Sjfb8856606 	satp = rte_ipsec_sa_type(ips->sa);
240*2d9fd380Sjfb8856606 	prep_process_group(sa, mb, cnt);
241*2d9fd380Sjfb8856606 
242*2d9fd380Sjfb8856606 	k = rte_ipsec_pkt_process(ips, mb, cnt);
243*2d9fd380Sjfb8856606 	copy_to_trf(trf, satp, mb, k);
244*2d9fd380Sjfb8856606 	return k;
245*2d9fd380Sjfb8856606 }
246*2d9fd380Sjfb8856606 
247*2d9fd380Sjfb8856606 /*
248*2d9fd380Sjfb8856606  * process packets synchronously
249*2d9fd380Sjfb8856606  */
250*2d9fd380Sjfb8856606 static uint32_t
ipsec_process_cpu_group(struct rte_ipsec_session * ips,void * sa,struct ipsec_traffic * trf,struct rte_mbuf * mb[],uint32_t cnt)251*2d9fd380Sjfb8856606 ipsec_process_cpu_group(struct rte_ipsec_session *ips, void *sa,
252*2d9fd380Sjfb8856606 	struct ipsec_traffic *trf, struct rte_mbuf *mb[], uint32_t cnt)
253*2d9fd380Sjfb8856606 {
254*2d9fd380Sjfb8856606 	uint64_t satp;
255*2d9fd380Sjfb8856606 	uint32_t k;
256*2d9fd380Sjfb8856606 
257*2d9fd380Sjfb8856606 	/* get SA type */
258*2d9fd380Sjfb8856606 	satp = rte_ipsec_sa_type(ips->sa);
259*2d9fd380Sjfb8856606 	prep_process_group(sa, mb, cnt);
260*2d9fd380Sjfb8856606 
261*2d9fd380Sjfb8856606 	k = rte_ipsec_pkt_cpu_prepare(ips, mb, cnt);
262*2d9fd380Sjfb8856606 	k = rte_ipsec_pkt_process(ips, mb, k);
263*2d9fd380Sjfb8856606 	copy_to_trf(trf, satp, mb, k);
264*2d9fd380Sjfb8856606 	return k;
265*2d9fd380Sjfb8856606 }
266*2d9fd380Sjfb8856606 
267*2d9fd380Sjfb8856606 /*
2684418919fSjohnjiang  * Process ipsec packets.
2694418919fSjohnjiang  * If packet belong to SA that is subject of inline-crypto,
2704418919fSjohnjiang  * then process it immediately.
2714418919fSjohnjiang  * Otherwise do necessary preparations and queue it to related
2724418919fSjohnjiang  * crypto-dev queue.
2734418919fSjohnjiang  */
2744418919fSjohnjiang void
ipsec_process(struct ipsec_ctx * ctx,struct ipsec_traffic * trf)2754418919fSjohnjiang ipsec_process(struct ipsec_ctx *ctx, struct ipsec_traffic *trf)
2764418919fSjohnjiang {
277*2d9fd380Sjfb8856606 	uint32_t i, k, n;
2784418919fSjohnjiang 	struct ipsec_sa *sa;
2794418919fSjohnjiang 	struct rte_ipsec_group *pg;
2804418919fSjohnjiang 	struct rte_ipsec_session *ips;
2814418919fSjohnjiang 	struct rte_ipsec_group grp[RTE_DIM(trf->ipsec.pkts)];
2824418919fSjohnjiang 
2834418919fSjohnjiang 	n = sa_group(trf->ipsec.saptr, trf->ipsec.pkts, grp, trf->ipsec.num);
2844418919fSjohnjiang 
2854418919fSjohnjiang 	for (i = 0; i != n; i++) {
286*2d9fd380Sjfb8856606 
2874418919fSjohnjiang 		pg = grp + i;
2884418919fSjohnjiang 		sa = ipsec_mask_saptr(pg->id.ptr);
2894418919fSjohnjiang 
290*2d9fd380Sjfb8856606 		/* fallback to cryptodev with RX packets which inline
291*2d9fd380Sjfb8856606 		 * processor was unable to process
292*2d9fd380Sjfb8856606 		 */
293*2d9fd380Sjfb8856606 		if (sa != NULL)
294*2d9fd380Sjfb8856606 			ips = (pg->id.val & IPSEC_SA_OFFLOAD_FALLBACK_FLAG) ?
295*2d9fd380Sjfb8856606 				ipsec_get_fallback_session(sa) :
296*2d9fd380Sjfb8856606 				ipsec_get_primary_session(sa);
2974418919fSjohnjiang 
2984418919fSjohnjiang 		/* no valid HW session for that SA, try to create one */
2994418919fSjohnjiang 		if (sa == NULL || (ips->crypto.ses == NULL &&
3004418919fSjohnjiang 				fill_ipsec_session(ips, ctx, sa) != 0))
3014418919fSjohnjiang 			k = 0;
3024418919fSjohnjiang 
3034418919fSjohnjiang 		/* process packets inline */
304*2d9fd380Sjfb8856606 		else {
305*2d9fd380Sjfb8856606 			switch (ips->type) {
3064418919fSjohnjiang 			/* enqueue packets to crypto dev */
307*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_NONE:
308*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
309*2d9fd380Sjfb8856606 				k = ipsec_prepare_crypto_group(ctx, sa, ips,
310*2d9fd380Sjfb8856606 					pg->m, pg->cnt);
311*2d9fd380Sjfb8856606 				break;
312*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
313*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
314*2d9fd380Sjfb8856606 				k = ipsec_process_inline_group(ips, sa,
315*2d9fd380Sjfb8856606 					trf, pg->m, pg->cnt);
316*2d9fd380Sjfb8856606 				break;
317*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
318*2d9fd380Sjfb8856606 				k = ipsec_process_cpu_group(ips, sa,
319*2d9fd380Sjfb8856606 					trf, pg->m, pg->cnt);
320*2d9fd380Sjfb8856606 				break;
321*2d9fd380Sjfb8856606 			default:
322*2d9fd380Sjfb8856606 				k = 0;
323*2d9fd380Sjfb8856606 			}
3244418919fSjohnjiang 		}
3254418919fSjohnjiang 
3264418919fSjohnjiang 		/* drop packets that cannot be enqueued/processed */
3274418919fSjohnjiang 		if (k != pg->cnt)
3284418919fSjohnjiang 			free_pkts(pg->m + k, pg->cnt - k);
3294418919fSjohnjiang 	}
3304418919fSjohnjiang }
3314418919fSjohnjiang 
3324418919fSjohnjiang static inline uint32_t
cqp_dequeue(struct cdev_qp * cqp,struct rte_crypto_op * cop[],uint32_t num)3334418919fSjohnjiang cqp_dequeue(struct cdev_qp *cqp, struct rte_crypto_op *cop[], uint32_t num)
3344418919fSjohnjiang {
3354418919fSjohnjiang 	uint32_t n;
3364418919fSjohnjiang 
3374418919fSjohnjiang 	if (cqp->in_flight == 0)
3384418919fSjohnjiang 		return 0;
3394418919fSjohnjiang 
3404418919fSjohnjiang 	n = rte_cryptodev_dequeue_burst(cqp->id, cqp->qp, cop, num);
3414418919fSjohnjiang 	RTE_ASSERT(cqp->in_flight >= n);
3424418919fSjohnjiang 	cqp->in_flight -= n;
3434418919fSjohnjiang 
3444418919fSjohnjiang 	return n;
3454418919fSjohnjiang }
3464418919fSjohnjiang 
3474418919fSjohnjiang static inline uint32_t
ctx_dequeue(struct ipsec_ctx * ctx,struct rte_crypto_op * cop[],uint32_t num)3484418919fSjohnjiang ctx_dequeue(struct ipsec_ctx *ctx, struct rte_crypto_op *cop[], uint32_t num)
3494418919fSjohnjiang {
3504418919fSjohnjiang 	uint32_t i, n;
3514418919fSjohnjiang 
3524418919fSjohnjiang 	n = 0;
3534418919fSjohnjiang 
3544418919fSjohnjiang 	for (i = ctx->last_qp; n != num && i != ctx->nb_qps; i++)
3554418919fSjohnjiang 		n += cqp_dequeue(ctx->tbl + i, cop + n, num - n);
3564418919fSjohnjiang 
3574418919fSjohnjiang 	for (i = 0; n != num && i != ctx->last_qp; i++)
3584418919fSjohnjiang 		n += cqp_dequeue(ctx->tbl + i, cop + n, num - n);
3594418919fSjohnjiang 
3604418919fSjohnjiang 	ctx->last_qp = i;
3614418919fSjohnjiang 	return n;
3624418919fSjohnjiang }
3634418919fSjohnjiang 
3644418919fSjohnjiang /*
3654418919fSjohnjiang  * dequeue packets from crypto-queues and finalize processing.
3664418919fSjohnjiang  */
3674418919fSjohnjiang void
ipsec_cqp_process(struct ipsec_ctx * ctx,struct ipsec_traffic * trf)3684418919fSjohnjiang ipsec_cqp_process(struct ipsec_ctx *ctx, struct ipsec_traffic *trf)
3694418919fSjohnjiang {
3704418919fSjohnjiang 	uint64_t satp;
3714418919fSjohnjiang 	uint32_t i, k, n, ng;
3724418919fSjohnjiang 	struct rte_ipsec_session *ss;
3734418919fSjohnjiang 	struct traffic_type *out;
3744418919fSjohnjiang 	struct rte_ipsec_group *pg;
3754418919fSjohnjiang 	struct rte_crypto_op *cop[RTE_DIM(trf->ipsec.pkts)];
3764418919fSjohnjiang 	struct rte_ipsec_group grp[RTE_DIM(trf->ipsec.pkts)];
3774418919fSjohnjiang 
3784418919fSjohnjiang 	trf->ip4.num = 0;
3794418919fSjohnjiang 	trf->ip6.num = 0;
3804418919fSjohnjiang 
3814418919fSjohnjiang 	out = &trf->ipsec;
3824418919fSjohnjiang 
3834418919fSjohnjiang 	/* dequeue completed crypto-ops */
3844418919fSjohnjiang 	n = ctx_dequeue(ctx, cop, RTE_DIM(cop));
3854418919fSjohnjiang 	if (n == 0)
3864418919fSjohnjiang 		return;
3874418919fSjohnjiang 
3884418919fSjohnjiang 	/* group them by ipsec session */
3894418919fSjohnjiang 	ng = rte_ipsec_pkt_crypto_group((const struct rte_crypto_op **)
3904418919fSjohnjiang 		(uintptr_t)cop, out->pkts, grp, n);
3914418919fSjohnjiang 
3924418919fSjohnjiang 	/* process each group of packets */
3934418919fSjohnjiang 	for (i = 0; i != ng; i++) {
3944418919fSjohnjiang 
3954418919fSjohnjiang 		pg = grp + i;
3964418919fSjohnjiang 		ss = pg->id.ptr;
3974418919fSjohnjiang 		satp = rte_ipsec_sa_type(ss->sa);
3984418919fSjohnjiang 
3994418919fSjohnjiang 		k = rte_ipsec_pkt_process(ss, pg->m, pg->cnt);
4004418919fSjohnjiang 		copy_to_trf(trf, satp, pg->m, k);
4014418919fSjohnjiang 
4024418919fSjohnjiang 		/* free bad packets, if any */
4034418919fSjohnjiang 		free_pkts(pg->m + k, pg->cnt - k);
4044418919fSjohnjiang 
4054418919fSjohnjiang 		n -= pg->cnt;
4064418919fSjohnjiang 	}
4074418919fSjohnjiang 
4084418919fSjohnjiang 	/* we should never have packet with unknown SA here */
4094418919fSjohnjiang 	RTE_VERIFY(n == 0);
4104418919fSjohnjiang }
411