diff mbox

[RFC] api: crypto: Move completion event allocation to implementation

Message ID 1417783375-9704-1-git-send-email-taras.kondratiuk@linaro.org
State New
Headers show

Commit Message

Taras Kondratiuk Dec. 5, 2014, 12:42 p.m. UTC
Some implementations may not need a separate buffer for completion
event but can reuse packet for this. Make it possible for implementation
to decide this by passing completion event as pointer to
odp_crypto_operation(). In synchronous mode implementation will return
completion event at that pointer. In asynchronous - ODP_BUFFER_INVALID.

This patch doesn't cover CUnit tests.

Signed-off-by: Taras Kondratiuk <taras.kondratiuk@linaro.org>
---
 example/ipsec/odp_ipsec.c                       |  106 ++++++++++++++---------
 platform/linux-generic/include/api/odp_crypto.h |   34 +++++---
 platform/linux-generic/odp_crypto.c             |   30 ++++---
 3 files changed, 101 insertions(+), 69 deletions(-)

Comments

Alexandru Badicioiu Dec. 5, 2014, 2:16 p.m. UTC | #1
Hi ,
what this patch wants to accomplish can be done with the actual API this
way : if the implementation really cannot reuse the input packet as the
completion event (are there implementations which cannot?) it can return an
error and the application could allocate a separate completion event:
There is a little overhead with the first assignment and with the failed
crypto operation in case of platforms which do not support reusing the
packet but the API doesn't need to be modified (only adding a new error
code).

odp_buffer_t compl = odp_packet_to_buffer(op_params.pkt);
rc = odp_crypto_operation(&op_params, &posted, compl);
if (odp_unlikely(ODP_CRYPTO_INVALID_COMPL_EVENT == rc)) {
      compl = odp_buffer_alloc();
      rc = odp_crypto_operation(&op_params, &posted, compl);
}

Alex




On 5 December 2014 at 14:42, Taras Kondratiuk <taras.kondratiuk@linaro.org>
wrote:

> Some implementations may not need a separate buffer for completion
> event but can reuse packet for this. Make it possible for implementation
> to decide this by passing completion event as pointer to
> odp_crypto_operation(). In synchronous mode implementation will return
> completion event at that pointer. In asynchronous - ODP_BUFFER_INVALID.
>
> This patch doesn't cover CUnit tests.
>
> Signed-off-by: Taras Kondratiuk <taras.kondratiuk@linaro.org>
> ---
>  example/ipsec/odp_ipsec.c                       |  106
> ++++++++++++++---------
>  platform/linux-generic/include/api/odp_crypto.h |   34 +++++---
>  platform/linux-generic/odp_crypto.c             |   30 ++++---
>  3 files changed, 101 insertions(+), 69 deletions(-)
>
> diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
> index 76d27c5..c25f631 100644
> --- a/example/ipsec/odp_ipsec.c
> +++ b/example/ipsec/odp_ipsec.c
> @@ -209,6 +209,33 @@ void free_pkt_ctx(pkt_ctx_t *ctx)
>  }
>
>  /**
> + * Convert completion event to completed operation packet
> + *
> + * @note Function frees completion event.
> + *
> + * @param completion  Event containing operation results
> + *
> + * @return Packet structure where data now resides or ODP_PACKET_INVALID
> + *         in case of any operation error.
> + */
> +static
> +odp_packet_t crypto_completion_to_packet(odp_buffer_t completion)
> +{
> +       odp_crypto_compl_status_t cipher_rc;
> +       odp_crypto_compl_status_t auth_rc;
> +       odp_packet_t pkt;
> +
> +       odp_crypto_get_operation_compl_status(completion, &cipher_rc,
> &auth_rc);
> +       if (!is_crypto_compl_status_ok(&cipher_rc))
> +               return ODP_PACKET_INVALID;
> +       if (!is_crypto_compl_status_ok(&auth_rc))
> +               return ODP_PACKET_INVALID;
> +       pkt = odp_crypto_get_operation_compl_packet(completion);
> +       odp_crypto_operation_compl_free(completion);
> +       return pkt;
> +}
> +
> +/**
>   * Use socket I/O workaround to query interface MAC address
>   *
>   * @todo Remove all references to USE_MAC_ADDR_HACK once
> @@ -677,18 +704,18 @@ pkt_disposition_e do_route_fwd_db(odp_packet_t pkt,
> pkt_ctx_t *ctx)
>   * @return PKT_CONTINUE if done else PKT_POSTED
>   */
>  static
> -pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
> +pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt,
>                                        pkt_ctx_t *ctx,
>                                        bool *skip)
>  {
> -       uint8_t *buf = odp_packet_addr(pkt);
> -       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
> +       uint8_t *buf = odp_packet_addr(*pkt);
> +       odp_buffer_t completion = ODP_BUFFER_INVALID;
> +       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(*pkt);
>         int hdr_len;
>         odph_ahhdr_t *ah = NULL;
>         odph_esphdr_t *esp = NULL;
>         ipsec_cache_entry_t *entry;
>         odp_crypto_op_params_t params;
> -       bool posted = 0;
>
>         /* Default to skip IPsec */
>         *skip = TRUE;
> @@ -710,8 +737,8 @@ pkt_disposition_e do_ipsec_in_classify(odp_packet_t
> pkt,
>         /* Initialize parameters block */
>         memset(&params, 0, sizeof(params));
>         params.session = entry->state.session;
> -       params.pkt = pkt;
> -       params.out_pkt = entry->in_place ? pkt : ODP_PACKET_INVALID;
> +       params.pkt = *pkt;
> +       params.out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID;
>
>         /*Save everything to context */
>         ctx->ipsec.ip_tos = ip->tos;
> @@ -743,12 +770,16 @@ pkt_disposition_e do_ipsec_in_classify(odp_packet_t
> pkt,
>
>         /* Issue crypto request */
>         *skip = FALSE;
> -       if (odp_crypto_operation(&params,
> -                                &posted,
> -                                odp_packet_to_buffer(pkt))) {
> +       if (odp_crypto_operation(&params, &completion))
>                 abort();
> -       }
> -       return (posted) ? PKT_POSTED : PKT_CONTINUE;
> +       if (completion == ODP_BUFFER_INVALID)
> +               return PKT_POSTED;
> +
> +       *pkt = crypto_completion_to_packet(completion);
> +       if (*pkt != ODP_PACKET_INVALID)
> +               return PKT_CONTINUE;
> +
> +       return PKT_DROP;
>  }
>
>  /**
> @@ -763,20 +794,10 @@ static
>  pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt,
>                                      pkt_ctx_t *ctx)
>  {
> -       odp_buffer_t event;
> -       odp_crypto_compl_status_t cipher_rc;
> -       odp_crypto_compl_status_t auth_rc;
>         odph_ipv4hdr_t *ip;
>         int hdr_len = ctx->ipsec.hdr_len;
>         int trl_len = 0;
>
> -       /* Check crypto result */
> -       event = odp_packet_to_buffer(pkt);
> -       odp_crypto_get_operation_compl_status(event, &cipher_rc, &auth_rc);
> -       if (!is_crypto_compl_status_ok(&cipher_rc))
> -               return PKT_DROP;
> -       if (!is_crypto_compl_status_ok(&auth_rc))
> -               return PKT_DROP;
>         ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
>
>         /*
> @@ -956,11 +977,11 @@ pkt_disposition_e do_ipsec_out_classify(odp_packet_t
> pkt,
>   * @return PKT_CONTINUE if done else PKT_POSTED
>   */
>  static
> -pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
> +pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt,
>                                    pkt_ctx_t *ctx)
>  {
> -       uint8_t *buf = odp_packet_addr(pkt);
> -       bool posted = 0;
> +       odp_buffer_t completion = ODP_BUFFER_INVALID;
> +       uint8_t *buf = odp_packet_addr(*pkt);
>
>         /* We were dispatched from atomic queue, assign sequence numbers */
>         if (ctx->ipsec.ah_offset) {
> @@ -977,12 +998,16 @@ pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
>         }
>
>         /* Issue crypto request */
> -       if (odp_crypto_operation(&ctx->ipsec.params,
> -                                &posted,
> -                                odp_packet_to_buffer(pkt))) {
> +       if (odp_crypto_operation(&ctx->ipsec.params, &completion))
>                 abort();
> -       }
> -       return (posted) ? PKT_POSTED : PKT_CONTINUE;
> +       if (completion == ODP_BUFFER_INVALID)
> +               return PKT_POSTED;
> +
> +       *pkt = crypto_completion_to_packet(completion);
> +       if (*pkt != ODP_PACKET_INVALID)
> +               return PKT_CONTINUE;
> +
> +       return PKT_DROP;
>  }
>
>  /**
> @@ -997,18 +1022,8 @@ static
>  pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt,
>                                       pkt_ctx_t *ctx)
>  {
> -       odp_buffer_t event;
> -       odp_crypto_compl_status_t cipher_rc;
> -       odp_crypto_compl_status_t auth_rc;
>         odph_ipv4hdr_t *ip;
>
> -       /* Check crypto result */
> -       event = odp_packet_to_buffer(pkt);
> -       odp_crypto_get_operation_compl_status(event, &cipher_rc, &auth_rc);
> -       if (!is_crypto_compl_status_ok(&cipher_rc))
> -               return PKT_DROP;
> -       if (!is_crypto_compl_status_ok(&auth_rc))
> -               return PKT_DROP;
>         ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
>
>         /* Finalize the IPv4 header */
> @@ -1059,7 +1074,13 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>
>                 /* Use schedule to get buf from any input queue */
>                 buf = SCHEDULE(&dispatchq, ODP_SCHED_WAIT);
> -               pkt = odp_packet_from_buffer(buf);
> +               if (completionq == dispatchq)
> +                       pkt = crypto_completion_to_packet(buf);
> +               else
> +                       pkt = odp_packet_from_buffer(buf);
> +
> +               if (pkt == ODP_PACKET_INVALID)
> +                       continue;
>
>                 /* Determine new work versus completion or sequence number
> */
>                 if ((completionq != dispatchq) && (seqnumq != dispatchq)) {
> @@ -1093,7 +1114,7 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>
>                         case PKT_STATE_IPSEC_IN_CLASSIFY:
>
> -                               rc = do_ipsec_in_classify(pkt, ctx, &skip);
> +                               rc = do_ipsec_in_classify(&pkt, ctx,
> &skip);
>                                 ctx->state = (skip) ?
>                                         PKT_STATE_ROUTE_LOOKUP :
>                                         PKT_STATE_IPSEC_IN_FINISH;
> @@ -1124,7 +1145,7 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>
>                         case PKT_STATE_IPSEC_OUT_SEQ:
>
> -                               rc = do_ipsec_out_seq(pkt, ctx);
> +                               rc = do_ipsec_out_seq(&pkt, ctx);
>                                 ctx->state = PKT_STATE_IPSEC_OUT_FINISH;
>                                 break;
>
> @@ -1150,7 +1171,6 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>                 if ((PKT_DROP == rc) || (PKT_DONE == rc))
>                         free_pkt_ctx(ctx);
>
> -
>                 /* Check for drop */
>                 if (PKT_DROP == rc)
>                         odph_packet_free(pkt);
> diff --git a/platform/linux-generic/include/api/odp_crypto.h
> b/platform/linux-generic/include/api/odp_crypto.h
> index 337e7cf..aac44d5 100644
> --- a/platform/linux-generic/include/api/odp_crypto.h
> +++ b/platform/linux-generic/include/api/odp_crypto.h
> @@ -225,29 +225,25 @@
> odp_crypto_session_create(odp_crypto_session_params_t *params,
>                           odp_crypto_session_t *session,
>                           enum odp_crypto_ses_create_err *status);
>
> -
>  /**
>   * Crypto per packet operation
>   *
>   * Performs the cryptographic operations specified during session creation
> - * on the packet.  If the operation is performed synchronously, "posted"
> - * will return FALSE and the result of the operation is immediately
> available
> - * in the completion event.  If "posted" returns TRUE the result will be
> - * delivered via the completion queue specified when the session was
> created.
> - *
> - * @todo Resolve if completion_event is necessary, can/should the output
> - *       packet buffer always be used instead.
> + * on the packet.  If the operation is performed synchronously, result
> will
> + * be returned in completion_event buffer immediately. In case of
> asynchronous
> + * operation completion event will return ODP_INVALID_BUFFER and the
> result
> + * will be delivered via the completion queue specified when the session
> was
> + * created.
>   *
> - * @param params            Operation parameters
> - * @param posted            Pointer to return posted, TRUE for async
> operation
> - * @param completion_event  Event by which the operation results are
> delivered.
> + * @param[in]  params            Operation parameters
> + * @param[out] completion_event  Pointer to completion event by which the
> + *                               synchronous operation results are
> delivered.
>   *
>   * @return 0 if successful else -1
>   */
>  int
>  odp_crypto_operation(odp_crypto_op_params_t *params,
> -                    bool *posted,
> -                    odp_buffer_t completion_event);
> +                    odp_buffer_t *completion_event);
>
>  /**
>   * Crypto per packet operation set user context in completion event
> @@ -297,6 +293,18 @@ void *
>  odp_crypto_get_operation_compl_ctx(odp_buffer_t completion_event);
>
>  /**
> + * Free completion event
> + *
> + * Completion event is an opaque buffer that is managed by implementation.
> + * The event can't be freed directly, because it can point to an output
> packet.
> + * This function should be used instead.
> + *
> + * @param completion_event  Event to be freed
> + */
> +void
> +odp_crypto_operation_compl_free(odp_buffer_t completion_event);
> +
> +/**
>   * Generate random byte string
>   *
>   * @param buf          Pointer to store result
> diff --git a/platform/linux-generic/odp_crypto.c
> b/platform/linux-generic/odp_crypto.c
> index d3cdec7..98cbdb7 100644
> --- a/platform/linux-generic/odp_crypto.c
> +++ b/platform/linux-generic/odp_crypto.c
> @@ -337,15 +337,14 @@
> odp_crypto_session_create(odp_crypto_session_params_t *params,
>
>  int
>  odp_crypto_operation(odp_crypto_op_params_t *params,
> -                    bool *posted,
> -                    odp_buffer_t completion_event)
> +                    odp_buffer_t *completion_event)
>  {
>         enum crypto_alg_err rc_cipher = ODP_CRYPTO_ALG_ERR_NONE;
>         enum crypto_alg_err rc_auth = ODP_CRYPTO_ALG_ERR_NONE;
>         odp_crypto_generic_session_t *session;
>         odp_crypto_generic_op_result_t *result;
> +       odp_buffer_t completion;
>
> -       *posted = 0;
>         session = (odp_crypto_generic_session_t
> *)(intptr_t)params->session;
>
>         /* Resolve output buffer */
> @@ -357,13 +356,12 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>                 if (odp_unlikely(ODP_PACKET_INVALID == params->out_pkt))
>                         abort();
>                 odp_packet_copy(params->out_pkt, params->pkt);
> -               if (completion_event == odp_packet_to_buffer(params->pkt))
> -                       completion_event =
> -                               odp_packet_to_buffer(params->out_pkt);
>                 odph_packet_free(params->pkt);
>                 params->pkt = ODP_PACKET_INVALID;
>         }
>
> +       completion = odp_packet_to_buffer(params->out_pkt);
> +
>         /* Invoke the functions */
>         if (session->do_cipher_first) {
>                 rc_cipher = session->cipher.func(params, session);
> @@ -374,7 +372,7 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>         }
>
>         /* Build Result (no HW so no errors) */
> -       result = get_op_result_from_buffer(completion_event);
> +       result = get_op_result_from_buffer(completion);
>         result->magic = OP_RESULT_MAGIC;
>         result->cipher.alg_err = rc_cipher;
>         result->cipher.hw_err = ODP_CRYPTO_HW_ERR_NONE;
> @@ -383,8 +381,10 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>
>         /* If specified during creation post event to completion queue */
>         if (ODP_QUEUE_INVALID != session->compl_queue) {
> -               odp_queue_enq(session->compl_queue, completion_event);
> -               *posted = 1;
> +               odp_queue_enq(session->compl_queue, completion);
> +               *completion_event = ODP_BUFFER_INVALID;
> +       } else {
> +               *completion_event = completion;
>         }
>         return 0;
>  }
> @@ -421,7 +421,6 @@ odp_hw_random_get(uint8_t *buf, size_t *len, bool
> use_entropy ODP_UNUSED)
>         rc = RAND_bytes(buf, *len);
>         return ((1 == rc) ? 0 : -1);
>  }
> -
>  void
>  odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
>                                       odp_crypto_compl_status_t *auth,
> @@ -454,8 +453,13 @@ void
>  }
>
>  odp_packet_t
> -odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event
> ODP_UNUSED)
> +odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
>  {
> -       ODP_UNIMPLEMENTED();
> -       return ODP_PACKET_INVALID;
> +       return odp_packet_from_buffer(completion_event);
> +}
> +
> +void
> +odp_crypto_operation_compl_free(odp_buffer_t completion_event ODP_UNUSED)
> +{
> +       /* Original packet is used as a completion, so nothing to free */
>  }
> --
> 1.7.9.5
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
Balasubramanian Manoharan Dec. 5, 2014, 2:38 p.m. UTC | #2
Hi,

