Next version should be marked API-NEXT, whether or not it is still an
RFC since IPsec APIs cannot move to master until we have a complete
implementation / validation test suite.

I realize this is an RFC, but it doesn't apply to the current api-next:

Applying: linux-gen: ipsec: draft IPsec implementation
Checking patch platform/linux-generic/include/odp_internal.h...
Checking patch platform/linux-generic/include/odp_ipsec_internal.h...
Checking patch platform/linux-generic/include/protocols/ip.h...
Checking patch platform/linux-generic/odp_event.c...
Checking patch platform/linux-generic/odp_init.c...
Checking patch platform/linux-generic/odp_ipsec.c...
error: while searching for:
 */

#include <odp/api/ipsec.h>

#include <string.h>

int odp_ipsec_capability(odp_ipsec_capability_t *capa)
{
memset(capa, 0, sizeof(odp_ipsec_capability_t));

return 0;
}

int odp_ipsec_cipher_capability(odp_cipher_alg_t cipher,
odp_crypto_cipher_capability_t capa[], int num)
{
(void)cipher;
(void)capa;
(void)num;

return -1;
}

int odp_ipsec_auth_capability(odp_auth_alg_t auth,
     odp_crypto_auth_capability_t capa[], int num)
{
(void)auth;
(void)capa;
(void)num;

return -1;
}

void odp_ipsec_config_init(odp_ipsec_config_t *config)
{
memset(config, 0, sizeof(odp_ipsec_config_t));
}

int odp_ipsec_config(const odp_ipsec_config_t *config)
{
(void)config;

return -1;
}

void odp_ipsec_sa_param_init(odp_ipsec_sa_param_t *param)
{
memset(param, 0, sizeof(odp_ipsec_sa_param_t));
}

odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
{
(void)param;

return ODP_IPSEC_SA_INVALID;
}

error: patch failed: platform/linux-generic/odp_ipsec.c:5
Hunk #2 succeeded at 68 (offset -336 lines).
Hunk #3 succeeded at 866 (offset -336 lines).
Hunk #4 succeeded at 916 (offset -336 lines).
Applied patch platform/linux-generic/include/odp_internal.h cleanly.
Applied patch platform/linux-generic/include/odp_ipsec_internal.h cleanly.
Applied patch platform/linux-generic/include/protocols/ip.h cleanly.
Applied patch platform/linux-generic/odp_event.c cleanly.
Applied patch platform/linux-generic/odp_init.c cleanly.
Applying patch platform/linux-generic/odp_ipsec.c with 1 reject...
Rejected hunk #1.
Hunk #2 applied cleanly.
Hunk #3 applied cleanly.
Hunk #4 applied cleanly.
Patch failed at 0001 linux-gen: ipsec: draft IPsec implementation


On Tue, Apr 11, 2017 at 8:41 AM, Dmitry Eremin-Solenikov
<dmitry.ereminsoleni...@linaro.org> wrote:
> For now it's only a preview with the following limitation:
>  - No inline processing support
>  - No SA lookups
>  - Only IPv4 support
>  - No tunnel support
>  - No header modification according to RFCs
>
> Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
> ---
>  platform/linux-generic/include/odp_internal.h      |    4 +
>  .../linux-generic/include/odp_ipsec_internal.h     |   71 ++
>  platform/linux-generic/include/protocols/ip.h      |   52 +
>  platform/linux-generic/odp_event.c                 |    5 +
>  platform/linux-generic/odp_init.c                  |   13 +
>  platform/linux-generic/odp_ipsec.c                 | 1172 
> +++++++++++++++++++-
>  6 files changed, 1287 insertions(+), 30 deletions(-)
>  create mode 100644 platform/linux-generic/include/odp_ipsec_internal.h
>
> diff --git a/platform/linux-generic/include/odp_internal.h 
> b/platform/linux-generic/include/odp_internal.h
> index 05c8a422..fd7848ac 100644
> --- a/platform/linux-generic/include/odp_internal.h
> +++ b/platform/linux-generic/include/odp_internal.h
> @@ -71,6 +71,7 @@ enum init_stage {
>         CLASSIFICATION_INIT,
>         TRAFFIC_MNGR_INIT,
>         NAME_TABLE_INIT,
> +       IPSEC_INIT,
>         MODULES_INIT,
>         ALL_INIT      /* All init stages completed */
>  };
> @@ -130,6 +131,9 @@ int _odp_ishm_init_local(void);
>  int _odp_ishm_term_global(void);
>  int _odp_ishm_term_local(void);
>
> +int odp_ipsec_init_global(void);
> +int odp_ipsec_term_global(void);
> +
>  int _odp_modules_init_global(void);
>
>  int cpuinfo_parser(FILE *file, system_info_t *sysinfo);
> diff --git a/platform/linux-generic/include/odp_ipsec_internal.h 
> b/platform/linux-generic/include/odp_ipsec_internal.h
> new file mode 100644
> index 00000000..c7620b88
> --- /dev/null
> +++ b/platform/linux-generic/include/odp_ipsec_internal.h
> @@ -0,0 +1,71 @@
> +/* Copyright (c) 2017, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:    BSD-3-Clause
> + */
> +
> +/**
> + * @file
> + *
> + * ODP internal IPsec routines
> + */
> +
> +#ifndef ODP_IPSEC_INTERNAL_H_
> +#define ODP_IPSEC_INTERNAL_H_
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <odp/api/std_types.h>
> +#include <odp/api/plat/strong_types.h>
> +
> +/** @ingroup odp_ipsec
> + *  @{
> + */
> +
> +typedef ODP_HANDLE_T(odp_ipsec_op_result_event_t);
> +
> +#define ODP_IPSEC_OP_RESULT_EVENT_INVALID \
> +       _odp_cast_scalar(odp_ipsec_op_result_event_t, 0xffffffff)
> +
> +/**
> + * Get ipsec_op_result_event handle from event
> + *
> + * Converts an ODP_EVENT_IPSEC_RESULT_EVENT type event to an IPsec result 
> event.
> + *
> + * @param ev   Event handle
> + *
> + * @return IPsec result handle
> + *
> + * @see odp_event_type()
> + */
> +odp_ipsec_op_result_event_t odp_ipsec_op_result_event_from_event(odp_event_t 
> ev);

The odp_ipsec_result() API is already defined. No need to invent a new one.

> +
> +/**
> + * Convert IPsec result event handle to event
> + *
> + * @param res  IPsec result handle
> + *
> + * @return Event handle
> + */
> +odp_event_t odp_ipsec_op_result_event_to_event(odp_ipsec_op_result_event_t 
> res);
> +
> +/**
> + * Free IPsec result event
> + *
> + * Frees the ipsec_op_result_event into the ipsec_op_result_event pool it 
> was allocated from.
> + *
> + * @param res           IPsec result handle
> + */
> +void odp_ipsec_op_result_event_free(odp_ipsec_op_result_event_t res);

For consistency with other free routines this would be
odp_ipsec_result_free(), and odp_event_free() would be extended to
cover this event type as well.

These APIs cannot be defined here, they need to be in
include/odp/api/spec/ipsec.h

