DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] ipsec: allow stateless IPsec processing
@ 2024-09-07 10:25 Aakash Sasidharan
  2024-09-08 11:57 ` [PATCH v2] " Aakash Sasidharan
  0 siblings, 1 reply; 10+ messages in thread
From: Aakash Sasidharan @ 2024-09-07 10:25 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Introduce stateless packet preparation API for IPsec
processing. The new API would allow preparation of IPsec
packets without altering the internal state of an IPsec
session.

For outbound IPsec processing, the change enables user to
provide sequence number to be used for the IPsec operation.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 lib/ipsec/esp_outb.c  | 85 +++++++++++++++++++++++++++++++------------
 lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
 lib/ipsec/sa.c        |  2 +
 lib/ipsec/sa.h        |  8 ++++
 4 files changed, 139 insertions(+), 24 deletions(-)

diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
index ec87b1dce2..de28cb166d 100644
--- a/lib/ipsec/esp_outb.c
+++ b/lib/ipsec/esp_outb.c
@@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
 /*
  * setup/update packets and crypto ops for ESP outbound tunnel case.
  */
-uint16_t
-esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
-	struct rte_crypto_op *cop[], uint16_t num)
+static inline uint16_t
+esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
 {
 	int32_t rc;
-	uint32_t i, k, n;
-	uint64_t sqn;
+	uint32_t i, k, n = num;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
 	struct rte_cryptodev_sym_session *cs;
@@ -305,11 +304,6 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	sa = ss->sa;
 	cs = ss->crypto.ses;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	k = 0;
 	for (i = 0; i != n; i++) {
 
@@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	return k;
 }
 
+uint16_t
+esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num)
+{
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn);
+}
+
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn);
+}
+
 /*
  * setup/update packet data and metadata for ESP outbound transport case.
  */
@@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, uint32_t *pofs,
 	return clen;
 }
 
-static uint16_t
-cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
-		struct rte_mbuf *mb[], uint16_t num,
-		esp_outb_prepare_t prepare, uint32_t cofs_mask)
+static inline uint16_t
+cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t prepare,
+		uint32_t cofs_mask,	uint64_t sqn)
 {
 	int32_t rc;
-	uint64_t sqn;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
-	uint32_t i, k, n;
+	uint32_t i, k, n = num;
 	uint32_t l2, l3;
 	union sym_op_data icv;
 	struct rte_crypto_va_iova_ptr iv[num];
@@ -551,11 +568,6 @@ cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
 
 	sa = ss->sa;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	for (i = 0, k = 0; i != n; i++) {
 
 		l2 = mb[i]->l2_len;
@@ -604,15 +616,40 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare, 0);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_tun_pkt_prepare, 0, sqn);
+}
+
+uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, num, outb_tun_pkt_prepare, 0, sqn);
 }
 
 uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
-		UINT32_MAX);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_trs_pkt_prepare,
+		UINT32_MAX, sqn);
 }
 
 /*
diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h
index f15f6f2966..b462068203 100644
--- a/lib/ipsec/rte_ipsec.h
+++ b/lib/ipsec/rte_ipsec.h
@@ -23,11 +23,26 @@ extern "C" {
 
 struct rte_ipsec_session;
 
+/**
+ * IPsec state for stateless processing of a batch of IPsec packets.
+ */
+struct rte_ipsec_state {
+	union {
+		/**
+		 * 64 bit sequence number to be used for the first packet of the
+		 * batch of packets.
+		 */
+		uint64_t sqn;
+	};
+};
+
 /**
  * IPsec session specific functions that will be used to:
  * - prepare - for input mbufs and given IPsec session prepare crypto ops
  *   that can be enqueued into the cryptodev associated with given session
  *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
+ * - prepare_stateless - similar to prepare, but further processing is done
+ *   based on IPsec state provided by the 'state' parameter.
  * - process - finalize processing of packets after crypto-dev finished
  *   with them or process packets that are subjects to inline IPsec offload
  *   (see rte_ipsec_pkt_process for more details).
@@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
 				struct rte_mbuf *mb[],
 				uint16_t num);
 	} prepare;
+	union {
+		uint16_t (*async)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				struct rte_crypto_op *cop[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+		uint16_t (*sync)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+	} prepare_stateless;
 	uint16_t (*process)(const struct rte_ipsec_session *ss,
 				struct rte_mbuf *mb[],
 				uint16_t num);
@@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct rte_ipsec_session *ss,
 	return ss->pkt_func.prepare.sync(ss, mb, num);
 }
 
+/**
+ * Same as rte_ipsec_pkt_crypto_prepare, but processing is done based on
+ * IPsec state provided by the 'state' parameter. Internal IPsec state won't
+ * be updated when this API is called.
+ *
+ * For input mbufs and given IPsec session prepare crypto ops that can be
+ * enqueued into the cryptodev associated with given session.
+ * expects that for each input packet:
+ *      - l2_len, l3_len are setup correctly
+ * Note that erroneous mbufs are not freed by the function,
+ * but are placed beyond last valid mbuf in the *mb* array.
+ * It is a user responsibility to handle them further.
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param cop
+ *   The address of an array of *num* pointers to the output *rte_crypto_op*
+ *   structures.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+static inline uint16_t
+rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
+	struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num, state);
+}
+
+static inline uint16_t
+rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
+}
+
 /**
  * Finalise processing of packets after crypto-dev finished with them or
  * process packets that are subjects to inline IPsec offload.
diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
index 2297bd6d72..ef51c566a3 100644
--- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.async = esp_outb_tun_prepare;
+		pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
+		pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h
index 719b5c735c..9b53586b2d 100644
--- a/lib/ipsec/sa.h
+++ b/lib/ipsec/sa.h
@@ -179,6 +179,10 @@ uint16_t
 esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
 
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state);
+
 uint16_t
 esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
@@ -207,6 +211,10 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state);
+
+uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2] ipsec: allow stateless IPsec processing
  2024-09-07 10:25 [PATCH] ipsec: allow stateless IPsec processing Aakash Sasidharan
@ 2024-09-08 11:57 ` Aakash Sasidharan
  2024-09-17 17:13   ` Konstantin Ananyev
  2024-10-03 13:45   ` [PATCH v3 1/2] " Aakash Sasidharan
  0 siblings, 2 replies; 10+ messages in thread
From: Aakash Sasidharan @ 2024-09-08 11:57 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Introduce stateless packet preparation API for IPsec
processing. The new API would allow preparation of IPsec
packets without altering the internal state of an IPsec
session.

For outbound IPsec processing, the change enables user to
provide sequence number to be used for the IPsec operation.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 lib/ipsec/esp_outb.c  | 85 +++++++++++++++++++++++++++++++------------
 lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
 lib/ipsec/sa.c        |  4 +-
 lib/ipsec/sa.h        |  8 ++++
 4 files changed, 140 insertions(+), 25 deletions(-)

diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
index ec87b1dce2..de28cb166d 100644
--- a/lib/ipsec/esp_outb.c
+++ b/lib/ipsec/esp_outb.c
@@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
 /*
  * setup/update packets and crypto ops for ESP outbound tunnel case.
  */
-uint16_t
-esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
-	struct rte_crypto_op *cop[], uint16_t num)
+static inline uint16_t
+esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
 {
 	int32_t rc;
-	uint32_t i, k, n;
-	uint64_t sqn;
+	uint32_t i, k, n = num;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
 	struct rte_cryptodev_sym_session *cs;
@@ -305,11 +304,6 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	sa = ss->sa;
 	cs = ss->crypto.ses;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	k = 0;
 	for (i = 0; i != n; i++) {
 
@@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	return k;
 }
 
+uint16_t
+esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num)
+{
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn);
+}
+
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn);
+}
+
 /*
  * setup/update packet data and metadata for ESP outbound transport case.
  */
@@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, uint32_t *pofs,
 	return clen;
 }
 
-static uint16_t
-cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
-		struct rte_mbuf *mb[], uint16_t num,
-		esp_outb_prepare_t prepare, uint32_t cofs_mask)
+static inline uint16_t
+cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t prepare,
+		uint32_t cofs_mask,	uint64_t sqn)
 {
 	int32_t rc;
-	uint64_t sqn;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
-	uint32_t i, k, n;
+	uint32_t i, k, n = num;
 	uint32_t l2, l3;
 	union sym_op_data icv;
 	struct rte_crypto_va_iova_ptr iv[num];
@@ -551,11 +568,6 @@ cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
 
 	sa = ss->sa;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	for (i = 0, k = 0; i != n; i++) {
 
 		l2 = mb[i]->l2_len;
@@ -604,15 +616,40 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare, 0);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_tun_pkt_prepare, 0, sqn);
+}
+
+uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, num, outb_tun_pkt_prepare, 0, sqn);
 }
 
 uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