In case of synchronous crypto operation the completion event is need only
in case of an error hence the application can check the return code for
failure and get info from completion event buffer only during that
scenario. This will greatly optimize the performance in synchronous crypto
operations.

Regards,
Bala

On 5 December 2014 at 19:46, Alexandru Badicioiu <
alexandru.badicioiu@linaro.org> wrote:

> Hi ,
> what this patch wants to accomplish can be done with the actual API this
> way : if the implementation really cannot reuse the input packet as the
> completion event (are there implementations which cannot?) it can return an
> error and the application could allocate a separate completion event:
> There is a little overhead with the first assignment and with the failed
> crypto operation in case of platforms which do not support reusing the
> packet but the API doesn't need to be modified (only adding a new error
> code).
>
> odp_buffer_t compl = odp_packet_to_buffer(op_params.pkt);
> rc = odp_crypto_operation(&op_params, &posted, compl);
> if (odp_unlikely(ODP_CRYPTO_INVALID_COMPL_EVENT == rc)) {
>       compl = odp_buffer_alloc();
>       rc = odp_crypto_operation(&op_params, &posted, compl);
> }
>
> Alex
>
>
>
>
> On 5 December 2014 at 14:42, Taras Kondratiuk <taras.kondratiuk@linaro.org
> > wrote:
>
>> Some implementations may not need a separate buffer for completion
>> event but can reuse packet for this. Make it possible for implementation
>> to decide this by passing completion event as pointer to
>> odp_crypto_operation(). In synchronous mode implementation will return
>> completion event at that pointer. In asynchronous - ODP_BUFFER_INVALID.
>>
>> This patch doesn't cover CUnit tests.
>>
>> Signed-off-by: Taras Kondratiuk <taras.kondratiuk@linaro.org>
>> ---
>>  example/ipsec/odp_ipsec.c                       |  106
>> ++++++++++++++---------
>>  platform/linux-generic/include/api/odp_crypto.h |   34 +++++---
>>  platform/linux-generic/odp_crypto.c             |   30 ++++---
>>  3 files changed, 101 insertions(+), 69 deletions(-)
>>
>> diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
>> index 76d27c5..c25f631 100644
>> --- a/example/ipsec/odp_ipsec.c
>> +++ b/example/ipsec/odp_ipsec.c
>> @@ -209,6 +209,33 @@ void free_pkt_ctx(pkt_ctx_t *ctx)
>>  }
>>
>>  /**
>> + * Convert completion event to completed operation packet
>> + *
>> + * @note Function frees completion event.
>> + *
>> + * @param completion  Event containing operation results
>> + *
>> + * @return Packet structure where data now resides or ODP_PACKET_INVALID
>> + *         in case of any operation error.
>> + */
>> +static
>> +odp_packet_t crypto_completion_to_packet(odp_buffer_t completion)
>> +{
>> +       odp_crypto_compl_status_t cipher_rc;
>> +       odp_crypto_compl_status_t auth_rc;
>> +       odp_packet_t pkt;
>> +
>> +       odp_crypto_get_operation_compl_status(completion, &cipher_rc,
>> &auth_rc);
>> +       if (!is_crypto_compl_status_ok(&cipher_rc))
>> +               return ODP_PACKET_INVALID;
>> +       if (!is_crypto_compl_status_ok(&auth_rc))
>> +               return ODP_PACKET_INVALID;
>> +       pkt = odp_crypto_get_operation_compl_packet(completion);
>> +       odp_crypto_operation_compl_free(completion);
>> +       return pkt;
>> +}
>> +
>> +/**
>>   * Use socket I/O workaround to query interface MAC address
>>   *
>>   * @todo Remove all references to USE_MAC_ADDR_HACK once
>> @@ -677,18 +704,18 @@ pkt_disposition_e do_route_fwd_db(odp_packet_t pkt,
>> pkt_ctx_t *ctx)
>>   * @return PKT_CONTINUE if done else PKT_POSTED
>>   */
>>  static
>> -pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
>> +pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt,
>>                                        pkt_ctx_t *ctx,
>>                                        bool *skip)
>>  {
>> -       uint8_t *buf = odp_packet_addr(pkt);
>> -       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
>> +       uint8_t *buf = odp_packet_addr(*pkt);
>> +       odp_buffer_t completion = ODP_BUFFER_INVALID;
>> +       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(*pkt);
>>         int hdr_len;
>>         odph_ahhdr_t *ah = NULL;
>>         odph_esphdr_t *esp = NULL;
>>         ipsec_cache_entry_t *entry;
>>         odp_crypto_op_params_t params;
>> -       bool posted = 0;
>>
>>         /* Default to skip IPsec */
>>         *skip = TRUE;
>> @@ -710,8 +737,8 @@ pkt_disposition_e do_ipsec_in_classify(odp_packet_t
>> pkt,
>>         /* Initialize parameters block */
>>         memset(&params, 0, sizeof(params));
>>         params.session = entry->state.session;
>> -       params.pkt = pkt;
>> -       params.out_pkt = entry->in_place ? pkt : ODP_PACKET_INVALID;
>> +       params.pkt = *pkt;
>> +       params.out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID;
>>
>>         /*Save everything to context */
>>         ctx->ipsec.ip_tos = ip->tos;
>> @@ -743,12 +770,16 @@ pkt_disposition_e do_ipsec_in_classify(odp_packet_t
>> pkt,
>>
>>         /* Issue crypto request */
>>         *skip = FALSE;
>> -       if (odp_crypto_operation(&params,
>> -                                &posted,
>> -                                odp_packet_to_buffer(pkt))) {
>> +       if (odp_crypto_operation(&params, &completion))
>>                 abort();
>> -       }
>> -       return (posted) ? PKT_POSTED : PKT_CONTINUE;
>> +       if (completion == ODP_BUFFER_INVALID)
>> +               return PKT_POSTED;
>> +
>> +       *pkt = crypto_completion_to_packet(completion);
>> +       if (*pkt != ODP_PACKET_INVALID)
>> +               return PKT_CONTINUE;
>> +
>> +       return PKT_DROP;
>>  }
>>
>>  /**
>> @@ -763,20 +794,10 @@ static
>>  pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt,
>>                                      pkt_ctx_t *ctx)
>>  {
>> -       odp_buffer_t event;
>> -       odp_crypto_compl_status_t cipher_rc;
>> -       odp_crypto_compl_status_t auth_rc;
>>         odph_ipv4hdr_t *ip;
>>         int hdr_len = ctx->ipsec.hdr_len;
>>         int trl_len = 0;
>>
>> -       /* Check crypto result */
>> -       event = odp_packet_to_buffer(pkt);
>> -       odp_crypto_get_operation_compl_status(event, &cipher_rc,
>> &auth_rc);
>> -       if (!is_crypto_compl_status_ok(&cipher_rc))
>> -               return PKT_DROP;
>> -       if (!is_crypto_compl_status_ok(&auth_rc))
>> -               return PKT_DROP;
>>         ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
>>
>>         /*
>> @@ -956,11 +977,11 @@ pkt_disposition_e
>> do_ipsec_out_classify(odp_packet_t pkt,
>>   * @return PKT_CONTINUE if done else PKT_POSTED
>>   */
>>  static
>> -pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
>> +pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt,
>>                                    pkt_ctx_t *ctx)
>>  {
>> -       uint8_t *buf = odp_packet_addr(pkt);
>> -       bool posted = 0;
>> +       odp_buffer_t completion = ODP_BUFFER_INVALID;
>> +       uint8_t *buf = odp_packet_addr(*pkt);
>>
>>         /* We were dispatched from atomic queue, assign sequence numbers
>> */
>>         if (ctx->ipsec.ah_offset) {
>> @@ -977,12 +998,16 @@ pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
>>         }
>>
>>         /* Issue crypto request */
>> -       if (odp_crypto_operation(&ctx->ipsec.params,
>> -                                &posted,
>> -                                odp_packet_to_buffer(pkt))) {
>> +       if (odp_crypto_operation(&ctx->ipsec.params, &completion))
>>                 abort();
>> -       }
>> -       return (posted) ? PKT_POSTED : PKT_CONTINUE;
>> +       if (completion == ODP_BUFFER_INVALID)
>> +               return PKT_POSTED;
>> +
>> +       *pkt = crypto_completion_to_packet(completion);
>> +       if (*pkt != ODP_PACKET_INVALID)
>> +               return PKT_CONTINUE;
>> +
>> +       return PKT_DROP;
>>  }
>>
>>  /**
>> @@ -997,18 +1022,8 @@ static
>>  pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt,
>>                                       pkt_ctx_t *ctx)
>>  {
>> -       odp_buffer_t event;
>> -       odp_crypto_compl_status_t cipher_rc;
>> -       odp_crypto_compl_status_t auth_rc;
>>         odph_ipv4hdr_t *ip;
>>
>> -       /* Check crypto result */
>> -       event = odp_packet_to_buffer(pkt);
>> -       odp_crypto_get_operation_compl_status(event, &cipher_rc,
>> &auth_rc);
>> -       if (!is_crypto_compl_status_ok(&cipher_rc))
>> -               return PKT_DROP;
>> -       if (!is_crypto_compl_status_ok(&auth_rc))
>> -               return PKT_DROP;
>>         ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
>>
>>         /* Finalize the IPv4 header */
>> @@ -1059,7 +1074,13 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>>
>>                 /* Use schedule to get buf from any input queue */
>>                 buf = SCHEDULE(&dispatchq, ODP_SCHED_WAIT);
>> -               pkt = odp_packet_from_buffer(buf);
>> +               if (completionq == dispatchq)
>> +                       pkt = crypto_completion_to_packet(buf);
>> +               else
>> +                       pkt = odp_packet_from_buffer(buf);
>> +
>> +               if (pkt == ODP_PACKET_INVALID)
>> +                       continue;
>>
>>                 /* Determine new work versus completion or sequence
>> number */
>>                 if ((completionq != dispatchq) && (seqnumq != dispatchq))
>> {
>> @@ -1093,7 +1114,7 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>>
>>                         case PKT_STATE_IPSEC_IN_CLASSIFY:
>>
>> -                               rc = do_ipsec_in_classify(pkt, ctx,
>> &skip);
>> +                               rc = do_ipsec_in_classify(&pkt, ctx,
>> &skip);
>>                                 ctx->state = (skip) ?
>>                                         PKT_STATE_ROUTE_LOOKUP :
>>                                         PKT_STATE_IPSEC_IN_FINISH;
>> @@ -1124,7 +1145,7 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>>
>>                         case PKT_STATE_IPSEC_OUT_SEQ:
>>
>> -                               rc = do_ipsec_out_seq(pkt, ctx);
>> +                               rc = do_ipsec_out_seq(&pkt, ctx);
>>                                 ctx->state = PKT_STATE_IPSEC_OUT_FINISH;
>>                                 break;
>>
>> @@ -1150,7 +1171,6 @@ void *pktio_thread(void *arg EXAMPLE_UNUSED)
>>                 if ((PKT_DROP == rc) || (PKT_DONE == rc))
>>                         free_pkt_ctx(ctx);
>>
>> -
>>                 /* Check for drop */
>>                 if (PKT_DROP == rc)
>>                         odph_packet_free(pkt);
>> diff --git a/platform/linux-generic/include/api/odp_crypto.h
>> b/platform/linux-generic/include/api/odp_crypto.h
>> index 337e7cf..aac44d5 100644
>> --- a/platform/linux-generic/include/api/odp_crypto.h
>> +++ b/platform/linux-generic/include/api/odp_crypto.h
>> @@ -225,29 +225,25 @@
>> odp_crypto_session_create(odp_crypto_session_params_t *params,
>>                           odp_crypto_session_t *session,
>>                           enum odp_crypto_ses_create_err *status);
>>
>> -
>>  /**
>>   * Crypto per packet operation
>>   *
>>   * Performs the cryptographic operations specified during session
>> creation
>> - * on the packet.  If the operation is performed synchronously, "posted"
>> - * will return FALSE and the result of the operation is immediately
>> available
>> - * in the completion event.  If "posted" returns TRUE the result will be
>> - * delivered via the completion queue specified when the session was
>> created.
>> - *
>> - * @todo Resolve if completion_event is necessary, can/should the output
>> - *       packet buffer always be used instead.
>> + * on the packet.  If the operation is performed synchronously, result
>> will
>> + * be returned in completion_event buffer immediately. In case of
>> asynchronous
>> + * operation completion event will return ODP_INVALID_BUFFER and the
>> result
>> + * will be delivered via the completion queue specified when the session
>> was
>> + * created.
>>   *
>> - * @param params            Operation parameters
>> - * @param posted            Pointer to return posted, TRUE for async
>> operation
>> - * @param completion_event  Event by which the operation results are
>> delivered.
>> + * @param[in]  params            Operation parameters
>> + * @param[out] completion_event  Pointer to completion event by which the
>> + *                               synchronous operation results are
>> delivered.
>>   *
>>   * @return 0 if successful else -1
>>   */
>>  int
>>  odp_crypto_operation(odp_crypto_op_params_t *params,
>> -                    bool *posted,
>> -                    odp_buffer_t completion_event);
>> +                    odp_buffer_t *completion_event);
>>
>>  /**
>>   * Crypto per packet operation set user context in completion event
>> @@ -297,6 +293,18 @@ void *
>>  odp_crypto_get_operation_compl_ctx(odp_buffer_t completion_event);
>>
>>  /**
>> + * Free completion event
>> + *
>> + * Completion event is an opaque buffer that is managed by
>> implementation.
>> + * The event can't be freed directly, because it can point to an output
>> packet.
>> + * This function should be used instead.
>> + *
>> + * @param completion_event  Event to be freed
>> + */
>> +void
>> +odp_crypto_operation_compl_free(odp_buffer_t completion_event);
>> +
>> +/**
>>   * Generate random byte string
>>   *
>>   * @param buf          Pointer to store result
>> diff --git a/platform/linux-generic/odp_crypto.c
>> b/platform/linux-generic/odp_crypto.c
>> index d3cdec7..98cbdb7 100644
>> --- a/platform/linux-generic/odp_crypto.c
>> +++ b/platform/linux-generic/odp_crypto.c
>> @@ -337,15 +337,14 @@
>> odp_crypto_session_create(odp_crypto_session_params_t *params,
>>
>>  int
>>  odp_crypto_operation(odp_crypto_op_params_t *params,
>> -                    bool *posted,
>> -                    odp_buffer_t completion_event)
>> +                    odp_buffer_t *completion_event)
>>  {
>>         enum crypto_alg_err rc_cipher = ODP_CRYPTO_ALG_ERR_NONE;
>>         enum crypto_alg_err rc_auth = ODP_CRYPTO_ALG_ERR_NONE;
>>         odp_crypto_generic_session_t *session;
>>         odp_crypto_generic_op_result_t *result;
>> +       odp_buffer_t completion;
>>
>> -       *posted = 0;
>>         session = (odp_crypto_generic_session_t
>> *)(intptr_t)params->session;
>>
>>         /* Resolve output buffer */
>> @@ -357,13 +356,12 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>>                 if (odp_unlikely(ODP_PACKET_INVALID == params->out_pkt))
>>                         abort();
>>                 odp_packet_copy(params->out_pkt, params->pkt);
>> -               if (completion_event == odp_packet_to_buffer(params->pkt))
>> -                       completion_event =
>> -                               odp_packet_to_buffer(params->out_pkt);
>>                 odph_packet_free(params->pkt);
>>                 params->pkt = ODP_PACKET_INVALID;
>>         }
>>
>> +       completion = odp_packet_to_buffer(params->out_pkt);
>> +
>>         /* Invoke the functions */
>>         if (session->do_cipher_first) {
>>                 rc_cipher = session->cipher.func(params, session);
>> @@ -374,7 +372,7 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>>         }
>>
>>         /* Build Result (no HW so no errors) */
>> -       result = get_op_result_from_buffer(completion_event);
>> +       result = get_op_result_from_buffer(completion);
>>         result->magic = OP_RESULT_MAGIC;
>>         result->cipher.alg_err = rc_cipher;
>>         result->cipher.hw_err = ODP_CRYPTO_HW_ERR_NONE;
>> @@ -383,8 +381,10 @@ odp_crypto_operation(odp_crypto_op_params_t *params,
>>
>>         /* If specified during creation post event to completion queue */
>>         if (ODP_QUEUE_INVALID != session->compl_queue) {
>> -               odp_queue_enq(session->compl_queue, completion_event);
>> -               *posted = 1;
>> +               odp_queue_enq(session->compl_queue, completion);
>> +               *completion_event = ODP_BUFFER_INVALID;
>> +       } else {
>> +               *completion_event = completion;
>>         }
>>         return 0;
>>  }
>> @@ -421,7 +421,6 @@ odp_hw_random_get(uint8_t *buf, size_t *len, bool
>> use_entropy ODP_UNUSED)
>>         rc = RAND_bytes(buf, *len);
>>         return ((1 == rc) ? 0 : -1);
>>  }
>> -
>>  void
>>  odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
>>                                       odp_crypto_compl_status_t *auth,
>> @@ -454,8 +453,13 @@ void
>>  }
>>
>>  odp_packet_t
>> -odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event
>> ODP_UNUSED)
>> +odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
>>  {
>> -       ODP_UNIMPLEMENTED();
>> -       return ODP_PACKET_INVALID;
>> +       return odp_packet_from_buffer(completion_event);
>> +}
>> +
>> +void
>> +odp_crypto_operation_compl_free(odp_buffer_t completion_event ODP_UNUSED)
>> +{
>> +       /* Original packet is used as a completion, so nothing to free */
>>  }
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> http://lists.linaro.org/mailman/listinfo/lng-odp
>>
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
>
Taras Kondratiuk Dec. 5, 2014, 3:45 p.m. UTC | #3
On 12/05/2014 04:16 PM, Alexandru Badicioiu wrote:
> Hi ,
> what this patch wants to accomplish can be done with the actual API this
> way : if the implementation really cannot reuse the input packet as the
> completion event (are there implementations which cannot?) it can return
> an error and the application could allocate a separate completion event:
> There is a little overhead with the first assignment and with the failed
> crypto operation in case of platforms which do not support reusing the
> packet but the API doesn't need to be modified (only adding a new error
> code).
>
> odp_buffer_t compl = odp_packet_to_buffer(op_params.pkt);
> rc = odp_crypto_operation(&op_params, &posted, compl);
> if (odp_unlikely(ODP_CRYPTO_INVALID_COMPL_EVENT == rc)) {
>        compl = odp_buffer_alloc();
>        rc = odp_crypto_operation(&op_params, &posted, compl);
> }