> +
> +/**
> + * @}
> + */
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> diff --git a/platform/linux-generic/include/protocols/ip.h 
> b/platform/linux-generic/include/protocols/ip.h
> index 2b34a753..9f3e1616 100644
> --- a/platform/linux-generic/include/protocols/ip.h
> +++ b/platform/linux-generic/include/protocols/ip.h
> @@ -89,6 +89,58 @@ typedef struct ODP_PACKED {
>  ODP_STATIC_ASSERT(sizeof(_odp_ipv4hdr_t) == _ODP_IPV4HDR_LEN,
>                   "_ODP_IPV4HDR_T__SIZE_ERROR");
>
> +/**
> + * Checksum
> + *
> + * @param buffer calculate chksum for buffer
> + * @param len    buffer length
> + *
> + * @return checksum value in host cpu order
> + */
> +static inline odp_u16sum_t _odp_chksum(void *buffer, int len)
> +{
> +       uint16_t *buf = (uint16_t *)buffer;
> +       uint32_t sum = 0;
> +       uint16_t result;
> +
> +       for (sum = 0; len > 1; len -= 2)
> +               sum += *buf++;
> +
> +       if (len == 1)
> +               sum += *(unsigned char *)buf;
> +
> +       sum = (sum >> 16) + (sum & 0xFFFF);
> +       sum += (sum >> 16);
> +       result = ~sum;
> +
> +       return  (__odp_force odp_u16sum_t) result;
> +}
> +
> +/**
> + * Calculate and fill in IPv4 checksum
> + *
> + * @note when using this api to populate data destined for the wire
> + * odp_cpu_to_be_16() can be used to remove sparse warnings
> + *
> + * @param pkt  ODP packet
> + *
> + * @return IPv4 checksum in host cpu order, or 0 on failure
> + */
> +static inline odp_u16sum_t _odp_ipv4_csum_update(odp_packet_t pkt)
> +{
> +       uint16_t *w;
> +       _odp_ipv4hdr_t *ip;
> +       int nleft = sizeof(_odp_ipv4hdr_t);
> +
> +       ip = (_odp_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
> +       if (ip == NULL)
> +               return 0;
> +
> +       w = (uint16_t *)(void *)ip;
> +       ip->chksum = _odp_chksum(w, nleft);
> +       return ip->chksum;
> +}
> +
>  /** IPv6 version */
>  #define _ODP_IPV6 6
>
> diff --git a/platform/linux-generic/odp_event.c 
> b/platform/linux-generic/odp_event.c
> index d71f4464..1a2cc0aa 100644
> --- a/platform/linux-generic/odp_event.c
> +++ b/platform/linux-generic/odp_event.c
> @@ -7,10 +7,12 @@
>  #include <odp/api/event.h>
>  #include <odp/api/buffer.h>
>  #include <odp/api/crypto.h>
> +#include <odp/api/ipsec.h>
>  #include <odp/api/packet.h>
>  #include <odp/api/timer.h>
>  #include <odp/api/pool.h>
>  #include <odp_buffer_internal.h>
> +#include <odp_ipsec_internal.h>
>  #include <odp_buffer_inlines.h>
>  #include <odp_debug_internal.h>
>
> @@ -34,6 +36,9 @@ void odp_event_free(odp_event_t event)
>         case ODP_EVENT_CRYPTO_COMPL:
>                 odp_crypto_compl_free(odp_crypto_compl_from_event(event));
>                 break;
> +       case ODP_EVENT_IPSEC_RESULT:
> +               
> odp_ipsec_op_result_event_free(odp_ipsec_op_result_event_from_event(event));

For consistency with other names this should be:
odp_ipsec_result_free(odp_ipsec_result_from_event(event));

The cast function in the other direction would be odp_ipsec_result_to_event().

> +               break;
>         default:
>                 ODP_ABORT("Invalid event type: %d\n", odp_event_type(event));
>         }
> diff --git a/platform/linux-generic/odp_init.c 
> b/platform/linux-generic/odp_init.c
> index 685e02fa..bebcc62e 100644
> --- a/platform/linux-generic/odp_init.c
> +++ b/platform/linux-generic/odp_init.c
> @@ -266,6 +266,12 @@ int odp_init_global(odp_instance_t *instance,
>         }
>         stage = NAME_TABLE_INIT;
>
> +       if (odp_ipsec_init_global()) {
> +               ODP_ERR("ODP IPsec init failed.\n");
> +               goto init_failed;
> +       }
> +       stage = IPSEC_INIT;
> +
>         if (_odp_modules_init_global()) {
>                 ODP_ERR("ODP modules init failed\n");
>                 goto init_failed;
> @@ -296,6 +302,13 @@ int _odp_term_global(enum init_stage stage)
>         switch (stage) {
>         case ALL_INIT:
>         case MODULES_INIT:
> +       case IPSEC_INIT:
> +               if (odp_ipsec_term_global()) {
> +                       ODP_ERR("ODP IPsec term failed.\n");
> +                       rc = -1;
> +               }
> +               /* Fall through */
> +
>         case NAME_TABLE_INIT:
>                 if (_odp_int_name_tbl_term_global()) {
>                         ODP_ERR("Name table term failed.\n");
> diff --git a/platform/linux-generic/odp_ipsec.c 
> b/platform/linux-generic/odp_ipsec.c
> index 10918dfb..2cc4c690 100644
> --- a/platform/linux-generic/odp_ipsec.c
> +++ b/platform/linux-generic/odp_ipsec.c
> @@ -5,56 +5,392 @@
>   */
>
>  #include <odp/api/ipsec.h>
> +#include <odp/api/packet.h>
> +#include <odp/api/shared_memory.h>
> +#include <odp/api/ticketlock.h>
> +
> +#include <odp_buffer_internal.h>
> +#include <odp_buffer_inlines.h>
> +#include <odp_debug_internal.h>
> +#include <odp_ipsec_internal.h>
> +#include <odp_pool_internal.h>
> +
> +#include <odp/api/plat/ticketlock_inlines.h>
> +
> +#include <protocols/ip.h>
> +#include <protocols/ipsec.h>
>
>  #include <string.h>
> +#include <stdbool.h>
> +
> +#define ODP_CONFIG_IPSEC_SAS   8
> +
> +#define MAX_IV_LEN             32   /**< Maximum IV length in bytes */
> +
> +typedef struct ipsec_sa_t {
> +       odp_ticketlock_t lock ODP_ALIGNED_CACHE;
> +       int reserved;

Why does a brand new struct need a reserved field like this?

> +       odp_ipsec_sa_t  ipsec_sa_hdl;
> +       uint32_t        ipsec_sa_idx;
> +
> +       odp_crypto_session_t session;
> +       odp_bool_t      in_place;
> +       void            *context;
> +       odp_queue_t     queue;
> +
> +       uint32_t        ah_icv_len;
> +       uint32_t        esp_iv_len;
> +       uint32_t        esp_block_len;
> +       uint32_t        spi;
> +       uint32_t        seq;
> +       uint8_t         iv[MAX_IV_LEN];  /**< ESP IV storage */
> +} ipsec_sa_t;
> +
> +typedef struct ipsec_sa_table_t {
> +       ipsec_sa_t ipsec_sa[ODP_CONFIG_IPSEC_SAS];
> +       odp_shm_t shm;
> +} ipsec_sa_table_t;
> +
> +static ipsec_sa_table_t *ipsec_sa_tbl;
> +
> +typedef struct odp_ipsec_ctx_s odp_ipsec_ctx_t;
> +
> +typedef void (*odp_ipsecproc_t)(odp_packet_t pkt, odp_ipsec_ctx_t *ctx);

The odp_ prefix should only be used for external ODP APIs. Use
_odp_ipsecproc_t for internal "ODP" routines, or just have private
names without a prefix. Same comment throughout for other internal
names that use the odp_ prefix here.
I realize we weren't always consistent in this convention, but we're
trying to keep to it for new development.

> +
> +/**
> + * Per packet IPsec processing context
> + */
> +struct odp_ipsec_ctx_s {
> +       odp_buffer_t buffer;     /**< Buffer for context */
> +       odp_ipsec_ctx_t *next;   /**< Next context in event */
> +
> +       uint8_t  ip_tos;         /**< Saved IP TOS value */
> +       uint16_t ip_frag_offset; /**< Saved IP flags value */
> +       uint8_t  ip_ttl;         /**< Saved IP TTL value */
> +       int      hdr_len;        /**< Length of IPsec headers */
> +       int      trl_len;        /**< Length of IPsec trailers */
> +       uint16_t tun_hdr_offset; /**< Offset of tunnel header from
> +                                     buffer start */
> +       uint16_t ah_offset;      /**< Offset of AH header from buffer start */
> +       uint16_t esp_offset;     /**< Offset of ESP header from buffer start 
> */
> +
> +       odp_ipsecproc_t postprocess;
> +       odp_ipsec_sa_t sa;
> +       odp_crypto_op_result_t crypto;
> +       odp_ipsec_op_status_t status;
> +
> +       /* Input only */
> +       uint32_t src_ip;         /**< SA source IP address */
> +       uint32_t dst_ip;         /**< SA dest IP address */
> +
> +       /* Output only */
> +       uint32_t *ah_seq;               /**< AH sequence number location */
> +       uint32_t *esp_seq;              /**< ESP sequence number location */
> +       uint16_t *tun_hdr_id;           /**< Tunnel header ID > */
> +};
> +
> +typedef struct {
> +       /* common buffer header */
> +       odp_buffer_hdr_t buf_hdr;
> +       odp_ipsec_ctx_t *ctx;
> +} odp_ipsec_op_result_event_hdr_t;
> +
> +#define SHM_CTX_POOL_BUF_COUNT 1024
> +
> +static odp_pool_t odp_odp_ipsec_ctx_pool = ODP_POOL_INVALID;

The duplicated prefix (odp_odp_...) looks odd here. Isn't one prefix sufficient?

> +static odp_pool_t odp_ipsec_op_result_pool = ODP_POOL_INVALID;
> +
> +static inline ipsec_sa_t *ipsec_sa_entry(uint32_t ipsec_sa_idx)
> +{
> +       return &ipsec_sa_tbl->ipsec_sa[ipsec_sa_idx];
> +}
> +
> +static inline ipsec_sa_t *ipsec_sa_entry_from_hdl(odp_ipsec_sa_t 
> ipsec_sa_hdl)
> +{
> +       return ipsec_sa_entry(_odp_typeval(ipsec_sa_hdl));
> +}
> +
> +static inline odp_ipsec_sa_t ipsec_sa_index_to_handle(uint32_t ipsec_sa_idx)
> +{
> +       return _odp_cast_scalar(odp_ipsec_sa_t, ipsec_sa_idx);
> +}
> +
> +int odp_ipsec_init_global(void)
> +{
> +       uint32_t i;
> +       odp_shm_t shm;
> +       odp_pool_param_t params;
> +
> +       /* Create context buffer pool */
> +       params.buf.size  = sizeof(odp_ipsec_ctx_t);
> +       params.buf.align = 0;
> +       params.buf.num   = SHM_CTX_POOL_BUF_COUNT;

Why this constant? Shouldn't this be something more IPsec-specific?

> +       params.type      = ODP_POOL_BUFFER;
> +
> +       odp_odp_ipsec_ctx_pool = odp_pool_create("odp_odp_ipsec_ctx_pool", 
> &params);
> +       if (ODP_POOL_INVALID == odp_odp_ipsec_ctx_pool) {
> +               ODP_ERR("Error: context pool create failed.\n");
> +               return -1;
> +       }
> +
> +       params.buf.size  = sizeof(odp_ipsec_op_result_event_hdr_t);
> +       params.buf.align = 0;
> +       params.buf.num   = SHM_CTX_POOL_BUF_COUNT;
> +       params.type      = ODP_POOL_BUFFER;
> +
> +       odp_ipsec_op_result_pool = 
> odp_pool_create("odp_ipsec_op_result_pool", &params);
> +       if (ODP_POOL_INVALID == odp_ipsec_op_result_pool) {
> +               ODP_ERR("Error: result pool create failed.\n");
> +               odp_pool_destroy(odp_odp_ipsec_ctx_pool);

Need at least a (void) here or else an RC check to keep tools like
Coverity happy.

> +               return -1;
> +       }
> +
> +       shm = odp_shm_reserve("_odp_ipsec_sa_table",
> +                             sizeof(ipsec_sa_table_t),
> +                             ODP_CACHE_LINE_SIZE, 0);
> +
> +       ipsec_sa_tbl = odp_shm_addr(shm);
> +       if (ipsec_sa_tbl == NULL) {
> +               odp_pool_destroy(odp_ipsec_op_result_pool);
> +               odp_pool_destroy(odp_odp_ipsec_ctx_pool);

Same as above. Add (void) here to keep Coverity happy.

> +               return -1;
> +       }
> +
> +       memset(ipsec_sa_tbl, 0, sizeof(ipsec_sa_table_t));
> +       ipsec_sa_tbl->shm = shm;
> +
> +       for (i = 0; i < ODP_CONFIG_IPSEC_SAS; i++) {
> +               ipsec_sa_t *ipsec_sa = ipsec_sa_entry(i);
> +
> +               odp_ticketlock_init(&ipsec_sa->lock);
> +               ipsec_sa->ipsec_sa_hdl = ipsec_sa_index_to_handle(i);
> +               ipsec_sa->ipsec_sa_idx = i;
> +       }
> +
> +       return 0;
> +}
> +
> +int odp_ipsec_term_global(void)
> +{
> +       int i;
> +       ipsec_sa_t *ipsec_sa;
> +       int ret = 0;
> +       int rc = 0;
> +
> +       ret = odp_pool_destroy(odp_odp_ipsec_ctx_pool);
> +       if (ret < 0) {
> +               ODP_ERR("ctx pool destroy failed");
> +               rc = -1;
> +       }
> +
> +       for (i = 0; i < ODP_CONFIG_IPSEC_SAS; i++) {
> +               ipsec_sa = ipsec_sa_entry(i);
> +
> +               odp_ticketlock_lock(&ipsec_sa->lock);
> +               if (ipsec_sa->reserved) {
> +                       ODP_ERR("Not destroyed ipsec_sa: %u\n", 
> ipsec_sa->ipsec_sa_idx);
> +                       rc = -1;
> +               }
> +               ipsec_sa->reserved = 1;
> +               odp_ticketlock_unlock(&ipsec_sa->lock);
> +       }

Looks like this loop should go ahead of the odp_pool_destroy. Best to
keep the term sequence a mirror of the init sequence.

> +
> +       ret = odp_shm_free(ipsec_sa_tbl->shm);
> +       if (ret < 0) {
> +               ODP_ERR("shm free failed");
> +               rc = -1;
> +       }

You're missing an odp_pool_destroy() for the odp_ipsec_op_result_pool here

> +
> +       return rc;
> +}
> +
> +static ipsec_sa_t *reserve_ipsec_sa(void)
> +{
> +       int i;
> +       ipsec_sa_t *ipsec_sa;
> +
> +       for (i = 0; i < ODP_CONFIG_IPSEC_SAS; i++) {
> +               ipsec_sa = ipsec_sa_entry(i);
> +
> +               odp_ticketlock_lock(&ipsec_sa->lock);
> +               if (ipsec_sa->reserved == 0) {
> +                       ipsec_sa->reserved = 1;
> +                       odp_ticketlock_unlock(&ipsec_sa->lock);
> +
> +                       return ipsec_sa;
> +               }
> +               odp_ticketlock_unlock(&ipsec_sa->lock);
> +       }
> +
> +       return NULL;
> +}
>
>  int odp_ipsec_capability(odp_ipsec_capability_t *capa)
>  {
> +       int rc;
> +       odp_crypto_capability_t crypto_capa;
> +
>         memset(capa, 0, sizeof(odp_ipsec_capability_t));
>
> +       rc = odp_crypto_capability(&crypto_capa);
> +       if (rc < 0)
> +               return rc;
> +
> +       capa->max_num_sa = ODP_CONFIG_IPSEC_SAS;
> +       capa->op_mode_sync = 2;

The spec is documented this way, but magic numbers like this always
look somewhat jarring. We should be using enums for this. We should
propose an IPsec API change for that.

> +       capa->ciphers = crypto_capa.ciphers;
> +       capa->auths = crypto_capa.auths;
> +
>         return 0;
>  }
>
>  int odp_ipsec_cipher_capability(odp_cipher_alg_t cipher,
>                                 odp_crypto_cipher_capability_t capa[], int 
> num)
>  {
> -       (void)cipher;
> -       (void)capa;
> -       (void)num;
> -
> -       return -1;
> +       return odp_crypto_cipher_capability(cipher, capa, num);
>  }
>
>  int odp_ipsec_auth_capability(odp_auth_alg_t auth,
>                               odp_crypto_auth_capability_t capa[], int num)
>  {
> -       (void)auth;
> -       (void)capa;
> -       (void)num;
> -
> -       return -1;
> +       return odp_crypto_auth_capability(auth, capa, num);
>  }
>
>  void odp_ipsec_config_init(odp_ipsec_config_t *config)
>  {
>         memset(config, 0, sizeof(odp_ipsec_config_t));
> +       config->inbound_mode = ODP_IPSEC_OP_MODE_SYNC;
> +       config->outbound_mode = ODP_IPSEC_OP_MODE_SYNC;
> +       config->max_num_sa = ODP_CONFIG_IPSEC_SAS;
> +       config->inbound.default_queue = ODP_QUEUE_INVALID;
> +       config->inbound.lookup.min_spi = 0;
> +       config->inbound.lookup.max_spi = UINT32_MAX;
> +       config->outbound.default_queue = ODP_QUEUE_INVALID;
>  }
>
> +static odp_ipsec_config_t ipsec_config;
> +
>  int odp_ipsec_config(const odp_ipsec_config_t *config)
>  {
> -       (void)config;
> +       /* FIXME: unsupported for now */
> +       if (ODP_IPSEC_OP_MODE_INLINE == config->outbound_mode)
> +               return -1;
>
> -       return -1;
> +       /* FIXME: unsupported for now */
> +       if (ODP_IPSEC_OP_MODE_INLINE == config->inbound_mode)
> +               return -1;
> +
> +       ipsec_config = *config;
> +
> +       return 0;
>  }
>
>  void odp_ipsec_sa_param_init(odp_ipsec_sa_param_t *param)
>  {
>         memset(param, 0, sizeof(odp_ipsec_sa_param_t));
> +       param->dest_queue = ODP_QUEUE_INVALID;
>  }
>
>  odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
>  {
> -       (void)param;
> +       ipsec_sa_t *ipsec_sa;
> +       odp_crypto_session_param_t crypto_param;
> +       odp_crypto_ses_create_err_t ses_create_rc;
> +
> +       ipsec_sa = reserve_ipsec_sa();
> +       if (NULL == ipsec_sa) {
> +               ODP_ERR("No more free SA\n");
> +               return ODP_IPSEC_SA_INVALID;
> +       }
> +
> +#if 1
> +       ipsec_sa->in_place = false;
> +#else
> +       ipsec_sa->in_place = true;
> +#endif
> +       ipsec_sa->spi = param->spi;
> +       ipsec_sa->seq = param->seq;
> +       ipsec_sa->context = param->context;
> +       ipsec_sa->queue = param->dest_queue;
> +
> +       odp_crypto_session_param_init(&crypto_param);
> +
> +       /* Setup parameters and call crypto library to create session */
> +       crypto_param.op = (ODP_IPSEC_DIR_INBOUND == param->dir) ?
> +                       ODP_CRYPTO_OP_DECODE :
> +                       ODP_CRYPTO_OP_ENCODE;
> +       crypto_param.auth_cipher_text = 1;
> +
> +       // FIXME: is it possible to use ASYNC crypto with ASYNC IPsec?

Did you mean to say SYNC crypto here, since that's what you're doing?

> +       crypto_param.pref_mode   = ODP_CRYPTO_SYNC;
> +       crypto_param.compl_queue = ODP_QUEUE_INVALID;
> +       crypto_param.output_pool = ODP_POOL_INVALID;
> +
> +       crypto_param.cipher_alg = param->crypto.cipher_alg;
> +       crypto_param.cipher_key = param->crypto.cipher_key;
> +       crypto_param.auth_alg = param->crypto.auth_alg;
> +       crypto_param.auth_key = param->crypto.auth_key;
> +
> +       switch (crypto_param.auth_alg) {
> +       case ODP_AUTH_ALG_NULL:
> +               ipsec_sa->ah_icv_len = 0;
> +               break;
> +       case ODP_AUTH_ALG_MD5_HMAC:
> +       case ODP_AUTH_ALG_MD5_96:
> +               ipsec_sa->ah_icv_len = 12;
> +               break;
> +       case ODP_AUTH_ALG_SHA1_HMAC:
> +               ipsec_sa->ah_icv_len = 12;
> +               break;
> +       case ODP_AUTH_ALG_SHA256_HMAC:
> +       case ODP_AUTH_ALG_SHA256_128:
> +               ipsec_sa->ah_icv_len = 16;
> +               break;
> +       case ODP_AUTH_ALG_SHA512_HMAC:
> +               ipsec_sa->ah_icv_len = 32;
> +               break;
> +       default:
> +               return ODP_IPSEC_SA_INVALID;
> +       }
> +
> +       switch (crypto_param.cipher_alg) {
> +       case ODP_CIPHER_ALG_NULL:
> +               ipsec_sa->esp_iv_len = 0;
> +               ipsec_sa->esp_block_len = 0;
> +               break;
> +       case ODP_CIPHER_ALG_DES:
> +       case ODP_CIPHER_ALG_3DES_CBC:
> +               ipsec_sa->esp_iv_len = 8;
> +               ipsec_sa->esp_block_len = 8;
> +               break;
> +       case ODP_CIPHER_ALG_AES_CBC:
> +       case ODP_CIPHER_ALG_AES128_CBC:
> +       case ODP_CIPHER_ALG_AES_GCM:
> +       case ODP_CIPHER_ALG_AES128_GCM:
> +               ipsec_sa->esp_iv_len = 16;
> +               ipsec_sa->esp_block_len = 16;
> +               break;
> +       }
> +
> +       /* Generate an IV */
> +       if (ipsec_sa->esp_iv_len) {
> +               crypto_param.iv.data = ipsec_sa->iv;
> +               crypto_param.iv.length = 
> odp_random_data(crypto_param.iv.data, ipsec_sa->esp_iv_len, 1);

The odp_random_data() API has been changed. This call should now be:
crypto_param.iv.length = odp_random_data(crypto_param.iv.data,
ipsec_sa->esp_iv_len, ODP_RANDOM_CRYPTO);

> +               if (crypto_param.iv.length != ipsec_sa->esp_iv_len)
> +                       goto error;
> +       }
> +
> +       if (odp_crypto_session_create(&crypto_param, &ipsec_sa->session, 
> &ses_create_rc))
> +               goto error;
> +       if (ODP_CRYPTO_SES_CREATE_ERR_NONE != ses_create_rc)
> +               goto error;
> +
> +       return ipsec_sa->ipsec_sa_hdl;
> +
> +error:
> +       odp_ticketlock_lock(&ipsec_sa->lock);
> +       ipsec_sa->reserved = 1;
> +       odp_ticketlock_unlock(&ipsec_sa->lock);

Since you reserve with reserve_ipsec_sa() you should create a
free_ipsec_sa() counterpart to keep things at the same semantic level.
Also since reserve_ipsec_sa() changes ipsec_sa->reserved from 0 to 1,
I'd assume that free() should set it back to 0, no?

>
>         return ODP_IPSEC_SA_INVALID;
>  }
> @@ -68,41 +404,790 @@ int odp_ipsec_sa_disable(odp_ipsec_sa_t sa)
>
>  int odp_ipsec_sa_destroy(odp_ipsec_sa_t sa)
>  {
> -       (void)sa;
> +       ipsec_sa_t *ipsec_sa = ipsec_sa_entry_from_hdl(sa);
> +       int rc = 0;
>
> -       return -1;
> +       odp_ticketlock_lock(&ipsec_sa->lock);
> +       if (ipsec_sa->reserved) {
> +               ODP_ERR("Destroying unallocated ipsec_sa: %u\n", 
> ipsec_sa->ipsec_sa_idx);
> +               rc = -1;
> +       } else {
> +               if (odp_crypto_session_destroy(ipsec_sa->session) < 0) {
> +                       ODP_ERR("Error destroying crypto session for 
> ipsec_sa: %u\n", ipsec_sa->ipsec_sa_idx);
> +                       rc = -1;
> +               }
> +
> +               ipsec_sa->reserved = 1;

Again having a common wrapper for reserving/freeing SAs makes sense.
Also since the area is cleared at init, reserved == 0 means free, no?

> +       }
> +       odp_ticketlock_unlock(&ipsec_sa->lock);
> +
> +       return rc;
> +}
> +
> +#define ipv4_data_p(ip) ((uint8_t *)((_odp_ipv4hdr_t *)ip + 1))
> +#define ipv4_data_len(ip) (odp_be_to_cpu_16(ip->tot_len) - 
> sizeof(_odp_ipv4hdr_t))

These simple definitions don't work if IP options are present. You
should use the IP hdr len field of the IP hdr to get the actual size.
(_ODP_IPV4HDR_IHL).

> +static inline
> +void ipv4_adjust_len(_odp_ipv4hdr_t *ip, int adj)
> +{
> +       ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) + adj);
> +}
> +
> +/**
> + * Verify crypto operation completed successfully
> + *
> + * @param status  Pointer to cryto completion structure
> + *
> + * @return true if all OK else false
> + */
> +static inline
> +odp_bool_t is_crypto_compl_status_ok(odp_crypto_compl_status_t *status)
> +{
> +       if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE)
> +               return false;
> +       if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE)
> +               return false;
> +       return true;

This could be simplified as:
return status->alg_err == ODP_CRYPTO_ALG_ERR_NONE && status->hw_err ==
ODP_CRYPTO_HW_ERR_NONE;

> +}
> +
> +/**
> + * Allocate per packet processing context and associate it with
> + * packet buffer
> + *
> + * @param pkt  Packet
> + *
> + * @return pointer to context area
> + */
> +static
> +odp_ipsec_ctx_t *odp_ipsec_alloc_pkt_ctx(void)
> +{
> +       odp_buffer_t ctx_buf = odp_buffer_alloc(odp_odp_ipsec_ctx_pool);
> +       odp_ipsec_ctx_t *ctx;
> +
> +       if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf))
> +               return NULL;
> +
> +       ctx = odp_buffer_addr(ctx_buf);
> +       memset(ctx, 0, sizeof(*ctx));
> +       ctx->buffer = ctx_buf;
> +
> +       return ctx;
> +}
> +
> +/**
> + * Release per packet resources
> + *
> + * @param ctx  Packet context
> + */
> +static
> +void odp_ipsec_free_pkt_ctx(odp_ipsec_ctx_t *ctx)
> +{
> +       if (ODP_PACKET_INVALID != ctx->crypto.pkt)
> +               odp_packet_free(ctx->crypto.pkt);
> +
> +       odp_buffer_free(ctx->buffer);
> +}
> +
> +odp_ipsec_op_result_event_t odp_ipsec_op_result_event_from_event(odp_event_t 
> ev)
> +{
> +       if (odp_unlikely(ODP_EVENT_INVALID == ev))
> +               return ODP_IPSEC_OP_RESULT_EVENT_INVALID;
> +
> +       if (odp_event_type(ev) != ODP_EVENT_IPSEC_RESULT)
> +               ODP_ABORT("Event not an IPsec result");
> +
> +       return (odp_ipsec_op_result_event_t)ev;
> +}