-		UINT32_MAX);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_trs_pkt_prepare,
+		UINT32_MAX, sqn);
 }
 
 /*
diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h
index f15f6f2966..b462068203 100644
--- a/lib/ipsec/rte_ipsec.h
+++ b/lib/ipsec/rte_ipsec.h
@@ -23,11 +23,26 @@ extern "C" {
 
 struct rte_ipsec_session;
 
+/**
+ * IPsec state for stateless processing of a batch of IPsec packets.
+ */
+struct rte_ipsec_state {
+	union {
+		/**
+		 * 64 bit sequence number to be used for the first packet of the
+		 * batch of packets.
+		 */
+		uint64_t sqn;
+	};
+};
+
 /**
  * IPsec session specific functions that will be used to:
  * - prepare - for input mbufs and given IPsec session prepare crypto ops
  *   that can be enqueued into the cryptodev associated with given session
  *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
+ * - prepare_stateless - similar to prepare, but further processing is done
+ *   based on IPsec state provided by the 'state' parameter.
  * - process - finalize processing of packets after crypto-dev finished
  *   with them or process packets that are subjects to inline IPsec offload
  *   (see rte_ipsec_pkt_process for more details).
@@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
 				struct rte_mbuf *mb[],
 				uint16_t num);
 	} prepare;
+	union {
+		uint16_t (*async)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				struct rte_crypto_op *cop[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+		uint16_t (*sync)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+	} prepare_stateless;
 	uint16_t (*process)(const struct rte_ipsec_session *ss,
 				struct rte_mbuf *mb[],
 				uint16_t num);
@@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct rte_ipsec_session *ss,
 	return ss->pkt_func.prepare.sync(ss, mb, num);
 }
 
+/**
+ * Same as rte_ipsec_pkt_crypto_prepare, but processing is done based on
+ * IPsec state provided by the 'state' parameter. Internal IPsec state won't
+ * be updated when this API is called.
+ *
+ * For input mbufs and given IPsec session prepare crypto ops that can be
+ * enqueued into the cryptodev associated with given session.
+ * expects that for each input packet:
+ *      - l2_len, l3_len are setup correctly
+ * Note that erroneous mbufs are not freed by the function,
+ * but are placed beyond last valid mbuf in the *mb* array.
+ * It is a user responsibility to handle them further.
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param cop
+ *   The address of an array of *num* pointers to the output *rte_crypto_op*
+ *   structures.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+static inline uint16_t
+rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
+	struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num, state);
+}
+
+static inline uint16_t
+rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
+}
+
 /**
  * Finalise processing of packets after crypto-dev finished with them or
  * process packets that are subjects to inline IPsec offload.
diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
index 2297bd6d72..741e079831 100644
--- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.async = esp_outb_tun_prepare;
+		pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
+		pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
 	int32_t rc;
 
 	rc = 0;
-	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
+	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
 
 	switch (ss->type) {
 	case RTE_SECURITY_ACTION_TYPE_NONE:
diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h
index 719b5c735c..9b53586b2d 100644
--- a/lib/ipsec/sa.h
+++ b/lib/ipsec/sa.h
@@ -179,6 +179,10 @@ uint16_t
 esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
 
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state);
+
 uint16_t
 esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
@@ -207,6 +211,10 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state);
+
+uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v2] ipsec: allow stateless IPsec processing
  2024-09-08 11:57 ` [PATCH v2] " Aakash Sasidharan
@ 2024-09-17 17:13   ` Konstantin Ananyev
  2024-09-20  2:12     ` Aakash Sasidharan
  2024-10-03 13:45   ` [PATCH v3 1/2] " Aakash Sasidharan
  1 sibling, 1 reply; 10+ messages in thread
From: Konstantin Ananyev @ 2024-09-17 17:13 UTC (permalink / raw)
  To: Aakash Sasidharan, Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, dev



> Introduce stateless packet preparation API for IPsec
> processing. The new API would allow preparation of IPsec
> packets without altering the internal state of an IPsec
> session.
> 
> For outbound IPsec processing, the change enables user to
> provide sequence number to be used for the IPsec operation.

Few questions/nits below.
As a generic one - we need to add a use-case/test-case for it.
Without it I think the patch is incomplete.

> 
> Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
> ---
>  lib/ipsec/esp_outb.c  | 85 +++++++++++++++++++++++++++++++------------
>  lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
>  lib/ipsec/sa.c        |  4 +-
>  lib/ipsec/sa.h        |  8 ++++
>  4 files changed, 140 insertions(+), 25 deletions(-)
> 
> diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
> index ec87b1dce2..de28cb166d 100644
> --- a/lib/ipsec/esp_outb.c
> +++ b/lib/ipsec/esp_outb.c
> @@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
>  /*
>   * setup/update packets and crypto ops for ESP outbound tunnel case.
>   */
> -uint16_t
> -esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
> -	struct rte_crypto_op *cop[], uint16_t num)
> +static inline uint16_t
> +esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
> +	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
>  {
>  	int32_t rc;
> -	uint32_t i, k, n;
> -	uint64_t sqn;
> +	uint32_t i, k, n = num;

You can just do s/num/n/ in function parameter list, then you don't need to keep
'num' at all.

>  	rte_be64_t sqc;
>  	struct rte_ipsec_sa *sa;
>  	struct rte_cryptodev_sym_session *cs;
> @@ -305,11 +304,6 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
>  	sa = ss->sa;
>  	cs = ss->crypto.ses;
> 
> -	n = num;
> -	sqn = esn_outb_update_sqn(sa, &n);
> -	if (n != num)
> -		rte_errno = EOVERFLOW;
> -
>  	k = 0;
>  	for (i = 0; i != n; i++) {
> 
> @@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
>  	return k;
>  }
> 
> +uint16_t
> +esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
> +	struct rte_crypto_op *cop[], uint16_t num)
> +{
> +	uint64_t sqn;
> +	uint32_t n;
> +
> +	n = num;
> +	sqn = esn_outb_update_sqn(ss->sa, &n);
> +	if (n != num)
> +		rte_errno = EOVERFLOW;
> +
> +	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn);
> +}
> +
> +uint16_t
> +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
> +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state)
> +{
> +	uint64_t sqn = state->sqn;
> +
> +	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn);
> +}
> +
>  /*
>   * setup/update packet data and metadata for ESP outbound transport case.
>   */
> @@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, uint32_t *pofs,
>  	return clen;
>  }
> 
> -static uint16_t
> -cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> -		struct rte_mbuf *mb[], uint16_t num,
> -		esp_outb_prepare_t prepare, uint32_t cofs_mask)
> +static inline uint16_t
> +cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
> +		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t prepare,
> +		uint32_t cofs_mask,	uint64_t sqn)
>  {
>  	int32_t rc;
> -	uint64_t sqn;
>  	rte_be64_t sqc;
>  	struct rte_ipsec_sa *sa;
> -	uint32_t i, k, n;
> +	uint32_t i, k, n = num;

Same here, you can just use 'n' instead of 'num'.

>  	uint32_t l2, l3;
>  	union sym_op_data icv;
>  	struct rte_crypto_va_iova_ptr iv[num];
> @@ -551,11 +568,6 @@ cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> 
>  	sa = ss->sa;
> 
> -	n = num;
> -	sqn = esn_outb_update_sqn(sa, &n);
> -	if (n != num)
> -		rte_errno = EOVERFLOW;
> -
>  	for (i = 0, k = 0; i != n; i++) {
> 
>  		l2 = mb[i]->l2_len;
> @@ -604,15 +616,40 @@ uint16_t
>  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
>  		struct rte_mbuf *mb[], uint16_t num)
>  {
> -	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare, 0);
> +	uint64_t sqn;
> +	uint32_t n;
> +
> +	n = num;
> +	sqn = esn_outb_update_sqn(ss->sa, &n);
> +	if (n != num)
> +		rte_errno = EOVERFLOW;
> +
> +	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_tun_pkt_prepare, 0, sqn);
> +}
> +
> +uint16_t
> +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
> +{
> +	uint64_t sqn = state->sqn;
> +
> +	return cpu_outb_pkt_prepare_helper(ss, mb, num, outb_tun_pkt_prepare, 0, sqn);
>  }
> 
>  uint16_t
>  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
>  		struct rte_mbuf *mb[], uint16_t num)
>  {
> -	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
> -		UINT32_MAX);
> +	uint64_t sqn;
> +	uint32_t n;
> +
> +	n = num;
> +	sqn = esn_outb_update_sqn(ss->sa, &n);
> +	if (n != num)
> +		rte_errno = EOVERFLOW;
> +
> +	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_trs_pkt_prepare,
> +		UINT32_MAX, sqn);
>  }
> 
>  /*
> diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h
> index f15f6f2966..b462068203 100644
> --- a/lib/ipsec/rte_ipsec.h
> +++ b/lib/ipsec/rte_ipsec.h
> @@ -23,11 +23,26 @@ extern "C" {
> 
>  struct rte_ipsec_session;
> 
> +/**
> + * IPsec state for stateless processing of a batch of IPsec packets.
> + */
> +struct rte_ipsec_state {
> +	union {

Curious what is the purpose of 'union' here?
What other mutually exclusive fields you plan to add here?

> +		/**
> +		 * 64 bit sequence number to be used for the first packet of the
> +		 * batch of packets.
> +		 */
> +		uint64_t sqn;
> +	};
> +};
> +
>  /**
>   * IPsec session specific functions that will be used to:
>   * - prepare - for input mbufs and given IPsec session prepare crypto ops
>   *   that can be enqueued into the cryptodev associated with given session
>   *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
> + * - prepare_stateless - similar to prepare, but further processing is done
> + *   based on IPsec state provided by the 'state' parameter.
>   * - process - finalize processing of packets after crypto-dev finished
>   *   with them or process packets that are subjects to inline IPsec offload
>   *   (see rte_ipsec_pkt_process for more details).
> @@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
>  				struct rte_mbuf *mb[],
>  				uint16_t num);
>  	} prepare;
> +	union {
> +		uint16_t (*async)(const struct rte_ipsec_session *ss,
> +				struct rte_mbuf *mb[],
> +				struct rte_crypto_op *cop[],
> +				uint16_t num,
> +				struct rte_ipsec_state *state);
> +		uint16_t (*sync)(const struct rte_ipsec_session *ss,
> +				struct rte_mbuf *mb[],
> +				uint16_t num,
> +				struct rte_ipsec_state *state);
> +	} prepare_stateless;
>  	uint16_t (*process)(const struct rte_ipsec_session *ss,
>  				struct rte_mbuf *mb[],
>  				uint16_t num);
> @@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct rte_ipsec_session *ss,
>  	return ss->pkt_func.prepare.sync(ss, mb, num);
>  }
> 
> +/**
> + * Same as rte_ipsec_pkt_crypto_prepare, but processing is done based on
> + * IPsec state provided by the 'state' parameter. Internal IPsec state won't
> + * be updated when this API is called.
> + *
> + * For input mbufs and given IPsec session prepare crypto ops that can be
> + * enqueued into the cryptodev associated with given session.
> + * expects that for each input packet:
> + *      - l2_len, l3_len are setup correctly
> + * Note that erroneous mbufs are not freed by the function,
> + * but are placed beyond last valid mbuf in the *mb* array.
> + * It is a user responsibility to handle them further.
> + * @param ss
> + *   Pointer to the *rte_ipsec_session* object the packets belong to.
> + * @param mb
> + *   The address of an array of *num* pointers to *rte_mbuf* structures
> + *   which contain the input packets.
> + * @param cop
> + *   The address of an array of *num* pointers to the output *rte_crypto_op*
> + *   structures.
> + * @param num
> + *   The maximum number of packets to process.
> + * @param state
> + *   The IPsec state to be used for processing current batch of packets.
> + * @return
> + *   Number of successfully processed packets, with error code set in rte_errno.
> + */

We probably need to mark new API as 'rte_experimental'.

