DPDK patches and discussions
 help / color / mirror / Atom feed
From: Konstantin Ananyev <konstantin.ananyev@huawei.com>
To: Aakash Sasidharan <asasidharan@marvell.com>,
	Konstantin Ananyev <konstantin.v.ananyev@yandex.ru>,
	Vladimir Medvedkin <vladimir.medvedkin@intel.com>
Cc: "gakhil@marvell.com" <gakhil@marvell.com>,
	"jerinj@marvell.com" <jerinj@marvell.com>,
	"anoobj@marvell.com" <anoobj@marvell.com>,
	"vvelumuri@marvell.com" <vvelumuri@marvell.com>,
	"dev@dpdk.org" <dev@dpdk.org>
Subject: RE: [PATCH v2] ipsec: allow stateless IPsec processing
Date: Tue, 17 Sep 2024 17:13:01 +0000	[thread overview]
Message-ID: <692b6f6259a0429bae57826d3ec08dc8@huawei.com> (raw)
In-Reply-To: <20240908115733.2708942-1-asasidharan@marvell.com>



> 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


      reply	other threads:[~2024-09-17 17:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-07 10:25 [PATCH] " Aakash Sasidharan
2024-09-08 11:57 ` [PATCH v2] " Aakash Sasidharan
2024-09-17 17:13   ` Konstantin Ananyev [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=692b6f6259a0429bae57826d3ec08dc8@huawei.com \
    --to=konstantin.ananyev@huawei.com \
    --cc=anoobj@marvell.com \
    --cc=asasidharan@marvell.com \
    --cc=dev@dpdk.org \
    --cc=gakhil@marvell.com \
    --cc=jerinj@marvell.com \
    --cc=konstantin.v.ananyev@yandex.ru \
    --cc=vladimir.medvedkin@intel.com \
    --cc=vvelumuri@marvell.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).