The type here is odp_ipsec_result_t, so as noted earlier this should
be named odp_ipsec_result_from_event() and use
ODP_IPSEC_RESULT_INVALID as the invalid value.

> +
> +static odp_ipsec_op_result_event_hdr_t 
> *ipsec_op_result_event_hdr_from_buf(odp_buffer_t buf)
> +{
> +       return (odp_ipsec_op_result_event_hdr_t *)(void *)buf_hdl_to_hdr(buf);

I'd simplify the internal struct name to ipsec_result_hdr_t or even
ipsec_result_t. No odp_ prefix, or perhaps _odp.

> +}
> +
> +static odp_ipsec_op_result_event_hdr_t 
> *ipsec_op_result_event_hdr(odp_ipsec_op_result_event_t res)

Better:
static ipsec_result_t *ipsec_result_from_event(odp_ipsec_result_t res)

> +{
> +       odp_buffer_t buf = 
> odp_buffer_from_event(odp_ipsec_op_result_event_to_event(res));
> +
> +       return ipsec_op_result_event_hdr_from_buf(buf);
> +}
> +
> +odp_event_t odp_ipsec_op_result_event_to_event(odp_ipsec_op_result_event_t 
> res)

The API should be named odp_ipsec_result_to_event() for consistency
with the other event cast functions.