> +static inline uint16_t
> +rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
> +	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
> +	struct rte_ipsec_state *state)
> +{
> +	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num, state);
> +}
> +
> +static inline uint16_t
> +rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
> +	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
> +{
> +	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
> +}
> +
>  /**
>   * Finalise processing of packets after crypto-dev finished with them or
>   * process packets that are subjects to inline IPsec offload.
> diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
> index 2297bd6d72..741e079831 100644
> --- a/lib/ipsec/sa.c
> +++ b/lib/ipsec/sa.c
> @@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
>  		pf->prepare.async = esp_outb_tun_prepare;
> +		pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
>  		pf->process = (sa->sqh_len != 0) ?
>  			esp_outb_sqh_process : pkt_flag_process;
>  		break;
> @@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
>  		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
> +		pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
>  		pf->process = (sa->sqh_len != 0) ?
>  			esp_outb_sqh_process : pkt_flag_process;
>  		break;
> @@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
>  	int32_t rc;
> 
>  	rc = 0;
> -	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
> +	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
> 
>  	switch (ss->type) {
>  	case RTE_SECURITY_ACTION_TYPE_NONE:
> diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h
> index 719b5c735c..9b53586b2d 100644
> --- a/lib/ipsec/sa.h
> +++ b/lib/ipsec/sa.h
> @@ -179,6 +179,10 @@ uint16_t
>  esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
>  	struct rte_crypto_op *cop[], uint16_t num);
> 
> +uint16_t
> +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
> +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state);
> +
>  uint16_t
>  esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
>  	struct rte_crypto_op *cop[], uint16_t num);
> @@ -207,6 +211,10 @@ uint16_t
>  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
>  		struct rte_mbuf *mb[], uint16_t num);
>  uint16_t
> +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state);
> +
> +uint16_t
>  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
>  		struct rte_mbuf *mb[], uint16_t num);
> 
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v2] ipsec: allow stateless IPsec processing
  2024-09-17 17:13   ` Konstantin Ananyev
@ 2024-09-20  2:12     ` Aakash Sasidharan
  2024-09-20  5:53       ` Aakash Sasidharan
  0 siblings, 1 reply; 10+ messages in thread
From: Aakash Sasidharan @ 2024-09-20  2:12 UTC (permalink / raw)
  To: Konstantin Ananyev, Konstantin Ananyev, Vladimir Medvedkin
  Cc: Akhil Goyal, Jerin Jacob, Anoob Joseph, Vidya Sagar Velumuri, dev

> > Introduce stateless packet preparation API for IPsec processing. The
> > new API would allow preparation of IPsec packets without altering the
> > internal state of an IPsec session.
> >
> > For outbound IPsec processing, the change enables user to provide
> > sequence number to be used for the IPsec operation.
> 
> Few questions/nits below.
> As a generic one - we need to add a use-case/test-case for it.
> Without it I think the patch is incomplete.

Ack. Will add test-case with v3.

> 
> >
> > Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
> > ---
> >  lib/ipsec/esp_outb.c  | 85
> > +++++++++++++++++++++++++++++++------------
> >  lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
> >  lib/ipsec/sa.c        |  4 +-
> >  lib/ipsec/sa.h        |  8 ++++
> >  4 files changed, 140 insertions(+), 25 deletions(-)
> >
> > diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c index
> > ec87b1dce2..de28cb166d 100644
> > --- a/lib/ipsec/esp_outb.c
> > +++ b/lib/ipsec/esp_outb.c
> > @@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa,
> > rte_be64_t sqc,
> >  /*
> >   * setup/update packets and crypto ops for ESP outbound tunnel case.
> >   */
> > -uint16_t
> > -esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf
> *mb[],
> > -	struct rte_crypto_op *cop[], uint16_t num)
> > +static inline uint16_t
> > +esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct
> rte_mbuf *mb[],
> > +	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
> >  {
> >  	int32_t rc;
> > -	uint32_t i, k, n;
> > -	uint64_t sqn;
> > +	uint32_t i, k, n = num;
> 
> You can just do s/num/n/ in function parameter list, then you don't need to
> keep 'num' at all.

This function will be called for normal IPsec processing. The function esn_outb_update_sqn() updates the local variable n passed as parameter in OVERFLOW case. If we remove the local variable n, this error path would be lost and it is not our intention I believe.

> 
> >  	rte_be64_t sqc;
> >  	struct rte_ipsec_sa *sa;
> >  	struct rte_cryptodev_sym_session *cs; @@ -305,11 +304,6 @@
> > esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf
> *mb[],
> >  	sa = ss->sa;
> >  	cs = ss->crypto.ses;
> >
> > -	n = num;
> > -	sqn = esn_outb_update_sqn(sa, &n);
> > -	if (n != num)
> > -		rte_errno = EOVERFLOW;
> > -
> >  	k = 0;
> >  	for (i = 0; i != n; i++) {
> >
> > @@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct
> rte_ipsec_session *ss, struct rte_mbuf *mb[],
> >  	return k;
> >  }
> >
> > +uint16_t
> > +esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf
> *mb[],
> > +	struct rte_crypto_op *cop[], uint16_t num) {
> > +	uint64_t sqn;
> > +	uint32_t n;
> > +
> > +	n = num;
> > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > +	if (n != num)
> > +		rte_errno = EOVERFLOW;
> > +
> > +	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn); }
> > +
> > +uint16_t
> > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct
> rte_mbuf *mb[],
> > +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state
> > +*state) {
> > +	uint64_t sqn = state->sqn;
> > +
> > +	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn); }
> > +
> >  /*
> >   * setup/update packet data and metadata for ESP outbound transport case.
> >   */
> > @@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct
> rte_ipsec_sa *sa, uint32_t *pofs,
> >  	return clen;
> >  }
> >
> > -static uint16_t
> > -cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> > -		struct rte_mbuf *mb[], uint16_t num,
> > -		esp_outb_prepare_t prepare, uint32_t cofs_mask)
> > +static inline uint16_t
> > +cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
> > +		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t
> prepare,
> > +		uint32_t cofs_mask,	uint64_t sqn)
> >  {
> >  	int32_t rc;
> > -	uint64_t sqn;
> >  	rte_be64_t sqc;
> >  	struct rte_ipsec_sa *sa;
> > -	uint32_t i, k, n;
> > +	uint32_t i, k, n = num;
> 
> Same here, you can just use 'n' instead of 'num'.

Same comment as above.

> 
> >  	uint32_t l2, l3;
> >  	union sym_op_data icv;
> >  	struct rte_crypto_va_iova_ptr iv[num]; @@ -551,11 +568,6 @@
> > cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> >
> >  	sa = ss->sa;
> >
> > -	n = num;
> > -	sqn = esn_outb_update_sqn(sa, &n);
> > -	if (n != num)
> > -		rte_errno = EOVERFLOW;
> > -
> >  	for (i = 0, k = 0; i != n; i++) {
> >
> >  		l2 = mb[i]->l2_len;
> > @@ -604,15 +616,40 @@ uint16_t
> >  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> >  		struct rte_mbuf *mb[], uint16_t num)  {
> > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare,
> 0);
> > +	uint64_t sqn;
> > +	uint32_t n;
> > +
> > +	n = num;
> > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > +	if (n != num)
> > +		rte_errno = EOVERFLOW;
> > +
> > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> outb_tun_pkt_prepare,
> > +0, sqn); }
> > +
> > +uint16_t
> > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> *state)
> > +{
> > +	uint64_t sqn = state->sqn;
> > +
> > +	return cpu_outb_pkt_prepare_helper(ss, mb, num,
> > +outb_tun_pkt_prepare, 0, sqn);
> >  }
> >
> >  uint16_t
> >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> >  		struct rte_mbuf *mb[], uint16_t num)  {
> > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
> > -		UINT32_MAX);
> > +	uint64_t sqn;
> > +	uint32_t n;
> > +
> > +	n = num;
> > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > +	if (n != num)
> > +		rte_errno = EOVERFLOW;
> > +
> > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> outb_trs_pkt_prepare,
> > +		UINT32_MAX, sqn);
> >  }
> >
> >  /*
> > diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h index
> > f15f6f2966..b462068203 100644
> > --- a/lib/ipsec/rte_ipsec.h
> > +++ b/lib/ipsec/rte_ipsec.h
> > @@ -23,11 +23,26 @@ extern "C" {
> >
> >  struct rte_ipsec_session;
> >
> > +/**
> > + * IPsec state for stateless processing of a batch of IPsec packets.
> > + */
> > +struct rte_ipsec_state {
> > +	union {
> 
> Curious what is the purpose of 'union' here?
> What other mutually exclusive fields you plan to add here?
> 
> > +		/**
> > +		 * 64 bit sequence number to be used for the first packet of
> the
> > +		 * batch of packets.
> > +		 */
> > +		uint64_t sqn;
> > +	};
> > +};
> > +
> >  /**
> >   * IPsec session specific functions that will be used to:
> >   * - prepare - for input mbufs and given IPsec session prepare crypto ops
> >   *   that can be enqueued into the cryptodev associated with given session
> >   *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
> > + * - prepare_stateless - similar to prepare, but further processing is done
> > + *   based on IPsec state provided by the 'state' parameter.
> >   * - process - finalize processing of packets after crypto-dev finished
> >   *   with them or process packets that are subjects to inline IPsec offload
> >   *   (see rte_ipsec_pkt_process for more details).
> > @@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
> >  				struct rte_mbuf *mb[],
> >  				uint16_t num);
> >  	} prepare;
> > +	union {
> > +		uint16_t (*async)(const struct rte_ipsec_session *ss,
> > +				struct rte_mbuf *mb[],
> > +				struct rte_crypto_op *cop[],
> > +				uint16_t num,
> > +				struct rte_ipsec_state *state);
> > +		uint16_t (*sync)(const struct rte_ipsec_session *ss,
> > +				struct rte_mbuf *mb[],
> > +				uint16_t num,
> > +				struct rte_ipsec_state *state);
> > +	} prepare_stateless;
> >  	uint16_t (*process)(const struct rte_ipsec_session *ss,
> >  				struct rte_mbuf *mb[],
> >  				uint16_t num);
> > @@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct
> rte_ipsec_session *ss,
> >  	return ss->pkt_func.prepare.sync(ss, mb, num);  }
> >
> > +/**
> > + * Same as rte_ipsec_pkt_crypto_prepare, but processing is done based
> > +on
> > + * IPsec state provided by the 'state' parameter. Internal IPsec
> > +state won't
> > + * be updated when this API is called.
> > + *
> > + * For input mbufs and given IPsec session prepare crypto ops that
> > +can be
> > + * enqueued into the cryptodev associated with given session.
> > + * expects that for each input packet:
> > + *      - l2_len, l3_len are setup correctly
> > + * Note that erroneous mbufs are not freed by the function,
> > + * but are placed beyond last valid mbuf in the *mb* array.
> > + * It is a user responsibility to handle them further.
> > + * @param ss
> > + *   Pointer to the *rte_ipsec_session* object the packets belong to.
> > + * @param mb
> > + *   The address of an array of *num* pointers to *rte_mbuf* structures
> > + *   which contain the input packets.
> > + * @param cop
> > + *   The address of an array of *num* pointers to the output
> *rte_crypto_op*
> > + *   structures.
> > + * @param num
> > + *   The maximum number of packets to process.
> > + * @param state
> > + *   The IPsec state to be used for processing current batch of packets.
> > + * @return
> > + *   Number of successfully processed packets, with error code set in
> rte_errno.
> > + */
> 
> We probably need to mark new API as 'rte_experimental'.

Ack. Will update in v3.

