diff mbox series

[API-NEXT,v3,2/4] api: ipsec: add inline IPSEC support

Message ID 1490367881-16266-2-git-send-email-petri.savolainen@linaro.org
State New
Headers show
Series [API-NEXT,v3,1/4] api: ipsec: extend lookaside API | expand

Commit Message

Petri Savolainen March 24, 2017, 3:04 p.m. UTC
Added support for inline IPSEC processing on packet input and
output. Inline mode IPSEC and traffic manager cannot be enabled
(currently) on the same pktio interface.

Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

---
 include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---
 include/odp/api/spec/packet_io.h |  32 ++++
 2 files changed, 360 insertions(+), 27 deletions(-)

-- 
2.8.1

Comments

Bill Fischofer March 26, 2017, 3:01 p.m. UTC | #1
On Fri, Mar 24, 2017 at 10:04 AM, Petri Savolainen
<petri.savolainen@linaro.org> wrote:
> Added support for inline IPSEC processing on packet input and

> output. Inline mode IPSEC and traffic manager cannot be enabled

> (currently) on the same pktio interface.

>

> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

> ---

>  include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---

>  include/odp/api/spec/packet_io.h |  32 ++++

>  2 files changed, 360 insertions(+), 27 deletions(-)

>

> diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h

> index d3e51bc..2e7e1e4 100644

> --- a/include/odp/api/spec/ipsec.h

> +++ b/include/odp/api/spec/ipsec.h

> @@ -19,6 +19,8 @@ extern "C" {

>  #endif

>

>  #include <odp/api/crypto.h>

> +#include <odp/api/packet_io.h>

> +#include <odp/api/classification.h>

>

>  /** @defgroup odp_ipsec ODP IPSEC

>   *  Operations of IPSEC API.

> @@ -51,11 +53,43 @@ typedef enum odp_ipsec_op_mode_t {

>           * Application uses asynchronous IPSEC operations,

>           * which return results via events.

>           */

> -       ODP_IPSEC_OP_MODE_ASYNC

> +       ODP_IPSEC_OP_MODE_ASYNC,

> +

> +       /** Inline IPSEC operation

> +         *

> +         * Packet input/output is connected directly to IPSEC inbound/outbound

> +         * processing. Application uses asynchronous or inline IPSEC

> +         * operations.

> +         */

> +       ODP_IPSEC_OP_MODE_INLINE,

> +

> +       /** IPSEC is disabled in inbound / outbound direction */

> +       ODP_IPSEC_OP_MODE_DISABLED

>

>  } odp_ipsec_op_mode_t;

>

>  /**

> + * Protocol layers in IPSEC configuration

> + */

> +typedef enum odp_ipsec_proto_layer_t {

> +       /** No layers */

> +       ODP_IPSEC_LAYER_NONE = 0,

> +

> +       /** Layer L2 protocols (Ethernet, VLAN, etc) */

> +       ODP_IPSEC_LAYER_L2,

> +

> +       /** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */

> +       ODP_IPSEC_LAYER_L3,

> +

> +       /** Layer L4 protocols (UDP, TCP, SCTP) */

> +       ODP_IPSEC_LAYER_L4,

> +

> +       /** All layers */

> +       ODP_IPSEC_LAYER_ALL

> +

> +} odp_ipsec_proto_layer_t;

> +

> +/**

>   * Configuration options for IPSEC inbound processing

>   */