> +{
> +       if (odp_unlikely(res == ODP_IPSEC_OP_RESULT_EVENT_INVALID))
> +               return ODP_EVENT_INVALID;
> +
> +       return (odp_event_t)res;
> +}
> +
> +static
> +odp_ipsec_op_result_event_t odp_ipsec_op_result_event_alloc(void)

static odp_ipsec_result_t odp_ipsec_result_alloc(void)

> +{
> +       odp_buffer_t buf = odp_buffer_alloc(odp_ipsec_op_result_pool);
> +
> +       if (odp_unlikely(buf == ODP_BUFFER_INVALID))
> +               return ODP_IPSEC_OP_RESULT_EVENT_INVALID;
> +
> +       _odp_buffer_event_type_set(buf, ODP_EVENT_IPSEC_RESULT);
> +
> +       return odp_ipsec_op_result_event_from_event(odp_buffer_to_event(buf));
> +}
> +
> +void odp_ipsec_op_result_event_free(odp_ipsec_op_result_event_t res)

void odp_ipsec_result_free(odp_ipsec_result_t res)

> +{
> +       odp_event_t ev = odp_ipsec_op_result_event_to_event(res);
> +       odp_ipsec_op_result_event_hdr_t *res_hdr;
> +
> +       res_hdr = ipsec_op_result_event_hdr(res);
> +       while (NULL != res_hdr->ctx) {
> +               odp_ipsec_ctx_t *ctx = res_hdr->ctx;
> +
> +               res_hdr->ctx = ctx->next;
> +               odp_ipsec_free_pkt_ctx(ctx);
> +       }
> +
> +       odp_buffer_free(odp_buffer_from_event(ev));
> +}