> 
> > +static inline uint16_t
> > +rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
> > +	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
> > +	struct rte_ipsec_state *state)
> > +{
> > +	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num,
> > +state); }
> > +
> > +static inline uint16_t
> > +rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
> > +	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
> > +{
> > +	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state); }
> > +
> >  /**
> >   * Finalise processing of packets after crypto-dev finished with them or
> >   * process packets that are subjects to inline IPsec offload.
> > diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c index
> > 2297bd6d72..741e079831 100644
> > --- a/lib/ipsec/sa.c
> > +++ b/lib/ipsec/sa.c
> > @@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct
> rte_ipsec_sa *sa,
> >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> >  		pf->prepare.async = esp_outb_tun_prepare;
> > +		pf->prepare_stateless.async =
> esp_outb_tun_prepare_stateless;
> >  		pf->process = (sa->sqh_len != 0) ?
> >  			esp_outb_sqh_process : pkt_flag_process;
> >  		break;
> > @@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct
> rte_ipsec_sa *sa,
> >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> >  		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
> > +		pf->prepare_stateless.sync =
> cpu_outb_tun_pkt_prepare_stateless;
> >  		pf->process = (sa->sqh_len != 0) ?
> >  			esp_outb_sqh_process : pkt_flag_process;
> >  		break;
> > @@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct
> rte_ipsec_session *ss,
> >  	int32_t rc;
> >
> >  	rc = 0;
> > -	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
> > +	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
> >
> >  	switch (ss->type) {
> >  	case RTE_SECURITY_ACTION_TYPE_NONE:
> > diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h index
> > 719b5c735c..9b53586b2d 100644
> > --- a/lib/ipsec/sa.h
> > +++ b/lib/ipsec/sa.h
> > @@ -179,6 +179,10 @@ uint16_t
> >  esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf
> *mb[],
> >  	struct rte_crypto_op *cop[], uint16_t num);
> >
> > +uint16_t
> > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct
> rte_mbuf *mb[],
> > +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state
> > +*state);
> > +
> >  uint16_t
> >  esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf
> *mb[],
> >  	struct rte_crypto_op *cop[], uint16_t num); @@ -207,6 +211,10 @@
> > uint16_t  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> >  		struct rte_mbuf *mb[], uint16_t num);  uint16_t
> > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > +*state);
> > +
> > +uint16_t
> >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> >  		struct rte_mbuf *mb[], uint16_t num);
> >
> > --
> > 2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v2] ipsec: allow stateless IPsec processing
  2024-09-20  2:12     ` Aakash Sasidharan
@ 2024-09-20  5:53       ` Aakash Sasidharan
  2024-09-25 11:59         ` Aakash Sasidharan
  0 siblings, 1 reply; 10+ messages in thread
From: Aakash Sasidharan @ 2024-09-20  5:53 UTC (permalink / raw)
  To: Konstantin Ananyev, Konstantin Ananyev, Vladimir Medvedkin
  Cc: Akhil Goyal, Jerin Jacob, Anoob Joseph, Vidya Sagar Velumuri, dev

> > > Introduce stateless packet preparation API for IPsec processing. The
> > > new API would allow preparation of IPsec packets without altering
> > > the internal state of an IPsec session.
> > >
> > > For outbound IPsec processing, the change enables user to provide
> > > sequence number to be used for the IPsec operation.
> >
> > Few questions/nits below.
> > As a generic one - we need to add a use-case/test-case for it.
> > Without it I think the patch is incomplete.
> 
> Ack. Will add test-case with v3.
> 
> >
> > >
> > > Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
> > > ---
> > >  lib/ipsec/esp_outb.c  | 85
> > > +++++++++++++++++++++++++++++++------------
> > >  lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
> > >  lib/ipsec/sa.c        |  4 +-
> > >  lib/ipsec/sa.h        |  8 ++++
> > >  4 files changed, 140 insertions(+), 25 deletions(-)
> > >
> > > diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c index
> > > ec87b1dce2..de28cb166d 100644
> > > --- a/lib/ipsec/esp_outb.c
> > > +++ b/lib/ipsec/esp_outb.c
> > > @@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa
> > > *sa, rte_be64_t sqc,
> > >  /*
> > >   * setup/update packets and crypto ops for ESP outbound tunnel case.
> > >   */
> > > -uint16_t
> > > -esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > rte_mbuf
> > *mb[],
> > > -	struct rte_crypto_op *cop[], uint16_t num)
> > > +static inline uint16_t
> > > +esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss,
> > > +struct
> > rte_mbuf *mb[],
> > > +	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
> > >  {
> > >  	int32_t rc;
> > > -	uint32_t i, k, n;
> > > -	uint64_t sqn;
> > > +	uint32_t i, k, n = num;
> >
> > You can just do s/num/n/ in function parameter list, then you don't
> > need to keep 'num' at all.
> 
> This function will be called for normal IPsec processing. The function
> esn_outb_update_sqn() updates the local variable n passed as parameter in
> OVERFLOW case. If we remove the local variable n, this error path would be
> lost and it is not our intention I believe.

Apologies. Replied too soon. I understand your suggestion and will update that in v3.

> 
> >
> > >  	rte_be64_t sqc;
> > >  	struct rte_ipsec_sa *sa;
> > >  	struct rte_cryptodev_sym_session *cs; @@ -305,11 +304,6 @@
> > > esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > rte_mbuf
> > *mb[],
> > >  	sa = ss->sa;
> > >  	cs = ss->crypto.ses;
> > >
> > > -	n = num;
> > > -	sqn = esn_outb_update_sqn(sa, &n);
> > > -	if (n != num)
> > > -		rte_errno = EOVERFLOW;
> > > -
> > >  	k = 0;
> > >  	for (i = 0; i != n; i++) {
> > >
> > > @@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct
> > rte_ipsec_session *ss, struct rte_mbuf *mb[],
> > >  	return k;
> > >  }
> > >
> > > +uint16_t
> > > +esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > +rte_mbuf
> > *mb[],
> > > +	struct rte_crypto_op *cop[], uint16_t num) {
> > > +	uint64_t sqn;
> > > +	uint32_t n;
> > > +
> > > +	n = num;
> > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > +	if (n != num)
> > > +		rte_errno = EOVERFLOW;
> > > +
> > > +	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn); }
> > > +
> > > +uint16_t
> > > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss,
> > > +struct
> > rte_mbuf *mb[],
> > > +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state
> > > +*state) {
> > > +	uint64_t sqn = state->sqn;
> > > +
> > > +	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn); }
> > > +
> > >  /*
> > >   * setup/update packet data and metadata for ESP outbound transport
> case.
> > >   */
> > > @@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct
> > rte_ipsec_sa *sa, uint32_t *pofs,
> > >  	return clen;
> > >  }
> > >
> > > -static uint16_t
> > > -cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> > > -		struct rte_mbuf *mb[], uint16_t num,
> > > -		esp_outb_prepare_t prepare, uint32_t cofs_mask)
> > > +static inline uint16_t
> > > +cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
> > > +		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t
> > prepare,
> > > +		uint32_t cofs_mask,	uint64_t sqn)
> > >  {
> > >  	int32_t rc;
> > > -	uint64_t sqn;
> > >  	rte_be64_t sqc;
> > >  	struct rte_ipsec_sa *sa;
> > > -	uint32_t i, k, n;
> > > +	uint32_t i, k, n = num;
> >
> > Same here, you can just use 'n' instead of 'num'.
> 
> Same comment as above.
> 
> >
> > >  	uint32_t l2, l3;
> > >  	union sym_op_data icv;
> > >  	struct rte_crypto_va_iova_ptr iv[num]; @@ -551,11 +568,6 @@
> > > cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> > >
> > >  	sa = ss->sa;
> > >
> > > -	n = num;
> > > -	sqn = esn_outb_update_sqn(sa, &n);
> > > -	if (n != num)
> > > -		rte_errno = EOVERFLOW;
> > > -
> > >  	for (i = 0, k = 0; i != n; i++) {
> > >
> > >  		l2 = mb[i]->l2_len;
> > > @@ -604,15 +616,40 @@ uint16_t
> > >  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> > >  		struct rte_mbuf *mb[], uint16_t num)  {
> > > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare,
> > 0);
> > > +	uint64_t sqn;
> > > +	uint32_t n;
> > > +
> > > +	n = num;
> > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > +	if (n != num)
> > > +		rte_errno = EOVERFLOW;
> > > +
> > > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> > outb_tun_pkt_prepare,
> > > +0, sqn); }
> > > +
> > > +uint16_t
> > > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> > > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > *state)
> > > +{
> > > +	uint64_t sqn = state->sqn;
> > > +
> > > +	return cpu_outb_pkt_prepare_helper(ss, mb, num,
> > > +outb_tun_pkt_prepare, 0, sqn);
> > >  }
> > >
> > >  uint16_t
> > >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> > >  		struct rte_mbuf *mb[], uint16_t num)  {
> > > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
> > > -		UINT32_MAX);
> > > +	uint64_t sqn;
> > > +	uint32_t n;
> > > +
> > > +	n = num;
> > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > +	if (n != num)
> > > +		rte_errno = EOVERFLOW;
> > > +
> > > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> > outb_trs_pkt_prepare,
> > > +		UINT32_MAX, sqn);
> > >  }
> > >
> > >  /*
> > > diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h index
> > > f15f6f2966..b462068203 100644
> > > --- a/lib/ipsec/rte_ipsec.h
> > > +++ b/lib/ipsec/rte_ipsec.h
> > > @@ -23,11 +23,26 @@ extern "C" {
> > >
> > >  struct rte_ipsec_session;
> > >
> > > +/**
> > > + * IPsec state for stateless processing of a batch of IPsec packets.
> > > + */
> > > +struct rte_ipsec_state {
> > > +	union {
> >
> > Curious what is the purpose of 'union' here?
> > What other mutually exclusive fields you plan to add here?
> >
> > > +		/**
> > > +		 * 64 bit sequence number to be used for the first packet of
> > the
> > > +		 * batch of packets.
> > > +		 */
> > > +		uint64_t sqn;
> > > +	};
> > > +};
> > > +
> > >  /**
> > >   * IPsec session specific functions that will be used to:
> > >   * - prepare - for input mbufs and given IPsec session prepare crypto ops
> > >   *   that can be enqueued into the cryptodev associated with given
> session
> > >   *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
> > > + * - prepare_stateless - similar to prepare, but further processing is done
> > > + *   based on IPsec state provided by the 'state' parameter.
> > >   * - process - finalize processing of packets after crypto-dev finished
> > >   *   with them or process packets that are subjects to inline IPsec offload
> > >   *   (see rte_ipsec_pkt_process for more details).
> > > @@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
> > >  				struct rte_mbuf *mb[],
> > >  				uint16_t num);
> > >  	} prepare;
> > > +	union {
> > > +		uint16_t (*async)(const struct rte_ipsec_session *ss,
> > > +				struct rte_mbuf *mb[],
> > > +				struct rte_crypto_op *cop[],
> > > +				uint16_t num,
> > > +				struct rte_ipsec_state *state);
> > > +		uint16_t (*sync)(const struct rte_ipsec_session *ss,
> > > +				struct rte_mbuf *mb[],
> > > +				uint16_t num,
> > > +				struct rte_ipsec_state *state);
> > > +	} prepare_stateless;
> > >  	uint16_t (*process)(const struct rte_ipsec_session *ss,
> > >  				struct rte_mbuf *mb[],
> > >  				uint16_t num);
> > > @@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct
> > rte_ipsec_session *ss,
> > >  	return ss->pkt_func.prepare.sync(ss, mb, num);  }
> > >
> > > +/**
> > > + * Same as rte_ipsec_pkt_crypto_prepare, but processing is done
> > > +based on
> > > + * IPsec state provided by the 'state' parameter. Internal IPsec
> > > +state won't
> > > + * be updated when this API is called.
> > > + *
> > > + * For input mbufs and given IPsec session prepare crypto ops that
> > > +can be
> > > + * enqueued into the cryptodev associated with given session.
> > > + * expects that for each input packet:
> > > + *      - l2_len, l3_len are setup correctly
> > > + * Note that erroneous mbufs are not freed by the function,
> > > + * but are placed beyond last valid mbuf in the *mb* array.
> > > + * It is a user responsibility to handle them further.
> > > + * @param ss
> > > + *   Pointer to the *rte_ipsec_session* object the packets belong to.
> > > + * @param mb
> > > + *   The address of an array of *num* pointers to *rte_mbuf* structures
> > > + *   which contain the input packets.
> > > + * @param cop
> > > + *   The address of an array of *num* pointers to the output
> > *rte_crypto_op*
> > > + *   structures.
> > > + * @param num
> > > + *   The maximum number of packets to process.
> > > + * @param state
> > > + *   The IPsec state to be used for processing current batch of packets.
> > > + * @return
> > > + *   Number of successfully processed packets, with error code set in
> > rte_errno.
> > > + */
> >
> > We probably need to mark new API as 'rte_experimental'.
> 
> Ack. Will update in v3.
> 
> >
> > > +static inline uint16_t
> > > +rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session
> *ss,
> > > +	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
> > > +	struct rte_ipsec_state *state)
> > > +{
> > > +	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num,
> > > +state); }
> > > +
> > > +static inline uint16_t
> > > +rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
> > > +	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > > +*state) {
> > > +	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state); }
> > > +
> > >  /**
> > >   * Finalise processing of packets after crypto-dev finished with them or
> > >   * process packets that are subjects to inline IPsec offload.
> > > diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c index
> > > 2297bd6d72..741e079831 100644
> > > --- a/lib/ipsec/sa.c
> > > +++ b/lib/ipsec/sa.c
> > > @@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct
> > rte_ipsec_sa *sa,
> > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> > >  		pf->prepare.async = esp_outb_tun_prepare;
> > > +		pf->prepare_stateless.async =
> > esp_outb_tun_prepare_stateless;
> > >  		pf->process = (sa->sqh_len != 0) ?
> > >  			esp_outb_sqh_process : pkt_flag_process;
> > >  		break;
> > > @@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct
> > rte_ipsec_sa *sa,
> > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> > >  		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
> > > +		pf->prepare_stateless.sync =
> > cpu_outb_tun_pkt_prepare_stateless;
> > >  		pf->process = (sa->sqh_len != 0) ?
> > >  			esp_outb_sqh_process : pkt_flag_process;
> > >  		break;
> > > @@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct
> > rte_ipsec_session *ss,
> > >  	int32_t rc;
> > >
> > >  	rc = 0;
> > > -	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
> > > +	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
> > >
> > >  	switch (ss->type) {
> > >  	case RTE_SECURITY_ACTION_TYPE_NONE:
> > > diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h index
> > > 719b5c735c..9b53586b2d 100644
> > > --- a/lib/ipsec/sa.h
> > > +++ b/lib/ipsec/sa.h
> > > @@ -179,6 +179,10 @@ uint16_t
> > >  esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > rte_mbuf
> > *mb[],
> > >  	struct rte_crypto_op *cop[], uint16_t num);
> > >
> > > +uint16_t
> > > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss,
> > > +struct
> > rte_mbuf *mb[],
> > > +	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state
> > > +*state);
> > > +
> > >  uint16_t
> > >  esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct
> > > rte_mbuf
> > *mb[],
> > >  	struct rte_crypto_op *cop[], uint16_t num); @@ -207,6 +211,10 @@
> > > uint16_t  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> > >  		struct rte_mbuf *mb[], uint16_t num);  uint16_t
> > > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
> > > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > > +*state);
> > > +
> > > +uint16_t
> > >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> > >  		struct rte_mbuf *mb[], uint16_t num);
> > >
> > > --
> > > 2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v2] ipsec: allow stateless IPsec processing
  2024-09-20  5:53       ` Aakash Sasidharan
@ 2024-09-25 11:59         ` Aakash Sasidharan
  0 siblings, 0 replies; 10+ messages in thread
From: Aakash Sasidharan @ 2024-09-25 11:59 UTC (permalink / raw)
  To: Konstantin Ananyev, Konstantin Ananyev, Vladimir Medvedkin
  Cc: Akhil Goyal, Jerin Jacob, Anoob Joseph, Vidya Sagar Velumuri,
	dev, Aakash Sasidharan

Realized that I missed to respond to one of your comments regarding the use of union.
Please find the comment below.

> > > > Introduce stateless packet preparation API for IPsec processing.
> > > > The new API would allow preparation of IPsec packets without
> > > > altering the internal state of an IPsec session.
> > > >
> > > > For outbound IPsec processing, the change enables user to provide
> > > > sequence number to be used for the IPsec operation.
> > >
> > > Few questions/nits below.
> > > As a generic one - we need to add a use-case/test-case for it.
> > > Without it I think the patch is incomplete.
> >
> > Ack. Will add test-case with v3.
> >
> > >
> > > >
> > > > Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
> > > > ---
> > > >  lib/ipsec/esp_outb.c  | 85
> > > > +++++++++++++++++++++++++++++++------------
> > > >  lib/ipsec/rte_ipsec.h | 68 ++++++++++++++++++++++++++++++++++
> > > >  lib/ipsec/sa.c        |  4 +-
> > > >  lib/ipsec/sa.h        |  8 ++++
> > > >  4 files changed, 140 insertions(+), 25 deletions(-)
> > > >
> > > > diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c index
> > > > ec87b1dce2..de28cb166d 100644
> > > > --- a/lib/ipsec/esp_outb.c
> > > > +++ b/lib/ipsec/esp_outb.c
> > > > @@ -288,13 +288,12 @@ outb_pkt_xprepare(const struct rte_ipsec_sa
> > > > *sa, rte_be64_t sqc,
> > > >  /*
> > > >   * setup/update packets and crypto ops for ESP outbound tunnel case.
> > > >   */
> > > > -uint16_t
> > > > -esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > > rte_mbuf
> > > *mb[],
> > > > -	struct rte_crypto_op *cop[], uint16_t num)
> > > > +static inline uint16_t
> > > > +esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss,
> > > > +struct
> > > rte_mbuf *mb[],
> > > > +	struct rte_crypto_op *cop[], uint16_t num, uint64_t sqn)
> > > >  {
> > > >  	int32_t rc;
> > > > -	uint32_t i, k, n;
> > > > -	uint64_t sqn;
> > > > +	uint32_t i, k, n = num;
> > >
> > > You can just do s/num/n/ in function parameter list, then you don't
> > > need to keep 'num' at all.
> >
> > This function will be called for normal IPsec processing. The function
> > esn_outb_update_sqn() updates the local variable n passed as parameter
> > in OVERFLOW case. If we remove the local variable n, this error path
> > would be lost and it is not our intention I believe.
> 
> Apologies. Replied too soon. I understand your suggestion and will update
> that in v3.
> 
> >
> > >
> > > >  	rte_be64_t sqc;
> > > >  	struct rte_ipsec_sa *sa;
> > > >  	struct rte_cryptodev_sym_session *cs; @@ -305,11 +304,6 @@
> > > > esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > > rte_mbuf
> > > *mb[],
> > > >  	sa = ss->sa;
> > > >  	cs = ss->crypto.ses;
> > > >
> > > > -	n = num;
> > > > -	sqn = esn_outb_update_sqn(sa, &n);
> > > > -	if (n != num)
> > > > -		rte_errno = EOVERFLOW;
> > > > -
> > > >  	k = 0;
> > > >  	for (i = 0; i != n; i++) {
> > > >
> > > > @@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct
> > > rte_ipsec_session *ss, struct rte_mbuf *mb[],
> > > >  	return k;
> > > >  }
> > > >
> > > > +uint16_t
> > > > +esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > > +rte_mbuf
> > > *mb[],
> > > > +	struct rte_crypto_op *cop[], uint16_t num) {
> > > > +	uint64_t sqn;
> > > > +	uint32_t n;
> > > > +
> > > > +	n = num;
> > > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > > +	if (n != num)
> > > > +		rte_errno = EOVERFLOW;
> > > > +
> > > > +	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn); }
> > > > +
> > > > +uint16_t
> > > > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session
> > > > +*ss, struct
> > > rte_mbuf *mb[],
> > > > +	struct rte_crypto_op *cop[], uint16_t num, struct
> > > > +rte_ipsec_state
> > > > +*state) {
> > > > +	uint64_t sqn = state->sqn;
> > > > +
> > > > +	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn); }
> > > > +
> > > >  /*
> > > >   * setup/update packet data and metadata for ESP outbound
> > > > transport
> > case.
> > > >   */
> > > > @@ -529,16 +547,15 @@ outb_cpu_crypto_prepare(const struct
> > > rte_ipsec_sa *sa, uint32_t *pofs,
> > > >  	return clen;
> > > >  }
> > > >
> > > > -static uint16_t
> > > > -cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> > > > -		struct rte_mbuf *mb[], uint16_t num,
> > > > -		esp_outb_prepare_t prepare, uint32_t cofs_mask)
> > > > +static inline uint16_t
> > > > +cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
> > > > +		struct rte_mbuf *mb[], uint16_t num, esp_outb_prepare_t
> > > prepare,
> > > > +		uint32_t cofs_mask,	uint64_t sqn)
> > > >  {
> > > >  	int32_t rc;
> > > > -	uint64_t sqn;
> > > >  	rte_be64_t sqc;
> > > >  	struct rte_ipsec_sa *sa;
> > > > -	uint32_t i, k, n;
> > > > +	uint32_t i, k, n = num;
> > >
> > > Same here, you can just use 'n' instead of 'num'.
> >
> > Same comment as above.
> >
> > >
> > > >  	uint32_t l2, l3;
> > > >  	union sym_op_data icv;
> > > >  	struct rte_crypto_va_iova_ptr iv[num]; @@ -551,11 +568,6 @@
> > > > cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
> > > >
> > > >  	sa = ss->sa;
> > > >
> > > > -	n = num;
> > > > -	sqn = esn_outb_update_sqn(sa, &n);
> > > > -	if (n != num)
> > > > -		rte_errno = EOVERFLOW;
> > > > -
> > > >  	for (i = 0, k = 0; i != n; i++) {
> > > >
> > > >  		l2 = mb[i]->l2_len;
> > > > @@ -604,15 +616,40 @@ uint16_t
> > > >  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> > > >  		struct rte_mbuf *mb[], uint16_t num)  {
> > > > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare,
> > > 0);
> > > > +	uint64_t sqn;
> > > > +	uint32_t n;
> > > > +
> > > > +	n = num;
> > > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > > +	if (n != num)
> > > > +		rte_errno = EOVERFLOW;
> > > > +
> > > > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> > > outb_tun_pkt_prepare,
> > > > +0, sqn); }
> > > > +
> > > > +uint16_t
> > > > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session
> *ss,
> > > > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > > *state)
> > > > +{
> > > > +	uint64_t sqn = state->sqn;
> > > > +
> > > > +	return cpu_outb_pkt_prepare_helper(ss, mb, num,
> > > > +outb_tun_pkt_prepare, 0, sqn);
> > > >  }
> > > >
> > > >  uint16_t
> > > >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> > > >  		struct rte_mbuf *mb[], uint16_t num)  {
> > > > -	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
> > > > -		UINT32_MAX);
> > > > +	uint64_t sqn;
> > > > +	uint32_t n;
> > > > +
> > > > +	n = num;
> > > > +	sqn = esn_outb_update_sqn(ss->sa, &n);
> > > > +	if (n != num)
> > > > +		rte_errno = EOVERFLOW;
> > > > +
> > > > +	return cpu_outb_pkt_prepare_helper(ss, mb, n,
> > > outb_trs_pkt_prepare,
> > > > +		UINT32_MAX, sqn);
> > > >  }
> > > >
> > > >  /*
> > > > diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h index
> > > > f15f6f2966..b462068203 100644
> > > > --- a/lib/ipsec/rte_ipsec.h
> > > > +++ b/lib/ipsec/rte_ipsec.h
> > > > @@ -23,11 +23,26 @@ extern "C" {
> > > >
> > > >  struct rte_ipsec_session;
> > > >
> > > > +/**
> > > > + * IPsec state for stateless processing of a batch of IPsec packets.
> > > > + */
> > > > +struct rte_ipsec_state {
> > > > +	union {
> > >
> > > Curious what is the purpose of 'union' here?
> > > What other mutually exclusive fields you plan to add here?

Our intention was to use a union to facilitate future support for the inbound path.
Would it be more appropriate to define the rte_ipsec_state itself as a union? For example:
union rte_ipsec_state {
    struct {
        uint64_t sqn;
    } outbound;
};

What do you think would be the best approach to future-proof the API?

> > >
> > > > +		/**
> > > > +		 * 64 bit sequence number to be used for the first packet of
> > > the
> > > > +		 * batch of packets.
> > > > +		 */
> > > > +		uint64_t sqn;
> > > > +	};
> > > > +};
> > > > +
> > > >  /**
> > > >   * IPsec session specific functions that will be used to:
> > > >   * - prepare - for input mbufs and given IPsec session prepare crypto ops
> > > >   *   that can be enqueued into the cryptodev associated with given
> > session
> > > >   *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
> > > > + * - prepare_stateless - similar to prepare, but further processing is done
> > > > + *   based on IPsec state provided by the 'state' parameter.
> > > >   * - process - finalize processing of packets after crypto-dev finished
> > > >   *   with them or process packets that are subjects to inline IPsec offload
> > > >   *   (see rte_ipsec_pkt_process for more details).
> > > > @@ -42,6 +57,17 @@ struct rte_ipsec_sa_pkt_func {
> > > >  				struct rte_mbuf *mb[],
> > > >  				uint16_t num);
> > > >  	} prepare;
> > > > +	union {
> > > > +		uint16_t (*async)(const struct rte_ipsec_session *ss,
> > > > +				struct rte_mbuf *mb[],
> > > > +				struct rte_crypto_op *cop[],
> > > > +				uint16_t num,
> > > > +				struct rte_ipsec_state *state);
> > > > +		uint16_t (*sync)(const struct rte_ipsec_session *ss,
> > > > +				struct rte_mbuf *mb[],
> > > > +				uint16_t num,
> > > > +				struct rte_ipsec_state *state);
> > > > +	} prepare_stateless;
> > > >  	uint16_t (*process)(const struct rte_ipsec_session *ss,
> > > >  				struct rte_mbuf *mb[],
> > > >  				uint16_t num);
> > > > @@ -128,6 +154,48 @@ rte_ipsec_pkt_cpu_prepare(const struct
> > > rte_ipsec_session *ss,
> > > >  	return ss->pkt_func.prepare.sync(ss, mb, num);  }
> > > >
> > > > +/**
> > > > + * Same as rte_ipsec_pkt_crypto_prepare, but processing is done
> > > > +based on
> > > > + * IPsec state provided by the 'state' parameter. Internal IPsec
> > > > +state won't
> > > > + * be updated when this API is called.
> > > > + *
> > > > + * For input mbufs and given IPsec session prepare crypto ops
> > > > +that can be
> > > > + * enqueued into the cryptodev associated with given session.
> > > > + * expects that for each input packet:
> > > > + *      - l2_len, l3_len are setup correctly
> > > > + * Note that erroneous mbufs are not freed by the function,
> > > > + * but are placed beyond last valid mbuf in the *mb* array.
> > > > + * It is a user responsibility to handle them further.
> > > > + * @param ss
> > > > + *   Pointer to the *rte_ipsec_session* object the packets belong to.
> > > > + * @param mb
> > > > + *   The address of an array of *num* pointers to *rte_mbuf* structures
> > > > + *   which contain the input packets.
> > > > + * @param cop
> > > > + *   The address of an array of *num* pointers to the output
> > > *rte_crypto_op*
> > > > + *   structures.
> > > > + * @param num
> > > > + *   The maximum number of packets to process.
> > > > + * @param state
> > > > + *   The IPsec state to be used for processing current batch of packets.
> > > > + * @return
> > > > + *   Number of successfully processed packets, with error code set in
> > > rte_errno.
> > > > + */
> > >
> > > We probably need to mark new API as 'rte_experimental'.
> >
> > Ack. Will update in v3.
> >
> > >
> > > > +static inline uint16_t
> > > > +rte_ipsec_pkt_crypto_prepare_stateless(const struct
> > > > +rte_ipsec_session
> > *ss,
> > > > +	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
> > > > +	struct rte_ipsec_state *state)
> > > > +{
> > > > +	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num,
> > > > +state); }
> > > > +
> > > > +static inline uint16_t
> > > > +rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
> > > > +	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > > > +*state) {
> > > > +	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
> > > > +}
> > > > +
> > > >  /**
> > > >   * Finalise processing of packets after crypto-dev finished with them or
> > > >   * process packets that are subjects to inline IPsec offload.
> > > > diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c index
> > > > 2297bd6d72..741e079831 100644
> > > > --- a/lib/ipsec/sa.c
> > > > +++ b/lib/ipsec/sa.c
> > > > @@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct
> > > rte_ipsec_sa *sa,
> > > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> > > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> > > >  		pf->prepare.async = esp_outb_tun_prepare;
> > > > +		pf->prepare_stateless.async =
> > > esp_outb_tun_prepare_stateless;
> > > >  		pf->process = (sa->sqh_len != 0) ?
> > > >  			esp_outb_sqh_process : pkt_flag_process;
> > > >  		break;
> > > > @@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct
> > > rte_ipsec_sa *sa,
> > > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
> > > >  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> > > >  		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
> > > > +		pf->prepare_stateless.sync =
> > > cpu_outb_tun_pkt_prepare_stateless;
> > > >  		pf->process = (sa->sqh_len != 0) ?
> > > >  			esp_outb_sqh_process : pkt_flag_process;
> > > >  		break;
> > > > @@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct
> > > rte_ipsec_session *ss,
> > > >  	int32_t rc;
> > > >
> > > >  	rc = 0;
> > > > -	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
> > > > +	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
> > > >
> > > >  	switch (ss->type) {
> > > >  	case RTE_SECURITY_ACTION_TYPE_NONE:
> > > > diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h index
> > > > 719b5c735c..9b53586b2d 100644
> > > > --- a/lib/ipsec/sa.h
> > > > +++ b/lib/ipsec/sa.h
> > > > @@ -179,6 +179,10 @@ uint16_t
> > > >  esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct
> > > > rte_mbuf
> > > *mb[],
> > > >  	struct rte_crypto_op *cop[], uint16_t num);
> > > >
> > > > +uint16_t
> > > > +esp_outb_tun_prepare_stateless(const struct rte_ipsec_session
> > > > +*ss, struct
> > > rte_mbuf *mb[],
> > > > +	struct rte_crypto_op *cop[], uint16_t num, struct
> > > > +rte_ipsec_state *state);
> > > > +
> > > >  uint16_t
> > > >  esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct
> > > > rte_mbuf
> > > *mb[],
> > > >  	struct rte_crypto_op *cop[], uint16_t num); @@ -207,6 +211,10 @@
> > > > uint16_t  cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
> > > >  		struct rte_mbuf *mb[], uint16_t num);  uint16_t
> > > > +cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session
> *ss,
> > > > +		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state
> > > > +*state);
> > > > +
> > > > +uint16_t
> > > >  cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
> > > >  		struct rte_mbuf *mb[], uint16_t num);
> > > >
> > > > --
> > > > 2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/2] ipsec: allow stateless IPsec processing
  2024-09-08 11:57 ` [PATCH v2] " Aakash Sasidharan
  2024-09-17 17:13   ` Konstantin Ananyev
@ 2024-10-03 13:45   ` Aakash Sasidharan
  2024-10-03 13:45     ` [PATCH v3 2/2] test/ipsec: add unit test for stateless processing Aakash Sasidharan
  2024-10-04  6:34     ` [PATCH v4 1/2] ipsec: allow stateless IPsec processing Aakash Sasidharan
  1 sibling, 2 replies; 10+ messages in thread
From: Aakash Sasidharan @ 2024-10-03 13:45 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Introduce stateless packet preparation API for IPsec
processing. The new API would allow preparation of IPsec
packets without altering the internal state of an IPsec
session.

For outbound IPsec processing, the change enables user to
provide sequence number to be used for the IPsec operation.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 doc/guides/prog_guide/ipsec_lib.rst    |   6 ++
 doc/guides/rel_notes/release_24_11.rst |   6 ++
 lib/ipsec/esp_outb.c                   | 101 +++++++++++++++++--------
 lib/ipsec/rte_ipsec.h                  |  84 ++++++++++++++++++++
 lib/ipsec/sa.c                         |   4 +-
 lib/ipsec/sa.h                         |   8 ++
 6 files changed, 176 insertions(+), 33 deletions(-)

diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst
index 0bdbdad1e4..395512f4f9 100644
--- a/doc/guides/prog_guide/ipsec_lib.rst
+++ b/doc/guides/prog_guide/ipsec_lib.rst
@@ -328,6 +328,12 @@ statistics. Per SA telemetry statistics can be enabled using
 ``rte_ipsec_telemetry_sa_add`` and disabled using
 ``rte_ipsec_telemetry_sa_del``. Note that these calls are not thread safe.
 
+Stateless IPsec packet processing support
+-----------------------------------------
+Support for stateless IPsec packet processing allowing use of custom
+sequence number to be used for IPsec outbound processing.
+rte_ipsec_pkt_stateless_prepare() takes as input the state parameter
+from the application and prepares the packet for IPsec processing.
 
 Limitations
 -----------
diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst
index 0ff70d9057..0964f13a12 100644
--- a/doc/guides/rel_notes/release_24_11.rst
+++ b/doc/guides/rel_notes/release_24_11.rst
@@ -84,6 +84,12 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+   * ipsec: Add support for stateless IPsec processing.
+
+     Added new API to support stateless IPsec processing.
+     The new API are ``rte_ipsec_pkr_crypto_prepare_stateless`` and
+     ``rte_ipsec_pkt_cpu_prepare_stateless`` .
+
 
 ABI Changes
 -----------
diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
index ec87b1dce2..617fc52b21 100644
--- a/lib/ipsec/esp_outb.c
+++ b/lib/ipsec/esp_outb.c
@@ -288,28 +288,22 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
 /*
  * setup/update packets and crypto ops for ESP outbound tunnel case.
  */