This approach really looks like a hack and it has several issues:

1. Application have to remember to free completion in case it was
    allocated. In asynchronous case completion event may be dequeued
    in another thread, so 'need to be freed' information should be
    passed somehow along with the completion event. Implementation is in
    much better position to handle this case.

2. Implicitly passing packet as a completion event may mislead
    application developer, because he may assume that he will get it back
    in exactly the same state (that's exactly what happened in our IPsec
    application). But accordingly to the specification completion event
    is an opaque token, so developer should not assume that its state is
    preserved. Instead we have accessors functions to get information
    from the completion event.
Taras Kondratiuk Dec. 5, 2014, 4:46 p.m. UTC | #4
On 12/05/2014 04:38 PM, Bala Manoharan wrote:
> Hi,
> 
> In case of synchronous crypto operation the completion event is need 
> only in case of an error hence the application can check the return code 
> for failure and get info from completion event buffer only during that 
> scenario. This will greatly optimize the performance in synchronous 
> crypto operations.

This RFC aims to eliminate completion event handling by application, so
implementation (if capable) can optimize it and use output packet
instead. Both sync and async implementation will benefit in the same
way.

What you are asking is a separate optimization for sync mode which also
can be achieved on top of this RFC. We can add a note to
odp_crypto_operation() description: "if the function succeeded and it
was synchronous an output packet can be queried without status check".


