aboutsummaryrefslogtreecommitdiff
path: root/doc/users-guide/users-guide-ipsec.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/users-guide/users-guide-ipsec.adoc')
-rw-r--r--doc/users-guide/users-guide-ipsec.adoc467
1 files changed, 467 insertions, 0 deletions
diff --git a/doc/users-guide/users-guide-ipsec.adoc b/doc/users-guide/users-guide-ipsec.adoc
new file mode 100644
index 000000000..6af676620
--- /dev/null
+++ b/doc/users-guide/users-guide-ipsec.adoc
@@ -0,0 +1,467 @@
+== IPsec services
+
+In addition to general cryptographic services, ODP offers offload support for
+the IPsec protocol. IPsec is a general term referencing a suite of protocols
+and packet formats and as such a full discussion of IPsec is beyond the scope
+of this document. See https://tools.ietf.org/html/rfc4301[RFC 4301] and
+related RFCs for more detail. This section assumes the reader is already
+familiar with IPsec and focuses on explaining the ODP APIs that support it.
+
+ODP provides APIs for the following IPsec services:
+
+* General IPsec configuration
+* Security Association (SA) configuration and lifecycle management
+* Synchronous and Asynchronous IPsec lookaside processing
+* Inline processing for full IPsec RX and/or TX offload
+* Pipelining for RX traffic
+* Fragmentation support for TX traffic
+* IPsec event management
+
+=== IPsec Capabilities and Configuration
+As with other features, ODP provides APIs that permit applications to query
+platform-specific IPsec capabilities. The `odp_ipsec_capability()` API queries
+the general IPsec features available while the `odp_ipsec_cipher_capability()`
+and `odp_ipsec_auth_capability()` APIs provide detail on the range of
+cipher and authentication algorithms supported by IPsec on this platform.
+
+General IPsec capabilities that are reported include:
+
+* The IPsec operation modes supported by this implementation. Different
+operation modes may be _not supported_, _supported_, or _preferred_. A
+preferred form means that this mode takes advantage of hardware
+acceleration features to achieve best performance.
+* Whether IPsec AH processing is supported. All ODP platforms must provide
+support for IPsec ESP processing, however since AH is relatively rare, it
+may not be supported, or supported only via software emulation (_e.g.,_ be
+non-preferred).
+* Whether IPsec headers can be retained on decrypt for inbound inline
+operations.
+* Whether classification pipelining is supported (to be discussed below).
+
+In addition, capabilities also inform the application of the maximum number
+of destination queues and classification CoS targets supported. These
+will be discussed further later.
+
+==== IPsec Operation Modes
+IPsec operates in one of three modes: Synchronous, Asynchronous, and Inline.
+
+==== Lookaside Processing
+Synchronous and Asynchronous are types of _lookaside_ processing. Which of
+these forms may be used depends on the IPsec operation mode. So synchronous
+APIs may only be used when operating in synchronous mode, and asynchronous
+APIs may only be used when operating in asynchronous mode.
+
+In lookaside mode, the application receives (or creates) an IPsec packet and
+then uses ODP to perform one of two functions:
+
+* To decrypt an IPsec packet into a "normal" packet
+* To take a "normal" packet and encrypt it into an IPsec packet.
+
+This process may be performed _synchronously_ with the APIs `odp_ipsec_in()`
+(to decrypt) and `odp_ipsec_out()` (to encrypt). Upon return from these calls
+the requested packet transformation is complete, or an error return code
+indicates that it could not be performed (_e.g.,_ packet decryption failed).
+
+Synchronous processing may be preferred if the application has a large number
+of worker threads so that blocking any individual worker while IPsec processing
+is performed represents a reasonable design. The alternative is to use
+_asynchronous_ forms of these APIs:
+
+* `odp_ipsec_in_enq()` for decrypt
+* `odp_ipsec_out_enq()` for encrypt
+
+These simply pass packets to IPsec for processing. When this processing is
+complete, the resulting packets are sent to the completion queue associated
+with the SA used by the operation, serving as IPsec completion events as
+shown here:
+
+image::ipsec-lookaside.svg[align="center"]
+
+If the operation fails because SA lookup failed for inbound processing, then
+these result packets are sent to the default queue specified as part of the
+`odp_ipsec_inbound_config_t` used in the `odp_ipsec_config()` call.
+
+Following an asynchronous IPsec call, the worker thread moves on to process
+other events until the IPsec completion shows up. At that point the worker
+thread sees whether the operation was successful or not and continues
+processing for that packet. These events may be direct-polled with
+`odp_queue_deq()` if the completion queue was created as a plain queue, or
+processed via the ODP scheduler if the completion queue was created as a
+scheduled queue.
+
+==== Inline Processing
+While lookaside processing offers flexibility, it still requires extra
+processing steps not required by modern hardware. To avoid this overhead
+ODP also offers _inline_ processing support for IPsec. In this mode the
+processing of IPsec packets on the RX and TX paths is fully offloaded as
+shown here:
+
+image::ipsec-inline.svg[align="center"]
+
+It is worth noting that, depending on the implementation and application
+needs, inline processing may be enabled only for one direction (inbound or
+outbound) or for both directions.
+
+On the receive side, once configured for inline processing, arriving IPsec
+packets that are recognized at the PktIO interface are decrypted automatically
+before the application ever sees them. On the transmit side, the application
+calls `odp_ipsec_out_inline()` and the packet is encrypted and queued for
+transmission as a single operation without further application involvement.
+Note that if an inbound IPsec packet is not recognized (_e.g.,_ it belongs to
+an unknown SA) then it will be presented to the application as-is without
+further processing. The application may then use a lookaside call to process
+the packet if it is able to supply a matching SA by other means.
+
+On the receive side, after an IPsec packet is decrypted, it may be
+_pipelined_ to the ODP classifier or added to a poll queue, as the
+application wishes. The advantage of classification pipelining is that inbound
+IPsec traffic is automatically decrypted and classified into appropriate
+flow-based queues for ease of processing.
+
+On the transmit side, since IPsec encryption and tunneling may exceed an
+output MTU, ODP also offers support for MTU configuration and automatic IPsec
+TX fragmentation.
+
+Both classification pipelining and TX fragmentation support are support
+features that are indicated by `odp_ipsec_capability()`.
+
+Note that at present inline IPsec output support sends resulting packets
+directly to an output PktIO. If it's desired to send them to the ODP
+Traffic Manager for shaping prior to transmission, use the lookaside APIs
+to perform the IPsec encrypt and then call `odp_tm_enq()` on the resulting
+packet.
+
+=== IPsec Configuration
+Prior to making use of IPsec services, the `odp_ipsec_config()` API is used to
+configure IPsec processing options. This API takes a pointer to an
+`odp_ipsec_config_t` struct as its argument.
+
+The `odp_ipsec_config_t` struct specifies the inbound and outbound processing
+modes (SYNC, ASYNC, or INLINE) that the application plans to use, the maximum
+number of Security Associations it will use, and sets inbound and outbound
+processing options.
+
+==== IPsec Inbound Configuration
+Inbound configuration options for IPsec specify the default `odp_queue_t` to
+be used for processing global events like SA lookup failures, how Security
+Parameter Index (SPI) lookup is to be performed, and whether the application
+requires ODP to retain outer headers for decrypted IPsec packets.
+
+Parsing options specify how "deep" decrypted packets are to be parsed
+after IPsec processing by specifying the packet layers of interest to the
+application (None, L2, L3, L4, or All). And which checksums should be verified
+on decrypted packets.
+
+==== IPsec Outbound Configuration
+Outbound configuration options for IPsec specify checksum insertion processing
+that should be performed prior to encryption.
+
+=== IPsec Events
+IPsec introduces one new event type and one new event subtype. These are:
+
+* IPsec packet events. These are events of type `ODP_EVENT_PACKET` that have
+subtype `ODP_EVENT_PACKET_IPSEC`. These are packets that carry additional
+IPsec-related metadata in the form of an `odp_ipsec_packet_result_t` struct
+that can be retrieved from the packet via the `odp_ipsec_result()` API.
+
+* IPsec status notifications. These are events of type `ODP_EVENT_IPSEC_STATUS`
+that indicate status events not associated with any particular IPsec
+packet. Such events carry status in the form of an `odp_ipsec_status_t`
+struct that is retrieved from the event via the `odp_ipsec_status()` API.
+
+IPsec-related events are thus part of normal and exception processing when
+working with IPsec.
+
+=== Security Associations (SAs)
+The fundamental "building block" for IPsec processing is the _Security
+Association (SA)_. Similar to a crypto session, the SA encapsulates the keying
+material and context needed to perform IPsec protocol processing for inbound
+or outbound packets on a given flow, as well as additional processing options
+that control how IPsec is to be used for packets processed under this
+SA. Security Associations are unidirectional (RX or TX) so a flow that
+requires both inbound (decrypt) and outbound (encrypt) IPsec functions will
+have two SAs associated with it. SAs in ODP are represented by the
+abstract type `odp_ipsec_sa_t`.
+
+After ODP initialization, IPsec support is dormant until it is configured
+by a call to `odp_ipsec_config()` as described earlier. Once configured,
+SAs may be created by calling `odp_ipsec_sa_create()`.
+
+==== SA Creation and Configuration
+The `odp_ipsec_sa_create()` API takes an `odp_ipsec_sa_param_t` argument that
+describes the SA to be created. Use the `odp_ipsec_sa_param_init()` API to
+initialize this to its default state and then override selected fields within
+the param struct as needed.
+
+Items specified in the `odp_ipsec_sa_param_t` struct include:
+
+* The direction of the SA (inbound or outbound).
+
+* The IPsec protocol being used (ESP or AH).
+
+* The IPsec protocol mode (Transport or Tunnel).
+
+* The parameters needed for the crypto and authentication algorithms to be
+used by this SA.
+
+* Miscellaneous SA options that control behavior such as use of Extended
+Sequence Numbers (ESNs), the use of UDP encapsulation, various copy
+options for header fields, and whether the TTL (Hop Limit) field should be
+decremented when operating in tunnel mode.
+
+* Parameters controlling the SA lifetime.
+
+* The Security Parameter Index (SPI) that packets will use to indicate that
+they belong to this SA.
+
+* The pipeline mode used by this SA.
+
+* The destination `odp_queue_t` to be used for events associated with this SA.
+
+* The user context pointer (and length) associated with this SA for
+application use.
+
+In addition, there are specific direction-specific parameters that vary
+based on whether the SA is for inbound or outbound use. For inbound SAs:
+
+* Controls for how this SA is to be looked up.
+
+* The minimum size of the anti-replay window to be used.
+
+* The default CoS to use when classification pipelining packets matching this
+SA.
+
+For outbound SAs:
+
+* Tunnel parameters to use when doing outbound processing in tunnel mode.
+
+* The fragmentation mode to be used.
+
+* The MTU to be used to control the maximum length IP packets that outbound
+IPsec operations may produce. This can be changed dynamically by the
+`odp_ipsec_sa_mtu_update()` API.
+
+As can be seen, SAs have a large degree of configurability.
+
+==== SA Lifecycle Management
+In discussing the lifecycle of an SA and the operations it supports, it is
+useful to refer to the following sequence diagram for IPsec configuration, SA
+management, and IPsec operations:
+
+image:ipsec_sa_states.svg[align="center"]
+
+After creation, IPsec services are active for this Security Association. The
+specific APIs that can be used on this SA depends on the IPsec operating mode
+that has been configured.
+
+===== IPsec Lookaside Processing
+If IPsec is operating in lookaside mode for the SA's direction (the
+`odp_ipsec_op_mode_t` is `ODP_IPSEC_OP_MODE_SYNC` or `ODP_IPSEC_OP_MODE_ASYNC`),
+then inbound or outbound lookaside operations may be performed. Asynchronous
+lookaside operations are also permitted if the SA is operating in inline
+mode, as described in the next section.
+
+The synchronous forms of these APIs are:
+
+* `odp_ipsec_in()`
+* `odp_ipsec_out()`
+
+Upon return from these calls, the return code tells the application the number
+of number of input packets that were consumed by the operation. The result of
+the operation is determined by calling the `odp_ipsec_result()` API for each
+output packet to retrieve its associated `odp_ipsec_result_t`.
+
+The asynchronous forms of these APIs are:
+
+* `odp_ipsec_in_enq()`
+* `odp_ipsec_out_enq()`
+
+Here again, the return code indicates how many input packets were
+processed. The success or failure is determined by inspecting the
+`odp_ipsec_result_t` associated with each packet completion event. These are
+presented as events of type `ODP_EVENT_PACKET` with subtype
+`ODP_EVENT_PACKET_IPSEC`.
+
+For both synchronous and asynchronous IPsec operations an input packet array
+is transformed into an output packet array as specified by a controlling
+parameter struct. For inbound operations, the `odp_ipsec_in_param_t` is
+used to specify how SA processing is to be performed for the requested
+operation. The caller may say that SA lookup processing should be performed
+for each input packet, a single (specified) SA should be used for all packets,
+or that each packet has a specified individual SA.
+
+For outbound lookaside operations, a corresponding `odp_ipsec_out_param_t`
+serves a similar role, but here the SA must be specified since the input
+packet(s) are non-IPsec packets. Again the option is to use a single SA for
+all input packets or one per input packet.
+
+For outbound operations, an associated array of `odp_ipsec_out_opt_t` structs
+is also used to control the fragmentation mode to be used as part of the
+outbound processing. Options here are to not fragment, to fragment before
+IPsec processing, after IPsec processing, or to only check whether IP
+fragmentation is needed but not to perform it. For check processing, the `mtu`
+status error bit in the `odp_ipsec_packet_result_t` is set if check processing
+detects that the resulting packet will not fit into the configured MTU. Note
+that the MTU associated with a given SA is set at SA creation and can be
+changed at any time via the `odp_ipsec_sa_mtu_update()` API.
+
+Once an asynchronous lookaside operation has been initiated, the worker thread
+that issued the asynchronous call can handle other events while waiting for
+the operation to complete. Completion of an asynchronous operation is
+indicated by the worker receiving an `ODP_EVENT_PACKET` that has subtype
+`ODP_EVENT_PACKET_IPSEC`. These events can be retrieved directly by polling
+the completion queue associated with the SA, or (more typically) via the ODP
+scheduler. Typical code for such completion processing would look as follows:
+
+[source,c]
+-----
+while (1) {
+ ev = odp_schedule(&queue, ODP_SCHED_WAIT);
+ ev_type = odp_event_types(ev, &ev_subtype);
+
+ switch (ev_type) {
+ case ODP_EVENT_PACKET:
+
+ switch (ev_subtype) {
+ case ODP_EVENT_PACKET_IPSEC:
+ pkt = odp_packet_from_event(ev);
+
+ if (odp_unlikely(odp_ipsec_result(&result, pkt) != 0)) {
+ /* Stale event, discard */
+ odp_event_free(ev);
+ continue;
+ }
+
+ if (odp_unlikely(result.status.all != ODP_IPSEC_OK)) {
+ if (result.status.error != ODP_IPSEC_OK) {
+ ...process error result
+ odp_event_free(ev);
+ continue;
+ } else {
+ ...process packet warnings
+ }
+ }
+
+ my_context = odp_ipsec_sa_context(result.sa);
+
+ if (result.flag.inline_mode) {
+ ...process inline inbound packet
+ } else {
+ ...process the async completion event
+ }
+
+ ...
+ break;
+
+ case ...
+ }
+ break;
+
+ case ODP_EVENT_IPSEC_STATUS:
+ ...process IPsec status event
+ break;
+
+ }
+}
+-----
+
+===== IPsec Inline Processing
+When IPsec is configured to operate in `ODP_IPSEC_OP_MODE_INLINE` mode,
+inbound processing is implicit. The application never sees these packets until
+after IPsec has already decrypted them. As shown in the code sketch above,
+such packets appear as events of subtype `ODP_EVENT_PACKET_IPSEC` and the
+`flag` field in the associated `odp_ipsec_packet_result_t` indicates
+`inline_mode`.
+
+For outbound IPsec processing, the `odp_ipsec_out_inline()` API operates as
+a "fire and forget" API. A success return code from this call indicates that
+the packet will be encrypted and transmitted to the `odp_pktio_t` indicated
+in the `odp_ipsec_out_inline_param_t` specified at the time of the call without
+any further application involvement. Only if a problem arises will the packet
+be returned to the application with an `odp_ipsec_packet_result_t` indicating
+the nature of the problem.
+
+Note that while operating in inline mode, asynchronous lookaside operations are
+also permitted. This provide the application with additional flexibility if,
+for example, some packets need additional handling that cannot be supported
+directly with inline IPsec processing.
+
+==== SA Lifetimes
+A fundamental principle of good security is that the keying material
+associated with sessions has a limited lifetime. In effect, keys grow "stale"
+over time or due to being used to encrypt too much data. The metrics used
+to limit effective SA lifetimes are:
+
+* Duration (time)
+* Usage (volume of traffic using the keys)
+
+Associated with each of these metrics are "soft" and "hard" limits. When a
+hard limit is reached, the SA is expired and cannot be used further. To support
+graceful transition to a replacement SA, soft limits are used. A soft limit is
+similar to a "low fuel" warning light on a car. It alerts the application that
+the SA is nearing the end of its useful life and should be renegotiated even
+as the SA continues to work normally.
+
+ODP support for SA limits is based on packet/byte counts. Applications that
+wish to use time-based SA limits may do so on their own using the timing
+facilities that ODP provides. However, since especially with inline IPsec
+processing, the application may not have explicit knowledge of the traffic
+volumes associated with a given SA, support for usage-based limits is
+integrated into ODP IPsec support.
+
+At `odp_ipsec_sa_create()` time, one of the fields in the
+`odp_ipsec_sa_param_t` struct is the `odp_ipsec_lifetime_t` sub-structure.
+This struct allows hard and/or soft limits to be specified in terms of total
+bytes encrypted/decrypted, total packet count, or both. A limit specification
+of 0 indicates no limit for that metric. If either is specified, the limit
+is triggered on whichever occurs first. Given the defined behavior of hard vs.
+soft limits, the soft limits, if used, should always be specified as lower
+than the hard limits. These should be sufficiently lower to enable adequate
+time to switch over to a replacement SA before the hard limit is reached.
+
+As noted, when an SA hard limit is reached the SA immediately enters the
+expired state and attempts to use it further are failed with an
+`odp_ipsec_result_t` that indicates a hard expiration limit. When a soft
+limit is reached for packets sent via `odp_ipsec_out_inline()`, this results
+in an `ODP_EVENT_IPSEC_STATUS` event being sent to the application on the
+queue associated with the SA that has reached the soft limit. This status
+event has an `odp_ipsec_status_id_t` of `ODP_IPSEC_STATUS_WARN` with a
+`odp_ipsec_warn_t` bits set to indicate the type of soft expiration reached.
+Receipt of this event alerts the application that the SA is nearing the end of
+its useful life and that it should be replaced. It is the application's
+responsibility to heed this warning. It is implementation-defined how many
+such warnings are issued when a soft limit is exceeded (once, first N packets,
+or all packets beyond the limit), so applications should be written to
+allow for possible repeated warnings.
+
+When operating in lookaside mode, expiration limits are carried as a warning
+in the `odp_op_status_t` section of the `odp_ipsec_result_t` struct. The same
+is true for inline inbound packets. When the soft limit is reached, these
+packets will carry a warning flag indicating this condition.
+
+==== SA Disablement and Destruction
+When it is time to retire an SA, the application does so by first issuing a
+call to the `odp_ipsec_sa_disable()` API. This call initiates termination
+processing for an SA by stopping use of the SA for new operations while still
+allowing those that are "in flight" to complete processing. Following this call
+the application continues to receive and process IPsec events as normal.
+
+Disable completion is indicated by the application seeing an event of type
+`ODP_EVENT_IPSEC_STATUS` for this SA that contains an `odp_ipsec_status_id_t`
+of `ODP_IPSEC_STATUS_SA_DISABLE`. For inbound SAs, receipt of this event means
+that the application has seen all IPsec packets associated with this SA that
+were pending at the time of the disable call. For outbound SAs, receipt of
+this event means that the application has seen all result events associated
+with packets sent via this SA.
+
+Note that once a packet has been "seen" by the application, it becomes the
+application's responsibility to ensure that it is fully processed before
+attempting to destroy its associated SA. The disable call exists to give
+the application assurance that there are no pending IPsec events for this
+SA associated with packets that it has not seen before.
+
+So after disabling the SA, the application can process pending packets
+normally until it sees the disable status event. At that point it knows that
+all pending packets that arrived before the disable have been seen and it is
+safe for the application to destroy it via `odp_ipsec_sa_destroy()`, thus
+completing the SA lifecycle.