-uint16_t
-esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
-	struct rte_crypto_op *cop[], uint16_t num)
+static inline uint16_t
+esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t n, uint64_t sqn)
 {
 	int32_t rc;
-	uint32_t i, k, n;
-	uint64_t sqn;
+	uint32_t i, k;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
 	struct rte_cryptodev_sym_session *cs;
 	union sym_op_data icv;
 	uint64_t iv[IPSEC_MAX_IV_QWORD];
-	uint32_t dr[num];
+	uint32_t dr[n];
 
 	sa = ss->sa;
 	cs = ss->crypto.ses;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	k = 0;
 	for (i = 0; i != n; i++) {
 
@@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	return k;
 }
 
+uint16_t
+esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num)
+{
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn);
+}
+
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn);
+}
+
 /*
  * setup/update packet data and metadata for ESP outbound transport case.
  */
@@ -529,33 +547,27 @@ outb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, uint32_t *pofs,
 	return clen;
 }
 
-static uint16_t
-cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
-		struct rte_mbuf *mb[], uint16_t num,
-		esp_outb_prepare_t prepare, uint32_t cofs_mask)
+static inline uint16_t
+cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t n, esp_outb_prepare_t prepare,
+		uint32_t cofs_mask,	uint64_t sqn)
 {
 	int32_t rc;
-	uint64_t sqn;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
-	uint32_t i, k, n;
+	uint32_t i, k;
 	uint32_t l2, l3;
 	union sym_op_data icv;
-	struct rte_crypto_va_iova_ptr iv[num];
-	struct rte_crypto_va_iova_ptr aad[num];
-	struct rte_crypto_va_iova_ptr dgst[num];
-	uint32_t dr[num];
-	uint32_t l4ofs[num];
-	uint32_t clen[num];
-	uint64_t ivbuf[num][IPSEC_MAX_IV_QWORD];
+	struct rte_crypto_va_iova_ptr iv[n];
+	struct rte_crypto_va_iova_ptr aad[n];
+	struct rte_crypto_va_iova_ptr dgst[n];
+	uint32_t dr[n];
+	uint32_t l4ofs[n];
+	uint32_t clen[n];
+	uint64_t ivbuf[n][IPSEC_MAX_IV_QWORD];
 
 	sa = ss->sa;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	for (i = 0, k = 0; i != n; i++) {
 
 		l2 = mb[i]->l2_len;
@@ -604,15 +616,40 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare, 0);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_tun_pkt_prepare, 0, sqn);
+}
+
+uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, num, outb_tun_pkt_prepare, 0, sqn);
 }
 
 uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