----------------- implementation ---------------------------
int
odp_crypto_operation(odp_crypto_op_params_t *params,
                     odp_buffer_t *completion_event)
{
	...
	process_packet(params->in_pkt, params->out_pkt);
	*completion_event = odp_packet_to_buffer(params->out_pkt)
        ...
	return 0;
}

odp_packet_t
odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
{
        return odp_packet_from_buffer(completion_event);
}

void
odp_crypto_operation_compl_free(odp_buffer_t completion_event)
{
}

----------------- application (odp_ipsec.c)----------------------------

	/* Issue crypto request */
        if (odp_crypto_operation(&params, &completion)) {
		/* Call odp_crypto_get_operation_status(completion) if details are needed */
		return PKT_DROP;
	}

	if (completion != ODP_BUFFER_INVALID) {
		*pkt = odp_crypto_get_operation_compl_packet(completion);
	        return (*pkt != ODP_PACKET_INVALID) ? PKT_CONTINUE : PKT_DROP:
	} else {
			return PKT_POSTED;

If buffer<->packet conversion is just casting, then overhead is zero.
Will it work for you?
Alexandru Badicioiu Dec. 8, 2014, 8:58 a.m. UTC | #5
Some comments inline.

Alex

On 5 December 2014 at 17:45, Taras Kondratiuk <taras.kondratiuk@linaro.org>
wrote:

> On 12/05/2014 04:16 PM, Alexandru Badicioiu wrote:
>
>> Hi ,
>> what this patch wants to accomplish can be done with the actual API this
>> way : if the implementation really cannot reuse the input packet as the
>> completion event (are there implementations which cannot?) it can return
>> an error and the application could allocate a separate completion event:
>> There is a little overhead with the first assignment and with the failed
>> crypto operation in case of platforms which do not support reusing the
>> packet but the API doesn't need to be modified (only adding a new error
>> code).
>>
>> odp_buffer_t compl = odp_packet_to_buffer(op_params.pkt);
>> rc = odp_crypto_operation(&op_params, &posted, compl);
>> if (odp_unlikely(ODP_CRYPTO_INVALID_COMPL_EVENT == rc)) {
>>        compl = odp_buffer_alloc();
>>        rc = odp_crypto_operation(&op_params, &posted, compl);
>> }
>>
>
> This approach really looks like a hack and it has several issues:


> 1. Application have to remember to free completion in case it was
>    allocated.

 [Alex] This is normal, right? If the application allocated something,
shouldn't have the responsibility to free it?
I think it is the case of your patch when the application has to remember
to free something which it did not allocate.
You have proposed completion_event_free API but there is no alloc call
which is unbalanced. The call is in fact no different
than normal buffer free and for implementations which reuse the packet it
will be empty, as it is in the patch.


> In asynchronous case completion event may be dequeued
>    in another thread, so 'need to be freed' information should be
>    passed somehow along with the completion event. Implementation is in
>    much better position to handle this case.
>
[Alex] The operation context is meant to "pass something along with the
completion event",
in case the application really needs this. However, the code example was
only to show
that the application has a mean to handle this packet vs new completion
event issue.
I think the API should be changed only if there's no other acceptable way
of doing something.
The cleanest approach is probably to introduce a capability call and the
application can check if
it can pass the input packet as the completion event.