We'll likely need corresponding odp_ipsec_status_alloc/free() routines
for those as well.

> +
> +static
> +void odp_ipsec_postprocess(odp_packet_t pkt, odp_ipsec_ctx_t *ctx)
> +{
> +       _odp_ipv4hdr_t *ip;
> +       int hdr_len;
> +       int trl_len = 0;
> +
> +       ip = (_odp_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
> +       hdr_len = ctx->hdr_len;
> +
> +       /*
> +        * Finish auth
> +        */
> +       if (ctx->ah_offset) {
> +               uint8_t *buf = odp_packet_data(pkt);
> +               _odp_ahhdr_t *ah;
> +
> +               ah = (_odp_ahhdr_t *)(ctx->ah_offset + buf);
> +               ip->proto = ah->next_header;
> +       }
> +
> +       /*
> +        * Finish cipher by finding ESP trailer and processing
> +        *
> +        * FIXME: ESP authentication ICV not supported
> +        */
> +       if (ctx->esp_offset) {
> +               uint8_t *eop = (uint8_t *)(ip) + 
> odp_be_to_cpu_16(ip->tot_len);
> +               _odp_esptrl_t *esp_t = (_odp_esptrl_t *)(eop) - 1;
> +
> +               ip->proto = esp_t->next_header;
> +               trl_len += esp_t->pad_len + sizeof(*esp_t);
> +       }
> +
> +       /* We have a tunneled IPv4 packet */
> +       if (ip->proto == _ODP_IPV4) {
> +               odp_packet_pull_head(pkt, sizeof(*ip));

Again, need to account for possible IP options.

> +       } else {
> +               /* Finalize the IPv4 header */
> +               ipv4_adjust_len(ip, -(hdr_len + trl_len));
> +               ip->ttl = ctx->ip_ttl;
> +               ip->tos = ctx->ip_tos;
> +               ip->frag_offset = odp_cpu_to_be_16(ctx->ip_frag_offset);
> +               ip->chksum = 0;
> +               _odp_ipv4_csum_update(pkt);
> +
> +               /* Correct the packet length and move payload into position */
> +               memmove(((uint8_t *)ip) + hdr_len, ip, sizeof(*ip));

You should use odp_packet_move_data() here as that routine
automagically handles any packet segmentation.

> +       }
> +
> +       odp_packet_pull_head(pkt, hdr_len);
> +       odp_packet_pull_tail(pkt, trl_len);
>  }
>
> +static
> +int odp_ipsec_finish(odp_ipsec_ctx_t *ctx,
> +                    odp_ipsec_packet_result_t *res,
> +                    odp_packet_t *pkt)
> +{
> +       odp_crypto_op_result_t *result = &ctx->crypto;
> +
> +       res->status = ctx->status;
> +
> +       /* Check crypto result */
> +       if (!result->ok) {
> +               if (!is_crypto_compl_status_ok(&result->cipher_status)) {
> +                       res->status.error.alg = 1;
> +                       return -1;
> +               }
> +               if (!is_crypto_compl_status_ok(&result->auth_status)) {
> +                       res->status.error.auth = 1;
> +                       return -1;
> +               }
> +       }
> +
> +       if (ctx->postprocess) {
> +               ctx->postprocess(result->pkt, ctx);
> +               ctx->postprocess = NULL;
> +       }
> +
> +       *pkt = result->pkt;
> +       result->pkt = ODP_PACKET_INVALID;
> +
> +       res->sa = ctx->sa;
> +
> +       return 1;
> +}
> +
> +static
> +int odp_ipsec_in_single(odp_packet_t pkt,
> +                       odp_ipsec_sa_t sa,
> +                       odp_ipsec_ctx_t *ctx)

odp_ prefix is particularly confusing here since the external API is
odp_ipsec_in()

> +{
> +       ipsec_sa_t *ipsec_sa;
> +       uint8_t *buf = odp_packet_data(pkt);
> +       _odp_ipv4hdr_t *ip = (_odp_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
> +       int hdr_len;
> +       _odp_ahhdr_t *ah = NULL;
> +       _odp_esphdr_t *esp = NULL;
> +       odp_crypto_op_param_t params;
> +       odp_bool_t posted = 0;
> +       uint8_t *in = ipv4_data_p(ip);
> +       int rc;
> +
> +       ctx->status.all_error = 0;
> +       ctx->status.all_flag = 0;
> +
> +       if (ODP_IPSEC_SA_INVALID == sa) {
> +               ctx->status.error.sa_lookup = 1;
> +               return -1;
> +       }
> +
> +       ipsec_sa = ipsec_sa_entry_from_hdl(sa);
> +       if (odp_unlikely(NULL == ipsec_sa)) {
> +               ctx->status.error.alg = 1;
> +               return -1;
> +       }
> +
> +       /* Check IP header for IPSec protocols and look it up */
> +       if (_ODP_IPPROTO_AH == ip->proto) {
> +               ah = (_odp_ahhdr_t *)in;
> +               in += ((ah)->ah_len + 2) * 4;
> +       } else if (_ODP_IPPROTO_ESP == ip->proto) {
> +               esp = (_odp_esphdr_t *)in;
> +               in += sizeof(_odp_esphdr_t);
> +       } else {
> +               ctx->status.error.proto = 1;
> +               return -1;
> +       }

We already have the odp_packet_has_ipsec() API that queries
IPsec-related fields set by the classifier. Not sure if that's useful
here.

> +
> +       hdr_len = in - (ipv4_data_p(ip));
> +
> +       /* Account for configured ESP IV length in packet */
> +       hdr_len += ipsec_sa->esp_iv_len;
> +
> +       /* Initialize parameters block */
> +       memset(&params, 0, sizeof(params));
> +       params.session = ipsec_sa->session;
> +       params.pkt = pkt;
> +       params.ctx = ctx;
> +
> +       /*Save everything to context */
> +       ctx->ip_tos = ip->tos;
> +       ctx->ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset);
> +       ctx->ip_ttl = ip->ttl;
> +       ctx->ah_offset = ah ? ((uint8_t *)ah) - buf : 0;
> +       ctx->esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
> +       ctx->hdr_len = hdr_len;
> +       ctx->trl_len = 0;
> +       //ctx->src_ip = ipsec_sa->src_ip;
> +       //ctx->dst_ip = ipsec_sa->dst_ip;
> +
> +       ctx->postprocess = odp_ipsec_postprocess;
> +       ctx->sa = sa;
> +
> +       /* If authenticating, zero the mutable fields build the request */
> +       if (ah) {
> +               ip->chksum = 0;
> +               ip->tos = 0;
> +               ip->frag_offset = 0;
> +               ip->ttl = 0;
> +
> +               params.auth_range.offset = ((uint8_t *)ip) - buf;
> +               params.auth_range.length = odp_be_to_cpu_16(ip->tot_len);
> +               params.hash_result_offset = ah->icv - buf;
> +       }
> +
> +       /* If deciphering build request */
> +       if (esp) {
> +               params.cipher_range.offset = ipv4_data_p(ip) + hdr_len - buf;
> +               params.cipher_range.length = ipv4_data_len(ip) - hdr_len;
> +               params.override_iv_ptr = esp->iv;
> +       }
> +
> +       /* Create new packet after all length extensions */
> +       params.out_pkt = ipsec_sa->in_place ? pkt :
> +                       odp_packet_alloc(odp_packet_pool(pkt),
> +                                        odp_packet_len(pkt));
> +       odp_packet_user_ptr_set(params.out_pkt,
> +                               odp_packet_user_ptr(params.pkt));
> +
> +       rc = odp_crypto_operation(&params, &posted, &ctx->crypto);
> +       if (rc < 0) {
> +               ODP_DBG("Crypto failed\n");
> +               ctx->status.error.alg = 1;
> +
> +               return rc;
> +       }
> +
> +       ODP_ASSERT(!posted);
> +
> +       return 0;
> +}
> +
> +/** Helper for calculating encode length using data length and block size */
> +#define ESP_ENCODE_LEN(x, b) ((((x) + (b - 1)) / b) * b)
> +
> +static
> +int odp_ipsec_out_single(odp_packet_t pkt,
> +                        odp_ipsec_sa_t sa,
> +                        odp_ipsec_ctx_t *ctx)

Same comment regarding odp_ prefix here.

> +{
> +       ipsec_sa_t *ipsec_sa;
> +       uint8_t *buf = odp_packet_data(pkt);
> +       _odp_ipv4hdr_t *ip = (_odp_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
> +       uint16_t ip_data_len = ipv4_data_len(ip);
> +       uint8_t *ip_data = ipv4_data_p(ip);
> +       odp_crypto_op_param_t params;
> +       odp_bool_t posted = 0;
> +       int hdr_len = 0;
> +       int trl_len = 0;
> +       _odp_ahhdr_t *ah = NULL;
> +       _odp_esphdr_t *esp = NULL;
> +       int rc;
> +
> +       ctx->status.all_error = 0;
> +       ctx->status.all_flag = 0;
> +
> +       if (ODP_IPSEC_SA_INVALID == sa) {
> +               ctx->status.error.sa_lookup = 1;
> +               return -1;
> +       }
> +
> +       ipsec_sa = ipsec_sa_entry_from_hdl(sa);
> +       if (odp_unlikely(NULL == ipsec_sa)) {
> +               ctx->status.error.alg = 1;
> +               return -1;
> +       }
> +
> +       /* Initialize parameters block */
> +       memset(&params, 0, sizeof(params));
> +       params.session = ipsec_sa->session;
> +       params.pkt = pkt;
> +       params.ctx = ctx;
> +
> +       /* Save IPv4 stuff */
> +       ctx->ip_tos = ip->tos;
> +       ctx->ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset);
> +       ctx->ip_ttl = ip->ttl;
> +
> +       ctx->postprocess = NULL;
> +       ctx->sa = sa;
> +
> +#if 0
> +       if (ipsec_sa->mode == IPSEC_SA_MODE_TUNNEL) {
> +               hdr_len += sizeof(_odp_ipv4hdr_t);
> +               ip_data = (uint8_t *)ip;
> +               ip_data_len += sizeof(_odp_ipv4hdr_t);
> +       }
> +#endif
> +       /* Compute ah and esp, determine length of headers, move the data */
> +       if (ipsec_sa->ah_icv_len) {
> +               ah = (_odp_ahhdr_t *)(ip_data + hdr_len);
> +               hdr_len += sizeof(_odp_ahhdr_t);
> +               hdr_len += ipsec_sa->ah_icv_len;
> +       }
> +       if (ipsec_sa->esp_iv_len) {
> +               esp = (_odp_esphdr_t *)(ip_data + hdr_len);
> +               hdr_len += sizeof(_odp_esphdr_t);
> +               hdr_len += ipsec_sa->esp_iv_len;
> +       }
> +       memmove(ip_data + hdr_len, ip_data, ip_data_len);

Again, use odp_packet_move_data() for this.

> +       ip_data += hdr_len;
> +
> +       /* update outer header in tunnel mode */
> +#if 0
> +       if (ipsec_sa->mode == IPSEC_SA_MODE_TUNNEL) {
> +               /* tunnel addresses */
> +               ip->src_addr = odp_cpu_to_be_32(ipsec_sa->tun_src_ip);
> +               ip->dst_addr = odp_cpu_to_be_32(ipsec_sa->tun_dst_ip);
> +       }
> +#endif
> +
> +       /* For cipher, compute encrypt length, build headers and request */
> +       if (esp) {
> +               uint32_t encrypt_len;
> +               _odp_esptrl_t *esp_t;
> +
> +               encrypt_len = ESP_ENCODE_LEN(ip_data_len + sizeof(*esp_t),
> +                                            ipsec_sa->esp_block_len);
> +               trl_len = encrypt_len - ip_data_len;
> +
> +               esp->spi = odp_cpu_to_be_32(ipsec_sa->spi);
> +               memcpy(esp + 1, ipsec_sa->iv, ipsec_sa->esp_iv_len);
> +
> +               esp_t = (_odp_esptrl_t *)(ip_data + encrypt_len) - 1;
> +               esp_t->pad_len     = trl_len - sizeof(*esp_t);
> +#if 0
> +               if (ipsec_sa->mode == IPSEC_SA_MODE_TUNNEL)
> +                       esp_t->next_header = _ODP_IPV4;
> +               else
> +#endif
> +                       esp_t->next_header = ip->proto;
> +               ip->proto = _ODP_IPPROTO_ESP;
> +
> +               params.cipher_range.offset = ip_data - buf;
> +               params.cipher_range.length = encrypt_len;
> +       }
> +
> +       /* For authentication, build header clear mutables and build request 
> */
> +       if (ah) {
> +               memset(ah, 0, sizeof(*ah) + ipsec_sa->ah_icv_len);
> +               ah->spi = odp_cpu_to_be_32(ipsec_sa->spi);
> +               ah->ah_len = 1 + (ipsec_sa->ah_icv_len / 4);
> +#if 0
> +               if (ipsec_sa->mode == IPSEC_SA_MODE_TUNNEL && !esp)
> +                       ah->next_header = _ODP_IPV4;
> +               else
> +#endif
> +                       ah->next_header = ip->proto;
> +               ip->proto = _ODP_IPPROTO_AH;
> +
> +               ip->chksum = 0;
> +               ip->tos = 0;
> +               ip->frag_offset = 0;
> +               ip->ttl = 0;
> +
> +               params.auth_range.offset = ((uint8_t *)ip) - buf;
> +               params.auth_range.length =
> +                       odp_be_to_cpu_16(ip->tot_len) + (hdr_len + trl_len);
> +               params.hash_result_offset = ah->icv - buf;
> +       }
> +
> +       /* Set IPv4 length before authentication */
> +       if (!odp_packet_push_tail(pkt, hdr_len + trl_len)) {
> +               ctx->status.error.alg = 1;
> +               return -1;
> +       }

Use odp_packet_extend_tail() here as that will handle additional
segment adds if current tailroom is insufficient.

> +
> +       ipv4_adjust_len(ip, hdr_len + trl_len);
> +
> +       /* Save remaining context */
> +       ctx->hdr_len = hdr_len;
> +       ctx->trl_len = trl_len;
> +       ctx->ah_offset = ah ? ((uint8_t *)ah) - buf : 0;
> +       ctx->esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
> +#if 0
> +       ctx->tun_hdr_offset = (ipsec_sa->mode == IPSEC_SA_MODE_TUNNEL) ?
> +                                      ((uint8_t *)ip - buf) : 0;
> +#else
> +       ctx->tun_hdr_offset = 0;
> +#endif
> +       ctx->ah_seq = &ipsec_sa->seq;
> +       ctx->esp_seq = &ipsec_sa->seq;
> +       //ctx->tun_hdr_id = &ipsec_sa->tun_hdr_id;
> +
> +       // FIXME: locking !!!!!
> +       if (ctx->ah_offset) {
> +               _odp_ahhdr_t *ah;
> +
> +               ah = (_odp_ahhdr_t *)(ctx->ah_offset + buf);
> +               ah->seq_no = odp_cpu_to_be_32((*ctx->ah_seq)++);
> +       }
> +       if (ctx->esp_offset) {
> +               _odp_esphdr_t *esp;
> +
> +               esp = (_odp_esphdr_t *)(ctx->esp_offset + buf);
> +               esp->seq_no = odp_cpu_to_be_32((*ctx->esp_seq)++);
> +       }
> +       if (ctx->tun_hdr_offset) {
> +               _odp_ipv4hdr_t *ip;
> +               int ret;
> +
> +               ip = (_odp_ipv4hdr_t *)(ctx->tun_hdr_offset + buf);
> +               ip->id = odp_cpu_to_be_16((*ctx->tun_hdr_id)++);
> +               if (!ip->id) {
> +                       /* re-init tunnel hdr id */
> +                       ret = odp_random_data((uint8_t *)ctx->tun_hdr_id,
> +                                             sizeof(*ctx->tun_hdr_id),
> +                                             1);

Use new form of this API:
ret = odp_random_data((uint8_t *)ctx->tun_hdr_id,
sizeof(*ctx->tun_hdr_id), ODP_RANDOM_CRYPTO);

> +                       if (ret != sizeof(*ctx->tun_hdr_id))
> +                               abort();

Need to recover and set appropriate RC here. OK as an initial
prototype, but mark as TODO.

> +               }
> +       }
> +
> +       /* Create new packet after all length extensions */
> +       params.out_pkt = ipsec_sa->in_place ? pkt :
> +                       odp_packet_alloc(odp_packet_pool(pkt),
> +                                        odp_packet_len(pkt));
> +       odp_packet_user_ptr_set(params.out_pkt, 
> odp_packet_user_ptr(params.pkt));
> +
> +       rc = odp_crypto_operation(&params, &posted, &ctx->crypto);
> +       if (rc < 0) {
> +               ODP_DBG("Crypto failed\n");
> +               ctx->status.error.alg = 1;
> +
> +               return rc;
> +       }
> +
> +       ODP_ASSERT(!posted);
> +
> +       return 0;
> +}
> +
> +#if 0
> +static odp_ipsec_op_opt_t default_opt = {
> +       .mode = ODP_IPSEC_FRAG_DISABLED,
> +};
> +#endif
> +
>  int odp_ipsec_in(const odp_ipsec_op_param_t *input,
>                  odp_ipsec_op_result_t *output)
>  {
> -       (void)input;
> -       (void)output;
> +       unsigned in_pkt = 0;
> +       unsigned out_pkt = 0;
> +       unsigned sa_idx = 0;
> +       unsigned opt_idx = 0;
> +       unsigned sa_inc = (input->num_sa > 1) ? 1 : 0;
> +       unsigned opt_inc = (input->num_opt > 1) ? 1 : 0;
>
> -       return -1;
> +       while (in_pkt < input->num_pkt && out_pkt < output->num_pkt) {
> +               odp_ipsec_sa_t sa;
> +               odp_ipsec_packet_result_t *res = &output->res[out_pkt];
> +               odp_ipsec_ctx_t ctx;
> +               int ret;
> +
> +               if (0 == input->num_sa)
> +                       sa = ODP_IPSEC_SA_INVALID;
> +               else
> +                       sa = input->sa[sa_idx];
> +
> +#if 0
> +               odp_ipsec_op_opt_t *opt;
> +
> +               if (0 == input->num_opt)
> +                       opt = &default_opt;
> +               else
> +                       opt = &input->opt[opt_idx];
> +#endif
> +
> +               res->num_out = 1;
> +               output->pkt[out_pkt] = input->pkt[in_pkt];
> +
> +               if (ODP_IPSEC_SA_INVALID == sa) {
> +                       res->status.error.sa_lookup = 1;
> +                       goto out;
> +               }
> +
> +               if (odp_ipsec_in_single(input->pkt[in_pkt], sa, &ctx) < 0) {
> +                       res->status.error.alg = 1;
> +                       goto out;
> +               }
> +
> +               ret = odp_ipsec_finish(&ctx, res, &output->pkt[out_pkt]);
> +               if (ret < 0)
> +                       res->status.error.alg = 1;
> +
> +out:
> +               in_pkt++;
> +               out_pkt++;
> +               sa_idx += sa_inc;
> +               opt_idx += opt_inc;
> +       }
> +
> +       return in_pkt;
>  }
>
>  int odp_ipsec_out(const odp_ipsec_op_param_t *input,
> -                 odp_ipsec_op_result_t *output)
> +                odp_ipsec_op_result_t *output)
>  {
> -       (void)input;
> -       (void)output;
> +       unsigned in_pkt = 0;
> +       unsigned out_pkt = 0;
> +       unsigned sa_idx = 0;
> +       unsigned opt_idx = 0;
> +       unsigned sa_inc = (input->num_sa > 1) ? 1 : 0;
> +       unsigned opt_inc = (input->num_opt > 1) ? 1 : 0;
>
> -       return -1;
> +       while (in_pkt < input->num_pkt && out_pkt < output->num_pkt) {
> +               odp_ipsec_sa_t sa;
> +               odp_ipsec_packet_result_t *res = &output->res[out_pkt];
> +               odp_ipsec_ctx_t ctx;
> +               int ret;
> +
> +               if (0 == input->num_sa)
> +                       sa = ODP_IPSEC_SA_INVALID;
> +               else
> +                       sa = input->sa[sa_idx];
> +
> +#if 0
> +               odp_ipsec_op_opt_t *opt;
> +
> +               if (0 == input->num_opt)
> +                       opt = &default_opt;
> +               else
> +                       opt = &input->opt[opt_idx];
> +#endif
> +
> +               res->num_out = 1;
> +               output->pkt[out_pkt] = input->pkt[in_pkt];
> +
> +               if (odp_ipsec_out_single(input->pkt[in_pkt], sa, &ctx) < 0) {
> +                       res->status.error.alg = 1;
> +                       goto out;
> +               }
> +
> +               ret = odp_ipsec_finish(&ctx, res, &output->pkt[out_pkt]);
> +               if (ret < 0)
> +                       res->status.error.alg = 1;
> +
> +out:
> +               in_pkt++;
> +               out_pkt++;
> +               sa_idx += sa_inc;
> +               opt_idx += opt_inc;
> +       }
> +
> +       return in_pkt;
>  }
>
>  int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input)
>  {
> -       (void)input;
> +       unsigned in_pkt = 0;
> +       unsigned sa_idx = 0;
> +       unsigned opt_idx = 0;
> +       unsigned sa_inc = (input->num_sa > 1) ? 1 : 0;
> +       unsigned opt_inc = (input->num_opt > 1) ? 1 : 0;
>
> -       return -1;
> +       while (in_pkt < input->num_pkt) {
> +               odp_ipsec_op_result_event_t ipsec_ev;

odp_ipsec_result_t ipsec_ev;

> +               odp_event_t ev;
> +               odp_ipsec_op_result_event_hdr_t *res_hdr;
> +               odp_ipsec_ctx_t *ctx;
> +               odp_ipsec_sa_t sa;
> +               odp_queue_t queue;
> +
> +               ipsec_ev = odp_ipsec_op_result_event_alloc();

ipsec_ev = odp_ipsec_result_alloc();

> +               if (ODP_IPSEC_OP_RESULT_EVENT_INVALID == ipsec_ev)

ODP_IPSEC_RESULT_INVALID

> +                       break;
> +
> +               ev = odp_ipsec_op_result_event_to_event(ipsec_ev);

ev = odp_ipsec_result_to_event(ipsec_ev);

> +
> +               res_hdr = ipsec_op_result_event_hdr(ipsec_ev);
> +
> +               ctx = odp_ipsec_alloc_pkt_ctx();
> +               if (NULL == ctx) {
> +                       odp_event_free(ev);
> +                       break;
> +               }
> +
> +               res_hdr->ctx = ctx;
> +
> +               if (0 == input->num_sa)
> +                       sa = ODP_IPSEC_SA_INVALID;
> +               else
> +                       sa = input->sa[sa_idx];
> +
> +#if 0
> +               odp_ipsec_op_opt_t *opt;
> +
> +               if (0 == input->num_opt)
> +                       opt = &default_opt;
> +               else
> +                       opt = &input->opt[opt_idx];
> +#endif
> +
> +               if (odp_ipsec_in_single(input->pkt[in_pkt], sa, ctx) < 0)
> +                       ctx->status.error.alg = 1;
> +
> +               in_pkt++;
> +               sa_idx += sa_inc;
> +               opt_idx += opt_inc;
> +
> +               if (ODP_IPSEC_SA_INVALID == sa)
> +                       queue = ipsec_config.inbound.default_queue;
> +               else
> +                       queue = ipsec_sa_entry_from_hdl(sa)->queue;
> +
> +               if (odp_queue_enq(queue, ev)) {
> +                       odp_event_free(ev);
> +                       return -1;
> +               }
> +       }
> +
> +       return in_pkt;
>  }
>
>  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input)
>  {
> -       (void)input;
> +       unsigned in_pkt = 0;
> +       unsigned sa_idx = 0;
> +       unsigned opt_idx = 0;
> +       unsigned sa_inc = (input->num_sa > 1) ? 1 : 0;
> +       unsigned opt_inc = (input->num_opt > 1) ? 1 : 0;
>
> -       return -1;
> +       while (in_pkt < input->num_pkt) {
> +               odp_ipsec_op_result_event_t ipsec_ev;

odp_ipsec_result_t ipsec_ev;

> +               odp_event_t ev;
> +               odp_ipsec_op_result_event_hdr_t *res_hdr;
> +               odp_ipsec_ctx_t *ctx;
> +               odp_ipsec_sa_t sa;
> +               odp_queue_t queue;
> +
> +               ipsec_ev = odp_ipsec_op_result_event_alloc();

ipsec_ev = odp_ipsec_result_alloc();

> +               if (ODP_IPSEC_OP_RESULT_EVENT_INVALID == ipsec_ev)

ODP_IPSEC_RESULT_INVALID

> +                       break;
> +
> +               ev = odp_ipsec_op_result_event_to_event(ipsec_ev);

ev = odp_ipsec_result_to_event(ipsec_ev);

> +
> +               res_hdr = ipsec_op_result_event_hdr(ipsec_ev);
> +
> +               ctx = odp_ipsec_alloc_pkt_ctx();
> +               if (NULL == ctx) {
> +                       odp_event_free(ev);
> +                       break;
> +               }
> +
> +               res_hdr->ctx = ctx;
> +
> +               if (0 == input->num_sa)
> +                       sa = ODP_IPSEC_SA_INVALID;
> +               else
> +                       sa = input->sa[sa_idx];
> +
> +#if 0
> +               odp_ipsec_op_opt_t *opt;
> +
> +               if (0 == input->num_opt)
> +                       opt = &default_opt;
> +               else
> +                       opt = &input->opt[opt_idx];
> +#endif
> +
> +               if (odp_ipsec_out_single(input->pkt[in_pkt], sa, ctx) < 0)
> +                       ctx->status.error.alg = 1;
> +
> +               in_pkt++;
> +               sa_idx += sa_inc;
> +               opt_idx += opt_inc;
> +
> +               if (ODP_IPSEC_SA_INVALID == sa)
> +                       queue = ipsec_config.outbound.default_queue;
> +               else
> +                       queue = ipsec_sa_entry_from_hdl(sa)->queue;
> +
> +               if (odp_queue_enq(queue, ev)) {
> +                       odp_event_free(ev);
> +                       return -1;
> +               }
> +       }
> +
> +       return in_pkt;
>  }
>
>  int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,
> @@ -117,9 +1202,36 @@ int odp_ipsec_out_inline(const odp_ipsec_op_param_t 
> *op_param,
>  int odp_ipsec_result(odp_ipsec_op_result_t *result, odp_event_t event)
>  {
>         (void)result;
> -       (void)event;
>
> -       return -1;
> +       odp_ipsec_op_result_event_t ipsec_ev;

odp_ipsec_result_t ipsec_ev;

> +       odp_ipsec_op_result_event_hdr_t *res_hdr;
> +       unsigned out_pkt;
> +       odp_ipsec_ctx_t *ctx;
> +
> +       ipsec_ev = odp_ipsec_op_result_event_from_event(event);

ipsec_ev = odp_ipsec_result_from_event(event);

> +       if (ODP_IPSEC_OP_RESULT_EVENT_INVALID == ipsec_ev)

ODP_IPSEC_RESULT_INVALID

> +               return -1;
> +
> +       res_hdr = ipsec_op_result_event_hdr(ipsec_ev);
> +
> +       for (out_pkt = 0; out_pkt < result->num_pkt; out_pkt++) {
> +               odp_ipsec_packet_result_t *res = &result->res[out_pkt];
> +               odp_packet_t *pkt = &result->pkt[out_pkt];
> +               odp_ipsec_ctx_t *ctx = res_hdr->ctx;
> +               int ret;
> +
> +               res_hdr->ctx = ctx->next;
> +               ret = odp_ipsec_finish(ctx, res, pkt);
> +               if (ret < 0)
> +                       res->status.error.alg = 1;
> +
> +               odp_ipsec_free_pkt_ctx(ctx);
> +       }
> +
> +       for (ctx = res_hdr->ctx; NULL != ctx; ctx = ctx->next)
> +               out_pkt++;
> +
> +       return out_pkt;
>  }
>
>  int odp_ipsec_status(odp_ipsec_status_t *status, odp_event_t event)
> @@ -140,9 +1252,9 @@ int odp_ipsec_mtu_update(odp_ipsec_sa_t sa, uint32_t mtu)
>
>  void *odp_ipsec_sa_context(odp_ipsec_sa_t sa)
>  {
> -       (void)sa;
> +       ipsec_sa_t *ipsec_sa = ipsec_sa_entry_from_hdl(sa);
>
> -       return NULL;
> +       return ipsec_sa->context;
>  }
>
>  uint64_t odp_ipsec_sa_to_u64(odp_ipsec_sa_t sa)
> --
> 2.11.0
>

Reply via email to