-		UINT32_MAX);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_trs_pkt_prepare,
+		UINT32_MAX, sqn);
 }
 
 /*
diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h
index f15f6f2966..316ace1f19 100644
--- a/lib/ipsec/rte_ipsec.h
+++ b/lib/ipsec/rte_ipsec.h
@@ -23,11 +23,24 @@ extern "C" {
 
 struct rte_ipsec_session;
 
+/**
+ * IPsec state for stateless processing of a batch of IPsec packets.
+ */
+struct rte_ipsec_state {
+	/**
+	 * 64 bit sequence number to be used for the first packet of the
+	 * batch of packets.
+	 */
+	uint64_t sqn;
+};
+
 /**
  * IPsec session specific functions that will be used to:
  * - prepare - for input mbufs and given IPsec session prepare crypto ops
  *   that can be enqueued into the cryptodev associated with given session
  *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
+ * - prepare_stateless - similar to prepare, but further processing is done
+ *   based on IPsec state provided by the 'state' parameter.
  * - process - finalize processing of packets after crypto-dev finished
  *   with them or process packets that are subjects to inline IPsec offload
  *   (see rte_ipsec_pkt_process for more details).
@@ -42,6 +55,17 @@ struct rte_ipsec_sa_pkt_func {
 				struct rte_mbuf *mb[],
 				uint16_t num);
 	} prepare;
+	union {
+		uint16_t (*async)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				struct rte_crypto_op *cop[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+		uint16_t (*sync)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+	} prepare_stateless;
 	uint16_t (*process)(const struct rte_ipsec_session *ss,
 				struct rte_mbuf *mb[],
 				uint16_t num);
@@ -128,6 +152,66 @@ rte_ipsec_pkt_cpu_prepare(const struct rte_ipsec_session *ss,
 	return ss->pkt_func.prepare.sync(ss, mb, num);
 }
 
+/**
+ * Same as *rte_ipsec_pkt_crypto_prepare*, but processing is done based on
+ * IPsec state provided by the 'state' parameter. Internal IPsec state won't
+ * be updated when this API is called.
+ *
+ * For input mbufs and given IPsec session prepare crypto ops that can be
+ * enqueued into the cryptodev associated with given session.
+ * expects that for each input packet:
+ *      - l2_len, l3_len are setup correctly
+ * Note that erroneous mbufs are not freed by the function,
+ * but are placed beyond last valid mbuf in the *mb* array.
+ * It is a user responsibility to handle them further.
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param cop
+ *   The address of an array of *num* pointers to the output *rte_crypto_op*
+ *   structures.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+__rte_experimental
+static inline uint16_t
+rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
+	struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num, state);
+}
+
+/**
+ * Same as *rte_ipsec_pkt_crypto_prepare_stateless*, but processing is done
+ * in synchronous mode.
+ *
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+__rte_experimental
+static inline uint16_t
+rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
+}
+
 /**
  * Finalise processing of packets after crypto-dev finished with them or
  * process packets that are subjects to inline IPsec offload.
diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
index 2297bd6d72..741e079831 100644
--- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.async = esp_outb_tun_prepare;
+		pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
+		pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
 	int32_t rc;
 
 	rc = 0;
-	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
+	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
 
 	switch (ss->type) {
 	case RTE_SECURITY_ACTION_TYPE_NONE:
diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h
index 719b5c735c..9b53586b2d 100644
--- a/lib/ipsec/sa.h
+++ b/lib/ipsec/sa.h
@@ -179,6 +179,10 @@ uint16_t
 esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
 
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state);
+
 uint16_t
 esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
@@ -207,6 +211,10 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state);
+
+uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 2/2] test/ipsec: add unit test for stateless processing
  2024-10-03 13:45   ` [PATCH v3 1/2] " Aakash Sasidharan
@ 2024-10-03 13:45     ` Aakash Sasidharan
  2024-10-04  6:34     ` [PATCH v4 1/2] ipsec: allow stateless IPsec processing Aakash Sasidharan
  1 sibling, 0 replies; 10+ messages in thread
From: Aakash Sasidharan @ 2024-10-03 13:45 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Add unit test for IPsec stateless processing.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 app/test/test_ipsec.c | 111 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 98 insertions(+), 13 deletions(-)

diff --git a/app/test/test_ipsec.c b/app/test/test_ipsec.c
index 6cb1bac1e7..f65b3eedc5 100644
--- a/app/test/test_ipsec.c
+++ b/app/test/test_ipsec.c
@@ -53,6 +53,7 @@ test_ipsec(void)
 #define BURST_SIZE		32
 #define REORDER_PKTS	1
 #define DEQUEUE_COUNT	1000
+#define SQN_START		255
 
 struct user_params {
 	enum rte_crypto_sym_xform_type auth;
@@ -82,6 +83,7 @@ struct ipsec_unitest_params {
 
 	struct rte_security_ipsec_xform ipsec_xform;
 
+	struct rte_ipsec_state ipsec_state;
 	struct rte_ipsec_sa_prm sa_prm;
 	struct rte_ipsec_session ss[MAX_NB_SAS];
 
@@ -91,6 +93,7 @@ struct ipsec_unitest_params {
 		*testbuf[BURST_SIZE];
 
 	uint16_t pkt_index;
+	bool is_stateless;
 };
 
 struct ipsec_test_cfg {
@@ -773,8 +776,13 @@ crypto_ipsec(uint16_t num_pkts)
 	struct rte_ipsec_group grp[1];
 
 	/* call crypto prepare */