> 2. Implicitly passing packet as a completion event may mislead
>    application developer, because he may assume that he will get it back
>    in exactly the same state (that's exactly what happened in our IPsec
>    application).

[Alex] The underlying buffer is passed, not the packet as such.
Implementation
knows where the packet and its metadata are in the packet and if no
INVALID_COMPLETION_EVENT error is returned it should be guaranteed
that the packet "state" is preserved. As I remember from the design,
the completion event is just a buffer where the crypto operation
returns the completion information. The only "opaque"
thing is how the crypto uses the buffer and how it lays out the output
information.


> But accordingly to the specification completion event
>    is an opaque token, so developer should not assume that its state is
>    preserved. Instead we have accessors functions to get information
>    from the completion event.
>
Taras Kondratiuk Dec. 8, 2014, 10:12 a.m. UTC | #6
On 12/08/2014 10:58 AM, Alexandru Badicioiu wrote:
> Some comments inline.
>
> Alex
>
> On 5 December 2014 at 17:45, Taras Kondratiuk
> <taras.kondratiuk@linaro.org <mailto:taras.kondratiuk@linaro.org>> wrote:
>
>     On 12/05/2014 04:16 PM, Alexandru Badicioiu wrote:
>
>         Hi ,
>         what this patch wants to accomplish can be done with the actual
>         API this
>         way : if the implementation really cannot reuse the input packet
>         as the
>         completion event (are there implementations which cannot?) it
>         can return
>         an error and the application could allocate a separate
>         completion event:
>         There is a little overhead with the first assignment and with
>         the failed
>         crypto operation in case of platforms which do not support
>         reusing the
>         packet but the API doesn't need to be modified (only adding a
>         new error
>         code).
>
>         odp_buffer_t compl = odp_packet_to_buffer(op___params.pkt);
>         rc = odp_crypto_operation(&op___params, &posted, compl);
>         if (odp_unlikely(ODP_CRYPTO___INVALID_COMPL_EVENT == rc)) {
>                 compl = odp_buffer_alloc();
>                 rc = odp_crypto_operation(&op___params, &posted, compl);
>         }
>
>
>     This approach really looks like a hack and it has several issues:
>
>
>     1. Application have to remember to free completion in case it was
>         allocated.
>
>   [Alex] This is normal, right? If the application allocated something,
> shouldn't have the responsibility to free it?

Sure freeing previously allocated buffer is normal, but *allocating* it
in a first place is *not necessary*. So no need to free anything.

> I think it is the case of your patch when the application has to
> remember to free something which it did not allocate.
> You have proposed completion_event_free API but there is no alloc call
> which is unbalanced. The call is in fact no different
> than normal buffer free and for implementations which reuse the packet
> it will be empty, as it is in the patch.

No. Difference is that application have to 'free' it *always*. No need
to determine action per event.
Regarding API balancing. It is the same use-case as ingress packets
processing: application can free them, but they are not allocated by
application.

>
>     In asynchronous case completion event may be dequeued
>         in another thread, so 'need to be freed' information should be
>         passed somehow along with the completion event. Implementation is in
>         much better position to handle this case.
>
> [Alex] The operation context is meant to "pass something along with the
> completion event",
> in case the application really needs this. However, the code example was
> only to show
> that the application has a mean to handle this packet vs new completion
> event issue.
> I think the API should be changed only if there's no other acceptable
> way of doing something.
> The cleanest approach is probably to introduce a capability call and the
> application can check if
> it can pass the input packet as the completion event.

Right, but IMO the approach you have proposed is not acceptable. It
doesn't make sense to freeze the API if small API changes can optimize
application and implementation sides. Especially at these early ODP
versions.

Unfortunately capability call won't solve the issue. Current crypto API
design was build on assumption that implementation can chose to process
a packet differently depending on its characteristics (size, cypher
algorithm, etc.). Depending on a type of processing chosen a completion
event may or may not be needed.

>
>
>     2. Implicitly passing packet as a completion event may mislead
>         application developer, because he may assume that he will get it
>     back
>         in exactly the same state (that's exactly what happened in our IPsec
>         application).
>
> [Alex] The underlying buffer is passed, not the packet as such.
> Implementation
> knows where the packet and its metadata are in the packet and if no
> INVALID_COMPLETION_EVENT error is returned it should be guaranteed
> that the packet "state" is preserved. As I remember from the design,
> the completion event is just a buffer where the crypto operation
> returns the completion information. The only "opaque"
> thing is how the crypto uses the buffer and how it lays out the output
> information.

Preserving an original completion buffer content is a wrong assumption.
Current specification doesn't say anything about it. Robby
initially used this as a workaround to avoid completion event
allocation on application side. That's exactly what this RFC is
addressing.