>  typedef struct odp_ipsec_inbound_config_t {

> @@ -81,9 +115,110 @@ typedef struct odp_ipsec_inbound_config_t {

>

>         } spi_lookup;

>

> +       /** Retain outer headers

> +        *

> +        *  Select up to which protocol layer (at least) outer headers are

> +        *  retained in inbound inline processing. Default value is

> +        *  ODP_IPSEC_LAYER_NONE.

> +        *

> +        *  ODP_IPSEC_LAYER_NONE: Application does not require any outer

> +        *                        headers to be retained.

> +        *

> +        *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.

> +        *

> +        *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the

> +        *                        same as ODP_IPSEC_LAYER_ALL.

> +        *

> +        *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the

> +        *                        same as ODP_IPSEC_LAYER_ALL.

> +        *

> +        *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are

> +        *                        retained. In transport mode, all headers

> +        *                        before IP (carrying IPSEC) are retained.

> +        *

> +        */

> +       odp_ipsec_proto_layer_t retain_outer;

> +

> +       /** Parse packet headers after IPSEC transformation

> +        *

> +        *  Select header parsing level after inbound processing. Headers of the

> +        *  resulting packet must be parsed (at least) up to this level. Parsing

> +        *  starts from IP (layer 3). Each successfully transformed packet has

> +        *  a valid value for L3 offset regardless of the parse configuration.

> +        *  Default value is ODP_IPSEC_LAYER_NONE.

> +        */

> +       odp_ipsec_proto_layer_t parse;

> +

> +       /** Flags to control IPSEC payload data checks up to the selected parse

> +        *  level. */

> +       union {

> +               struct {

> +                       /** Check IPv4 header checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t ipv4_chksum   : 1;

> +

> +                       /** Check UDP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t udp_chksum    : 1;

> +

> +                       /** Check TCP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t tcp_chksum    : 1;

> +

> +                       /** Check SCTP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t sctp_chksum   : 1;

> +               } check;

> +

> +               /** All bits of the bit field structure

> +                 *

> +                 * This field can be used to set/clear all flags, or bitwise

> +                 * operations over the entire structure. */

> +               uint32_t all_check;

> +       };

> +

>  } odp_ipsec_inbound_config_t;

>

>  /**

> + * Configuration options for IPSEC outbound processing

> + */

> +typedef struct odp_ipsec_outbound_config_t {

> +       /** Flags to control L3/L4 checksum insertion as part of outbound

> +        *  packet processing. Packet must have set with valid L3/L4 offsets.

> +        *  Checksum configuration is ignored for packets that checksum cannot

> +        *  be computed for (e.g. IPv4 fragments). Application may use a packet

> +        *  metadata flag to disable checksum insertion per packet bases.

> +        */

> +       union {

> +               struct {

> +                       /** Insert IPv4 header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_ipv4   : 1;

> +

> +                       /** Insert UDP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_udp    : 1;

> +

> +                       /** Insert TCP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_tcp    : 1;

> +

> +                       /** Insert SCTP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_sctp   : 1;

> +

> +               } chksum;

> +

> +               /** All bits of the bit field structure

> +                 *

> +                 * This field can be used to set/clear all flags, or bitwise

> +                 * operations over the entire structure. */

> +               uint32_t all_chksum;

> +       };

> +

> +} odp_ipsec_outbound_config_t;

> +

> +/**

>   * IPSEC capability

>   */

>  typedef struct odp_ipsec_capability_t {

> @@ -106,6 +241,23 @@ typedef struct odp_ipsec_capability_t {

>          */

>         uint8_t op_mode_async;

>

> +       /** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support

> +        *

> +        *  0: Inline IPSEC operation is not supported

> +        *  1: Inline IPSEC operation is supported

> +        *  2: Inline IPSEC operation is supported and preferred

> +        */

> +       uint8_t op_mode_inline;

> +

> +       /** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of

> +        *  resulting inbound packets.


Since the operating mode here is INLINE, why not simply ODP_IPSEC_INLINE_CLS?

> +        *

> +        *  0: Classification of resulting packets is not supported

> +        *  1: Classification of resulting packets is supported

> +        *  2: Classification of resulting packets is supported and preferred

> +        */

> +       uint8_t pipeline_cls;


inline_cls seems clearer here since this section is configuring inline
processing options.

> +

>         /** Soft expiry limit in seconds support

>          *

>          *  0: Limit is not supported

> @@ -132,12 +284,19 @@ typedef struct odp_ipsec_capability_t {

>   * IPSEC configuration options

>   */

>  typedef struct odp_ipsec_config_t {

> -       /** IPSEC operation mode. Application selects which mode (sync or async)

> -        *  will be used for IPSEC operations.

> +       /** Inbound IPSEC operation mode. Application selects which mode

> +        *  will be used for inbound IPSEC operations.

>          *

>          *  @see odp_ipsec_in(), odp_ipsec_in_enq()

>          */

> -       odp_ipsec_op_mode_t op_mode;

> +       odp_ipsec_op_mode_t inbound_mode;

> +

> +       /** Outbound IPSEC operation mode. Application selects which mode

> +        *  will be used for outbound IPSEC operations.

> +        *

> +        *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()

> +        */

> +       odp_ipsec_op_mode_t outbound_mode;

>

>         /** Maximum number of IPSEC SAs that application will use

>          * simultaneously */

> @@ -146,6 +305,9 @@ typedef struct odp_ipsec_config_t {

>         /** IPSEC inbound processing configuration */

>         odp_ipsec_inbound_config_t inbound;

>

> +       /** IPSEC outbound processing configuration */

> +       odp_ipsec_outbound_config_t outbound;

> +

>  } odp_ipsec_config_t;

>

>  /**

> @@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {

>         ODP_IPSEC_LOOKUP_DISABLED = 0,

>

>         /** Inbound SA lookup is enabled. Lookup matches only SPI value.

> -        *  SA lookup failure status (error.sa_lookup) is reported through

> +        *  In inline mode, a lookup miss directs the packet back to normal

> +        *  packet input interface processing. In other modes, the SA lookup

> +        *  failure status (error.sa_lookup) is reported through

>          *  odp_ipsec_packet_result_t. */

> -       ODP_IPSEC_LOOKUP_SPI

> +       ODP_IPSEC_LOOKUP_SPI,

> +

> +       /** Inbound SA lookup is enabled. Lookup matches both SPI value and

> +         * destination IP address. Functionality is otherwise identical to

> +         * ODP_IPSEC_LOOKUP_SPI. */

> +       ODP_IPSEC_LOOKUP_DSTADDR_SPI

>

>  } odp_ipsec_lookup_mode_t;

>

>  /**

> + * Result event pipeline configuration

> + */

> +typedef enum odp_ipsec_pipeline_t {

> +       /** Do not pipeline */

> +       ODP_IPSEC_PIPELINE_NONE = 0,

> +

> +       /** Send IPSEC result events to the classifier.

> +        *

> +        *  IPSEC capability 'pipeline_cls' determines if pipelined

> +        *  classification is supported. */

> +       ODP_IPSEC_PIPELINE_CLS

> +

> +} odp_ipsec_pipeline_t;


I'm not sure that calling this odp_ipsec_pipeline_t is better than the
previous odp_ipsec_dest_mode_t. But since this is all about
configuring INLINE processing, how about odp_ipsec_inline_config_t and
the values are ODP_IPSEC_INLINE_DONE and ODP_IPSEC_INLINE_CLS. DONE
simply indicates that inline processing is finished and the result is
delivered back to the application.

Since this is a per-SA configuration, the question is whether it
should be one setting or separate in and out configs since we want a
structure that will accommodate an ODP_IPSEC_INLINE_TM for sending
IPsec output directly to TM. Whether we want to introduce that now, we
want a structure that will accommodate this extension without needing
redesign in the next iteration.

> +

> +/**

>   * IPSEC Security Association (SA) parameters

>   */

>  typedef struct odp_ipsec_sa_param_t {

> @@ -432,6 +616,21 @@ typedef struct odp_ipsec_sa_param_t {

>         /** SPI value */

>         uint32_t spi;

>

> +       /** Additional inbound SA lookup parameters. Values are considered

> +        *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */

> +       struct {

> +               /** Select IP version

> +                *

> +                *  4:   IPv4

> +                *  6:   IPv6

> +                */

> +               uint8_t ip_version;

> +

> +               /** IP destination address (NETWORK ENDIAN) */

> +               void    *dst_addr;

> +

> +       } lookup_param;

> +

>         /** MTU for outbound IP fragmentation offload

>          *

>          *  This is the maximum length of IP packets that outbound IPSEC

> @@ -440,13 +639,31 @@ typedef struct odp_ipsec_sa_param_t {

>          */

>         uint32_t mtu;

>

> +       /** Select pipelined destination for IPSEC result events

> +        *

> +        *  Asynchronous and inline modes generate result events. Select where

> +        *  those events are sent. Inbound SAs may choose to use pipelined

> +        *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.

> +        */

> +       odp_ipsec_pipeline_t pipeline;

> +

>         /** Destination queue for IPSEC events

>          *

> -        *  Operations in asynchronous mode enqueue resulting events into

> -        *  this queue.

> +        *  Operations in asynchronous or inline mode enqueue resulting events

> +        *  into this queue.

>          */

>         odp_queue_t dest_queue;


It seems confusing to have both pipeline and queue here since both are
referring to what should happen next after IPsec processing is
finished. The cases are:

Input processing: Following IPsec processing the packet should either
be sent to the classifier or delivered to a destination event queue.

Output processing: Following IPsec processing the packet should either
be sent back to the application via a destination event queue, or
forwarded to a TM queue or directly to a pktio for transmission.

Having two separate controls means that there are invalid combinations
that have to be dealt with, which seems messy.

>

> +       /** Classifier destination CoS for IPSEC result events

> +        *

> +        *  Result events for successfully decapsulated packets are sent to

> +        *  classification through this CoS. Other result events are sent to

> +        *  'dest_queue'. This field is considered only when 'pipeline' is

> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio

> +        *  interface default CoS.

> +        */

> +       odp_cos_t dest_cos;


Having multiple pieces of information needed for the same config
suggests opportunities for simplification. Perhaps a scheme along the
following lines:

typedef struct odp_ipsec_next_config_t {

} odp_ipsec_next_config_t;

> +

>         /** User defined SA context pointer

>          *

>          *  User defined context pointer associated with the SA.

> @@ -679,6 +896,18 @@ typedef struct odp_ipsec_op_status_t {

>                 uint32_t all_error;

>         };

>

> +       union {

> +               /** Status flags */

> +               struct {

> +                       /** Packet was processed in inline mode */

> +                       uint32_t inline_mode      : 1;

> +

> +               } flag;

> +

> +               /** All flag bits */

> +               uint32_t all_flag;

> +       };

> +

>  } odp_ipsec_op_status_t;

>

>  /**

> @@ -708,7 +937,7 @@ typedef struct odp_ipsec_op_param_t {

>

>         /** Pointer to an array of packets

>          *

> -        *  Each packet must have a valid value for these meta-data:

> +        *  Each packet must have a valid value for these metadata:

>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>          *  * L4 offset: For inbound direction, when udp_encap is enabled -

>          *               offset to the first byte of the encapsulating UDP

> @@ -733,6 +962,35 @@ typedef struct odp_ipsec_op_param_t {

>  } odp_ipsec_op_param_t;

>

>  /**

> + * Outbound inline IPSEC operation parameters

> + */

> +typedef struct odp_ipsec_inline_op_param_t {

> +       /** Packet output interface for inline output operation

> +        *

> +        *  Outbound inline IPSEC operation uses this packet IO interface to

> +        *  output the packet after a successful IPSEC transformation. The pktio

> +        *  must have been configured to operate in inline IPSEC mode.

> +        */

> +       odp_pktio_t pktio;

> +

> +       /** Outer headers for inline output operation

> +        *

> +        *  Outbound inline IPSEC operation uses this information to prepend

> +        *  outer headers to the IPSEC packet before sending it out.

> +        */

> +       struct {

> +               /** Points to first byte of outer headers to be copied in

> +                *  front of the outgoing IPSEC packet. Implementation copies

> +                *  the headers during odp_ipsec_out_inline() call. */

> +               uint8_t *ptr;

> +

> +               /** Outer header length in bytes */

> +               uint32_t len;

> +       } outer_hdr;

> +

> +} odp_ipsec_inline_op_param_t;

> +

> +/**

>   * IPSEC operation result for a packet

>   */

>  typedef struct odp_ipsec_packet_result_t {

> @@ -758,6 +1016,23 @@ typedef struct odp_ipsec_packet_result_t {

>          */

>         odp_ipsec_sa_t sa;

>

> +       /** Packet outer header status before inbound inline processing.

> +        *  This is valid only when status.flag.inline_mode is set.

> +        */

> +       struct {

> +               /** Points to the first byte of retained outer headers. These

> +                *  headers are stored in a contiquous, per packet,

> +                *  implementation specific memory space. Since the memory space

> +                *  may overlap with e.g. packet head/tailroom, the content

> +                *  becomes invalid if packet data storage is modified in

> +                *  anyway. The memory space may not be sharable to other

> +                *  threads. */

> +               uint8_t *ptr;

> +

> +               /** Outer header length in bytes */

> +               uint32_t len;

> +       } outer_hdr;

> +

>  } odp_ipsec_packet_result_t;

>

>  /**

> @@ -779,18 +1054,14 @@ typedef struct odp_ipsec_op_result_t {

>          *  at least 'num_pkt' elements.

>          *

>          *  Each successfully transformed packet has a valid value for these

> -        *  meta-data:

> +        *  metadata regardless of the inner packet parse configuration.

> +        *  (odp_ipsec_inbound_config_t):

>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

> -        *  * L4 offset: Offset to the first byte of the valid and known L4

> -        *               header (immediately following the IP header).

> -        *  * Various flags about L3 and L4 layers:

> -        *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,

> -        *               has_ipsec, has_udp, has_tcp, etc depending on

> -        *               the resulted packet format

> +        *  * pktio:     For inbound inline IPSEC processed packets, original

> +        *               packet input interface

>          *

> -        * @see odp_packet_l3_offset(), odp_packet_l4_offset(),

> -        *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),

> -        *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()

> +        *  Other metadata for parse results and error checks depend on

> +        *  configuration (selected parse and error check levels).

>          */

>         odp_packet_t *pkt;

>

> @@ -921,10 +1192,10 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>  /**

>   * Inbound asynchronous IPSEC operation

>   *

> - * This operation does inbound IPSEC processing in asynchronous mode

> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

> - * odp_ipsec_in(), but outputs all results through one or more

> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

> + * This operation does inbound IPSEC processing in asynchronous mode. It

> + * processes packets otherwise identically to odp_ipsec_in(), but outputs all

> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

> + * ordering considerations.

>   *

>   * Asynchronous mode maintains (operation input) packet order per SA when

>   * application calls the operation within an ordered or atomic scheduler context

> @@ -934,6 +1205,11 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>   * events for the same SA are enqueued in order, and packet handles (for the

>   * same SA) are stored in order within an event.

>   *

> + * The function may be used also in inline processing mode, e.g. for IPSEC

> + * packets for which inline processing is not possible. Packets for the same SA

> + * may be processed simultaneously in both modes (initiated by this function

> + * and inline operation).

> + *

>   * @param         input   Operation input parameters

>   *

>   * @return Number of input packets consumed (0 ... input.num_pkt)

> @@ -946,10 +1222,10 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>  /**

>   * Outbound asynchronous IPSEC operation

>   *

> - * This operation does outbound IPSEC processing in asynchronous mode

> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

> - * odp_ipsec_out(), but outputs all results through one or more

> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

> + * This operation does outbound IPSEC processing in asynchronous mode. It

> + * processes packets otherwise identically to odp_ipsec_out(), but outputs all

> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

> + * ordering considerations.

>   *

>   * Asynchronous mode maintains (operation input) packet order per SA when

>   * application calls the operation within an ordered or atomic scheduler context

> @@ -959,6 +1235,9 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>   * events for the same SA are enqueued in order, and packet handles (for the

>   * same SA) are stored in order within an event.

>   *

> + * The function may be used also in inline processing mode, e.g. for IPSEC

> + * packets for which inline processing is not possible.

> + *

>   * @param         input   Operation input parameters

>   *

>   * @return Number of input packets consumed (0 ... input.num_pkt)

> @@ -969,6 +1248,28 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);

>

>  /**

> + * Outbound inline IPSEC operation

> + *

> + * This operation does outbound inline IPSEC processing for the packets. It's

> + * otherwise identical to odp_ipsec_out_enq(), but outputs all successfully

> + * transformed packets to the specified output interface, instead of generating

> + * result events for those.

> + *

> + * Inline operation parameters are defined per packet. The array of parameters

> + * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.

> + *

> + * @param         op_param      Operation parameters

> + * @param         inline_param  Outbound inline operation specific parameters

> + *

> + * @return Number of packets consumed (0 ... op_param.num_pkt)

> + * @retval <0     On failure

> + *

> + * @see odp_ipsec_out_enq()

> + */

> +int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,

> +                        const odp_ipsec_inline_op_param_t *inline_param);

> +

> +/**

>   * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event

>   *

>   * Copies IPSEC operation results from an event. The event must be of

> diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h

> index cec1f22..8802089 100644

> --- a/include/odp/api/spec/packet_io.h

> +++ b/include/odp/api/spec/packet_io.h

> @@ -407,6 +407,38 @@ typedef struct odp_pktio_config_t {

>          * interface capability before enabling the same. */

>         odp_bool_t enable_loop;

>

> +       /** Inbound IPSEC inlined with packet input

> +        *

> +        *  Enable/disable inline inbound IPSEC operation. When enabled packet

> +        *  input directs all IPSEC packets automatically to IPSEC inbound

> +        *  processing. IPSEC configuration is done through the IPSEC API.

> +        *  Packets that are not (recognized as) IPSEC are processed

> +        *  according to the packet input configuration.

> +        *

> +        *  0: Disable inbound IPSEC inline operation (default)

> +        *  1: Enable inbound IPSEC inline operation

> +        *

> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

> +        */

> +       odp_bool_t inbound_ipsec;

> +

> +       /** Outbound IPSEC inlined with packet output

> +        *

> +        *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC

> +        *  outbound processing can send outgoing IPSEC packets directly

> +        *  to the pktio interface for output. IPSEC configuration is done

> +        *  through the IPSEC API.

> +        *

> +        *  Outbound IPSEC inline operation cannot be combined with traffic

> +        *  manager (ODP_PKTOUT_MODE_TM).

> +        *

> +        *  0: Disable outbound IPSEC inline operation (default)

> +        *  1: Enable outbound IPSEC inline operation

> +        *

> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

> +        */

> +       odp_bool_t outbound_ipsec;

> +

>  } odp_pktio_config_t;

>

>  /**

> --

> 2.8.1

>
Bill Fischofer March 26, 2017, 3:06 p.m. UTC | #2
Hit return too soon.

On Sun, Mar 26, 2017 at 10:01 AM, Bill Fischofer
<bill.fischofer@linaro.org> wrote:
> On Fri, Mar 24, 2017 at 10:04 AM, Petri Savolainen

> <petri.savolainen@linaro.org> wrote:

>> Added support for inline IPSEC processing on packet input and

>> output. Inline mode IPSEC and traffic manager cannot be enabled

>> (currently) on the same pktio interface.

>>

>> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

>> ---

>>  include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---

>>  include/odp/api/spec/packet_io.h |  32 ++++

>>  2 files changed, 360 insertions(+), 27 deletions(-)

>>

>> diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h

>> index d3e51bc..2e7e1e4 100644

>> --- a/include/odp/api/spec/ipsec.h

>> +++ b/include/odp/api/spec/ipsec.h

>> @@ -19,6 +19,8 @@ extern "C" {

>>  #endif

>>

>>  #include <odp/api/crypto.h>

>> +#include <odp/api/packet_io.h>

>> +#include <odp/api/classification.h>

>>

>>  /** @defgroup odp_ipsec ODP IPSEC

>>   *  Operations of IPSEC API.

>> @@ -51,11 +53,43 @@ typedef enum odp_ipsec_op_mode_t {

>>           * Application uses asynchronous IPSEC operations,

>>           * which return results via events.

>>           */

>> -       ODP_IPSEC_OP_MODE_ASYNC

>> +       ODP_IPSEC_OP_MODE_ASYNC,

>> +

>> +       /** Inline IPSEC operation

>> +         *

>> +         * Packet input/output is connected directly to IPSEC inbound/outbound

>> +         * processing. Application uses asynchronous or inline IPSEC

>> +         * operations.

>> +         */

>> +       ODP_IPSEC_OP_MODE_INLINE,

>> +

>> +       /** IPSEC is disabled in inbound / outbound direction */

>> +       ODP_IPSEC_OP_MODE_DISABLED

>>

>>  } odp_ipsec_op_mode_t;

>>

>>  /**

>> + * Protocol layers in IPSEC configuration

>> + */

>> +typedef enum odp_ipsec_proto_layer_t {

>> +       /** No layers */

>> +       ODP_IPSEC_LAYER_NONE = 0,

>> +

>> +       /** Layer L2 protocols (Ethernet, VLAN, etc) */

>> +       ODP_IPSEC_LAYER_L2,

>> +

>> +       /** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */

>> +       ODP_IPSEC_LAYER_L3,

>> +

>> +       /** Layer L4 protocols (UDP, TCP, SCTP) */

>> +       ODP_IPSEC_LAYER_L4,

>> +

>> +       /** All layers */

>> +       ODP_IPSEC_LAYER_ALL

>> +

>> +} odp_ipsec_proto_layer_t;

>> +

>> +/**

>>   * Configuration options for IPSEC inbound processing

>>   */

>>  typedef struct odp_ipsec_inbound_config_t {

>> @@ -81,9 +115,110 @@ typedef struct odp_ipsec_inbound_config_t {

>>

>>         } spi_lookup;

>>

>> +       /** Retain outer headers

>> +        *

>> +        *  Select up to which protocol layer (at least) outer headers are

>> +        *  retained in inbound inline processing. Default value is

>> +        *  ODP_IPSEC_LAYER_NONE.

>> +        *

>> +        *  ODP_IPSEC_LAYER_NONE: Application does not require any outer

>> +        *                        headers to be retained.

>> +        *

>> +        *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.

>> +        *

>> +        *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the

>> +        *                        same as ODP_IPSEC_LAYER_ALL.

>> +        *

>> +        *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the

>> +        *                        same as ODP_IPSEC_LAYER_ALL.

>> +        *

>> +        *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are

>> +        *                        retained. In transport mode, all headers

>> +        *                        before IP (carrying IPSEC) are retained.

>> +        *

>> +        */

>> +       odp_ipsec_proto_layer_t retain_outer;

>> +

>> +       /** Parse packet headers after IPSEC transformation

>> +        *

>> +        *  Select header parsing level after inbound processing. Headers of the

>> +        *  resulting packet must be parsed (at least) up to this level. Parsing

>> +        *  starts from IP (layer 3). Each successfully transformed packet has

>> +        *  a valid value for L3 offset regardless of the parse configuration.

>> +        *  Default value is ODP_IPSEC_LAYER_NONE.

>> +        */

>> +       odp_ipsec_proto_layer_t parse;

>> +

>> +       /** Flags to control IPSEC payload data checks up to the selected parse

>> +        *  level. */

>> +       union {

>> +               struct {

>> +                       /** Check IPv4 header checksum in IPSEC payload.

>> +                        *  Default value is 0. */

>> +                       uint32_t ipv4_chksum   : 1;

>> +

>> +                       /** Check UDP checksum in IPSEC payload.

>> +                        *  Default value is 0. */

>> +                       uint32_t udp_chksum    : 1;

>> +

>> +                       /** Check TCP checksum in IPSEC payload.

>> +                        *  Default value is 0. */

>> +                       uint32_t tcp_chksum    : 1;

>> +

>> +                       /** Check SCTP checksum in IPSEC payload.

>> +                        *  Default value is 0. */

>> +                       uint32_t sctp_chksum   : 1;

>> +               } check;

>> +

>> +               /** All bits of the bit field structure

>> +                 *

>> +                 * This field can be used to set/clear all flags, or bitwise

>> +                 * operations over the entire structure. */

>> +               uint32_t all_check;

>> +       };

>> +

>>  } odp_ipsec_inbound_config_t;

>>

>>  /**

>> + * Configuration options for IPSEC outbound processing

>> + */

>> +typedef struct odp_ipsec_outbound_config_t {

>> +       /** Flags to control L3/L4 checksum insertion as part of outbound

>> +        *  packet processing. Packet must have set with valid L3/L4 offsets.

>> +        *  Checksum configuration is ignored for packets that checksum cannot

>> +        *  be computed for (e.g. IPv4 fragments). Application may use a packet

>> +        *  metadata flag to disable checksum insertion per packet bases.

>> +        */

>> +       union {

>> +               struct {

>> +                       /** Insert IPv4 header checksum on the payload packet

>> +                        *  before IPSEC transformation. Default value is 0. */

>> +                       uint32_t inner_ipv4   : 1;

>> +

>> +                       /** Insert UDP header checksum on the payload packet

>> +                        *  before IPSEC transformation. Default value is 0. */

>> +                       uint32_t inner_udp    : 1;

>> +

>> +                       /** Insert TCP header checksum on the payload packet

>> +                        *  before IPSEC transformation. Default value is 0. */

>> +                       uint32_t inner_tcp    : 1;

>> +

>> +                       /** Insert SCTP header checksum on the payload packet

>> +                        *  before IPSEC transformation. Default value is 0. */

>> +                       uint32_t inner_sctp   : 1;

>> +

>> +               } chksum;

>> +

>> +               /** All bits of the bit field structure

>> +                 *

>> +                 * This field can be used to set/clear all flags, or bitwise

>> +                 * operations over the entire structure. */

>> +               uint32_t all_chksum;

>> +       };

>> +

>> +} odp_ipsec_outbound_config_t;

>> +

>> +/**

>>   * IPSEC capability

>>   */

>>  typedef struct odp_ipsec_capability_t {

>> @@ -106,6 +241,23 @@ typedef struct odp_ipsec_capability_t {

>>          */

>>         uint8_t op_mode_async;

>>

>> +       /** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support

>> +        *

>> +        *  0: Inline IPSEC operation is not supported

>> +        *  1: Inline IPSEC operation is supported

>> +        *  2: Inline IPSEC operation is supported and preferred

>> +        */

>> +       uint8_t op_mode_inline;

>> +

>> +       /** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of

>> +        *  resulting inbound packets.

>

> Since the operating mode here is INLINE, why not simply ODP_IPSEC_INLINE_CLS?

>

>> +        *

>> +        *  0: Classification of resulting packets is not supported

>> +        *  1: Classification of resulting packets is supported

>> +        *  2: Classification of resulting packets is supported and preferred

>> +        */

>> +       uint8_t pipeline_cls;

>

> inline_cls seems clearer here since this section is configuring inline

> processing options.

>

>> +

>>         /** Soft expiry limit in seconds support

>>          *

>>          *  0: Limit is not supported

>> @@ -132,12 +284,19 @@ typedef struct odp_ipsec_capability_t {

>>   * IPSEC configuration options

>>   */

>>  typedef struct odp_ipsec_config_t {

>> -       /** IPSEC operation mode. Application selects which mode (sync or async)

>> -        *  will be used for IPSEC operations.

>> +       /** Inbound IPSEC operation mode. Application selects which mode

>> +        *  will be used for inbound IPSEC operations.

>>          *

>>          *  @see odp_ipsec_in(), odp_ipsec_in_enq()

>>          */

>> -       odp_ipsec_op_mode_t op_mode;

>> +       odp_ipsec_op_mode_t inbound_mode;

>> +

>> +       /** Outbound IPSEC operation mode. Application selects which mode

>> +        *  will be used for outbound IPSEC operations.

>> +        *

>> +        *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()

>> +        */

>> +       odp_ipsec_op_mode_t outbound_mode;

>>

>>         /** Maximum number of IPSEC SAs that application will use

>>          * simultaneously */

>> @@ -146,6 +305,9 @@ typedef struct odp_ipsec_config_t {

>>         /** IPSEC inbound processing configuration */

>>         odp_ipsec_inbound_config_t inbound;

>>

>> +       /** IPSEC outbound processing configuration */

>> +       odp_ipsec_outbound_config_t outbound;

>> +

>>  } odp_ipsec_config_t;

>>

>>  /**

>> @@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {

>>         ODP_IPSEC_LOOKUP_DISABLED = 0,

>>

>>         /** Inbound SA lookup is enabled. Lookup matches only SPI value.

>> -        *  SA lookup failure status (error.sa_lookup) is reported through

>> +        *  In inline mode, a lookup miss directs the packet back to normal

>> +        *  packet input interface processing. In other modes, the SA lookup

>> +        *  failure status (error.sa_lookup) is reported through

>>          *  odp_ipsec_packet_result_t. */

>> -       ODP_IPSEC_LOOKUP_SPI

>> +       ODP_IPSEC_LOOKUP_SPI,

>> +

>> +       /** Inbound SA lookup is enabled. Lookup matches both SPI value and

>> +         * destination IP address. Functionality is otherwise identical to

>> +         * ODP_IPSEC_LOOKUP_SPI. */

>> +       ODP_IPSEC_LOOKUP_DSTADDR_SPI

>>

>>  } odp_ipsec_lookup_mode_t;

>>

>>  /**

>> + * Result event pipeline configuration

>> + */

>> +typedef enum odp_ipsec_pipeline_t {

>> +       /** Do not pipeline */

>> +       ODP_IPSEC_PIPELINE_NONE = 0,

>> +

>> +       /** Send IPSEC result events to the classifier.

>> +        *

>> +        *  IPSEC capability 'pipeline_cls' determines if pipelined

>> +        *  classification is supported. */

>> +       ODP_IPSEC_PIPELINE_CLS

>> +

>> +} odp_ipsec_pipeline_t;

>

> I'm not sure that calling this odp_ipsec_pipeline_t is better than the

> previous odp_ipsec_dest_mode_t. But since this is all about

> configuring INLINE processing, how about odp_ipsec_inline_config_t and

> the values are ODP_IPSEC_INLINE_DONE and ODP_IPSEC_INLINE_CLS. DONE

> simply indicates that inline processing is finished and the result is

> delivered back to the application.

>

> Since this is a per-SA configuration, the question is whether it

> should be one setting or separate in and out configs since we want a

> structure that will accommodate an ODP_IPSEC_INLINE_TM for sending

> IPsec output directly to TM. Whether we want to introduce that now, we

> want a structure that will accommodate this extension without needing

> redesign in the next iteration.

>

>> +

>> +/**

>>   * IPSEC Security Association (SA) parameters

>>   */

>>  typedef struct odp_ipsec_sa_param_t {

>> @@ -432,6 +616,21 @@ typedef struct odp_ipsec_sa_param_t {

>>         /** SPI value */

>>         uint32_t spi;

>>

>> +       /** Additional inbound SA lookup parameters. Values are considered

>> +        *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */

>> +       struct {

>> +               /** Select IP version

>> +                *

>> +                *  4:   IPv4

>> +                *  6:   IPv6

>> +                */

>> +               uint8_t ip_version;

>> +

>> +               /** IP destination address (NETWORK ENDIAN) */

>> +               void    *dst_addr;

>> +

>> +       } lookup_param;

>> +

>>         /** MTU for outbound IP fragmentation offload

>>          *

>>          *  This is the maximum length of IP packets that outbound IPSEC

>> @@ -440,13 +639,31 @@ typedef struct odp_ipsec_sa_param_t {

>>          */

>>         uint32_t mtu;

>>

>> +       /** Select pipelined destination for IPSEC result events

>> +        *

>> +        *  Asynchronous and inline modes generate result events. Select where

>> +        *  those events are sent. Inbound SAs may choose to use pipelined

>> +        *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.

>> +        */

>> +       odp_ipsec_pipeline_t pipeline;

>> +

>>         /** Destination queue for IPSEC events

>>          *

>> -        *  Operations in asynchronous mode enqueue resulting events into

>> -        *  this queue.

>> +        *  Operations in asynchronous or inline mode enqueue resulting events

>> +        *  into this queue.

>>          */

>>         odp_queue_t dest_queue;

>

> It seems confusing to have both pipeline and queue here since both are

> referring to what should happen next after IPsec processing is

> finished. The cases are:

>

> Input processing: Following IPsec processing the packet should either

> be sent to the classifier or delivered to a destination event queue.

>

> Output processing: Following IPsec processing the packet should either

> be sent back to the application via a destination event queue, or

> forwarded to a TM queue or directly to a pktio for transmission.

>

> Having two separate controls means that there are invalid combinations

> that have to be dealt with, which seems messy.

>

>>

>> +       /** Classifier destination CoS for IPSEC result events

>> +        *

>> +        *  Result events for successfully decapsulated packets are sent to

>> +        *  classification through this CoS. Other result events are sent to

>> +        *  'dest_queue'. This field is considered only when 'pipeline' is

>> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio

>> +        *  interface default CoS.

>> +        */

>> +       odp_cos_t dest_cos;

>

> Having multiple pieces of information needed for the same config

> suggests opportunities for simplification. Perhaps a scheme along the

> following lines:

>

enum odp_ipsec_next_t {
       ODP_IPSEC_NEXT_QUEUE = 0,
       ODP_IPSEC_NEXT_COS,
       ODP_IPSEC_NEXT_PKTIO,
       ODP_IPSEC_NEXT_TM,
} odp_ipsec_next_t;

> typedef struct odp_ipsec_next_config_t {

        odp_ipsec_next_t next;
        union {
            odp_queue_t queue;
            odp_cos_t cos;
            odp_pktio_t pktio;
            odp_tm_queue_t tm_q;
        };
>

> } odp_ipsec_next_config_t;

>

>> +

>>         /** User defined SA context pointer

>>          *

>>          *  User defined context pointer associated with the SA.

>> @@ -679,6 +896,18 @@ typedef struct odp_ipsec_op_status_t {

>>                 uint32_t all_error;

>>         };

>>

>> +       union {

>> +               /** Status flags */

>> +               struct {

>> +                       /** Packet was processed in inline mode */

>> +                       uint32_t inline_mode      : 1;

>> +

>> +               } flag;

>> +

>> +               /** All flag bits */

>> +               uint32_t all_flag;

>> +       };

>> +

>>  } odp_ipsec_op_status_t;

>>

>>  /**

>> @@ -708,7 +937,7 @@ typedef struct odp_ipsec_op_param_t {

>>

>>         /** Pointer to an array of packets

>>          *

>> -        *  Each packet must have a valid value for these meta-data:

>> +        *  Each packet must have a valid value for these metadata:

>>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>>          *  * L4 offset: For inbound direction, when udp_encap is enabled -

>>          *               offset to the first byte of the encapsulating UDP

>> @@ -733,6 +962,35 @@ typedef struct odp_ipsec_op_param_t {

>>  } odp_ipsec_op_param_t;

>>

>>  /**

>> + * Outbound inline IPSEC operation parameters

>> + */

>> +typedef struct odp_ipsec_inline_op_param_t {

>> +       /** Packet output interface for inline output operation

>> +        *

>> +        *  Outbound inline IPSEC operation uses this packet IO interface to

>> +        *  output the packet after a successful IPSEC transformation. The pktio

>> +        *  must have been configured to operate in inline IPSEC mode.

>> +        */

>> +       odp_pktio_t pktio;

>> +

>> +       /** Outer headers for inline output operation

>> +        *

>> +        *  Outbound inline IPSEC operation uses this information to prepend

>> +        *  outer headers to the IPSEC packet before sending it out.

>> +        */

>> +       struct {

>> +               /** Points to first byte of outer headers to be copied in

>> +                *  front of the outgoing IPSEC packet. Implementation copies

>> +                *  the headers during odp_ipsec_out_inline() call. */

>> +               uint8_t *ptr;

>> +

>> +               /** Outer header length in bytes */

>> +               uint32_t len;

>> +       } outer_hdr;

>> +

>> +} odp_ipsec_inline_op_param_t;

>> +

>> +/**

>>   * IPSEC operation result for a packet

>>   */

>>  typedef struct odp_ipsec_packet_result_t {

>> @@ -758,6 +1016,23 @@ typedef struct odp_ipsec_packet_result_t {

>>          */

>>         odp_ipsec_sa_t sa;

>>

>> +       /** Packet outer header status before inbound inline processing.

>> +        *  This is valid only when status.flag.inline_mode is set.

>> +        */

>> +       struct {

>> +               /** Points to the first byte of retained outer headers. These

>> +                *  headers are stored in a contiquous, per packet,

>> +                *  implementation specific memory space. Since the memory space

>> +                *  may overlap with e.g. packet head/tailroom, the content

>> +                *  becomes invalid if packet data storage is modified in

>> +                *  anyway. The memory space may not be sharable to other

>> +                *  threads. */

>> +               uint8_t *ptr;

>> +

>> +               /** Outer header length in bytes */

>> +               uint32_t len;

>> +       } outer_hdr;

>> +

>>  } odp_ipsec_packet_result_t;

>>

>>  /**

>> @@ -779,18 +1054,14 @@ typedef struct odp_ipsec_op_result_t {

>>          *  at least 'num_pkt' elements.

>>          *

>>          *  Each successfully transformed packet has a valid value for these

>> -        *  meta-data:

>> +        *  metadata regardless of the inner packet parse configuration.

>> +        *  (odp_ipsec_inbound_config_t):

>>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>> -        *  * L4 offset: Offset to the first byte of the valid and known L4

>> -        *               header (immediately following the IP header).

>> -        *  * Various flags about L3 and L4 layers:

>> -        *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,

>> -        *               has_ipsec, has_udp, has_tcp, etc depending on

>> -        *               the resulted packet format

>> +        *  * pktio:     For inbound inline IPSEC processed packets, original

>> +        *               packet input interface

>>          *

>> -        * @see odp_packet_l3_offset(), odp_packet_l4_offset(),

>> -        *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),

>> -        *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()

>> +        *  Other metadata for parse results and error checks depend on

>> +        *  configuration (selected parse and error check levels).

>>          */

>>         odp_packet_t *pkt;

>>

>> @@ -921,10 +1192,10 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>>  /**

>>   * Inbound asynchronous IPSEC operation

>>   *

>> - * This operation does inbound IPSEC processing in asynchronous mode

>> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

>> - * odp_ipsec_in(), but outputs all results through one or more

>> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

>> + * This operation does inbound IPSEC processing in asynchronous mode. It

>> + * processes packets otherwise identically to odp_ipsec_in(), but outputs all

>> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

>> + * ordering considerations.

>>   *

>>   * Asynchronous mode maintains (operation input) packet order per SA when

>>   * application calls the operation within an ordered or atomic scheduler context

>> @@ -934,6 +1205,11 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>>   * events for the same SA are enqueued in order, and packet handles (for the

>>   * same SA) are stored in order within an event.

>>   *

>> + * The function may be used also in inline processing mode, e.g. for IPSEC

>> + * packets for which inline processing is not possible. Packets for the same SA

>> + * may be processed simultaneously in both modes (initiated by this function

>> + * and inline operation).

>> + *

>>   * @param         input   Operation input parameters

>>   *

>>   * @return Number of input packets consumed (0 ... input.num_pkt)

>> @@ -946,10 +1222,10 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>  /**

>>   * Outbound asynchronous IPSEC operation

>>   *

>> - * This operation does outbound IPSEC processing in asynchronous mode

>> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

>> - * odp_ipsec_out(), but outputs all results through one or more

>> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

>> + * This operation does outbound IPSEC processing in asynchronous mode. It

>> + * processes packets otherwise identically to odp_ipsec_out(), but outputs all

>> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

>> + * ordering considerations.

>>   *

>>   * Asynchronous mode maintains (operation input) packet order per SA when

>>   * application calls the operation within an ordered or atomic scheduler context

>> @@ -959,6 +1235,9 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>   * events for the same SA are enqueued in order, and packet handles (for the

>>   * same SA) are stored in order within an event.

>>   *

>> + * The function may be used also in inline processing mode, e.g. for IPSEC

>> + * packets for which inline processing is not possible.

>> + *

>>   * @param         input   Operation input parameters

>>   *

>>   * @return Number of input packets consumed (0 ... input.num_pkt)

>> @@ -969,6 +1248,28 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);

>>

>>  /**

>> + * Outbound inline IPSEC operation

>> + *

>> + * This operation does outbound inline IPSEC processing for the packets. It's

>> + * otherwise identical to odp_ipsec_out_enq(), but outputs all successfully

>> + * transformed packets to the specified output interface, instead of generating

>> + * result events for those.

>> + *

>> + * Inline operation parameters are defined per packet. The array of parameters

>> + * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.

>> + *

>> + * @param         op_param      Operation parameters

>> + * @param         inline_param  Outbound inline operation specific parameters

>> + *

>> + * @return Number of packets consumed (0 ... op_param.num_pkt)

>> + * @retval <0     On failure

>> + *

>> + * @see odp_ipsec_out_enq()

>> + */

>> +int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,

>> +                        const odp_ipsec_inline_op_param_t *inline_param);

>> +

>> +/**

>>   * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event

>>   *

>>   * Copies IPSEC operation results from an event. The event must be of

>> diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h

>> index cec1f22..8802089 100644

>> --- a/include/odp/api/spec/packet_io.h

>> +++ b/include/odp/api/spec/packet_io.h

>> @@ -407,6 +407,38 @@ typedef struct odp_pktio_config_t {

>>          * interface capability before enabling the same. */

>>         odp_bool_t enable_loop;

>>

>> +       /** Inbound IPSEC inlined with packet input

>> +        *

>> +        *  Enable/disable inline inbound IPSEC operation. When enabled packet

>> +        *  input directs all IPSEC packets automatically to IPSEC inbound

>> +        *  processing. IPSEC configuration is done through the IPSEC API.

>> +        *  Packets that are not (recognized as) IPSEC are processed

>> +        *  according to the packet input configuration.

>> +        *

>> +        *  0: Disable inbound IPSEC inline operation (default)

>> +        *  1: Enable inbound IPSEC inline operation

>> +        *

>> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

>> +        */

>> +       odp_bool_t inbound_ipsec;

>> +

>> +       /** Outbound IPSEC inlined with packet output

>> +        *

>> +        *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC

>> +        *  outbound processing can send outgoing IPSEC packets directly

>> +        *  to the pktio interface for output. IPSEC configuration is done

>> +        *  through the IPSEC API.

>> +        *

>> +        *  Outbound IPSEC inline operation cannot be combined with traffic

>> +        *  manager (ODP_PKTOUT_MODE_TM).

>> +        *

>> +        *  0: Disable outbound IPSEC inline operation (default)

>> +        *  1: Enable outbound IPSEC inline operation

>> +        *

>> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

>> +        */

>> +       odp_bool_t outbound_ipsec;

>> +

>>  } odp_pktio_config_t;

>>

>>  /**

>> --

>> 2.8.1

>>
Bogdan Pricope March 27, 2017, 11:43 a.m. UTC | #3
On 26 March 2017 at 18:06, Bill Fischofer <bill.fischofer@linaro.org> wrote:
> Hit return too soon.

>

> On Sun, Mar 26, 2017 at 10:01 AM, Bill Fischofer

> <bill.fischofer@linaro.org> wrote:

>> On Fri, Mar 24, 2017 at 10:04 AM, Petri Savolainen

>> <petri.savolainen@linaro.org> wrote:

>>> Added support for inline IPSEC processing on packet input and

>>> output. Inline mode IPSEC and traffic manager cannot be enabled

>>> (currently) on the same pktio interface.

>>>

>>> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

>>> ---

>>>  include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---

>>>  include/odp/api/spec/packet_io.h |  32 ++++

>>>  2 files changed, 360 insertions(+), 27 deletions(-)

>>>

>>> diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h

>>> index d3e51bc..2e7e1e4 100644

>>> --- a/include/odp/api/spec/ipsec.h

>>> +++ b/include/odp/api/spec/ipsec.h

>>> @@ -19,6 +19,8 @@ extern "C" {

>>>  #endif

>>>

>>>  #include <odp/api/crypto.h>

>>> +#include <odp/api/packet_io.h>

>>> +#include <odp/api/classification.h>

>>>

>>>  /** @defgroup odp_ipsec ODP IPSEC

>>>   *  Operations of IPSEC API.

>>> @@ -51,11 +53,43 @@ typedef enum odp_ipsec_op_mode_t {

>>>           * Application uses asynchronous IPSEC operations,

>>>           * which return results via events.

>>>           */

>>> -       ODP_IPSEC_OP_MODE_ASYNC

>>> +       ODP_IPSEC_OP_MODE_ASYNC,

>>> +

>>> +       /** Inline IPSEC operation

>>> +         *

>>> +         * Packet input/output is connected directly to IPSEC inbound/outbound

>>> +         * processing. Application uses asynchronous or inline IPSEC

>>> +         * operations.

>>> +         */

>>> +       ODP_IPSEC_OP_MODE_INLINE,

>>> +

>>> +       /** IPSEC is disabled in inbound / outbound direction */

>>> +       ODP_IPSEC_OP_MODE_DISABLED

>>>

>>>  } odp_ipsec_op_mode_t;

>>>

>>>  /**

>>> + * Protocol layers in IPSEC configuration

>>> + */

>>> +typedef enum odp_ipsec_proto_layer_t {

>>> +       /** No layers */

>>> +       ODP_IPSEC_LAYER_NONE = 0,

>>> +

>>> +       /** Layer L2 protocols (Ethernet, VLAN, etc) */

>>> +       ODP_IPSEC_LAYER_L2,

>>> +

>>> +       /** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */

>>> +       ODP_IPSEC_LAYER_L3,

>>> +

>>> +       /** Layer L4 protocols (UDP, TCP, SCTP) */

>>> +       ODP_IPSEC_LAYER_L4,

>>> +

>>> +       /** All layers */

>>> +       ODP_IPSEC_LAYER_ALL

>>> +

>>> +} odp_ipsec_proto_layer_t;

>>> +

>>> +/**

>>>   * Configuration options for IPSEC inbound processing

>>>   */

>>>  typedef struct odp_ipsec_inbound_config_t {

>>> @@ -81,9 +115,110 @@ typedef struct odp_ipsec_inbound_config_t {

>>>

>>>         } spi_lookup;

>>>

>>> +       /** Retain outer headers

>>> +        *

>>> +        *  Select up to which protocol layer (at least) outer headers are

>>> +        *  retained in inbound inline processing. Default value is

>>> +        *  ODP_IPSEC_LAYER_NONE.

>>> +        *

>>> +        *  ODP_IPSEC_LAYER_NONE: Application does not require any outer

>>> +        *                        headers to be retained.

>>> +        *

>>> +        *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.

>>> +        *

>>> +        *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the

>>> +        *                        same as ODP_IPSEC_LAYER_ALL.

>>> +        *

>>> +        *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the

>>> +        *                        same as ODP_IPSEC_LAYER_ALL.

>>> +        *

>>> +        *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are

>>> +        *                        retained. In transport mode, all headers

>>> +        *                        before IP (carrying IPSEC) are retained.

>>> +        *

>>> +        */

>>> +       odp_ipsec_proto_layer_t retain_outer;

>>> +

>>> +       /** Parse packet headers after IPSEC transformation

>>> +        *

>>> +        *  Select header parsing level after inbound processing. Headers of the

>>> +        *  resulting packet must be parsed (at least) up to this level. Parsing

>>> +        *  starts from IP (layer 3). Each successfully transformed packet has

>>> +        *  a valid value for L3 offset regardless of the parse configuration.

>>> +        *  Default value is ODP_IPSEC_LAYER_NONE.

>>> +        */

>>> +       odp_ipsec_proto_layer_t parse;

>>> +

>>> +       /** Flags to control IPSEC payload data checks up to the selected parse

>>> +        *  level. */

>>> +       union {

>>> +               struct {

>>> +                       /** Check IPv4 header checksum in IPSEC payload.

>>> +                        *  Default value is 0. */

>>> +                       uint32_t ipv4_chksum   : 1;

>>> +

>>> +                       /** Check UDP checksum in IPSEC payload.

>>> +                        *  Default value is 0. */

>>> +                       uint32_t udp_chksum    : 1;

>>> +

>>> +                       /** Check TCP checksum in IPSEC payload.

>>> +                        *  Default value is 0. */

>>> +                       uint32_t tcp_chksum    : 1;

>>> +

>>> +                       /** Check SCTP checksum in IPSEC payload.

>>> +                        *  Default value is 0. */

>>> +                       uint32_t sctp_chksum   : 1;

>>> +               } check;

>>> +

>>> +               /** All bits of the bit field structure

>>> +                 *

>>> +                 * This field can be used to set/clear all flags, or bitwise

>>> +                 * operations over the entire structure. */

>>> +               uint32_t all_check;

>>> +       };

>>> +

>>>  } odp_ipsec_inbound_config_t;

>>>

>>>  /**

>>> + * Configuration options for IPSEC outbound processing

>>> + */

>>> +typedef struct odp_ipsec_outbound_config_t {

>>> +       /** Flags to control L3/L4 checksum insertion as part of outbound

>>> +        *  packet processing. Packet must have set with valid L3/L4 offsets.

>>> +        *  Checksum configuration is ignored for packets that checksum cannot

>>> +        *  be computed for (e.g. IPv4 fragments). Application may use a packet

>>> +        *  metadata flag to disable checksum insertion per packet bases.

>>> +        */

>>> +       union {

>>> +               struct {

>>> +                       /** Insert IPv4 header checksum on the payload packet

>>> +                        *  before IPSEC transformation. Default value is 0. */

>>> +                       uint32_t inner_ipv4   : 1;

>>> +

>>> +                       /** Insert UDP header checksum on the payload packet

>>> +                        *  before IPSEC transformation. Default value is 0. */

>>> +                       uint32_t inner_udp    : 1;

>>> +

>>> +                       /** Insert TCP header checksum on the payload packet

>>> +                        *  before IPSEC transformation. Default value is 0. */

>>> +                       uint32_t inner_tcp    : 1;

>>> +

>>> +                       /** Insert SCTP header checksum on the payload packet

>>> +                        *  before IPSEC transformation. Default value is 0. */

>>> +                       uint32_t inner_sctp   : 1;

>>> +

>>> +               } chksum;

>>> +

>>> +               /** All bits of the bit field structure

>>> +                 *

>>> +                 * This field can be used to set/clear all flags, or bitwise

>>> +                 * operations over the entire structure. */

>>> +               uint32_t all_chksum;

>>> +       };

>>> +

>>> +} odp_ipsec_outbound_config_t;

>>> +

>>> +/**

>>>   * IPSEC capability

>>>   */

>>>  typedef struct odp_ipsec_capability_t {

>>> @@ -106,6 +241,23 @@ typedef struct odp_ipsec_capability_t {

>>>          */

>>>         uint8_t op_mode_async;

>>>

>>> +       /** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support

>>> +        *

>>> +        *  0: Inline IPSEC operation is not supported

>>> +        *  1: Inline IPSEC operation is supported

>>> +        *  2: Inline IPSEC operation is supported and preferred

>>> +        */

>>> +       uint8_t op_mode_inline;

>>> +

>>> +       /** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of

>>> +        *  resulting inbound packets.

>>

>> Since the operating mode here is INLINE, why not simply ODP_IPSEC_INLINE_CLS?

>>

>>> +        *

>>> +        *  0: Classification of resulting packets is not supported

>>> +        *  1: Classification of resulting packets is supported

>>> +        *  2: Classification of resulting packets is supported and preferred

>>> +        */

>>> +       uint8_t pipeline_cls;

>>

>> inline_cls seems clearer here since this section is configuring inline

>> processing options.

>>

>>> +

>>>         /** Soft expiry limit in seconds support

>>>          *

>>>          *  0: Limit is not supported

>>> @@ -132,12 +284,19 @@ typedef struct odp_ipsec_capability_t {

>>>   * IPSEC configuration options

>>>   */

>>>  typedef struct odp_ipsec_config_t {

>>> -       /** IPSEC operation mode. Application selects which mode (sync or async)

>>> -        *  will be used for IPSEC operations.

>>> +       /** Inbound IPSEC operation mode. Application selects which mode

>>> +        *  will be used for inbound IPSEC operations.

>>>          *

>>>          *  @see odp_ipsec_in(), odp_ipsec_in_enq()

>>>          */

>>> -       odp_ipsec_op_mode_t op_mode;

>>> +       odp_ipsec_op_mode_t inbound_mode;

>>> +

>>> +       /** Outbound IPSEC operation mode. Application selects which mode

>>> +        *  will be used for outbound IPSEC operations.

>>> +        *

>>> +        *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()

>>> +        */

>>> +       odp_ipsec_op_mode_t outbound_mode;

>>>

>>>         /** Maximum number of IPSEC SAs that application will use

>>>          * simultaneously */

>>> @@ -146,6 +305,9 @@ typedef struct odp_ipsec_config_t {

>>>         /** IPSEC inbound processing configuration */

>>>         odp_ipsec_inbound_config_t inbound;

>>>

>>> +       /** IPSEC outbound processing configuration */

>>> +       odp_ipsec_outbound_config_t outbound;

>>> +

>>>  } odp_ipsec_config_t;

>>>

>>>  /**

>>> @@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {

>>>         ODP_IPSEC_LOOKUP_DISABLED = 0,

>>>

>>>         /** Inbound SA lookup is enabled. Lookup matches only SPI value.

>>> -        *  SA lookup failure status (error.sa_lookup) is reported through

>>> +        *  In inline mode, a lookup miss directs the packet back to normal

>>> +        *  packet input interface processing. In other modes, the SA lookup

>>> +        *  failure status (error.sa_lookup) is reported through

>>>          *  odp_ipsec_packet_result_t. */

>>> -       ODP_IPSEC_LOOKUP_SPI

>>> +       ODP_IPSEC_LOOKUP_SPI,

>>> +

>>> +       /** Inbound SA lookup is enabled. Lookup matches both SPI value and

>>> +         * destination IP address. Functionality is otherwise identical to

>>> +         * ODP_IPSEC_LOOKUP_SPI. */

>>> +       ODP_IPSEC_LOOKUP_DSTADDR_SPI

>>>

>>>  } odp_ipsec_lookup_mode_t;

>>>

>>>  /**

>>> + * Result event pipeline configuration

>>> + */

>>> +typedef enum odp_ipsec_pipeline_t {

>>> +       /** Do not pipeline */

>>> +       ODP_IPSEC_PIPELINE_NONE = 0,

>>> +

>>> +       /** Send IPSEC result events to the classifier.

>>> +        *

>>> +        *  IPSEC capability 'pipeline_cls' determines if pipelined

>>> +        *  classification is supported. */

>>> +       ODP_IPSEC_PIPELINE_CLS

>>> +

>>> +} odp_ipsec_pipeline_t;

>>

>> I'm not sure that calling this odp_ipsec_pipeline_t is better than the

>> previous odp_ipsec_dest_mode_t. But since this is all about

>> configuring INLINE processing, how about odp_ipsec_inline_config_t and

>> the values are ODP_IPSEC_INLINE_DONE and ODP_IPSEC_INLINE_CLS. DONE

>> simply indicates that inline processing is finished and the result is

>> delivered back to the application.

>>

>> Since this is a per-SA configuration, the question is whether it

>> should be one setting or separate in and out configs since we want a

>> structure that will accommodate an ODP_IPSEC_INLINE_TM for sending

>> IPsec output directly to TM. Whether we want to introduce that now, we

>> want a structure that will accommodate this extension without needing

>> redesign in the next iteration.

>>

>>> +

>>> +/**

>>>   * IPSEC Security Association (SA) parameters

>>>   */

>>>  typedef struct odp_ipsec_sa_param_t {

>>> @@ -432,6 +616,21 @@ typedef struct odp_ipsec_sa_param_t {

>>>         /** SPI value */

>>>         uint32_t spi;

>>>

>>> +       /** Additional inbound SA lookup parameters. Values are considered

>>> +        *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */

>>> +       struct {

>>> +               /** Select IP version

>>> +                *

>>> +                *  4:   IPv4

>>> +                *  6:   IPv6

>>> +                */

>>> +               uint8_t ip_version;

>>> +

>>> +               /** IP destination address (NETWORK ENDIAN) */

>>> +               void    *dst_addr;

>>> +

>>> +       } lookup_param;

>>> +

>>>         /** MTU for outbound IP fragmentation offload

>>>          *

>>>          *  This is the maximum length of IP packets that outbound IPSEC

>>> @@ -440,13 +639,31 @@ typedef struct odp_ipsec_sa_param_t {

>>>          */

>>>         uint32_t mtu;

>>>

>>> +       /** Select pipelined destination for IPSEC result events

>>> +        *

>>> +        *  Asynchronous and inline modes generate result events. Select where

>>> +        *  those events are sent. Inbound SAs may choose to use pipelined

>>> +        *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.

>>> +        */

>>> +       odp_ipsec_pipeline_t pipeline;

>>> +

>>>         /** Destination queue for IPSEC events

>>>          *

>>> -        *  Operations in asynchronous mode enqueue resulting events into

>>> -        *  this queue.

>>> +        *  Operations in asynchronous or inline mode enqueue resulting events

>>> +        *  into this queue.

>>>          */

>>>         odp_queue_t dest_queue;

>>

>> It seems confusing to have both pipeline and queue here since both are

>> referring to what should happen next after IPsec processing is

>> finished. The cases are:

>>

>> Input processing: Following IPsec processing the packet should either

>> be sent to the classifier or delivered to a destination event queue.

>>

>> Output processing: Following IPsec processing the packet should either

>> be sent back to the application via a destination event queue, or

>> forwarded to a TM queue or directly to a pktio for transmission.

>>

>> Having two separate controls means that there are invalid combinations

>> that have to be dealt with, which seems messy.

>>

>>>

>>> +       /** Classifier destination CoS for IPSEC result events

>>> +        *

>>> +        *  Result events for successfully decapsulated packets are sent to

>>> +        *  classification through this CoS. Other result events are sent to

>>> +        *  'dest_queue'. This field is considered only when 'pipeline' is

>>> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio

>>> +        *  interface default CoS.

>>> +        */

>>> +       odp_cos_t dest_cos;

>>

>> Having multiple pieces of information needed for the same config

>> suggests opportunities for simplification. Perhaps a scheme along the

>> following lines:

>>

> enum odp_ipsec_next_t {

>        ODP_IPSEC_NEXT_QUEUE = 0,

>        ODP_IPSEC_NEXT_COS,

>        ODP_IPSEC_NEXT_PKTIO,

>        ODP_IPSEC_NEXT_TM,

> } odp_ipsec_next_t;

>

>> typedef struct odp_ipsec_next_config_t {

>         odp_ipsec_next_t next;

>         union {

>             odp_queue_t queue;

>             odp_cos_t cos;

>             odp_pktio_t pktio;

>             odp_tm_queue_t tm_q;

>         };

>>

>> } odp_ipsec_next_config_t;


Maybe this form will make it clearer:
union {
        struct {
            odp_ipsec_dest_in_type_t dest_type;

            union {
                odp_queue_t queue;
                odp_cos_t cos;
            } dest_val;
        } inbound;

        struct {
            odp_ipsec_dest_out_type_t dest_type;

            union {
                odp_queue_t queue;
                odp_pktio_t pktio;
                odp_tm_queue_t tm_q;
            } dest_val;
        } outbound;
    } dest;

Yet, I still believe this model is limiting flexibility... maybe we
need a framework with a generic way to connect different HW modules.

>>

>>> +

>>>         /** User defined SA context pointer

>>>          *

>>>          *  User defined context pointer associated with the SA.

>>> @@ -679,6 +896,18 @@ typedef struct odp_ipsec_op_status_t {

>>>                 uint32_t all_error;

>>>         };

>>>

>>> +       union {

>>> +               /** Status flags */

>>> +               struct {

>>> +                       /** Packet was processed in inline mode */

>>> +                       uint32_t inline_mode      : 1;

>>> +

>>> +               } flag;

>>> +

>>> +               /** All flag bits */

>>> +               uint32_t all_flag;

>>> +       };

>>> +

>>>  } odp_ipsec_op_status_t;

>>>

>>>  /**

>>> @@ -708,7 +937,7 @@ typedef struct odp_ipsec_op_param_t {

>>>

>>>         /** Pointer to an array of packets

>>>          *

>>> -        *  Each packet must have a valid value for these meta-data:

>>> +        *  Each packet must have a valid value for these metadata:

>>>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>>>          *  * L4 offset: For inbound direction, when udp_encap is enabled -

>>>          *               offset to the first byte of the encapsulating UDP

>>> @@ -733,6 +962,35 @@ typedef struct odp_ipsec_op_param_t {

>>>  } odp_ipsec_op_param_t;

>>>

>>>  /**

>>> + * Outbound inline IPSEC operation parameters

>>> + */

>>> +typedef struct odp_ipsec_inline_op_param_t {

>>> +       /** Packet output interface for inline output operation

>>> +        *

>>> +        *  Outbound inline IPSEC operation uses this packet IO interface to

>>> +        *  output the packet after a successful IPSEC transformation. The pktio

>>> +        *  must have been configured to operate in inline IPSEC mode.

>>> +        */

>>> +       odp_pktio_t pktio;

>>> +

>>> +       /** Outer headers for inline output operation

>>> +        *

>>> +        *  Outbound inline IPSEC operation uses this information to prepend

>>> +        *  outer headers to the IPSEC packet before sending it out.

>>> +        */

>>> +       struct {

>>> +               /** Points to first byte of outer headers to be copied in

>>> +                *  front of the outgoing IPSEC packet. Implementation copies

>>> +                *  the headers during odp_ipsec_out_inline() call. */

>>> +               uint8_t *ptr;

>>> +

>>> +               /** Outer header length in bytes */

>>> +               uint32_t len;

>>> +       } outer_hdr;

>>> +

>>> +} odp_ipsec_inline_op_param_t;

>>> +

>>> +/**

>>>   * IPSEC operation result for a packet

>>>   */

>>>  typedef struct odp_ipsec_packet_result_t {

>>> @@ -758,6 +1016,23 @@ typedef struct odp_ipsec_packet_result_t {

>>>          */

>>>         odp_ipsec_sa_t sa;

>>>

>>> +       /** Packet outer header status before inbound inline processing.

>>> +        *  This is valid only when status.flag.inline_mode is set.

>>> +        */

>>> +       struct {

>>> +               /** Points to the first byte of retained outer headers. These

>>> +                *  headers are stored in a contiquous, per packet,

>>> +                *  implementation specific memory space. Since the memory space

>>> +                *  may overlap with e.g. packet head/tailroom, the content

>>> +                *  becomes invalid if packet data storage is modified in

>>> +                *  anyway. The memory space may not be sharable to other

>>> +                *  threads. */

>>> +               uint8_t *ptr;

>>> +

>>> +               /** Outer header length in bytes */

>>> +               uint32_t len;

>>> +       } outer_hdr;

>>> +

>>>  } odp_ipsec_packet_result_t;

>>>

>>>  /**

>>> @@ -779,18 +1054,14 @@ typedef struct odp_ipsec_op_result_t {

>>>          *  at least 'num_pkt' elements.

>>>          *

>>>          *  Each successfully transformed packet has a valid value for these

>>> -        *  meta-data:

>>> +        *  metadata regardless of the inner packet parse configuration.

>>> +        *  (odp_ipsec_inbound_config_t):

>>>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>>> -        *  * L4 offset: Offset to the first byte of the valid and known L4

>>> -        *               header (immediately following the IP header).

>>> -        *  * Various flags about L3 and L4 layers:

>>> -        *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,

>>> -        *               has_ipsec, has_udp, has_tcp, etc depending on

>>> -        *               the resulted packet format

>>> +        *  * pktio:     For inbound inline IPSEC processed packets, original

>>> +        *               packet input interface

>>>          *

>>> -        * @see odp_packet_l3_offset(), odp_packet_l4_offset(),

>>> -        *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),

>>> -        *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()

>>> +        *  Other metadata for parse results and error checks depend on

>>> +        *  configuration (selected parse and error check levels).

>>>          */

>>>         odp_packet_t *pkt;

>>>

>>> @@ -921,10 +1192,10 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>>>  /**

>>>   * Inbound asynchronous IPSEC operation

>>>   *

>>> - * This operation does inbound IPSEC processing in asynchronous mode

>>> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

>>> - * odp_ipsec_in(), but outputs all results through one or more

>>> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

>>> + * This operation does inbound IPSEC processing in asynchronous mode. It

>>> + * processes packets otherwise identically to odp_ipsec_in(), but outputs all

>>> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

>>> + * ordering considerations.

>>>   *

>>>   * Asynchronous mode maintains (operation input) packet order per SA when

>>>   * application calls the operation within an ordered or atomic scheduler context

>>> @@ -934,6 +1205,11 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>>>   * events for the same SA are enqueued in order, and packet handles (for the

>>>   * same SA) are stored in order within an event.

>>>   *

>>> + * The function may be used also in inline processing mode, e.g. for IPSEC

>>> + * packets for which inline processing is not possible. Packets for the same SA

>>> + * may be processed simultaneously in both modes (initiated by this function

>>> + * and inline operation).

>>> + *

>>>   * @param         input   Operation input parameters

>>>   *

>>>   * @return Number of input packets consumed (0 ... input.num_pkt)

>>> @@ -946,10 +1222,10 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>>  /**

>>>   * Outbound asynchronous IPSEC operation

>>>   *

>>> - * This operation does outbound IPSEC processing in asynchronous mode

>>> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

>>> - * odp_ipsec_out(), but outputs all results through one or more

>>> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

>>> + * This operation does outbound IPSEC processing in asynchronous mode. It

>>> + * processes packets otherwise identically to odp_ipsec_out(), but outputs all

>>> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

>>> + * ordering considerations.

>>>   *

>>>   * Asynchronous mode maintains (operation input) packet order per SA when

>>>   * application calls the operation within an ordered or atomic scheduler context

>>> @@ -959,6 +1235,9 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>>   * events for the same SA are enqueued in order, and packet handles (for the

>>>   * same SA) are stored in order within an event.

>>>   *

>>> + * The function may be used also in inline processing mode, e.g. for IPSEC

>>> + * packets for which inline processing is not possible.

>>> + *

>>>   * @param         input   Operation input parameters

>>>   *

>>>   * @return Number of input packets consumed (0 ... input.num_pkt)

>>> @@ -969,6 +1248,28 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>>>  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);

>>>

>>>  /**

>>> + * Outbound inline IPSEC operation

>>> + *

>>> + * This operation does outbound inline IPSEC processing for the packets. It's

>>> + * otherwise identical to odp_ipsec_out_enq(), but outputs all successfully

>>> + * transformed packets to the specified output interface, instead of generating

>>> + * result events for those.

>>> + *

>>> + * Inline operation parameters are defined per packet. The array of parameters

>>> + * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.

>>> + *

>>> + * @param         op_param      Operation parameters

>>> + * @param         inline_param  Outbound inline operation specific parameters

>>> + *

>>> + * @return Number of packets consumed (0 ... op_param.num_pkt)

>>> + * @retval <0     On failure

>>> + *

>>> + * @see odp_ipsec_out_enq()

>>> + */

>>> +int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,

>>> +                        const odp_ipsec_inline_op_param_t *inline_param);

>>> +

>>> +/**

>>>   * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event

>>>   *

>>>   * Copies IPSEC operation results from an event. The event must be of

>>> diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h

>>> index cec1f22..8802089 100644

>>> --- a/include/odp/api/spec/packet_io.h

>>> +++ b/include/odp/api/spec/packet_io.h

>>> @@ -407,6 +407,38 @@ typedef struct odp_pktio_config_t {

>>>          * interface capability before enabling the same. */

>>>         odp_bool_t enable_loop;

>>>

>>> +       /** Inbound IPSEC inlined with packet input

>>> +        *

>>> +        *  Enable/disable inline inbound IPSEC operation. When enabled packet

>>> +        *  input directs all IPSEC packets automatically to IPSEC inbound

>>> +        *  processing. IPSEC configuration is done through the IPSEC API.

>>> +        *  Packets that are not (recognized as) IPSEC are processed

>>> +        *  according to the packet input configuration.

>>> +        *

>>> +        *  0: Disable inbound IPSEC inline operation (default)

>>> +        *  1: Enable inbound IPSEC inline operation

>>> +        *

>>> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

>>> +        */

>>> +       odp_bool_t inbound_ipsec;

>>> +

>>> +       /** Outbound IPSEC inlined with packet output

>>> +        *

>>> +        *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC

>>> +        *  outbound processing can send outgoing IPSEC packets directly

>>> +        *  to the pktio interface for output. IPSEC configuration is done

>>> +        *  through the IPSEC API.

>>> +        *

>>> +        *  Outbound IPSEC inline operation cannot be combined with traffic

>>> +        *  manager (ODP_PKTOUT_MODE_TM).

>>> +        *

>>> +        *  0: Disable outbound IPSEC inline operation (default)

>>> +        *  1: Enable outbound IPSEC inline operation

>>> +        *

>>> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

>>> +        */

>>> +       odp_bool_t outbound_ipsec;

>>> +

>>>  } odp_pktio_config_t;

>>>

>>>  /**

>>> --

>>> 2.8.1

>>>
Savolainen, Petri (Nokia - FI/Espoo) March 27, 2017, 11:55 a.m. UTC | #4
> >> +

> >> +       /** Support of pipelined classification

> (ODP_IPSEC_PIPELINE_CLS) of

> >> +        *  resulting inbound packets.

> >

> > Since the operating mode here is INLINE, why not simply

> ODP_IPSEC_INLINE_CLS?



Classifier can be used also in async mode, which would make term "inline" overloaded. Term inline is used to make difference between IPSEC inline and async modes. Pipeline is used for defining further processing for successfully ipsec transformed packets. Exception (not transformed) packets do not go into the pipeline.


> >

> >> +        *

> >> +        *  0: Classification of resulting packets is not supported

> >> +        *  1: Classification of resulting packets is supported

> >> +        *  2: Classification of resulting packets is supported and

> preferred

> >> +        */

> >> +       uint8_t pipeline_cls;

> >

> > inline_cls seems clearer here since this section is configuring inline

> > processing options.



Pipeline config is for inline and async modes. It's documented under SA param.


> >>  /**

> >> + * Result event pipeline configuration

> >> + */

> >> +typedef enum odp_ipsec_pipeline_t {

> >> +       /** Do not pipeline */

> >> +       ODP_IPSEC_PIPELINE_NONE = 0,

> >> +

> >> +       /** Send IPSEC result events to the classifier.

> >> +        *

> >> +        *  IPSEC capability 'pipeline_cls' determines if pipelined

> >> +        *  classification is supported. */

> >> +       ODP_IPSEC_PIPELINE_CLS

> >> +

> >> +} odp_ipsec_pipeline_t;

> >

> > I'm not sure that calling this odp_ipsec_pipeline_t is better than the

> > previous odp_ipsec_dest_mode_t. But since this is all about

> > configuring INLINE processing, how about odp_ipsec_inline_config_t and

> > the values are ODP_IPSEC_INLINE_DONE and ODP_IPSEC_INLINE_CLS. DONE

> > simply indicates that inline processing is finished and the result is

> > delivered back to the application.

> >

> > Since this is a per-SA configuration, the question is whether it

> > should be one setting or separate in and out configs since we want a

> > structure that will accommodate an ODP_IPSEC_INLINE_TM for sending

> > IPsec output directly to TM. Whether we want to introduce that now, we

> > want a structure that will accommodate this extension without needing

> > redesign in the next iteration.


It's also for async mode.

Pipeline enum may grow in the future (e.g. with TM). I don't see a problem that some pipeline commands are for inbound and some for outbound SAs, a single SA cannot be both in and out. So, CLS would a valid option for inbound and TM for outbound.


> >> +       /** Select pipelined destination for IPSEC result events

> >> +        *

> >> +        *  Asynchronous and inline modes generate result events.

> Select where

> >> +        *  those events are sent. Inbound SAs may choose to use

> pipelined

> >> +        *  classification. The default value is

> ODP_IPSEC_PIPELINE_NONE.

> >> +        */

> >> +       odp_ipsec_pipeline_t pipeline;

> >> +

> >>         /** Destination queue for IPSEC events

> >>          *

> >> -        *  Operations in asynchronous mode enqueue resulting events

> into

> >> -        *  this queue.

> >> +        *  Operations in asynchronous or inline mode enqueue resulting

> events

> >> +        *  into this queue.

> >>          */

> >>         odp_queue_t dest_queue;

> >

> > It seems confusing to have both pipeline and queue here since both are

> > referring to what should happen next after IPsec processing is

> > finished. The cases are:

> >

> > Input processing: Following IPsec processing the packet should either

> > be sent to the classifier or delivered to a destination event queue.


Exception (not decrypted) packets go to the SA queue in both cases (with or without CLS).

> >

> > Output processing: Following IPsec processing the packet should either

> > be sent back to the application via a destination event queue, or

> > forwarded to a TM queue or directly to a pktio for transmission.


Again failures will go to SA queue in all cases.


> >

> > Having two separate controls means that there are invalid combinations

> > that have to be dealt with, which seems messy.


Pipeline controls the next (additional) step for successfully IPsec'ed packets, others go SA queue.


> >

> >>

> >> +       /** Classifier destination CoS for IPSEC result events

> >> +        *

> >> +        *  Result events for successfully decapsulated packets are

> sent to

> >> +        *  classification through this CoS. Other result events are

> sent to

> >> +        *  'dest_queue'. This field is considered only when 'pipeline'

> is

> >> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between

> any pktio

> >> +        *  interface default CoS.

> >> +        */

> >> +       odp_cos_t dest_cos;

> >

> > Having multiple pieces of information needed for the same config

> > suggests opportunities for simplification. Perhaps a scheme along the

> > following lines:

> >

> enum odp_ipsec_next_t {

>        ODP_IPSEC_NEXT_QUEUE = 0,

>        ODP_IPSEC_NEXT_COS,

>        ODP_IPSEC_NEXT_PKTIO,

>        ODP_IPSEC_NEXT_TM,

> } odp_ipsec_next_t;

> 

> > typedef struct odp_ipsec_next_config_t {

>         odp_ipsec_next_t next;

>         union {

>             odp_queue_t queue;

>             odp_cos_t cos;

>             odp_pktio_t pktio;

>             odp_tm_queue_t tm_q;

>         };



Queue is needed always (in inline and async). Pktio and tm queue handles are per packet, not per SA. Outer header is per packet and depends on output interface. Output interface may change rapidly due to a route change.

-Petri
Bogdan Pricope March 27, 2017, 12:06 p.m. UTC | #5
On 24 March 2017 at 17:04, Petri Savolainen <petri.savolainen@linaro.org> wrote:
> Added support for inline IPSEC processing on packet input and

> output. Inline mode IPSEC and traffic manager cannot be enabled

> (currently) on the same pktio interface.

>

> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

> ---

>  include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---

>  include/odp/api/spec/packet_io.h |  32 ++++

>  2 files changed, 360 insertions(+), 27 deletions(-)

>

> diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h

> index d3e51bc..2e7e1e4 100644

> --- a/include/odp/api/spec/ipsec.h

> +++ b/include/odp/api/spec/ipsec.h

> @@ -19,6 +19,8 @@ extern "C" {

>  #endif

>

>  #include <odp/api/crypto.h>

> +#include <odp/api/packet_io.h>

> +#include <odp/api/classification.h>

>

>  /** @defgroup odp_ipsec ODP IPSEC

>   *  Operations of IPSEC API.

> @@ -51,11 +53,43 @@ typedef enum odp_ipsec_op_mode_t {

>           * Application uses asynchronous IPSEC operations,

>           * which return results via events.

>           */

> -       ODP_IPSEC_OP_MODE_ASYNC

> +       ODP_IPSEC_OP_MODE_ASYNC,

> +

> +       /** Inline IPSEC operation

> +         *

> +         * Packet input/output is connected directly to IPSEC inbound/outbound

> +         * processing. Application uses asynchronous or inline IPSEC

> +         * operations.

> +         */

> +       ODP_IPSEC_OP_MODE_INLINE,

> +

> +       /** IPSEC is disabled in inbound / outbound direction */

> +       ODP_IPSEC_OP_MODE_DISABLED

>

>  } odp_ipsec_op_mode_t;

>

>  /**

> + * Protocol layers in IPSEC configuration

> + */

> +typedef enum odp_ipsec_proto_layer_t {

> +       /** No layers */

> +       ODP_IPSEC_LAYER_NONE = 0,

> +

> +       /** Layer L2 protocols (Ethernet, VLAN, etc) */

> +       ODP_IPSEC_LAYER_L2,

> +

> +       /** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */

> +       ODP_IPSEC_LAYER_L3,

> +

> +       /** Layer L4 protocols (UDP, TCP, SCTP) */

> +       ODP_IPSEC_LAYER_L4,

> +

> +       /** All layers */

> +       ODP_IPSEC_LAYER_ALL

> +

> +} odp_ipsec_proto_layer_t;

> +

> +/**

>   * Configuration options for IPSEC inbound processing

>   */

>  typedef struct odp_ipsec_inbound_config_t {

> @@ -81,9 +115,110 @@ typedef struct odp_ipsec_inbound_config_t {

>

>         } spi_lookup;

>

> +       /** Retain outer headers

> +        *

> +        *  Select up to which protocol layer (at least) outer headers are

> +        *  retained in inbound inline processing. Default value is

> +        *  ODP_IPSEC_LAYER_NONE.

> +        *

> +        *  ODP_IPSEC_LAYER_NONE: Application does not require any outer

> +        *                        headers to be retained.

> +        *

> +        *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.

> +        *

> +        *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the

> +        *                        same as ODP_IPSEC_LAYER_ALL.

> +        *

> +        *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the

> +        *                        same as ODP_IPSEC_LAYER_ALL.

> +        *

> +        *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are

> +        *                        retained. In transport mode, all headers

> +        *                        before IP (carrying IPSEC) are retained.

> +        *

> +        */

> +       odp_ipsec_proto_layer_t retain_outer;

> +

> +       /** Parse packet headers after IPSEC transformation

> +        *

> +        *  Select header parsing level after inbound processing. Headers of the

> +        *  resulting packet must be parsed (at least) up to this level. Parsing

> +        *  starts from IP (layer 3). Each successfully transformed packet has

> +        *  a valid value for L3 offset regardless of the parse configuration.

> +        *  Default value is ODP_IPSEC_LAYER_NONE.

> +        */

> +       odp_ipsec_proto_layer_t parse;

> +

> +       /** Flags to control IPSEC payload data checks up to the selected parse

> +        *  level. */

> +       union {

> +               struct {

> +                       /** Check IPv4 header checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t ipv4_chksum   : 1;

> +

> +                       /** Check UDP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t udp_chksum    : 1;

> +

> +                       /** Check TCP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t tcp_chksum    : 1;

> +

> +                       /** Check SCTP checksum in IPSEC payload.

> +                        *  Default value is 0. */

> +                       uint32_t sctp_chksum   : 1;

> +               } check;

> +

> +               /** All bits of the bit field structure

> +                 *

> +                 * This field can be used to set/clear all flags, or bitwise

> +                 * operations over the entire structure. */

> +               uint32_t all_check;

> +       };

> +

>  } odp_ipsec_inbound_config_t;

>

>  /**

> + * Configuration options for IPSEC outbound processing

> + */

> +typedef struct odp_ipsec_outbound_config_t {

> +       /** Flags to control L3/L4 checksum insertion as part of outbound

> +        *  packet processing. Packet must have set with valid L3/L4 offsets.

> +        *  Checksum configuration is ignored for packets that checksum cannot

> +        *  be computed for (e.g. IPv4 fragments). Application may use a packet

> +        *  metadata flag to disable checksum insertion per packet bases.

> +        */

> +       union {

> +               struct {

> +                       /** Insert IPv4 header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_ipv4   : 1;

> +

> +                       /** Insert UDP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_udp    : 1;

> +

> +                       /** Insert TCP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_tcp    : 1;

> +

> +                       /** Insert SCTP header checksum on the payload packet

> +                        *  before IPSEC transformation. Default value is 0. */

> +                       uint32_t inner_sctp   : 1;

> +

> +               } chksum;

> +

> +               /** All bits of the bit field structure

> +                 *

> +                 * This field can be used to set/clear all flags, or bitwise

> +                 * operations over the entire structure. */

> +               uint32_t all_chksum;

> +       };

> +

> +} odp_ipsec_outbound_config_t;

> +

> +/**

>   * IPSEC capability

>   */

>  typedef struct odp_ipsec_capability_t {

> @@ -106,6 +241,23 @@ typedef struct odp_ipsec_capability_t {

>          */

>         uint8_t op_mode_async;

>

> +       /** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support

> +        *

> +        *  0: Inline IPSEC operation is not supported

> +        *  1: Inline IPSEC operation is supported

> +        *  2: Inline IPSEC operation is supported and preferred

> +        */

> +       uint8_t op_mode_inline;

> +

> +       /** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of

> +        *  resulting inbound packets.

> +        *

> +        *  0: Classification of resulting packets is not supported

> +        *  1: Classification of resulting packets is supported

> +        *  2: Classification of resulting packets is supported and preferred

> +        */

> +       uint8_t pipeline_cls;

> +

>         /** Soft expiry limit in seconds support

>          *

>          *  0: Limit is not supported

> @@ -132,12 +284,19 @@ typedef struct odp_ipsec_capability_t {

>   * IPSEC configuration options

>   */

>  typedef struct odp_ipsec_config_t {

> -       /** IPSEC operation mode. Application selects which mode (sync or async)

> -        *  will be used for IPSEC operations.

> +       /** Inbound IPSEC operation mode. Application selects which mode

> +        *  will be used for inbound IPSEC operations.

>          *

>          *  @see odp_ipsec_in(), odp_ipsec_in_enq()

>          */

> -       odp_ipsec_op_mode_t op_mode;

> +       odp_ipsec_op_mode_t inbound_mode;

> +

> +       /** Outbound IPSEC operation mode. Application selects which mode

> +        *  will be used for outbound IPSEC operations.

> +        *

> +        *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()

> +        */

> +       odp_ipsec_op_mode_t outbound_mode;

>

>         /** Maximum number of IPSEC SAs that application will use

>          * simultaneously */

> @@ -146,6 +305,9 @@ typedef struct odp_ipsec_config_t {

>         /** IPSEC inbound processing configuration */

>         odp_ipsec_inbound_config_t inbound;

>

> +       /** IPSEC outbound processing configuration */

> +       odp_ipsec_outbound_config_t outbound;

> +

>  } odp_ipsec_config_t;

>

>  /**

> @@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {

>         ODP_IPSEC_LOOKUP_DISABLED = 0,

>

>         /** Inbound SA lookup is enabled. Lookup matches only SPI value.

> -        *  SA lookup failure status (error.sa_lookup) is reported through

> +        *  In inline mode, a lookup miss directs the packet back to normal

> +        *  packet input interface processing. In other modes, the SA lookup

> +        *  failure status (error.sa_lookup) is reported through

>          *  odp_ipsec_packet_result_t. */


You mean, lookup miss will be reported:
 - for lookaside, async mode -> "default_queue"
 - for lookaside, sync mode -> "odp_ipsec_op_result_t" of the operation
 - for inline mode: "normal packet input"
?


> -       ODP_IPSEC_LOOKUP_SPI

> +       ODP_IPSEC_LOOKUP_SPI,

> +

> +       /** Inbound SA lookup is enabled. Lookup matches both SPI value and

> +         * destination IP address. Functionality is otherwise identical to

> +         * ODP_IPSEC_LOOKUP_SPI. */

> +       ODP_IPSEC_LOOKUP_DSTADDR_SPI

>

>  } odp_ipsec_lookup_mode_t;

>

>  /**

> + * Result event pipeline configuration

> + */

> +typedef enum odp_ipsec_pipeline_t {

> +       /** Do not pipeline */

> +       ODP_IPSEC_PIPELINE_NONE = 0,

> +

> +       /** Send IPSEC result events to the classifier.

> +        *

> +        *  IPSEC capability 'pipeline_cls' determines if pipelined

> +        *  classification is supported. */

> +       ODP_IPSEC_PIPELINE_CLS

> +

> +} odp_ipsec_pipeline_t;

> +

> +/**

>   * IPSEC Security Association (SA) parameters

>   */

>  typedef struct odp_ipsec_sa_param_t {

> @@ -432,6 +616,21 @@ typedef struct odp_ipsec_sa_param_t {

>         /** SPI value */

>         uint32_t spi;

>

> +       /** Additional inbound SA lookup parameters. Values are considered

> +        *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */

> +       struct {

> +               /** Select IP version

> +                *

> +                *  4:   IPv4

> +                *  6:   IPv6

> +                */

> +               uint8_t ip_version;

> +

> +               /** IP destination address (NETWORK ENDIAN) */

> +               void    *dst_addr;

> +

> +       } lookup_param;

> +

>         /** MTU for outbound IP fragmentation offload

>          *

>          *  This is the maximum length of IP packets that outbound IPSEC

> @@ -440,13 +639,31 @@ typedef struct odp_ipsec_sa_param_t {

>          */

>         uint32_t mtu;

>

> +       /** Select pipelined destination for IPSEC result events

> +        *

> +        *  Asynchronous and inline modes generate result events. Select where

> +        *  those events are sent. Inbound SAs may choose to use pipelined

> +        *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.

> +        */

> +       odp_ipsec_pipeline_t pipeline;

> +

>         /** Destination queue for IPSEC events

>          *

> -        *  Operations in asynchronous mode enqueue resulting events into

> -        *  this queue.

> +        *  Operations in asynchronous or inline mode enqueue resulting events

> +        *  into this queue.

>          */

>         odp_queue_t dest_queue;

>

> +       /** Classifier destination CoS for IPSEC result events

> +        *

> +        *  Result events for successfully decapsulated packets are sent to

> +        *  classification through this CoS. Other result events are sent to

> +        *  'dest_queue'. This field is considered only when 'pipeline' is

> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio

> +        *  interface default CoS.

> +        */

> +       odp_cos_t dest_cos;

> +

>         /** User defined SA context pointer

>          *

>          *  User defined context pointer associated with the SA.

> @@ -679,6 +896,18 @@ typedef struct odp_ipsec_op_status_t {

>                 uint32_t all_error;

>         };

>

> +       union {

> +               /** Status flags */

> +               struct {

> +                       /** Packet was processed in inline mode */

> +                       uint32_t inline_mode      : 1;

> +

> +               } flag;

> +

> +               /** All flag bits */

> +               uint32_t all_flag;

> +       };

> +

>  } odp_ipsec_op_status_t;

>

>  /**

> @@ -708,7 +937,7 @@ typedef struct odp_ipsec_op_param_t {

>

>         /** Pointer to an array of packets

>          *

> -        *  Each packet must have a valid value for these meta-data:

> +        *  Each packet must have a valid value for these metadata:

>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

>          *  * L4 offset: For inbound direction, when udp_encap is enabled -

>          *               offset to the first byte of the encapsulating UDP

> @@ -733,6 +962,35 @@ typedef struct odp_ipsec_op_param_t {

>  } odp_ipsec_op_param_t;

>

>  /**

> + * Outbound inline IPSEC operation parameters

> + */

> +typedef struct odp_ipsec_inline_op_param_t {

> +       /** Packet output interface for inline output operation

> +        *

> +        *  Outbound inline IPSEC operation uses this packet IO interface to

> +        *  output the packet after a successful IPSEC transformation. The pktio

> +        *  must have been configured to operate in inline IPSEC mode.

> +        */

> +       odp_pktio_t pktio;

> +

> +       /** Outer headers for inline output operation

> +        *

> +        *  Outbound inline IPSEC operation uses this information to prepend

> +        *  outer headers to the IPSEC packet before sending it out.

> +        */

> +       struct {

> +               /** Points to first byte of outer headers to be copied in

> +                *  front of the outgoing IPSEC packet. Implementation copies

> +                *  the headers during odp_ipsec_out_inline() call. */

> +               uint8_t *ptr;

> +

> +               /** Outer header length in bytes */

> +               uint32_t len;

> +       } outer_hdr;

> +

> +} odp_ipsec_inline_op_param_t;

> +

> +/**

>   * IPSEC operation result for a packet

>   */

>  typedef struct odp_ipsec_packet_result_t {

> @@ -758,6 +1016,23 @@ typedef struct odp_ipsec_packet_result_t {

>          */

>         odp_ipsec_sa_t sa;

>

> +       /** Packet outer header status before inbound inline processing.

> +        *  This is valid only when status.flag.inline_mode is set.

> +        */

> +       struct {

> +               /** Points to the first byte of retained outer headers. These

> +                *  headers are stored in a contiquous, per packet,

> +                *  implementation specific memory space. Since the memory space

> +                *  may overlap with e.g. packet head/tailroom, the content

> +                *  becomes invalid if packet data storage is modified in

> +                *  anyway. The memory space may not be sharable to other

> +                *  threads. */

> +               uint8_t *ptr;

> +

> +               /** Outer header length in bytes */

> +               uint32_t len;

> +       } outer_hdr;

> +

>  } odp_ipsec_packet_result_t;

>

>  /**

> @@ -779,18 +1054,14 @@ typedef struct odp_ipsec_op_result_t {

>          *  at least 'num_pkt' elements.

>          *

>          *  Each successfully transformed packet has a valid value for these

> -        *  meta-data:

> +        *  metadata regardless of the inner packet parse configuration.

> +        *  (odp_ipsec_inbound_config_t):

>          *  * L3 offset: Offset to the first byte of the (outmost) IP header

> -        *  * L4 offset: Offset to the first byte of the valid and known L4

> -        *               header (immediately following the IP header).

> -        *  * Various flags about L3 and L4 layers:

> -        *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,

> -        *               has_ipsec, has_udp, has_tcp, etc depending on

> -        *               the resulted packet format

> +        *  * pktio:     For inbound inline IPSEC processed packets, original

> +        *               packet input interface

>          *

> -        * @see odp_packet_l3_offset(), odp_packet_l4_offset(),

> -        *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),

> -        *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()

> +        *  Other metadata for parse results and error checks depend on

> +        *  configuration (selected parse and error check levels).

>          */

>         odp_packet_t *pkt;

>

> @@ -921,10 +1192,10 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>  /**

>   * Inbound asynchronous IPSEC operation

>   *

> - * This operation does inbound IPSEC processing in asynchronous mode

> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

> - * odp_ipsec_in(), but outputs all results through one or more

> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

> + * This operation does inbound IPSEC processing in asynchronous mode. It

> + * processes packets otherwise identically to odp_ipsec_in(), but outputs all

> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

> + * ordering considerations.

>   *

>   * Asynchronous mode maintains (operation input) packet order per SA when

>   * application calls the operation within an ordered or atomic scheduler context

> @@ -934,6 +1205,11 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,

>   * events for the same SA are enqueued in order, and packet handles (for the

>   * same SA) are stored in order within an event.

>   *

> + * The function may be used also in inline processing mode, e.g. for IPSEC

> + * packets for which inline processing is not possible. Packets for the same SA

> + * may be processed simultaneously in both modes (initiated by this function

> + * and inline operation).

> + *

>   * @param         input   Operation input parameters

>   *

>   * @return Number of input packets consumed (0 ... input.num_pkt)

> @@ -946,10 +1222,10 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>  /**

>   * Outbound asynchronous IPSEC operation

>   *

> - * This operation does outbound IPSEC processing in asynchronous mode

> - * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to

> - * odp_ipsec_out(), but outputs all results through one or more

> - * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.

> + * This operation does outbound IPSEC processing in asynchronous mode. It

> + * processes packets otherwise identically to odp_ipsec_out(), but outputs all

> + * results through one or more ODP_EVENT_IPSEC_RESULT events with the following

> + * ordering considerations.

>   *

>   * Asynchronous mode maintains (operation input) packet order per SA when

>   * application calls the operation within an ordered or atomic scheduler context

> @@ -959,6 +1235,9 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>   * events for the same SA are enqueued in order, and packet handles (for the

>   * same SA) are stored in order within an event.

>   *

> + * The function may be used also in inline processing mode, e.g. for IPSEC

> + * packets for which inline processing is not possible.

> + *

>   * @param         input   Operation input parameters

>   *

>   * @return Number of input packets consumed (0 ... input.num_pkt)

> @@ -969,6 +1248,28 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);

>  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);

>

>  /**

> + * Outbound inline IPSEC operation

> + *

> + * This operation does outbound inline IPSEC processing for the packets. It's

> + * otherwise identical to odp_ipsec_out_enq(), but outputs all successfully

> + * transformed packets to the specified output interface, instead of generating

> + * result events for those.

> + *

> + * Inline operation parameters are defined per packet. The array of parameters

> + * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.

> + *

> + * @param         op_param      Operation parameters

> + * @param         inline_param  Outbound inline operation specific parameters

> + *

> + * @return Number of packets consumed (0 ... op_param.num_pkt)

> + * @retval <0     On failure

> + *

> + * @see odp_ipsec_out_enq()

> + */

> +int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,

> +                        const odp_ipsec_inline_op_param_t *inline_param);

> +

> +/**

>   * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event

>   *

>   * Copies IPSEC operation results from an event. The event must be of

> diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h

> index cec1f22..8802089 100644

> --- a/include/odp/api/spec/packet_io.h

> +++ b/include/odp/api/spec/packet_io.h

> @@ -407,6 +407,38 @@ typedef struct odp_pktio_config_t {

>          * interface capability before enabling the same. */

>         odp_bool_t enable_loop;

>

> +       /** Inbound IPSEC inlined with packet input

> +        *

> +        *  Enable/disable inline inbound IPSEC operation. When enabled packet

> +        *  input directs all IPSEC packets automatically to IPSEC inbound

> +        *  processing. IPSEC configuration is done through the IPSEC API.

> +        *  Packets that are not (recognized as) IPSEC are processed

> +        *  according to the packet input configuration.

> +        *

> +        *  0: Disable inbound IPSEC inline operation (default)

> +        *  1: Enable inbound IPSEC inline operation

> +        *

> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

> +        */

> +       odp_bool_t inbound_ipsec;

> +

> +       /** Outbound IPSEC inlined with packet output

> +        *

> +        *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC

> +        *  outbound processing can send outgoing IPSEC packets directly

> +        *  to the pktio interface for output. IPSEC configuration is done

> +        *  through the IPSEC API.

> +        *

> +        *  Outbound IPSEC inline operation cannot be combined with traffic

> +        *  manager (ODP_PKTOUT_MODE_TM).

> +        *

> +        *  0: Disable outbound IPSEC inline operation (default)

> +        *  1: Enable outbound IPSEC inline operation

> +        *

> +        *  @see odp_ipsec_config(), odp_ipsec_sa_create()

> +        */

> +       odp_bool_t outbound_ipsec;

> +

>  } odp_pktio_config_t;

>

>  /**

> --

> 2.8.1

>
Savolainen, Petri (Nokia - FI/Espoo) March 27, 2017, 12:20 p.m. UTC | #6
> >>>

> >>> +       /** Classifier destination CoS for IPSEC result events

> >>> +        *

> >>> +        *  Result events for successfully decapsulated packets are

> sent to

> >>> +        *  classification through this CoS. Other result events are

> sent to

> >>> +        *  'dest_queue'. This field is considered only when

> 'pipeline' is

> >>> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between

> any pktio

> >>> +        *  interface default CoS.

> >>> +        */

> >>> +       odp_cos_t dest_cos;

> >>

> >> Having multiple pieces of information needed for the same config

> >> suggests opportunities for simplification. Perhaps a scheme along the

> >> following lines:

> >>

> > enum odp_ipsec_next_t {

> >        ODP_IPSEC_NEXT_QUEUE = 0,

> >        ODP_IPSEC_NEXT_COS,

> >        ODP_IPSEC_NEXT_PKTIO,

> >        ODP_IPSEC_NEXT_TM,

> > } odp_ipsec_next_t;

> >

> >> typedef struct odp_ipsec_next_config_t {

> >         odp_ipsec_next_t next;

> >         union {

> >             odp_queue_t queue;

> >             odp_cos_t cos;

> >             odp_pktio_t pktio;

> >             odp_tm_queue_t tm_q;

> >         };

> >>

> >> } odp_ipsec_next_config_t;

> 

> Maybe this form will make it clearer:

> union {

>         struct {

>             odp_ipsec_dest_in_type_t dest_type;

> 

>             union {

>                 odp_queue_t queue;

>                 odp_cos_t cos;

>             } dest_val;

>         } inbound;

> 

>         struct {

>             odp_ipsec_dest_out_type_t dest_type;

> 

>             union {

>                 odp_queue_t queue;

>                 odp_pktio_t pktio;

>                 odp_tm_queue_t tm_q;

>             } dest_val;

>         } outbound;

>     } dest;

> 

> Yet, I still believe this model is limiting flexibility... maybe we

> need a framework with a generic way to connect different HW modules.

> 


See my answer for Bill about handle usage.

Actually, limiting flexibility is good for the spec. We can dictate in each step which other accelerators are possible next steps of a pipeline and how exceptions are handled.

E.g. today IPSEC spec specifies
* pktin -> IPSEC -> CLS -> queue

maybe tomorrow CLS would allow pipeline with DPI, and we'd extend to (with proper event format)
* pktin -> IPSEC -> CLS -> queue
                     |
                     +---> DPI -> queue


Even with a generic accelerator pipeline, only a few combinations would be actually useful or even possible to implement (with all the exception handling).


-Petri
Savolainen, Petri (Nokia - FI/Espoo) March 27, 2017, 12:28 p.m. UTC | #7
> >  /**

> > @@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {

> >         ODP_IPSEC_LOOKUP_DISABLED = 0,

> >

> >         /** Inbound SA lookup is enabled. Lookup matches only SPI value.

> > -        *  SA lookup failure status (error.sa_lookup) is reported

> through

> > +        *  In inline mode, a lookup miss directs the packet back to

> normal

> > +        *  packet input interface processing. In other modes, the SA

> lookup

> > +        *  failure status (error.sa_lookup) is reported through

> >          *  odp_ipsec_packet_result_t. */

> 

> You mean, lookup miss will be reported:

>  - for lookaside, async mode -> "default_queue"

>  - for lookaside, sync mode -> "odp_ipsec_op_result_t" of the operation

>  - for inline mode: "normal packet input"

> ?


It's the same struct (odp_ipsec_op_result_t) in both sync and async cases. In the first case it's an output param, in the second case it's carried as an event.

-Petri
Nikhil Agarwal March 27, 2017, 12:43 p.m. UTC | #8
-- Since the Inline IPSEC is part of sNIC capability (at least for NXP), we cannot deliver packets to user specified queues. It will be delivered on pktio queues itself. On pktio then you can define the hashing/classification rules to distribute packet to different queues. For classification it will be delivered to pktio default CoS only.

-- In case user wants to retain the packet header, we cannot remove them from packet and put it somewhere else, hence parsing will be based on retained headers.

-- ESP/AH are different protocols, either of them can be optionally supported, shall be part of capability.

Regards
Nikhil

-----Original Message-----
From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of Petri Savolainen

Sent: Friday, March 24, 2017 8:35 PM
To: lng-odp@lists.linaro.org
Subject: [lng-odp] [API-NEXT PATCH v3 2/4] api: ipsec: add inline IPSEC support

Added support for inline IPSEC processing on packet input and output. Inline mode IPSEC and traffic manager cannot be enabled
(currently) on the same pktio interface.

Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

---
 include/odp/api/spec/ipsec.h     | 355 ++++++++++++++++++++++++++++++++++++---
 include/odp/api/spec/packet_io.h |  32 ++++
 2 files changed, 360 insertions(+), 27 deletions(-)

--
2.8.1diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h index d3e51bc..2e7e1e4 100644
--- a/include/odp/api/spec/ipsec.h
+++ b/include/odp/api/spec/ipsec.h
@@ -19,6 +19,8 @@ extern "C" {
 #endif
 
 #include <odp/api/crypto.h>
+#include <odp/api/packet_io.h>
+#include <odp/api/classification.h>
 
 /** @defgroup odp_ipsec ODP IPSEC
  *  Operations of IPSEC API.
@@ -51,11 +53,43 @@ typedef enum odp_ipsec_op_mode_t {
 	  * Application uses asynchronous IPSEC operations,
 	  * which return results via events.
 	  */
-	ODP_IPSEC_OP_MODE_ASYNC
+	ODP_IPSEC_OP_MODE_ASYNC,
+
+	/** Inline IPSEC operation
+	  *
+	  * Packet input/output is connected directly to IPSEC inbound/outbound
+	  * processing. Application uses asynchronous or inline IPSEC
+	  * operations.
+	  */
+	ODP_IPSEC_OP_MODE_INLINE,
+
+	/** IPSEC is disabled in inbound / outbound direction */
+	ODP_IPSEC_OP_MODE_DISABLED
 
 } odp_ipsec_op_mode_t;
 
 /**
+ * Protocol layers in IPSEC configuration  */ typedef enum 
+odp_ipsec_proto_layer_t {
+	/** No layers */
+	ODP_IPSEC_LAYER_NONE = 0,
+
+	/** Layer L2 protocols (Ethernet, VLAN, etc) */
+	ODP_IPSEC_LAYER_L2,
+
+	/** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */
+	ODP_IPSEC_LAYER_L3,
+
+	/** Layer L4 protocols (UDP, TCP, SCTP) */
+	ODP_IPSEC_LAYER_L4,
+
+	/** All layers */
+	ODP_IPSEC_LAYER_ALL
+
+} odp_ipsec_proto_layer_t;
+
+/**
  * Configuration options for IPSEC inbound processing
  */
 typedef struct odp_ipsec_inbound_config_t { @@ -81,9 +115,110 @@ typedef struct odp_ipsec_inbound_config_t {
 
 	} spi_lookup;
 
+	/** Retain outer headers
+	 *
+	 *  Select up to which protocol layer (at least) outer headers are
+	 *  retained in inbound inline processing. Default value is
+	 *  ODP_IPSEC_LAYER_NONE.
+	 *
+	 *  ODP_IPSEC_LAYER_NONE: Application does not require any outer
+	 *                        headers to be retained.
+	 *
+	 *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.
+	 *
+	 *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the
+	 *                        same as ODP_IPSEC_LAYER_ALL.
+	 *
+	 *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the
+	 *                        same as ODP_IPSEC_LAYER_ALL.
+	 *
+	 *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are
+	 *                        retained. In transport mode, all headers
+	 *                        before IP (carrying IPSEC) are retained.
+	 *
+	 */
+	odp_ipsec_proto_layer_t retain_outer;
+
+	/** Parse packet headers after IPSEC transformation
+	 *
+	 *  Select header parsing level after inbound processing. Headers of the
+	 *  resulting packet must be parsed (at least) up to this level. Parsing
+	 *  starts from IP (layer 3). Each successfully transformed packet has
+	 *  a valid value for L3 offset regardless of the parse configuration.
+	 *  Default value is ODP_IPSEC_LAYER_NONE.
+	 */
+	odp_ipsec_proto_layer_t parse;
+
+	/** Flags to control IPSEC payload data checks up to the selected parse
+	 *  level. */
+	union {
+		struct {
+			/** Check IPv4 header checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t ipv4_chksum   : 1;
+
+			/** Check UDP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t udp_chksum    : 1;
+
+			/** Check TCP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t tcp_chksum    : 1;
+
+			/** Check SCTP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t sctp_chksum   : 1;
+		} check;
+
+		/** All bits of the bit field structure
+		  *
+		  * This field can be used to set/clear all flags, or bitwise
+		  * operations over the entire structure. */
+		uint32_t all_check;
+	};
+
 } odp_ipsec_inbound_config_t;
 
 /**
+ * Configuration options for IPSEC outbound processing  */ typedef 
+struct odp_ipsec_outbound_config_t {
+	/** Flags to control L3/L4 checksum insertion as part of outbound
+	 *  packet processing. Packet must have set with valid L3/L4 offsets.
+	 *  Checksum configuration is ignored for packets that checksum cannot
+	 *  be computed for (e.g. IPv4 fragments). Application may use a packet
+	 *  metadata flag to disable checksum insertion per packet bases.
+	 */
+	union {
+		struct {
+			/** Insert IPv4 header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_ipv4   : 1;
+
+			/** Insert UDP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_udp    : 1;
+
+			/** Insert TCP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_tcp    : 1;
+
+			/** Insert SCTP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_sctp   : 1;
+
+		} chksum;
+
+		/** All bits of the bit field structure
+		  *
+		  * This field can be used to set/clear all flags, or bitwise
+		  * operations over the entire structure. */
+		uint32_t all_chksum;
+	};
+
+} odp_ipsec_outbound_config_t;
+
+/**
  * IPSEC capability
  */
 typedef struct odp_ipsec_capability_t { @@ -106,6 +241,23 @@ typedef struct odp_ipsec_capability_t {
 	 */
 	uint8_t op_mode_async;
 
+	/** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support
+	 *
+	 *  0: Inline IPSEC operation is not supported
+	 *  1: Inline IPSEC operation is supported
+	 *  2: Inline IPSEC operation is supported and preferred
+	 */
+	uint8_t op_mode_inline;
+
+	/** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of
+	 *  resulting inbound packets.
+	 *
+	 *  0: Classification of resulting packets is not supported
+	 *  1: Classification of resulting packets is supported
+	 *  2: Classification of resulting packets is supported and preferred
+	 */
+	uint8_t pipeline_cls;
+
 	/** Soft expiry limit in seconds support
 	 *
 	 *  0: Limit is not supported
@@ -132,12 +284,19 @@ typedef struct odp_ipsec_capability_t {
  * IPSEC configuration options
  */
 typedef struct odp_ipsec_config_t {
-	/** IPSEC operation mode. Application selects which mode (sync or async)
-	 *  will be used for IPSEC operations.
+	/** Inbound IPSEC operation mode. Application selects which mode
+	 *  will be used for inbound IPSEC operations.
 	 *
 	 *  @see odp_ipsec_in(), odp_ipsec_in_enq()
 	 */
-	odp_ipsec_op_mode_t op_mode;
+	odp_ipsec_op_mode_t inbound_mode;
+
+	/** Outbound IPSEC operation mode. Application selects which mode
+	 *  will be used for outbound IPSEC operations.
+	 *
+	 *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()
+	 */
+	odp_ipsec_op_mode_t outbound_mode;
 
 	/** Maximum number of IPSEC SAs that application will use
 	 * simultaneously */
@@ -146,6 +305,9 @@ typedef struct odp_ipsec_config_t {
 	/** IPSEC inbound processing configuration */
 	odp_ipsec_inbound_config_t inbound;
 
+	/** IPSEC outbound processing configuration */
+	odp_ipsec_outbound_config_t outbound;
+
 } odp_ipsec_config_t;
 
 /**
@@ -385,13 +547,35 @@ typedef enum odp_ipsec_lookup_mode_t {
 	ODP_IPSEC_LOOKUP_DISABLED = 0,
 
 	/** Inbound SA lookup is enabled. Lookup matches only SPI value.
-	 *  SA lookup failure status (error.sa_lookup) is reported through
+	 *  In inline mode, a lookup miss directs the packet back to normal
+	 *  packet input interface processing. In other modes, the SA lookup
+	 *  failure status (error.sa_lookup) is reported through
 	 *  odp_ipsec_packet_result_t. */
-	ODP_IPSEC_LOOKUP_SPI
+	ODP_IPSEC_LOOKUP_SPI,
+
+	/** Inbound SA lookup is enabled. Lookup matches both SPI value and
+	  * destination IP address. Functionality is otherwise identical to
+	  * ODP_IPSEC_LOOKUP_SPI. */
+	ODP_IPSEC_LOOKUP_DSTADDR_SPI
 
 } odp_ipsec_lookup_mode_t;
 
 /**
+ * Result event pipeline configuration
+ */
+typedef enum odp_ipsec_pipeline_t {
+	/** Do not pipeline */
+	ODP_IPSEC_PIPELINE_NONE = 0,
+
+	/** Send IPSEC result events to the classifier.
+	 *
+	 *  IPSEC capability 'pipeline_cls' determines if pipelined
+	 *  classification is supported. */
+	ODP_IPSEC_PIPELINE_CLS
+
+} odp_ipsec_pipeline_t;
+
+/**
  * IPSEC Security Association (SA) parameters
  */
 typedef struct odp_ipsec_sa_param_t {
@@ -432,6 +616,21 @@ typedef struct odp_ipsec_sa_param_t {
 	/** SPI value */
 	uint32_t spi;
 
+	/** Additional inbound SA lookup parameters. Values are considered
+	 *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */
+	struct {
+		/** Select IP version
+		 *
+		 *  4:   IPv4
+		 *  6:   IPv6
+		 */
+		uint8_t ip_version;
+
+		/** IP destination address (NETWORK ENDIAN) */
+		void    *dst_addr;
+
+	} lookup_param;
+
 	/** MTU for outbound IP fragmentation offload
 	 *
 	 *  This is the maximum length of IP packets that outbound IPSEC @@ -440,13 +639,31 @@ typedef struct odp_ipsec_sa_param_t {
 	 */
 	uint32_t mtu;
 
+	/** Select pipelined destination for IPSEC result events
+	 *
+	 *  Asynchronous and inline modes generate result events. Select where
+	 *  those events are sent. Inbound SAs may choose to use pipelined
+	 *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.
+	 */
+	odp_ipsec_pipeline_t pipeline;
+
 	/** Destination queue for IPSEC events
 	 *
-	 *  Operations in asynchronous mode enqueue resulting events into
-	 *  this queue.
+	 *  Operations in asynchronous or inline mode enqueue resulting events
+	 *  into this queue.
 	 */
 	odp_queue_t dest_queue;
 
+	/** Classifier destination CoS for IPSEC result events
+	 *
+	 *  Result events for successfully decapsulated packets are sent to
+	 *  classification through this CoS. Other result events are sent to
+	 *  'dest_queue'. This field is considered only when 'pipeline' is
+	 *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio
+	 *  interface default CoS.
+	 */
+	odp_cos_t dest_cos;
+
 	/** User defined SA context pointer
 	 *
 	 *  User defined context pointer associated with the SA.
@@ -679,6 +896,18 @@ typedef struct odp_ipsec_op_status_t {
 		uint32_t all_error;
 	};
 
+	union {
+		/** Status flags */
+		struct {
+			/** Packet was processed in inline mode */
+			uint32_t inline_mode      : 1;
+
+		} flag;
+
+		/** All flag bits */
+		uint32_t all_flag;
+	};
+
 } odp_ipsec_op_status_t;
 
 /**
@@ -708,7 +937,7 @@ typedef struct odp_ipsec_op_param_t {
 
 	/** Pointer to an array of packets
 	 *
-	 *  Each packet must have a valid value for these meta-data:
+	 *  Each packet must have a valid value for these metadata:
 	 *  * L3 offset: Offset to the first byte of the (outmost) IP header
 	 *  * L4 offset: For inbound direction, when udp_encap is enabled -
 	 *               offset to the first byte of the encapsulating UDP
@@ -733,6 +962,35 @@ typedef struct odp_ipsec_op_param_t {  } odp_ipsec_op_param_t;
 
 /**
+ * Outbound inline IPSEC operation parameters  */ typedef struct 
+odp_ipsec_inline_op_param_t {
+	/** Packet output interface for inline output operation
+	 *
+	 *  Outbound inline IPSEC operation uses this packet IO interface to
+	 *  output the packet after a successful IPSEC transformation. The pktio
+	 *  must have been configured to operate in inline IPSEC mode.
+	 */
+	odp_pktio_t pktio;
+
+	/** Outer headers for inline output operation
+	 *
+	 *  Outbound inline IPSEC operation uses this information to prepend
+	 *  outer headers to the IPSEC packet before sending it out.
+	 */
+	struct {
+		/** Points to first byte of outer headers to be copied in
+		 *  front of the outgoing IPSEC packet. Implementation copies
+		 *  the headers during odp_ipsec_out_inline() call. */
+		uint8_t *ptr;
+
+		/** Outer header length in bytes */
+		uint32_t len;
+	} outer_hdr;
+
+} odp_ipsec_inline_op_param_t;
+
+/**
  * IPSEC operation result for a packet
  */
 typedef struct odp_ipsec_packet_result_t { @@ -758,6 +1016,23 @@ typedef struct odp_ipsec_packet_result_t {
 	 */
 	odp_ipsec_sa_t sa;
 
+	/** Packet outer header status before inbound inline processing.
+	 *  This is valid only when status.flag.inline_mode is set.
+	 */
+	struct {
+		/** Points to the first byte of retained outer headers. These
+		 *  headers are stored in a contiquous, per packet,
+		 *  implementation specific memory space. Since the memory space
+		 *  may overlap with e.g. packet head/tailroom, the content
+		 *  becomes invalid if packet data storage is modified in
+		 *  anyway. The memory space may not be sharable to other
+		 *  threads. */
+		uint8_t *ptr;
+
+		/** Outer header length in bytes */
+		uint32_t len;
+	} outer_hdr;
+
 } odp_ipsec_packet_result_t;
 
 /**
@@ -779,18 +1054,14 @@ typedef struct odp_ipsec_op_result_t {
 	 *  at least 'num_pkt' elements.
 	 *
 	 *  Each successfully transformed packet has a valid value for these
-	 *  meta-data:
+	 *  metadata regardless of the inner packet parse configuration.
+	 *  (odp_ipsec_inbound_config_t):
 	 *  * L3 offset: Offset to the first byte of the (outmost) IP header
-	 *  * L4 offset: Offset to the first byte of the valid and known L4
-	 *               header (immediately following the IP header).
-	 *  * Various flags about L3 and L4 layers:
-	 *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,
-	 *               has_ipsec, has_udp, has_tcp, etc depending on
-	 *               the resulted packet format
+	 *  * pktio:     For inbound inline IPSEC processed packets, original
+	 *               packet input interface
 	 *
-	 * @see odp_packet_l3_offset(), odp_packet_l4_offset(),
-	 *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),
-	 *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()
+	 *  Other metadata for parse results and error checks depend on
+	 *  configuration (selected parse and error check levels).
 	 */
 	odp_packet_t *pkt;
 
@@ -921,10 +1192,10 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,
 /**
  * Inbound asynchronous IPSEC operation
  *
- * This operation does inbound IPSEC processing in asynchronous mode
- * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to
- * odp_ipsec_in(), but outputs all results through one or more
- * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.
+ * This operation does inbound IPSEC processing in asynchronous mode. 
+ It
+ * processes packets otherwise identically to odp_ipsec_in(), but 
+ outputs all
+ * results through one or more ODP_EVENT_IPSEC_RESULT events with the 
+ following
+ * ordering considerations.
  *
  * Asynchronous mode maintains (operation input) packet order per SA when
  * application calls the operation within an ordered or atomic scheduler context @@ -934,6 +1205,11 @@ int odp_ipsec_out(const odp_ipsec_op_param_t *input,
  * events for the same SA are enqueued in order, and packet handles (for the
  * same SA) are stored in order within an event.
  *
+ * The function may be used also in inline processing mode, e.g. for 
+ IPSEC
+ * packets for which inline processing is not possible. Packets for the 
+ same SA
+ * may be processed simultaneously in both modes (initiated by this 
+ function
+ * and inline operation).
+ *
  * @param         input   Operation input parameters
  *
  * @return Number of input packets consumed (0 ... input.num_pkt) @@ -946,10 +1222,10 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);
 /**
  * Outbound asynchronous IPSEC operation
  *
- * This operation does outbound IPSEC processing in asynchronous mode
- * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to
- * odp_ipsec_out(), but outputs all results through one or more
- * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.
+ * This operation does outbound IPSEC processing in asynchronous mode. 
+ It
+ * processes packets otherwise identically to odp_ipsec_out(), but 
+ outputs all
+ * results through one or more ODP_EVENT_IPSEC_RESULT events with the 
+ following
+ * ordering considerations.
  *
  * Asynchronous mode maintains (operation input) packet order per SA when
  * application calls the operation within an ordered or atomic scheduler context @@ -959,6 +1235,9 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);
  * events for the same SA are enqueued in order, and packet handles (for the
  * same SA) are stored in order within an event.
  *
+ * The function may be used also in inline processing mode, e.g. for 
+ IPSEC
+ * packets for which inline processing is not possible.
+ *
  * @param         input   Operation input parameters
  *
  * @return Number of input packets consumed (0 ... input.num_pkt) @@ -969,6 +1248,28 @@ int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);  int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);
 
 /**
+ * Outbound inline IPSEC operation
+ *
+ * This operation does outbound inline IPSEC processing for the 
+packets. It's
+ * otherwise identical to odp_ipsec_out_enq(), but outputs all 
+successfully
+ * transformed packets to the specified output interface, instead of 
+generating
+ * result events for those.
+ *
+ * Inline operation parameters are defined per packet. The array of 
+parameters
+ * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.
+ *
+ * @param         op_param      Operation parameters
+ * @param         inline_param  Outbound inline operation specific parameters
+ *
+ * @return Number of packets consumed (0 ... op_param.num_pkt)
+ * @retval <0     On failure
+ *
+ * @see odp_ipsec_out_enq()
+ */
+int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,
+			 const odp_ipsec_inline_op_param_t *inline_param);
+
+/**
  * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event
  *
  * Copies IPSEC operation results from an event. The event must be of diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h
index cec1f22..8802089 100644
--- a/include/odp/api/spec/packet_io.h
+++ b/include/odp/api/spec/packet_io.h
@@ -407,6 +407,38 @@ typedef struct odp_pktio_config_t {
 	 * interface capability before enabling the same. */
 	odp_bool_t enable_loop;
 
+	/** Inbound IPSEC inlined with packet input
+	 *
+	 *  Enable/disable inline inbound IPSEC operation. When enabled packet
+	 *  input directs all IPSEC packets automatically to IPSEC inbound
+	 *  processing. IPSEC configuration is done through the IPSEC API.
+	 *  Packets that are not (recognized as) IPSEC are processed
+	 *  according to the packet input configuration.
+	 *
+	 *  0: Disable inbound IPSEC inline operation (default)
+	 *  1: Enable inbound IPSEC inline operation
+	 *
+	 *  @see odp_ipsec_config(), odp_ipsec_sa_create()
+	 */
+	odp_bool_t inbound_ipsec;
+
+	/** Outbound IPSEC inlined with packet output
+	 *
+	 *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC
+	 *  outbound processing can send outgoing IPSEC packets directly
+	 *  to the pktio interface for output. IPSEC configuration is done
+	 *  through the IPSEC API.
+	 *
+	 *  Outbound IPSEC inline operation cannot be combined with traffic
+	 *  manager (ODP_PKTOUT_MODE_TM).
+	 *
+	 *  0: Disable outbound IPSEC inline operation (default)
+	 *  1: Enable outbound IPSEC inline operation
+	 *
+	 *  @see odp_ipsec_config(), odp_ipsec_sa_create()
+	 */
+	odp_bool_t outbound_ipsec;
+
 } odp_pktio_config_t;
 
 /**

Bogdan Pricope March 27, 2017, 12:52 p.m. UTC | #9
1. Maybe we need to separate exception path from success path (allow
same path / separate path).
2. If a combination is not supported than configuration will fail....
(we can have a function to validate configured combinations, if
needed). It will be a "natural" limitation.

The real benefit is that API will be stable: adding a HW module will
mean implementing the new combinations (wo changing API for all the
other modules).


On 27 March 2017 at 15:20, Savolainen, Petri (Nokia - FI/Espoo)
<petri.savolainen@nokia-bell-labs.com> wrote:
>> >>>

>> >>> +       /** Classifier destination CoS for IPSEC result events

>> >>> +        *

>> >>> +        *  Result events for successfully decapsulated packets are

>> sent to

>> >>> +        *  classification through this CoS. Other result events are

>> sent to

>> >>> +        *  'dest_queue'. This field is considered only when

>> 'pipeline' is

>> >>> +        *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between

>> any pktio

>> >>> +        *  interface default CoS.

>> >>> +        */

>> >>> +       odp_cos_t dest_cos;

>> >>

>> >> Having multiple pieces of information needed for the same config

>> >> suggests opportunities for simplification. Perhaps a scheme along the

>> >> following lines:

>> >>

>> > enum odp_ipsec_next_t {

>> >        ODP_IPSEC_NEXT_QUEUE = 0,

>> >        ODP_IPSEC_NEXT_COS,

>> >        ODP_IPSEC_NEXT_PKTIO,

>> >        ODP_IPSEC_NEXT_TM,

>> > } odp_ipsec_next_t;

>> >

>> >> typedef struct odp_ipsec_next_config_t {

>> >         odp_ipsec_next_t next;

>> >         union {

>> >             odp_queue_t queue;

>> >             odp_cos_t cos;

>> >             odp_pktio_t pktio;

>> >             odp_tm_queue_t tm_q;

>> >         };

>> >>

>> >> } odp_ipsec_next_config_t;

>>

>> Maybe this form will make it clearer:

>> union {

>>         struct {

>>             odp_ipsec_dest_in_type_t dest_type;

>>

>>             union {

>>                 odp_queue_t queue;

>>                 odp_cos_t cos;

>>             } dest_val;

>>         } inbound;

>>

>>         struct {

>>             odp_ipsec_dest_out_type_t dest_type;

>>

>>             union {

>>                 odp_queue_t queue;

>>                 odp_pktio_t pktio;

>>                 odp_tm_queue_t tm_q;

>>             } dest_val;

>>         } outbound;

>>     } dest;

>>

>> Yet, I still believe this model is limiting flexibility... maybe we

>> need a framework with a generic way to connect different HW modules.

>>

>

> See my answer for Bill about handle usage.

>

> Actually, limiting flexibility is good for the spec. We can dictate in each step which other accelerators are possible next steps of a pipeline and how exceptions are handled.

>

> E.g. today IPSEC spec specifies

> * pktin -> IPSEC -> CLS -> queue

>

> maybe tomorrow CLS would allow pipeline with DPI, and we'd extend to (with proper event format)

> * pktin -> IPSEC -> CLS -> queue

>                      |

>                      +---> DPI -> queue

>

>

> Even with a generic accelerator pipeline, only a few combinations would be actually useful or even possible to implement (with all the exception handling).

>

>

> -Petri

>

>
diff mbox series

Patch

diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h
index d3e51bc..2e7e1e4 100644
--- a/include/odp/api/spec/ipsec.h
+++ b/include/odp/api/spec/ipsec.h
@@ -19,6 +19,8 @@  extern "C" {
 #endif
 
 #include <odp/api/crypto.h>
+#include <odp/api/packet_io.h>
+#include <odp/api/classification.h>
 
 /** @defgroup odp_ipsec ODP IPSEC
  *  Operations of IPSEC API.
@@ -51,11 +53,43 @@  typedef enum odp_ipsec_op_mode_t {
 	  * Application uses asynchronous IPSEC operations,
 	  * which return results via events.
 	  */
-	ODP_IPSEC_OP_MODE_ASYNC
+	ODP_IPSEC_OP_MODE_ASYNC,
+
+	/** Inline IPSEC operation
+	  *
+	  * Packet input/output is connected directly to IPSEC inbound/outbound
+	  * processing. Application uses asynchronous or inline IPSEC
+	  * operations.
+	  */
+	ODP_IPSEC_OP_MODE_INLINE,
+
+	/** IPSEC is disabled in inbound / outbound direction */
+	ODP_IPSEC_OP_MODE_DISABLED
 
 } odp_ipsec_op_mode_t;
 
 /**
+ * Protocol layers in IPSEC configuration
+ */
+typedef enum odp_ipsec_proto_layer_t {
+	/** No layers */
+	ODP_IPSEC_LAYER_NONE = 0,
+
+	/** Layer L2 protocols (Ethernet, VLAN, etc) */
+	ODP_IPSEC_LAYER_L2,
+
+	/** Layer L3 protocols (IPv4, IPv6, ICMP, IPSEC, etc) */
+	ODP_IPSEC_LAYER_L3,
+
+	/** Layer L4 protocols (UDP, TCP, SCTP) */
+	ODP_IPSEC_LAYER_L4,
+
+	/** All layers */
+	ODP_IPSEC_LAYER_ALL
+
+} odp_ipsec_proto_layer_t;
+
+/**
  * Configuration options for IPSEC inbound processing
  */
 typedef struct odp_ipsec_inbound_config_t {
@@ -81,9 +115,110 @@  typedef struct odp_ipsec_inbound_config_t {
 
 	} spi_lookup;
 
+	/** Retain outer headers
+	 *
+	 *  Select up to which protocol layer (at least) outer headers are
+	 *  retained in inbound inline processing. Default value is
+	 *  ODP_IPSEC_LAYER_NONE.
+	 *
+	 *  ODP_IPSEC_LAYER_NONE: Application does not require any outer
+	 *                        headers to be retained.
+	 *
+	 *  ODP_IPSEC_LAYER_L2:   Retain headers up to layer 2.
+	 *
+	 *  ODP_IPSEC_LAYER_L3:   Retain headers up to layer 3, otherwise the
+	 *                        same as ODP_IPSEC_LAYER_ALL.
+	 *
+	 *  ODP_IPSEC_LAYER_L4:   Retain headers up to layer 4, otherwise the
+	 *                        same as ODP_IPSEC_LAYER_ALL.
+	 *
+	 *  ODP_IPSEC_LAYER_ALL:  In tunnel mode, all headers before IPSEC are
+	 *                        retained. In transport mode, all headers
+	 *                        before IP (carrying IPSEC) are retained.
+	 *
+	 */
+	odp_ipsec_proto_layer_t retain_outer;
+
+	/** Parse packet headers after IPSEC transformation
+	 *
+	 *  Select header parsing level after inbound processing. Headers of the
+	 *  resulting packet must be parsed (at least) up to this level. Parsing
+	 *  starts from IP (layer 3). Each successfully transformed packet has
+	 *  a valid value for L3 offset regardless of the parse configuration.
+	 *  Default value is ODP_IPSEC_LAYER_NONE.
+	 */
+	odp_ipsec_proto_layer_t parse;
+
+	/** Flags to control IPSEC payload data checks up to the selected parse
+	 *  level. */
+	union {
+		struct {
+			/** Check IPv4 header checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t ipv4_chksum   : 1;
+
+			/** Check UDP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t udp_chksum    : 1;
+
+			/** Check TCP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t tcp_chksum    : 1;
+
+			/** Check SCTP checksum in IPSEC payload.
+			 *  Default value is 0. */
+			uint32_t sctp_chksum   : 1;
+		} check;
+
+		/** All bits of the bit field structure
+		  *
+		  * This field can be used to set/clear all flags, or bitwise
+		  * operations over the entire structure. */
+		uint32_t all_check;
+	};
+
 } odp_ipsec_inbound_config_t;
 
 /**
+ * Configuration options for IPSEC outbound processing
+ */
+typedef struct odp_ipsec_outbound_config_t {
+	/** Flags to control L3/L4 checksum insertion as part of outbound
+	 *  packet processing. Packet must have set with valid L3/L4 offsets.
+	 *  Checksum configuration is ignored for packets that checksum cannot
+	 *  be computed for (e.g. IPv4 fragments). Application may use a packet
+	 *  metadata flag to disable checksum insertion per packet bases.
+	 */
+	union {
+		struct {
+			/** Insert IPv4 header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_ipv4   : 1;
+
+			/** Insert UDP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_udp    : 1;
+
+			/** Insert TCP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_tcp    : 1;
+
+			/** Insert SCTP header checksum on the payload packet
+			 *  before IPSEC transformation. Default value is 0. */
+			uint32_t inner_sctp   : 1;
+
+		} chksum;
+
+		/** All bits of the bit field structure
+		  *
+		  * This field can be used to set/clear all flags, or bitwise
+		  * operations over the entire structure. */
+		uint32_t all_chksum;
+	};
+
+} odp_ipsec_outbound_config_t;
+
+/**
  * IPSEC capability
  */
 typedef struct odp_ipsec_capability_t {
@@ -106,6 +241,23 @@  typedef struct odp_ipsec_capability_t {
 	 */
 	uint8_t op_mode_async;
 
+	/** Inline IPSEC operation mode (ODP_IPSEC_OP_MODE_INLINE) support
+	 *
+	 *  0: Inline IPSEC operation is not supported
+	 *  1: Inline IPSEC operation is supported
+	 *  2: Inline IPSEC operation is supported and preferred
+	 */
+	uint8_t op_mode_inline;
+
+	/** Support of pipelined classification (ODP_IPSEC_PIPELINE_CLS) of
+	 *  resulting inbound packets.
+	 *
+	 *  0: Classification of resulting packets is not supported
+	 *  1: Classification of resulting packets is supported
+	 *  2: Classification of resulting packets is supported and preferred
+	 */
+	uint8_t pipeline_cls;
+
 	/** Soft expiry limit in seconds support
 	 *
 	 *  0: Limit is not supported
@@ -132,12 +284,19 @@  typedef struct odp_ipsec_capability_t {
  * IPSEC configuration options
  */
 typedef struct odp_ipsec_config_t {
-	/** IPSEC operation mode. Application selects which mode (sync or async)
-	 *  will be used for IPSEC operations.
+	/** Inbound IPSEC operation mode. Application selects which mode
+	 *  will be used for inbound IPSEC operations.
 	 *
 	 *  @see odp_ipsec_in(), odp_ipsec_in_enq()
 	 */
-	odp_ipsec_op_mode_t op_mode;
+	odp_ipsec_op_mode_t inbound_mode;
+
+	/** Outbound IPSEC operation mode. Application selects which mode
+	 *  will be used for outbound IPSEC operations.
+	 *
+	 *  @see odp_ipsec_out(), odp_ipsec_out_enq(), odp_ipsec_out_inline()
+	 */
+	odp_ipsec_op_mode_t outbound_mode;
 
 	/** Maximum number of IPSEC SAs that application will use
 	 * simultaneously */
@@ -146,6 +305,9 @@  typedef struct odp_ipsec_config_t {
 	/** IPSEC inbound processing configuration */
 	odp_ipsec_inbound_config_t inbound;
 
+	/** IPSEC outbound processing configuration */
+	odp_ipsec_outbound_config_t outbound;
+
 } odp_ipsec_config_t;
 
 /**
@@ -385,13 +547,35 @@  typedef enum odp_ipsec_lookup_mode_t {
 	ODP_IPSEC_LOOKUP_DISABLED = 0,
 
 	/** Inbound SA lookup is enabled. Lookup matches only SPI value.
-	 *  SA lookup failure status (error.sa_lookup) is reported through
+	 *  In inline mode, a lookup miss directs the packet back to normal
+	 *  packet input interface processing. In other modes, the SA lookup
+	 *  failure status (error.sa_lookup) is reported through
 	 *  odp_ipsec_packet_result_t. */
-	ODP_IPSEC_LOOKUP_SPI
+	ODP_IPSEC_LOOKUP_SPI,
+
+	/** Inbound SA lookup is enabled. Lookup matches both SPI value and
+	  * destination IP address. Functionality is otherwise identical to
+	  * ODP_IPSEC_LOOKUP_SPI. */
+	ODP_IPSEC_LOOKUP_DSTADDR_SPI
 
 } odp_ipsec_lookup_mode_t;
 
 /**
+ * Result event pipeline configuration
+ */
+typedef enum odp_ipsec_pipeline_t {
+	/** Do not pipeline */
+	ODP_IPSEC_PIPELINE_NONE = 0,
+
+	/** Send IPSEC result events to the classifier.
+	 *
+	 *  IPSEC capability 'pipeline_cls' determines if pipelined
+	 *  classification is supported. */
+	ODP_IPSEC_PIPELINE_CLS
+
+} odp_ipsec_pipeline_t;
+
+/**
  * IPSEC Security Association (SA) parameters
  */
 typedef struct odp_ipsec_sa_param_t {
@@ -432,6 +616,21 @@  typedef struct odp_ipsec_sa_param_t {
 	/** SPI value */
 	uint32_t spi;
 
+	/** Additional inbound SA lookup parameters. Values are considered
+	 *  only in ODP_IPSEC_LOOKUP_DSTADDR_SPI lookup mode. */
+	struct {
+		/** Select IP version
+		 *
+		 *  4:   IPv4
+		 *  6:   IPv6
+		 */
+		uint8_t ip_version;
+
+		/** IP destination address (NETWORK ENDIAN) */
+		void    *dst_addr;
+
+	} lookup_param;
+
 	/** MTU for outbound IP fragmentation offload
 	 *
 	 *  This is the maximum length of IP packets that outbound IPSEC
@@ -440,13 +639,31 @@  typedef struct odp_ipsec_sa_param_t {
 	 */
 	uint32_t mtu;
 
+	/** Select pipelined destination for IPSEC result events
+	 *
+	 *  Asynchronous and inline modes generate result events. Select where
+	 *  those events are sent. Inbound SAs may choose to use pipelined
+	 *  classification. The default value is ODP_IPSEC_PIPELINE_NONE.
+	 */
+	odp_ipsec_pipeline_t pipeline;
+
 	/** Destination queue for IPSEC events
 	 *
-	 *  Operations in asynchronous mode enqueue resulting events into
-	 *  this queue.
+	 *  Operations in asynchronous or inline mode enqueue resulting events
+	 *  into this queue.
 	 */
 	odp_queue_t dest_queue;
 
+	/** Classifier destination CoS for IPSEC result events
+	 *
+	 *  Result events for successfully decapsulated packets are sent to
+	 *  classification through this CoS. Other result events are sent to
+	 *  'dest_queue'. This field is considered only when 'pipeline' is
+	 *  ODP_IPSEC_PIPELINE_CLS. The CoS must not be shared between any pktio
+	 *  interface default CoS.
+	 */
+	odp_cos_t dest_cos;
+
 	/** User defined SA context pointer
 	 *
 	 *  User defined context pointer associated with the SA.
@@ -679,6 +896,18 @@  typedef struct odp_ipsec_op_status_t {
 		uint32_t all_error;
 	};
 
+	union {
+		/** Status flags */
+		struct {
+			/** Packet was processed in inline mode */
+			uint32_t inline_mode      : 1;
+
+		} flag;
+
+		/** All flag bits */
+		uint32_t all_flag;
+	};
+
 } odp_ipsec_op_status_t;
 
 /**
@@ -708,7 +937,7 @@  typedef struct odp_ipsec_op_param_t {
 
 	/** Pointer to an array of packets
 	 *
-	 *  Each packet must have a valid value for these meta-data:
+	 *  Each packet must have a valid value for these metadata:
 	 *  * L3 offset: Offset to the first byte of the (outmost) IP header
 	 *  * L4 offset: For inbound direction, when udp_encap is enabled -
 	 *               offset to the first byte of the encapsulating UDP
@@ -733,6 +962,35 @@  typedef struct odp_ipsec_op_param_t {
 } odp_ipsec_op_param_t;
 
 /**
+ * Outbound inline IPSEC operation parameters
+ */
+typedef struct odp_ipsec_inline_op_param_t {
+	/** Packet output interface for inline output operation
+	 *
+	 *  Outbound inline IPSEC operation uses this packet IO interface to
+	 *  output the packet after a successful IPSEC transformation. The pktio
+	 *  must have been configured to operate in inline IPSEC mode.
+	 */
+	odp_pktio_t pktio;
+
+	/** Outer headers for inline output operation
+	 *
+	 *  Outbound inline IPSEC operation uses this information to prepend
+	 *  outer headers to the IPSEC packet before sending it out.
+	 */
+	struct {
+		/** Points to first byte of outer headers to be copied in
+		 *  front of the outgoing IPSEC packet. Implementation copies
+		 *  the headers during odp_ipsec_out_inline() call. */
+		uint8_t *ptr;
+
+		/** Outer header length in bytes */
+		uint32_t len;
+	} outer_hdr;
+
+} odp_ipsec_inline_op_param_t;
+
+/**
  * IPSEC operation result for a packet
  */
 typedef struct odp_ipsec_packet_result_t {
@@ -758,6 +1016,23 @@  typedef struct odp_ipsec_packet_result_t {
 	 */
 	odp_ipsec_sa_t sa;
 
+	/** Packet outer header status before inbound inline processing.
+	 *  This is valid only when status.flag.inline_mode is set.
+	 */
+	struct {
+		/** Points to the first byte of retained outer headers. These
+		 *  headers are stored in a contiquous, per packet,
+		 *  implementation specific memory space. Since the memory space
+		 *  may overlap with e.g. packet head/tailroom, the content
+		 *  becomes invalid if packet data storage is modified in
+		 *  anyway. The memory space may not be sharable to other
+		 *  threads. */
+		uint8_t *ptr;
+
+		/** Outer header length in bytes */
+		uint32_t len;
+	} outer_hdr;
+
 } odp_ipsec_packet_result_t;
 
 /**
@@ -779,18 +1054,14 @@  typedef struct odp_ipsec_op_result_t {
 	 *  at least 'num_pkt' elements.
 	 *
 	 *  Each successfully transformed packet has a valid value for these
-	 *  meta-data:
+	 *  metadata regardless of the inner packet parse configuration.
+	 *  (odp_ipsec_inbound_config_t):
 	 *  * L3 offset: Offset to the first byte of the (outmost) IP header
-	 *  * L4 offset: Offset to the first byte of the valid and known L4
-	 *               header (immediately following the IP header).
-	 *  * Various flags about L3 and L4 layers:
-	 *               has_l3, has_l4, has_ipv4, has_ipv6, has_ipfrag,
-	 *               has_ipsec, has_udp, has_tcp, etc depending on
-	 *               the resulted packet format
+	 *  * pktio:     For inbound inline IPSEC processed packets, original
+	 *               packet input interface
 	 *
-	 * @see odp_packet_l3_offset(), odp_packet_l4_offset(),
-	 *      odp_packet_has_ipv4(), odp_packet_has_ipv6(),
-	 *      odp_packet_has_ipfrag(), odp_packet_has_ipsec()
+	 *  Other metadata for parse results and error checks depend on
+	 *  configuration (selected parse and error check levels).
 	 */
 	odp_packet_t *pkt;
 
@@ -921,10 +1192,10 @@  int odp_ipsec_out(const odp_ipsec_op_param_t *input,
 /**
  * Inbound asynchronous IPSEC operation
  *
- * This operation does inbound IPSEC processing in asynchronous mode
- * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to
- * odp_ipsec_in(), but outputs all results through one or more
- * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.
+ * This operation does inbound IPSEC processing in asynchronous mode. It
+ * processes packets otherwise identically to odp_ipsec_in(), but outputs all
+ * results through one or more ODP_EVENT_IPSEC_RESULT events with the following
+ * ordering considerations.
  *
  * Asynchronous mode maintains (operation input) packet order per SA when
  * application calls the operation within an ordered or atomic scheduler context
@@ -934,6 +1205,11 @@  int odp_ipsec_out(const odp_ipsec_op_param_t *input,
  * events for the same SA are enqueued in order, and packet handles (for the
  * same SA) are stored in order within an event.
  *
+ * The function may be used also in inline processing mode, e.g. for IPSEC
+ * packets for which inline processing is not possible. Packets for the same SA
+ * may be processed simultaneously in both modes (initiated by this function
+ * and inline operation).
+ *
  * @param         input   Operation input parameters
  *
  * @return Number of input packets consumed (0 ... input.num_pkt)
@@ -946,10 +1222,10 @@  int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);
 /**
  * Outbound asynchronous IPSEC operation
  *
- * This operation does outbound IPSEC processing in asynchronous mode
- * (ODP_IPSEC_OP_MODE_ASYNC). It processes packets otherwise identically to
- * odp_ipsec_out(), but outputs all results through one or more
- * ODP_EVENT_IPSEC_RESULT events with the following ordering considerations.
+ * This operation does outbound IPSEC processing in asynchronous mode. It
+ * processes packets otherwise identically to odp_ipsec_out(), but outputs all
+ * results through one or more ODP_EVENT_IPSEC_RESULT events with the following
+ * ordering considerations.
  *
  * Asynchronous mode maintains (operation input) packet order per SA when
  * application calls the operation within an ordered or atomic scheduler context
@@ -959,6 +1235,9 @@  int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);
  * events for the same SA are enqueued in order, and packet handles (for the
  * same SA) are stored in order within an event.
  *
+ * The function may be used also in inline processing mode, e.g. for IPSEC
+ * packets for which inline processing is not possible.
+ *
  * @param         input   Operation input parameters
  *
  * @return Number of input packets consumed (0 ... input.num_pkt)
@@ -969,6 +1248,28 @@  int odp_ipsec_in_enq(const odp_ipsec_op_param_t *input);
 int odp_ipsec_out_enq(const odp_ipsec_op_param_t *input);
 
 /**
+ * Outbound inline IPSEC operation
+ *
+ * This operation does outbound inline IPSEC processing for the packets. It's
+ * otherwise identical to odp_ipsec_out_enq(), but outputs all successfully
+ * transformed packets to the specified output interface, instead of generating
+ * result events for those.
+ *
+ * Inline operation parameters are defined per packet. The array of parameters
+ * must have 'op_param.num_pkt' elements and is pointed to by 'inline_param'.
+ *
+ * @param         op_param      Operation parameters
+ * @param         inline_param  Outbound inline operation specific parameters
+ *
+ * @return Number of packets consumed (0 ... op_param.num_pkt)
+ * @retval <0     On failure
+ *
+ * @see odp_ipsec_out_enq()
+ */
+int odp_ipsec_out_inline(const odp_ipsec_op_param_t *op_param,
+			 const odp_ipsec_inline_op_param_t *inline_param);
+
+/**
  * Get IPSEC results from an ODP_EVENT_IPSEC_RESULT event
  *
  * Copies IPSEC operation results from an event. The event must be of
diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h
index cec1f22..8802089 100644
--- a/include/odp/api/spec/packet_io.h
+++ b/include/odp/api/spec/packet_io.h
@@ -407,6 +407,38 @@  typedef struct odp_pktio_config_t {
 	 * interface capability before enabling the same. */
 	odp_bool_t enable_loop;
 
+	/** Inbound IPSEC inlined with packet input
+	 *
+	 *  Enable/disable inline inbound IPSEC operation. When enabled packet
+	 *  input directs all IPSEC packets automatically to IPSEC inbound
+	 *  processing. IPSEC configuration is done through the IPSEC API.
+	 *  Packets that are not (recognized as) IPSEC are processed
+	 *  according to the packet input configuration.
+	 *
+	 *  0: Disable inbound IPSEC inline operation (default)
+	 *  1: Enable inbound IPSEC inline operation
+	 *
+	 *  @see odp_ipsec_config(), odp_ipsec_sa_create()
+	 */
+	odp_bool_t inbound_ipsec;
+
+	/** Outbound IPSEC inlined with packet output
+	 *
+	 *  Enable/disable inline outbound IPSEC operation. When enabled IPSEC
+	 *  outbound processing can send outgoing IPSEC packets directly
+	 *  to the pktio interface for output. IPSEC configuration is done
+	 *  through the IPSEC API.
+	 *
+	 *  Outbound IPSEC inline operation cannot be combined with traffic
+	 *  manager (ODP_PKTOUT_MODE_TM).
+	 *
+	 *  0: Disable outbound IPSEC inline operation (default)
+	 *  1: Enable outbound IPSEC inline operation
+	 *
+	 *  @see odp_ipsec_config(), odp_ipsec_sa_create()
+	 */
+	odp_bool_t outbound_ipsec;
+
 } odp_pktio_config_t;
 
 /**