-	k = rte_ipsec_pkt_crypto_prepare(&ut_params->ss[0], ut_params->ibuf,
-		ut_params->cop, num_pkts);
+	if (ut_params->is_stateless && (ut_params->ipsec_state.sqn != 0))
+		k = rte_ipsec_pkt_crypto_prepare_stateless(&ut_params->ss[0],
+			ut_params->ibuf, ut_params->cop, num_pkts, &ut_params->ipsec_state);
+	else
+		k = rte_ipsec_pkt_crypto_prepare(&ut_params->ss[0], ut_params->ibuf,
+			ut_params->cop, num_pkts);
+
 	if (k != num_pkts) {
 		RTE_LOG(ERR, USER1, "rte_ipsec_pkt_crypto_prepare fail\n");
 		return TEST_FAILED;
@@ -1322,7 +1330,28 @@ crypto_outb_burst_null_null_check(struct ipsec_unitest_params *ut_params,
 }
 
 static int
-test_ipsec_crypto_outb_burst_null_null(int i)
+test_ipsec_verify_sqn(struct ipsec_unitest_params *ut_params,
+		uint16_t num_pkts, uint32_t sqn_start)
+{
+	struct rte_esp_hdr esph;
+	uint8_t *obuf_data;
+	uint32_t sqn;
+	uint16_t j;
+
+	for (j = 0; j < num_pkts; j++) {
+		obuf_data = rte_pktmbuf_mtod(ut_params->obuf[j], void *);
+
+		memcpy(&esph, obuf_data + sizeof(ipv4_outer), sizeof(esph));
+		sqn = rte_be_to_cpu_32(esph.seq);
+		TEST_ASSERT_EQUAL(sqn, sqn_start + j,
+			"Invalid sequence number in packet %u\n", j);
+	}
+
+	return 0;
+}
+
+static int
+test_ipsec_crypto_outb_single_burst_null_null(int i, uint32_t sqn_start)
 {
 	struct ipsec_testsuite_params *ts_params = &testsuite_params;
 	struct ipsec_unitest_params *ut_params = &unittest_params;
@@ -1330,15 +1359,6 @@ test_ipsec_crypto_outb_burst_null_null(int i)
 	uint16_t j;
 	int32_t rc;
 
-	/* create rte_ipsec_sa*/
-	rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE,
-			test_cfg[i].replay_win_sz, test_cfg[i].flags, 0);
-	if (rc != 0) {
-		RTE_LOG(ERR, USER1, "create_sa failed, cfg %d\n", i);
-		return rc;
-	}
-
-	/* Generate input mbuf data */
 	for (j = 0; j < num_pkts && rc == 0; j++) {
 		ut_params->ibuf[j] = setup_test_string(ts_params->mbuf_pool,
 			null_plain_data, sizeof(null_plain_data),
@@ -1351,7 +1371,7 @@ test_ipsec_crypto_outb_burst_null_null(int i)
 			ut_params->testbuf[j] = setup_test_string_tunneled(
 					ts_params->mbuf_pool,
 					null_plain_data, test_cfg[i].pkt_sz,
-					OUTBOUND_SPI, j + 1);
+					OUTBOUND_SPI, j + sqn_start);
 			if (ut_params->testbuf[j] == NULL)
 				rc = TEST_FAILED;
 		}
@@ -1374,10 +1394,73 @@ test_ipsec_crypto_outb_burst_null_null(int i)
 	if (rc == TEST_FAILED)
 		test_ipsec_dump_buffers(ut_params, i);
 
+	test_ipsec_verify_sqn(ut_params, num_pkts, sqn_start);
+
+	return rc;
+}
+
+static int
+test_ipsec_crypto_outb_burst_null_null(int i)
+{
+	struct ipsec_unitest_params *ut_params = &unittest_params;
+	uint32_t sqn_start;
+	int32_t rc;
+
+	/* create rte_ipsec_sa*/
+	rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE,
+			test_cfg[i].replay_win_sz, test_cfg[i].flags, 0);
+	if (rc != 0) {
+		RTE_LOG(ERR, USER1, "create_sa failed, cfg %d\n", i);
+		return rc;
+	}
+
+	/* Generate input mbuf data and test normal IPsec processing */
+	sqn_start = 1;
+	rc = test_ipsec_crypto_outb_single_burst_null_null(i, sqn_start);
+	if (rc != 0) {
+		RTE_LOG(ERR, USER1, "burst failed, cfg %d\n", i);
+		return rc;
+	}
+
+	if (ut_params->is_stateless) {
+
+		/* Generate input mbuf data for stateless IPsec processing. */
+		sqn_start = ut_params->ipsec_state.sqn = SQN_START;
+		rc = test_ipsec_crypto_outb_single_burst_null_null(i, sqn_start);
+		if (rc != 0) {
+			RTE_LOG(ERR, USER1, "stateless burst failed, cfg %d\n", i);
+			return rc;
+		}
+	}
+
 	destroy_sa(0);
 	return rc;
 }
 
+static int
+test_ipsec_crypto_outb_burst_stateless_null_null_wrapper(void)
+{
+	struct ipsec_unitest_params *ut_params = &unittest_params;
+	int rc = 0;
+	int i;
+
+	ut_params->ipsec_xform.spi = OUTBOUND_SPI;
+	ut_params->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
+	ut_params->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+	ut_params->ipsec_xform.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+	ut_params->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;
+	ut_params->is_stateless = true;
+
+	for (i = 0; i < num_cfg && rc == 0; i++) {
+		ut_params->ipsec_xform.options.esn = test_cfg[i].esn;
+		ut_params->ipsec_state.sqn = 0;
+		rc = test_ipsec_crypto_outb_burst_null_null(i);
+
+	}
+
+	return rc;
+}
+
 static int
 test_ipsec_crypto_outb_burst_null_null_wrapper(void)
 {
@@ -2496,6 +2579,8 @@ static struct unit_test_suite ipsec_testsuite  = {
 			test_ipsec_crypto_inb_burst_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
 			test_ipsec_crypto_outb_burst_null_null_wrapper),
+		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
+			test_ipsec_crypto_outb_burst_stateless_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
 			test_ipsec_inline_crypto_inb_burst_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4 1/2] ipsec: allow stateless IPsec processing
  2024-10-03 13:45   ` [PATCH v3 1/2] " Aakash Sasidharan
  2024-10-03 13:45     ` [PATCH v3 2/2] test/ipsec: add unit test for stateless processing Aakash Sasidharan
@ 2024-10-04  6:34     ` Aakash Sasidharan
  2024-10-04  6:34       ` [PATCH v4 2/2] test/ipsec: add unit test for stateless processing Aakash Sasidharan
  1 sibling, 1 reply; 10+ messages in thread
From: Aakash Sasidharan @ 2024-10-04  6:34 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Introduce stateless packet preparation API for IPsec
processing. The new API would allow preparation of IPsec
packets without altering the internal state of an IPsec
session.

For outbound IPsec processing, the change enables user to
provide sequence number to be used for the IPsec operation.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 doc/guides/prog_guide/ipsec_lib.rst    |   6 ++
 doc/guides/rel_notes/release_24_11.rst |   6 ++
 lib/ipsec/esp_outb.c                   | 101 +++++++++++++++++--------
 lib/ipsec/rte_ipsec.h                  |  84 ++++++++++++++++++++
 lib/ipsec/sa.c                         |   4 +-
 lib/ipsec/sa.h                         |   8 ++
 6 files changed, 176 insertions(+), 33 deletions(-)

diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst
index 0bdbdad1e4..395512f4f9 100644
--- a/doc/guides/prog_guide/ipsec_lib.rst
+++ b/doc/guides/prog_guide/ipsec_lib.rst
@@ -328,6 +328,12 @@ statistics. Per SA telemetry statistics can be enabled using
 ``rte_ipsec_telemetry_sa_add`` and disabled using
 ``rte_ipsec_telemetry_sa_del``. Note that these calls are not thread safe.
 
+Stateless IPsec packet processing support
+-----------------------------------------
+Support for stateless IPsec packet processing allowing use of custom
+sequence number to be used for IPsec outbound processing.
+rte_ipsec_pkt_stateless_prepare() takes as input the state parameter
+from the application and prepares the packet for IPsec processing.
 
 Limitations
 -----------
diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst
index 0ff70d9057..0964f13a12 100644
--- a/doc/guides/rel_notes/release_24_11.rst
+++ b/doc/guides/rel_notes/release_24_11.rst
@@ -84,6 +84,12 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+   * ipsec: Add support for stateless IPsec processing.
+
+     Added new API to support stateless IPsec processing.
+     The new API are ``rte_ipsec_pkr_crypto_prepare_stateless`` and
+     ``rte_ipsec_pkt_cpu_prepare_stateless`` .
+
 
 ABI Changes
 -----------
diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
index ec87b1dce2..617fc52b21 100644
--- a/lib/ipsec/esp_outb.c
+++ b/lib/ipsec/esp_outb.c
@@ -288,28 +288,22 @@ outb_pkt_xprepare(const struct rte_ipsec_sa *sa, rte_be64_t sqc,
 /*
  * setup/update packets and crypto ops for ESP outbound tunnel case.
  */
-uint16_t
-esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
-	struct rte_crypto_op *cop[], uint16_t num)
+static inline uint16_t
+esp_outb_tun_prepare_helper(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t n, uint64_t sqn)
 {
 	int32_t rc;
-	uint32_t i, k, n;
-	uint64_t sqn;
+	uint32_t i, k;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
 	struct rte_cryptodev_sym_session *cs;
 	union sym_op_data icv;
 	uint64_t iv[IPSEC_MAX_IV_QWORD];
-	uint32_t dr[num];
+	uint32_t dr[n];
 
 	sa = ss->sa;
 	cs = ss->crypto.ses;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	k = 0;
 	for (i = 0; i != n; i++) {
 
@@ -339,6 +333,30 @@ esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	return k;
 }
 
+uint16_t
+esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num)
+{
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, n, sqn);
+}
+
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return esp_outb_tun_prepare_helper(ss, mb, cop, num, sqn);
+}
+
 /*
  * setup/update packet data and metadata for ESP outbound transport case.
  */
@@ -529,33 +547,27 @@ outb_cpu_crypto_prepare(const struct rte_ipsec_sa *sa, uint32_t *pofs,
 	return clen;
 }
 