>
>     But accordingly to the specification completion event
>         is an opaque token, so developer should not assume that its state is
>         preserved. Instead we have accessors functions to get information
>         from the completion event.
>
>
Balasubramanian Manoharan Dec. 8, 2014, 11:30 a.m. UTC | #7
On Friday 05 December 2014 10:16 PM, Taras Kondratiuk wrote:
> On 12/05/2014 04:38 PM, Bala Manoharan wrote:
>> Hi,
>>
>> In case of synchronous crypto operation the completion event is need
>> only in case of an error hence the application can check the return code
>> for failure and get info from completion event buffer only during that
>> scenario. This will greatly optimize the performance in synchronous
>> crypto operations.
> This RFC aims to eliminate completion event handling by application, so
> implementation (if capable) can optimize it and use output packet
> instead. Both sync and async implementation will benefit in the same
> way.
>
> What you are asking is a separate optimization for sync mode which also
> can be achieved on top of this RFC. We can add a note to
> odp_crypto_operation() description: "if the function succeeded and it
> was synchronous an output packet can be queried without status check".
>
>
> ----------------- implementation ---------------------------
> int
> odp_crypto_operation(odp_crypto_op_params_t *params,
>                       odp_buffer_t *completion_event)
> {
> 	...
> 	process_packet(params->in_pkt, params->out_pkt);
> 	*completion_event = odp_packet_to_buffer(params->out_pkt)
>          ...
> 	return 0;
> }
>
> odp_packet_t
> odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
> {
>          return odp_packet_from_buffer(completion_event);
> }
>
> void
> odp_crypto_operation_compl_free(odp_buffer_t completion_event)
> {
> }
>
> ----------------- application (odp_ipsec.c)----------------------------
>
> 	/* Issue crypto request */
>          if (odp_crypto_operation(&params, &completion)) {
> 		/* Call odp_crypto_get_operation_status(completion) if details are needed */
> 		return PKT_DROP;
> 	}
>
> 	if (completion != ODP_BUFFER_INVALID) {
> 		*pkt = odp_crypto_get_operation_compl_packet(completion);
> 	        return (*pkt != ODP_PACKET_INVALID) ? PKT_CONTINUE : PKT_DROP:
> 	} else {
> 			return PKT_POSTED;
>
> If buffer<->packet conversion is just casting, then overhead is zero.
> Will it work for you?
In Sync crypto operation the output pkt is specified as part of the 
odp_crypto_op_params_t by the original design.
Hence it will not required to get the packet from completion event. The 
completion event needs to be checked
only during failure and during success the same can be ignored by the 
application.

Regards,
Bala
Taras Kondratiuk Dec. 8, 2014, 12:06 p.m. UTC | #8
On 12/08/2014 01:30 PM, Bala wrote:
>
> On Friday 05 December 2014 10:16 PM, Taras Kondratiuk wrote:
>> On 12/05/2014 04:38 PM, Bala Manoharan wrote:
>>> Hi,
>>>
>>> In case of synchronous crypto operation the completion event is need
>>> only in case of an error hence the application can check the return code
>>> for failure and get info from completion event buffer only during that
>>> scenario. This will greatly optimize the performance in synchronous
>>> crypto operations.
>> This RFC aims to eliminate completion event handling by application, so
>> implementation (if capable) can optimize it and use output packet
>> instead. Both sync and async implementation will benefit in the same
>> way.
>>
>> What you are asking is a separate optimization for sync mode which also
>> can be achieved on top of this RFC. We can add a note to
>> odp_crypto_operation() description: "if the function succeeded and it
>> was synchronous an output packet can be queried without status check".
>>
>>
>> ----------------- implementation ---------------------------
>> int
>> odp_crypto_operation(odp_crypto_op_params_t *params,
>>                       odp_buffer_t *completion_event)
>> {
>>     ...
>>     process_packet(params->in_pkt, params->out_pkt);
>>     *completion_event = odp_packet_to_buffer(params->out_pkt)
>>          ...
>>     return 0;
>> }
>>
>> odp_packet_t
>> odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
>> {
>>          return odp_packet_from_buffer(completion_event);
>> }
>>
>> void
>> odp_crypto_operation_compl_free(odp_buffer_t completion_event)
>> {
>> }
>>
>> ----------------- application (odp_ipsec.c)----------------------------
>>
>>     /* Issue crypto request */
>>          if (odp_crypto_operation(&params, &completion)) {
>>         /* Call odp_crypto_get_operation_status(completion) if details
>> are needed */
>>         return PKT_DROP;
>>     }
>>
>>     if (completion != ODP_BUFFER_INVALID) {
>>         *pkt = odp_crypto_get_operation_compl_packet(completion);
>>             return (*pkt != ODP_PACKET_INVALID) ? PKT_CONTINUE :
>> PKT_DROP:
>>     } else {
>>             return PKT_POSTED;
>>
>> If buffer<->packet conversion is just casting, then overhead is zero.
>> Will it work for you?
> In Sync crypto operation the output pkt is specified as part of the
> odp_crypto_op_params_t by the original design.
> Hence it will not required to get the packet from completion event. The
> completion event needs to be checked
> only during failure and during success the same can be ignored by the
> application.

Actually sync/async mode doesn't change a way how output packet is
handled from application point of view. There are two options:
1. Packet is allocated by application and specified in out_pkt.
    If operation is finished synchronously and successfully, then output
    packet is present in out_pkt.
2. out_pkt is set to ODP_PACKET_INVALID, so implementation allocates it.
    In this case output packet have to be obtained as in the code above.

So in general, will it help you to have next to zero overhead?
diff mbox

Patch

diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
index 76d27c5..c25f631 100644
--- a/example/ipsec/odp_ipsec.c
+++ b/example/ipsec/odp_ipsec.c
@@ -209,6 +209,33 @@  void free_pkt_ctx(pkt_ctx_t *ctx)
 }
 
 /**
+ * Convert completion event to completed operation packet
+ *
+ * @note Function frees completion event.
+ *
+ * @param completion  Event containing operation results
+ *
+ * @return Packet structure where data now resides or ODP_PACKET_INVALID
+ *         in case of any operation error.
+ */
+static
+odp_packet_t crypto_completion_to_packet(odp_buffer_t completion)
+{
+	odp_crypto_compl_status_t cipher_rc;
+	odp_crypto_compl_status_t auth_rc;
+	odp_packet_t pkt;
+
+	odp_crypto_get_operation_compl_status(completion, &cipher_rc, &auth_rc);
+	if (!is_crypto_compl_status_ok(&cipher_rc))
+		return ODP_PACKET_INVALID;
+	if (!is_crypto_compl_status_ok(&auth_rc))
+		return ODP_PACKET_INVALID;
+	pkt = odp_crypto_get_operation_compl_packet(completion);
+	odp_crypto_operation_compl_free(completion);
+	return pkt;
+}
+
+/**
  * Use socket I/O workaround to query interface MAC address
  *
  * @todo Remove all references to USE_MAC_ADDR_HACK once
@@ -677,18 +704,18 @@  pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx)
  * @return PKT_CONTINUE if done else PKT_POSTED
  */
 static
-pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
+pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt,
 				       pkt_ctx_t *ctx,
 				       bool *skip)
 {
-	uint8_t *buf = odp_packet_addr(pkt);
-	odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
+	uint8_t *buf = odp_packet_addr(*pkt);
+	odp_buffer_t completion = ODP_BUFFER_INVALID;
+	odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3(*pkt);
 	int hdr_len;
 	odph_ahhdr_t *ah = NULL;
 	odph_esphdr_t *esp = NULL;
 	ipsec_cache_entry_t *entry;
 	odp_crypto_op_params_t params;
-	bool posted = 0;
 
 	/* Default to skip IPsec */
 	*skip = TRUE;
@@ -710,8 +737,8 @@  pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
 	/* Initialize parameters block */
 	memset(&params, 0, sizeof(params));
 	params.session = entry->state.session;
-	params.pkt = pkt;
-	params.out_pkt = entry->in_place ? pkt : ODP_PACKET_INVALID;
+	params.pkt = *pkt;
+	params.out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID;
 
 	/*Save everything to context */
 	ctx->ipsec.ip_tos = ip->tos;
@@ -743,12 +770,16 @@  pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
 
 	/* Issue crypto request */
 	*skip = FALSE;
-	if (odp_crypto_operation(&params,
-				 &posted,
-				 odp_packet_to_buffer(pkt))) {
+	if (odp_crypto_operation(&params, &completion))
 		abort();
-	}
-	return (posted) ? PKT_POSTED : PKT_CONTINUE;
+	if (completion == ODP_BUFFER_INVALID)
+		return PKT_POSTED;
+
+	*pkt = crypto_completion_to_packet(completion);
+	if (*pkt != ODP_PACKET_INVALID)
+		return PKT_CONTINUE;
+
+	return PKT_DROP;
 }
 
 /**
@@ -763,20 +794,10 @@  static
 pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt,
 				     pkt_ctx_t *ctx)
 {
-	odp_buffer_t event;
-	odp_crypto_compl_status_t cipher_rc;
-	odp_crypto_compl_status_t auth_rc;
 	odph_ipv4hdr_t *ip;
 	int hdr_len = ctx->ipsec.hdr_len;
 	int trl_len = 0;
 
-	/* Check crypto result */
-	event = odp_packet_to_buffer(pkt);
-	odp_crypto_get_operation_compl_status(event, &cipher_rc, &auth_rc);
-	if (!is_crypto_compl_status_ok(&cipher_rc))
-		return PKT_DROP;
-	if (!is_crypto_compl_status_ok(&auth_rc))
-		return PKT_DROP;
 	ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
 
 	/*
@@ -956,11 +977,11 @@  pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt,
  * @return PKT_CONTINUE if done else PKT_POSTED
  */
 static
-pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
+pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt,
 				   pkt_ctx_t *ctx)
 {
-	uint8_t *buf = odp_packet_addr(pkt);
-	bool posted = 0;
+	odp_buffer_t completion = ODP_BUFFER_INVALID;
+	uint8_t *buf = odp_packet_addr(*pkt);
 
 	/* We were dispatched from atomic queue, assign sequence numbers */
 	if (ctx->ipsec.ah_offset) {
@@ -977,12 +998,16 @@  pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
 	}
 
 	/* Issue crypto request */
-	if (odp_crypto_operation(&ctx->ipsec.params,
-				 &posted,
-				 odp_packet_to_buffer(pkt))) {
+	if (odp_crypto_operation(&ctx->ipsec.params, &completion))
 		abort();
-	}
-	return (posted) ? PKT_POSTED : PKT_CONTINUE;
+	if (completion == ODP_BUFFER_INVALID)
+		return PKT_POSTED;
+
+	*pkt = crypto_completion_to_packet(completion);
+	if (*pkt != ODP_PACKET_INVALID)
+		return PKT_CONTINUE;
+
+	return PKT_DROP;
 }
 
 /**
@@ -997,18 +1022,8 @@  static
 pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt,
 				      pkt_ctx_t *ctx)
 {
-	odp_buffer_t event;
-	odp_crypto_compl_status_t cipher_rc;
-	odp_crypto_compl_status_t auth_rc;
 	odph_ipv4hdr_t *ip;
 
-	/* Check crypto result */
-	event = odp_packet_to_buffer(pkt);
-	odp_crypto_get_operation_compl_status(event, &cipher_rc, &auth_rc);
-	if (!is_crypto_compl_status_ok(&cipher_rc))
-		return PKT_DROP;
-	if (!is_crypto_compl_status_ok(&auth_rc))
-		return PKT_DROP;
 	ip = (odph_ipv4hdr_t *)odp_packet_l3(pkt);
 
 	/* Finalize the IPv4 header */
