On Tue, Mar 21, 2017 at 9:17 AM, Petri Savolainen <
petri.savolai...@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.savolai...@linaro.org>
> ---
>  include/odp/api/spec/ipsec.h     | 348 ++++++++++++++++++++++++++++++
> ++++++---
>  include/odp/api/spec/packet_io.h |  32 ++++
>  2 files changed, 355 insertions(+), 25 deletions(-)
>
> diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h
> index e951e49..23d02cf 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) */
>

Nit: Correct spelling is IPsec, not IPSec, per RFC 4301.


> +       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 {
> @@ -77,9 +111,113 @@ typedef struct odp_ipsec_inbound_config_t {
>                 uint32_t max;
>         } spi;
>
> +       /** 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 in IPSEC payload
> +        *
> +        *  Select header parsing level after inbound processing. Packet
> headers
> +        *  in IPSEC payload must be parsed (at least) up to this level.
> +        *  Default value is ODP_IPSEC_LAYER_NONE.
> +        *
> +        *  Note that IPSec payload is never a L2 packet
> (ODP_IPSEC_LAYER_L2
>

IPsec


> +        *  equals ODP_IPSEC_LAYER_NONE). In transport mode, IPSEC payload
> +        *  starts after IP header (ODP_IPSEC_LAYER_L3 equals
> +        *  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 {
> @@ -102,6 +240,24 @@ 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 inline classification (ODP_IPSEC_DEST_CLS) for
> resulting
> +        *  inbound packets.
> +        *
> +        *  0: Inline classification of resulting packets is not supported
> +        *  1: Inline classification of resulting packets is supported
> +        *  2: Inline classification of resulting packets is supported and
> +        *     preferred
> +        */
> +       uint8_t cls_inline;
> +
>         /** Soft expiry limit in seconds support
>          *
>          *  0: Limit is not supported
> @@ -128,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 */
> @@ -142,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;
>
>  /**
> @@ -381,11 +547,29 @@ typedef enum odp_ipsec_lookup_mode_t {
>         ODP_IPSEC_LOOKUP_DISABLED = 0,
>
>         /** Inbound SA lookup is enabled. Used SPI values must be unique.
> */
> -       ODP_IPSEC_LOOKUP_IN_UNIQUE_SA
> +       ODP_IPSEC_LOOKUP_IN_UNIQUE_SPI,
> +
> +       /** Inbound SA lookup is enabled. Lookup matches both SPI and
> +         * destination IP address. Used SPI values must be unique. */
> +       ODP_IPSEC_LOOKUP_IN_DSTADDR_UNIQUE_SPI
>
>  } odp_ipsec_lookup_mode_t;
>
>  /**
> + * Result event destination
> + */
> +typedef enum odp_ipsec_dest_mode_t {
> +       /** Destination for IPSEC result events is a queue. */
> +       ODP_IPSEC_DEST_QUEUE = 0,
> +
> +       /** Destination for IPSEC result events is the classifier.
> +        *  IPSEC capability 'cls_inline' determines if inline
> classification
> +        *  is supported. */
> +       ODP_IPSEC_DEST_CLS
> +
> +} odp_ipsec_dest_mode_t;
> +
> +/**
>   * IPSEC Security Association (SA) parameters
>   */
>  typedef struct odp_ipsec_sa_param_t {
> @@ -426,6 +610,17 @@ 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_IN_DSTADDR_UNIQUE_SPI lookup mode. */
> +       struct {
> +               /* v4 or v6 */
> +               uint8_t ip_version;
>

Is this an enum? If not perhaps doc this as 4 = IPv4, 6 = IPv6.


> +
> +               /* 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
> @@ -434,13 +629,32 @@ typedef struct odp_ipsec_sa_param_t {
>          */
>         uint32_t mtu;
>
> +       /** Select where IPSEC result events are sent
> +        *
> +        *  Asynchronous and inline modes generate result events. Select
> where
> +        *  those events are sent. Inbound SAs may choose between a queue
> or
> +        *  the classifier. Outbound SAs must define a queue always.
> +        *  The default value is ODP_IPSEC_DEST_QUEUE.
> +        */
> +       odp_ipsec_dest_mode_t dest_mode;
> +
>         /** 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 'dest_mode' is
> +        *  ODP_IPSEC_DEST_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.
> @@ -673,6 +887,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;
>
>  /**
> @@ -727,6 +953,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;
>

Shouldn't we have an option for this to be output to an odp_tm_queue_t
instead of a pktio?
Also, for output are there any controls over which odp_pktout_queue_t is
used, or is this undefined?


> +
> +       /** 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;
>

Should this be an odp_packet_t rather than a raw set of bytes? The
rationale for making this an odp_packet_t is that this could then be a
packet reference which can be used for (re)transmit tracking. For input
having this be raw bytes makes sense since the ODP implementation is
controlling their allocation and placement, however for output how is the
application going to allocate these? Presumably it would create a header
via odp_packet_alloc() and then use odp_packet_data() to get this address,
but that seems cumbersome compared to simply passing the odp_packet_t
directly. The alternative would seem to require that the application use
some sort of odp_shm_reserve() call, but that gets awkward and is far less
efficient than packet allocation, which is a fastpath operation.


> +
> +               /** 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 {
> @@ -752,6 +1007,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;
>
>  /**
> @@ -773,18 +1045,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:
> +        *  meta-data regardless of the inner packet parse configuration.
>

Vestigial typo. It's metadata, not meta-data. Might as well clean up here.


> +        *  (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 meta-data for parse results and error checks depend on
> +        *  configuration (selected parse and error check levels).
>          */
>         odp_packet_t *pkt;
>
> @@ -915,10 +1183,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
> @@ -928,6 +1196,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)
> @@ -940,10 +1213,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
> @@ -953,6 +1226,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)
> @@ -963,6 +1239,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).
>

We need to fix this since TM is likely to be the preferred TX mode, just as
the classifier is the preferred RX mode. There's no reason why IPsec
traffic shouldn't also be subject to TM policies.


> +        *
> +        *  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
>
>

Reply via email to