-static uint16_t
-cpu_outb_pkt_prepare(const struct rte_ipsec_session *ss,
-		struct rte_mbuf *mb[], uint16_t num,
-		esp_outb_prepare_t prepare, uint32_t cofs_mask)
+static inline uint16_t
+cpu_outb_pkt_prepare_helper(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t n, esp_outb_prepare_t prepare,
+		uint32_t cofs_mask,	uint64_t sqn)
 {
 	int32_t rc;
-	uint64_t sqn;
 	rte_be64_t sqc;
 	struct rte_ipsec_sa *sa;
-	uint32_t i, k, n;
+	uint32_t i, k;
 	uint32_t l2, l3;
 	union sym_op_data icv;
-	struct rte_crypto_va_iova_ptr iv[num];
-	struct rte_crypto_va_iova_ptr aad[num];
-	struct rte_crypto_va_iova_ptr dgst[num];
-	uint32_t dr[num];
-	uint32_t l4ofs[num];
-	uint32_t clen[num];
-	uint64_t ivbuf[num][IPSEC_MAX_IV_QWORD];
+	struct rte_crypto_va_iova_ptr iv[n];
+	struct rte_crypto_va_iova_ptr aad[n];
+	struct rte_crypto_va_iova_ptr dgst[n];
+	uint32_t dr[n];
+	uint32_t l4ofs[n];
+	uint32_t clen[n];
+	uint64_t ivbuf[n][IPSEC_MAX_IV_QWORD];
 
 	sa = ss->sa;
 
-	n = num;
-	sqn = esn_outb_update_sqn(sa, &n);
-	if (n != num)
-		rte_errno = EOVERFLOW;
-
 	for (i = 0, k = 0; i != n; i++) {
 
 		l2 = mb[i]->l2_len;
@@ -604,15 +616,40 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_tun_pkt_prepare, 0);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_tun_pkt_prepare, 0, sqn);
+}
+
+uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	uint64_t sqn = state->sqn;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, num, outb_tun_pkt_prepare, 0, sqn);
 }
 
 uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num)
 {
-	return cpu_outb_pkt_prepare(ss, mb, num, outb_trs_pkt_prepare,
-		UINT32_MAX);
+	uint64_t sqn;
+	uint32_t n;
+
+	n = num;
+	sqn = esn_outb_update_sqn(ss->sa, &n);
+	if (n != num)
+		rte_errno = EOVERFLOW;
+
+	return cpu_outb_pkt_prepare_helper(ss, mb, n, outb_trs_pkt_prepare,
+		UINT32_MAX, sqn);
 }
 
 /*
diff --git a/lib/ipsec/rte_ipsec.h b/lib/ipsec/rte_ipsec.h
index f15f6f2966..316ace1f19 100644
--- a/lib/ipsec/rte_ipsec.h
+++ b/lib/ipsec/rte_ipsec.h
@@ -23,11 +23,24 @@ extern "C" {
 
 struct rte_ipsec_session;
 
+/**
+ * IPsec state for stateless processing of a batch of IPsec packets.
+ */
+struct rte_ipsec_state {
+	/**
+	 * 64 bit sequence number to be used for the first packet of the
+	 * batch of packets.
+	 */
+	uint64_t sqn;
+};
+
 /**
  * IPsec session specific functions that will be used to:
  * - prepare - for input mbufs and given IPsec session prepare crypto ops
  *   that can be enqueued into the cryptodev associated with given session
  *   (see *rte_ipsec_pkt_crypto_prepare* below for more details).
+ * - prepare_stateless - similar to prepare, but further processing is done
+ *   based on IPsec state provided by the 'state' parameter.
  * - process - finalize processing of packets after crypto-dev finished
  *   with them or process packets that are subjects to inline IPsec offload
  *   (see rte_ipsec_pkt_process for more details).
@@ -42,6 +55,17 @@ struct rte_ipsec_sa_pkt_func {
 				struct rte_mbuf *mb[],
 				uint16_t num);
 	} prepare;
+	union {
+		uint16_t (*async)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				struct rte_crypto_op *cop[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+		uint16_t (*sync)(const struct rte_ipsec_session *ss,
+				struct rte_mbuf *mb[],
+				uint16_t num,
+				struct rte_ipsec_state *state);
+	} prepare_stateless;
 	uint16_t (*process)(const struct rte_ipsec_session *ss,
 				struct rte_mbuf *mb[],
 				uint16_t num);
@@ -128,6 +152,66 @@ rte_ipsec_pkt_cpu_prepare(const struct rte_ipsec_session *ss,
 	return ss->pkt_func.prepare.sync(ss, mb, num);
 }
 
+/**
+ * Same as *rte_ipsec_pkt_crypto_prepare*, but processing is done based on
+ * IPsec state provided by the 'state' parameter. Internal IPsec state won't
+ * be updated when this API is called.
+ *
+ * For input mbufs and given IPsec session prepare crypto ops that can be
+ * enqueued into the cryptodev associated with given session.
+ * expects that for each input packet:
+ *      - l2_len, l3_len are setup correctly
+ * Note that erroneous mbufs are not freed by the function,
+ * but are placed beyond last valid mbuf in the *mb* array.
+ * It is a user responsibility to handle them further.
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param cop
+ *   The address of an array of *num* pointers to the output *rte_crypto_op*
+ *   structures.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+__rte_experimental
+static inline uint16_t
+rte_ipsec_pkt_crypto_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num,
+	struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.async(ss, mb, cop, num, state);
+}
+
+/**
+ * Same as *rte_ipsec_pkt_crypto_prepare_stateless*, but processing is done
+ * in synchronous mode.
+ *
+ * @param ss
+ *   Pointer to the *rte_ipsec_session* object the packets belong to.
+ * @param mb
+ *   The address of an array of *num* pointers to *rte_mbuf* structures
+ *   which contain the input packets.
+ * @param num
+ *   The maximum number of packets to process.
+ * @param state
+ *   The IPsec state to be used for processing current batch of packets.
+ * @return
+ *   Number of successfully processed packets, with error code set in rte_errno.
+ */
+__rte_experimental
+static inline uint16_t
+rte_ipsec_pkt_cpu_prepare_stateless(const struct rte_ipsec_session *ss,
+	struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state)
+{
+	return ss->pkt_func.prepare_stateless.sync(ss, mb, num, state);
+}
+
 /**
  * Finalise processing of packets after crypto-dev finished with them or
  * process packets that are subjects to inline IPsec offload.
diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
index 2297bd6d72..741e079831 100644
--- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -710,6 +710,7 @@ lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.async = esp_outb_tun_prepare;
+		pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -748,6 +749,7 @@ cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
 		pf->prepare.sync = cpu_outb_tun_pkt_prepare;
+		pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
 		pf->process = (sa->sqh_len != 0) ?
 			esp_outb_sqh_process : pkt_flag_process;
 		break;
@@ -810,7 +812,7 @@ ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
 	int32_t rc;
 
 	rc = 0;
-	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, NULL };
+	pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
 
 	switch (ss->type) {
 	case RTE_SECURITY_ACTION_TYPE_NONE:
diff --git a/lib/ipsec/sa.h b/lib/ipsec/sa.h
index 719b5c735c..9b53586b2d 100644
--- a/lib/ipsec/sa.h
+++ b/lib/ipsec/sa.h
@@ -179,6 +179,10 @@ uint16_t
 esp_outb_tun_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
 
+uint16_t
+esp_outb_tun_prepare_stateless(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
+	struct rte_crypto_op *cop[], uint16_t num, struct rte_ipsec_state *state);
+
 uint16_t
 esp_outb_trs_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
 	struct rte_crypto_op *cop[], uint16_t num);
@@ -207,6 +211,10 @@ uint16_t
 cpu_outb_tun_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 uint16_t
+cpu_outb_tun_pkt_prepare_stateless(const struct rte_ipsec_session *ss,
+		struct rte_mbuf *mb[], uint16_t num, struct rte_ipsec_state *state);
+
+uint16_t
 cpu_outb_trs_pkt_prepare(const struct rte_ipsec_session *ss,
 		struct rte_mbuf *mb[], uint16_t num);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4 2/2] test/ipsec: add unit test for stateless processing
  2024-10-04  6:34     ` [PATCH v4 1/2] ipsec: allow stateless IPsec processing Aakash Sasidharan
@ 2024-10-04  6:34       ` Aakash Sasidharan
  0 siblings, 0 replies; 10+ messages in thread
From: Aakash Sasidharan @ 2024-10-04  6:34 UTC (permalink / raw)
  To: Konstantin Ananyev, Vladimir Medvedkin
  Cc: gakhil, jerinj, anoobj, vvelumuri, asasidharan, dev

Add unit test for IPsec stateless processing.

Signed-off-by: Aakash Sasidharan <asasidharan@marvell.com>
---
 app/test/test_ipsec.c | 113 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 99 insertions(+), 14 deletions(-)

diff --git a/app/test/test_ipsec.c b/app/test/test_ipsec.c
index 6cb1bac1e7..ac63c3b6d3 100644
--- a/app/test/test_ipsec.c
+++ b/app/test/test_ipsec.c
@@ -53,6 +53,7 @@ test_ipsec(void)
 #define BURST_SIZE		32
 #define REORDER_PKTS	1
 #define DEQUEUE_COUNT	1000
+#define SQN_START		255
 
 struct user_params {
 	enum rte_crypto_sym_xform_type auth;
@@ -82,6 +83,7 @@ struct ipsec_unitest_params {
 
 	struct rte_security_ipsec_xform ipsec_xform;
 
+	struct rte_ipsec_state ipsec_state;
 	struct rte_ipsec_sa_prm sa_prm;
 	struct rte_ipsec_session ss[MAX_NB_SAS];
 
@@ -91,6 +93,7 @@ struct ipsec_unitest_params {
 		*testbuf[BURST_SIZE];
 
 	uint16_t pkt_index;
+	bool is_stateless;
 };
 
 struct ipsec_test_cfg {
@@ -773,8 +776,13 @@ crypto_ipsec(uint16_t num_pkts)
 	struct rte_ipsec_group grp[1];
 
 	/* call crypto prepare */
-	k = rte_ipsec_pkt_crypto_prepare(&ut_params->ss[0], ut_params->ibuf,
-		ut_params->cop, num_pkts);
+	if (ut_params->is_stateless && (ut_params->ipsec_state.sqn != 0))
+		k = rte_ipsec_pkt_crypto_prepare_stateless(&ut_params->ss[0],
+			ut_params->ibuf, ut_params->cop, num_pkts, &ut_params->ipsec_state);
+	else
+		k = rte_ipsec_pkt_crypto_prepare(&ut_params->ss[0], ut_params->ibuf,
+			ut_params->cop, num_pkts);
+
 	if (k != num_pkts) {
 		RTE_LOG(ERR, USER1, "rte_ipsec_pkt_crypto_prepare fail\n");
 		return TEST_FAILED;
@@ -1322,23 +1330,35 @@ crypto_outb_burst_null_null_check(struct ipsec_unitest_params *ut_params,
 }
 
 static int
-test_ipsec_crypto_outb_burst_null_null(int i)
+test_ipsec_verify_sqn(struct ipsec_unitest_params *ut_params,
+		uint16_t num_pkts, uint32_t sqn_start)
+{
+	struct rte_esp_hdr esph;
+	uint8_t *obuf_data;
+	uint32_t sqn;
+	uint16_t j;
+
+	for (j = 0; j < num_pkts; j++) {
+		obuf_data = rte_pktmbuf_mtod(ut_params->obuf[j], void *);
+
+		memcpy(&esph, obuf_data + sizeof(ipv4_outer), sizeof(esph));
+		sqn = rte_be_to_cpu_32(esph.seq);
+		TEST_ASSERT_EQUAL(sqn, sqn_start + j,
+			"Invalid sequence number in packet %u\n", j);
+	}
+
+	return 0;
+}
+
+static int
+test_ipsec_crypto_outb_single_burst_null_null(int i, uint32_t sqn_start)
 {
 	struct ipsec_testsuite_params *ts_params = &testsuite_params;
 	struct ipsec_unitest_params *ut_params = &unittest_params;
 	uint16_t num_pkts = test_cfg[i].num_pkts;
 	uint16_t j;
-	int32_t rc;
-
-	/* create rte_ipsec_sa*/
-	rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE,
-			test_cfg[i].replay_win_sz, test_cfg[i].flags, 0);
-	if (rc != 0) {
-		RTE_LOG(ERR, USER1, "create_sa failed, cfg %d\n", i);
-		return rc;
-	}
+	int rc = 0;
 
-	/* Generate input mbuf data */
 	for (j = 0; j < num_pkts && rc == 0; j++) {
 		ut_params->ibuf[j] = setup_test_string(ts_params->mbuf_pool,
 			null_plain_data, sizeof(null_plain_data),
@@ -1351,7 +1371,7 @@ test_ipsec_crypto_outb_burst_null_null(int i)
 			ut_params->testbuf[j] = setup_test_string_tunneled(
 					ts_params->mbuf_pool,
 					null_plain_data, test_cfg[i].pkt_sz,
-					OUTBOUND_SPI, j + 1);
+					OUTBOUND_SPI, j + sqn_start);
 			if (ut_params->testbuf[j] == NULL)
 				rc = TEST_FAILED;
 		}
@@ -1374,10 +1394,73 @@ test_ipsec_crypto_outb_burst_null_null(int i)
 	if (rc == TEST_FAILED)
 		test_ipsec_dump_buffers(ut_params, i);
 
+	test_ipsec_verify_sqn(ut_params, num_pkts, sqn_start);
+
+	return rc;
+}
+
+static int
+test_ipsec_crypto_outb_burst_null_null(int i)
+{
+	struct ipsec_unitest_params *ut_params = &unittest_params;
+	uint32_t sqn_start;
+	int32_t rc;
+
+	/* create rte_ipsec_sa*/
+	rc = create_sa(RTE_SECURITY_ACTION_TYPE_NONE,
+			test_cfg[i].replay_win_sz, test_cfg[i].flags, 0);
+	if (rc != 0) {
+		RTE_LOG(ERR, USER1, "create_sa failed, cfg %d\n", i);
+		return rc;
+	}
+
+	/* Generate input mbuf data and test normal IPsec processing */
+	sqn_start = 1;
+	rc = test_ipsec_crypto_outb_single_burst_null_null(i, sqn_start);
+	if (rc != 0) {
+		RTE_LOG(ERR, USER1, "burst failed, cfg %d\n", i);
+		return rc;
+	}
+
+	if (ut_params->is_stateless) {
+
+		/* Generate input mbuf data for stateless IPsec processing. */
+		sqn_start = ut_params->ipsec_state.sqn = SQN_START;
+		rc = test_ipsec_crypto_outb_single_burst_null_null(i, sqn_start);
+		if (rc != 0) {
+			RTE_LOG(ERR, USER1, "stateless burst failed, cfg %d\n", i);
+			return rc;
+		}
+	}
+
 	destroy_sa(0);
 	return rc;
 }
 
+static int
+test_ipsec_crypto_outb_burst_stateless_null_null_wrapper(void)
+{
+	struct ipsec_unitest_params *ut_params = &unittest_params;
+	int rc = 0;
+	int i;
+
+	ut_params->ipsec_xform.spi = OUTBOUND_SPI;
+	ut_params->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
+	ut_params->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+	ut_params->ipsec_xform.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+	ut_params->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;
+	ut_params->is_stateless = true;
+
+	for (i = 0; i < num_cfg && rc == 0; i++) {
+		ut_params->ipsec_xform.options.esn = test_cfg[i].esn;
+		ut_params->ipsec_state.sqn = 0;
+		rc = test_ipsec_crypto_outb_burst_null_null(i);
+
+	}
+
+	return rc;
+}
+
 static int
 test_ipsec_crypto_outb_burst_null_null_wrapper(void)
 {
@@ -2496,6 +2579,8 @@ static struct unit_test_suite ipsec_testsuite  = {
 			test_ipsec_crypto_inb_burst_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
 			test_ipsec_crypto_outb_burst_null_null_wrapper),
+		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
+			test_ipsec_crypto_outb_burst_stateless_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
 			test_ipsec_inline_crypto_inb_burst_null_null_wrapper),
 		TEST_CASE_ST(ut_setup_ipsec, ut_teardown_ipsec,
-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2024-10-04  6:34 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-09-07 10:25 [PATCH] ipsec: allow stateless IPsec processing Aakash Sasidharan
2024-09-08 11:57 ` [PATCH v2] " Aakash Sasidharan
2024-09-17 17:13   ` Konstantin Ananyev
2024-09-20  2:12     ` Aakash Sasidharan
2024-09-20  5:53       ` Aakash Sasidharan
2024-09-25 11:59         ` Aakash Sasidharan
2024-10-03 13:45   ` [PATCH v3 1/2] " Aakash Sasidharan
2024-10-03 13:45     ` [PATCH v3 2/2] test/ipsec: add unit test for stateless processing Aakash Sasidharan
2024-10-04  6:34     ` [PATCH v4 1/2] ipsec: allow stateless IPsec processing Aakash Sasidharan
2024-10-04  6:34       ` [PATCH v4 2/2] test/ipsec: add unit test for stateless processing Aakash Sasidharan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).