@@ -1059,7 +1074,13 @@  void *pktio_thread(void *arg EXAMPLE_UNUSED)
 
 		/* Use schedule to get buf from any input queue */
 		buf = SCHEDULE(&dispatchq, ODP_SCHED_WAIT);
-		pkt = odp_packet_from_buffer(buf);
+		if (completionq == dispatchq)
+			pkt = crypto_completion_to_packet(buf);
+		else
+			pkt = odp_packet_from_buffer(buf);
+
+		if (pkt == ODP_PACKET_INVALID)
+			continue;
 
 		/* Determine new work versus completion or sequence number */
 		if ((completionq != dispatchq) && (seqnumq != dispatchq)) {
@@ -1093,7 +1114,7 @@  void *pktio_thread(void *arg EXAMPLE_UNUSED)
 
 			case PKT_STATE_IPSEC_IN_CLASSIFY:
 
-				rc = do_ipsec_in_classify(pkt, ctx, &skip);
+				rc = do_ipsec_in_classify(&pkt, ctx, &skip);
 				ctx->state = (skip) ?
 					PKT_STATE_ROUTE_LOOKUP :
 					PKT_STATE_IPSEC_IN_FINISH;
@@ -1124,7 +1145,7 @@  void *pktio_thread(void *arg EXAMPLE_UNUSED)
 
 			case PKT_STATE_IPSEC_OUT_SEQ:
 
-				rc = do_ipsec_out_seq(pkt, ctx);
+				rc = do_ipsec_out_seq(&pkt, ctx);
 				ctx->state = PKT_STATE_IPSEC_OUT_FINISH;
 				break;
 
@@ -1150,7 +1171,6 @@  void *pktio_thread(void *arg EXAMPLE_UNUSED)
 		if ((PKT_DROP == rc) || (PKT_DONE == rc))
 			free_pkt_ctx(ctx);
 
-
 		/* Check for drop */
 		if (PKT_DROP == rc)
 			odph_packet_free(pkt);
diff --git a/platform/linux-generic/include/api/odp_crypto.h b/platform/linux-generic/include/api/odp_crypto.h
index 337e7cf..aac44d5 100644
--- a/platform/linux-generic/include/api/odp_crypto.h
+++ b/platform/linux-generic/include/api/odp_crypto.h
@@ -225,29 +225,25 @@  odp_crypto_session_create(odp_crypto_session_params_t *params,
 			  odp_crypto_session_t *session,
 			  enum odp_crypto_ses_create_err *status);
 
-
 /**
  * Crypto per packet operation
  *
  * Performs the cryptographic operations specified during session creation
- * on the packet.  If the operation is performed synchronously, "posted"
- * will return FALSE and the result of the operation is immediately available
- * in the completion event.  If "posted" returns TRUE the result will be
- * delivered via the completion queue specified when the session was created.
- *
- * @todo Resolve if completion_event is necessary, can/should the output
- *       packet buffer always be used instead.
+ * on the packet.  If the operation is performed synchronously, result will
+ * be returned in completion_event buffer immediately. In case of asynchronous
+ * operation completion event will return ODP_INVALID_BUFFER and the result
+ * will be delivered via the completion queue specified when the session was
+ * created.
  *
- * @param params            Operation parameters
- * @param posted            Pointer to return posted, TRUE for async operation
- * @param completion_event  Event by which the operation results are delivered.
+ * @param[in]  params            Operation parameters
+ * @param[out] completion_event  Pointer to completion event by which the
+ *                               synchronous operation results are delivered.
  *
  * @return 0 if successful else -1
  */
 int
 odp_crypto_operation(odp_crypto_op_params_t *params,
-		     bool *posted,
-		     odp_buffer_t completion_event);
+		     odp_buffer_t *completion_event);
 
 /**
  * Crypto per packet operation set user context in completion event
@@ -297,6 +293,18 @@  void *
 odp_crypto_get_operation_compl_ctx(odp_buffer_t completion_event);
 
 /**
+ * Free completion event
+ *
+ * Completion event is an opaque buffer that is managed by implementation.
+ * The event can't be freed directly, because it can point to an output packet.
+ * This function should be used instead.
+ *
+ * @param completion_event  Event to be freed
+ */
+void
+odp_crypto_operation_compl_free(odp_buffer_t completion_event);
+
+/**
  * Generate random byte string
  *
  * @param buf          Pointer to store result
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index d3cdec7..98cbdb7 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -337,15 +337,14 @@  odp_crypto_session_create(odp_crypto_session_params_t *params,
 
 int
 odp_crypto_operation(odp_crypto_op_params_t *params,
-		     bool *posted,
-		     odp_buffer_t completion_event)
+		     odp_buffer_t *completion_event)
 {
 	enum crypto_alg_err rc_cipher = ODP_CRYPTO_ALG_ERR_NONE;
 	enum crypto_alg_err rc_auth = ODP_CRYPTO_ALG_ERR_NONE;
 	odp_crypto_generic_session_t *session;
 	odp_crypto_generic_op_result_t *result;
+	odp_buffer_t completion;
 
-	*posted = 0;
 	session = (odp_crypto_generic_session_t *)(intptr_t)params->session;
 
 	/* Resolve output buffer */
@@ -357,13 +356,12 @@  odp_crypto_operation(odp_crypto_op_params_t *params,
 		if (odp_unlikely(ODP_PACKET_INVALID == params->out_pkt))
 			abort();
 		odp_packet_copy(params->out_pkt, params->pkt);
-		if (completion_event == odp_packet_to_buffer(params->pkt))
-			completion_event =
-				odp_packet_to_buffer(params->out_pkt);
 		odph_packet_free(params->pkt);
 		params->pkt = ODP_PACKET_INVALID;
 	}
 
+	completion = odp_packet_to_buffer(params->out_pkt);
+
 	/* Invoke the functions */
 	if (session->do_cipher_first) {
 		rc_cipher = session->cipher.func(params, session);
@@ -374,7 +372,7 @@  odp_crypto_operation(odp_crypto_op_params_t *params,
 	}
 
 	/* Build Result (no HW so no errors) */
-	result = get_op_result_from_buffer(completion_event);
+	result = get_op_result_from_buffer(completion);
 	result->magic = OP_RESULT_MAGIC;
 	result->cipher.alg_err = rc_cipher;
 	result->cipher.hw_err = ODP_CRYPTO_HW_ERR_NONE;
@@ -383,8 +381,10 @@  odp_crypto_operation(odp_crypto_op_params_t *params,
 
 	/* If specified during creation post event to completion queue */
 	if (ODP_QUEUE_INVALID != session->compl_queue) {
-		odp_queue_enq(session->compl_queue, completion_event);
-		*posted = 1;
+		odp_queue_enq(session->compl_queue, completion);
+		*completion_event = ODP_BUFFER_INVALID;
+	} else {
+		*completion_event = completion;
 	}
 	return 0;
 }
@@ -421,7 +421,6 @@  odp_hw_random_get(uint8_t *buf, size_t *len, bool use_entropy ODP_UNUSED)
 	rc = RAND_bytes(buf, *len);
 	return ((1 == rc) ? 0 : -1);
 }
-
 void
 odp_crypto_get_operation_compl_status(odp_buffer_t completion_event,
 				      odp_crypto_compl_status_t *auth,
@@ -454,8 +453,13 @@  void
 }
 
 odp_packet_t
-odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event ODP_UNUSED)
+odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event)
 {
-	ODP_UNIMPLEMENTED();
-	return ODP_PACKET_INVALID;
+	return odp_packet_from_buffer(completion_event);
+}
+
+void
+odp_crypto_operation_compl_free(odp_buffer_t completion_event ODP_UNUSED)
+{
+	/* Original packet is used as a completion, so nothing to free */
 }